From: Bruce Rogers <brogers@suse.com>
Date: Fri, 24 Jul 2020 15:21:09 -0600
Subject: ipxe: qemu ipxe to tarball delta

Include-If: %if 0%{?patch-possibly-applied-elsewhere}

This patch represents the delta between the v1.4.2 qemu ipxe submodule
and the ipxe tarball source included with the v1.4.2 qemu package,
which we patch.

Signed-off-by: Bruce Rogers <brogers@suse.com>
---
 contrib/rom-o-matic/bottom.php                |   18 +-
 contrib/rom-o-matic/build.php                 |    9 +-
 contrib/rom-o-matic/customize-flags.php       |   18 +-
 contrib/rom-o-matic/directions.php            |   12 +-
 contrib/rom-o-matic/flag-table.php            |   32 +
 contrib/rom-o-matic/index.php                 |    6 +-
 contrib/rom-o-matic/top.php                   |   12 +-
 contrib/rom-o-matic/utils.php                 |    5 +-
 contrib/vm/bochsrc.txt                        |  720 +-
 src/Makefile                                  |   38 +-
 src/Makefile.housekeeping                     |  226 +-
 src/arch/i386/Makefile                        |   10 +-
 src/arch/i386/Makefile.pcbios                 |    1 +
 src/arch/i386/core/aout_loader.c              |  144 -
 src/arch/i386/core/basemem_packet.c           |    3 +-
 src/arch/i386/core/cmdline.c                  |  113 -
 src/arch/i386/core/cpu.c                      |   73 -
 src/arch/i386/core/freebsd_loader.c           |  377 -
 src/arch/i386/core/gdbmach.c                  |    3 +-
 src/arch/i386/core/linux/linuxprefix.S        |   28 +
 src/arch/i386/core/pic8259.c                  |    3 +-
 src/arch/i386/core/rdtsc_timer.c              |    3 +-
 src/arch/i386/core/relocate.c                 |   31 +-
 src/arch/i386/core/runtime.c                  |  265 +
 src/arch/i386/core/video_subr.c               |    9 +
 src/arch/i386/core/wince_loader.c             |  273 -
 src/arch/i386/core/x86_io.c                   |   96 -
 src/arch/i386/drivers/net/undi.c              |    5 +-
 src/arch/i386/drivers/net/undiload.c          |    3 +-
 src/arch/i386/drivers/net/undinet.c           |  171 +-
 src/arch/i386/drivers/net/undionly.c          |   15 +-
 src/arch/i386/drivers/net/undipreload.c       |    3 +-
 src/arch/i386/drivers/net/undirom.c           |    3 +-
 src/arch/i386/firmware/pcbios/basemem.c       |    3 +-
 src/arch/i386/firmware/pcbios/bios_console.c  |   21 +-
 src/arch/i386/firmware/pcbios/e820mangler.S   |    3 +-
 src/arch/i386/firmware/pcbios/fakee820.c      |    3 +-
 src/arch/i386/firmware/pcbios/hidemem.c       |   23 +-
 src/arch/i386/firmware/pcbios/memmap.c        |   19 +-
 src/arch/i386/firmware/pcbios/pnpbios.c       |    3 +-
 src/arch/i386/hci/commands/pxe_cmd.c          |    3 +-
 src/arch/i386/hci/commands/reboot_cmd.c       |    3 +-
 src/arch/i386/image/bootsector.c              |   18 +-
 src/arch/i386/image/bzimage.c                 |  257 +-
 src/arch/i386/image/com32.c                   |    3 +-
 src/arch/i386/image/comboot.c                 |    5 +-
 src/arch/i386/image/elfboot.c                 |    6 +-
 src/arch/i386/image/initrd.c                  |  300 +
 src/arch/i386/image/multiboot.c               |  155 +-
 src/arch/i386/image/nbi.c                     |   11 +-
 src/arch/i386/image/pxe_image.c               |   19 +-
 src/arch/i386/image/sdi.c                     |  136 +
 src/arch/i386/include/bios.h                  |    1 +
 src/arch/i386/include/bits/byteswap.h         |   91 +-
 src/arch/i386/include/bits/cpu.h              |   86 -
 src/arch/i386/include/bits/entropy.h          |   14 +
 src/arch/i386/include/bits/errfile.h          |   42 -
 src/arch/i386/include/bits/io.h               |   14 -
 src/arch/i386/include/bits/time.h             |   14 +
 src/arch/i386/include/efi/ipxe/dhcp_arch.h    |    3 +-
 src/arch/i386/include/initrd.h                |   29 +
 src/arch/i386/include/int13.h                 |   70 +-
 src/arch/i386/include/ipxe/bios_sanboot.h     |   11 +
 src/arch/i386/include/ipxe/guestrpc.h         |   68 +
 src/arch/i386/include/ipxe/rtc_entropy.h      |   62 +
 src/arch/i386/include/ipxe/rtc_time.h         |   18 +
 src/arch/i386/include/ipxe/vmware.h           |   81 +
 src/arch/i386/include/ipxe/x86_io.h           |  153 -
 src/arch/i386/include/librm.h                 |    6 +
 src/arch/i386/include/pcbios/ipxe/dhcp_arch.h |    3 +-
 src/arch/i386/include/pic8259.h               |    2 +
 src/arch/i386/include/pxe.h                   |   50 +-
 src/arch/i386/include/pxe_api.h               |  148 +-
 src/arch/i386/include/rtc.h                   |   83 +
 src/arch/i386/include/sdi.h                   |   39 +
 src/arch/i386/interface/pcbios/bios_smbios.c  |    5 +-
 src/arch/i386/interface/pcbios/bios_timer.c   |    3 +-
 src/arch/i386/interface/pcbios/int13.c        |  773 +-
 .../i386/interface/pcbios/memtop_umalloc.c    |   88 +-
 src/arch/i386/interface/pcbios/pcibios.c      |    3 +-
 src/arch/i386/interface/pcbios/rtc_entropy.c  |  199 +
 src/arch/i386/interface/pcbios/rtc_time.c     |  138 +
 src/arch/i386/interface/pxe/pxe_call.c        |  317 +-
 src/arch/i386/interface/pxe/pxe_entry.S       |    3 +-
 src/arch/i386/interface/pxe/pxe_exit_hook.c   |   61 +
 src/arch/i386/interface/pxe/pxe_file.c        |  142 +-
 src/arch/i386/interface/pxe/pxe_loader.c      |    3 +-
 src/arch/i386/interface/pxe/pxe_preboot.c     |  117 +-
 src/arch/i386/interface/pxe/pxe_tftp.c        |   54 +-
 src/arch/i386/interface/pxe/pxe_udp.c         |   25 +-
 src/arch/i386/interface/pxe/pxe_undi.c        |  514 +-
 src/arch/i386/interface/pxeparent/pxeparent.c |    3 +-
 .../i386/interface/pxeparent/pxeparent_dhcp.c |    3 +-
 src/arch/i386/interface/syslinux/com32_call.c |    3 +-
 .../i386/interface/syslinux/com32_wrapper.S   |    3 +-
 .../i386/interface/syslinux/comboot_call.c    |   27 +-
 src/arch/i386/interface/vmware/guestinfo.c    |  282 +
 src/arch/i386/interface/vmware/guestrpc.c     |  328 +
 src/arch/i386/interface/vmware/vmconsole.c    |  134 +
 src/arch/i386/interface/vmware/vmware.c       |   58 +
 src/arch/i386/prefix/exeprefix.S              |    5 +-
 src/arch/i386/prefix/kkkpxeprefix.S           |   19 +
 src/arch/i386/prefix/libprefix.S              |   93 +-
 src/arch/i386/prefix/linuxprefix.S            |   28 -
 src/arch/i386/prefix/lkrnprefix.S             |   61 +-
 src/arch/i386/prefix/mromprefix.S             |  118 +-
 src/arch/i386/prefix/nbiprefix.S              |    4 +
 src/arch/i386/prefix/pxeprefix.S              |   72 +-
 src/arch/i386/prefix/romprefix.S              |  141 +-
 src/arch/i386/prefix/undiloader.S             |    4 +-
 src/arch/i386/scripts/i386.lds                |   51 +-
 src/arch/i386/transitions/liba20.S            |   12 +-
 src/arch/i386/transitions/librm.S             |   28 +-
 src/arch/x86/Makefile                         |    1 +
 src/arch/x86/core/cpuid.c                     |  155 +
 src/arch/x86/core/debugcon.c                  |   86 +
 src/arch/x86/core/pcidirect.c                 |    3 +-
 src/arch/x86/core/x86_bigint.c                |   91 +
 src/arch/x86/core/x86_io.c                    |  102 +
 src/arch/x86/core/x86_string.c                |  161 +-
 src/arch/x86/core/x86_tcpip.c                 |  169 +
 src/arch/x86/hci/commands/cpuid_cmd.c         |   98 +
 src/arch/x86/include/bits/bigint.h            |  318 +
 src/arch/x86/include/bits/errfile.h           |   50 +
 src/arch/x86/include/bits/io.h                |   14 +
 src/arch/x86/include/bits/string.h            |  214 +-
 src/arch/x86/include/bits/tcpip.h             |   17 +
 src/arch/x86/include/ipxe/cpuid.h             |   53 +
 src/arch/x86/include/ipxe/x86_io.h            |  159 +
 src/arch/x86/interface/efi/efix86_nap.c       |    3 +-
 src/arch/x86/prefix/efidrvprefix.c            |    3 +-
 src/arch/x86/prefix/efiprefix.c               |    3 +-
 src/arch/x86_64/Makefile                      |   12 +
 src/arch/x86_64/core/linux/linuxprefix.S      |   25 +
 src/arch/x86_64/include/bits/byteswap.h       |   25 +
 src/arch/x86_64/include/bits/entropy.h        |   12 +
 src/arch/x86_64/include/bits/errfile.h        |   11 -
 src/arch/x86_64/include/bits/io.h             |   10 -
 src/arch/x86_64/include/bits/time.h           |   12 +
 src/arch/x86_64/include/efi/ipxe/dhcp_arch.h  |    5 +-
 src/arch/x86_64/prefix/linuxprefix.S          |   25 -
 src/config/colour.h                           |   32 +
 src/config/config.c                           |   47 +-
 src/config/console.h                          |    6 +-
 src/config/defaults/efi.h                     |    4 +-
 src/config/defaults/linux.h                   |    2 +
 src/config/defaults/pcbios.h                  |    6 +-
 src/config/entropy.h                          |   16 +
 src/config/general.h                          |   27 +-
 src/config/sideband.h                         |    3 +
 src/config/time.h                             |   16 +
 src/core/acpi.c                               |    3 +-
 src/core/ansiesc.c                            |    3 +-
 src/core/assert.c                             |   31 +
 src/core/base16.c                             |    3 +-
 src/core/base64.c                             |   12 +-
 src/core/basename.c                           |    3 +-
 src/core/bitmap.c                             |    3 +-
 src/core/blockdev.c                           |    3 +-
 src/core/btext.c                              | 5039 ------------
 src/core/console.c                            |    7 +-
 src/core/cpio.c                               |    3 +-
 src/core/ctype.c                              |    3 +-
 src/core/cwuri.c                              |    3 +-
 src/core/debug.c                              |   56 +-
 src/core/debug_md5.c                          |    3 +-
 src/core/device.c                             |    3 +-
 src/core/downloader.c                         |   17 +-
 src/core/edd.c                                |    3 +-
 src/core/exec.c                               |  125 +-
 src/core/fnrec.c                              |    3 +-
 src/core/gdbserial.c                          |    3 +-
 src/core/gdbstub.c                            |    3 +-
 src/core/gdbudp.c                             |    3 +-
 src/core/getkey.c                             |    5 +-
 src/core/getopt.c                             |    8 +-
 src/core/hw.c                                 |   23 +-
 src/core/image.c                              |  167 +-
 src/core/init.c                               |    3 +-
 src/core/interface.c                          |    3 +-
 src/core/iobuf.c                              |  154 +-
 src/core/job.c                                |    3 +-
 src/core/linebuf.c                            |    3 +-
 src/core/lineconsole.c                        |   67 +
 src/core/list.c                               |   84 +
 src/core/log.c                                |   63 +
 src/core/main.c                               |   81 +-
 src/core/malloc.c                             |  130 +-
 src/core/memblock.c                           |   81 +
 src/core/menu.c                               |  178 +
 src/core/misc.c                               |   12 +
 src/core/monojob.c                            |   57 +-
 src/core/null_sanboot.c                       |    4 +-
 src/core/null_time.c                          |   30 +
 src/core/nvo.c                                |   10 +-
 src/core/open.c                               |    3 +-
 src/core/parseopt.c                           |   92 +-
 src/core/pcmcia.c                             |    1 -
 src/core/pending.c                            |   80 +
 src/core/posix_io.c                           |    3 +-
 src/core/process.c                            |   51 +-
 src/core/refcnt.c                             |    3 +-
 src/core/resolv.c                             |   14 +-
 src/core/serial.c                             |    7 +-
 src/core/serial_console.c                     |   17 +-
 src/core/settings.c                           |  858 +-
 src/core/strtoull.c                           |   12 +
 src/core/time.c                               |  138 +
 src/core/timer.c                              |    3 +-
 src/core/uri.c                                |    3 +-
 src/core/uuid.c                               |    5 +-
 src/core/version.c                            |   41 +
 src/core/vsprintf.c                           |   77 +-
 src/core/wchar.c                              |   43 +
 src/core/xfer.c                               |   46 +-
 src/core/xferbuf.c                            |  108 +
 src/crypto/aes_wrap.c                         |    5 +-
 src/crypto/arc4.c                             |    3 +-
 src/crypto/asn1.c                             |  745 +-
 src/crypto/axtls/aes.c                        |  197 +-
 src/crypto/axtls/bigint.c                     | 1496 ----
 src/crypto/axtls/bigint.h                     |   60 +-
 src/crypto/axtls/bigint_impl.h                |   66 +-
 src/crypto/axtls/config.h                     |   13 +
 src/crypto/axtls/crypto.h                     |  235 +-
 src/crypto/axtls/os_port.h                    |   67 +-
 src/crypto/axtls/rsa.c                        |  332 -
 src/crypto/axtls/sha1.c                       |  240 -
 src/crypto/axtls_aes.c                        |    8 +-
 src/crypto/axtls_sha1.c                       |   25 -
 src/crypto/bigint.c                           |  135 +
 src/crypto/cbc.c                              |    7 +-
 src/crypto/chap.c                             |    3 +-
 src/crypto/clientcert.c                       |  183 +
 src/crypto/cms.c                              |  705 ++
 src/crypto/crandom.c                          |   55 -
 src/crypto/crc32.c                            |    3 +-
 src/crypto/crypto_null.c                      |   52 +-
 src/crypto/drbg.c                             |  427 +
 src/crypto/entropy.c                          |  479 ++
 src/crypto/hash_df.c                          |  138 +
 src/crypto/hmac.c                             |    3 +-
 src/crypto/hmac_drbg.c                        |  359 +
 src/crypto/md5.c                              |  424 +-
 src/crypto/null_entropy.c                     |   36 +
 src/crypto/ocsp.c                             |  824 ++
 src/crypto/random_nz.c                        |   76 +
 src/crypto/rbg.c                              |  115 +
 src/crypto/rootcert.c                         |  133 +
 src/crypto/rsa.c                              |  642 ++
 src/crypto/sha1.c                             |  272 +
 src/crypto/sha1extra.c                        |   37 +-
 src/crypto/sha256.c                           |  256 +
 src/crypto/x509.c                             | 1636 +++-
 src/drivers/bitbash/bitbash.c                 |    3 +-
 src/drivers/bitbash/i2c_bit.c                 |   14 +-
 src/drivers/bitbash/spi_bit.c                 |    9 +-
 src/drivers/block/ata.c                       |    3 +-
 src/drivers/block/ibft.c                      |    3 +
 src/drivers/block/scsi.c                      |   33 +-
 src/drivers/bus/isa.c                         |    6 +-
 src/drivers/bus/isapnp.c                      |    3 +-
 src/drivers/bus/pci.c                         |    3 +-
 src/drivers/bus/pcibackup.c                   |    3 +-
 src/drivers/bus/pcivpd.c                      |    3 +-
 src/drivers/infiniband/arbel.c                |  909 ++-
 src/drivers/infiniband/arbel.h                |   36 +-
 src/drivers/infiniband/hermon.c               | 2550 +++---
 src/drivers/infiniband/hermon.h               |   35 +-
 src/drivers/infiniband/linda.c                |   20 +-
 src/drivers/infiniband/linda.h                |    3 +-
 src/drivers/infiniband/mlx_bitops.h           |    3 +-
 src/drivers/infiniband/qib7322.c              |   23 +-
 src/drivers/infiniband/qib7322.h              |    3 +-
 src/drivers/infiniband/qib_genbits.pl         |    3 +-
 src/drivers/net/3c509-eisa.c                  |    1 -
 src/drivers/net/3c509.h                       |    2 +-
 src/drivers/net/3c515.c                       |    5 +-
 src/drivers/net/3c595.c                       |    2 +-
 src/drivers/net/amd8111e.c                    |    3 +-
 src/drivers/net/amd8111e.h                    |    5 +-
 src/drivers/net/ath/ath.h                     |  239 +
 src/drivers/net/ath/ath5k/ath5k.c             | 1698 ++++
 src/drivers/net/ath/ath5k/ath5k.h             | 1279 +++
 src/drivers/net/ath/ath5k/ath5k_attach.c      |  340 +
 src/drivers/net/ath/ath5k/ath5k_caps.c        |  154 +
 src/drivers/net/ath/ath5k/ath5k_desc.c        |  544 ++
 src/drivers/net/ath/ath5k/ath5k_dma.c         |  631 ++
 src/drivers/net/ath/ath5k/ath5k_eeprom.c      | 1760 ++++
 src/drivers/net/ath/ath5k/ath5k_gpio.c        |  122 +
 src/drivers/net/ath/ath5k/ath5k_initvals.c    | 1560 ++++
 src/drivers/net/ath/ath5k/ath5k_pcu.c         |  534 ++
 src/drivers/net/ath/ath5k/ath5k_phy.c         | 2581 ++++++
 src/drivers/net/ath/ath5k/ath5k_qcu.c         |  390 +
 src/drivers/net/ath/ath5k/ath5k_reset.c       | 1174 +++
 src/drivers/net/ath/ath5k/ath5k_rfkill.c      |  107 +
 src/drivers/net/ath/ath5k/base.h              |  145 +
 src/drivers/net/ath/ath5k/desc.h              |  332 +
 src/drivers/net/ath/ath5k/eeprom.h            |  451 +
 src/drivers/net/ath/ath5k/reg.h               | 2589 ++++++
 src/drivers/net/ath/ath5k/rfbuffer.h          | 1181 +++
 src/drivers/net/ath/ath5k/rfgain.h            |  516 ++
 src/drivers/net/ath/ath9k/ani.h               |  168 +
 src/drivers/net/ath/ath9k/ar5008_initvals.h   |  672 ++
 src/drivers/net/ath/ath9k/ar9001_initvals.h   | 1356 +++
 src/drivers/net/ath/ath9k/ar9002_initvals.h   | 3264 ++++++++
 src/drivers/net/ath/ath9k/ar9002_phy.h        |  613 ++
 .../net/ath/ath9k/ar9003_2p2_initvals.h       | 1864 +++++
 src/drivers/net/ath/ath9k/ar9003_eeprom.h     |  338 +
 src/drivers/net/ath/ath9k/ar9003_mac.h        |  125 +
 src/drivers/net/ath/ath9k/ar9003_phy.h        | 1124 +++
 src/drivers/net/ath/ath9k/ar9340_initvals.h   | 1525 ++++
 src/drivers/net/ath/ath9k/ar9485_initvals.h   | 1161 +++
 src/drivers/net/ath/ath9k/ath9k.c             |  208 +
 src/drivers/net/ath/ath9k/ath9k.h             |  521 ++
 src/drivers/net/ath/ath9k/ath9k_ani.c         |  733 ++
 src/drivers/net/ath/ath9k/ath9k_ar5008_phy.c  | 1663 ++++
 .../net/ath/ath9k/ath9k_ar9002_calib.c        |  997 +++
 src/drivers/net/ath/ath9k/ath9k_ar9002_hw.c   |  607 ++
 src/drivers/net/ath/ath9k/ath9k_ar9002_mac.c  |  454 ++
 src/drivers/net/ath/ath9k/ath9k_ar9002_phy.c  |  578 ++
 .../net/ath/ath9k/ath9k_ar9003_calib.c        |  932 +++
 .../net/ath/ath9k/ath9k_ar9003_eeprom.c       | 5005 ++++++++++++
 src/drivers/net/ath/ath9k/ath9k_ar9003_hw.c   |  409 +
 src/drivers/net/ath/ath9k/ath9k_ar9003_mac.c  |  669 ++
 src/drivers/net/ath/ath9k/ath9k_ar9003_phy.c  | 1277 +++
 src/drivers/net/ath/ath9k/ath9k_calib.c       |  403 +
 src/drivers/net/ath/ath9k/ath9k_common.c      |   69 +
 src/drivers/net/ath/ath9k/ath9k_eeprom.c      |  551 ++
 src/drivers/net/ath/ath9k/ath9k_eeprom_4k.c   | 1078 +++
 src/drivers/net/ath/ath9k/ath9k_eeprom_9287.c | 1019 +++
 src/drivers/net/ath/ath9k/ath9k_eeprom_def.c  | 1351 +++
 src/drivers/net/ath/ath9k/ath9k_hw.c          | 2067 +++++
 src/drivers/net/ath/ath9k/ath9k_init.c        |  593 ++
 src/drivers/net/ath/ath9k/ath9k_mac.c         |  733 ++
 src/drivers/net/ath/ath9k/ath9k_main.c        |  916 +++
 src/drivers/net/ath/ath9k/ath9k_recv.c        |  521 ++
 src/drivers/net/ath/ath9k/ath9k_xmit.c        |  813 ++
 src/drivers/net/ath/ath9k/calib.h             |  115 +
 src/drivers/net/ath/ath9k/common.h            |   56 +
 src/drivers/net/ath/ath9k/eeprom.h            |  714 ++
 src/drivers/net/ath/ath9k/hw-ops.h            |  268 +
 src/drivers/net/ath/ath9k/hw.h                |  995 +++
 src/drivers/net/ath/ath9k/mac.h               |  707 ++
 src/drivers/net/ath/ath9k/phy.h               |   51 +
 src/drivers/net/ath/ath9k/reg.h               | 1919 +++++
 src/drivers/net/ath/ath_hw.c                  |  183 +
 src/drivers/net/ath/ath_key.c                 |   82 +
 src/drivers/net/ath/ath_main.c                |   59 +
 src/drivers/net/ath/ath_regd.c                |  602 ++
 src/drivers/net/ath/reg.h                     |   64 +
 src/drivers/net/ath/regd.h                    |  263 +
 src/drivers/net/ath/regd_common.h             |  481 ++
 src/drivers/net/ath5k/ath5k.c                 | 1698 ----
 src/drivers/net/ath5k/ath5k.h                 | 1279 ---
 src/drivers/net/ath5k/ath5k_attach.c          |  340 -
 src/drivers/net/ath5k/ath5k_caps.c            |  154 -
 src/drivers/net/ath5k/ath5k_desc.c            |  544 --
 src/drivers/net/ath5k/ath5k_dma.c             |  631 --
 src/drivers/net/ath5k/ath5k_eeprom.c          | 1760 ----
 src/drivers/net/ath5k/ath5k_gpio.c            |  122 -
 src/drivers/net/ath5k/ath5k_initvals.c        | 1560 ----
 src/drivers/net/ath5k/ath5k_pcu.c             |  534 --
 src/drivers/net/ath5k/ath5k_phy.c             | 2581 ------
 src/drivers/net/ath5k/ath5k_qcu.c             |  390 -
 src/drivers/net/ath5k/ath5k_reset.c           | 1174 ---
 src/drivers/net/ath5k/ath5k_rfkill.c          |  107 -
 src/drivers/net/ath5k/base.h                  |  145 -
 src/drivers/net/ath5k/desc.h                  |  332 -
 src/drivers/net/ath5k/eeprom.h                |  451 -
 src/drivers/net/ath5k/reg.h                   | 2589 ------
 src/drivers/net/ath5k/rfbuffer.h              | 1181 ---
 src/drivers/net/ath5k/rfgain.h                |  516 --
 src/drivers/net/atl1e.c                       |    4 +-
 src/drivers/net/atl1e.h                       |    4 +-
 src/drivers/net/b44.c                         |   60 +-
 src/drivers/net/b44.h                         |    3 +-
 src/drivers/net/cs89x0.c                      |    3 +-
 src/drivers/net/cs89x0.h                      |    3 +-
 src/drivers/net/davicom.c                     |    8 +-
 src/drivers/net/depca.c                       |    1 -
 src/drivers/net/dmfe.c                        |   23 +-
 src/drivers/net/e1000/e1000.c                 |   35 -
 src/drivers/net/e1000/e1000.h                 |  326 -
 src/drivers/net/e1000/e1000_82540.c           |  754 --
 src/drivers/net/e1000/e1000_82541.c           | 1314 ---
 src/drivers/net/e1000/e1000_82541.h           |   86 -
 src/drivers/net/e1000/e1000_82542.c           |  571 --
 src/drivers/net/e1000/e1000_82543.c           | 1635 ----
 src/drivers/net/e1000/e1000_82543.h           |   45 -
 src/drivers/net/e1000/e1000_api.c             | 1108 ---
 src/drivers/net/e1000/e1000_api.h             |  127 -
 src/drivers/net/e1000/e1000_defines.h         | 1416 ----
 src/drivers/net/e1000/e1000_hw.h              |  728 --
 src/drivers/net/e1000/e1000_mac.c             | 2196 -----
 src/drivers/net/e1000/e1000_mac.h             |   94 -
 src/drivers/net/e1000/e1000_main.c            |  909 ---
 src/drivers/net/e1000/e1000_manage.c          |  389 -
 src/drivers/net/e1000/e1000_manage.h          |   84 -
 src/drivers/net/e1000/e1000_nvm.c             |  923 ---
 src/drivers/net/e1000/e1000_nvm.h             |   63 -
 src/drivers/net/e1000/e1000_osdep.h           |  118 -
 src/drivers/net/e1000/e1000_phy.c             | 2308 ------
 src/drivers/net/e1000/e1000_phy.h             |  171 -
 src/drivers/net/e1000/e1000_regs.h            |  329 -
 src/drivers/net/e1000e/e1000e.c               |   34 -
 src/drivers/net/e1000e/e1000e.h               |  532 --
 src/drivers/net/e1000e/e1000e_80003es2lan.c   | 1533 ----
 src/drivers/net/e1000e/e1000e_80003es2lan.h   |  100 -
 src/drivers/net/e1000e/e1000e_82571.c         | 1818 -----
 src/drivers/net/e1000e/e1000e_82571.h         |   55 -
 src/drivers/net/e1000e/e1000e_defines.h       | 1469 ----
 src/drivers/net/e1000e/e1000e_hw.h            |  719 --
 src/drivers/net/e1000e/e1000e_ich8lan.c       | 3444 --------
 src/drivers/net/e1000e/e1000e_ich8lan.h       |  196 -
 src/drivers/net/e1000e/e1000e_mac.c           | 1883 -----
 src/drivers/net/e1000e/e1000e_mac.h           |   79 -
 src/drivers/net/e1000e/e1000e_main.c          | 1265 ---
 src/drivers/net/e1000e/e1000e_manage.c        |  372 -
 src/drivers/net/e1000e/e1000e_manage.h        |   86 -
 src/drivers/net/e1000e/e1000e_nvm.c           |  596 --
 src/drivers/net/e1000e/e1000e_nvm.h           |   53 -
 src/drivers/net/e1000e/e1000e_phy.c           | 3323 --------
 src/drivers/net/e1000e/e1000e_phy.h           |  261 -
 src/drivers/net/e1000e/e1000e_regs.h          |  340 -
 src/drivers/net/eepro100.c                    |    6 +-
 src/drivers/net/efi/snpnet.c                  |   45 +-
 src/drivers/net/epic100.c                     |    9 +-
 src/drivers/net/epic100.h                     |    2 +-
 src/drivers/net/etherfabric.c                 |   11 +-
 src/drivers/net/forcedeth.c                   |   13 +-
 src/drivers/net/forcedeth.h                   |    5 +-
 src/drivers/net/igb/igb.c                     |   32 -
 src/drivers/net/igb/igb.h                     |  324 -
 src/drivers/net/igb/igb_82575.c               | 1617 ----
 src/drivers/net/igb/igb_82575.h               |  442 -
 src/drivers/net/igb/igb_api.c                 | 1108 ---
 src/drivers/net/igb/igb_api.h                 |  166 -
 src/drivers/net/igb/igb_defines.h             | 1515 ----
 src/drivers/net/igb/igb_hw.h                  |  697 --
 src/drivers/net/igb/igb_mac.c                 | 1991 -----
 src/drivers/net/igb/igb_mac.h                 |   82 -
 src/drivers/net/igb/igb_main.c                | 1010 ---
 src/drivers/net/igb/igb_manage.c              |  388 -
 src/drivers/net/igb/igb_manage.h              |   83 -
 src/drivers/net/igb/igb_nvm.c                 |  627 --
 src/drivers/net/igb/igb_nvm.h                 |   52 -
 src/drivers/net/igb/igb_osdep.h               |  129 -
 src/drivers/net/igb/igb_phy.c                 | 2470 ------
 src/drivers/net/igb/igb_phy.h                 |  171 -
 src/drivers/net/igb/igb_regs.h                |  486 --
 src/drivers/net/igbvf/igbvf_main.c            |    3 +-
 src/drivers/net/igbvf/igbvf_vf.h              |    1 +
 src/drivers/net/intel.c                       |  959 +++
 src/drivers/net/intel.h                       |  257 +
 src/drivers/net/ipoib.c                       |  655 +-
 src/drivers/net/jme.c                         |    3 +-
 src/drivers/net/jme.h                         |    3 +-
 src/drivers/net/mii.c                         |  113 +
 src/drivers/net/mtd80x.c                      | 1022 ---
 src/drivers/net/myri10ge.c                    |   11 +-
 src/drivers/net/myri10ge_mcp.h                |    5 +-
 src/drivers/net/myson.c                       |  670 ++
 src/drivers/net/myson.h                       |  200 +
 src/drivers/net/natsemi.c                     | 1287 +--
 src/drivers/net/natsemi.h                     |  485 +-
 src/drivers/net/ns83820.c                     | 1007 ---
 src/drivers/net/p80211hdr.h                   |    2 +-
 src/drivers/net/pcnet32.c                     |    5 +-
 src/drivers/net/pcnet32.h                     |    3 +-
 src/drivers/net/phantom/nx_bitops.h           |    3 +-
 src/drivers/net/phantom/phantom.c             |    3 +-
 src/drivers/net/phantom/phantom.h             |    3 +-
 src/drivers/net/phantom/phantom_hw.h          |    3 +-
 src/drivers/net/r8169.c                       | 2232 -----
 src/drivers/net/r8169.h                       |  486 --
 src/drivers/net/realtek.c                     | 1169 +++
 src/drivers/net/realtek.h                     |  286 +
 src/drivers/net/rtl8139.c                     |  596 --
 src/drivers/net/sis190.h                      |    4 +-
 src/drivers/net/sis900.c                      |   10 +-
 src/drivers/net/skeleton.c                    |  310 +
 src/drivers/net/skeleton.h                    |   23 +
 src/drivers/net/skge.c                        |    3 +-
 src/drivers/net/skge.h                        |    8 +-
 src/drivers/net/sky2.c                        |    7 +-
 src/drivers/net/sky2.h                        |    6 +-
 src/drivers/net/smc9000.h                     |    4 +-
 src/drivers/net/sundance.c                    |    9 +-
 src/drivers/net/tg3.c                         | 3435 --------
 src/drivers/net/tg3.h                         | 2121 -----
 src/drivers/net/tg3/tg3.c                     |  945 +++
 src/drivers/net/tg3/tg3.h                     | 3431 ++++++++
 src/drivers/net/tg3/tg3_hw.c                  | 2661 ++++++
 src/drivers/net/tg3/tg3_phy.c                 | 1603 ++++
 src/drivers/net/tlan.c                        |    9 +-
 src/drivers/net/tlan.h                        |    3 +-
 src/drivers/net/via-rhine.c                   |   10 +-
 src/drivers/net/via-velocity.c                |    5 +-
 src/drivers/net/via-velocity.h                |    2 +-
 src/drivers/net/virtio-net.c                  |    2 +-
 src/drivers/net/vmxnet3.c                     |  670 ++
 src/drivers/net/vmxnet3.h                     |  498 ++
 src/drivers/net/vxge/vxge_main.c              |    2 +-
 src/drivers/net/w89c840.c                     |    3 +-
 src/drivers/nvs/nvs.c                         |    3 +-
 src/drivers/nvs/nvsvpd.c                      |    3 +-
 src/drivers/nvs/spi.c                         |    3 +-
 src/drivers/nvs/threewire.c                   |    3 +-
 src/hci/commands/autoboot_cmd.c               |    3 +-
 src/hci/commands/config_cmd.c                 |    3 +-
 src/hci/commands/dhcp_cmd.c                   |    3 +-
 src/hci/commands/digest_cmd.c                 |    8 +-
 src/hci/commands/fcmgmt_cmd.c                 |    3 +-
 src/hci/commands/gdbstub_cmd.c                |    3 +-
 src/hci/commands/ifmgmt_cmd.c                 |    3 +-
 src/hci/commands/image_cmd.c                  |  433 +-
 src/hci/commands/image_trust_cmd.c            |  173 +
 src/hci/commands/iwmgmt_cmd.c                 |    3 +-
 src/hci/commands/login_cmd.c                  |    3 +-
 src/hci/commands/lotest_cmd.c                 |    3 +-
 src/hci/commands/menu_cmd.c                   |  286 +
 src/hci/commands/nslookup_cmd.c               |   79 +
 src/hci/commands/nvo_cmd.c                    |   42 +-
 src/hci/commands/route_cmd.c                  |    3 +-
 src/hci/commands/sanboot_cmd.c                |  137 +-
 src/hci/commands/sync_cmd.c                   |   83 +
 src/hci/commands/time_cmd.c                   |   52 +-
 src/hci/commands/vlan_cmd.c                   |    3 +-
 src/hci/editstring.c                          |   19 +-
 src/hci/keymap/keymap_no-latin1.c             |   34 +
 src/hci/mucurses/ansi_screen.c                |   16 +-
 src/hci/mucurses/mucurses.c                   |    1 -
 src/hci/mucurses/widgets/editbox.c            |    3 +-
 src/hci/readline.c                            |   40 +-
 src/hci/shell.c                               |    5 +-
 src/hci/tui/login_ui.c                        |   18 +-
 src/hci/tui/menu_ui.c                         |  370 +
 src/hci/tui/settings_ui.c                     |   14 +-
 src/hci/wireless_errors.c                     |    3 +-
 src/image/efi_image.c                         |  190 +-
 src/image/elf.c                               |   32 +-
 src/image/script.c                            |   42 +-
 src/image/segment.c                           |    3 +-
 src/include/assert.h                          |    3 +
 src/include/btext.h                           |   62 -
 src/include/compiler.h                        |   19 +-
 src/include/errno.h                           |    3 +-
 src/include/etherboot.h                       |    1 -
 src/include/hci/ifmgmt_cmd.h                  |    3 +-
 src/include/ipxe/aes.h                        |    4 +
 src/include/ipxe/ansiesc.h                    |    7 +
 src/include/ipxe/arp.h                        |    8 +-
 src/include/ipxe/asn1.h                       |  287 +-
 src/include/ipxe/bigint.h                     |  301 +
 src/include/ipxe/bitbash.h                    |   32 +
 src/include/ipxe/bitops.h                     |    3 +-
 src/include/ipxe/clientcert.h                 |   43 +
 src/include/ipxe/cms.h                        |   75 +
 src/include/ipxe/console.h                    |   61 +-
 src/include/ipxe/crypto.h                     |  100 +-
 src/include/ipxe/dhcp.h                       |   86 +-
 src/include/ipxe/drbg.h                       |  135 +
 src/include/ipxe/eapol.h                      |    3 +-
 src/include/ipxe/efi/Base.h                   |   51 +-
 src/include/ipxe/efi/Guid/FileInfo.h          |   73 +
 src/include/ipxe/efi/Guid/FileSystemInfo.h    |   65 +
 src/include/ipxe/efi/Guid/WinCertificate.h    |    4 +-
 src/include/ipxe/efi/Ia32/ProcessorBind.h     |   22 +-
 src/include/ipxe/efi/IndustryStandard/Pci22.h |   12 +-
 src/include/ipxe/efi/Library/BaseLib.h        | 7250 +++++++++++++++++
 src/include/ipxe/efi/Pi/PiBootMode.h          |    5 +-
 src/include/ipxe/efi/Pi/PiDxeCis.h            |   13 +-
 src/include/ipxe/efi/Pi/PiFirmwareFile.h      |   24 +-
 src/include/ipxe/efi/Pi/PiFirmwareVolume.h    |   13 +-
 src/include/ipxe/efi/Pi/PiHob.h               |   21 +-
 src/include/ipxe/efi/Pi/PiStatusCode.h        |   78 +-
 src/include/ipxe/efi/Protocol/BlockIo.h       |  243 +
 .../ipxe/efi/Protocol/ComponentName2.h        |    5 +-
 src/include/ipxe/efi/Protocol/Cpu.h           |    4 +-
 src/include/ipxe/efi/Protocol/DevicePath.h    |  235 +-
 .../ipxe/efi/Protocol/DevicePathToText.h      |   87 +
 src/include/ipxe/efi/Protocol/FormBrowser2.h  |    4 +
 .../ipxe/efi/Protocol/HiiConfigAccess.h       |    6 +
 src/include/ipxe/efi/Protocol/LoadFile.h      |   90 +
 .../efi/Protocol/NetworkInterfaceIdentifier.h |   25 +-
 .../ipxe/efi/Protocol/PciRootBridgeIo.h       |   10 +-
 .../ipxe/efi/Protocol/SimpleFileSystem.h      |  403 +
 src/include/ipxe/efi/Protocol/SimpleTextIn.h  |    4 +-
 .../ipxe/efi/Protocol/SimpleTextInEx.h        |  327 +
 src/include/ipxe/efi/Uefi/UefiBaseType.h      |    4 +-
 src/include/ipxe/efi/Uefi/UefiGpt.h           |    3 +-
 .../efi/Uefi/UefiInternalFormRepresentation.h |   39 +-
 src/include/ipxe/efi/Uefi/UefiMultiPhase.h    |   42 +-
 src/include/ipxe/efi/Uefi/UefiSpec.h          |  123 +-
 src/include/ipxe/efi/X64/ProcessorBind.h      |    6 +-
 src/include/ipxe/efi/efi.h                    |   53 +-
 src/include/ipxe/efi/efi_download.h           |  157 +
 src/include/ipxe/efi/efi_file.h               |   13 +
 src/include/ipxe/efi/efi_hii.h                |  192 +-
 src/include/ipxe/efi/efi_pci.h                |    5 +
 src/include/ipxe/efi/efi_snp.h                |   79 +
 src/include/ipxe/efi/efi_uaccess.h            |    6 +
 src/include/ipxe/efi/import.pl                |   15 +-
 src/include/ipxe/elf.h                        |    2 +-
 src/include/ipxe/eltorito.h                   |  103 +
 src/include/ipxe/entropy.h                    |  224 +
 src/include/ipxe/errfile.h                    |   28 +-
 src/include/ipxe/ethernet.h                   |    9 +
 src/include/ipxe/fc.h                         |   77 +-
 src/include/ipxe/features.h                   |    2 +
 src/include/ipxe/fip.h                        |    3 +-
 src/include/ipxe/hash_df.h                    |   18 +
 src/include/ipxe/hmac_drbg.h                  |  253 +
 src/include/ipxe/http.h                       |    1 +
 src/include/ipxe/ib_packet.h                  |    5 +-
 src/include/ipxe/image.h                      |   44 +-
 src/include/ipxe/infiniband.h                 |   31 +-
 src/include/ipxe/iobuf.h                      |   14 +-
 src/include/ipxe/ip.h                         |   25 +-
 src/include/ipxe/ipoib.h                      |   42 +-
 src/include/ipxe/isapnp.h                     |    3 +-
 src/include/ipxe/iscsi.h                      |    4 +-
 src/include/ipxe/iso9660.h                    |   44 +
 src/include/ipxe/lineconsole.h                |   36 +
 src/include/ipxe/linux/linux_entropy.h        |   32 +
 src/include/ipxe/linux/linux_time.h           |   18 +
 src/include/ipxe/linux/linux_uaccess.h        |    6 +
 src/include/ipxe/list.h                       |  385 +-
 src/include/ipxe/malloc.h                     |   38 +-
 src/include/ipxe/md5.h                        |   69 +-
 src/include/ipxe/memblock.h                   |   17 +
 src/include/ipxe/menu.h                       |   49 +
 src/include/ipxe/mii.h                        |   87 +
 src/include/ipxe/net80211.h                   |    2 +-
 src/include/ipxe/netdevice.h                  |   39 +-
 src/include/ipxe/null_entropy.h               |   52 +
 src/include/ipxe/null_sanboot.h               |    5 +
 src/include/ipxe/null_time.h                  |   23 +
 src/include/ipxe/nvo.h                        |    4 +
 src/include/ipxe/ocsp.h                       |  102 +
 src/include/ipxe/parseopt.h                   |    7 +-
 src/include/ipxe/pci.h                        |    5 +-
 src/include/ipxe/pending.h                    |   34 +
 src/include/ipxe/process.h                    |  140 +-
 src/include/ipxe/random_nz.h                  |   16 +
 src/include/ipxe/rbg.h                        |   43 +
 src/include/ipxe/retry.h                      |    1 +
 src/include/ipxe/rootcert.h                   |   16 +
 src/include/ipxe/rotate.h                     |   12 +-
 src/include/ipxe/rsa.h                        |   75 +-
 src/include/ipxe/sanboot.h                    |   11 +-
 src/include/ipxe/sec80211.h                   |    3 +-
 src/include/ipxe/serial.h                     |    1 +
 src/include/ipxe/settings.h                   |   61 +-
 src/include/ipxe/sha1.h                       |   78 +-
 src/include/ipxe/sha256.h                     |   73 +
 src/include/ipxe/smbios.h                     |   12 +
 src/include/ipxe/syslog.h                     |   13 +-
 src/include/ipxe/tcp.h                        |   78 +-
 src/include/ipxe/tcpip.h                      |   12 +-
 src/include/ipxe/test.h                       |   45 +
 src/include/ipxe/tftp.h                       |    2 -
 src/include/ipxe/threewire.h                  |   13 +
 src/include/ipxe/time.h                       |   59 +
 src/include/ipxe/tls.h                        |  161 +-
 src/include/ipxe/uaccess.h                    |   21 +
 src/include/ipxe/uuid.h                       |   21 +-
 src/include/ipxe/validator.h                  |   17 +
 src/include/ipxe/version.h                    |   16 +
 src/include/ipxe/vlan.h                       |    1 +
 src/include/ipxe/wpa.h                        |    3 +-
 src/include/ipxe/x509.h                       |  376 +-
 src/include/ipxe/xferbuf.h                    |   31 +
 src/include/linux_api.h                       |    1 -
 src/include/mii.h                             |  288 +-
 src/include/readline/readline.h               |    4 +-
 src/include/stdarg.h                          |   26 +
 src/include/stddef.h                          |    1 +
 src/include/stdio.h                           |    4 +
 src/include/stdlib.h                          |    4 -
 src/include/string.h                          |    1 +
 src/include/sys/time.h                        |   24 +-
 src/include/syslog.h                          |  100 +
 src/include/time.h                            |   51 +-
 src/include/usr/autoboot.h                    |   15 +-
 src/include/usr/imgmgmt.h                     |   43 +-
 src/include/usr/imgtrust.h                    |   17 +
 src/include/usr/nslookup.h                    |   14 +
 src/include/wchar.h                           |   29 +
 src/interface/bofm/bofm.c                     |   24 +-
 src/interface/efi/efi_bofm.c                  |  120 +-
 src/interface/efi/efi_console.c               |   11 +-
 src/interface/efi/efi_debug.c                 |  114 +
 src/interface/efi/efi_download.c              |  225 +
 src/interface/efi/efi_driver.c                |   30 +-
 src/interface/efi/efi_file.c                  |  593 ++
 src/interface/efi/efi_hii.c                   |  577 ++
 src/interface/efi/efi_init.c                  |   16 +-
 src/interface/efi/efi_io.c                    |    3 +-
 src/interface/efi/efi_pci.c                   |   25 +-
 src/interface/efi/efi_smbios.c                |    5 +-
 src/interface/efi/efi_snp.c                   |  525 +-
 src/interface/efi/efi_snp_hii.c               |  707 ++
 src/interface/efi/efi_strerror.c              |    3 +-
 src/interface/efi/efi_strings.c               |    3 +-
 src/interface/efi/efi_timer.c                 |    3 +-
 src/interface/efi/efi_uaccess.c               |    3 +-
 src/interface/efi/efi_umalloc.c               |    3 +-
 src/interface/linux/linux_console.c           |    9 +
 src/interface/linux/linux_entropy.c           |   97 +
 src/interface/linux/linux_nap.c               |    3 +-
 src/interface/linux/linux_time.c              |   45 +
 src/interface/linux/linux_uaccess.c           |    3 +-
 src/interface/smbios/smbios.c                 |   20 +-
 src/interface/smbios/smbios_settings.c        |   51 +-
 src/net/80211/net80211.c                      |   39 +-
 src/net/80211/rc80211.c                       |    3 +-
 src/net/80211/sec80211.c                      |    3 +-
 src/net/80211/wep.c                           |    3 +-
 src/net/80211/wpa.c                           |    8 +-
 src/net/80211/wpa_ccmp.c                      |    4 +-
 src/net/80211/wpa_psk.c                       |    4 +-
 src/net/80211/wpa_tkip.c                      |   12 +-
 src/net/aoe.c                                 |    8 +-
 src/net/arp.c                                 |  456 +-
 src/net/cachedhcp.c                           |    3 +-
 src/net/dhcpopts.c                            |    3 +-
 src/net/dhcppkt.c                             |    3 +-
 src/net/eapol.c                               |    7 +-
 src/net/eth_slow.c                            |    7 +-
 src/net/ethernet.c                            |   22 +-
 src/net/fakedhcp.c                            |   12 +-
 src/net/fc.c                                  |   91 +-
 src/net/fcels.c                               |   19 +-
 src/net/fcns.c                                |   19 +-
 src/net/fcoe.c                                |   11 +-
 src/net/fcp.c                                 |   71 +-
 src/net/icmp.c                                |    3 +-
 src/net/infiniband.c                          |   72 +-
 src/net/infiniband/ib_cm.c                    |    3 +-
 src/net/infiniband/ib_cmrc.c                  |   33 +-
 src/net/infiniband/ib_mcast.c                 |    3 +-
 src/net/infiniband/ib_mi.c                    |   19 +-
 src/net/infiniband/ib_packet.c                |   66 +-
 src/net/infiniband/ib_pathrec.c               |    3 +-
 src/net/infiniband/ib_sma.c                   |    3 +-
 src/net/infiniband/ib_smc.c                   |    3 +-
 src/net/iobpad.c                              |    3 +-
 src/net/ipv4.c                                |  454 +-
 src/net/ipv6.c                                |    4 +-
 src/net/mii.c                                 |  147 -
 src/net/netdev_settings.c                     |    3 +-
 src/net/netdevice.c                           |  138 +-
 src/net/nullnet.c                             |    3 +-
 src/net/rarp.c                                |    7 +-
 src/net/retry.c                               |   26 +-
 src/net/tcp.c                                 |  174 +-
 src/net/tcp/ftp.c                             |  100 +-
 src/net/tcp/http.c                            |  519 +-
 src/net/tcp/httpcore.c                        | 1363 ++++
 src/net/tcp/https.c                           |    3 +-
 src/net/tcp/iscsi.c                           |  146 +-
 src/net/tcp/syslogs.c                         |  274 +
 src/net/tcpip.c                               |    4 +-
 src/net/tls.c                                 | 1759 +++-
 src/net/udp.c                                 |    7 +-
 src/net/udp/dhcp.c                            |   80 +-
 src/net/udp/dns.c                             |   37 +-
 src/net/udp/slam.c                            |    3 +-
 src/net/udp/syslog.c                          |  142 +-
 src/net/udp/tftp.c                            |   39 +-
 src/net/validator.c                           |  576 ++
 src/net/vlan.c                                |   27 +-
 src/tests/aes_cbc_test.c                      |  193 +
 src/tests/base64_test.c                       |  124 +
 src/tests/bigint_test.c                       | 2437 ++++++
 src/tests/bofm_test.c                         |    3 +-
 src/tests/byteswap_test.c                     |   92 +
 src/tests/cbc_test.c                          |  171 +
 src/tests/cbc_test.h                          |   57 +
 src/tests/cms_test.c                          | 1438 ++++
 src/tests/crc32_test.c                        |  116 +
 src/tests/digest_test.c                       |  105 +
 src/tests/digest_test.h                       |   37 +
 src/tests/entropy_sample.c                    |   72 +
 src/tests/hash_df_test.c                      |  898 ++
 src/tests/hmac_drbg_test.c                    | 1386 ++++
 src/tests/list_test.c                         |  483 ++
 src/tests/md5_test.c                          |  100 +
 src/tests/memcpy_test.c                       |  290 +-
 src/tests/ocsp_test.c                         | 1450 ++++
 src/tests/pubkey_test.h                       |  175 +
 src/tests/rsa_test.c                          |  492 ++
 src/tests/settings_test.c                     |  278 +
 src/tests/sha1_test.c                         |  105 +
 src/tests/sha256_test.c                       |  108 +
 src/tests/string_test.c                       |  133 +
 src/tests/tcpip_test.c                        |  213 +
 src/tests/test.c                              |  174 +
 src/tests/tests.c                             |   48 +
 src/tests/time_test.c                         |  183 +
 src/tests/x509_test.c                         |  948 +++
 src/usr/autoboot.c                            |  207 +-
 src/usr/dhcpmgmt.c                            |   15 +-
 src/usr/fcmgmt.c                              |    6 +-
 src/usr/ifmgmt.c                              |    6 +-
 src/usr/imgmgmt.c                             |  202 +-
 src/usr/imgtrust.c                            |  110 +
 src/usr/iwmgmt.c                              |    4 +-
 src/usr/lotest.c                              |  149 +-
 src/usr/nslookup.c                            |  185 +
 src/usr/prompt.c                              |    3 +-
 src/usr/pxemenu.c                             |    5 +-
 src/usr/route.c                               |    3 +-
 src/util/Makefile                             |   10 +-
 src/util/Option/ROM.pm                        |  236 +-
 src/util/catrom.pl                            |   49 +-
 src/util/disrom.pl                            |  130 +-
 src/util/efirom.c                             |   21 +-
 src/util/einfo.c                              |   21 +-
 src/util/elf2efi.c                            |   21 +-
 src/util/fixrom.pl                            |   13 +-
 src/util/fnrec.pl                             |    3 +-
 src/util/geniso                               |    2 +-
 src/util/genkeymap.pl                         |    9 +-
 src/util/get-pci-ids                          |    3 +-
 src/util/iccfix.c                             |    3 +-
 src/util/licence.pl                           |    3 +-
 src/util/mergerom.pl                          |   33 +-
 src/util/niclist.pl                           |  588 ++
 src/util/nrv2b.c                              |    7 +-
 src/util/parserom.pl                          |    4 +-
 src/util/romcheck.pl                          |   54 +
 src/util/zbin.c                               |   79 +-
 835 files changed, 134216 insertions(+), 94792 deletions(-)

diff --git a/roms/ipxe/contrib/rom-o-matic/bottom.php b/roms/ipxe/contrib/rom-o-matic/bottom.php
index ff094fd8d6168fb0ff005ad36c57..9ba8e3190a7519b37ba23b2019b2 100644
--- a/roms/ipxe/contrib/rom-o-matic/bottom.php
+++ b/roms/ipxe/contrib/rom-o-matic/bottom.php
@@ -1,4 +1,4 @@
-<?
+<?php
 
 /**
  * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
@@ -27,25 +27,25 @@ Resources:
 <ul>
   <li>
     Source code for iPXE images is available at
-    <a href="http://etherboot.org/wiki/download" target="_blank">
-    http://etherboot.org/wiki/download</a>
+    <a href="http://www.ipxe.org/download" target="_blank">
+    http://www.ipxe.org/download</a>
     <br><br>
   </li>
   <li>
     For general information about using iPXE, please visit the
-    <a href="http://www.etherboot.org/" target="_blank">
-    Etherboot Project Home Page</a>
+    <a href="http://www.ipxe.org/" target="_blank">
+    iPXE Project Home Page</a>
     <br><br>
   </li>
   <li>
     For Email-based support for iPXE please join
-    <a href="http://etherboot.org/wiki/mailinglists" target="_blank">
-    Etherboot Project mailing lists.</a>
+    <a href="http://www.ipxe.org/contact" target="_blank">
+    iPXE Project mailing lists.</a>
     <br><br>
   </li>
   <li>
     For real-time online iPXE support via IRC please visit the
-    <a href="irc://irc.freenode.net/%23etherboot"> #etherboot channel
+    <a href="irc://irc.freenode.net/%23ipxe"> #ipxe channel
     of irc.freenode.net</a>.
     <br><br>
   </li>
@@ -53,7 +53,7 @@ Resources:
 <hr>
   <font size="-1">
     <br>
-    Please email <a href="mailto:<? echo "${webmaster_email}" ?>"><? echo "${webmaster_email}"?></a>
+    Please email <a href="mailto:<?php echo "${webmaster_email}" ?>"><?php echo "${webmaster_email}"?></a>
     with questions or comments about this website.
   </font>
   <br><br>
diff --git a/roms/ipxe/contrib/rom-o-matic/build.php b/roms/ipxe/contrib/rom-o-matic/build.php
index 3101b3e39c4bf2a64f97ca305a01..b2b5bb4526af42d4b916fd61eff4 100644
--- a/roms/ipxe/contrib/rom-o-matic/build.php
+++ b/roms/ipxe/contrib/rom-o-matic/build.php
@@ -179,7 +179,12 @@ if ( $embedded_script != "" ) {
 
 // Make the requested image.  $status is set to 0 on success
 $make_target = "bin/${nic}.${fmt_extension}";
-$make_cmd = "make -C '$build_dir' '$make_target' $emb_script_cmd $2>&1";
+$gitversion = exec('git describe --always --abbrev=1 --match "" 2>/dev/null');
+if ($gitversion) {
+	$gitversion = "GITVERSION=$gitversion";
+}
+
+$make_cmd = "make -C '$build_dir' '$make_target' $gitversion $emb_script_cmd 2>&1";
 
 exec ( $make_cmd, $maketxt, $status );
 
@@ -239,7 +244,7 @@ if ( $status == 0 ) {
             // Delete build directory as soon as it is not needed
             rm_build_dir ();
 
-            $output_filename = "ipxe-${version}-${nic}.${fmt_extension}";
+            $output_filename = preg_replace('/[^a-z0-9\+\.\-]/i', '', "ipxe-${version}-${nic}.${fmt_extension}");
 
             // Try to force IE to handle downloading right.
             Header ( "Cache-control: private");
diff --git a/roms/ipxe/contrib/rom-o-matic/customize-flags.php b/roms/ipxe/contrib/rom-o-matic/customize-flags.php
index 23090439331a020cd35ce2d93843..e283921a894c45317d1a8e9ad8f7 100644
--- a/roms/ipxe/contrib/rom-o-matic/customize-flags.php
+++ b/roms/ipxe/contrib/rom-o-matic/customize-flags.php
@@ -34,30 +34,30 @@ include_once $top_inc;
 ?>
 
 <form action="build.php" method=POST>
-  <input type="hidden" name="version" value = "<? echo $version ?>">
+  <input type="hidden" name="version" value = "<?php echo $version ?>">
   <input type="hidden" name="use_flags" value="1">
   <h3>
-    Make changes below and press <? echo $build ?> to create an image, <br>
-    Or press <? echo $restart ?> to return to the main page.
+    Make changes below and press <?php echo $build ?> to create an image, <br>
+    Or press <?php echo $restart ?> to return to the main page.
   </h3>
   <hr>
   <ul>
-  <? require ( "directions.php" ); ?>
+  <?php require ( "directions.php" ); ?>
   </ul>
   <hr>
-  <? echo_flags( $flags ); ?>
+  <?php echo_flags( $flags ); ?>
   <hr>
   <h3>Embedded Script:</h3>
-  <? echo textarea ( "embedded_script", "", "10", "50" ); ?>
+  <?php echo textarea ( "embedded_script", "", "10", "50" ); ?>
   <br><br>
   <hr>
   <center><table width="35%"><tr>
-  <td align="left"> <? echo $build; ?> </td>
-  <td align="right"> <? echo $restart ?></td>
+  <td align="left"> <?php echo $build; ?> </td>
+  <td align="right"> <?php echo $restart ?></td>
   </tr></table></center>
 </form>
 
-<? include_once $bottom_inc; ?>
+<?php include_once $bottom_inc; ?>
 <?
 // For emacs:
 //
diff --git a/roms/ipxe/contrib/rom-o-matic/directions.php b/roms/ipxe/contrib/rom-o-matic/directions.php
index cba5eb44a689bab79f09fe428086..540121eddc0992019c8367cb03ab 100644
--- a/roms/ipxe/contrib/rom-o-matic/directions.php
+++ b/roms/ipxe/contrib/rom-o-matic/directions.php
@@ -1,4 +1,4 @@
-<?
+<?php
 
 /**
  * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
@@ -21,12 +21,12 @@
 
 ?>
     <li>
-      Choose an output format: <? echo keys_menubox ( "ofmt", $ofmts,
+      Choose an output format: <?php echo keys_menubox ( "ofmt", $ofmts,
       isset ( $_POST['ofmt'] ) ? $_POST['ofmt'] : "") ?>
       <br><br>
     </li>
     <li>
-      Choose a NIC type: <? echo keys_menubox ( "nic", $nics,
+      Choose a NIC type: <?php echo keys_menubox ( "nic", $nics,
       isset ( $_POST['nic'] ) ? $_POST['nic'] : "" ) ?>
       <br><br>
     </li>
@@ -37,14 +37,14 @@
       <em>PCI VENDOR CODE</em> and <em>PCI DEVICE CODE</em>  <br>
       that match the NIC device for which you are making this image.<br><br>
       Information on how to determine NIC PCI IDs may be found
-      <a href="http://etherboot.org/wiki/romburning"
+      <a href="http://www.ipxe.org/howto/romburning"
       target="_blank">here</a>.
       <br><br>
-      PCI VENDOR CODE:  <? echo textbox ( "pci_vendor_code",
+      PCI VENDOR CODE:  <?php echo textbox ( "pci_vendor_code",
       isset ( $_POST['pci_vendor_code'] ) ? $_POST['pci_vendor_code']
               : "", 6 ); ?>
       &nbsp;&nbsp;
-      PCI DEVICE CODE:  <? echo textbox ( "pci_device_code",
+      PCI DEVICE CODE:  <?php echo textbox ( "pci_device_code",
       isset ( $_POST['pci_device_code'] ) ? $_POST['pci_device_code']
               : "", 6 ); ?>
       <h4>Please note for ROM images:</h4>
diff --git a/roms/ipxe/contrib/rom-o-matic/flag-table.php b/roms/ipxe/contrib/rom-o-matic/flag-table.php
index 078e5fd6083f328ce267f0b8f69f..fe81c8029183e876f126a460edec 100644
--- a/roms/ipxe/contrib/rom-o-matic/flag-table.php
+++ b/roms/ipxe/contrib/rom-o-matic/flag-table.php
@@ -98,6 +98,27 @@ $flag_table = array (
 	   "cfgsec" => "general"
 	   ),
 
+        "KEYBOARD_MAP"
+        => array (
+           "flag" => "KEYBOARD_MAP",
+           "type" => "choice",
+	   "options" => array("al","az","bg","by","cf","cz","de","dk","es","et","fi","fr",
+	      "gr","hu","il","it","lt","mk","mt","nl","no","pl","pt","ro","ru","sg","sr",
+	      "th","ua","uk","us","wo"),
+           "value" => "us",
+           "cfgsec" => "console"
+           ),
+
+	"LOG_LEVEL"
+	=> array (
+	   "flag" => "LOG_LEVEL",
+	   "type" => "choice",
+	   "options" => array("LOG_NONE","LOG_EMERG","LOG_ALERT","LOG_CRIT","LOG_ERR",
+	      "LOG_WARNING","LOG_NOTICE","LOG_INFO","LOG_DEBUG","LOG_ALL"),
+	   "value" => "LOG_NONE",
+	   "cfgsec" => "console"
+	   ),
+
 	// End Console Options
 
 	// Begin Network Protocol Options:
@@ -487,6 +508,17 @@ $flag_table = array (
 
 	// End Wireless options
 
+	// Obscure options required to compile
+	"NETDEV_DISCARD_RATE"
+	=> array (
+	   "flag" => "NETDEV_DISCARD_RATE",
+	   "type" => "integer",
+	   "value" => "0",
+	   "cfgsec" => "general",
+	   "hide_from_user" => true
+	   )
+
+	// End Obscure options
 );
 
 // For emacs:
diff --git a/roms/ipxe/contrib/rom-o-matic/index.php b/roms/ipxe/contrib/rom-o-matic/index.php
index 12b7e1a80d9a6fecb498db063b38..26585c975829f0e5f5aaeffead9b 100644
--- a/roms/ipxe/contrib/rom-o-matic/index.php
+++ b/roms/ipxe/contrib/rom-o-matic/index.php
@@ -27,10 +27,10 @@ include_once $top_inc;
 
 ?>
 <form action="build.php" method=POST>
-  <input type="hidden" name="version" value = "<? echo $version ?>">
+  <input type="hidden" name="version" value = "<?php echo $version ?>">
   <h3>To create an image:</h3>
   <ol>
-    <? require ( "directions.php" ); ?>
+    <?php require ( "directions.php" ); ?>
     <li>
       Generate and download an image:
       <input type="submit" name="A" value="Get Image">
@@ -44,4 +44,4 @@ include_once $top_inc;
   </ol>
 </form>
 
-<? include_once $bottom_inc ?>
+<?php include_once $bottom_inc ?>
diff --git a/roms/ipxe/contrib/rom-o-matic/top.php b/roms/ipxe/contrib/rom-o-matic/top.php
index 25562086bde4e4c5f3e83a882ecf..42a8e2d275ffafd4a4c6c5d9f096 100644
--- a/roms/ipxe/contrib/rom-o-matic/top.php
+++ b/roms/ipxe/contrib/rom-o-matic/top.php
@@ -1,6 +1,6 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 
-<?
+<?php
 
 /**
  * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
@@ -25,17 +25,17 @@
 
 <html>
 <head>
-  <link rev="made" href="mailto:<? echo "${webmaster_email}" ?>">
+  <link rev="made" href="mailto:<?php echo "${webmaster_email}" ?>">
   <meta name="keywords" content="rom, etherboot, ipxe, open source, rom-o-matic.net">
-  <title><? echo $header_title ?></title>
-  <meta name="description" content="<? echo $description ?>">
+  <title><?php echo $header_title ?></title>
+  <meta name="description" content="<?php echo $description ?>">
 </head>
 <h1>
-<? echo "$html_title" ?>&nbsp;
+<?php echo "$html_title" ?>&nbsp;
 </h1>
 <hr>
 <h2>
-<? echo "$html_tagline" ?>
+<?php echo "$html_tagline" ?>
 </h2>
 </form>
 <hr>
diff --git a/roms/ipxe/contrib/rom-o-matic/utils.php b/roms/ipxe/contrib/rom-o-matic/utils.php
index dc5bd41441a861304071bc6d23f1..e0e62f447918f9871247ea1a328b 100644
--- a/roms/ipxe/contrib/rom-o-matic/utils.php
+++ b/roms/ipxe/contrib/rom-o-matic/utils.php
@@ -1,4 +1,4 @@
-<? // -*- Mode: PHP; -*-
+<?php // -*- Mode: PHP; -*-
 
 /**
  * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
@@ -131,7 +131,8 @@ function parse_nic_file ()
         if ( strpos ( $first_eight_chars, "family" ) === 0 ) {
 
             // get pathname of NIC driver
-            list ( $dummy, $nic ) = split( "[ \t]+", $line );
+            #list ( $dummy, $nic ) = split( "[ \t]+", $line );
+            list ( $dummy, $nic ) = explode("\t", $line);
             settype ( $nic, "string" );
 
             // extract filename name of driver from pathname
diff --git a/roms/ipxe/contrib/vm/bochsrc.txt b/roms/ipxe/contrib/vm/bochsrc.txt
index 32842a3b2a76db4e985b47a18e98..d0f12504b6633b370a7bcedd94db 100644
--- a/roms/ipxe/contrib/vm/bochsrc.txt
+++ b/roms/ipxe/contrib/vm/bochsrc.txt
@@ -1,15 +1,29 @@
 # You may now use double quotes around pathnames, in case
 # your pathname includes spaces.
 
+#=======================================================================
+# PLUGIN_CTRL:
+# Controls the presence of optional device plugins. These plugins are loaded
+# directly with this option and some of them install a config option that is
+# only available when the plugin device is loaded. The value "1" means to load
+# the plugin and "0" will unload it (if loaded before).
+# These plugins are currently supported: 'biosdev', 'e1000', 'es1370',
+# 'extfpuirq', 'gameport', 'iodebug', 'ne2k', 'parallel', 'pcidev', 'pcipnic',
+# 'sb16', 'serial', 'speaker', 'unmapped', 'usb_ohci', 'usb_uhci' and 'usb_xhci'.
+#=======================================================================
+plugin_ctrl: unmapped=1, biosdev=1, speaker=1, e1000=1, parallel=1, serial=1
+
 #=======================================================================
 # CONFIG_INTERFACE
 #
 # The configuration interface is a series of menus or dialog boxes that
 # allows you to change all the settings that control Bochs's behavior.
-# There are two choices of configuration interface: a text mode version
-# called "textconfig" and a graphical version called "wx".  The text
-# mode version uses stdin/stdout and is always compiled in.  The graphical
-# version is only available when you use "--with-wx" on the configure
+# Depending on the platform there are up to 3 choices of configuration
+# interface: a text mode version called "textconfig" and two graphical versions
+# called "win32config" and "wx".  The text mode version uses stdin/stdout and
+# is always compiled in, unless Bochs is compiled for wx only. The choice
+# "win32config" is only available on win32 and it is the default there.
+# The choice "wx" is only available when you use "--with-wx" on the configure
 # command.  If you do not write a config_interface line, Bochs will
 # choose a default for you.
 #
@@ -17,6 +31,7 @@
 # the "wx" display library.
 #=======================================================================
 #config_interface: textconfig
+#config_interface: win32config
 #config_interface: wx
 
 #=======================================================================
@@ -33,7 +48,6 @@
 #   x              use X windows interface, cross platform
 #   win32          use native win32 libraries
 #   carbon         use Carbon library (for MacOS X)
-#   beos           use native BeOS libraries
 #   macintosh      use MacOS pre-10
 #   amigaos        use native AmigaOS libraries
 #   sdl            use SDL library, cross platform
@@ -47,18 +61,23 @@
 # the "wx" display library.
 #
 # Specific options:
-# Some display libraries now support specific option to control their
-# behaviour. See the examples below for currently supported options.
+# Some display libraries now support specific options to control their
+# behaviour. These options are supported by more than one display library:
+#
+# "gui_debug"   - use GTK debugger gui (sdl, x) / Win32 debugger gui (win32)
+# "hideIPS"     - disable IPS output in status bar (sdl, wx, x)
+# "nokeyrepeat" - turn off host keyboard repeat (sdl, win32, x)
+#
+# See the examples below for other currently supported options.
 #=======================================================================
 #display_library: amigaos
-#display_library: beos
 #display_library: carbon
 #display_library: macintosh
 #display_library: nogui
 #display_library: rfb, options="timeout=60" # time to wait for client
 #display_library: sdl, options="fullscreen" # startup in fullscreen mode
 #display_library: term
-#display_library: win32, options="legacyF12" # use F12 to toggle mouse
+#display_library: win32
 #display_library: wx
 #display_library: x
 
@@ -67,67 +86,245 @@
 # The ROM BIOS controls what the PC does when it first powers on.
 # Normally, you can use a precompiled BIOS in the source or binary
 # distribution called BIOS-bochs-latest. The ROM BIOS is usually loaded
-# starting at address 0xf0000, and it is exactly 64k long.
+# starting at address 0xf0000, and it is exactly 64k long. Another option
+# is 128k BIOS which is loaded at address 0xe0000.
 # You can also use the environment variable $BXSHARE to specify the
 # location of the BIOS.
 # The usage of external large BIOS images (up to 512k) at memory top is
 # now supported, but we still recommend to use the BIOS distributed with
-# Bochs. Now the start address can be calculated from image size.
+# Bochs. The start address optional, since it can be calculated from image size.
 #=======================================================================
-romimage: file=bochs/bios/BIOS-bochs-latest, address=0xe0000
+#romimage: file=$BXSHARE/BIOS-bochs-latest
+#romimage: file=bios/seabios-1.6.3.bin
 #romimage: file=mybios.bin, address=0xfff80000 # 512k at memory top
-#romimage: file=mybios.bin # calculate start address from image size
+romimage: file=bochs/bios/BIOS-bochs-latest
 
 #=======================================================================
 # CPU:
 # This defines cpu-related parameters inside Bochs:
 #
+#  MODEL:
+#    Selects CPU configuration to emulate from pre-defined list of all
+#    supported configurations. When this option is used, the CPUID option
+#    has no effect anymore.
+#
+#  CPU configurations that can be selected:
+# -----------------------------------------------------------------
+#  pentium_mmx                Intel Pentium MMX
+#  amd_k6_2_chomper           AMD-K6(tm) 3D processor (Chomper)
+#  p2_klamath                 Intel Pentium II (Klamath)
+#  p3_katmai                  Intel Pentium III (Katmai)
+#  p4_willamette              Intel(R) Pentium(R) 4 (Willamette)
+#  core_duo_t2400_yonah       Intel(R) Core(TM) Duo CPU T2400 (Yonah)
+#  atom_n270                  Intel(R) Atom(TM) CPU N270
+#  athlon64_clawhammer        AMD Athlon(tm) 64 Processor 2800+ (Clawhammer)
+#  athlon64_venice            AMD Athlon(tm) 64 Processor 3000+ (Venice)
+#  turion64_tyler             AMD Turion(tm) 64 X2 Mobile TL-60 (Tyler)
+#  phenom_8650_toliman        AMD Phenom X3 8650 (Toliman)
+#  p4_prescott_celeron_336    Intel(R) Celeron(R) 336 (Prescott)
+#  core2_penryn_t9600         Intel Mobile Core 2 Duo T9600 (Penryn)
+#  corei5_lynnfield_750       Intel(R) Core(TM) i5   750 (Lynnfield)
+#  corei5_arrandale_m520      Intel(R) Core(TM) i5 M 520 (Arrandale)
+#  corei7_sandy_bridge_2600k  Intel(R) Core(TM) i7-2600K (Sandy Bridge)
+#  corei7_ivy_bridge_3770k    Intel(R) Core(TM) i7-3770K CPU (Ivy Bridge)
+#
 #  COUNT:
-#  Set the number of processors:cores per processor:threads per core
-#  when Bochs is compiled for SMP emulation.
-#  Bochs currently supports up to 8 threads running simultaniosly.
-#  If Bochs is compiled without SMP support, it won't accept values
-#  different from 1.
+#    Set the number of processors:cores per processor:threads per core
+#    when Bochs is compiled for SMP emulation.
+#    Bochs currently supports up to 8 threads running simultaniosly.
+#    If Bochs is compiled without SMP support, it won't accept values
+#    different from 1.
+#
+#  QUANTUM:
+#    Maximum amount of instructions allowed to execute by processor before
+#    returning control to another cpu. This option exists only in Bochs
+#    binary compiled with SMP support.
 #
 #  RESET_ON_TRIPLE_FAULT:
-#  Reset the CPU when triple fault occur (highly recommended) rather than
-#  PANIC. Remember that if you trying to continue after triple fault the
-#  simulation will be completely bogus !
+#    Reset the CPU when triple fault occur (highly recommended) rather than
+#    PANIC. Remember that if you trying to continue after triple fault the
+#    simulation will be completely bogus !
+#
+#  CPUID_LIMIT_WINNT:
+#    Determine whether to limit maximum CPUID function to 2. This mode is
+#    required to workaround WinNT installation and boot issues.
+#
+#  MSRS:
+#    Define path to user CPU Model Specific Registers (MSRs) specification.
+#    See example in msrs.def.
+#
+#  IGNORE_BAD_MSRS:
+#    Ignore MSR references that Bochs does not understand; print a warning
+#    message instead of generating #GP exception. This option is enabled
+#    by default but will not be avaiable if configurable MSRs are enabled.
+#
+#  MWAIT_IS_NOP:
+#    When this option is enabled MWAIT will not put the CPU into a sleep state.
+#    This option exists only if Bochs compiled with --enable-monitor-mwait.
 #
 #  IPS:
-#  Emulated Instructions Per Second.  This is the number of IPS that bochs
-#  is capable of running on your machine. You can recompile Bochs with
-#  --enable-show-ips option enabled, to find your workstation's capability.
-#  Measured IPS value will then be logged into your log file or status bar
-#  (if supported by the gui).
+#    Emulated Instructions Per Second. This is the number of IPS that bochs
+#    is capable of running on your machine. You can recompile Bochs with
+#    --enable-show-ips option enabled, to find your host's capability.
+#    Measured IPS value will then be logged into your log file or shown
+#    in the status bar (if supported by the gui).
 #
-#  IPS is used to calibrate many time-dependent events within the bochs
-#  simulation.  For example, changing IPS affects the frequency of VGA
-#  updates, the duration of time before a key starts to autorepeat, and
-#  the measurement of BogoMips and other benchmarks.
+#    IPS is used to calibrate many time-dependent events within the bochs
+#    simulation.  For example, changing IPS affects the frequency of VGA
+#    updates, the duration of time before a key starts to autorepeat, and
+#    the measurement of BogoMips and other benchmarks.
 #
 #  Examples:
-#  Machine                                         Mips
-# ________________________________________________________________
-#  2.1Ghz Athlon XP with Linux 2.6/g++ 3.4         12 to 15 Mips
-#  1.6Ghz Intel P4 with Win2000/g++ 3.3             5 to  7 Mips
-#  650Mhz Athlon K-7 with Linux 2.4.4/egcs-2.91.66  2 to  2.5 Mips
-#  400Mhz Pentium II with Linux 2.0.36/egcs-1.0.3   1 to  1.8 Mips
+#
+#  Bochs Machine/Compiler                                 Mips
+# ______________________________________________________________________
+#  2.4.6 3.4Ghz Intel Core i7 2600 with Win7x64/g++ 4.5.2 85 to 95 Mips
+#  2.3.7 3.2Ghz Intel Core 2 Q9770 with WinXP/g++ 3.4     50 to 55 Mips
+#  2.3.7 2.6Ghz Intel Core 2 Duo with WinXP/g++ 3.4       38 to 43 Mips
+#  2.2.6 2.6Ghz Intel Core 2 Duo with WinXP/g++ 3.4       21 to 25 Mips
+#  2.2.6 2.1Ghz Athlon XP with Linux 2.6/g++ 3.4          12 to 15 Mips
+#=======================================================================
+cpu: model=core2_penryn_t9600, count=1, ips=50000000, reset_on_triple_fault=1, ignore_bad_msrs=1, msrs="msrs.def"
+cpu: cpuid_limit_winnt=0
+
+#=======================================================================
+# CPUID:
+#
+# This defines features and functionality supported by Bochs emulated CPU.
+# The option has no offect if CPU model was selected in CPU option.
+#
+#  MMX:
+#    Select MMX instruction set support.
+#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 5.
+#
+#  APIC:
+#    Select APIC configuration (LEGACY/XAPIC/XAPIC_EXT/X2APIC).
+#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 5.
+#
+#  SEP:
+#    Select SYSENTER/SYSEXIT instruction set support.
+#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
+#
+#  SSE:
+#    Select SSE instruction set support.
+#    Any of NONE/SSE/SSE2/SSE3/SSSE3/SSE4_1/SSE4_2 could be selected.
+#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
+#
+#  SSE4A:
+#    Select AMD SSE4A instructions support.
+#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
+#
+#  AES:
+#    Select AES instruction set support.
+#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
+#
+#  MOVBE:
+#    Select MOVBE Intel(R) Atom instruction support.
+#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
+#
+#  XSAVE:
+#    Select XSAVE extensions support.
+#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
+#
+#  XSAVEOPT:
+#    Select XSAVEOPT instruction support.
+#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
+#
+#  AVX:
+#    Select AVX/AVX2 instruction set support.
+#    This option exists only if Bochs compiled with --enable-avx option.
+#
+#  AVX_F16C:
+#    Select AVX float16 convert instructions support.
+#    This option exists only if Bochs compiled with --enable-avx option.
+#
+#  AVX_FMA:
+#    Select AVX fused multiply add (FMA) instructions support.
+#    This option exists only if Bochs compiled with --enable-avx option.
+#
+#  BMI:
+#    Select BMI1/BMI2 instructions support.
+#    This option exists only if Bochs compiled with --enable-avx option.
+#
+#  XOP:
+#    Select AMD XOP instructions support.
+#    This option exists only if Bochs compiled with --enable-avx option.
+#
+#  FMA4:
+#    Select AMD four operand FMA instructions support.
+#    This option exists only if Bochs compiled with --enable-avx option.
+#
+#  TBM:
+#    Select AMD Trailing Bit Manipulation (TBM) instructions support.
+#    This option exists only if Bochs compiled with --enable-avx option.
+#
+#  X86-64:
+#    Enable x86-64 and long mode support.
+#    This option exists only if Bochs compiled with x86-64 support.
+#
+#  1G_PAGES:
+#    Enable 1G page size support in long mode.
+#    This option exists only if Bochs compiled with x86-64 support.
+#
+#  PCID:
+#    Enable Process-Context Identifiers (PCID) support in long mode.
+#    This option exists only if Bochs compiled with x86-64 support.
+#
+#  FSGSBASE:
+#    Enable GS/GS BASE access instructions support in long mode.
+#    This option exists only if Bochs compiled with x86-64 support.
+#
+#  SMEP:
+#    Enable Supervisor Mode Execution Protection (SMEP) support.
+#    This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6.
+#
+#  MWAIT:
+#    Select MONITOR/MWAIT instructions support.
+#    This option exists only if Bochs compiled with --enable-monitor-mwait.
+#
+#  VMX:
+#    Select VMX extensions emulation support.
+#    This option exists only if Bochs compiled with --enable-vmx option.
+#
+#  VENDOR_STRING:
+#    Set the CPUID vendor string returned by CPUID(0x0). This should be a
+#    twelve-character ASCII string.
+#
+#  BRAND_STRING:
+#    Set the CPUID vendor string returned by CPUID(0x80000002 .. 0x80000004).
+#    This should be at most a forty-eight-character ASCII string.
+#
+#  FAMILY:
+#    Set model information returned by CPUID. Default family value determined
+#    by configure option --enable-cpu-level.
+#
+#  MODEL:
+#    Set model information returned by CPUID. Default model value is 3.
+#
+#  STEPPING:
+#    Set stepping information returned by CPUID. Default stepping value is 3.
 #=======================================================================
-cpu: count=1, ips=10000000, reset_on_triple_fault=1
+#cpuid: x86_64=1, mmx=1, sep=1, sse=sse4_2, apic=xapic, aes=1, movbe=1, xsave=1
+#cpuid: family=6, model=0x1a, stepping=5
 
 #=======================================================================
-# MEGS
-# Set the number of Megabytes of physical memory you want to emulate.
-# The default is 32MB, most OS's won't need more than that.
-# The maximum amount of memory supported is 2048Mb.
+# MEMORY
+# Set the amount of physical memory you want to emulate.
+#
+# GUEST:
+# Set amount of guest physical memory to emulate. The default is 32MB,
+# the maximum amount limited only by physical address space limitations.
+#
+# HOST:
+# Set amount of host memory you want to allocate for guest RAM emulation.
+# It is possible to allocate less memory than you want to emulate in guest
+# system. This will fake guest to see the non-existing memory. Once guest
+# system touches new memory block it will be dynamically taken from the
+# memory pool. You will be warned (by FATAL PANIC) in case guest already
+# used all allocated host memory and wants more.
+#
 #=======================================================================
-#megs: 256
-#megs: 128
-#megs: 64
-megs: 32
-#megs: 16
-#megs: 8
+memory: guest=512, host=256
 
 #=======================================================================
 # OPTROMIMAGE[1-4]:
@@ -144,8 +341,7 @@ megs: 32
 #optromimage2: file=optionalrom.bin, address=0xd1000
 #optromimage3: file=optionalrom.bin, address=0xd2000
 #optromimage4: file=optionalrom.bin, address=0xd3000
-optromimage1: file=../../src/bin/pnic.rom, address=0xd0000
-#optromimage1: file=../../src/bin/rtl8029.rom, address=0xd0000
+optromimage1: file=../../src/bin/intel.rom, address=0xcb000
 
 #optramimage1: file=/path/file1.img, address=0x0010000
 #optramimage2: file=/path/file2.img, address=0x0020000
@@ -157,18 +353,31 @@ optromimage1: file=../../src/bin/pnic.rom, address=0xd0000
 # You now need to load a VGA ROM BIOS into C0000.
 #=======================================================================
 #vgaromimage: file=bios/VGABIOS-elpin-2.40
-vgaromimage: file=bochs/bios/VGABIOS-lgpl-latest
+#vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest
 #vgaromimage: file=bios/VGABIOS-lgpl-latest-cirrus
+vgaromimage: file=bochs/bios/VGABIOS-lgpl-latest
 
 #=======================================================================
 # VGA:
-# Here you can specify the display extension to be used. With the value
-# 'none' you can use standard VGA with no extension. Other supported
-# values are 'vbe' for Bochs VBE and 'cirrus' for Cirrus SVGA support.
+# This defines parameters related to the VGA display
+#
+#   EXTENSION
+#     Here you can specify the display extension to be used. With the value
+#     'none' you can use standard VGA with no extension. Other supported
+#     values are 'vbe' for Bochs VBE and 'cirrus' for Cirrus SVGA support.
+#
+#   UPDATE_FREQ
+#     The VGA update frequency is based on the emulated clock and the default
+#     value is 5. Keep in mind that you must tweak the 'cpu: ips=N' directive
+#     to be as close to the number of emulated instructions-per-second your
+#     workstation can do, for this to be accurate. If the realtime sync is
+#     enabled with the 'clock' option, the value is based on the real time.
+#     This parameter can be changed at runtime.
+#
+# Examples:
+#   vga: extension=cirrus, update_freq=10
 #=======================================================================
-#vga: extension=cirrus
-#vga: extension=vbe
-vga: extension=none
+#vga: extension=vbe, update_freq=5
 
 #=======================================================================
 # FLOPPYA:
@@ -177,36 +386,42 @@ vga: extension=none
 # booting from 'a' (or 'floppy').
 #
 # You can set the initial status of the media to 'ejected' or 'inserted'.
-#   floppya: 2_88=path, status=ejected             (2.88M 3.5" floppy)
-#   floppya: 1_44=path, status=inserted            (1.44M 3.5" floppy)
-#   floppya: 1_2=path, status=ejected              (1.2M  5.25" floppy)
-#   floppya: 720k=path, status=inserted            (720K  3.5" floppy)
-#   floppya: 360k=path, status=inserted            (360K  5.25" floppy)
-#   floppya: 320k=path, status=inserted            (320K  5.25" floppy)
-#   floppya: 180k=path, status=inserted            (180K  5.25" floppy)
-#   floppya: 160k=path, status=inserted            (160K  5.25" floppy)
-#   floppya: image=path, status=inserted           (guess type from image size)
+#   floppya: 2_88=path, status=ejected    (2.88M 3.5"  media)
+#   floppya: 1_44=path, status=inserted   (1.44M 3.5"  media)
+#   floppya: 1_2=path, status=ejected     (1.2M  5.25" media)
+#   floppya: 720k=path, status=inserted   (720K  3.5"  media)
+#   floppya: 360k=path, status=inserted   (360K  5.25" media)
+#   floppya: 320k=path, status=inserted   (320K  5.25" media)
+#   floppya: 180k=path, status=inserted   (180K  5.25" media)
+#   floppya: 160k=path, status=inserted   (160K  5.25" media)
+#   floppya: image=path, status=inserted  (guess media type from image size)
+#   floppya: 1_44=vvfat:path, status=inserted  (use directory as VFAT media)
+#   floppya: type=1_44                    (1.44M 3.5" floppy drive, no media)
 #
 # The path should be the name of a disk image file.  On Unix, you can use a raw
 # device name such as /dev/fd0 on Linux.  On win32 platforms, use drive letters
 # such as a: or b: as the path.  The parameter 'image' works with image files
 # only. In that case the size must match one of the supported types.
+# The parameter 'type' can be used to enable the floppy drive without media
+# and status specified. Usually the drive type is set up based on the media type.
+# The optional parameter 'write_protected' can be used to control the media
+# write protect switch. By default it is turned off.
 #=======================================================================
 #floppya: 1_44=/dev/fd0, status=inserted
 #floppya: image=../1.44, status=inserted
 #floppya: 1_44=/dev/fd0H1440, status=inserted
 #floppya: 1_2=../1_2, status=inserted
 #floppya: 1_44=a:, status=inserted
-#floppya: 1_44=a.img, status=inserted
+#floppya: 1_44=a.img, status=inserted, write_protected=1
 #floppya: 1_44=/dev/rfd0a, status=inserted
-floppya: 1_44=../../src/bin/pnic.dsk, status=inserted
+floppya: 1_44=../../src/bin/ipxe.dsk, status=inserted
 
 #=======================================================================
 # FLOPPYB:
 # See FLOPPYA above for syntax
 #=======================================================================
 #floppyb: 1_44=b:, status=inserted
-floppyb: 1_44=b.img, status=inserted
+#floppyb: 1_44=b.img, status=inserted
 
 #=======================================================================
 # ATA0, ATA1, ATA2, ATA3
@@ -236,8 +451,8 @@ ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
 # This defines the type and characteristics of all attached ata devices:
 #   type=       type of attached device [disk|cdrom]
 #   mode=       only valid for disks [flat|concat|external|dll|sparse|vmware3]
-#   mode=       only valid for disks [undoable|growing|volatile]
-#   path=       path of the image
+#   mode=       only valid for disks [undoable|growing|volatile|vvfat]
+#   path=       path of the image / directory
 #   cylinders=  only valid for disks
 #   heads=      only valid for disks
 #   spt=        only valid for disks
@@ -245,7 +460,7 @@ ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
 #   biosdetect= type of biosdetection [none|auto], only for disks on ata0 [cmos]
 #   translation=type of translation of the bios, only for disks [none|lba|large|rechs|auto]
 #   model=      string returned by identify device command
-#   journal=    optional filename of the redolog for undoable and volatile disks
+#   journal=    optional filename of the redolog for undoable, volatile and vvfat disks
 #
 # Point this at a hard disk image file, cdrom iso file, or physical cdrom
 # device.  To create a hard disk image, try running bximage.  It will help you
@@ -259,10 +474,11 @@ ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
 # access the "first" cdrom in the system.  On MacOSX, use path="drive"
 # to access the physical drive.
 #
-# The path is always mandatory. For flat hard disk images created with
-# bximage geometry autodetection can be used (cylinders=0 -> cylinders are
-# calculated using heads=16 and spt=63). For other hard disk images and modes
-# the cylinders, heads, and spt are mandatory.
+# The path is mandatory for hard disks. Disk geometry autodetection works with
+# images created by bximage if CHS is set to 0/0/0 (cylinders are calculated
+# using  heads=16 and spt=63). For other hard disk images and modes the
+# cylinders, heads, and spt are mandatory. In all cases the disk size reported
+# from the image must be exactly C*H*S*512.
 #
 # Default values are:
 #   mode=flat, biosdetect=auto, translation=auto, model="Generic 1234"
@@ -279,7 +495,10 @@ ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
 #   ata3-master: type=disk, mode=flat, path=483M.sample, cylinders=1024, heads=15, spt=63
 #   ata3-slave:  type=cdrom, path=iso.sample, status=inserted
 #=======================================================================
+#ata0-master: type=disk, mode=flat, path="30M.sample"
 #ata0-master: type=disk, mode=flat, path="30M.sample", cylinders=615, heads=6, spt=17
+#ata0-master: type=disk, mode=flat, path="c.img", cylinders=0 # autodetect
+#ata0-slave: type=disk, mode=vvfat, path=/bochs/images/vvfat, journal=vvfat.redolog
 #ata0-slave: type=cdrom, path=D:, status=inserted
 #ata0-slave: type=cdrom, path=/dev/cdrom, status=inserted
 #ata0-slave: type=cdrom, path="drive", status=inserted
@@ -287,15 +506,13 @@ ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
 
 #=======================================================================
 # BOOT:
-# This defines the boot sequence. Now you can specify up to 3 boot drives.
-# You can either boot from 'floppy', 'disk' or 'cdrom'
-# legacy 'a' and 'c' are also supported
+# This defines the boot sequence. Now you can specify up to 3 boot drives,
+# which can be 'floppy', 'disk', 'cdrom' or 'network' (boot ROM).
+# Legacy 'a' and 'c' are also supported.
 # Examples:
 #   boot: floppy
-#   boot: disk
-#   boot: cdrom
-#   boot: c
-#   boot: a
+#   boot: cdrom, disk
+#   boot: network, disk
 #   boot: cdrom, floppy, disk
 #=======================================================================
 #boot: floppy
@@ -307,7 +524,17 @@ boot: network, floppy
 # This defines the parameters of the clock inside Bochs:
 #
 #  SYNC:
-#  TO BE COMPLETED (see Greg explanation in feature request #536329)
+#  This defines the method how to synchronize the Bochs internal time
+#  with realtime. With the value 'none' the Bochs time relies on the IPS
+#  value and no host time synchronization is used. The 'slowdown' method
+#  sacrifices performance to preserve reproducibility while allowing host
+#  time correlation. The 'realtime' method sacrifices reproducibility to
+#  preserve performance and host-time correlation.
+#  It is possible to enable both synchronization methods.
+#
+#  RTC_SYNC:
+#  If this option is enabled together with the realtime synchronization,
+#  the RTC runs at realtime speed. This feature is disabled by default.
 #
 #  TIME0:
 #  Specifies the start (boot) time of the virtual machine. Use a time
@@ -342,7 +569,6 @@ boot: network, floppy
 #   floppy_bootsig_check: disabled=0
 #   floppy_bootsig_check: disabled=1
 #=======================================================================
-#floppy_bootsig_check: disabled=1
 floppy_bootsig_check: disabled=0
 
 #=======================================================================
@@ -378,7 +604,7 @@ log: bochsout.txt
 #=======================================================================
 # LOG CONTROLS
 #
-# Bochs now has four severity levels for event logging.
+# Bochs has four severity levels for event logging.
 #   panic: cannot proceed.  If you choose to continue after a panic,
 #          don't be surprised if you get strange behavior or crashes.
 #   error: something went wrong, but it is probably safe to continue the
@@ -387,9 +613,13 @@ log: bochsout.txt
 #   debug: messages useful only when debugging the code.  This may
 #          spit out thousands per second.
 #
-# For events of each level, you can choose to crash, report, or ignore.
-# TODO: allow choice based on the facility: e.g. crash on panics from
-#       everything except the cdrom, and only report those.
+# For events of each level, you can choose to exit Bochs ('fatal'), 'report'
+# or 'ignore'. On some guis you have the additional choice 'ask'. A gui dialog
+# appears asks how to proceed.
+#
+# It is also possible to specify the 'action' to do for each Bochs facility
+# separately (e.g. crash on panics from everything except the cdrom, and only
+# report those). See the 'log function' module list in the user documentation.
 #
 # If you are experiencing many panics, it can be helpful to change
 # the panic action to report instead of fatal.  However, be aware
@@ -400,8 +630,7 @@ log: bochsout.txt
 panic: action=ask
 error: action=report
 info: action=report
-debug: action=ignore
-#pass: action=fatal
+debug: action=ignore, pci=report # report BX_DEBUG from module 'pci'
 
 #=======================================================================
 # DEBUGGER_LOG:
@@ -425,18 +654,29 @@ debugger_log: -
 # Then do `sleep 1000000' in the com1 window to keep the shell from
 # messing with things, and run bochs in the other window.  Serial I/O to
 # com1 (port 0x3f8) will all go to the other window.
+# In socket* and pipe* (win32 only) modes Bochs becomes either socket/named pipe
+# client or server. In client mode it connects to an already running server (if
+# connection fails Bochs treats com port as not connected). In server mode it
+# opens socket/named pipe and waits until a client application connects to it
+# before starting simulation. This mode is useful for remote debugging (e.g.
+# with gdb's "target remote host:port" command or windbg's command line option
+# -k com:pipe,port=\\.\pipe\pipename). Note: 'socket' is a shorthand for
+# 'socket-client' and 'pipe' for 'pipe-client'. Socket modes use simple TCP
+# communication, pipe modes use duplex byte mode pipes.
 # Other serial modes are 'null' (no input/output), 'file' (output to a file
 # specified as the 'dev' parameter), 'raw' (use the real serial port - under
 # construction for win32), 'mouse' (standard serial mouse - requires
-# mouse option setting 'type=serial' or 'type=serial_wheel') and 'socket'
-# (connect a networking socket).
+# mouse option setting 'type=serial', 'type=serial_wheel' or 'type=serial_msys').
 #
 # Examples:
 #   com1: enabled=1, mode=null
 #   com1: enabled=1, mode=mouse
 #   com2: enabled=1, mode=file, dev=serial.out
 #   com3: enabled=1, mode=raw, dev=com1
-#   com3: enabled=1, mode=socket, dev=localhost:8888
+#   com3: enabled=1, mode=socket-client, dev=localhost:8888
+#   com3: enabled=1, mode=socket-server, dev=localhost:8888
+#   com4: enabled=1, mode=pipe-client, dev=\\.\pipe\mypipe
+#   com4: enabled=1, mode=pipe-server, dev=\\.\pipe\mypipe
 #=======================================================================
 #com1: enabled=1, mode=term, dev=/dev/ttyp9
 
@@ -461,6 +701,9 @@ parport1: enabled=1, file="parport.out"
 # This defines the SB16 sound emulation. It can have several of the
 # following properties.
 # All properties are in the format sb16: property=value
+# enabled:
+#      This optional property controls the presence of the SB16 emulation.
+#      The emulation is turned on unless this property is used and set to 0.
 # midi: The filename is where the midi data is sent. This can be a
 #       device or just a file if you want to record the midi data.
 # midimode:
@@ -488,26 +731,25 @@ parport1: enabled=1, file="parport.out"
 #      non-continuous sound.  750000 is usually a good value.  This needs a
 #      reasonably correct setting for the IPS parameter of the CPU option.
 #
-# For an example look at the next line:
+# Examples for output devices:
+#   sb16: midimode=1, midi="", wavemode=1, wave=""           # win32
+#   sb16: midimode=1, midi=alsa:128:0, wavemode=1, wave=alsa # Linux with ALSA
 #=======================================================================
-
 #sb16: midimode=1, midi=/dev/midi00, wavemode=1, wave=/dev/dsp, loglevel=2, log=sb16.log, dmatimer=600000
 
 #=======================================================================
-# VGA_UPDATE_INTERVAL:
-# Video memory is scanned for updates and screen updated every so many
-# virtual seconds.  The default is 40000, about 25Hz. Keep in mind that
-# you must tweak the 'cpu: ips=N' directive to be as close to the number
-# of emulated instructions-per-second your workstation can do, for this
-# to be accurate.
+# ES1370:
+# This defines the ES1370 sound emulation. The parameter 'enabled' controls the
+# presence of the device. In addition to this, it must be loaded with 'plugin_ctrl'
+# and assigned to a PCI slot. The 'wavedev' parameter is similar to the 'wave'
+# parameter of the SB16 soundcard. The emulation supports recording and playback
+# (except DAC1+DAC2 output at the same time).
 #
 # Examples:
-#   vga_update_interval: 250000
+#   es1370: enabled=1, wavedev=""       # win32
+#   es1370: enabled=1, wavedev=alsa     # Linux with ALSA
 #=======================================================================
-vga_update_interval: 300000
-
-# using for Winstone '98 tests
-#vga_update_interval:  100000
+#es1370: enabled=1, wavedev=alsa
 
 #=======================================================================
 # KEYBOARD_SERIAL_DELAY:
@@ -537,24 +779,34 @@ keyboard_paste_delay: 100000
 
 #=======================================================================
 # MOUSE:
-# This option prevents Bochs from creating mouse "events" unless a mouse
-# is  enabled. The hardware emulation itself is not disabled by this.
-# You can turn the mouse on by setting enabled to 1, or turn it off by
-# setting enabled to 0. Unless you have a particular reason for enabling
-# the mouse by default, it is recommended that you leave it off.
-# You can also toggle the mouse usage at runtime (control key + middle
-# mouse button on X11, SDL, wxWidgets and Win32).
-# With the mouse type option you can select the type of mouse to emulate.
-# The default value is 'ps2'. The other choices are 'imps2' (wheel mouse
-# on PS/2), 'serial', 'serial_wheel' (one com port requires setting
-# 'mode=mouse') and 'usb' (3-button mouse - one of the USB ports must be
-# connected with the 'mouse' device - requires PCI and USB support).
+# This defines parameters for the emulated mouse type, the initial status
+# of the mouse capture and the runtime method to toggle it.
+#
+#  TYPE:
+#  With the mouse type option you can select the type of mouse to emulate.
+#  The default value is 'ps2'. The other choices are 'imps2' (wheel mouse
+#  on PS/2), 'serial', 'serial_wheel' and 'serial_msys' (one com port requires
+#  setting 'mode=mouse'). To connect a mouse to an USB port, see the 'usb_uhci',
+#  'usb_ohci' or 'usb_xhci' options (requires PCI and USB support).
+#
+#  ENABLED:
+#  The Bochs gui creates mouse "events" unless the 'enabled' option is
+#  set to 0. The hardware emulation itself is not disabled by this.
+#  Unless you have a particular reason for enabling the mouse by default,
+#  it is recommended that you leave it off. You can also toggle the mouse
+#  usage at runtime (RFB, SDL, Win32, wxWidgets and X11 - see below).
+#
+#  TOGGLE:
+#  The default method to toggle the mouse capture at runtime is to press the
+#  CTRL key and the middle mouse button ('ctrl+mbutton'). This option allows
+#  to change the method to 'ctrl+f10' (like DOSBox), 'ctrl+alt' (like QEMU)
+#  or 'f12' (replaces win32 'legacyF12' option).
 #
 # Examples:
 #   mouse: enabled=1
-#   mouse: enabled=1, type=imps2
-#   mouse: enabled=1, type=serial
-#   mouse: enabled=0
+#   mouse: type=imps2, enabled=1
+#   mouse: type=serial, enabled=1
+#   mouse: enabled=0, toggle=ctrl+f10
 #=======================================================================
 mouse: enabled=0
 
@@ -586,54 +838,86 @@ private_colormap: enabled=0
 #=======================================================================
 # ne2k: NE2000 compatible ethernet adapter
 #
-# Examples:
-# ne2k: ioaddr=IOADDR, irq=IRQ, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT
+# Format:
+# ne2k: enabled=1, ioaddr=IOADDR, irq=IRQ, mac=MACADDR, ethmod=MODULE,
+#       ethdev=DEVICE, script=SCRIPT, bootrom=BOOTROM
 #
-# ioaddr, irq: You probably won't need to change ioaddr and irq, unless there
-# are IRQ conflicts.
+# IOADDR, IRQ: You probably won't need to change ioaddr and irq, unless there
+# are IRQ conflicts. These arguments are ignored when assign the ne2k to a
+# PCI slot.
 #
-# mac: The MAC address MUST NOT match the address of any machine on the net.
+# MAC: The MAC address MUST NOT match the address of any machine on the net.
 # Also, the first byte must be an even number (bit 0 set means a multicast
 # address), and you cannot use ff:ff:ff:ff:ff:ff because that's the broadcast
 # address.  For the ethertap module, you must use fe:fd:00:00:00:01.  There may
 # be other restrictions too.  To be safe, just use the b0:c4... address.
 #
-# ethdev: The ethdev value is the name of the network interface on your host
+# ETHDEV: The ethdev value is the name of the network interface on your host
 # platform.  On UNIX machines, you can get the name by running ifconfig.  On
 # Windows machines, you must run niclist to get the name of the ethdev.
 # Niclist source code is in misc/niclist.c and it is included in Windows
 # binary releases.
 #
-# script: The script value is optional, and is the name of a script that
+# SCRIPT: The script value is optional, and is the name of a script that
 # is executed after bochs initialize the network interface. You can use
 # this script to configure this network interface, or enable masquerading.
 # This is mainly useful for the tun/tap devices that only exist during
 # Bochs execution. The network interface name is supplied to the script
-# as first parameter
+# as first parameter.
+#
+# BOOTROM: The bootrom value is optional, and is the name of the ROM image
+# to load. Note that this feature is only implemented for the PCI version of
+# the NE2000.
 #
 # If you don't want to make connections to any physical networks,
 # you can use the following 'ethmod's to simulate a virtual network.
 #   null: All packets are discarded, but logged to a few files.
-#   arpback: ARP is simulated. Disabled by default.
 #   vde:  Virtual Distributed Ethernet
 #   vnet: ARP, ICMP-echo(ping), DHCP and read/write TFTP are simulated.
 #         The virtual host uses 192.168.10.1.
 #         DHCP assigns 192.168.10.2 to the guest.
-#         TFTP uses the ethdev value for the root directory and doesn't
+#         TFTP uses the 'ethdev' value for the root directory and doesn't
 #         overwrite files.
 #
 #=======================================================================
-# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=fbsd, ethdev=en0 #macosx
-# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=fbsd, ethdev=xl0
-# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0
-# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=win32, ethdev=MYCARD
-# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0
-# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun0, script=./tunconfig
-# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=null, ethdev=eth0
-# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=vde, ethdev="/tmp/vde.ctl"
-# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=vnet, ethdev="c:/temp"
-pnic: mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun:tap0
-#ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun:tap0
+# ne2k: ioaddr=0x300, irq=9, mac=fe:fd:00:00:00:01, ethmod=fbsd, ethdev=en0 #macosx
+# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:00, ethmod=fbsd, ethdev=xl0
+# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0
+# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=win32, ethdev=MYCARD
+# ne2k: ioaddr=0x300, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0
+# ne2k: ioaddr=0x300, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun0, script=./tunconfig
+# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=null, ethdev=eth0
+# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=vde, ethdev="/tmp/vde.ctl"
+# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=vnet, ethdev="c:/temp"
+# ne2k: mac=b0:c4:20:00:00:01, ethmod=slirp, script=/usr/local/bin/slirp, bootrom=ne2k_pci.rom
+
+#=======================================================================
+# pnic: Bochs/Etherboot pseudo-NIC
+#
+# Format:
+# pnic: enabled=1, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT,
+#       bootrom=BOOTROM
+#
+# The pseudo-NIC accepts the same syntax (for mac, ethmod, ethdev, script,
+# bootrom) and supports the same networking modules as the NE2000 adapter.
+# In addition to this, it must be loaded with 'plugin_ctrl' and assigned
+# to a PCI slot.
+#=======================================================================
+#pnic: enabled=1, mac=b0:c4:20:00:00:00, ethmod=vnet
+
+#=======================================================================
+# e1000: Intel(R) 82540EM Gigabit Ethernet adapter
+#
+# Format:
+# e1000: enabled=1, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT
+#        bootrom=BOOTROM
+#
+# The E1000 accepts the same syntax (for mac, ethmod, ethdev, script, bootrom)
+# and supports the same networking modules as the NE2000 adapter. In addition
+# to this, it must be loaded with 'plugin_ctrl' and assigned to a PCI slot.
+#=======================================================================
+#e1000: enabled=1, mac=52:54:00:12:34:56, ethmod=slirp, script=/usr/local/bin/slirp
+e1000: enabled=1, mac=52:54:00:12:34:56, ethmod=tuntap, ethdev=/dev/net/tun:tap0
 
 #=======================================================================
 # KEYBOARD_MAPPING:
@@ -662,45 +946,88 @@ keyboard_mapping: enabled=0, map=
 # USER_SHORTCUT:
 # This defines the keyboard shortcut to be sent when you press the "user"
 # button in the headerbar. The shortcut string is a combination of maximum
-# 3 key names (listed below) separated with a '-' character. The old-style
-# syntax (without the '-') still works for the key combinations supported
-# in Bochs 2.2.1.
+# 3 key names (listed below) separated with a '-' character.
 # Valid key names:
 # "alt", "bksl", "bksp", "ctrl", "del", "down", "end", "enter", "esc",
 # "f1", ... "f12", "home", "ins", "left", "menu", "minus", "pgdwn", "pgup",
-# "plus", "right", "shift", "space", "tab", "up", and "win".
+# "plus", "right", "shift", "space", "tab", "up", "win", "print" and "power".
 #
 # Example:
 #   user_shortcut: keys=ctrl-alt-del
 #=======================================================================
-user_shortcut: keys=ctrl-alt-del
+#user_shortcut: keys=ctrl-alt-del
 
 #=======================================================================
-# I440FXSUPPORT:
-# This option controls the presence of the i440FX PCI chipset. You can
-# also specify the devices connected to PCI slots. Up to 5 slots are
-# available now. These devices are currently supported: ne2k, pcivga,
-# pcidev and pcipnic. If Bochs is compiled with Cirrus SVGA support
-# you'll have the additional choice 'cirrus'.
+# PCI:
+# This option controls the presence of a PCI chipset in Bochs. Currently it only
+# supports the i440FX chipset. You can also specify the devices connected to
+# PCI slots. Up to 5 slots are available. These devices are currently supported:
+# cirrus, e1000, es1370, ne2k, pcivga, pcidev, pcipnic, usb_ohci and usb_xhci.
 #
 # Example:
-#   i440fxsupport: enabled=1, slot1=pcivga, slot2=ne2k
+#   pci: enabled=1, chipset=i440fx, slot1=pcivga, slot2=ne2k
 #=======================================================================
-i440fxsupport: enabled=1, slot1=pcipnic
-#i440fxsupport: enabled=1, slot1=ne2k
+pci: enabled=1, chipset=i440fx, slot1=e1000
 
 #=======================================================================
-# USB1:
+# USB_UHCI:
 # This option controls the presence of the USB root hub which is a part
-# of the i440FX PCI chipset. With the portX option you can connect devices
-# to the hub (currently supported: 'mouse' and 'keypad'). If you connect
-# the mouse to one of the ports and use the mouse option 'type=usb' you'll
-# have a 3-button USB mouse.
+# of the i440FX PCI chipset. With the portX parameter you can connect devices
+# to the hub (currently supported: 'mouse', 'tablet', 'keypad', 'disk', 'cdrom'
+# 'hub' and 'printer'). NOTE: UHCI must be loaded with 'plugin_ctrl'.
 #
-# Example:
-#   usb1: enabled=1, port1=mouse, port2=keypad
+# The optionsX parameter can be used to assign specific options to the device
+# connected to the corresponding USB port. Currently this feature is only used
+# to set the speed reported by device and by the 'disk' device to specify
+# an alternative redolog file of some image modes.
+#
+# If you connect the mouse or tablet to one of the ports, Bochs forwards the
+# mouse movement data to the USB device instead of the selected mouse type.
+# When connecting the keypad to one of the ports, Bochs forwards the input of
+# the numeric keypad to the USB device instead of the PS/2 keyboard.
+#
+# To connect a 'flat' mode image as an USB hardisk you can use the 'disk' device
+# with the path to the image separated with a colon. To use other disk image modes
+# similar to ATA disks the syntax 'disk:mode:filename' must be used (see below).
+#
+# To emulate an USB cdrom you can use the 'cdrom' device name and the path to
+# an ISO image or raw device name also separated with a colon. An option to
+# insert/eject media is available in the runtime configuration.
+#
+# The device name 'hub' connects an external hub with max. 8 ports (default: 4)
+# to the root hub. To specify the number of ports you have to add the value
+# separated with a colon. Connecting devices to the external hub ports is only
+# available in the runtime configuration.
+#
+# The device 'printer' emulates the HP Deskjet 920C printer. The PCL data is
+# sent to a file specified in bochsrc.txt. The current code appends the PCL
+# code to the file if the file already existed. It would probably be nice to
+# overwrite the file instead, asking user first.
+#=======================================================================
+#usb_uhci: enabled=1
+#usb_uhci: enabled=1, port1=mouse, port2=disk:usbstick.img
+#usb_uhci: enabled=1, port1=hub:7, port2=disk:growing:usbdisk.img
+#usb_uhci: enabled=1, port2=disk:undoable:usbdisk.img, options1=journal:redo.log
+#usb_uhci: enabled=1, port1=printer:printdata.bin, port2=cdrom:image.iso
+
+#=======================================================================
+# USB_OHCI:
+# This option controls the presence of the USB OHCI host controller with a
+# 2-port hub. The portX option accepts the same device types with the same
+# syntax as the UHCI controller (see above). The OHCI HC must be assigned to
+# a PCI slot and loaded with 'plugin_ctrl'.
+#=======================================================================
+#usb_ohci: enabled=1
+#usb_ohci: enabled=1, port1=printer:usbprinter.bin
+
 #=======================================================================
-#usb1: enabled=1
+# USB_XHCI:
+# This option controls the presence of the experimental USB xHCI host controller
+# with a 4-port hub. The portX option accepts the same device types with the
+# same syntax as the UHCI controller (see above). The xHCI HC must be assigned
+# to a PCI slot and loaded with 'plugin_ctrl'.
+#=======================================================================
+#usb_xhci: enabled=1
 
 #=======================================================================
 # CMOSIMAGE:
@@ -715,12 +1042,50 @@ i440fxsupport: enabled=1, slot1=pcipnic
 #cmosimage: file=cmos.img, rtc_init=time0
 
 #=======================================================================
-# other stuff
+# MAGIC_BREAK:
+# This enables the "magic breakpoint" feature when using the debugger.
+# The useless cpu instruction XCHG BX, BX causes Bochs to enter the
+# debugger mode. This might be useful for software development.
+#
+# Example:
+#   magic_break: enabled=1
 #=======================================================================
+#magic_break: enabled=1
 magic_break: enabled=1
+
+#=======================================================================
+# PORT_E9_HACK:
+# The 0xE9 port doesn't exists in normal ISA architecture. However, we
+# define a convention here, to display on the console of the system running
+# Bochs anything that is written to it. The idea is to provide debug output
+# very early when writing BIOS or OS code for example, without having to
+# bother with setting up a serial port or etc. Reading from port 0xE9 will
+# will return 0xe9 to let you know if the feature is available.
+# Leave this 0 unless you have a reason to use it.
+#
+# Example:
+#   port_e9_hack: enabled=1
+#=======================================================================
+port_e9_hack: enabled=1
+
+#=======================================================================
+# DEBUG_SYMBOLS:
+# This loads symbols from the specified file for use in Bochs' internal
+# debugger. Symbols are loaded into global context. This is equivalent to
+# issuing ldsym debugger command at start up.
+#
+# Example:
+#   debug_symbols: file="kernel.sym"
+#   debug_symbols: file="kernel.sym", offset=0x80000000
+#=======================================================================
+#debug_symbols: file="kernel.sym"
+
+#=======================================================================
+# other stuff
+#=======================================================================
 #load32bitOSImage: os=nullkernel, path=../kernel.img, iolog=../vga_io.log
 #load32bitOSImage: os=linux, path=../linux.img, iolog=../vga_io.log, initrd=../initrd.img
-#text_snapshot_check: enable
+#print_timestamps: enabled=1
 
 #-------------------------
 # PCI host device mapping
@@ -735,11 +1100,12 @@ magic_break: enabled=1
 #gdbstub: enabled=0, port=1234, text_base=0, data_base=0, bss_base=0
 
 #=======================================================================
-# IPS:
-# The IPS directive is DEPRECATED. Use the parameter IPS of the CPU
-# directive instead.
+# USER_PLUGIN:
+# Load user-defined plugin. This option is available only if Bochs is
+# compiled with plugin support. Maximum 8 different plugins are supported.
+# See the example in the Bochs sources how to write a plugin device.
 #=======================================================================
-#ips: 10000000
+#user_plugin: name=testdev
 
 #=======================================================================
 # for Macintosh, use the style of pathnames in the following
@@ -749,3 +1115,17 @@ magic_break: enabled=1
 # romimage: file=:bios:BIOS-bochs-latest, address=0xf0000
 # floppya: 1_44=[fd:], status=inserted
 #=======================================================================
+
+#=======================================================================
+# MEGS
+# Set the number of Megabytes of physical memory you want to emulate.
+# The default is 32MB, most OS's won't need more than that.
+# The maximum amount of memory supported is 2048Mb.
+# The 'MEGS' option is deprecated. Use 'MEMORY' option instead.
+#=======================================================================
+#megs: 256
+#megs: 128
+#megs: 64
+#megs: 32
+#megs: 16
+#megs: 8
diff --git a/roms/ipxe/src/Makefile b/roms/ipxe/src/Makefile
index 8cc976ba09a50c86cdf3bd236778..207369a96f8fcbad84b758fb29d3 100644
--- a/roms/ipxe/src/Makefile
+++ b/roms/ipxe/src/Makefile
@@ -7,6 +7,7 @@ CLEANUP		:=
 CFLAGS		:=
 ASFLAGS		:=
 LDFLAGS		:=
+HOST_CFLAGS	:=
 MAKEDEPS	:= Makefile
 
 ###############################################################################
@@ -32,6 +33,7 @@ RANLIB		:= $(CROSS_COMPILE)ranlib
 OBJCOPY		:= $(CROSS_COMPILE)objcopy
 NM		:= $(CROSS_COMPILE)nm
 OBJDUMP		:= $(CROSS_COMPILE)objdump
+OPENSSL		:= openssl
 PARSEROM	:= ./util/parserom.pl
 FIXROM		:= ./util/fixrom.pl
 SYMCHECK	:= ./util/symcheck.pl
@@ -68,9 +70,12 @@ SRCDIRS		+= drivers/net/igb
 SRCDIRS		+= drivers/net/igbvf
 SRCDIRS		+= drivers/net/phantom
 SRCDIRS		+= drivers/net/rtl818x
-SRCDIRS		+= drivers/net/ath5k
+SRCDIRS		+= drivers/net/ath
+SRCDIRS		+= drivers/net/ath/ath5k
+SRCDIRS		+= drivers/net/ath/ath9k
 SRCDIRS		+= drivers/net/vxge
 SRCDIRS		+= drivers/net/efi
+SRCDIRS		+= drivers/net/tg3
 SRCDIRS		+= drivers/block
 SRCDIRS		+= drivers/nvs
 SRCDIRS		+= drivers/bitbash
@@ -138,7 +143,25 @@ everything :
 		bin-i386-efi/ipxe.efirom \
 		bin-x86_64-efi/ipxe.efi bin-x86_64-efi/ipxe.efidrv \
 		bin-x86_64-efi/ipxe.efirom \
-		bin-i386-linux/tap.linux bin-x86_64-linux/tap.linux
+		bin-i386-linux/tap.linux bin-x86_64-linux/tap.linux \
+		bin-i386-linux/tests.linux bin-x86_64-linux/tests.linux
+
+###############################################################################
+#
+# VMware build target: all ROMs used with VMware
+#
+vmware : bin/8086100f.mrom bin/808610d3.mrom bin/10222000.rom bin/15ad07b0.rom
+	@$(ECHO) '==========================================================='
+	@$(ECHO) 
+	@$(ECHO) 'Available ROMs:'
+	@$(ECHO) '    bin/8086100f.mrom -- intel/e1000'
+	@$(ECHO) '    bin/808610d3.mrom -- intel/e1000e'
+	@$(ECHO) '    bin/10222000.rom  -- vlance/pcnet32'
+	@$(ECHO) '    bin/15ad07b0.rom  -- vmxnet3'
+	@$(ECHO) 
+	@$(ECHO) 'For more information, see http://ipxe.org/howto/vmware'
+	@$(ECHO)
+	@$(ECHO) '==========================================================='
 
 ###############################################################################
 #
@@ -160,13 +183,12 @@ VERSION_PATCH	= 0
 EXTRAVERSION	= +
 MM_VERSION	= $(VERSION_MAJOR).$(VERSION_MINOR)
 VERSION		= $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION)
-CFLAGS		+= -DVERSION_MAJOR=$(VERSION_MAJOR) \
-		   -DVERSION_MINOR=$(VERSION_MINOR) \
-		   -DVERSION_PATCH=$(VERSION_PATCH) \
-		   -DVERSION=\"$(VERSION)\"
-IDENT		= '$(@F) $(VERSION) (GPL) ipxe.org'
+GITVERSION := $(shell git describe --always --abbrev=1 --match "" 2>/dev/null)
+ifneq ($(GITVERSION),)
+VERSION		+= ($(GITVERSION))
+endif
 version :
-	@$(ECHO) $(VERSION)
+	@$(ECHO) "$(VERSION)"
 
 ###############################################################################
 #
diff --git a/roms/ipxe/src/Makefile.housekeeping b/roms/ipxe/src/Makefile.housekeeping
index ba01f16d5682edfc7fe095b65892..d40f226f684761c5572977b0bd7c 100644
--- a/roms/ipxe/src/Makefile.housekeeping
+++ b/roms/ipxe/src/Makefile.housekeeping
@@ -162,9 +162,12 @@ endif
 # output of "size".  Inhibit this.
 #
 ifeq ($(CCTYPE),gcc)
-CFI_TEST = $(CC) -fno-dwarf2-cfi-asm -x c -c /dev/null \
+CFI_TEST = $(CC) -fno-dwarf2-cfi-asm -fno-exceptions -fno-unwind-tables \
+		 -fno-asynchronous-unwind-tables -x c -c /dev/null \
 		 -o /dev/null >/dev/null 2>&1
-CFI_FLAGS := $(shell $(CFI_TEST) && $(ECHO) '-fno-dwarf2-cfi-asm')
+CFI_FLAGS := $(shell $(CFI_TEST) && \
+	       $(ECHO) '-fno-dwarf2-cfi-asm -fno-exceptions ' \
+		       '-fno-unwind-tables -fno-asynchronous-unwind-tables')
 WORKAROUND_CFLAGS += $(CFI_FLAGS)
 endif
 
@@ -381,6 +384,7 @@ CFLAGS		+= -g
 ifeq ($(CCTYPE),gcc)
 CFLAGS		+= -ffreestanding
 CFLAGS		+= -Wall -W -Wformat-nonliteral
+HOST_CFLAGS	+= -Wall -W -Wformat-nonliteral
 endif
 ifeq ($(CCTYPE),icc)
 CFLAGS		+= -fno-builtin
@@ -411,12 +415,14 @@ endif
 CFLAGS		+= $(WORKAROUND_CFLAGS) $(EXTRA_CFLAGS)
 ASFLAGS		+= $(WORKAROUND_ASFLAGS) $(EXTRA_ASFLAGS)
 LDFLAGS		+= $(WORKAROUND_LDFLAGS) $(EXTRA_LDFLAGS)
+HOST_CFLAGS	+= -O2 -g
 
 # Inhibit -Werror if NO_WERROR is specified on make command line
 #
 ifneq ($(NO_WERROR),1)
 CFLAGS		+= -Werror
 ASFLAGS		+= --fatal-warnings
+HOST_CFLAGS	+= -Werror
 endif
 
 # Function trace recorder state in the last build.  This is needed
@@ -450,14 +456,20 @@ endif
 
 # Enable per-item sections and section garbage collection.  Note that
 # some older versions of gcc support -fdata-sections but treat it as
-# implying -fno-common, which would break our build.
+# implying -fno-common, which would break our build.  Some other older
+# versions issue a spurious and uninhibitable warning if
+# -ffunction-sections is used with -g, which would also break our
+# build since we use -Werror.
 #
 ifeq ($(CCTYPE),gcc)
 DS_TEST		= $(ECHO) 'char x;' | \
 		  $(CC) -fdata-sections -S -x c - -o - 2>/dev/null | \
 		  grep -E '\.comm' > /dev/null
 DS_FLAGS	:= $(shell $(DS_TEST) && $(ECHO) '-fdata-sections')
-CFLAGS		+= -ffunction-sections $(DS_FLAGS)
+FS_TEST		= $(CC) -ffunction-sections -g -c -x c /dev/null \
+		  -o /dev/null 2>/dev/null
+FS_FLAGS	:= $(shell $(FS_TEST) && $(ECHO) '-ffunction-sections')
+CFLAGS		+= $(FS_FLAGS) $(DS_FLAGS)
 endif
 LDFLAGS		+= --gc-sections
 
@@ -508,6 +520,150 @@ RULE_S_to_s	= $(Q)$(PREPROCESS_S) $< > $@
 
 DEBUG_TARGETS	+= dbg%.o c s
 
+# List of embedded images included in the last build of embedded.o.
+# This is needed in order to correctly rebuild embedded.o whenever the
+# list of objects changes.
+#
+EMBED		:= $(EMBEDDED_IMAGE) # Maintain backwards compatibility
+EMBEDDED_LIST	:= $(BIN)/.embedded.list
+ifeq ($(wildcard $(EMBEDDED_LIST)),)
+EMBED_OLD := <invalid>
+else
+EMBED_OLD := $(shell cat $(EMBEDDED_LIST))
+endif
+ifneq ($(EMBED_OLD),$(EMBED))
+$(shell $(ECHO) "$(EMBED)" > $(EMBEDDED_LIST))
+endif
+
+$(EMBEDDED_LIST) :
+
+VERYCLEANUP	+= $(EMBEDDED_LIST)
+
+EMBEDDED_FILES	:= $(subst $(COMMA), ,$(EMBED))
+EMBED_ALL	:= $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\
+		     EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\
+			     \"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" ))
+
+embedded_DEPS += $(EMBEDDED_FILES) $(EMBEDDED_LIST)
+
+CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)"
+
+# List of trusted root certificates
+#
+TRUSTED_LIST	:= $(BIN)/.trusted.list
+ifeq ($(wildcard $(TRUSTED_LIST)),)
+TRUST_OLD := <invalid>
+else
+TRUST_OLD := $(shell cat $(TRUSTED_LIST))
+endif
+ifneq ($(TRUST_OLD),$(TRUST))
+$(shell $(ECHO) "$(TRUST)" > $(TRUSTED_LIST))
+endif
+
+$(TRUSTED_LIST) :
+
+VERYCLEANUP	+= $(TRUSTED_LIST)
+
+# Trusted root certificate fingerprints
+#
+TRUSTED_CERTS	:= $(subst $(COMMA), ,$(TRUST))
+TRUSTED_FPS	:= $(foreach CERT,$(TRUSTED_CERTS),\
+		     0x$(subst :,$(COMMA) 0x,$(lastword $(subst =, ,\
+			 $(shell $(OPENSSL) x509 -in $(CERT) -noout -sha256 \
+				 -fingerprint))))$(COMMA))
+
+rootcert_DEPS += $(TRUSTED_FILES) $(TRUSTED_LIST)
+
+CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)")
+
+# (Single-element) list of client certificates
+#
+CERT_LIST := $(BIN)/.certificate.list
+ifeq ($(wildcard $(CERT_LIST)),)
+CERT_OLD := <invalid>
+else
+CERT_OLD := $(shell cat $(CERT_LIST))
+endif
+ifneq ($(CERT_OLD),$(CERT))
+$(shell $(ECHO) "$(CERT)" > $(CERT_LIST))
+endif
+
+$(CERT_LIST) :
+
+VERYCLEANUP += $(CERT_LIST)
+
+# Embedded client certificate
+#
+CERT_INC := $(BIN)/.certificate.der
+
+ifdef CERT
+$(CERT_INC) : $(CERT) $(CERT_LIST)
+	$(Q)$(OPENSSL) x509 -in $< -outform DER -out $@
+
+clientcert_DEPS += $(CERT_INC)
+endif
+
+CLEANUP += $(CERT_INC)
+
+clientcert_DEPS += $(CERT_LIST)
+
+CFLAGS_clientcert += $(if $(CERT),-DCERTIFICATE="\"$(CERT_INC)\"")
+
+# (Single-element) list of client private keys
+#
+ifdef KEY
+PRIVKEY	:= $(KEY) # Maintain backwards compatibility
+endif
+PRIVKEY_LIST := $(BIN)/.private_key.list
+ifeq ($(wildcard $(PRIVKEY_LIST)),)
+PRIVKEY_OLD := <invalid>
+else
+PRIVKEY_OLD := $(shell cat $(PRIVKEY_LIST))
+endif
+ifneq ($(PRIVKEY_OLD),$(PRIVKEY))
+$(shell $(ECHO) "$(PRIVKEY)" > $(PRIVKEY_LIST))
+endif
+
+$(PRIVKEY_LIST) :
+
+VERYCLEANUP += $(PRIVKEY_LIST)
+
+# Embedded client private key
+#
+PRIVKEY_INC := $(BIN)/.private_key.der
+
+ifdef PRIVKEY
+$(PRIVKEY_INC) : $(PRIVKEY) $(PRIVKEY_LIST)
+	$(Q)$(OPENSSL) rsa -in $< -outform DER -out $@
+
+clientcert_DEPS += $(PRIVKEY_INC)
+endif
+
+CLEANUP += $(PRIVKEY_INC)
+
+clientcert_DEPS += $(PRIVKEY_LIST)
+
+CFLAGS_clientcert += $(if $(PRIVKEY),-DPRIVATE_KEY="\"$(PRIVKEY_INC)\"")
+
+# These files use .incbin inline assembly to include a binary file.
+# Unfortunately ccache does not detect this dependency and caches
+# builds even when the binary file has changed.
+#
+$(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC)
+
+$(BIN)/clientcert.o : override CC := env CCACHE_DISABLE=1 $(CC)
+
+# Version number
+#
+CFLAGS_version += -DVERSION_MAJOR=$(VERSION_MAJOR) \
+		  -DVERSION_MINOR=$(VERSION_MINOR) \
+		  -DVERSION_PATCH=$(VERSION_PATCH) \
+		  -DVERSION="\"$(VERSION)\""
+# Make sure the version number gets updated on every git checkout
+ifneq ($(GITVERSION),)
+$(BIN)/version.o : ../.git/index
+endif
+
 # 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.
@@ -521,9 +677,9 @@ DEBUG_TARGETS	+= dbg%.o c s
 define deps_template
 	@$(ECHO) "  [DEPS] $(1)"
 	@$(MKDIR) -p $(BIN)/deps/$(dir $(1))
-	@$(CPP) $(CFLAGS) $(CFLAGS_$(2)) $(CFLAGS_$(3)) -DOBJECT=$(3) \
+	$(Q)$(CPP) $(CFLAGS) $(CFLAGS_$(2)) $(CFLAGS_$(3)) -DOBJECT=$(3) \
 		-Wno-error -M $(1) -MG -MP | \
-		sed 's/\.o\s*:/_DEPS =/' > $(BIN)/deps/$(1).d
+		sed 's/\.o\s*:/_DEPS +=/' > $(BIN)/deps/$(1).d
 endef
 
 # rules_template : generate rules for a given source file
@@ -549,7 +705,8 @@ define rules_template
 		    '\n$(TGT)_OBJS += $$(BIN)/$(3).$(TGT)\n' ) ) \
 		 '\n$(BIN)/deps/$(1).d : $$($(3)_DEPS)\n' \
 		 '\nTAGS : $$($(3)_DEPS)\n' > $(BIN)/rules/$(1).r
-	@$(PERL) $(PARSEROM) $(1) >> $(BIN)/rules/$(1).r
+	@$(if $(findstring drivers/,$(1)),\
+	   $(PERL) $(PARSEROM) $(1) >> $(BIN)/rules/$(1).r)
 endef
 
 # Rule to generate the dependency list file
@@ -596,39 +753,6 @@ drivers :
 roms :
 	@$(ECHO) $(ROMS)
 
-# List of embedded images included in the last build of embedded.o.
-# This is needed in order to correctly rebuild embedded.o whenever the
-# list of objects changes.
-#
-EMBEDDED_LIST	:= $(BIN)/.embedded.list
-ifeq ($(wildcard $(EMBEDDED_LIST)),)
-EMBEDDED_IMAGE_OLD := <invalid>
-else
-EMBEDDED_IMAGE_OLD := $(shell cat $(EMBEDDED_LIST))
-endif
-ifneq ($(EMBEDDED_IMAGE_OLD),$(EMBEDDED_IMAGE))
-$(shell $(ECHO) "$(EMBEDDED_IMAGE)" > $(EMBEDDED_LIST))
-endif
-
-$(EMBEDDED_LIST) :
-
-VERYCLEANUP	+= $(EMBEDDED_LIST)
-
-EMBEDDED_FILES	:= $(subst $(COMMA), ,$(EMBEDDED_IMAGE))
-EMBED_ALL	:= $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\
-		     EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\
-			     \"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" ))
-
-$(BIN)/embedded.o : $(EMBEDDED_FILES) $(EMBEDDED_LIST)
-
-# This file uses .incbin inline assembly to include a binary file.
-# Unfortunately ccache does not detect this dependency and caches builds even
-# when the binary file has changed.
-#
-$(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC)
-
-CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)"
-
 # Generate error usage information
 #
 $(BIN)/%.einfo : $(BIN)/%.o
@@ -953,13 +1077,13 @@ endif # defined(BIN)
 #
 $(NRV2B) : util/nrv2b.c $(MAKEDEPS)
 	$(QM)$(ECHO) "  [HOSTCC] $@"
-	$(Q)$(HOST_CC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -DNDEBUG \
-		       -DBITSIZE=32 -DENDIAN=0 -o $@ $<
+	$(Q)$(HOST_CC) $(HOST_CFLAGS) -DENCODE -DDECODE -DMAIN -DVERBOSE \
+		       -DNDEBUG -DBITSIZE=32 -DENDIAN=0 -o $@ $<
 CLEANUP	+= $(NRV2B)
 
 $(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS)
 	$(QM)$(ECHO) "  [HOSTCC] $@"
-	$(Q)$(HOST_CC) -O2 -o $@ $<
+	$(Q)$(HOST_CC) $(HOST_CFLAGS) -o $@ $<
 CLEANUP += $(ZBIN)
 
 ###############################################################################
@@ -967,23 +1091,25 @@ CLEANUP += $(ZBIN)
 # The EFI image converter
 #
 ELF2EFI_CFLAGS	:= -I$(BINUTILS_DIR)/include -I$(BFD_DIR)/include \
-		   -I$(ZLIB_DIR)/include -idirafter include \
-		   -L$(BINUTILS_DIR)/lib -L$(BFD_DIR)/lib -L$(ZLIB_DIR)/lib \
+		   -I$(ZLIB_DIR)/include -idirafter include
+ELF2EFI_LDFLAGS	:= -L$(BINUTILS_DIR)/lib -L$(BFD_DIR)/lib -L$(ZLIB_DIR)/lib \
 		   -lbfd -ldl -liberty -lz -Wl,--no-warn-search-mismatch
 
 $(ELF2EFI32) : util/elf2efi.c $(MAKEDEPS)
 	$(QM)$(ECHO) "  [HOSTCC] $@"
-	$(Q)$(HOST_CC) $< $(ELF2EFI_CFLAGS) -DEFI_TARGET_IA32 -O2 -o $@
+	$(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_IA32 $< \
+		$(ELF2EFI_LDFLAGS) -o $@
 CLEANUP += $(ELF2EFI32)
 
 $(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS)
 	$(QM)$(ECHO) "  [HOSTCC] $@"
-	$(Q)$(HOST_CC) $< $(ELF2EFI_CFLAGS) -DEFI_TARGET_X64 -O2 -o $@
+	$(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_X64 $< \
+		$(ELF2EFI_LDFLAGS) -o $@
 CLEANUP += $(ELF2EFI64)
 
 $(EFIROM) : util/efirom.c $(MAKEDEPS)
 	$(QM)$(ECHO) "  [HOSTCC] $@"
-	$(Q)$(HOST_CC) -idirafter include -O2 -o $@ $<
+	$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
 CLEANUP += $(EFIROM)
 
 ###############################################################################
@@ -992,7 +1118,7 @@ CLEANUP += $(EFIROM)
 #
 $(ICCFIX) : util/iccfix.c $(MAKEDEPS)
 	$(QM)$(ECHO) "  [HOSTCC] $@"
-	$(Q)$(HOST_CC) -idirafter include -O2 -o $@ $<
+	$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
 CLEANUP += $(ICCFIX)
 
 ###############################################################################
@@ -1001,7 +1127,7 @@ CLEANUP += $(ICCFIX)
 #
 $(EINFO) : util/einfo.c $(MAKEDEPS)
 	$(QM)$(ECHO) "  [HOSTCC] $@"
-	$(Q)$(HOST_CC) -idirafter include -O2 -o $@ $<
+	$(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $<
 CLEANUP += $(EINFO)
 
 ###############################################################################
diff --git a/roms/ipxe/src/arch/i386/Makefile b/roms/ipxe/src/arch/i386/Makefile
index 3261fff3939e6564bf950751f5b8..8314f26da1ec7b6f6c09eaeefc11 100644
--- a/roms/ipxe/src/arch/i386/Makefile
+++ b/roms/ipxe/src/arch/i386/Makefile
@@ -54,6 +54,8 @@ CFLAGS		+= -m32
 ASFLAGS		+= --32
 ifeq ($(HOST_OS),FreeBSD)
 LDFLAGS		+= -m elf_i386_fbsd
+else ifeq ($(HOST_OS),OpenBSD)
+LDFLAGS		+= -m elf_i386_obsd
 else
 LDFLAGS		+= -m elf_i386
 endif
@@ -85,15 +87,9 @@ SRCDIRS		+= arch/i386/interface/pcbios
 SRCDIRS		+= arch/i386/interface/pxe
 SRCDIRS		+= arch/i386/interface/pxeparent
 SRCDIRS 	+= arch/i386/interface/syslinux
+SRCDIRS		+= arch/i386/interface/vmware
 SRCDIRS		+= arch/i386/hci/commands
 
-# The various xxx_loader.c files are #included into core/loader.c and
-# should not be compiled directly.
-#
-NON_AUTO_SRCS	+= arch/i386/core/aout_loader.c
-NON_AUTO_SRCS	+= arch/i386/core/freebsd_loader.c
-NON_AUTO_SRCS	+= arch/i386/core/wince_loader.c
-
 # Include common x86 Makefile
 #
 MAKEDEPS	+= arch/x86/Makefile
diff --git a/roms/ipxe/src/arch/i386/Makefile.pcbios b/roms/ipxe/src/arch/i386/Makefile.pcbios
index 258c5d7d83dc2df211f8eb847a60..e1b226f5aab429c407aca99cd803 100644
--- a/roms/ipxe/src/arch/i386/Makefile.pcbios
+++ b/roms/ipxe/src/arch/i386/Makefile.pcbios
@@ -19,6 +19,7 @@ MEDIA		+= mrom
 MEDIA		+= pxe
 MEDIA		+= kpxe
 MEDIA		+= kkpxe
+MEDIA		+= kkkpxe
 MEDIA		+= lkrn
 MEDIA		+= dsk
 MEDIA		+= nbi
diff --git a/roms/ipxe/src/arch/i386/core/aout_loader.c b/roms/ipxe/src/arch/i386/core/aout_loader.c
deleted file mode 100644
index f85620e97f77a3f8b49a0711dc2d17322c89d5e4..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/arch/i386/core/aout_loader.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/* a.out */
-struct exec {
-	unsigned long      a_midmag;	/* flags<<26 | mid<<16 | magic */
-	unsigned long      a_text;	/* text segment size */
-	unsigned long      a_data;	/* initialized data size */
-	unsigned long      a_bss;	/* uninitialized data size */
-	unsigned long      a_syms;	/* symbol table size */
-	unsigned long      a_entry;	/* entry point */
-	unsigned long      a_trsize;	/* text relocation size */
-	unsigned long      a_drsize;	/* data relocation size */
-};
-
-struct aout_state {
-	struct exec head;
-	unsigned long curaddr;
-	int segment;			/* current segment number, -1 for none */
-	unsigned long loc;		/* start offset of current block */
-	unsigned long skip;		/* padding to be skipped to current segment */
-	unsigned long toread;		/* remaining data to be read in the segment */
-};
-
-static struct aout_state astate;
-
-static sector_t aout_download(unsigned char *data, unsigned int len, int eof);
-static inline os_download_t aout_probe(unsigned char *data, unsigned int len)
-{
-	unsigned long start, mid, end, istart, iend;
-	if (len < sizeof(astate.head)) {
-		return 0;
-	}
-	memcpy(&astate.head, data, sizeof(astate.head));
-	if ((astate.head.a_midmag & 0xffff) != 0x010BL) {
-		return 0;
-	}
-	
-	printf("(a.out");
-	aout_freebsd_probe();
-	printf(")... ");
-	/* Check the aout image */
-	start  = astate.head.a_entry;
-	mid    = (((start + astate.head.a_text) + 4095) & ~4095) + astate.head.a_data;
-	end    = ((mid + 4095) & ~4095) + astate.head.a_bss;
-	istart = 4096;
-	iend   = istart + (mid - start);
-	if (!prep_segment(start, mid, end, istart, iend))
-		return dead_download;
-	astate.segment = -1;
-	astate.loc = 0;
-	astate.skip = 0;
-	astate.toread = 0;
-	return aout_download;
-}
-
-static sector_t aout_download(unsigned char *data, unsigned int len, int eof)
-{
-	unsigned int offset;	/* working offset in the current data block */
-
-	offset = 0;
-
-#ifdef AOUT_LYNX_KDI
-	astate.segment++;
-	if (astate.segment == 0) {
-		astate.curaddr = 0x100000;
-		astate.head.a_entry = astate.curaddr + 0x20;
-	}
-	memcpy(phys_to_virt(astate.curaddr), data, len);
-	astate.curaddr += len;
-	return 0;
-#endif
-
-	do {
-		if (astate.segment != -1) {
-			if (astate.skip) {
-				if (astate.skip >= len - offset) {
-					astate.skip -= len - offset;
-					break;
-				}
-				offset += astate.skip;
-				astate.skip = 0;
-			}
-
-			if (astate.toread) {
-				if (astate.toread >= len - offset) {
-					memcpy(phys_to_virt(astate.curaddr), data+offset,
-						len - offset);
-					astate.curaddr += len - offset;
-					astate.toread -= len - offset;
-					break;
-				}
-				memcpy(phys_to_virt(astate.curaddr), data+offset, astate.toread);
-				offset += astate.toread;
-				astate.toread = 0;
-			}
-		}
-
-		/* Data left, but current segment finished - look for the next
-		 * segment.  This is quite simple for a.out files.  */
-		astate.segment++;
-		switch (astate.segment) {
-		case 0:
-			/* read text */
-			astate.curaddr = astate.head.a_entry;
-			astate.skip = 4096;
-			astate.toread = astate.head.a_text;
-			break;
-		case 1:
-			/* read data */
-			/* skip and curaddr may be wrong, but I couldn't find
-			 * examples where this failed.  There is no reasonable
-			 * documentation for a.out available.  */
-			astate.skip = ((astate.curaddr + 4095) & ~4095) - astate.curaddr;
-			astate.curaddr = (astate.curaddr + 4095) & ~4095;
-			astate.toread = astate.head.a_data;
-			break;
-		case 2:
-			/* initialize bss and start kernel */
-			astate.curaddr = (astate.curaddr + 4095) & ~4095;
-			astate.skip = 0;
-			astate.toread = 0;
-			memset(phys_to_virt(astate.curaddr), '\0', astate.head.a_bss);
-			goto aout_startkernel;
-		default:
-			break;
-		}
-	} while (offset < len);
-
-	astate.loc += len;
-
-	if (eof) {
-		unsigned long entry;
-
-aout_startkernel:
-		entry = astate.head.a_entry;
-		done(1);
-
-		aout_freebsd_boot();
-#ifdef AOUT_LYNX_KDI
-		xstart32(entry);
-#endif
-		printf("unexpected a.out variant\n");
-		longjmp(restart_etherboot, -2);
-	}
-	return 0;
-}
diff --git a/roms/ipxe/src/arch/i386/core/basemem_packet.c b/roms/ipxe/src/arch/i386/core/basemem_packet.c
index d487cce367f218ee03f802c1468c..06ffa3bbd26c9dc297a15a5a8f6d 100644
--- a/roms/ipxe/src/arch/i386/core/basemem_packet.c
+++ b/roms/ipxe/src/arch/i386/core/basemem_packet.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/i386/core/cmdline.c b/roms/ipxe/src/arch/i386/core/cmdline.c
deleted file mode 100644
index fa5adb8c6b75ae4d2192fbb118dc1f4f5b7a5321..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/arch/i386/core/cmdline.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2011 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_LICENCE ( GPL2_OR_LATER );
-
-/** @file
- *
- * Command line passed to iPXE
- *
- */
-
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <ipxe/init.h>
-#include <ipxe/image.h>
-#include <ipxe/script.h>
-#include <realmode.h>
-
-/** Command line physical address
- *
- * This can be set by the prefix.
- */
-uint32_t __bss16 ( cmdline_phys );
-#define cmdline_phys __use_data16 ( cmdline_phys )
-
-/** Internal copy of the command line */
-static char *cmdline_copy;
-
-/** Free command line image */
-static void cmdline_image_free ( struct refcnt *refcnt ) {
-	struct image *image = container_of ( refcnt, struct image, refcnt );
-
-	DBGC ( image, "CMDLINE freeing command line\n" );
-	free ( cmdline_copy );
-}
-
-/** Embedded script representing the command line */
-static struct image cmdline_image = {
-	.refcnt = REF_INIT ( cmdline_image_free ),
-	.name = "<CMDLINE>",
-	.type = &script_image_type,
-};
-
-/**
- * Initialise command line
- *
- */
-static void cmdline_init ( void ) {
-	struct image *image = &cmdline_image;
-	userptr_t cmdline_user;
-	char *cmdline;
-	char *tmp;
-	size_t len;
-
-	/* Do nothing if no command line was specified */
-	if ( ! cmdline_phys ) {
-		DBGC ( image, "CMDLINE found no command line\n" );
-		return;
-	}
-	cmdline_user = phys_to_user ( cmdline_phys );
-	len = ( strlen_user ( cmdline_user, 0 ) + 1 /* NUL */ );
-
-	/* Allocate and copy command line */
-	cmdline_copy = malloc ( len );
-	if ( ! cmdline_copy ) {
-		DBGC ( image, "CMDLINE could not allocate %zd bytes\n", len );
-		/* No way to indicate failure */
-		return;
-	}
-	cmdline = cmdline_copy;
-	copy_from_user ( cmdline, cmdline_user, 0, len );
-	DBGC ( image, "CMDLINE found \"%s\"\n", cmdline );
-
-	/* Check for unwanted cruft in the command line */
-	while ( isspace ( *cmdline ) )
-		cmdline++;
-	if ( ( tmp = strstr ( cmdline, "BOOT_IMAGE=" ) ) != NULL ) {
-		DBGC ( image, "CMDLINE stripping \"%s\"\n", tmp );
-		*tmp = '\0';
-	}
-	DBGC ( image, "CMDLINE using \"%s\"\n", cmdline );
-
-	/* Prepare and register image */
-	cmdline_image.data = virt_to_user ( cmdline );
-	cmdline_image.len = strlen ( cmdline );
-	if ( cmdline_image.len )
-		register_image ( &cmdline_image );
-
-	/* Drop our reference to the image */
-	image_put ( &cmdline_image );
-}
-
-/** Command line initialisation function */
-struct init_fn cmdline_init_fn __init_fn ( INIT_NORMAL ) = {
-	.initialise = cmdline_init,
-};
diff --git a/roms/ipxe/src/arch/i386/core/cpu.c b/roms/ipxe/src/arch/i386/core/cpu.c
deleted file mode 100644
index c24fa4e694e1e222212ac0ef8e2b53717cfdb6df..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/arch/i386/core/cpu.c
+++ /dev/null
@@ -1,73 +0,0 @@
-#include <stdint.h>
-#include <string.h>
-#include <cpu.h>
-
-/** @file
- *
- * CPU identification
- *
- */
-
-/**
- * Test to see if CPU flag is changeable
- *
- * @v flag		Flag to test
- * @ret can_change	Flag is changeable
- */
-static inline int flag_is_changeable ( unsigned int flag ) {
-	uint32_t f1, f2;
-
-	__asm__ ( "pushfl\n\t"
-		  "pushfl\n\t"
-		  "popl %0\n\t"
-		  "movl %0,%1\n\t"
-		  "xorl %2,%0\n\t"
-		  "pushl %0\n\t"
-		  "popfl\n\t"
-		  "pushfl\n\t"
-		  "popl %0\n\t"
-		  "popfl\n\t"
-		  : "=&r" ( f1 ), "=&r" ( f2 )
-		  : "ir" ( flag ) );
-
-	return ( ( ( f1 ^ f2 ) & flag ) != 0 );
-}
-
-/**
- * Get CPU information
- *
- * @v cpu		CPU information structure to fill in
- */
-void get_cpuinfo ( struct cpuinfo_x86 *cpu ) {
-	unsigned int cpuid_level;
-	unsigned int cpuid_extlevel;
-	unsigned int discard_1, discard_2, discard_3;
-
-	memset ( cpu, 0, sizeof ( *cpu ) );
-
-	/* Check for CPUID instruction */
-	if ( ! flag_is_changeable ( X86_EFLAGS_ID ) ) {
-		DBG ( "CPUID not supported\n" );
-		return;
-	}
-
-	/* Get features, if present */
-	cpuid ( 0x00000000, &cpuid_level, &discard_1,
-		&discard_2, &discard_3 );
-	if ( cpuid_level >= 0x00000001 ) {
-		cpuid ( 0x00000001, &discard_1, &discard_2,
-			&discard_3, &cpu->features );
-	} else {
-		DBG ( "CPUID cannot return capabilities\n" );
-	}
-
-	/* Get 64-bit features, if present */
-	cpuid ( 0x80000000, &cpuid_extlevel, &discard_1,
-		&discard_2, &discard_3 );
-	if ( ( cpuid_extlevel & 0xffff0000 ) == 0x80000000 ) {
-		if ( cpuid_extlevel >= 0x80000001 ) {
-			cpuid ( 0x80000001, &discard_1, &discard_2,
-				&discard_3, &cpu->amd_features );
-		}
-	}
-}
diff --git a/roms/ipxe/src/arch/i386/core/freebsd_loader.c b/roms/ipxe/src/arch/i386/core/freebsd_loader.c
deleted file mode 100644
index 464f6d9392e017ce458ef3bfcf2649002167a3f9..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/arch/i386/core/freebsd_loader.c
+++ /dev/null
@@ -1,377 +0,0 @@
-/* bootinfo */
-#define BOOTINFO_VERSION 1
-#define NODEV           (-1)    /* non-existent device */
-#define PAGE_SHIFT      12              /* LOG2(PAGE_SIZE) */
-#define PAGE_SIZE       (1<<PAGE_SHIFT) /* bytes/page */
-#define PAGE_MASK       (PAGE_SIZE-1)
-#define N_BIOS_GEOM     8
-
-struct bootinfo {
-        unsigned int            bi_version;
-        const unsigned char     *bi_kernelname;
-        struct nfs_diskless     *bi_nfs_diskless;
-                                /* End of fields that are always present. */
-#define bi_endcommon            bi_n_bios_used
-        unsigned int            bi_n_bios_used;
-        unsigned long           bi_bios_geom[N_BIOS_GEOM];
-        unsigned int            bi_size;
-        unsigned char           bi_memsizes_valid;
-        unsigned char           bi_pad[3];
-        unsigned long           bi_basemem;
-        unsigned long           bi_extmem;
-        unsigned long           bi_symtab;
-        unsigned long           bi_esymtab;
-	/* Note that these are in the FreeBSD headers but were not here... */
-	unsigned long           bi_kernend;		/* end of kernel space */
-	unsigned long           bi_envp;		/* environment */
-	unsigned long           bi_modulep;		/* preloaded modules */
-};
-
-static struct bootinfo bsdinfo;
-
-#ifdef ELF_IMAGE
-static Elf32_Shdr *shdr;	/* To support the FreeBSD kludge! */
-static Address symtab_load;
-static Address symstr_load;
-static int symtabindex;
-static int symstrindex;
-#endif
-
-static enum {
-	Unknown, Tagged, Aout, Elf, Aout_FreeBSD, Elf_FreeBSD,
-} image_type = Unknown;
-
-static unsigned int off;
-
-
-#ifdef ELF_IMAGE
-static void elf_freebsd_probe(void)
-{
-	image_type = Elf;
-	if (	(estate.e.elf32.e_entry & 0xf0000000) && 
-		(estate.e.elf32.e_type == ET_EXEC))
-	{
-		image_type = Elf_FreeBSD;
-		printf("/FreeBSD");
-		off = -(estate.e.elf32.e_entry & 0xff000000);
-		estate.e.elf32.e_entry += off;
-	}
-	/* Make sure we have a null to start with... */
-	shdr = 0;
-	
-	/* Clear the symbol index values... */
-	symtabindex = -1;
-	symstrindex = -1;
-	
-	/* ...and the load addresses of the symbols  */
-	symtab_load = 0;
-	symstr_load = 0;
-}
-
-static void elf_freebsd_fixup_segment(void)
-{
-	if (image_type == Elf_FreeBSD) {
-		estate.p.phdr32[estate.segment].p_paddr += off;
-	}
-}
-
-static void elf_freebsd_find_segment_end(void)
-{
-	/* Count the bytes read even for the last block
-	 * as we will need to know where the last block
-	 * ends in order to load the symbols correctly.
-	 * (plus it could be useful elsewhere...)
-	 * Note that we need to count the actual size,
-	 * not just the end of the disk image size.
-	 */
-	estate.curaddr += 
-		(estate.p.phdr32[estate.segment].p_memsz - 
-		estate.p.phdr32[estate.segment].p_filesz);
-}
-
-static int elf_freebsd_debug_loader(unsigned int offset)
-{
-	/* No more segments to be loaded - time to start the
-	 * nasty state machine to support the loading of
-	 * FreeBSD debug symbols due to the fact that FreeBSD
-	 * uses/exports the kernel's debug symbols in order
-	 * to make much of the system work!  Amazing (arg!)
-	 *
-	 * We depend on the fact that for the FreeBSD kernel,
-	 * there is only one section of debug symbols and that
-	 * the section is after all of the loaded sections in
-	 * the file.  This assumes a lot but is somewhat required
-	 * to make this code not be too annoying.  (Where do you
-	 * load symbols when the code has not loaded yet?)
-	 * Since this function is actually just a callback from
-	 * the network data transfer code, we need to be able to
-	 * work with the data as it comes in.  There is no chance
-	 * for doing a seek other than forwards.
-	 *
-	 * The process we use is to first load the section
-	 * headers.  Once they are loaded (shdr != 0) we then
-	 * look for where the symbol table and symbol table
-	 * strings are and setup some state that we found
-	 * them and fall into processing the first one (which
-	 * is the symbol table) and after that has been loaded,
-	 * we try the symbol strings.  Note that the order is
-	 * actually required as the memory image depends on
-	 * the symbol strings being loaded starting at the
-	 * end of the symbol table.  The kernel assumes this
-	 * layout of the image.
-	 *
-	 * At any point, if we get to the end of the load file
-	 * or the section requested is earlier in the file than
-	 * the current file pointer, we just end up falling
-	 * out of this and booting the kernel without this
-	 * information.
-	 */
-
-	/* Make sure that the next address is long aligned... */
-	/* Assumes size of long is a power of 2... */
-	estate.curaddr = (estate.curaddr + sizeof(long) - 1) & ~(sizeof(long) - 1);
-	
-	/* If we have not yet gotten the shdr loaded, try that */
-	if (shdr == 0)
-	{
-		estate.toread = estate.e.elf32.e_shnum * estate.e.elf32.e_shentsize;
-		estate.skip = estate.e.elf32.e_shoff - (estate.loc + offset);
-		if (estate.toread)
-		{
-#if ELF_DEBUG
-			printf("shdr *, size %lX, curaddr %lX\n", 
-				estate.toread, estate.curaddr);
-#endif
-			
-			/* Start reading at the curaddr and make that the shdr */
-			shdr = (Elf32_Shdr *)phys_to_virt(estate.curaddr);
-			
-			/* Start to read... */
-			return 1;
-		}
-	}
-	else
-	{
-		/* We have the shdr loaded, check if we have found
-		 * the indexs where the symbols are supposed to be */
-		if ((symtabindex == -1) && (symstrindex == -1))
-		{
-			int i;
-			/* Make sure that the address is page aligned... */
-			/* Symbols need to start in their own page(s)... */
-			estate.curaddr = (estate.curaddr + 4095) & ~4095;
-			
-			/* Need to make new indexes... */
-			for (i=0; i < estate.e.elf32.e_shnum; i++)
-			{
-				if (shdr[i].sh_type == SHT_SYMTAB)
-				{
-					int j;
-					for (j=0; j < estate.e.elf32.e_phnum; j++)
-					{
-						/* Check only for loaded sections */
-						if ((estate.p.phdr32[j].p_type | 0x80) == (PT_LOAD | 0x80))
-						{
-							/* Only the extra symbols */
-							if ((shdr[i].sh_offset >= estate.p.phdr32[j].p_offset) &&
-								((shdr[i].sh_offset + shdr[i].sh_size) <=
-									(estate.p.phdr32[j].p_offset + estate.p.phdr32[j].p_filesz)))
-							{
-								shdr[i].sh_offset=0;
-								shdr[i].sh_size=0;
-								break;
-							}
-						}
-					}
-					if ((shdr[i].sh_offset != 0) && (shdr[i].sh_size != 0))
-					{
-						symtabindex = i;
-						symstrindex = shdr[i].sh_link;
-					}
-				}
-			}
-		}
-		
-		/* Check if we have a symbol table index and have not loaded it */
-		if ((symtab_load == 0) && (symtabindex >= 0))
-		{
-			/* No symbol table yet?  Load it first... */
-			
-			/* This happens to work out in a strange way.
-			 * If we are past the point in the file already,
-			 * we will skip a *large* number of bytes which
-			 * ends up bringing us to the end of the file and
-			 * an old (default) boot.  Less code and lets
-			 * the state machine work in a cleaner way but this
-			 * is a nasty side-effect trick... */
-			estate.skip = shdr[symtabindex].sh_offset - (estate.loc + offset);
-			
-			/* And we need to read this many bytes... */
-			estate.toread = shdr[symtabindex].sh_size;
-			
-			if (estate.toread)
-			{
-#if ELF_DEBUG
-				printf("db sym, size %lX, curaddr %lX\n", 
-					estate.toread, estate.curaddr);
-#endif
-				/* Save where we are loading this... */
-				symtab_load = estate.curaddr;
-				
-				*((long *)phys_to_virt(estate.curaddr)) = estate.toread;
-				estate.curaddr += sizeof(long);
-				
-				/* Start to read... */
-				return 1;
-			}
-		}
-		else if ((symstr_load == 0) && (symstrindex >= 0))
-		{
-			/* We have already loaded the symbol table, so
-			 * now on to the symbol strings... */
-			
-			
-			/* Same nasty trick as above... */
-			estate.skip = shdr[symstrindex].sh_offset - (estate.loc + offset);
-			
-			/* And we need to read this many bytes... */
-			estate.toread = shdr[symstrindex].sh_size;
-			
-			if (estate.toread)
-			{
-#if ELF_DEBUG
-				printf("db str, size %lX, curaddr %lX\n", 
-					estate.toread, estate.curaddr);
-#endif
-				/* Save where we are loading this... */
-				symstr_load = estate.curaddr;
-				
-				*((long *)phys_to_virt(estate.curaddr)) = estate.toread;
-				estate.curaddr += sizeof(long);
-				
-				/* Start to read... */
-				return 1;
-			}
-		}
-	}
-	/* all done */
-	return 0;
-}
-
-static void elf_freebsd_boot(unsigned long entry) 
-{
-	if (image_type != Elf_FreeBSD)
-		return;
-
-	memset(&bsdinfo, 0, sizeof(bsdinfo));
-	bsdinfo.bi_basemem = meminfo.basememsize;
-	bsdinfo.bi_extmem = meminfo.memsize;
-	bsdinfo.bi_memsizes_valid = 1;
-	bsdinfo.bi_version = BOOTINFO_VERSION;
-	bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
-	bsdinfo.bi_nfs_diskless = NULL;
-	bsdinfo.bi_size = sizeof(bsdinfo);
-#define RB_BOOTINFO     0x80000000      /* have `struct bootinfo *' arg */  
-	if(freebsd_kernel_env[0] != '\0'){
-		freebsd_howto |= RB_BOOTINFO;
-		bsdinfo.bi_envp = (unsigned long)freebsd_kernel_env;
-	}
-	
-	/* Check if we have symbols loaded, and if so,
-	 * made the meta_data needed to pass those to
-	 * the kernel. */
-	if ((symtab_load !=0) && (symstr_load != 0))
-	{
-		unsigned long *t;
-		
-		bsdinfo.bi_symtab = symtab_load;
-		
-		/* End of symbols (long aligned...) */
-		/* Assumes size of long is a power of 2... */
-		bsdinfo.bi_esymtab = (symstr_load +
-			sizeof(long) +
-			*((long *)phys_to_virt(symstr_load)) +
-			sizeof(long) - 1) & ~(sizeof(long) - 1);
-		
-		/* Where we will build the meta data... */
-		t = phys_to_virt(bsdinfo.bi_esymtab);
-		
-#if ELF_DEBUG
-		printf("Metadata at %lX\n",t);
-#endif
-		
-		/* Set up the pointer to the memory... */
-		bsdinfo.bi_modulep = virt_to_phys(t);
-		
-		/* The metadata structure is an array of 32-bit
-		 * words where we store some information about the
-		 * system.  This is critical, as FreeBSD now looks
-		 * only for the metadata for the extended symbol
-		 * information rather than in the bootinfo.
-		 */
-		/* First, do the kernel name and the kernel type */
-		/* Note that this assumed x86 byte order... */
-		
-		/* 'kernel\0\0' */
-		*t++=MODINFO_NAME; *t++= 7; *t++=0x6E72656B; *t++=0x00006C65;
-		
-		/* 'elf kernel\0\0' */
-		*t++=MODINFO_TYPE; *t++=11; *t++=0x20666C65; *t++=0x6E72656B; *t++ = 0x00006C65;
-		
-		/* Now the symbol start/end - note that they are
-		 * here in local/physical address - the Kernel
-		 * boot process will relocate the addresses. */
-		*t++=MODINFOMD_SSYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_symtab;
-		*t++=MODINFOMD_ESYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_esymtab;
-		
-		*t++=MODINFO_END; *t++=0; /* end of metadata */
-		
-		/* Since we have symbols we need to make
-		 * sure that the kernel knows its own end
-		 * of memory...  It is not _end but after
-		 * the symbols and the metadata... */
-		bsdinfo.bi_kernend = virt_to_phys(t);
-		
-		/* Signal locore.s that we have a valid bootinfo
-		 * structure that was completely filled in. */
-		freebsd_howto |= 0x80000000;
-	}
-	
-	xstart32(entry, freebsd_howto, NODEV, 0, 0, 0, 
-		virt_to_phys(&bsdinfo), 0, 0, 0);
-	longjmp(restart_etherboot, -2);
-}
-#endif
-
-#ifdef AOUT_IMAGE
-static void aout_freebsd_probe(void)
-{
-	image_type = Aout;
-	if (((astate.head.a_midmag >> 16) & 0xffff) == 0) {
-		/* Some other a.out variants have a different
-		 * value, and use other alignments (e.g. 1K),
-		 * not the 4K used by FreeBSD.  */
-		image_type = Aout_FreeBSD;
-		printf("/FreeBSD");
-		off = -(astate.head.a_entry & 0xff000000);
-		astate.head.a_entry += off;
-	}
-}
-
-static void aout_freebsd_boot(void)
-{
-	if (image_type == Aout_FreeBSD) {
-		memset(&bsdinfo, 0, sizeof(bsdinfo));
-		bsdinfo.bi_basemem = meminfo.basememsize;
-		bsdinfo.bi_extmem = meminfo.memsize;
-		bsdinfo.bi_memsizes_valid = 1;
-		bsdinfo.bi_version = BOOTINFO_VERSION;
-		bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF);
-		bsdinfo.bi_nfs_diskless = NULL;
-		bsdinfo.bi_size = sizeof(bsdinfo);
-		xstart32(astate.head.a_entry, freebsd_howto, NODEV, 0, 0, 0, 
-			virt_to_phys(&bsdinfo), 0, 0, 0);
-		longjmp(restart_etherboot, -2);
-	}
-}
-#endif
diff --git a/roms/ipxe/src/arch/i386/core/gdbmach.c b/roms/ipxe/src/arch/i386/core/gdbmach.c
index 68b37c040552d67632922597e095..4232c7553b28791413469b6a7b18 100644
--- a/roms/ipxe/src/arch/i386/core/gdbmach.c
+++ b/roms/ipxe/src/arch/i386/core/gdbmach.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/i386/core/linux/linuxprefix.S b/roms/ipxe/src/arch/i386/core/linux/linuxprefix.S
new file mode 100644
index 0000000000000000000000000000000000000000..398d3cb213f6887a481aec7e69ed955e67a59bb8
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/core/linux/linuxprefix.S
@@ -0,0 +1,28 @@
+#include <linux/unistd.h>
+
+	.section ".text"
+	.code32
+	.globl _linux_start
+	.type _linux_start, @function
+
+_linux_start:
+	xorl	%ebp, %ebp
+
+	popl	%esi       // save argc
+	movl	%esp, %edi // save argv
+
+	andl	$~15, %esp // 16-byte align the stack
+
+	pushl	%edi // argv -> C arg2
+	pushl	%esi // argc -> C arg1
+
+	call	save_args
+
+	/* Our main doesn't use any arguments */
+	call	main
+
+	movl	%eax, %ebx // rc -> syscall arg1
+	movl	$__NR_exit, %eax
+	int	$0x80
+
+	.size _linux_start, . - _linux_start
diff --git a/roms/ipxe/src/arch/i386/core/pic8259.c b/roms/ipxe/src/arch/i386/core/pic8259.c
index 0264c0c1b518cd5e90e9acece112..0a9ea2e03a34b7be13175c3c117f 100644
--- a/roms/ipxe/src/arch/i386/core/pic8259.c
+++ b/roms/ipxe/src/arch/i386/core/pic8259.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/i386/core/rdtsc_timer.c b/roms/ipxe/src/arch/i386/core/rdtsc_timer.c
index d2a8cc84f8b3ec6e062c1d35f66e..2f31afc66f91a407bdde004a7987 100644
--- a/roms/ipxe/src/arch/i386/core/rdtsc_timer.c
+++ b/roms/ipxe/src/arch/i386/core/rdtsc_timer.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/i386/core/relocate.c b/roms/ipxe/src/arch/i386/core/relocate.c
index 47450e757725088c162984688487..5fbf2d2c27a419be250a8d2e7453 100644
--- a/roms/ipxe/src/arch/i386/core/relocate.c
+++ b/roms/ipxe/src/arch/i386/core/relocate.c
@@ -33,8 +33,10 @@ extern char _etextdata[];
 /**
  * Relocate iPXE
  *
- * @v ix86		x86 register dump from prefix
- * @ret ix86		x86 registers to return to prefix
+ * @v ebp		Maximum address to use for relocation
+ * @ret esi		Current physical address
+ * @ret edi		New physical address
+ * @ret ecx		Length to copy
  *
  * This finds a suitable location for iPXE near the top of 32-bit
  * address space, and returns the physical address of the new location
@@ -42,7 +44,7 @@ extern char _etextdata[];
  */
 __asmcall void relocate ( struct i386_all_regs *ix86 ) {
 	struct memory_map memmap;
-	unsigned long start, end, size, padded_size;
+	unsigned long start, end, size, padded_size, max;
 	unsigned long new_start, new_end;
 	unsigned i;
 
@@ -57,6 +59,13 @@ __asmcall void relocate ( struct i386_all_regs *ix86 ) {
 	      "...need %lx bytes for %d-byte alignment\n",
 	      start, end, padded_size, max_align );
 
+	/* Determine maximum usable address */
+	max = MAX_ADDR;
+	if ( ix86->regs.ebp < max ) {
+		max = ix86->regs.ebp;
+		DBG ( "Limiting relocation to [0,%lx)\n", max );
+	}
+
 	/* Walk through the memory map and find the highest address
 	 * below 4GB that iPXE will fit into.
 	 */
@@ -67,18 +76,18 @@ __asmcall void relocate ( struct i386_all_regs *ix86 ) {
 
 		DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
 		
-		/* Truncate block to MAX_ADDR.  This will be less than
-		 * 4GB, which means that we can get away with using
-		 * just 32-bit arithmetic after this stage.
+		/* Truncate block to maximum address.  This will be
+		 * less than 4GB, which means that we can get away
+		 * with using just 32-bit arithmetic after this stage.
 		 */
-		if ( region->start > MAX_ADDR ) {
-			DBG ( "...starts after MAX_ADDR=%lx\n", MAX_ADDR );
+		if ( region->start > max ) {
+			DBG ( "...starts after max=%lx\n", max );
 			continue;
 		}
 		r_start = region->start;
-		if ( region->end > MAX_ADDR ) {
-			DBG ( "...end truncated to MAX_ADDR=%lx\n", MAX_ADDR );
-			r_end = MAX_ADDR;
+		if ( region->end > max ) {
+			DBG ( "...end truncated to max=%lx\n", max );
+			r_end = max;
 		} else {
 			r_end = region->end;
 		}
diff --git a/roms/ipxe/src/arch/i386/core/runtime.c b/roms/ipxe/src/arch/i386/core/runtime.c
new file mode 100644
index 0000000000000000000000000000000000000000..18ca7936e6f1e770fee4cdd44d83e131d4a50700
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/core/runtime.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2011 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Command line and initrd passed to iPXE at runtime
+ *
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/init.h>
+#include <ipxe/image.h>
+#include <ipxe/script.h>
+#include <ipxe/umalloc.h>
+#include <realmode.h>
+
+/** Command line physical address
+ *
+ * This can be set by the prefix.
+ */
+uint32_t __bss16 ( cmdline_phys );
+#define cmdline_phys __use_data16 ( cmdline_phys )
+
+/** initrd physical address
+ *
+ * This can be set by the prefix.
+ */
+uint32_t __bss16 ( initrd_phys );
+#define initrd_phys __use_data16 ( initrd_phys )
+
+/** initrd length
+ *
+ * This can be set by the prefix.
+ */
+uint32_t __bss16 ( initrd_len );
+#define initrd_len __use_data16 ( initrd_len )
+
+/** Internal copy of the command line */
+static char *cmdline_copy;
+
+/** Free command line image */
+static void cmdline_image_free ( struct refcnt *refcnt ) {
+	struct image *image = container_of ( refcnt, struct image, refcnt );
+
+	DBGC ( image, "RUNTIME freeing command line\n" );
+	free ( cmdline_copy );
+}
+
+/** Embedded script representing the command line */
+static struct image cmdline_image = {
+	.refcnt = REF_INIT ( cmdline_image_free ),
+	.name = "<CMDLINE>",
+	.type = &script_image_type,
+};
+
+/** Colour for debug messages */
+#define colour &cmdline_image
+
+/**
+ * Strip unwanted cruft from command line
+ *
+ * @v cmdline		Command line
+ * @v cruft		Initial substring of cruft to strip
+ */
+static void cmdline_strip ( char *cmdline, const char *cruft ) {
+	char *strip;
+	char *strip_end;
+
+	/* Find unwanted cruft, if present */
+	if ( ! ( strip = strstr ( cmdline, cruft ) ) )
+		return;
+
+	/* Strip unwanted cruft */
+	strip_end = strchr ( strip, ' ' );
+	if ( strip_end ) {
+		*strip_end = '\0';
+		DBGC ( colour, "RUNTIME stripping \"%s\"\n", strip );
+		strcpy ( strip, ( strip_end + 1 ) );
+	} else {
+		DBGC ( colour, "RUNTIME stripping \"%s\"\n", strip );
+		*strip = '\0';
+	}
+}
+
+/**
+ * Initialise command line
+ *
+ * @ret rc		Return status code
+ */
+static int cmdline_init ( void ) {
+	userptr_t cmdline_user;
+	char *cmdline;
+	size_t len;
+	int rc;
+
+	/* Do nothing if no command line was specified */
+	if ( ! cmdline_phys ) {
+		DBGC ( colour, "RUNTIME found no command line\n" );
+		return 0;
+	}
+	cmdline_user = phys_to_user ( cmdline_phys );
+	len = ( strlen_user ( cmdline_user, 0 ) + 1 /* NUL */ );
+
+	/* Allocate and copy command line */
+	cmdline_copy = malloc ( len );
+	if ( ! cmdline_copy ) {
+		DBGC ( colour, "RUNTIME could not allocate %zd bytes for "
+		       "command line\n", len );
+		rc = -ENOMEM;
+		goto err_alloc_cmdline_copy;
+	}
+	cmdline = cmdline_copy;
+	copy_from_user ( cmdline, cmdline_user, 0, len );
+	DBGC ( colour, "RUNTIME found command line \"%s\" at %08x\n",
+	       cmdline, cmdline_phys );
+
+	/* Mark command line as consumed */
+	cmdline_phys = 0;
+
+	/* Strip unwanted cruft from the command line */
+	cmdline_strip ( cmdline, "BOOT_IMAGE=" );
+	cmdline_strip ( cmdline, "initrd=" );
+	while ( isspace ( *cmdline ) )
+		cmdline++;
+	DBGC ( colour, "RUNTIME using command line \"%s\"\n", cmdline );
+
+	/* Prepare and register image */
+	cmdline_image.data = virt_to_user ( cmdline );
+	cmdline_image.len = strlen ( cmdline );
+	if ( cmdline_image.len ) {
+		if ( ( rc = register_image ( &cmdline_image ) ) != 0 ) {
+			DBGC ( colour, "RUNTIME could not register command "
+			       "line: %s\n", strerror ( rc ) );
+			goto err_register_image;
+		}
+	}
+
+	/* Drop our reference to the image */
+	image_put ( &cmdline_image );
+
+	return 0;
+
+ err_register_image:
+	image_put ( &cmdline_image );
+ err_alloc_cmdline_copy:
+	return rc;
+}
+
+/**
+ * Initialise initrd
+ *
+ * @ret rc		Return status code
+ */
+static int initrd_init ( void ) {
+	struct image *image;
+	int rc;
+
+	/* Do nothing if no initrd was specified */
+	if ( ! initrd_phys ) {
+		DBGC ( colour, "RUNTIME found no initrd\n" );
+		return 0;
+	}
+	if ( ! initrd_len ) {
+		DBGC ( colour, "RUNTIME found empty initrd\n" );
+		return 0;
+	}
+	DBGC ( colour, "RUNTIME found initrd at [%x,%x)\n",
+	       initrd_phys, ( initrd_phys + initrd_len ) );
+
+	/* Allocate image */
+	image = alloc_image ( NULL );
+	if ( ! image ) {
+		DBGC ( colour, "RUNTIME could not allocate image for "
+		       "initrd\n" );
+		rc = -ENOMEM;
+		goto err_alloc_image;
+	}
+	if ( ( rc = image_set_name ( image, "<INITRD>" ) ) != 0 ) {
+		DBGC ( colour, "RUNTIME could not set image name: %s\n",
+		       strerror ( rc ) );
+		goto err_set_name;
+	}
+
+	/* Allocate and copy initrd content */
+	image->data = umalloc ( initrd_len );
+	if ( ! image->data ) {
+		DBGC ( colour, "RUNTIME could not allocate %d bytes for "
+		       "initrd\n", initrd_len );
+		rc = -ENOMEM;
+		goto err_umalloc;
+	}
+	image->len = initrd_len;
+	memcpy_user ( image->data, 0, phys_to_user ( initrd_phys ), 0,
+		      initrd_len );
+
+	/* Mark initrd as consumed */
+	initrd_phys = 0;
+
+	/* Register image */
+	if ( ( rc = register_image ( image ) ) != 0 ) {
+		DBGC ( colour, "RUNTIME could not register initrd: %s\n",
+		       strerror ( rc ) );
+		goto err_register_image;
+	}
+
+	/* Drop our reference to the image */
+	image_put ( image );
+
+	return 0;
+
+ err_register_image:
+ err_umalloc:
+ err_set_name:
+	image_put ( image );
+ err_alloc_image:
+	return rc;
+}
+
+/**
+ * Initialise command line and initrd
+ *
+ */
+static void runtime_init ( void ) {
+	int rc;
+
+	/* Initialise command line */
+	if ( ( rc = cmdline_init() ) != 0 ) {
+		/* No way to report failure */
+		return;
+	}
+
+	/* Initialise initrd */
+	if ( ( rc = initrd_init() ) != 0 ) {
+		/* No way to report failure */
+		return;
+	}
+}
+
+/** Command line and initrd initialisation function */
+struct startup_fn runtime_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
+	.startup = runtime_init,
+};
diff --git a/roms/ipxe/src/arch/i386/core/video_subr.c b/roms/ipxe/src/arch/i386/core/video_subr.c
index 6885ad9af26d54cbdeb4d1d46306..306c6d56cc1b4fbd67f2a6ade903 100644
--- a/roms/ipxe/src/arch/i386/core/video_subr.c
+++ b/roms/ipxe/src/arch/i386/core/video_subr.c
@@ -11,6 +11,14 @@
 #include <ipxe/console.h>
 #include <ipxe/init.h>
 #include "vga.h"
+#include <config/console.h>
+
+/* Set default console usage if applicable */
+#if ! ( defined ( CONSOLE_DIRECT_VGA ) && \
+	CONSOLE_EXPLICIT ( CONSOLE_DIRECT_VGA ) )
+#undef CONSOLE_DIRECT_VGA
+#define CONSOLE_DIRECT_VGA ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
+#endif
 
 struct console_driver vga_console __console_driver;
 
@@ -97,6 +105,7 @@ static void vga_putc(int byte)
 struct console_driver vga_console __console_driver = {
 	.putchar = vga_putc,
 	.disabled = 1,
+	.usage = CONSOLE_DIRECT_VGA,
 };
 
 struct init_fn video_init_fn __init_fn ( INIT_EARLY ) = {
diff --git a/roms/ipxe/src/arch/i386/core/wince_loader.c b/roms/ipxe/src/arch/i386/core/wince_loader.c
deleted file mode 100644
index f452b659b8af31548458aac9ac2c139e5d1c8767..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/arch/i386/core/wince_loader.c
+++ /dev/null
@@ -1,273 +0,0 @@
-#define LOAD_DEBUG	0
-
-static int get_x_header(unsigned char *data, unsigned long now);
-static void jump_2ep();
-static unsigned char ce_signature[] = {'B', '0', '0', '0', 'F', 'F', '\n',};
-static char ** ep;
-
-#define BOOT_ARG_PTR_LOCATION 0x001FFFFC
-
-typedef struct _BOOT_ARGS{
-	unsigned char ucVideoMode;
-	unsigned char ucComPort;
-	unsigned char ucBaudDivisor;
-	unsigned char ucPCIConfigType;
-	
-	unsigned long dwSig;
-	#define BOOTARG_SIG 0x544F4F42
-	unsigned long dwLen;
-	
-	unsigned char ucLoaderFlags;
-	unsigned char ucEshellFlags;
-	unsigned char ucEdbgAdapterType;
-	unsigned char ucEdbgIRQ;
-	
-	unsigned long dwEdbgBaseAddr;
-	unsigned long dwEdbgDebugZone;	
-	unsigned long dwDHCPLeaseTime;
-	unsigned long dwEdbgFlags;
-	
-	unsigned long dwEBootFlag;
-	unsigned long dwEBootAddr;
-	unsigned long dwLaunchAddr;
-	
-	unsigned long pvFlatFrameBuffer;
-	unsigned short vesaMode;
-	unsigned short cxDisplayScreen;
-	unsigned short cyDisplayScreen;
-	unsigned short cxPhysicalScreen;
-	unsigned short cyPhysicalScreen;
-	unsigned short cbScanLineLength;
-	unsigned short bppScreen;
-	
-	unsigned char RedMaskSize;
-	unsigned char REdMaskPosition;
-	unsigned char GreenMaskSize;
-	unsigned char GreenMaskPosition;
-	unsigned char BlueMaskSize;
-	unsigned char BlueMaskPosition;
-} BOOT_ARGS;
-
-BOOT_ARGS BootArgs;
-
-static struct segment_info{
-	unsigned long addr;		// Section Address
-	unsigned long size;		// Section Size
-	unsigned long checksum;		// Section CheckSum
-} X;
-
-#define PSIZE	(1500)			//Max Packet Size
-#define DSIZE  (PSIZE+12)
-static unsigned long dbuffer_available =0;
-static unsigned long not_loadin =0;
-static unsigned long d_now =0;
-
-unsigned long entry;
-static unsigned long ce_curaddr;
-
-
-static sector_t ce_loader(unsigned char *data, unsigned int len, int eof);
-static os_download_t wince_probe(unsigned char *data, unsigned int len)
-{
-	if (strncmp(ce_signature, data, sizeof(ce_signature)) != 0) {
-		return 0;
-	}
-	printf("(WINCE)");
-	return ce_loader;
-}
-
-static sector_t ce_loader(unsigned char *data, unsigned int len, int eof)
-{
-	static unsigned char dbuffer[DSIZE];
-	int this_write = 0;
-	static int firsttime = 1;
-
-	/*
-	 *	new packet in, we have to 
-	 *	[1] copy data to dbuffer,
-	 *
-	 *	update...
-	 *	[2]  dbuffer_available
-	 */
-	memcpy( (dbuffer+dbuffer_available), data, len);	//[1]
-	dbuffer_available += len;	// [2]
-	len = 0;
-
-	d_now = 0;
-	
-#if 0
-	printf("dbuffer_available =%ld \n", dbuffer_available);
-#endif 
-	
-	if (firsttime) 
-	{
-		d_now = sizeof(ce_signature);
-		printf("String Physical Address = %lx \n", 
-			*(unsigned long *)(dbuffer+d_now));
-		
-		d_now += sizeof(unsigned long);
-		printf("Image Size = %ld [%lx]\n", 
-			*(unsigned long *)(dbuffer+d_now), 
-			*(unsigned long *)(dbuffer+d_now));
-		
-		d_now += sizeof(unsigned long);
-		dbuffer_available -= d_now;			
-		
-		d_now = (unsigned long)get_x_header(dbuffer, d_now);
-		firsttime = 0;
-	}
-	
-	if (not_loadin == 0)
-	{
-		d_now = get_x_header(dbuffer, d_now);
-	}
-	
-	while ( not_loadin > 0 )
-	{
-		/* dbuffer do not have enough data to loading, copy all */
-#if LOAD_DEBUG
-		printf("[0] not_loadin = [%ld], dbuffer_available = [%ld] \n", 
-			not_loadin, dbuffer_available);
-		printf("[0] d_now = [%ld] \n", d_now);
-#endif
-		
-		if( dbuffer_available <= not_loadin)
-		{
-			this_write = dbuffer_available ;
-			memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write );
-			ce_curaddr += this_write;
-			not_loadin -= this_write;
-			
-			/* reset index and available in the dbuffer */
-			dbuffer_available = 0;
-			d_now = 0;
-#if LOAD_DEBUG
-			printf("[1] not_loadin = [%ld], dbuffer_available = [%ld] \n", 
-				not_loadin, dbuffer_available);
-			printf("[1] d_now = [%ld], this_write = [%d] \n", 
-				d_now, this_write);
-#endif
-				
-			// get the next packet...
-			return (0);
-		}
-			
-		/* dbuffer have more data then loading ... , copy partital.... */
-		else
-		{
-			this_write = not_loadin;
-			memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write);
-			ce_curaddr += this_write;
-			not_loadin = 0;
-			
-			/* reset index and available in the dbuffer */
-			dbuffer_available -= this_write;
-			d_now += this_write;
-#if LOAD_DEBUG
-			printf("[2] not_loadin = [%ld], dbuffer_available = [%ld] \n", 
-				not_loadin, dbuffer_available);
-			printf("[2] d_now = [%ld], this_write = [%d] \n\n", 
-				d_now, this_write);
-#endif
-			
-			/* dbuffer not empty, proceed processing... */
-			
-			// don't have enough data to get_x_header..
-			if ( dbuffer_available < (sizeof(unsigned long) * 3) )
-			{
-//				printf("we don't have enough data remaining to call get_x. \n");
-				memcpy( (dbuffer+0), (dbuffer+d_now), dbuffer_available);
-				return (0);
-			}
-			else
-			{
-#if LOAD_DEBUG				
-				printf("with remaining data to call get_x \n");
-				printf("dbuffer available = %ld , d_now = %ld\n", 
-					dbuffer_available, d_now);
-#endif					
-				d_now = get_x_header(dbuffer, d_now);
-			}
-		}
-	}
-	return (0);
-}
-
-static int get_x_header(unsigned char *dbuffer, unsigned long now)
-{
-	X.addr = *(unsigned long *)(dbuffer + now);
-	X.size = *(unsigned long *)(dbuffer + now + sizeof(unsigned long));
-	X.checksum = *(unsigned long *)(dbuffer + now + sizeof(unsigned long)*2);
-
-	if (X.addr == 0)
-	{
-		entry = X.size;
-		done(1);
-		printf("Entry Point Address = [%lx] \n", entry);
-		jump_2ep();		
-	}
-
-	if (!prep_segment(X.addr, X.addr + X.size, X.addr + X.size, 0, 0)) {
-		longjmp(restart_etherboot, -2);
-	}
-
-	ce_curaddr = X.addr;
-	now += sizeof(unsigned long)*3;
-
-	/* re-calculate dbuffer available... */
-	dbuffer_available -= sizeof(unsigned long)*3;
-
-	/* reset index of this section */
-	not_loadin = X.size;
-	
-#if 1
-	printf("\n");
-	printf("\t Section Address = [%lx] \n", X.addr);
-	printf("\t Size = %d [%lx]\n", X.size, X.size);
-	printf("\t Checksum = %ld [%lx]\n", X.checksum, X.checksum);
-#endif
-#if LOAD_DEBUG
-	printf("____________________________________________\n");
-	printf("\t dbuffer_now = %ld \n", now);
-	printf("\t dbuffer available = %ld \n", dbuffer_available);
-	printf("\t not_loadin = %ld \n", not_loadin);
-#endif
-
-	return now;
-}
-
-static void jump_2ep()
-{
-	BootArgs.ucVideoMode = 1;
-	BootArgs.ucComPort = 1;
-	BootArgs.ucBaudDivisor = 1;
-	BootArgs.ucPCIConfigType = 1;	// do not fill with 0
-	
-	BootArgs.dwSig = BOOTARG_SIG;
-	BootArgs.dwLen = sizeof(BootArgs);
-	
-	if(BootArgs.ucVideoMode == 0)
-	{
-		BootArgs.cxDisplayScreen = 640;
-		BootArgs.cyDisplayScreen = 480;
-		BootArgs.cxPhysicalScreen = 640;
-		BootArgs.cyPhysicalScreen = 480;
-		BootArgs.bppScreen = 16;
-		BootArgs.cbScanLineLength  = 1024;
-		BootArgs.pvFlatFrameBuffer = 0x800a0000;	// ollie say 0x98000000
-	}	
-	else if(BootArgs.ucVideoMode != 0xFF)
-	{
-		BootArgs.cxDisplayScreen = 0;
-		BootArgs.cyDisplayScreen = 0;
-		BootArgs.cxPhysicalScreen = 0;
-		BootArgs.cyPhysicalScreen = 0;
-		BootArgs.bppScreen = 0;
-		BootArgs.cbScanLineLength  = 0;
-		BootArgs.pvFlatFrameBuffer = 0;	
-	}
-
-	ep = phys_to_virt(BOOT_ARG_PTR_LOCATION);
-	*ep= virt_to_phys(&BootArgs);
-	xstart32(entry);
-}
diff --git a/roms/ipxe/src/arch/i386/core/x86_io.c b/roms/ipxe/src/arch/i386/core/x86_io.c
deleted file mode 100644
index 2fba0680c825a25357f280db9e94827760015a61..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/arch/i386/core/x86_io.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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_LICENCE ( GPL2_OR_LATER );
-
-#include <ipxe/io.h>
-#include <ipxe/x86_io.h>
-
-/** @file
- *
- * iPXE 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/roms/ipxe/src/arch/i386/drivers/net/undi.c b/roms/ipxe/src/arch/i386/drivers/net/undi.c
index 34fd09562857571faa4edd1cf0d9..2bc54824c7b1abadc143cdcfaf94 100644
--- a/roms/ipxe/src/arch/i386/drivers/net/undi.c
+++ b/roms/ipxe/src/arch/i386/drivers/net/undi.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -140,7 +141,7 @@ static struct pci_device_id undipci_nics[] = {
 PCI_ROM ( 0xffff, 0xffff, "undipci", "UNDI (PCI)", 0 ),
 };
 
-struct pci_driver undipci_driver __pci_driver = {
+struct pci_driver undipci_driver __pci_driver_fallback = {
 	.ids = undipci_nics,
 	.id_count = ( sizeof ( undipci_nics ) / sizeof ( undipci_nics[0] ) ),
 	.probe = undipci_probe,
diff --git a/roms/ipxe/src/arch/i386/drivers/net/undiload.c b/roms/ipxe/src/arch/i386/drivers/net/undiload.c
index c278db79588ecd589bb43bfe8981..0edfa35dc607715d56f4fcd64307 100644
--- a/roms/ipxe/src/arch/i386/drivers/net/undiload.c
+++ b/roms/ipxe/src/arch/i386/drivers/net/undiload.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/i386/drivers/net/undinet.c b/roms/ipxe/src/arch/i386/drivers/net/undinet.c
index 56bd628863acfdcf3bed126bc18f..e956b989adfdd3034dfbbd61de3a 100644
--- a/roms/ipxe/src/arch/i386/drivers/net/undinet.c
+++ b/roms/ipxe/src/arch/i386/drivers/net/undinet.c
@@ -13,12 +13,15 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <string.h>
+#include <unistd.h>
+#include <byteswap.h>
 #include <pxe.h>
 #include <realmode.h>
 #include <pic8259.h>
@@ -34,7 +37,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <undinet.h>
 #include <pxeparent.h>
 
-
 /** @file
  *
  * UNDI network device driver
@@ -63,6 +65,15 @@ struct undi_nic {
 
 /** @} */
 
+/** Maximum number of times to retry PXENV_UNDI_INITIALIZE */
+#define UNDI_INITIALIZE_RETRY_MAX 10
+
+/** Delay between retries of PXENV_UNDI_INITIALIZE */
+#define UNDI_INITIALIZE_RETRY_DELAY_MS 200
+
+/** Alignment of received frame payload */
+#define UNDI_RX_ALIGN 16
+
 static void undinet_close ( struct net_device *netdev );
 
 /** Address of UNDI entry point */
@@ -160,6 +171,10 @@ static int undinet_isr_triggered ( void ) {
 static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd );
 #define undinet_tbd __use_data16 ( undinet_tbd )
 
+/** UNDI transmit destination address */
+static uint8_t __data16_array ( undinet_destaddr, [ETH_ALEN] );
+#define undinet_destaddr __use_data16 ( undinet_destaddr )
+
 /**
  * Transmit packet
  *
@@ -169,8 +184,14 @@ static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd );
  */
 static int undinet_transmit ( struct net_device *netdev,
 			      struct io_buffer *iobuf ) {
+	struct undi_nic *undinic = netdev->priv;
 	struct s_PXENV_UNDI_TRANSMIT undi_transmit;
-	size_t len = iob_len ( iobuf );
+	const void *ll_dest;
+	const void *ll_source;
+	uint16_t net_proto;
+	unsigned int flags;
+	uint8_t protocol;
+	size_t len;
 	int rc;
 
 	/* Technically, we ought to make sure that the previous
@@ -183,15 +204,49 @@ static int undinet_transmit ( struct net_device *netdev,
 	 * transmit the next packet.
 	 */
 
+	/* Some PXE stacks are unable to cope with P_UNKNOWN, and will
+	 * always try to prepend a link-layer header.  Work around
+	 * these stacks by stripping the existing link-layer header
+	 * and allowing the PXE stack to (re)construct the link-layer
+	 * header itself.
+	 */
+	if ( ( rc = eth_pull ( netdev, iobuf, &ll_dest, &ll_source,
+			       &net_proto, &flags ) ) != 0 ) {
+		DBGC ( undinic, "UNDINIC %p could not strip Ethernet header: "
+		       "%s\n", undinic, strerror ( rc ) );
+		return rc;
+	}
+	memcpy ( undinet_destaddr, ll_dest, sizeof ( undinet_destaddr ) );
+	switch ( net_proto ) {
+	case htons ( ETH_P_IP ) :
+		protocol = P_IP;
+		break;
+	case htons ( ETH_P_ARP ) :
+		protocol = P_ARP;
+		break;
+	case htons ( ETH_P_RARP ) :
+		protocol = P_RARP;
+		break;
+	default:
+		/* Unknown protocol; restore the original link-layer header */
+		iob_push ( iobuf, sizeof ( struct ethhdr ) );
+		protocol = P_UNKNOWN;
+		break;
+	}
+
 	/* Copy packet to UNDI I/O buffer */
+	len = iob_len ( iobuf );
 	if ( len > sizeof ( basemem_packet ) )
 		len = sizeof ( basemem_packet );
 	memcpy ( &basemem_packet, iobuf->data, len );
 
 	/* Create PXENV_UNDI_TRANSMIT data structure */
 	memset ( &undi_transmit, 0, sizeof ( undi_transmit ) );
+	undi_transmit.Protocol = protocol;
+	undi_transmit.XmitFlag = ( ( flags & LL_BROADCAST ) ?
+				   XMT_BROADCAST : XMT_DESTADDR );
 	undi_transmit.DestAddr.segment = rm_ds;
-	undi_transmit.DestAddr.offset = __from_data16 ( &undinet_tbd );
+	undi_transmit.DestAddr.offset = __from_data16 ( &undinet_destaddr );
 	undi_transmit.TBD.segment = rm_ds;
 	undi_transmit.TBD.offset = __from_data16 ( &undinet_tbd );
 
@@ -248,6 +303,7 @@ static void undinet_poll ( struct net_device *netdev ) {
 	struct s_PXENV_UNDI_ISR undi_isr;
 	struct io_buffer *iobuf = NULL;
 	size_t len;
+	size_t reserve_len;
 	size_t frag_len;
 	size_t max_frag_len;
 	int rc;
@@ -295,6 +351,8 @@ static void undinet_poll ( struct net_device *netdev ) {
 			/* Packet fragment received */
 			len = undi_isr.FrameLength;
 			frag_len = undi_isr.BufferLength;
+			reserve_len = ( -undi_isr.FrameHeaderLength &
+					( UNDI_RX_ALIGN - 1 ) );
 			if ( ( len == 0 ) || ( len < frag_len ) ) {
 				/* Don't laugh.  VMWare does it. */
 				DBGC ( undinic, "UNDINIC %p reported insane "
@@ -303,15 +361,17 @@ static void undinet_poll ( struct net_device *netdev ) {
 				netdev_rx_err ( netdev, NULL, -EINVAL );
 				break;
 			}
-			if ( ! iobuf )
-				iobuf = alloc_iob ( len );
 			if ( ! iobuf ) {
-				DBGC ( undinic, "UNDINIC %p could not "
-				       "allocate %zd bytes for RX buffer\n",
-				       undinic, len );
-				/* Fragment will be dropped */
-				netdev_rx_err ( netdev, NULL, -ENOMEM );
-				goto done;
+				iobuf = alloc_iob ( reserve_len + len );
+				if ( ! iobuf ) {
+					DBGC ( undinic, "UNDINIC %p could not "
+					       "allocate %zd bytes for RX "
+					       "buffer\n", undinic, len );
+					/* Fragment will be dropped */
+					netdev_rx_err ( netdev, NULL, -ENOMEM );
+					goto done;
+				}
+				iob_reserve ( iobuf, reserve_len );
 			}
 			max_frag_len = iob_tailroom ( iobuf );
 			if ( frag_len > max_frag_len ) {
@@ -471,6 +531,53 @@ static struct net_device_operations undinet_operations = {
 	.irq   		= undinet_irq,
 };
 
+/** A device with broken support for generating interrupts */
+struct undinet_irq_broken {
+	/** PCI vendor ID */
+	uint16_t pci_vendor;
+	/** PCI device ID */
+	uint16_t pci_device;
+};
+
+/**
+ * List of devices with broken support for generating interrupts
+ *
+ * Some PXE stacks are known to claim that IRQs are supported, but
+ * then never generate interrupts.  No satisfactory solution has been
+ * found to this problem; the workaround is to add the PCI vendor and
+ * device IDs to this list.  This is something of a hack, since it
+ * will generate false positives for identical devices with a working
+ * PXE stack (e.g. those that have been reflashed with iPXE), but it's
+ * an improvement on the current situation.
+ */
+static const struct undinet_irq_broken undinet_irq_broken_list[] = {
+	/* HP XX70x laptops */
+	{ .pci_vendor = 0x8086, .pci_device = 0x1502 },
+	{ .pci_vendor = 0x8086, .pci_device = 0x1503 },
+};
+
+/**
+ * Check for devices with broken support for generating interrupts
+ *
+ * @v undi		UNDI device
+ * @ret irq_is_broken	Interrupt support is broken; no interrupts are generated
+ */
+static int undinet_irq_is_broken ( struct undi_device *undi ) {
+	const struct undinet_irq_broken *broken;
+	unsigned int i;
+
+	for ( i = 0 ; i < ( sizeof ( undinet_irq_broken_list ) /
+			    sizeof ( undinet_irq_broken_list[0] ) ) ; i++ ) {
+		broken = &undinet_irq_broken_list[i];
+		if ( ( undi->dev.desc.bus_type == BUS_TYPE_PCI ) &&
+		     ( undi->dev.desc.vendor == broken->pci_vendor ) &&
+		     ( undi->dev.desc.device == broken->pci_device ) ) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
 /**
  * Probe UNDI device
  *
@@ -482,12 +589,13 @@ int undinet_probe ( struct undi_device *undi ) {
 	struct undi_nic *undinic;
 	struct s_PXENV_START_UNDI start_undi;
 	struct s_PXENV_UNDI_STARTUP undi_startup;
-	struct s_PXENV_UNDI_INITIALIZE undi_initialize;
+	struct s_PXENV_UNDI_INITIALIZE undi_init;
 	struct s_PXENV_UNDI_GET_INFORMATION undi_info;
 	struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
 	struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
 	struct s_PXENV_UNDI_CLEANUP undi_cleanup;
 	struct s_PXENV_STOP_UNDI stop_undi;
+	unsigned int retry;
 	int rc;
 
 	/* Allocate net device */
@@ -524,12 +632,27 @@ int undinet_probe ( struct undi_device *undi ) {
 					     &undi_startup,
 					     sizeof ( undi_startup ) ) ) != 0 )
 			goto err_undi_startup;
-		memset ( &undi_initialize, 0, sizeof ( undi_initialize ) );
-		if ( ( rc = pxeparent_call ( undinet_entry,
-					     PXENV_UNDI_INITIALIZE,
-					     &undi_initialize,
-					     sizeof ( undi_initialize ))) != 0 )
-			goto err_undi_initialize;
+		/* On some PXE stacks, PXENV_UNDI_INITIALIZE may fail
+		 * due to a transient condition (e.g. media test
+		 * failing because the link has only just come out of
+		 * reset).  We may therefore need to retry this call
+		 * several times.
+		 */
+		for ( retry = 0 ; ; ) {
+			memset ( &undi_init, 0, sizeof ( undi_init ) );
+			if ( ( rc = pxeparent_call ( undinet_entry,
+						     PXENV_UNDI_INITIALIZE,
+						     &undi_init,
+						     sizeof ( undi_init ))) ==0)
+				break;
+			if ( ++retry > UNDI_INITIALIZE_RETRY_MAX )
+				goto err_undi_initialize;
+			DBGC ( undinic, "UNDINIC %p retrying "
+			       "PXENV_UNDI_INITIALIZE (retry %d)\n",
+			       undinic, retry );
+			/* Delay to allow link to settle if necessary */
+			mdelay ( UNDI_INITIALIZE_RETRY_DELAY_MS );
+		}
 	}
 	undi->flags |= UNDI_FL_INITIALIZED;
 
@@ -539,6 +662,7 @@ int undinet_probe ( struct undi_device *undi ) {
 				     &undi_info, sizeof ( undi_info ) ) ) != 0 )
 		goto err_undi_get_information;
 	memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
+	memcpy ( netdev->ll_addr, undi_info.CurrentNodeAddress, ETH_ALEN );
 	undinic->irq = undi_info.IntNumber;
 	if ( undinic->irq > IRQ_MAX ) {
 		DBGC ( undinic, "UNDINIC %p has invalid IRQ %d\n",
@@ -558,8 +682,10 @@ int undinet_probe ( struct undi_device *undi ) {
 	DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n",
 	       undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
 	       undi_iface.ServiceFlags );
-	if ( undi_iface.ServiceFlags & SUPPORTED_IRQ )
+	if ( ( undi_iface.ServiceFlags & SUPPORTED_IRQ ) &&
+	     ( undinic->irq != 0 ) ) {
 		undinic->irq_supported = 1;
+	}
 	DBGC ( undinic, "UNDINIC %p using %s mode\n", undinic,
 	       ( undinic->irq_supported ? "interrupt" : "polling" ) );
 	if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
@@ -568,6 +694,11 @@ int undinet_probe ( struct undi_device *undi ) {
 		       undinic );
 		undinic->hacks |= UNDI_HACK_EB54;
 	}
+	if ( undinet_irq_is_broken ( undi ) ) {
+		DBGC ( undinic, "UNDINIC %p forcing polling mode due to "
+		       "broken interrupts\n", undinic );
+		undinic->irq_supported = 0;
+	}
 
 	/* Register network device */
 	if ( ( rc = register_netdev ( netdev ) ) != 0 )
diff --git a/roms/ipxe/src/arch/i386/drivers/net/undionly.c b/roms/ipxe/src/arch/i386/drivers/net/undionly.c
index c38b574dbc433a8c1f7435d1bc7c..028fac5d9475b39b6a18b16a402f 100644
--- a/roms/ipxe/src/arch/i386/drivers/net/undionly.c
+++ b/roms/ipxe/src/arch/i386/drivers/net/undionly.c
@@ -13,16 +13,19 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
 #include <ipxe/device.h>
 #include <ipxe/init.h>
+#include <ipxe/pci.h>
 #include <undi.h>
 #include <undinet.h>
 #include <undipreload.h>
@@ -62,15 +65,21 @@ static int undibus_probe ( struct root_device *rootdev ) {
 	}
 
 	/* Add to device hierarchy */
-	strncpy ( undi->dev.name, "UNDI",
-		  ( sizeof ( undi->dev.name ) - 1 ) );
+	undi->dev.driver_name = "undionly";
 	if ( undi->pci_busdevfn != UNDI_NO_PCI_BUSDEVFN ) {
 		undi->dev.desc.bus_type = BUS_TYPE_PCI;
 		undi->dev.desc.location = undi->pci_busdevfn;
 		undi->dev.desc.vendor = undi->pci_vendor;
 		undi->dev.desc.device = undi->pci_device;
+		snprintf ( undi->dev.name, sizeof ( undi->dev.name ),
+			   "UNDI-PCI%02x:%02x.%x",
+			   PCI_BUS ( undi->pci_busdevfn ),
+			   PCI_SLOT ( undi->pci_busdevfn ),
+			   PCI_FUNC ( undi->pci_busdevfn ) );
 	} else if ( undi->isapnp_csn != UNDI_NO_ISAPNP_CSN ) {
 		undi->dev.desc.bus_type = BUS_TYPE_ISAPNP;
+		snprintf ( undi->dev.name, sizeof ( undi->dev.name ),
+			   "UNDI-ISAPNP" );
 	}
 	undi->dev.parent = &rootdev->dev;
 	list_add ( &undi->dev.siblings, &rootdev->dev.children);
diff --git a/roms/ipxe/src/arch/i386/drivers/net/undipreload.c b/roms/ipxe/src/arch/i386/drivers/net/undipreload.c
index a4b2f4ac76f4d7baaa92ceeabbe8..81d7a80eb7d3da9fe16d8d2fece4 100644
--- a/roms/ipxe/src/arch/i386/drivers/net/undipreload.c
+++ b/roms/ipxe/src/arch/i386/drivers/net/undipreload.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/i386/drivers/net/undirom.c b/roms/ipxe/src/arch/i386/drivers/net/undirom.c
index 2463d96981b1fdb767a332769042..b54c6170f116c2c3ff729f52401a 100644
--- a/roms/ipxe/src/arch/i386/drivers/net/undirom.c
+++ b/roms/ipxe/src/arch/i386/drivers/net/undirom.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c b/roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c
index d18e8b8099cab83238dcf8a0c19e..b23f2c356c09972ae011be1fb50d 100644
--- a/roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c
+++ b/roms/ipxe/src/arch/i386/firmware/pcbios/basemem.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c b/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c
index 1ecd07dddeb59d2d28b77503c509..25c8dad2dd0feaec69752ff8a382 100644
--- a/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c
+++ b/roms/ipxe/src/arch/i386/firmware/pcbios/bios_console.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -23,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/console.h>
 #include <ipxe/ansiesc.h>
 #include <ipxe/keymap.h>
+#include <config/console.h>
 
 #define ATTR_BOLD		0x08
 
@@ -48,6 +50,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 #define ATTR_DEFAULT		ATTR_FCOL_WHITE
 
+/* Set default console usage if applicable */
+#if ! ( defined ( CONSOLE_PCBIOS ) && CONSOLE_EXPLICIT ( CONSOLE_PCBIOS ) )
+#undef CONSOLE_PCBIOS
+#define CONSOLE_PCBIOS ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
+#endif
+
 /** Current character attribute */
 static unsigned int bios_attr = ATTR_DEFAULT;
 
@@ -163,6 +171,14 @@ static void bios_putchar ( int character ) {
 					   /* Skip non-printable characters */
 					   "cmpb $0x20, %%al\n\t"
 					   "jb 1f\n\t"
+					   /* Read attribute */
+					   "movb %%al, %%cl\n\t"
+					   "movb $0x08, %%ah\n\t"
+					   "int $0x10\n\t"
+					   "xchgb %%al, %%cl\n\t"
+					   /* Skip if attribute matches */
+					   "cmpb %%ah, %%bl\n\t"
+					   "je 1f\n\t"
 					   /* Set attribute */
 					   "movw $0x0001, %%cx\n\t"
 					   "movb $0x09, %%ah\n\t"
@@ -201,6 +217,8 @@ static const char ansi_sequences[] = {
 	BIOS_KEY ( "\x4d", "[C" )	/* Right arrow */
 	BIOS_KEY ( "\x47", "[H" )	/* Home */
 	BIOS_KEY ( "\x4f", "[F" )	/* End */
+	BIOS_KEY ( "\x49", "[5~" )	/* Page up */
+	BIOS_KEY ( "\x51", "[6~" )	/* Page down */
 	BIOS_KEY ( "\x3f", "[15~" )	/* F5 */
 	BIOS_KEY ( "\x40", "[17~" )	/* F6 */
 	BIOS_KEY ( "\x41", "[18~" )	/* F7 */
@@ -311,4 +329,5 @@ struct console_driver bios_console __console_driver = {
 	.putchar = bios_putchar,
 	.getchar = bios_getchar,
 	.iskey = bios_iskey,
+	.usage = CONSOLE_PCBIOS,
 };
diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S b/roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S
index eeed51f894dde0d28cb55fa98935..cea17ef8e9299d85dfb994d1c970 100644
--- a/roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S
+++ b/roms/ipxe/src/arch/i386/firmware/pcbios/e820mangler.S
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER )
diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c b/roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c
index ea116fe50fe6accec3b247204377..e5f7137281c2d2588bf13529eb36 100644
--- a/roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c
+++ b/roms/ipxe/src/arch/i386/firmware/pcbios/fakee820.c
@@ -12,7 +12,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c b/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c
index cc5fc28f7350129f598c9b3c5ae6..8f3069e18eaba0c3ffc63d9c3be1 100644
--- a/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c
+++ b/roms/ipxe/src/arch/i386/firmware/pcbios/hidemem.c
@@ -12,7 +12,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -189,6 +190,8 @@ static void hide_etherboot ( void ) {
  * possible.
  */
 static void unhide_etherboot ( int flags __unused ) {
+	struct memory_map memmap;
+	int rc;
 
 	/* If we have more than one hooked interrupt at this point, it
 	 * means that some other vector is still hooked, in which case
@@ -202,15 +205,23 @@ static void unhide_etherboot ( int flags __unused ) {
 		return;
 	}
 
-	/* Try to unhook INT 15.  If it fails, then just leave it
-	 * hooked; it takes care of protecting itself.  :)
-	 */
-	unhook_bios_interrupt ( 0x15, ( unsigned int ) int15,
-				&int15_vector );
+	/* Try to unhook INT 15 */
+	if ( ( rc = unhook_bios_interrupt ( 0x15, ( unsigned int ) int15,
+					    &int15_vector ) ) != 0 ) {
+		DBG ( "Cannot unhook INT15: %s\n", strerror ( rc ) );
+		/* Leave it hooked; there's nothing else we can do,
+		 * and it should be intrinsically safe (though
+		 * wasteful of RAM).
+		 */
+	}
 
 	/* Unhook fake E820 map, if used */
 	if ( FAKE_E820 )
 		unfake_e820();
+
+	/* Dump memory map after unhiding */
+	DBG ( "Unhidden iPXE from system memory map\n" );
+	get_memmap ( &memmap );
 }
 
 /** Hide Etherboot startup function */
diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c b/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c
index 493d2c20134bee01205f4e7f6139..0937a7ce279655b10342153c853b 100644
--- a/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c
+++ b/roms/ipxe/src/arch/i386/firmware/pcbios/memmap.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -62,6 +63,10 @@ struct e820_entry {
 static struct e820_entry __bss16 ( e820buf );
 #define e820buf __use_data16 ( e820buf )
 
+/** We are running during POST; inhibit INT 15,e820 and INT 15,e801 */
+uint8_t __bss16 ( memmap_post );
+#define memmap_post __use_data16 ( memmap_post )
+
 /**
  * Get size of extended memory via INT 15,e801
  *
@@ -73,6 +78,12 @@ static unsigned int extmemsize_e801 ( void ) {
 	unsigned int flags;
 	unsigned int extmem;
 
+	/* Inhibit INT 15,e801 during POST */
+	if ( memmap_post ) {
+		DBG ( "INT 15,e801 not available during POST\n" );
+		return 0;
+	}
+
 	__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
 					   "int $0x15\n\t"
 					   "pushfw\n\t"
@@ -163,6 +174,12 @@ static int meme820 ( struct memory_map *memmap ) {
 	unsigned int flags;
 	unsigned int discard_D;
 
+	/* Inhibit INT 15,e820 during POST */
+	if ( memmap_post ) {
+		DBG ( "INT 15,e820 not available during POST\n" );
+		return -ENOTTY;
+	}
+
 	/* Clear the E820 buffer.  Do this once before starting,
 	 * rather than on each call; some BIOSes rely on the contents
 	 * being preserved between calls.
diff --git a/roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c b/roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c
index c572914f2cb10c7fdf7b7561a300..5c74b0431b0dc413cffc8ebeea60 100644
--- a/roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c
+++ b/roms/ipxe/src/arch/i386/firmware/pcbios/pnpbios.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c b/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c
index 79585cde82307773c951a26b7788..f86f180ce980a5badd8f70ab1c6d 100644
--- a/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c
+++ b/roms/ipxe/src/arch/i386/hci/commands/pxe_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #include <ipxe/netdevice.h>
diff --git a/roms/ipxe/src/arch/i386/hci/commands/reboot_cmd.c b/roms/ipxe/src/arch/i386/hci/commands/reboot_cmd.c
index d6a1d9a36fb00d5d0afd9947e394..74c69c94eec5729f28018e5e4142 100644
--- a/roms/ipxe/src/arch/i386/hci/commands/reboot_cmd.c
+++ b/roms/ipxe/src/arch/i386/hci/commands/reboot_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #include <realmode.h>
diff --git a/roms/ipxe/src/arch/i386/image/bootsector.c b/roms/ipxe/src/arch/i386/image/bootsector.c
index f96cf201e2942c26be2fab7874df..ab3cf94c21fbeda059d47d95cc6a 100644
--- a/roms/ipxe/src/arch/i386/image/bootsector.c
+++ b/roms/ipxe/src/arch/i386/image/bootsector.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -79,9 +80,22 @@ int call_bootsector ( unsigned int segment, unsigned int offset,
 					   "movw %%ss, %%ax\n\t"
 					   "movw %%ax, %%cs:saved_ss\n\t"
 					   "movw %%sp, %%cs:saved_sp\n\t"
-					   /* Jump to boot sector */
+					   /* Prepare jump to boot sector */
 					   "pushw %%bx\n\t"
 					   "pushw %%di\n\t"
+					   /* Clear all registers */
+					   "xorl %%eax, %%eax\n\t"
+					   "xorl %%ebx, %%ebx\n\t"
+					   "xorl %%ecx, %%ecx\n\t"
+					   /* %edx contains drive number */
+					   "xorl %%esi, %%esi\n\t"
+					   "xorl %%edi, %%edi\n\t"
+					   "xorl %%ebp, %%ebp\n\t"
+					   "movw %%ax, %%ds\n\t"
+					   "movw %%ax, %%es\n\t"
+					   "movw %%ax, %%fs\n\t"
+					   "movw %%ax, %%gs\n\t"
+					   /* Jump to boot sector */
 					   "sti\n\t"
 					   "lret\n\t"
 					   /* Preserved variables */
diff --git a/roms/ipxe/src/arch/i386/image/bzimage.c b/roms/ipxe/src/arch/i386/image/bzimage.c
index cc7aecab44ce98601c31227a5c5a..12be17793fbedf0d92b16f411e28 100644
--- a/roms/ipxe/src/arch/i386/image/bzimage.c
+++ b/roms/ipxe/src/arch/i386/image/bzimage.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -32,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <assert.h>
 #include <realmode.h>
 #include <bzimage.h>
+#include <initrd.h>
 #include <ipxe/uaccess.h>
 #include <ipxe/image.h>
 #include <ipxe/segment.h>
@@ -214,7 +216,8 @@ static void bzimage_update_header ( struct image *image,
 	} else {
 		bzimg->cmdline_magic.magic = BZI_CMDLINE_MAGIC;
 		bzimg->cmdline_magic.offset = bzimg->rm_cmdline;
-		bzimg->bzhdr.setup_move_size = bzimg->rm_memsz;
+		if ( bzimg->version >= 0x0200 )
+			bzimg->bzhdr.setup_move_size = bzimg->rm_memsz;
 	}
 
 	/* Set video mode */
@@ -302,11 +305,10 @@ static int bzimage_parse_cmdline ( struct image *image,
  * @v image		bzImage image
  * @v bzimg		bzImage context
  * @v cmdline		Kernel command line
- * @ret rc		Return status code
  */
-static int bzimage_set_cmdline ( struct image *image,
-				 struct bzimage_context *bzimg,
-				 const char *cmdline ) {
+static void bzimage_set_cmdline ( struct image *image,
+				  struct bzimage_context *bzimg,
+				  const char *cmdline ) {
 	size_t cmdline_len;
 
 	/* Copy command line down to real-mode portion */
@@ -316,8 +318,32 @@ static int bzimage_set_cmdline ( struct image *image,
 	copy_to_user ( bzimg->rm_kernel, bzimg->rm_cmdline,
 		       cmdline, cmdline_len );
 	DBGC ( image, "bzImage %p command line \"%s\"\n", image, cmdline );
+}
 
-	return 0;
+/**
+ * Parse standalone image command line for cpio parameters
+ *
+ * @v image		bzImage file
+ * @v cpio		CPIO header
+ * @v cmdline		Command line
+ */
+static void bzimage_parse_cpio_cmdline ( struct image *image,
+					 struct cpio_header *cpio,
+					 const char *cmdline ) {
+	char *arg;
+	char *end;
+	unsigned int mode;
+
+	/* Look for "mode=" */
+	if ( ( arg = strstr ( cmdline, "mode=" ) ) ) {
+		arg += 5;
+		mode = strtoul ( arg, &end, 8 /* Octal for file mode */ );
+		if ( *end && ( *end != ' ' ) ) {
+			DBGC ( image, "bzImage %p strange \"mode=\""
+			       "terminator '%c'\n", image, *end );
+		}
+		cpio_set_field ( cpio->c_mode, ( 0100000 | mode ) );
+	}
 }
 
 /**
@@ -326,14 +352,17 @@ static int bzimage_set_cmdline ( struct image *image,
  * @v image		bzImage image
  * @v initrd		initrd image
  * @v address		Address at which to load, or UNULL
- * @ret len		Length of loaded image, rounded up to 4 bytes
+ * @ret len		Length of loaded image, rounded up to INITRD_ALIGN
  */
 static size_t bzimage_load_initrd ( struct image *image,
 				    struct image *initrd,
 				    userptr_t address ) {
 	char *filename = initrd->cmdline;
+	char *cmdline;
 	struct cpio_header cpio;
         size_t offset = 0;
+	size_t name_len;
+	size_t pad_len;
 
 	/* Do not include kernel image itself as an initrd */
 	if ( initrd == image )
@@ -341,24 +370,28 @@ static size_t bzimage_load_initrd ( struct image *image,
 
 	/* Create cpio header before non-prebuilt images */
 	if ( filename && filename[0] ) {
-		size_t name_len = ( strlen ( filename ) + 1 );
-
-		DBGC ( image, "bzImage %p inserting initrd %p as %s\n",
-		       image, initrd, filename );
+		cmdline = strchr ( filename, ' ' );
+		name_len = ( ( cmdline ? ( ( size_t ) ( cmdline - filename ) )
+			       : strlen ( filename ) ) + 1 /* NUL */ );
 		memset ( &cpio, '0', sizeof ( cpio ) );
 		memcpy ( cpio.c_magic, CPIO_MAGIC, sizeof ( cpio.c_magic ) );
 		cpio_set_field ( cpio.c_mode, 0100644 );
 		cpio_set_field ( cpio.c_nlink, 1 );
 		cpio_set_field ( cpio.c_filesize, initrd->len );
 		cpio_set_field ( cpio.c_namesize, name_len );
+		if ( cmdline ) {
+			bzimage_parse_cpio_cmdline ( image, &cpio,
+						     ( cmdline + 1 /* ' ' */ ));
+		}
 		if ( address ) {
 			copy_to_user ( address, offset, &cpio,
 				       sizeof ( cpio ) );
 		}
 		offset += sizeof ( cpio );
 		if ( address ) {
+			memset_user ( address, offset, 0, name_len );
 			copy_to_user ( address, offset, filename,
-				       name_len );
+				       ( name_len - 1 /* NUL (or space) */ ) );
 		}
 		offset += name_len;
 		offset = ( ( offset + 0x03 ) & ~0x03 );
@@ -366,80 +399,146 @@ static size_t bzimage_load_initrd ( struct image *image,
 
 	/* Copy in initrd image body */
 	if ( address )
-		memcpy_user ( address, offset, initrd->data, 0, initrd->len );
-	offset += initrd->len;
+		memmove_user ( address, offset, initrd->data, 0, initrd->len );
 	if ( address ) {
-		DBGC ( image, "bzImage %p has initrd %p at [%lx,%lx)\n",
-		       image, initrd, user_to_phys ( address, 0 ),
-		       user_to_phys ( address, offset ) );
+		DBGC ( image, "bzImage %p initrd %p [%#08lx,%#08lx,%#08lx)"
+		       "%s%s\n", image, initrd, user_to_phys ( address, 0 ),
+		       user_to_phys ( address, offset ),
+		       user_to_phys ( address, ( offset + initrd->len ) ),
+		       ( filename ? " " : "" ), ( filename ? filename : "" ) );
+		DBGC2_MD5A ( image, user_to_phys ( address, offset ),
+			     user_to_virt ( address, offset ), initrd->len );
 	}
+	offset += initrd->len;
+
+	/* Round up to multiple of INITRD_ALIGN and zero-pad */
+	pad_len = ( ( -offset ) & ( INITRD_ALIGN - 1 ) );
+	if ( address )
+		memset_user ( address, offset, 0, pad_len );
+	offset += pad_len;
 
-	/* Round up to 4-byte boundary */
-	offset = ( ( offset + 0x03 ) & ~0x03 );
 	return offset;
 }
 
 /**
- * Load initrds, if any
+ * Check that initrds can be loaded
  *
  * @v image		bzImage image
  * @v bzimg		bzImage context
  * @ret rc		Return status code
  */
-static int bzimage_load_initrds ( struct image *image,
-				  struct bzimage_context *bzimg ) {
+static int bzimage_check_initrds ( struct image *image,
+				   struct bzimage_context *bzimg ) {
 	struct image *initrd;
-	size_t total_len = 0;
-	physaddr_t address;
+	userptr_t bottom;
+	size_t len = 0;
 	int rc;
 
-	/* Add up length of all initrd images */
-	for_each_image ( initrd )
-		total_len += bzimage_load_initrd ( image, initrd, UNULL );
+	/* Calculate total loaded length of initrds */
+	for_each_image ( initrd ) {
 
-	/* Give up if no initrd images found */
-	if ( ! total_len )
-		return 0;
+		/* Skip kernel */
+		if ( initrd == image )
+			continue;
+
+		/* Calculate length */
+		len += bzimage_load_initrd ( image, initrd, UNULL );
+
+		DBGC ( image, "bzImage %p initrd %p from [%#08lx,%#08lx)%s%s\n",
+		       image, initrd, user_to_phys ( initrd->data, 0 ),
+		       user_to_phys ( initrd->data, initrd->len ),
+		       ( initrd->cmdline ? " " : "" ),
+		       ( initrd->cmdline ? initrd->cmdline : "" ) );
+		DBGC2_MD5A ( image, user_to_phys ( initrd->data, 0 ),
+			     user_to_virt ( initrd->data, 0 ), initrd->len );
+	}
+
+	/* Calculate lowest usable address */
+	bottom = userptr_add ( bzimg->pm_kernel, bzimg->pm_sz );
 
-	/* Find a suitable start address.  Try 1MB boundaries,
-	 * starting from the downloaded kernel image itself and
-	 * working downwards until we hit an available region.
+	/* Check that total length fits within space available for
+	 * reshuffling.  This is a conservative check, since CPIO
+	 * headers are not present during reshuffling, but this
+	 * doesn't hurt and keeps the code simple.
 	 */
-	for ( address = ( user_to_phys ( image->data, 0 ) & ~0xfffff ) ; ;
-	      address -= 0x100000 ) {
-		/* Check that we're not going to overwrite the
-		 * kernel itself.  This check isn't totally
-		 * accurate, but errs on the side of caution.
-		 */
-		if ( address <= ( BZI_LOAD_HIGH_ADDR + image->len ) ) {
-			DBGC ( image, "bzImage %p could not find a location "
-			       "for initrd\n", image );
-			return -ENOBUFS;
-		}
-		/* Check that we are within the kernel's range */
-		if ( ( address + total_len - 1 ) > bzimg->mem_limit )
-			continue;
-		/* Prepare and verify segment */
-		if ( ( rc = prep_segment ( phys_to_user ( address ), 0,
-					   total_len ) ) != 0 )
-			continue;
-		/* Use this address */
-		break;
+	if ( ( rc = initrd_reshuffle_check ( len, bottom ) ) != 0 ) {
+		DBGC ( image, "bzImage %p failed reshuffle check: %s\n",
+		       image, strerror ( rc ) );
+		return rc;
 	}
 
-	/* Record initrd location */
-	bzimg->ramdisk_image = address;
-	bzimg->ramdisk_size = total_len;
+	/* Check that total length fits within kernel's memory limit */
+	if ( user_to_phys ( bottom, len ) > bzimg->mem_limit ) {
+		DBGC ( image, "bzImage %p not enough space for initrds\n",
+		       image );
+		return -ENOBUFS;
+	}
+
+	return 0;
+}
+
+/**
+ * Load initrds, if any
+ *
+ * @v image		bzImage image
+ * @v bzimg		bzImage context
+ */
+static void bzimage_load_initrds ( struct image *image,
+				   struct bzimage_context *bzimg ) {
+	struct image *initrd;
+	struct image *highest = NULL;
+	struct image *other;
+	userptr_t top;
+	userptr_t dest;
+	size_t len;
+
+	/* Reshuffle initrds into desired order */
+	initrd_reshuffle ( userptr_add ( bzimg->pm_kernel, bzimg->pm_sz ) );
 
-	/* Construct initrd */
-	DBGC ( image, "bzImage %p constructing initrd at [%lx,%lx)\n",
-	       image, address, ( address + total_len ) );
+	/* Find highest initrd */
 	for_each_image ( initrd ) {
-		address += bzimage_load_initrd ( image, initrd,
-						 phys_to_user ( address ) );
+		if ( ( highest == NULL ) ||
+		     ( userptr_sub ( initrd->data, highest->data ) > 0 ) ) {
+			highest = initrd;
+		}
 	}
 
-	return 0;
+	/* Do nothing if there are no initrds */
+	if ( ! highest )
+		return;
+
+	/* Find highest usable address */
+	top = userptr_add ( highest->data,
+			    ( ( highest->len + INITRD_ALIGN - 1 ) &
+			      ~( INITRD_ALIGN - 1 ) ) );
+	if ( user_to_phys ( top, 0 ) > bzimg->mem_limit )
+		top = phys_to_user ( bzimg->mem_limit );
+	DBGC ( image, "bzImage %p loading initrds from %#08lx downwards\n",
+	       image, user_to_phys ( top, 0 ) );
+
+	/* Load initrds in order */
+	for_each_image ( initrd ) {
+
+		/* Calculate cumulative length of following
+		 * initrds (including padding).
+		 */
+		len = 0;
+		for_each_image ( other ) {
+			if ( other == initrd )
+				len = 0;
+			len += bzimage_load_initrd ( image, other, UNULL );
+		}
+
+		/* Load initrd at this address */
+		dest = userptr_add ( top, -len );
+		bzimage_load_initrd ( image, initrd, dest );
+
+		/* Record initrd location */
+		if ( ! bzimg->ramdisk_image ) {
+			bzimg->ramdisk_image = user_to_phys ( dest, 0 );
+			bzimg->ramdisk_size = len;
+		}
+	}
 }
 
 /**
@@ -472,33 +571,37 @@ static int bzimage_exec ( struct image *image ) {
 		return rc;
 	}
 
+	/* Parse command line for bootloader parameters */
+	if ( ( rc = bzimage_parse_cmdline ( image, &bzimg, cmdline ) ) != 0)
+		return rc;
+
+	/* Check that initrds can be loaded */
+	if ( ( rc = bzimage_check_initrds ( image, &bzimg ) ) != 0 )
+		return rc;
+
+	/* Remove kernel from image list (without invalidating image pointer) */
+	unregister_image ( image_get ( image ) );
+
 	/* Load segments */
 	memcpy_user ( bzimg.rm_kernel, 0, image->data,
 		      0, bzimg.rm_filesz );
 	memcpy_user ( bzimg.pm_kernel, 0, image->data,
 		      bzimg.rm_filesz, bzimg.pm_sz );
 
-	/* Update and write out header */
-	bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
-
-	/* Parse command line for bootloader parameters */
-	if ( ( rc = bzimage_parse_cmdline ( image, &bzimg, cmdline ) ) != 0)
-		return rc;
-
 	/* Store command line */
-	if ( ( rc = bzimage_set_cmdline ( image, &bzimg, cmdline ) ) != 0 )
-		return rc;
+	bzimage_set_cmdline ( image, &bzimg, cmdline );
+
+	/* Prepare for exiting.  Must do this before loading initrds,
+	 * since loading the initrds will corrupt the external heap.
+	 */
+	shutdown_boot();
 
 	/* Load any initrds */
-	if ( ( rc = bzimage_load_initrds ( image, &bzimg ) ) != 0 )
-		return rc;
+	bzimage_load_initrds ( image, &bzimg );
 
 	/* Update kernel header */
 	bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
 
-	/* Prepare for exiting */
-	shutdown_boot();
-
 	DBGC ( image, "bzImage %p jumping to RM kernel at %04x:0000 "
 	       "(stack %04x:%04zx)\n", image, ( bzimg.rm_kernel_seg + 0x20 ),
 	       bzimg.rm_kernel_seg, bzimg.rm_heap );
diff --git a/roms/ipxe/src/arch/i386/image/com32.c b/roms/ipxe/src/arch/i386/image/com32.c
index d6e48ebe1ac593b5d1c98b62236b..5cc9a4476296caed1f75957c3d2b 100644
--- a/roms/ipxe/src/arch/i386/image/com32.c
+++ b/roms/ipxe/src/arch/i386/image/com32.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 /**
diff --git a/roms/ipxe/src/arch/i386/image/comboot.c b/roms/ipxe/src/arch/i386/image/comboot.c
index 0b924cce2afb7b2cc36ff8088067..1ec02331d19dcf92475148844d9a 100644
--- a/roms/ipxe/src/arch/i386/image/comboot.c
+++ b/roms/ipxe/src/arch/i386/image/comboot.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 /**
@@ -228,7 +229,7 @@ static int comboot_identify ( struct image *image ) {
 
 	++ext;
 
-	if ( strcasecmp( ext, "com" ) && strcasecmp( ext, "cbt" ) ) {
+	if ( strcasecmp( ext, "cbt" ) ) {
 		DBGC ( image, "COMBOOT %p: unrecognized extension %s\n",
 		       image, ext );
 		return -ENOEXEC;
diff --git a/roms/ipxe/src/arch/i386/image/elfboot.c b/roms/ipxe/src/arch/i386/image/elfboot.c
index 89e70a3b8fe480a544cb36dce9e8..a867a95669f7109692200c8b94bb 100644
--- a/roms/ipxe/src/arch/i386/image/elfboot.c
+++ b/roms/ipxe/src/arch/i386/image/elfboot.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -42,10 +43,11 @@ FEATURE ( FEATURE_IMAGE, "ELF", DHCP_EB_FEATURE_ELF, 1 );
  */
 static int elfboot_exec ( struct image *image ) {
 	physaddr_t entry;
+	physaddr_t max;
 	int rc;
 
 	/* Load the image using core ELF support */
-	if ( ( rc = elf_load ( image, &entry ) ) != 0 ) {
+	if ( ( rc = elf_load ( image, &entry, &max ) ) != 0 ) {
 		DBGC ( image, "ELF %p could not load: %s\n",
 		       image, strerror ( rc ) );
 		return rc;
diff --git a/roms/ipxe/src/arch/i386/image/initrd.c b/roms/ipxe/src/arch/i386/image/initrd.c
new file mode 100644
index 0000000000000000000000000000000000000000..eaba3a6454968e687dace2476101943a0e5778a2
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/image/initrd.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <initrd.h>
+#include <ipxe/image.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/init.h>
+#include <ipxe/memblock.h>
+
+/** @file
+ *
+ * Initial ramdisk (initrd) reshuffling
+ *
+ */
+
+/** Maximum address available for initrd */
+userptr_t initrd_top;
+
+/** Minimum address available for initrd */
+userptr_t initrd_bottom;
+
+/**
+ * Squash initrds as high as possible in memory
+ *
+ * @v top		Highest possible address
+ * @ret used		Lowest address used by initrds
+ */
+static userptr_t initrd_squash_high ( userptr_t top ) {
+	userptr_t current = top;
+	struct image *initrd;
+	struct image *highest;
+	size_t len;
+
+	/* Squash up any initrds already within or below the region */
+	while ( 1 ) {
+
+		/* Find the highest image not yet in its final position */
+		highest = NULL;
+		for_each_image ( initrd ) {
+			if ( ( userptr_sub ( initrd->data, current ) < 0 ) &&
+			     ( ( highest == NULL ) ||
+			       ( userptr_sub ( initrd->data,
+					       highest->data ) > 0 ) ) ) {
+				highest = initrd;
+			}
+		}
+		if ( ! highest )
+			break;
+
+		/* Move this image to its final position */
+		len = ( ( highest->len + INITRD_ALIGN - 1 ) &
+			~( INITRD_ALIGN - 1 ) );
+		current = userptr_sub ( current, len );
+		DBGC ( &images, "INITRD squashing %s [%#08lx,%#08lx)->"
+		       "[%#08lx,%#08lx)\n", highest->name,
+		       user_to_phys ( highest->data, 0 ),
+		       user_to_phys ( highest->data, highest->len ),
+		       user_to_phys ( current, 0 ),
+		       user_to_phys ( current, highest->len ) );
+		memmove_user ( current, 0, highest->data, 0, highest->len );
+		highest->data = current;
+	}
+
+	/* Copy any remaining initrds (e.g. embedded images) to the region */
+	for_each_image ( initrd ) {
+		if ( userptr_sub ( initrd->data, top ) >= 0 ) {
+			len = ( ( initrd->len + INITRD_ALIGN - 1 ) &
+				~( INITRD_ALIGN - 1 ) );
+			current = userptr_sub ( current, len );
+			DBGC ( &images, "INITRD copying %s [%#08lx,%#08lx)->"
+			       "[%#08lx,%#08lx)\n", initrd->name,
+			       user_to_phys ( initrd->data, 0 ),
+			       user_to_phys ( initrd->data, initrd->len ),
+			       user_to_phys ( current, 0 ),
+			       user_to_phys ( current, initrd->len ) );
+			memcpy_user ( current, 0, initrd->data, 0,
+				      initrd->len );
+			initrd->data = current;
+		}
+	}
+
+	return current;
+}
+
+/**
+ * Swap position of two adjacent initrds
+ *
+ * @v low		Lower initrd
+ * @v high		Higher initrd
+ * @v free		Free space
+ * @v free_len		Length of free space
+ */
+static void initrd_swap ( struct image *low, struct image *high,
+			  userptr_t free, size_t free_len ) {
+	size_t len = 0;
+	size_t frag_len;
+	size_t new_len;
+
+	DBGC ( &images, "INITRD swapping %s [%#08lx,%#08lx)<->[%#08lx,%#08lx) "
+	       "%s\n", low->name, user_to_phys ( low->data, 0 ),
+	       user_to_phys ( low->data, low->len ),
+	       user_to_phys ( high->data, 0 ),
+	       user_to_phys ( high->data, high->len ), high->name );
+
+	/* Round down length of free space */
+	free_len &= ~( INITRD_ALIGN - 1 );
+	assert ( free_len > 0 );
+
+	/* Swap image data */
+	while ( len < high->len ) {
+
+		/* Calculate maximum fragment length */
+		frag_len = ( high->len - len );
+		if ( frag_len > free_len )
+			frag_len = free_len;
+		new_len = ( ( len + frag_len + INITRD_ALIGN - 1 ) &
+			    ~( INITRD_ALIGN - 1 ) );
+
+		/* Swap fragments */
+		memcpy_user ( free, 0, high->data, len, frag_len );
+		memmove_user ( low->data, new_len, low->data, len, low->len );
+		memcpy_user ( low->data, len, free, 0, frag_len );
+		len = new_len;
+	}
+
+	/* Adjust data pointers */
+	high->data = low->data;
+	low->data = userptr_add ( low->data, len );
+}
+
+/**
+ * Swap position of any two adjacent initrds not currently in the correct order
+ *
+ * @v free		Free space
+ * @v free_len		Length of free space
+ * @ret swapped		A pair of initrds was swapped
+ */
+static int initrd_swap_any ( userptr_t free, size_t free_len ) {
+	struct image *low;
+	struct image *high;
+	size_t padded_len;
+	userptr_t adjacent;
+
+	/* Find any pair of initrds that can be swapped */
+	for_each_image ( low ) {
+
+		/* Calculate location of adjacent image (if any) */
+		padded_len = ( ( low->len + INITRD_ALIGN - 1 ) &
+			       ~( INITRD_ALIGN - 1 ) );
+		adjacent = userptr_add ( low->data, padded_len );
+
+		/* Search for adjacent image */
+		for_each_image ( high ) {
+
+			/* If we have found the adjacent image, swap and exit */
+			if ( high->data == adjacent ) {
+				initrd_swap ( low, high, free, free_len );
+				return 1;
+			}
+
+			/* Stop search if all remaining potential
+			 * adjacent images are already in the correct
+			 * order.
+			 */
+			if ( high == low )
+				break;
+		}
+	}
+
+	/* Nothing swapped */
+	return 0;
+}
+
+/**
+ * Dump initrd locations (for debug)
+ *
+ */
+static void initrd_dump ( void ) {
+	struct image *initrd;
+
+	/* Do nothing unless debugging is enabled */
+	if ( ! DBG_LOG )
+		return;
+
+	/* Dump initrd locations */
+	for_each_image ( initrd ) {
+		DBGC ( &images, "INITRD %s at [%#08lx,%#08lx)\n",
+		       initrd->name, user_to_phys ( initrd->data, 0 ),
+		       user_to_phys ( initrd->data, initrd->len ) );
+		DBGC2_MD5A ( &images, user_to_phys ( initrd->data, 0 ),
+			     user_to_virt ( initrd->data, 0 ), initrd->len );
+	}
+}
+
+/**
+ * Reshuffle initrds into desired order at top of memory
+ *
+ * @v bottom		Lowest address available for initrds
+ *
+ * After this function returns, the initrds have been rearranged in
+ * memory and the external heap structures will have been corrupted.
+ * Reshuffling must therefore take place immediately prior to jumping
+ * to the loaded OS kernel; no further execution within iPXE is
+ * permitted.
+ */
+void initrd_reshuffle ( userptr_t bottom ) {
+	userptr_t top;
+	userptr_t used;
+	userptr_t free;
+	size_t free_len;
+
+	/* Calculate limits of available space for initrds */
+	top = initrd_top;
+	if ( userptr_sub ( initrd_bottom, bottom ) > 0 )
+		bottom = initrd_bottom;
+
+	/* Debug */
+	DBGC ( &images, "INITRD region [%#08lx,%#08lx)\n",
+	       user_to_phys ( bottom, 0 ), user_to_phys ( top, 0 ) );
+	initrd_dump();
+
+	/* Squash initrds as high as possible in memory */
+	used = initrd_squash_high ( top );
+
+	/* Calculate available free space */
+	free = bottom;
+	free_len = userptr_sub ( used, free );
+
+	/* Bubble-sort initrds into desired order */
+	while ( initrd_swap_any ( free, free_len ) ) {}
+
+	/* Debug */
+	initrd_dump();
+}
+
+/**
+ * Check that there is enough space to reshuffle initrds
+ *
+ * @v len		Total length of initrds (including padding)
+ * @v bottom		Lowest address available for initrds
+ * @ret rc		Return status code
+ */
+int initrd_reshuffle_check ( size_t len, userptr_t bottom ) {
+	userptr_t top;
+	size_t available;
+
+	/* Calculate limits of available space for initrds */
+	top = initrd_top;
+	if ( userptr_sub ( initrd_bottom, bottom ) > 0 )
+		bottom = initrd_bottom;
+	available = userptr_sub ( top, bottom );
+
+	/* Allow for a sensible minimum amount of free space */
+	len += INITRD_MIN_FREE_LEN;
+
+	/* Check for available space */
+	return ( ( len < available ) ? 0 : -ENOBUFS );
+}
+
+/**
+ * initrd startup function
+ *
+ */
+static void initrd_startup ( void ) {
+	size_t len;
+
+	/* Record largest memory block available.  Do this after any
+	 * allocations made during driver startup (e.g. large host
+	 * memory blocks for Infiniband devices, which may still be in
+	 * use at the time of rearranging if a SAN device is hooked)
+	 * but before any allocations for downloaded images (which we
+	 * can safely reuse when rearranging).
+	 */
+	len = largest_memblock ( &initrd_bottom );
+	initrd_top = userptr_add ( initrd_bottom, len );
+}
+
+/** initrd startup function */
+struct startup_fn startup_initrd __startup_fn ( STARTUP_LATE ) = {
+	.startup = initrd_startup,
+};
diff --git a/roms/ipxe/src/arch/i386/image/multiboot.c b/roms/ipxe/src/arch/i386/image/multiboot.c
index 15e8fd52b1ae02eeb093cffc0a11..3d6d2bf341bace0e85b58c8f939d 100644
--- a/roms/ipxe/src/arch/i386/image/multiboot.c
+++ b/roms/ipxe/src/arch/i386/image/multiboot.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -37,6 +38,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/elf.h>
 #include <ipxe/init.h>
 #include <ipxe/features.h>
+#include <ipxe/uri.h>
+#include <ipxe/version.h>
 
 FEATURE ( FEATURE_IMAGE, "MBOOT", DHCP_EB_FEATURE_MULTIBOOT, 1 );
 
@@ -139,53 +142,60 @@ static void multiboot_build_memmap ( struct image *image,
 /**
  * Add command line in base memory
  *
- * @v imgname		Image name
- * @v cmdline		Command line
+ * @v image		Image
  * @ret physaddr	Physical address of command line
  */
-physaddr_t multiboot_add_cmdline ( const char *imgname, const char *cmdline ) {
-	char *mb_cmdline;
-
-	if ( ! cmdline )
-		cmdline = "";
-
-	/* Copy command line to base memory buffer */
-	mb_cmdline = ( mb_cmdlines + mb_cmdline_offset );
-	mb_cmdline_offset +=
-		( snprintf ( mb_cmdline,
-			     ( sizeof ( mb_cmdlines ) - mb_cmdline_offset ),
-			     "%s %s", imgname, cmdline ) + 1 );
-
-	/* Truncate to terminating NUL in buffer if necessary */
-	if ( mb_cmdline_offset > sizeof ( mb_cmdlines ) )
-		mb_cmdline_offset = ( sizeof ( mb_cmdlines ) - 1 );
+static physaddr_t multiboot_add_cmdline ( struct image *image ) {
+	char *mb_cmdline = ( mb_cmdlines + mb_cmdline_offset );
+	size_t remaining = ( sizeof ( mb_cmdlines ) - mb_cmdline_offset );
+	char *buf = mb_cmdline;
+	size_t len;
+
+	/* Copy image URI to base memory buffer as start of command line */
+	len = ( unparse_uri ( buf, remaining, image->uri,
+			      URI_ALL ) + 1 /* NUL */ );
+	if ( len > remaining )
+		len = remaining;
+	mb_cmdline_offset += len;
+	buf += len;
+	remaining -= len;
+
+	/* Copy command line to base memory buffer, if present */
+	if ( image->cmdline ) {
+		mb_cmdline_offset--; /* Strip NUL */
+		buf--;
+		remaining++;
+		len = ( snprintf ( buf, remaining, " %s",
+				   image->cmdline ) + 1 /* NUL */ );
+		if ( len > remaining )
+			len = remaining;
+		mb_cmdline_offset += len;
+	}
 
 	return virt_to_phys ( mb_cmdline );
 }
 
 /**
- * Build multiboot module list
+ * Add multiboot modules
  *
  * @v image		Multiboot image
- * @v modules		Module list to fill, or NULL
- * @ret count		Number of modules
+ * @v start		Start address for modules
+ * @v mbinfo		Multiboot information structure
+ * @v modules		Multiboot module list
+ * @ret rc		Return status code
  */
-static unsigned int
-multiboot_build_module_list ( struct image *image,
-			      struct multiboot_module *modules,
-			      unsigned int limit ) {
+static int multiboot_add_modules ( struct image *image, physaddr_t start,
+				   struct multiboot_info *mbinfo,
+				   struct multiboot_module *modules,
+				   unsigned int limit ) {
 	struct image *module_image;
 	struct multiboot_module *module;
-	unsigned int count = 0;
-	unsigned int insert;
-	physaddr_t start;
-	physaddr_t end;
-	unsigned int i;
+	int rc;
 
 	/* Add each image as a multiboot module */
 	for_each_image ( module_image ) {
 
-		if ( count >= limit ) {
+		if ( mbinfo->mods_count >= limit ) {
 			DBGC ( image, "MULTIBOOT %p limit of %d modules "
 			       "reached\n", image, limit );
 			break;
@@ -195,38 +205,36 @@ multiboot_build_module_list ( struct image *image,
 		if ( module_image == image )
 			continue;
 
-		/* At least some OSes expect the multiboot modules to
-		 * be in ascending order, so we have to support it.
-		 */
-		start = user_to_phys ( module_image->data, 0 );
-		end = user_to_phys ( module_image->data, module_image->len );
-		for ( insert = 0 ; insert < count ; insert++ ) {
-			if ( start < modules[insert].mod_start )
-				break;
+		/* Page-align the module */
+		start = ( ( start + 0xfff ) & ~0xfff );
+
+		/* Prepare segment */
+		if ( ( rc = prep_segment ( phys_to_user ( start ),
+					   module_image->len,
+					   module_image->len ) ) != 0 ) {
+			DBGC ( image, "MULTIBOOT %p could not prepare module "
+			       "%s: %s\n", image, module_image->name,
+			       strerror ( rc ) );
+			return rc;
 		}
-		module = &modules[insert];
-		memmove ( ( module + 1 ), module,
-			  ( ( count - insert ) * sizeof ( *module ) ) );
-		module->mod_start = start;
-		module->mod_end = end;
-		module->string = multiboot_add_cmdline ( module_image->name,
-						       module_image->cmdline );
-		module->reserved = 0;
-		
-		/* We promise to page-align modules */
-		assert ( ( module->mod_start & 0xfff ) == 0 );
 
-		count++;
-	}
+		/* Copy module */
+		memcpy_user ( phys_to_user ( start ), 0,
+			      module_image->data, 0, module_image->len );
 
-	/* Dump module configuration */
-	for ( i = 0 ; i < count ; i++ ) {
-		DBGC ( image, "MULTIBOOT %p module %d is [%x,%x)\n",
-		       image, i, modules[i].mod_start,
-		       modules[i].mod_end );
+		/* Add module to list */
+		module = &modules[mbinfo->mods_count++];
+		module->mod_start = start;
+		module->mod_end = ( start + module_image->len );
+		module->string = multiboot_add_cmdline ( module_image );
+		module->reserved = 0;
+		DBGC ( image, "MULTIBOOT %p module %s is [%x,%x)\n",
+		       image, module_image->name, module->mod_start,
+		       module->mod_end );
+		start += module_image->len;
 	}
 
-	return count;
+	return 0;
 }
 
 /**
@@ -240,7 +248,7 @@ static struct multiboot_info __bss16 ( mbinfo );
 #define mbinfo __use_data16 ( mbinfo )
 
 /** The multiboot bootloader name */
-static char __data16_array ( mb_bootloader_name, [] ) = "iPXE " VERSION;
+static char __bss16_array ( mb_bootloader_name, [32] );
 #define mb_bootloader_name __use_data16 ( mb_bootloader_name )
 
 /** The multiboot memory map */
@@ -305,11 +313,12 @@ static int multiboot_find_header ( struct image *image,
  * @v image		Multiboot file
  * @v hdr		Multiboot header descriptor
  * @ret entry		Entry point
+ * @ret max		Maximum used address
  * @ret rc		Return status code
  */
 static int multiboot_load_raw ( struct image *image,
 				struct multiboot_header_info *hdr,
-				physaddr_t *entry ) {
+				physaddr_t *entry, physaddr_t *max ) {
 	size_t offset;
 	size_t filesz;
 	size_t memsz;
@@ -340,8 +349,9 @@ static int multiboot_load_raw ( struct image *image,
 	/* Copy image to segment */
 	memcpy_user ( buffer, 0, image->data, offset, filesz );
 
-	/* Record execution entry point */
+	/* Record execution entry point and maximum used address */
 	*entry = hdr->mb.entry_addr;
+	*max = ( hdr->mb.load_addr + memsz );
 
 	return 0;
 }
@@ -351,13 +361,15 @@ static int multiboot_load_raw ( struct image *image,
  *
  * @v image		Multiboot file
  * @ret entry		Entry point
+ * @ret max		Maximum used address
  * @ret rc		Return status code
  */
-static int multiboot_load_elf ( struct image *image, physaddr_t *entry ) {
+static int multiboot_load_elf ( struct image *image, physaddr_t *entry,
+				physaddr_t *max ) {
 	int rc;
 
 	/* Load ELF image*/
-	if ( ( rc = elf_load ( image, entry ) ) != 0 ) {
+	if ( ( rc = elf_load ( image, entry, max ) ) != 0 ) {
 		DBGC ( image, "MULTIBOOT %p ELF image failed to load: %s\n",
 		       image, strerror ( rc ) );
 		return rc;
@@ -375,6 +387,7 @@ static int multiboot_load_elf ( struct image *image, physaddr_t *entry ) {
 static int multiboot_exec ( struct image *image ) {
 	struct multiboot_header_info hdr;
 	physaddr_t entry;
+	physaddr_t max;
 	int rc;
 
 	/* Locate multiboot header, if present */
@@ -396,8 +409,8 @@ static int multiboot_exec ( struct image *image ) {
 	 * the ELF header if present, and Solaris relies on this
 	 * behaviour.
 	 */
-	if ( ( ( rc = multiboot_load_elf ( image, &entry ) ) != 0 ) &&
-	     ( ( rc = multiboot_load_raw ( image, &hdr, &entry ) ) != 0 ) )
+	if ( ( ( rc = multiboot_load_elf ( image, &entry, &max ) ) != 0 ) &&
+	     ( ( rc = multiboot_load_raw ( image, &hdr, &entry, &max ) ) != 0 ))
 		return rc;
 
 	/* Populate multiboot information structure */
@@ -405,12 +418,16 @@ static int multiboot_exec ( struct image *image ) {
 	mbinfo.flags = ( MBI_FLAG_LOADER | MBI_FLAG_MEM | MBI_FLAG_MMAP |
 			 MBI_FLAG_CMDLINE | MBI_FLAG_MODS );
 	mb_cmdline_offset = 0;
-	mbinfo.cmdline = multiboot_add_cmdline ( image->name, image->cmdline );
-	mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules,
-				( sizeof(mbmodules) / sizeof(mbmodules[0]) ) );
+	mbinfo.cmdline = multiboot_add_cmdline ( image );
 	mbinfo.mods_addr = virt_to_phys ( mbmodules );
 	mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
+	snprintf ( mb_bootloader_name, sizeof ( mb_bootloader_name ),
+		   "iPXE %s", product_version );
 	mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name );
+	if ( ( rc = multiboot_add_modules ( image, max, &mbinfo, mbmodules,
+					    ( sizeof ( mbmodules ) /
+					      sizeof ( mbmodules[0] ) ) ) ) !=0)
+		return rc;
 
 	/* Multiboot images may not return and have no callback
 	 * interface, so shut everything down prior to booting the OS.
diff --git a/roms/ipxe/src/arch/i386/image/nbi.c b/roms/ipxe/src/arch/i386/image/nbi.c
index c516bb2ecc64b2d6aa230bedb3f8..d3e523e9252c08ec01b4d5edcef6 100644
--- a/roms/ipxe/src/arch/i386/image/nbi.c
+++ b/roms/ipxe/src/arch/i386/image/nbi.c
@@ -10,6 +10,7 @@
 #include <ipxe/fakedhcp.h>
 #include <ipxe/image.h>
 #include <ipxe/features.h>
+#include <ipxe/version.h>
 
 /** @file
  *
@@ -94,12 +95,6 @@ struct ebinfo {
 	uint16_t flags;         /* Bit flags */
 };
 
-/** Info passed to NBI image */
-static struct ebinfo loaderinfo = {
-	VERSION_MAJOR, VERSION_MINOR,
-	0
-};
-
 /**
  * Prepare a segment for an NBI image
  *
@@ -281,6 +276,10 @@ static int nbi_boot16 ( struct image *image, struct imgheader *imgheader ) {
  * @ret rc		Return status code, if image returns
  */
 static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) {
+	struct ebinfo loaderinfo = {
+		product_major_version, product_minor_version,
+		0
+	};
 	int discard_D, discard_S, discard_b;
 	int rc;
 
diff --git a/roms/ipxe/src/arch/i386/image/pxe_image.c b/roms/ipxe/src/arch/i386/image/pxe_image.c
index bdccc93d6cf2be5013621cd59af3..4a7d874be2deaca9bffaa975d3a8 100644
--- a/roms/ipxe/src/arch/i386/image/pxe_image.c
+++ b/roms/ipxe/src/arch/i386/image/pxe_image.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -35,6 +36,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 FEATURE ( FEATURE_IMAGE, "PXE", DHCP_EB_FEATURE_PXE, 1 );
 
+/** PXE command line */
+const char *pxe_cmdline;
+
 /**
  * Execute PXE image
  *
@@ -62,16 +66,29 @@ static int pxe_exec ( struct image *image ) {
 		       image );
 		return -ENODEV;
 	}
+	netdev_get ( netdev );
 
 	/* Activate PXE */
 	pxe_activate ( netdev );
 
+	/* Set PXE command line */
+	pxe_cmdline = image->cmdline;
+
 	/* Start PXE NBP */
 	rc = pxe_start_nbp();
 
+	/* Clear PXE command line */
+	pxe_cmdline = NULL;
+
 	/* Deactivate PXE */
 	pxe_deactivate();
 
+	/* Try to reopen network device.  Ignore errors, since the NBP
+	 * may have called PXENV_STOP_UNDI.
+	 */
+	netdev_open ( netdev );
+	netdev_put ( netdev );
+
 	return rc;
 }
 
diff --git a/roms/ipxe/src/arch/i386/image/sdi.c b/roms/ipxe/src/arch/i386/image/sdi.c
new file mode 100644
index 0000000000000000000000000000000000000000..df1c3a868961884fa2090c27746c4646f7b658b8
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/image/sdi.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <realmode.h>
+#include <sdi.h>
+#include <ipxe/image.h>
+#include <ipxe/features.h>
+
+/** @file
+ *
+ * System Deployment Image (SDI)
+ *
+ * Based on the MSDN article "RAM boot using SDI in Windows XP
+ * Embedded with Service Pack 1", available at the time of writing
+ * from:
+ *
+ *   http://msdn.microsoft.com/en-us/library/ms838543.aspx
+ */
+
+FEATURE ( FEATURE_IMAGE, "SDI", DHCP_EB_FEATURE_SDI, 1 );
+
+/**
+ * Parse SDI image header
+ *
+ * @v image		SDI file
+ * @v sdi		SDI header to fill in
+ * @ret rc		Return status code
+ */
+static int sdi_parse_header ( struct image *image, struct sdi_header *sdi ) {
+
+	/* Sanity check */
+	if ( image->len < sizeof ( *sdi ) ) {
+		DBGC ( image, "SDI %p too short for SDI header\n", image );
+		return -ENOEXEC;
+	}
+
+	/* Read in header */
+	copy_from_user ( sdi, image->data, 0, sizeof ( *sdi ) );
+
+	/* Check signature */
+	if ( sdi->magic != SDI_MAGIC ) {
+		DBGC ( image, "SDI %p is not an SDI image\n", image );
+		return -ENOEXEC;
+	}
+
+	return 0;
+}
+
+/**
+ * Execute SDI image
+ *
+ * @v image		SDI file
+ * @ret rc		Return status code
+ */
+static int sdi_exec ( struct image *image ) {
+	struct sdi_header sdi;
+	uint32_t sdiptr;
+	int rc;
+
+	/* Parse image header */
+	if ( ( rc = sdi_parse_header ( image, &sdi ) ) != 0 )
+		return rc;
+
+	/* Check that image is bootable */
+	if ( sdi.boot_size == 0 ) {
+		DBGC ( image, "SDI %p is not bootable\n", image );
+		return -ENOTTY;
+	}
+	DBGC ( image, "SDI %p image at %08lx+%08zx\n",
+	       image, user_to_phys ( image->data, 0 ), image->len );
+	DBGC ( image, "SDI %p boot code at %08lx+%llx\n", image,
+	       user_to_phys ( image->data, sdi.boot_offset ), sdi.boot_size );
+
+	/* Copy boot code */
+	memcpy_user ( real_to_user ( SDI_BOOT_SEG, SDI_BOOT_OFF ), 0,
+		      image->data, sdi.boot_offset, sdi.boot_size );
+
+	/* Jump to boot code */
+	sdiptr = ( user_to_phys ( image->data, 0 ) | SDI_WTF );
+	__asm__ __volatile__ ( REAL_CODE ( "ljmp %0, %1\n\t" )
+			       : : "i" ( SDI_BOOT_SEG ),
+				   "i" ( SDI_BOOT_OFF ),
+				   "d" ( sdiptr ) );
+
+	/* There is no way for the image to return, since we provide
+	 * no return address.
+	 */
+	assert ( 0 );
+
+	return -ECANCELED; /* -EIMPOSSIBLE */
+}
+
+/**
+ * Probe SDI image
+ *
+ * @v image		SDI file
+ * @ret rc		Return status code
+ */
+static int sdi_probe ( struct image *image ) {
+	struct sdi_header sdi;
+	int rc;
+
+	/* Parse image */
+	if ( ( rc = sdi_parse_header ( image, &sdi ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/** SDI image type */
+struct image_type sdi_image_type __image_type ( PROBE_NORMAL ) = {
+	.name = "SDI",
+	.probe = sdi_probe,
+	.exec = sdi_exec,
+};
diff --git a/roms/ipxe/src/arch/i386/include/bios.h b/roms/ipxe/src/arch/i386/include/bios.h
index 70bb73daccaa26dc5799cb1aa8ea..fadb9f1b74b084ed651893f8a059 100644
--- a/roms/ipxe/src/arch/i386/include/bios.h
+++ b/roms/ipxe/src/arch/i386/include/bios.h
@@ -4,6 +4,7 @@
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #define BDA_SEG 0x0040
+#define BDA_EQUIPMENT_WORD 0x0010
 #define BDA_FBMS 0x0013
 #define BDA_NUM_DRIVES 0x0075
 
diff --git a/roms/ipxe/src/arch/i386/include/bits/byteswap.h b/roms/ipxe/src/arch/i386/include/bits/byteswap.h
index ddbd40edbd414d2019b95be72d67..0d9cb967c22dac3c6140196f6f59 100644
--- a/roms/ipxe/src/arch/i386/include/bits/byteswap.h
+++ b/roms/ipxe/src/arch/i386/include/bits/byteswap.h
@@ -1,43 +1,70 @@
-#ifndef ETHERBOOT_BITS_BYTESWAP_H
-#define ETHERBOOT_BITS_BYTESWAP_H
+#ifndef _BITS_BYTESWAP_H
+#define _BITS_BYTESWAP_H
+
+/** @file
+ *
+ * Byte-order swapping functions
+ *
+ */
+
+#include <stdint.h>
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
-static inline __attribute__ ((always_inline, const)) uint16_t
-__bswap_variable_16(uint16_t x)
-{
-	__asm__("xchgb %b0,%h0\n\t"
-		: "=q" (x)
-		: "0" (x));
+static inline __attribute__ (( always_inline, const )) uint16_t
+__bswap_variable_16 ( uint16_t x ) {
+	__asm__ ( "xchgb %b0,%h0" : "=q" ( x ) : "0" ( x ) );
 	return x;
 }
 
-static inline __attribute__ ((always_inline, const)) uint32_t
-__bswap_variable_32(uint32_t x)
-{
-	__asm__("xchgb %b0,%h0\n\t"
-		"rorl $16,%0\n\t"
-		"xchgb %b0,%h0"
-		: "=q" (x)
-		: "0" (x));
+static inline __attribute__ (( always_inline )) void
+__bswap_16s ( uint16_t *x ) {
+	__asm__ ( "rorw $8, %0" : "+m" ( *x ) );
+}
+
+static inline __attribute__ (( always_inline, const )) uint32_t
+__bswap_variable_32 ( uint32_t x ) {
+	__asm__ ( "bswapl %0" : "=r" ( x ) : "0" ( x ) );
 	return x;
 }
 
-static inline __attribute__ ((always_inline, const)) uint64_t
-__bswap_variable_64(uint64_t x)
-{
-	union {
-		uint64_t qword;
-		uint32_t dword[2]; 
-	} u;
-
-	u.qword = x;
-	u.dword[0] = __bswap_variable_32(u.dword[0]);
-	u.dword[1] = __bswap_variable_32(u.dword[1]);
-	__asm__("xchgl %0,%1"
-		: "=r" ( u.dword[0] ), "=r" ( u.dword[1] )
-		: "0" ( u.dword[0] ), "1" ( u.dword[1] ) );
-	return u.qword;
+static inline __attribute__ (( always_inline )) void
+__bswap_32s ( uint32_t *x ) {
+	__asm__ ( "bswapl %0" : "=r" ( *x ) : "0" ( *x ) );
+}
+
+static inline __attribute__ (( always_inline, const )) uint64_t
+__bswap_variable_64 ( uint64_t x ) {
+	uint32_t in_high = ( x >> 32 );
+	uint32_t in_low = ( x & 0xffffffffUL );
+	uint32_t out_high;
+	uint32_t out_low;
+
+	__asm__ ( "bswapl %0\n\t"
+		  "bswapl %1\n\t"
+		  "xchgl %0,%1\n\t"
+		  : "=r" ( out_high ), "=r" ( out_low )
+		  : "0" ( in_high ), "1" ( in_low ) );
+
+	return ( ( ( ( uint64_t ) out_high ) << 32 ) |
+		 ( ( uint64_t ) out_low ) );
+}
+
+static inline __attribute__ (( always_inline )) void
+__bswap_64s ( uint64_t *x ) {
+	struct {
+		uint32_t __attribute__ (( may_alias )) low;
+		uint32_t __attribute__ (( may_alias )) high;
+	} __attribute__ (( may_alias )) *dwords = ( ( void * ) x );
+	uint32_t discard;
+
+	__asm__ ( "movl %0,%2\n\t"
+		  "bswapl %2\n\t"
+		  "xchgl %2,%1\n\t"
+		  "bswapl %2\n\t"
+		  "movl %2,%0\n\t"
+		  : "+m" ( dwords->low ), "+m" ( dwords->high ),
+		    "=r" ( discard ) );
 }
 
-#endif /* ETHERBOOT_BITS_BYTESWAP_H */
+#endif /* _BITS_BYTESWAP_H */
diff --git a/roms/ipxe/src/arch/i386/include/bits/cpu.h b/roms/ipxe/src/arch/i386/include/bits/cpu.h
deleted file mode 100644
index 83339dddd0710e7cffa503c2eea5963fb56fd27e..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/arch/i386/include/bits/cpu.h
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef I386_BITS_CPU_H
-#define I386_BITS_CPU_H
-
-/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
-#define X86_FEATURE_FPU		0 /* Onboard FPU */
-#define X86_FEATURE_VME		1 /* Virtual Mode Extensions */
-#define X86_FEATURE_DE		2 /* Debugging Extensions */
-#define X86_FEATURE_PSE 	3 /* Page Size Extensions */
-#define X86_FEATURE_TSC		4 /* Time Stamp Counter */
-#define X86_FEATURE_MSR		5 /* Model-Specific Registers, RDMSR, WRMSR */
-#define X86_FEATURE_PAE		6 /* Physical Address Extensions */
-#define X86_FEATURE_MCE		7 /* Machine Check Architecture */
-#define X86_FEATURE_CX8		8 /* CMPXCHG8 instruction */
-#define X86_FEATURE_APIC	9 /* Onboard APIC */
-#define X86_FEATURE_SEP		11 /* SYSENTER/SYSEXIT */
-#define X86_FEATURE_MTRR	12 /* Memory Type Range Registers */
-#define X86_FEATURE_PGE		13 /* Page Global Enable */
-#define X86_FEATURE_MCA		14 /* Machine Check Architecture */
-#define X86_FEATURE_CMOV	15 /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
-#define X86_FEATURE_PAT		16 /* Page Attribute Table */
-#define X86_FEATURE_PSE36	17 /* 36-bit PSEs */
-#define X86_FEATURE_PN		18 /* Processor serial number */
-#define X86_FEATURE_CLFLSH	19 /* Supports the CLFLUSH instruction */
-#define X86_FEATURE_DTES	21 /* Debug Trace Store */
-#define X86_FEATURE_ACPI	22 /* ACPI via MSR */
-#define X86_FEATURE_MMX		23 /* Multimedia Extensions */
-#define X86_FEATURE_FXSR	24 /* FXSAVE and FXRSTOR instructions (fast save and restore */
-				          /* of FPU context), and CR4.OSFXSR available */
-#define X86_FEATURE_XMM		25 /* Streaming SIMD Extensions */
-#define X86_FEATURE_XMM2	26 /* Streaming SIMD Extensions-2 */
-#define X86_FEATURE_SELFSNOOP	27 /* CPU self snoop */
-#define X86_FEATURE_HT		28 /* Hyper-Threading */
-#define X86_FEATURE_ACC		29 /* Automatic clock control */
-#define X86_FEATURE_IA64	30 /* IA-64 processor */
-
-/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
-/* Don't duplicate feature flags which are redundant with Intel! */
-#define X86_FEATURE_SYSCALL	11 /* SYSCALL/SYSRET */
-#define X86_FEATURE_MMXEXT	22 /* AMD MMX extensions */
-#define X86_FEATURE_LM		29 /* Long Mode (x86-64) */
-#define X86_FEATURE_3DNOWEXT	30 /* AMD 3DNow! extensions */
-#define X86_FEATURE_3DNOW	31 /* 3DNow! */
-
-/** x86 CPU information */
-struct cpuinfo_x86 {
-	/** CPU features */
-	unsigned int features;
-	/** 64-bit CPU features */
-	unsigned int amd_features;
-};
-
-/*
- * EFLAGS bits
- */
-#define X86_EFLAGS_CF	0x00000001 /* Carry Flag */
-#define X86_EFLAGS_PF	0x00000004 /* Parity Flag */
-#define X86_EFLAGS_AF	0x00000010 /* Auxillary carry Flag */
-#define X86_EFLAGS_ZF	0x00000040 /* Zero Flag */
-#define X86_EFLAGS_SF	0x00000080 /* Sign Flag */
-#define X86_EFLAGS_TF	0x00000100 /* Trap Flag */
-#define X86_EFLAGS_IF	0x00000200 /* Interrupt Flag */
-#define X86_EFLAGS_DF	0x00000400 /* Direction Flag */
-#define X86_EFLAGS_OF	0x00000800 /* Overflow Flag */
-#define X86_EFLAGS_IOPL	0x00003000 /* IOPL mask */
-#define X86_EFLAGS_NT	0x00004000 /* Nested Task */
-#define X86_EFLAGS_RF	0x00010000 /* Resume Flag */
-#define X86_EFLAGS_VM	0x00020000 /* Virtual Mode */
-#define X86_EFLAGS_AC	0x00040000 /* Alignment Check */
-#define X86_EFLAGS_VIF	0x00080000 /* Virtual Interrupt Flag */
-#define X86_EFLAGS_VIP	0x00100000 /* Virtual Interrupt Pending */
-#define X86_EFLAGS_ID	0x00200000 /* CPUID detection flag */
-
-/*
- * Generic CPUID function
- */
-static inline __attribute__ (( always_inline )) void
-cpuid ( int op, unsigned int *eax, unsigned int *ebx,
-	unsigned int *ecx, unsigned int *edx ) {
-	__asm__ ( "cpuid" :
-		  "=a" ( *eax ), "=b" ( *ebx ), "=c" ( *ecx ), "=d" ( *edx )
-		: "0" ( op ) );
-}
-
-extern void get_cpuinfo ( struct cpuinfo_x86 *cpu );
-
-#endif /* I386_BITS_CPU_H */
diff --git a/roms/ipxe/src/arch/i386/include/bits/entropy.h b/roms/ipxe/src/arch/i386/include/bits/entropy.h
new file mode 100644
index 0000000000000000000000000000000000000000..6dcceec6d6be7c76983516217b0035aa0c8b26e7
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/include/bits/entropy.h
@@ -0,0 +1,14 @@
+#ifndef _BITS_ENTROPY_H
+#define _BITS_ENTROPY_H
+
+/** @file
+ *
+ * i386-specific entropy API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/rtc_entropy.h>
+
+#endif /* _BITS_ENTROPY_H */
diff --git a/roms/ipxe/src/arch/i386/include/bits/errfile.h b/roms/ipxe/src/arch/i386/include/bits/errfile.h
deleted file mode 100644
index 32b8a085bb1a2aaeae9349610591dac447af6b0c..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/arch/i386/include/bits/errfile.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef _BITS_ERRFILE_H
-#define _BITS_ERRFILE_H
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/**
- * @addtogroup errfile Error file identifiers
- * @{
- */
-
-#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_bios_smbios	( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 )
-#define ERRFILE_biosint		( ERRFILE_ARCH | ERRFILE_CORE | 0x00040000 )
-#define ERRFILE_int13		( ERRFILE_ARCH | ERRFILE_CORE | 0x00050000 )
-#define ERRFILE_pxeparent	( ERRFILE_ARCH | ERRFILE_CORE | 0x00060000 )
-
-#define ERRFILE_bootsector     ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
-#define ERRFILE_bzimage	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
-#define ERRFILE_eltorito       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00020000 )
-#define ERRFILE_multiboot      ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00030000 )
-#define ERRFILE_nbi	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00040000 )
-#define ERRFILE_pxe_image      ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00050000 )
-#define ERRFILE_elfboot	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00060000 )
-#define ERRFILE_comboot        ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00070000 )
-#define ERRFILE_com32          ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00080000 )
-#define ERRFILE_comboot_resolv ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00090000 )
-#define ERRFILE_comboot_call   ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000a0000 )
-
-#define ERRFILE_undi		 ( ERRFILE_ARCH | ERRFILE_NET | 0x00000000 )
-#define ERRFILE_undiload	 ( ERRFILE_ARCH | ERRFILE_NET | 0x00010000 )
-#define ERRFILE_undinet		 ( ERRFILE_ARCH | ERRFILE_NET | 0x00020000 )
-#define ERRFILE_undionly	 ( ERRFILE_ARCH | ERRFILE_NET | 0x00030000 )
-#define ERRFILE_undirom		 ( ERRFILE_ARCH | ERRFILE_NET | 0x00040000 )
-
-#define ERRFILE_timer_rdtsc    ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00000000 )
-#define ERRFILE_timer_bios     ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00010000 )
-
-/** @} */
-
-#endif /* _BITS_ERRFILE_H */
diff --git a/roms/ipxe/src/arch/i386/include/bits/io.h b/roms/ipxe/src/arch/i386/include/bits/io.h
deleted file mode 100644
index f3ecf89bbae55c219f0a39028d259f9913fbe663..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/arch/i386/include/bits/io.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _BITS_IO_H
-#define _BITS_IO_H
-
-/** @file
- *
- * i386-specific I/O API implementations
- *
- */
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include <ipxe/x86_io.h>
-
-#endif /* _BITS_IO_H */
diff --git a/roms/ipxe/src/arch/i386/include/bits/time.h b/roms/ipxe/src/arch/i386/include/bits/time.h
new file mode 100644
index 0000000000000000000000000000000000000000..24dd020e92264f17a5442a27add74eefcf06ce4b
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/include/bits/time.h
@@ -0,0 +1,14 @@
+#ifndef _BITS_TIME_H
+#define _BITS_TIME_H
+
+/** @file
+ *
+ * i386-specific time API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/rtc_time.h>
+
+#endif /* _BITS_TIME_H */
diff --git a/roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h b/roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h
index 902caff9576c7f8ee6d3954c1367..18417721917c66123f63c09dc9e9 100644
--- a/roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h
+++ b/roms/ipxe/src/arch/i386/include/efi/ipxe/dhcp_arch.h
@@ -33,7 +33,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 		      'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '6', ':', \
 		      'U', 'N', 'D', 'I', ':', '0', '0', '3', '0', '1', '0' )
 
-#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_WORD ( 6 )
+#define DHCP_ARCH_CLIENT_ARCHITECTURE \
+	DHCP_WORD ( DHCP_CLIENT_ARCHITECTURE_IA32 )
 
 #define DHCP_ARCH_CLIENT_NDI DHCP_OPTION ( 1 /* UNDI */ , 3, 10 /* v3.10 */ )
 
diff --git a/roms/ipxe/src/arch/i386/include/initrd.h b/roms/ipxe/src/arch/i386/include/initrd.h
new file mode 100644
index 0000000000000000000000000000000000000000..c25d0924b662735fe53e78208799274f54d3ee95
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/include/initrd.h
@@ -0,0 +1,29 @@
+#ifndef _INITRD_H
+#define _INITRD_H
+
+/** @file
+ *
+ * Initial ramdisk (initrd) reshuffling
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/uaccess.h>
+
+/** Minimum alignment for initrds
+ *
+ * Chosen to maximise memcpy() speeds
+ */
+#define INITRD_ALIGN 4
+
+/** Minimum free space required to reshuffle initrds
+ *
+ * Chosen to avoid absurdly long reshuffling times
+ */
+#define INITRD_MIN_FREE_LEN ( 512 * 1024 )
+
+extern void initrd_reshuffle ( userptr_t bottom );
+extern int initrd_reshuffle_check ( size_t len, userptr_t bottom );
+
+#endif /* _INITRD_H */
diff --git a/roms/ipxe/src/arch/i386/include/int13.h b/roms/ipxe/src/arch/i386/include/int13.h
index a14ebb2e93e79d5114ef210054d3..e337ca1d17d2e5b290caaa468991 100644
--- a/roms/ipxe/src/arch/i386/include/int13.h
+++ b/roms/ipxe/src/arch/i386/include/int13.h
@@ -45,6 +45,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define INT13_GET_EXTENDED_PARAMETERS	0x48
 /** Get CD-ROM status / terminate emulation */
 #define INT13_CDROM_STATUS_TERMINATE	0x4b
+/** Read CD-ROM boot catalog */
+#define INT13_CDROM_READ_BOOT_CATALOG	0x4d
 
 /** @} */
 
@@ -69,6 +71,19 @@ FILE_LICENCE ( GPL2_OR_LATER );
 /** Block size for non-extended INT 13 calls */
 #define INT13_BLKSIZE 512
 
+/** @defgroup int13fddtype INT 13 floppy disk drive types
+ * @{
+ */
+
+/** 360K */
+#define INT13_FDD_TYPE_360K		0x01
+/** 1.2M */
+#define INT13_FDD_TYPE_1M2		0x02
+/** 720K */
+#define INT13_FDD_TYPE_720K		0x03
+/** 1.44M */
+#define INT13_FDD_TYPE_1M44		0x04
+
 /** An INT 13 disk address packet */
 struct int13_disk_address {
 	/** Size of the packet, in bytes */
@@ -217,6 +232,18 @@ struct int13_cdrom_specification {
 	uint8_t head;
 } __attribute__ (( packed ));
 
+/** Bootable CD-ROM boot catalog command packet */
+struct int13_cdrom_boot_catalog_command {
+	/** Size of packet in bytes */
+	uint8_t size;
+	/** Number of sectors of boot catalog to read */
+	uint8_t count;
+	/** Buffer for boot catalog */
+	uint32_t buffer;
+	/** First sector in boot catalog to transfer */
+	uint16_t start;
+} __attribute__ (( packed ));
+
 /** A C/H/S address within a partition table entry */
 struct partition_chs {
 	/** Head number */
@@ -261,7 +288,46 @@ struct master_boot_record {
 	uint16_t magic;
 } __attribute__ (( packed ));
 
-/** Use natural BIOS drive number */
-#define INT13_USE_NATURAL_DRIVE 0xff
+/** MBR magic signature */
+#define INT13_MBR_MAGIC 0xaa55
+
+/** A floppy disk geometry */
+struct int13_fdd_geometry {
+	/** Number of tracks */
+	uint8_t tracks;
+	/** Number of heads and sectors per track */
+	uint8_t heads_spt;
+};
+
+/** Define a floppy disk geometry */
+#define INT13_FDD_GEOMETRY( cylinders, heads, sectors )			\
+	{								\
+		.tracks = (cylinders),					\
+		.heads_spt = ( ( (heads) << 6 ) | (sectors) ),		\
+	}
+
+/** Get floppy disk number of cylinders */
+#define INT13_FDD_CYLINDERS( geometry ) ( (geometry)->tracks )
+
+/** Get floppy disk number of heads */
+#define INT13_FDD_HEADS( geometry ) ( (geometry)->heads_spt >> 6 )
+
+/** Get floppy disk number of sectors per track */
+#define INT13_FDD_SECTORS( geometry ) ( (geometry)->heads_spt & 0x3f )
+
+/** A floppy drive parameter table */
+struct int13_fdd_parameters {
+	uint8_t step_rate__head_unload;
+	uint8_t head_load__ndma;
+	uint8_t motor_off_delay;
+	uint8_t bytes_per_sector;
+	uint8_t sectors_per_track;
+	uint8_t gap_length;
+	uint8_t data_length;
+	uint8_t format_gap_length;
+	uint8_t format_filler;
+	uint8_t head_settle_time;
+	uint8_t motor_start_time;
+} __attribute__ (( packed ));
 
 #endif /* INT13_H */
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h b/roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h
index 0979454873f3a7dc4d66952f6d3c..689227b7066547f11fe664b8dc16 100644
--- a/roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h
+++ b/roms/ipxe/src/arch/i386/include/ipxe/bios_sanboot.h
@@ -15,4 +15,15 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define SANBOOT_PREFIX_pcbios __pcbios_
 #endif
 
+/**
+ * Get default SAN drive number
+ *
+ * @ret drive		Default drive number
+ */
+static inline __always_inline unsigned int
+SANBOOT_INLINE ( pcbios, san_default_drive ) ( void ) {
+	/* Default to booting from first hard disk */
+	return 0x80;
+}
+
 #endif /* _IPXE_BIOS_SANBOOT_H */
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/guestrpc.h b/roms/ipxe/src/arch/i386/include/ipxe/guestrpc.h
new file mode 100644
index 0000000000000000000000000000000000000000..72a0f714fba7f8e5c423dcf4f97205cd4c11562e
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/include/ipxe/guestrpc.h
@@ -0,0 +1,68 @@
+#ifndef _IPXE_GUESTRPC_H
+#define _IPXE_GUESTRPC_H
+
+/** @file
+ *
+ * VMware GuestRPC mechanism
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/vmware.h>
+
+/** GuestRPC magic number */
+#define GUESTRPC_MAGIC 0x49435052 /* "RPCI" */
+
+/** Open RPC channel */
+#define GUESTRPC_OPEN 0x00
+
+/** Open RPC channel success status */
+#define GUESTRPC_OPEN_SUCCESS 0x00010000
+
+/** Send RPC command length */
+#define GUESTRPC_COMMAND_LEN 0x01
+
+/** Send RPC command length success status */
+#define GUESTRPC_COMMAND_LEN_SUCCESS 0x00810000
+
+/** Send RPC command data */
+#define GUESTRPC_COMMAND_DATA 0x02
+
+/** Send RPC command data success status */
+#define GUESTRPC_COMMAND_DATA_SUCCESS 0x00010000
+
+/** Receive RPC reply length */
+#define GUESTRPC_REPLY_LEN 0x03
+
+/** Receive RPC reply length success status */
+#define GUESTRPC_REPLY_LEN_SUCCESS 0x00830000
+
+/** Receive RPC reply data */
+#define GUESTRPC_REPLY_DATA 0x04
+
+/** Receive RPC reply data success status */
+#define GUESTRPC_REPLY_DATA_SUCCESS 0x00010000
+
+/** Finish receiving RPC reply */
+#define GUESTRPC_REPLY_FINISH 0x05
+
+/** Finish receiving RPC reply success status */
+#define GUESTRPC_REPLY_FINISH_SUCCESS 0x00010000
+
+/** Close RPC channel */
+#define GUESTRPC_CLOSE 0x06
+
+/** Close RPC channel success status */
+#define GUESTRPC_CLOSE_SUCCESS 0x00010000
+
+/** RPC command success status */
+#define GUESTRPC_SUCCESS 0x2031 /* "1 " */
+
+extern int guestrpc_open ( void );
+extern void guestrpc_close ( int channel );
+extern int guestrpc_command ( int channel, const char *command, char *reply,
+			      size_t reply_len );
+
+#endif /* _IPXE_GUESTRPC_H */
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/rtc_entropy.h b/roms/ipxe/src/arch/i386/include/ipxe/rtc_entropy.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c3cf2104ed56a52f6bd4c6fc62f54993f15b284
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/include/ipxe/rtc_entropy.h
@@ -0,0 +1,62 @@
+#ifndef _IPXE_RTC_ENTROPY_H
+#define _IPXE_RTC_ENTROPY_H
+
+/** @file
+ *
+ * RTC-based entropy source
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+#ifdef ENTROPY_RTC
+#define ENTROPY_PREFIX_rtc
+#else
+#define ENTROPY_PREFIX_rtc __rtc_
+#endif
+
+/**
+ * min-entropy per sample
+ *
+ * @ret min_entropy	min-entropy of each sample
+ */
+static inline __always_inline double
+ENTROPY_INLINE ( rtc, min_entropy_per_sample ) ( void ) {
+
+	/* The min-entropy has been measured on several platforms
+	 * using the entropy_sample test code.  Modelling the samples
+	 * as independent, and using a confidence level of 99.99%, the
+	 * measurements were as follows:
+	 *
+	 *    qemu-kvm		: 7.38 bits
+	 *    VMware		: 7.46 bits
+	 *    Physical hardware	: 2.67 bits
+	 *
+	 * We choose the lowest of these (2.67 bits) and apply a 50%
+	 * safety margin to allow for some potential non-independence
+	 * of samples.
+	 */
+	return 1.3;
+}
+
+extern uint8_t rtc_sample ( void );
+
+/**
+ * Get noise sample
+ *
+ * @ret noise		Noise sample
+ * @ret rc		Return status code
+ */
+static inline __always_inline int
+ENTROPY_INLINE ( rtc, get_noise ) ( noise_sample_t *noise ) {
+
+	/* Get sample */
+	*noise = rtc_sample();
+
+	/* Always successful */
+	return 0;
+}
+
+#endif /* _IPXE_RTC_ENTROPY_H */
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/rtc_time.h b/roms/ipxe/src/arch/i386/include/ipxe/rtc_time.h
new file mode 100644
index 0000000000000000000000000000000000000000..c0dfe3f88accaef45bdbdae2c5a65949fd284150
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/include/ipxe/rtc_time.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_RTC_TIME_H
+#define _IPXE_RTC_TIME_H
+
+/** @file
+ *
+ * RTC-based time source
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef TIME_RTC
+#define TIME_PREFIX_rtc
+#else
+#define TIME_PREFIX_rtc __rtc_
+#endif
+
+#endif /* _IPXE_RTC_TIME_H */
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/vmware.h b/roms/ipxe/src/arch/i386/include/ipxe/vmware.h
new file mode 100644
index 0000000000000000000000000000000000000000..2ac65f43678c59b485fece8534bdec4e8e0fc663
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/include/ipxe/vmware.h
@@ -0,0 +1,81 @@
+#ifndef _IPXE_VMWARE_H
+#define _IPXE_VMWARE_H
+
+/** @file
+ *
+ * VMware backdoor mechanism
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/** VMware backdoor I/O port */
+#define VMW_PORT 0x5658
+
+/** VMware backdoor magic value */
+#define VMW_MAGIC 0x564d5868 /* "VMXh" */
+
+/** VMware backdoor magic instruction */
+#define VMW_BACKDOOR "inl %%dx, %%eax"
+
+/** Get VMware version */
+#define VMW_CMD_GET_VERSION 0x0a
+
+/** Issue GuestRPC command */
+#define VMW_CMD_GUESTRPC 0x1e
+
+/**
+ * Get VMware version
+ *
+ * @ret version		VMware version(?)
+ * @ret magic		VMware magic number, if present
+ * @ret product_type	VMware product type
+ */
+static inline __attribute__ (( always_inline )) void
+vmware_cmd_get_version ( uint32_t *version, uint32_t *magic,
+			 uint32_t *product_type ) {
+	uint32_t discard_d;
+
+	/* Perform backdoor call */
+	__asm__ __volatile__ ( VMW_BACKDOOR
+			       : "=a" ( *version ), "=b" ( *magic ),
+				 "=c" ( *product_type ), "=d" ( discard_d )
+			       : "0" ( VMW_MAGIC ), "1" ( 0 ),
+				 "2" ( VMW_CMD_GET_VERSION ),
+				 "3" ( VMW_PORT ) );
+}
+
+/**
+ * Issue GuestRPC command
+ *
+ * @v channel		Channel number
+ * @v subcommand	GuestRPC subcommand
+ * @v parameter		Subcommand-specific parameter
+ * @ret edxhi		Subcommand-specific result
+ * @ret ebx		Subcommand-specific result
+ * @ret status		Command status
+ */
+static inline __attribute__ (( always_inline )) uint32_t
+vmware_cmd_guestrpc ( int channel, uint16_t subcommand, uint32_t parameter,
+		      uint16_t *edxhi, uint32_t *ebx ) {
+	uint32_t discard_a;
+	uint32_t status;
+	uint32_t edx;
+
+	/* Perform backdoor call */
+	__asm__ __volatile__ ( VMW_BACKDOOR
+			       : "=a" ( discard_a ), "=b" ( *ebx ),
+				 "=c" ( status ), "=d" ( edx )
+			       : "0" ( VMW_MAGIC ), "1" ( parameter ),
+				 "2" ( VMW_CMD_GUESTRPC | ( subcommand << 16 )),
+				 "3" ( VMW_PORT | ( channel << 16 ) ) );
+	*edxhi = ( edx >> 16 );
+
+	return status;
+}
+
+extern int vmware_present ( void );
+
+#endif /* _IPXE_VMWARE_H */
diff --git a/roms/ipxe/src/arch/i386/include/ipxe/x86_io.h b/roms/ipxe/src/arch/i386/include/ipxe/x86_io.h
deleted file mode 100644
index a79501e2cc15e6f1c93d8b37dace3cd7a98a7ca6..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/arch/i386/include/ipxe/x86_io.h
+++ /dev/null
@@ -1,153 +0,0 @@
-#ifndef _IPXE_X86_IO_H
-#define _IPXE_X86_IO_H
-
-/** @file
- *
- * iPXE 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.
- */
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#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 /* _IPXE_X86_IO_H */
diff --git a/roms/ipxe/src/arch/i386/include/librm.h b/roms/ipxe/src/arch/i386/include/librm.h
index c6992f64395d581c30031a780b9a..801f586b8e39c8291e16b2ebe080 100644
--- a/roms/ipxe/src/arch/i386/include/librm.h
+++ b/roms/ipxe/src/arch/i386/include/librm.h
@@ -68,6 +68,12 @@ UACCESS_INLINE ( librm, userptr_add ) ( userptr_t userptr, off_t offset ) {
 	return trivial_userptr_add ( userptr, offset );
 }
 
+static inline __always_inline off_t
+UACCESS_INLINE ( librm, userptr_sub ) ( userptr_t userptr,
+					userptr_t subtrahend ) {
+	return trivial_userptr_sub ( userptr, subtrahend );
+}
+
 static inline __always_inline void
 UACCESS_INLINE ( librm, memcpy_user ) ( userptr_t dest, off_t dest_off,
 					userptr_t src, off_t src_off,
diff --git a/roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h b/roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h
index 822b3eba9100f0e762f1117a49fa..a36d9cfa18c86d456e3c7d47ba5c 100644
--- a/roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h
+++ b/roms/ipxe/src/arch/i386/include/pcbios/ipxe/dhcp_arch.h
@@ -33,7 +33,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 		      'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '0', ':', \
 		      'U', 'N', 'D', 'I', ':', '0', '0', '2', '0', '0', '1' )
 
-#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_WORD ( 0 )
+#define DHCP_ARCH_CLIENT_ARCHITECTURE \
+	DHCP_WORD ( DHCP_CLIENT_ARCHITECTURE_X86 )
 
 #define DHCP_ARCH_CLIENT_NDI DHCP_OPTION ( 1 /* UNDI */ , 2, 1 /* v2.1 */ )
 
diff --git a/roms/ipxe/src/arch/i386/include/pic8259.h b/roms/ipxe/src/arch/i386/include/pic8259.h
index f8e20c4c46c4fac607215575b349..a07e97d30602acd6153cb8a2fd34 100644
--- a/roms/ipxe/src/arch/i386/include/pic8259.h
+++ b/roms/ipxe/src/arch/i386/include/pic8259.h
@@ -9,6 +9,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #ifndef PIC8259_H
 #define PIC8259_H
 
+#include <ipxe/io.h>
+
 /* For segoff_t */
 #include "realmode.h"
 
diff --git a/roms/ipxe/src/arch/i386/include/pxe.h b/roms/ipxe/src/arch/i386/include/pxe.h
index 909c8d818af1b0a1fab165479799..0206f683ae01f89c2ec8dff536cf 100644
--- a/roms/ipxe/src/arch/i386/include/pxe.h
+++ b/roms/ipxe/src/arch/i386/include/pxe.h
@@ -6,8 +6,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include "pxe_types.h"
 #include "pxe_api.h"
 #include <ipxe/device.h>
+#include <ipxe/tables.h>
 
-/* Parameter block for pxenv_unknown() */
+/** PXE API invalid function code */
+#define PXENV_UNKNOWN 0xffff
+
+/** Parameter block for pxenv_unknown() */
 struct s_PXENV_UNKNOWN {
 	PXENV_STATUS_t Status;			/**< PXE status code */
 } __attribute__ (( packed ));
@@ -72,6 +76,45 @@ union u_PXENV_ANY {
 
 typedef union u_PXENV_ANY PXENV_ANY_t;
 
+/** A PXE API call */
+struct pxe_api_call {
+	/** Entry point
+	 *
+	 * @v params		PXE API call parameters
+	 * @ret exit		PXE API call exit code
+	 */
+	PXENV_EXIT_t ( * entry ) ( union u_PXENV_ANY *params );
+	/** Length of parameters */
+	uint16_t params_len;
+	/** Opcode */
+	uint16_t opcode;
+};
+
+/** PXE API call table */
+#define PXE_API_CALLS __table ( struct pxe_api_call, "pxe_api_calls" )
+
+/** Declare a PXE API call */
+#define __pxe_api_call __table_entry ( PXE_API_CALLS, 01 )
+
+/**
+ * Define a PXE API call
+ *
+ * @v _opcode		Opcode
+ * @v _entry		Entry point
+ * @v _params_type	Type of parameter structure
+ * @ret call		PXE API call
+ */
+#define PXE_API_CALL( _opcode, _entry, _params_type ) {			      \
+	.entry = ( ( ( ( PXENV_EXIT_t ( * ) ( _params_type *params ) ) NULL ) \
+		    == ( ( typeof ( _entry ) * ) NULL ) )		      \
+		   ? ( ( PXENV_EXIT_t ( * )				      \
+			 ( union u_PXENV_ANY *params ) ) _entry )	      \
+		   : ( ( PXENV_EXIT_t ( * )				      \
+			 ( union u_PXENV_ANY *params ) ) _entry ) ),	      \
+	.params_len = sizeof ( _params_type ),				      \
+	.opcode = _opcode,						      \
+	}
+
 /** An UNDI expansion ROM header */
 struct undi_rom_header {
 	/** Signature
@@ -144,9 +187,12 @@ struct pcir_header {
 #define PCIR_SIGNATURE \
 	( ( 'P' << 0 ) + ( 'C' << 8 ) + ( 'I' << 16 ) + ( 'R' << 24 ) )
 
-
 extern struct net_device *pxe_netdev;
+extern const char *pxe_cmdline;
 
 extern void pxe_set_netdev ( struct net_device *netdev );
+extern PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
+					   *tftp_read_file );
+extern PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader );
 
 #endif /* PXE_H */
diff --git a/roms/ipxe/src/arch/i386/include/pxe_api.h b/roms/ipxe/src/arch/i386/include/pxe_api.h
index 9b40187ed102b115d482c3379bcd..e4396efb2307e332999db209e8e5 100644
--- a/roms/ipxe/src/arch/i386/include/pxe_api.h
+++ b/roms/ipxe/src/arch/i386/include/pxe_api.h
@@ -14,7 +14,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  *
  * As an alternative, at your option, you may use this file under the
  * following terms, known as the "MIT license":
@@ -252,9 +253,6 @@ struct s_PXENV_UNLOAD_STACK {
 
 typedef struct s_PXENV_UNLOAD_STACK PXENV_UNLOAD_STACK_t;
 
-extern PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK
-					 *unload_stack );
-
 /** @} */ /* pxenv_unload_stack */
 
 /** @defgroup pxenv_get_cached_info PXENV_GET_CACHED_INFO
@@ -403,9 +401,6 @@ struct bootph {
 
 typedef struct bootph BOOTPLAYER_t;
 
-extern PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
-					    *get_cached_info );
-
 /** @} */ /* pxenv_get_cached_info */
 
 /** @defgroup pxenv_restart_tftp PXENV_RESTART_TFTP
@@ -423,9 +418,6 @@ struct s_PXENV_TFTP_READ_FILE;
 
 typedef struct s_PXENV_RESTART_TFTP PXENV_RESTART_TFTP_t;
 
-extern PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
-					 *restart_tftp );
-
 /** @} */ /* pxenv_restart_tftp */
 
 /** @defgroup pxenv_start_undi PXENV_START_UNDI
@@ -496,8 +488,6 @@ struct s_PXENV_START_UNDI {
 
 typedef struct s_PXENV_START_UNDI PXENV_START_UNDI_t;
 
-extern PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi );
-
 /** @} */ /* pxenv_start_undi */
 
 /** @defgroup pxenv_stop_undi PXENV_STOP_UNDI
@@ -517,8 +507,6 @@ struct s_PXENV_STOP_UNDI {
 
 typedef struct s_PXENV_STOP_UNDI PXENV_STOP_UNDI_t;
 
-extern PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi );
-
 /** @} */ /* pxenv_stop_undi */
 
 /** @defgroup pxenv_start_base PXENV_START_BASE
@@ -538,8 +526,6 @@ struct s_PXENV_START_BASE {
 
 typedef struct s_PXENV_START_BASE PXENV_START_BASE_t;
 
-extern PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base );
-
 /** @} */ /* pxenv_start_base */
 
 /** @defgroup pxenv_stop_base PXENV_STOP_BASE
@@ -559,8 +545,6 @@ struct s_PXENV_STOP_BASE {
 
 typedef struct s_PXENV_STOP_BASE PXENV_STOP_BASE_t;
 
-extern PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base );
-
 /** @} */ /* pxenv_stop_base */
 
 /** @} */ /* pxe_preboot_api */
@@ -600,8 +584,6 @@ struct s_PXENV_TFTP_OPEN {
 
 typedef struct s_PXENV_TFTP_OPEN PXENV_TFTP_OPEN_t;
 
-extern PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open );
-
 /** @} */ /* pxenv_tftp_open */
 
 /** @defgroup pxenv_tftp_close PXENV_TFTP_CLOSE
@@ -621,8 +603,6 @@ struct s_PXENV_TFTP_CLOSE {
 
 typedef struct s_PXENV_TFTP_CLOSE PXENV_TFTP_CLOSE_t;
 
-extern PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close );
-
 /** @} */ /* pxenv_tftp_close */
 
 /** @defgroup pxenv_tftp_read PXENV_TFTP_READ
@@ -645,8 +625,6 @@ struct s_PXENV_TFTP_READ {
 
 typedef struct s_PXENV_TFTP_READ PXENV_TFTP_READ_t;
 
-extern PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read );
-
 /** @} */ /* pxenv_tftp_read */
 
 /** @defgroup pxenv_tftp_read_file PXENV_TFTP_READ_FILE
@@ -690,9 +668,6 @@ struct s_PXENV_TFTP_READ_FILE {
 
 typedef struct s_PXENV_TFTP_READ_FILE PXENV_TFTP_READ_FILE_t;
 
-extern PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
-					   *tftp_read_file );
-
 /** @} */ /* pxenv_tftp_read_file */
 
 /** @defgroup pxenv_tftp_get_fsize PXENV_TFTP_GET_FSIZE
@@ -716,9 +691,6 @@ struct s_PXENV_TFTP_GET_FSIZE {
 
 typedef struct s_PXENV_TFTP_GET_FSIZE PXENV_TFTP_GET_FSIZE_t;
 
-extern PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
-					   *get_fsize );
-
 /** @} */ /* pxenv_tftp_get_fsize */
 
 /** @} */ /* pxe_tftp_api */
@@ -748,8 +720,6 @@ struct s_PXENV_UDP_OPEN {
 
 typedef struct s_PXENV_UDP_OPEN PXENV_UDP_OPEN_t;
 
-extern PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *udp_open );
-
 /** @} */ /* pxenv_udp_open */
 
 /** @defgroup pxenv_udp_close PXENV_UDP_CLOSE
@@ -769,8 +739,6 @@ struct s_PXENV_UDP_CLOSE {
 
 typedef struct s_PXENV_UDP_CLOSE PXENV_UDP_CLOSE_t;
 
-extern PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close );
-
 /** @} */ /* pxenv_udp_close */
 
 /** @defgroup pxenv_udp_write PXENV_UDP_WRITE
@@ -796,8 +764,6 @@ struct s_PXENV_UDP_WRITE {
 
 typedef struct s_PXENV_UDP_WRITE PXENV_UDP_WRITE_t;
 
-extern PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *udp_write );
-
 /** @} */ /* pxenv_udp_write */
 
 /** @defgroup pxenv_udp_read PXENV_UDP_READ
@@ -823,8 +789,6 @@ struct s_PXENV_UDP_READ {
 
 typedef struct s_PXENV_UDP_READ PXENV_UDP_READ_t;
 
-extern PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *udp_read );
-
 /** @} */ /* pxenv_udp_read */
 
 /** @} */ /* pxe_udp_api */
@@ -860,9 +824,6 @@ struct s_PXENV_UNDI_STARTUP {
 
 typedef struct s_PXENV_UNDI_STARTUP PXENV_UNDI_STARTUP_t;
 
-extern PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP
-					 *undi_startup );
-
 /** @} */ /* pxenv_undi_startup */
 
 /** @defgroup pxenv_undi_cleanup PXENV_UNDI_CLEANUP
@@ -882,9 +843,6 @@ struct s_PXENV_UNDI_CLEANUP {
 
 typedef struct s_PXENV_UNDI_CLEANUP PXENV_UNDI_CLEANUP_t;
 
-extern PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP
-					 *undi_cleanup );
-
 /** @} */ /* pxenv_undi_cleanup */
 
 /** @defgroup pxenv_undi_initialize PXENV_UNDI_INITIALIZE
@@ -913,9 +871,6 @@ struct s_PXENV_UNDI_INITIALIZE {
 
 typedef struct s_PXENV_UNDI_INITIALIZE PXENV_UNDI_INITIALIZE_t;
 
-extern PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE
-					    *undi_initialize );
-
 /** @} */ /* pxenv_undi_initialize */
 
 /** @defgroup pxenv_undi_reset_adapter PXENV_UNDI_RESET_ADAPTER
@@ -950,9 +905,6 @@ struct s_PXENV_UNDI_RESET {
 
 typedef struct s_PXENV_UNDI_RESET PXENV_UNDI_RESET_t;
 
-extern PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET
-					       *undi_reset_adapter );
-
 /** @} */ /* pxenv_undi_reset_adapter */
 
 /** @defgroup pxenv_undi_shutdown PXENV_UNDI_SHUTDOWN
@@ -972,9 +924,6 @@ struct s_PXENV_UNDI_SHUTDOWN {
 
 typedef struct s_PXENV_UNDI_SHUTDOWN PXENV_UNDI_SHUTDOWN_t;
 
-extern PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN
-					  *undi_shutdown );
-
 /** @} */ /* pxenv_undi_shutdown */
 
 /** @defgroup pxenv_undi_open PXENV_UNDI_OPEN
@@ -1024,8 +973,6 @@ struct s_PXENV_UNDI_OPEN {
 
 typedef struct s_PXENV_UNDI_OPEN PXENV_UNDI_OPEN_t;
 
-extern PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open );
-
 /** @} */ /* pxenv_undi_open */
 
 /** @defgroup pxenv_undi_close PXENV_UNDI_CLOSE
@@ -1045,8 +992,6 @@ struct s_PXENV_UNDI_CLOSE {
 
 typedef struct s_PXENV_UNDI_CLOSE PXENV_UNDI_CLOSE_t;
 
-extern PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close );
-
 /** @} */ /* pxenv_undi_close */
 
 /** @defgroup pxenv_undi_transmit PXENV_UNDI_TRANSMIT
@@ -1122,9 +1067,6 @@ struct s_PXENV_UNDI_TRANSMIT {
 
 typedef struct s_PXENV_UNDI_TRANSMIT PXENV_UNDI_TRANSMIT_t;
 
-extern PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
-					  *undi_transmit );
-
 /** @} */ /* pxenv_undi_transmit */
 
 /** @defgroup pxenv_undi_set_mcast_address PXENV_UNDI_SET_MCAST_ADDRESS
@@ -1146,9 +1088,6 @@ struct s_PXENV_UNDI_SET_MCAST_ADDRESS {
 
 typedef struct s_PXENV_UNDI_SET_MCAST_ADDRESS PXENV_UNDI_SET_MCAST_ADDRESS_t;
 
-extern PXENV_EXIT_t pxenv_undi_set_mcast_address (
-	       struct s_PXENV_UNDI_SET_MCAST_ADDRESS *undi_set_mcast_address );
-
 /** @} */ /* pxenv_undi_set_mcast_address */
 
 /** @defgroup pxenv_undi_set_station_address PXENV_UNDI_SET_STATION_ADDRESS
@@ -1169,9 +1108,6 @@ struct s_PXENV_UNDI_SET_STATION_ADDRESS {
 
 typedef struct s_PXENV_UNDI_SET_STATION_ADDRESS PXENV_UNDI_SET_STATION_ADDRESS_t;
 
-extern PXENV_EXIT_t pxenv_undi_set_station_address (
-	   struct s_PXENV_UNDI_SET_STATION_ADDRESS *undi_set_station_address );
-
 /** @} */ /* pxenv_undi_set_station_address */
 
 /** @defgroup pxenv_undi_set_packet_filter PXENV_UNDI_SET_PACKET_FILTER
@@ -1202,9 +1138,6 @@ struct s_PXENV_UNDI_SET_PACKET_FILTER {
 
 typedef struct s_PXENV_UNDI_SET_PACKET_FILTER PXENV_UNDI_SET_PACKET_FILTER_t;
 
-extern PXENV_EXIT_t pxenv_undi_set_packet_filter (
-	       struct s_PXENV_UNDI_SET_PACKET_FILTER *undi_set_packet_filter );
-
 /** @} */ /* pxenv_undi_set_packet_filter */
 
 /** @defgroup pxenv_undi_get_information PXENV_UNDI_GET_INFORMATION
@@ -1248,9 +1181,6 @@ struct s_PXENV_UNDI_GET_INFORMATION {
 
 typedef struct s_PXENV_UNDI_GET_INFORMATION PXENV_UNDI_GET_INFORMATION_t;
 
-extern PXENV_EXIT_t pxenv_undi_get_information (
-		   struct s_PXENV_UNDI_GET_INFORMATION *undi_get_information );
-
 /** @} */ /* pxenv_undi_get_information */
 
 /** @defgroup pxenv_undi_get_statistics PXENV_UNDI_GET_STATISTICS
@@ -1274,9 +1204,6 @@ struct s_PXENV_UNDI_GET_STATISTICS {
 
 typedef struct s_PXENV_UNDI_GET_STATISTICS PXENV_UNDI_GET_STATISTICS_t;
 
-extern PXENV_EXIT_t pxenv_undi_get_statistics (
-		     struct s_PXENV_UNDI_GET_STATISTICS *undi_get_statistics );
-
 /** @} */ /* pxenv_undi_get_statistics */
 
 /** @defgroup pxenv_undi_clear_statistics PXENV_UNDI_CLEAR_STATISTICS
@@ -1296,9 +1223,6 @@ struct s_PXENV_UNDI_CLEAR_STATISTICS {
 
 typedef struct s_PXENV_UNDI_CLEAR_STATISTICS PXENV_UNDI_CLEAR_STATISTICS_t;
 
-extern PXENV_EXIT_t pxenv_undi_clear_statistics (
-		 struct s_PXENV_UNDI_CLEAR_STATISTICS *undi_clear_statistics );
-
 /** @} */ /* pxenv_undi_clear_statistics */
 
 /** @defgroup pxenv_undi_initiate_diags PXENV_UNDI_INITIATE_DIAGS
@@ -1318,9 +1242,6 @@ struct s_PXENV_UNDI_INITIATE_DIAGS {
 
 typedef struct s_PXENV_UNDI_INITIATE_DIAGS PXENV_UNDI_INITIATE_DIAGS_t;
 
-extern PXENV_EXIT_t pxenv_undi_initiate_diags (
-		     struct s_PXENV_UNDI_INITIATE_DIAGS *undi_initiate_diags );
-
 /** @} */ /* pxenv_undi_initiate_diags */
 
 /** @defgroup pxenv_undi_force_interrupt PXENV_UNDI_FORCE_INTERRUPT
@@ -1340,9 +1261,6 @@ struct s_PXENV_UNDI_FORCE_INTERRUPT {
 
 typedef struct s_PXENV_UNDI_FORCE_INTERRUPT PXENV_UNDI_FORCE_INTERRUPT_t;
 
-extern PXENV_EXIT_t pxenv_undi_force_interrupt (
-		   struct s_PXENV_UNDI_FORCE_INTERRUPT *undi_force_interrupt );
-
 /** @} */ /* pxenv_undi_force_interrupt */
 
 /** @defgroup pxenv_undi_get_mcast_address PXENV_UNDI_GET_MCAST_ADDRESS
@@ -1364,9 +1282,6 @@ struct s_PXENV_UNDI_GET_MCAST_ADDRESS {
 
 typedef struct s_PXENV_UNDI_GET_MCAST_ADDRESS PXENV_UNDI_GET_MCAST_ADDRESS_t;
 
-extern PXENV_EXIT_t pxenv_undi_get_mcast_address (
-	       struct s_PXENV_UNDI_GET_MCAST_ADDRESS *undi_get_mcast_address );
-
 /** @} */ /* pxenv_undi_get_mcast_address */
 
 /** @defgroup pxenv_undi_get_nic_type PXENV_UNDI_GET_NIC_TYPE
@@ -1427,9 +1342,6 @@ struct s_PXENV_UNDI_GET_NIC_TYPE {
 
 typedef struct s_PXENV_UNDI_GET_NIC_TYPE PXENV_UNDI_GET_NIC_TYPE_t;
 
-extern PXENV_EXIT_t pxenv_undi_get_nic_type ( 
-			 struct s_PXENV_UNDI_GET_NIC_TYPE *undi_get_nic_type );
-
 /** @} */ /* pxenv_undi_get_nic_type */
 
 /** @defgroup pxenv_undi_get_iface_info PXENV_UNDI_GET_IFACE_INFO
@@ -1488,9 +1400,6 @@ struct s_PXENV_UNDI_GET_IFACE_INFO {
 
 typedef struct s_PXENV_UNDI_GET_IFACE_INFO PXENV_UNDI_GET_IFACE_INFO_t;
 
-extern PXENV_EXIT_t pxenv_undi_get_iface_info (
-		     struct s_PXENV_UNDI_GET_IFACE_INFO *undi_get_iface_info );
-
 /** @} */ /* pxenv_undi_get_iface_info */
 
 /** @defgroup pxenv_undi_get_state PXENV_UNDI_GET_STATE
@@ -1524,9 +1433,6 @@ struct s_PXENV_UNDI_GET_STATE {
 
 typedef struct s_PXENV_UNDI_GET_STATE PXENV_UNDI_GET_STATE_t;
 
-extern PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
-					   *undi_get_state );
-
 /** @} */ /* pxenv_undi_get_state */
 
 /** @defgroup pxenv_undi_isr PXENV_UNDI_ISR
@@ -1595,8 +1501,6 @@ struct s_PXENV_UNDI_ISR {
 
 typedef struct s_PXENV_UNDI_ISR PXENV_UNDI_ISR_t;
 
-extern PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr );
-
 /** @} */ /* pxenv_undi_isr */
 
 /** @} */ /* pxe_undi_api */
@@ -1608,6 +1512,12 @@ extern PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr );
  * @{
  */
 
+/** Minimum possible opcode used within PXE FILE API */
+#define PXENV_FILE_MIN 0x00e0
+
+/** Minimum possible opcode used within PXE FILE API */
+#define PXENV_FILE_MAX 0x00ef
+
 /** @defgroup pxenv_file_open PXENV_FILE_OPEN
  *
  * FILE OPEN
@@ -1628,8 +1538,6 @@ struct s_PXENV_FILE_OPEN {
 
 typedef struct s_PXENV_FILE_OPEN PXENV_FILE_OPEN_t;
 
-extern PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open );
-
 /** @} */ /* pxenv_file_open */
 
 /** @defgroup pxenv_file_close PXENV_FILE_CLOSE
@@ -1650,9 +1558,6 @@ struct s_PXENV_FILE_CLOSE {
 
 typedef struct s_PXENV_FILE_CLOSE PXENV_FILE_CLOSE_t;
 
-extern PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE
-				       *file_close );
-
 /** @} */ /* pxenv_file_close */
 
 /** @defgroup pxenv_file_select PXENV_FILE_SELECT
@@ -1677,9 +1582,6 @@ struct s_PXENV_FILE_SELECT {
 
 typedef struct s_PXENV_FILE_SELECT PXENV_FILE_SELECT_t;
 
-extern PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT
-					*file_select );
-
 /** @} */ /* pxenv_file_select */
 
 /** @defgroup pxenv_file_read PXENV_FILE_READ
@@ -1702,8 +1604,6 @@ struct s_PXENV_FILE_READ {
 
 typedef struct s_PXENV_FILE_READ PXENV_FILE_READ_t;
 
-extern PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read );
-
 /** @} */ /* pxenv_file_read */
 
 /** @defgroup pxenv_get_file_size PXENV_GET_FILE_SIZE
@@ -1725,9 +1625,6 @@ struct s_PXENV_GET_FILE_SIZE {
 
 typedef struct s_PXENV_GET_FILE_SIZE PXENV_GET_FILE_SIZE_t;
 
-extern PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE
-					  *get_file_size );
-
 /** @} */ /* pxenv_get_file_size */
 
 /** @defgroup pxenv_file_exec PXENV_FILE_EXEC
@@ -1748,8 +1645,6 @@ struct s_PXENV_FILE_EXEC {
 
 typedef struct s_PXENV_FILE_EXEC PXENV_FILE_EXEC_t;
 
-extern PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec );
-
 /** @} */ /* pxenv_file_exec */
 
 /** @defgroup pxenv_file_api_check PXENV_FILE_API_CHECK
@@ -1774,8 +1669,6 @@ struct s_PXENV_FILE_API_CHECK {
 
 typedef struct s_PXENV_FILE_API_CHECK PXENV_FILE_API_CHECK_t;
 
-extern PXENV_EXIT_t pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_check );
-
 /** @} */ /* pxenv_file_api_check */
 
 /** @defgroup pxenv_file_exit_hook PXENV_FILE_EXIT_HOOK
@@ -1796,10 +1689,29 @@ struct s_PXENV_FILE_EXIT_HOOK {
 
 typedef struct s_PXENV_FILE_EXIT_HOOK PXENV_FILE_EXIT_HOOK_t;
 
-extern PXENV_EXIT_t pxenv_file_exit_hook ( struct s_PXENV_FILE_EXIT_HOOK *file_exit_hook );
-
 /** @} */ /* pxenv_file_exit_hook */
 
+/** @defgroup pxenv_file_cmdline PXENV_FILE_CMDLINE
+ *
+ * FILE CMDLINE
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_file_cmdline() */
+#define PXENV_FILE_CMDLINE			0x00e8
+
+/** Parameter block for pxenv_file_cmdline() */
+struct s_PXENV_FILE_CMDLINE {
+	PXENV_STATUS_t Status;		/**< PXE status code */
+	UINT16_t BufferSize;		/**< Data buffer size */
+	SEGOFF16_t Buffer;		/**< Data buffer */
+} __attribute__ (( packed ));
+
+typedef struct s_PXENV_FILE_CMDLINE PXENV_FILE_CMDLINE_t;
+
+/** @} */ /* pxe_file_cmdline */
+
 /** @} */ /* pxe_file_api */
 
 /** @defgroup pxe_loader_api PXE Loader API
@@ -1847,8 +1759,6 @@ struct s_UNDI_LOADER {
 
 typedef struct s_UNDI_LOADER UNDI_LOADER_t;
 
-extern PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader );
-
 /** @} */ /* pxe_loader_api */
 
 /** @} */ /* pxe */
diff --git a/roms/ipxe/src/arch/i386/include/rtc.h b/roms/ipxe/src/arch/i386/include/rtc.h
new file mode 100644
index 0000000000000000000000000000000000000000..2a6abbae57295430932424680c2dbd349471e0eb
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/include/rtc.h
@@ -0,0 +1,83 @@
+#ifndef _RTC_H
+#define _RTC_H
+
+/** @file
+ *
+ * CMOS Real-Time Clock (RTC)
+ *
+ * The CMOS/RTC registers are documented (with varying degrees of
+ * accuracy and consistency) at
+ *
+ *    http://www.nondot.org/sabre/os/files/MiscHW/RealtimeClockFAQ.txt
+ *    http://wiki.osdev.org/RTC
+ *    http://wiki.osdev.org/CMOS
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <pic8259.h>
+
+/** RTC IRQ */
+#define RTC_IRQ 8
+
+/** RTC interrupt vector */
+#define RTC_INT IRQ_INT ( RTC_IRQ )
+
+/** CMOS/RTC address (and NMI) register */
+#define CMOS_ADDRESS 0x70
+
+/** NMI disable bit */
+#define CMOS_DISABLE_NMI 0x80
+
+/** CMOS/RTC data register */
+#define CMOS_DATA 0x71
+
+/** RTC seconds */
+#define RTC_SEC 0x00
+
+/** RTC minutes */
+#define RTC_MIN 0x02
+
+/** RTC hours */
+#define RTC_HOUR 0x04
+
+/** RTC weekday */
+#define RTC_WDAY 0x06
+
+/** RTC day of month */
+#define RTC_MDAY 0x07
+
+/** RTC month */
+#define RTC_MON 0x08
+
+/** RTC year */
+#define RTC_YEAR 0x09
+
+/** RTC status register A */
+#define RTC_STATUS_A 0x0a
+
+/** RTC update in progress bit */
+#define RTC_STATUS_A_UPDATE_IN_PROGRESS 0x80
+
+/** RTC status register B */
+#define RTC_STATUS_B 0x0b
+
+/** RTC 24 hour format bit */
+#define RTC_STATUS_B_24_HOUR 0x02
+
+/** RTC binary mode bit */
+#define RTC_STATUS_B_BINARY 0x04
+
+/** RTC Periodic Interrupt Enabled bit */
+#define RTC_STATUS_B_PIE 0x40
+
+/** RTC status register C */
+#define RTC_STATUS_C 0x0c
+
+/** RTC status register D */
+#define RTC_STATUS_D 0x0d
+
+/** CMOS default address */
+#define CMOS_DEFAULT_ADDRESS RTC_STATUS_D
+
+#endif /* _RTC_H */
diff --git a/roms/ipxe/src/arch/i386/include/sdi.h b/roms/ipxe/src/arch/i386/include/sdi.h
new file mode 100644
index 0000000000000000000000000000000000000000..fc486402d1894adf52f5fedf74444719a14c3d9a
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/include/sdi.h
@@ -0,0 +1,39 @@
+#ifndef _SDI_H
+#define _SDI_H
+
+/** @file
+ *
+ * System Deployment Image (SDI)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** SDI image header */
+struct sdi_header {
+	/** Signature */
+	uint32_t magic;
+	/** Version (as an ASCII string) */
+	uint32_t version;
+	/** Reserved */
+	uint8_t reserved[8];
+	/** Boot code offset */
+	uint64_t boot_offset;
+	/** Boot code size */
+	uint64_t boot_size;
+} __attribute__ (( packed ));
+
+/** SDI image signature */
+#define SDI_MAGIC \
+	( ( '$' << 0 ) | ( 'S' << 8 ) | ( 'D' << 16 ) | ( 'I' << 24 ) )
+
+/** SDI boot segment */
+#define SDI_BOOT_SEG 0x0000
+
+/** SDI boot offset */
+#define SDI_BOOT_OFF 0x7c00
+
+/** Constant to binary-OR with physical address of SDI image */
+#define SDI_WTF 0x41
+
+#endif /* _SDI_H */
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c b/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c
index cde3d0603f9454d5dd24d6203ade..76a32e93db69081b8962d3068e4f 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/bios_smbios.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -76,6 +77,8 @@ static int bios_find_smbios ( struct smbios *smbios ) {
 		smbios->address = phys_to_user ( u.entry.smbios_address );
 		smbios->len = u.entry.smbios_len;
 		smbios->count = u.entry.smbios_count;
+		smbios->version =
+			SMBIOS_VERSION ( u.entry.major, u.entry.minor );
 		return 0;
 	}
 
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c b/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c
index 70c3986b1252626c7a4c8e44479d..3cb8756f74841662f2874f3c4cdd 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/bios_timer.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/int13.c b/roms/ipxe/src/arch/i386/interface/pcbios/int13.c
index 392dbd5fbba7e5abfd22045317aa..1c7a8128f27861dda1ec773e8c78 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/int13.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/int13.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -37,6 +38,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/sanboot.h>
 #include <ipxe/device.h>
 #include <ipxe/pci.h>
+#include <ipxe/iso9660.h>
+#include <ipxe/eltorito.h>
 #include <realmode.h>
 #include <bios.h>
 #include <biosint.h>
@@ -75,9 +78,9 @@ struct int13_drive {
 	/** Underlying block device interface */
 	struct interface block;
 
-	/** BIOS in-use drive number (0x80-0xff) */
+	/** BIOS in-use drive number (0x00-0xff) */
 	unsigned int drive;
-	/** BIOS natural drive number (0x80-0xff)
+	/** BIOS natural drive number (0x00-0xff)
 	 *
 	 * This is the drive number that would have been assigned by
 	 * 'naturally' appending the drive to the end of the BIOS
@@ -91,6 +94,13 @@ struct int13_drive {
 
 	/** Block device capacity */
 	struct block_device_capacity capacity;
+	/** INT 13 emulated blocksize shift
+	 *
+	 * To allow for emulation of CD-ROM access, this represents
+	 * the left-shift required to translate from INT 13 blocks to
+	 * underlying blocks.
+	 */
+	unsigned int blksize_shift;
 
 	/** Number of cylinders
 	 *
@@ -117,6 +127,11 @@ struct int13_drive {
 	 */
 	unsigned int sectors_per_track;
 
+	/** Drive is a CD-ROM */
+	int is_cdrom;
+	/** Address of El Torito boot catalog (if any) */
+	unsigned int boot_catalog;
+
 	/** Underlying device status, if in error */
 	int block_rc;
 	/** Status of last operation */
@@ -130,17 +145,85 @@ static struct segoff __text16 ( int13_vector );
 /** Assembly wrapper */
 extern void int13_wrapper ( void );
 
+/** Dummy floppy disk parameter table */
+static struct int13_fdd_parameters __data16 ( int13_fdd_params ) = {
+	/* 512 bytes per sector */
+	.bytes_per_sector = 0x02,
+	/* Highest sectors per track that we ever return */
+	.sectors_per_track = 48,
+};
+#define int13_fdd_params __use_data16 ( int13_fdd_params )
+
 /** List of registered emulated drives */
 static LIST_HEAD ( int13s );
 
 /**
- * Number of BIOS drives
+ * Equipment word
+ *
+ * This is a cached copy of the BIOS Data Area equipment word at
+ * 40:10.
+ */
+static uint16_t equipment_word;
+
+/**
+ * Number of BIOS floppy disk drives
+ *
+ * This is derived from the equipment word.  It is held in .text16 to
+ * allow for easy access by the INT 13,08 wrapper.
+ */
+static uint8_t __text16 ( num_fdds );
+#define num_fdds __use_text16 ( num_fdds )
+
+/**
+ * Number of BIOS hard disk drives
+ *
+ * This is a cached copy of the BIOS Data Area number of hard disk
+ * drives at 40:75.  It is held in .text16 to allow for easy access by
+ * the INT 13,08 wrapper.
+ */
+static uint8_t __text16 ( num_drives );
+#define num_drives __use_text16 ( num_drives )
+
+/**
+ * Calculate INT 13 drive sector size
+ *
+ * @v int13		Emulated drive
+ * @ret blksize		Sector size
+ */
+static inline size_t int13_blksize ( struct int13_drive *int13 ) {
+	return ( int13->capacity.blksize << int13->blksize_shift );
+}
+
+/**
+ * Calculate INT 13 drive capacity
+ *
+ * @v int13		Emulated drive
+ * @ret blocks		Number of blocks
+ */
+static inline uint64_t int13_capacity ( struct int13_drive *int13 ) {
+	return ( int13->capacity.blocks >> int13->blksize_shift );
+}
+
+/**
+ * Calculate INT 13 drive capacity (limited to 32 bits)
  *
- * Note that this is the number of drives in the system as a whole
- * (i.e. a mirror of the counter at 40:75), rather than a count of the
- * number of emulated drives.
+ * @v int13		Emulated drive
+ * @ret blocks		Number of blocks
  */
-static uint8_t num_drives;
+static inline uint32_t int13_capacity32 ( struct int13_drive *int13 ) {
+	uint64_t capacity = int13_capacity ( int13 );
+	return ( ( capacity <= 0xffffffffUL ) ? capacity : 0xffffffff );
+}
+
+/**
+ * Test if INT 13 drive is a floppy disk drive
+ *
+ * @v int13		Emulated drive
+ * @ret is_fdd		Emulated drive is a floppy disk
+ */
+static inline int int13_is_fdd ( struct int13_drive *int13 ) {
+	return ( ! ( int13->drive & 0x80 ) );
+}
 
 /** An INT 13 command */
 struct int13_command {
@@ -319,6 +402,10 @@ static int int13_rw ( struct int13_drive *int13, uint64_t lba,
 	size_t frag_len;
 	int rc;
 
+	/* Translate to underlying blocksize */
+	lba <<= int13->blksize_shift;
+	count <<= int13->blksize_shift;
+
 	while ( count ) {
 
 		/* Determine fragment length */
@@ -371,63 +458,245 @@ static int int13_read_capacity ( struct int13_drive *int13 ) {
 }
 
 /**
- * Guess INT 13 drive geometry
+ * Parse ISO9660 parameters
  *
  * @v int13		Emulated drive
+ * @v scratch		Scratch area for single-sector reads
+ * @ret rc		Return status code
+ *
+ * Reads and parses ISO9660 parameters, if present.
+ */
+static int int13_parse_iso9660 ( struct int13_drive *int13, void *scratch ) {
+	static const struct iso9660_primary_descriptor_fixed primary_check = {
+		.type = ISO9660_TYPE_PRIMARY,
+		.id = ISO9660_ID,
+	};
+	struct iso9660_primary_descriptor *primary = scratch;
+	static const struct eltorito_descriptor_fixed boot_check = {
+		.type = ISO9660_TYPE_BOOT,
+		.id = ISO9660_ID,
+		.version = 1,
+		.system_id = "EL TORITO SPECIFICATION",
+	};
+	struct eltorito_descriptor *boot = scratch;
+	unsigned int blksize;
+	unsigned int blksize_shift;
+	int rc;
+
+	/* Calculate required blocksize shift */
+	blksize = int13_blksize ( int13 );
+	blksize_shift = 0;
+	while ( blksize < ISO9660_BLKSIZE ) {
+		blksize <<= 1;
+		blksize_shift++;
+	}
+	if ( blksize > ISO9660_BLKSIZE ) {
+		/* Do nothing if the blksize is invalid for CD-ROM access */
+		return 0;
+	}
+
+	/* Read primary volume descriptor */
+	if ( ( rc = int13_rw ( int13,
+			       ( ISO9660_PRIMARY_LBA << blksize_shift ), 1,
+			       virt_to_user ( primary ), block_read ) ) != 0 ){
+		DBGC ( int13, "INT13 drive %02x could not read ISO9660 "
+		       "primary volume descriptor: %s\n",
+		       int13->drive, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Do nothing unless this is an ISO image */
+	if ( memcmp ( primary, &primary_check, sizeof ( primary_check ) ) != 0 )
+		return 0;
+	DBGC ( int13, "INT13 drive %02x contains an ISO9660 filesystem; "
+	       "treating as CD-ROM\n", int13->drive );
+	int13->is_cdrom = 1;
+
+	/* Read boot record volume descriptor */
+	if ( ( rc = int13_rw ( int13,
+			       ( ELTORITO_LBA << blksize_shift ), 1,
+			       virt_to_user ( boot ), block_read ) ) != 0 ) {
+		DBGC ( int13, "INT13 drive %02x could not read El Torito boot "
+		       "record volume descriptor: %s\n",
+		       int13->drive, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Check for an El Torito boot catalog */
+	if ( memcmp ( boot, &boot_check, sizeof ( boot_check ) ) == 0 ) {
+		int13->boot_catalog = boot->sector;
+		DBGC ( int13, "INT13 drive %02x has an El Torito boot catalog "
+		       "at LBA %08x\n", int13->drive, int13->boot_catalog );
+	} else {
+		DBGC ( int13, "INT13 drive %02x has no El Torito boot "
+		       "catalog\n", int13->drive );
+	}
+
+	/* Configure drive for no-emulation CD-ROM access */
+	int13->blksize_shift += blksize_shift;
+
+	return 0;
+}
+
+/**
+ * Guess INT 13 hard disk drive geometry
+ *
+ * @v int13		Emulated drive
+ * @v scratch		Scratch area for single-sector reads
+ * @ret heads		Guessed number of heads
+ * @ret sectors		Guessed number of sectors per track
  * @ret rc		Return status code
  *
  * Guesses the drive geometry by inspecting the partition table.
  */
-static int int13_guess_geometry ( struct int13_drive *int13 ) {
-	struct master_boot_record mbr;
+static int int13_guess_geometry_hdd ( struct int13_drive *int13, void *scratch,
+				      unsigned int *heads,
+				      unsigned int *sectors ) {
+	struct master_boot_record *mbr = scratch;
 	struct partition_table_entry *partition;
-	unsigned int guessed_heads = 255;
-	unsigned int guessed_sectors_per_track = 63;
-	unsigned long blocks;
-	unsigned long blocks_per_cyl;
 	unsigned int i;
 	int rc;
 
-	/* Don't even try when the blksize is invalid for C/H/S access */
-	if ( int13->capacity.blksize != INT13_BLKSIZE )
-		return 0;
+	/* Default guess is xx/255/63 */
+	*heads = 255;
+	*sectors = 63;
 
 	/* Read partition table */
-	if ( ( rc = int13_rw ( int13, 0, 1, virt_to_user ( &mbr ),
+	if ( ( rc = int13_rw ( int13, 0, 1, virt_to_user ( mbr ),
 			       block_read ) ) != 0 ) {
-		DBGC ( int13, "INT13 drive %02x could not read partition "
-		       "table to guess geometry: %s\n",
+		DBGC ( int13, "INT13 drive %02x could not read "
+		       "partition table to guess geometry: %s\n",
 		       int13->drive, strerror ( rc ) );
 		return rc;
 	}
 	DBGC2 ( int13, "INT13 drive %02x has MBR:\n", int13->drive );
-	DBGC2_HDA ( int13, 0, &mbr, sizeof ( mbr ) );
+	DBGC2_HDA ( int13, 0, mbr, sizeof ( *mbr ) );
 	DBGC ( int13, "INT13 drive %02x has signature %08x\n",
-	       int13->drive, mbr.signature );
+	       int13->drive, mbr->signature );
 
-	/* Scan through partition table and modify guesses for heads
-	 * and sectors_per_track if we find any used partitions.
+	/* Scan through partition table and modify guesses for
+	 * heads and sectors_per_track if we find any used
+	 * partitions.
 	 */
 	for ( i = 0 ; i < 4 ; i++ ) {
-		partition = &mbr.partitions[i];
+		partition = &mbr->partitions[i];
 		if ( ! partition->type )
 			continue;
-		guessed_heads = ( PART_HEAD ( partition->chs_end ) + 1 );
-		guessed_sectors_per_track = PART_SECTOR ( partition->chs_end );
+		*heads = ( PART_HEAD ( partition->chs_end ) + 1 );
+		*sectors = PART_SECTOR ( partition->chs_end );
 		DBGC ( int13, "INT13 drive %02x guessing C/H/S xx/%d/%d based "
-		       "on partition %d\n", int13->drive, guessed_heads,
-		       guessed_sectors_per_track, ( i + 1 ) );
+		       "on partition %d\n",
+		       int13->drive, *heads, *sectors, ( i + 1 ) );
+	}
+
+	return 0;
+}
+
+/** Recognised floppy disk geometries */
+static const struct int13_fdd_geometry int13_fdd_geometries[] = {
+	INT13_FDD_GEOMETRY ( 40, 1, 8 ),
+	INT13_FDD_GEOMETRY ( 40, 1, 9 ),
+	INT13_FDD_GEOMETRY ( 40, 2, 8 ),
+	INT13_FDD_GEOMETRY ( 40, 1, 9 ),
+	INT13_FDD_GEOMETRY ( 80, 2, 8 ),
+	INT13_FDD_GEOMETRY ( 80, 2, 9 ),
+	INT13_FDD_GEOMETRY ( 80, 2, 15 ),
+	INT13_FDD_GEOMETRY ( 80, 2, 18 ),
+	INT13_FDD_GEOMETRY ( 80, 2, 20 ),
+	INT13_FDD_GEOMETRY ( 80, 2, 21 ),
+	INT13_FDD_GEOMETRY ( 82, 2, 21 ),
+	INT13_FDD_GEOMETRY ( 83, 2, 21 ),
+	INT13_FDD_GEOMETRY ( 80, 2, 22 ),
+	INT13_FDD_GEOMETRY ( 80, 2, 23 ),
+	INT13_FDD_GEOMETRY ( 80, 2, 24 ),
+	INT13_FDD_GEOMETRY ( 80, 2, 36 ),
+	INT13_FDD_GEOMETRY ( 80, 2, 39 ),
+	INT13_FDD_GEOMETRY ( 80, 2, 40 ),
+	INT13_FDD_GEOMETRY ( 80, 2, 44 ),
+	INT13_FDD_GEOMETRY ( 80, 2, 48 ),
+};
+
+/**
+ * Guess INT 13 floppy disk drive geometry
+ *
+ * @v int13		Emulated drive
+ * @ret heads		Guessed number of heads
+ * @ret sectors		Guessed number of sectors per track
+ * @ret rc		Return status code
+ *
+ * Guesses the drive geometry by inspecting the disk size.
+ */
+static int int13_guess_geometry_fdd ( struct int13_drive *int13,
+				      unsigned int *heads,
+				      unsigned int *sectors ) {
+	unsigned int blocks = int13_capacity ( int13 );
+	const struct int13_fdd_geometry *geometry;
+	unsigned int cylinders;
+	unsigned int i;
+
+	/* Look for a match against a known geometry */
+	for ( i = 0 ; i < ( sizeof ( int13_fdd_geometries ) /
+			    sizeof ( int13_fdd_geometries[0] ) ) ; i++ ) {
+		geometry = &int13_fdd_geometries[i];
+		cylinders = INT13_FDD_CYLINDERS ( geometry );
+		*heads = INT13_FDD_HEADS ( geometry );
+		*sectors = INT13_FDD_SECTORS ( geometry );
+		if ( ( cylinders * (*heads) * (*sectors) ) == blocks ) {
+			DBGC ( int13, "INT13 drive %02x guessing C/H/S "
+			       "%d/%d/%d based on size %dK\n", int13->drive,
+			       cylinders, *heads, *sectors, ( blocks / 2 ) );
+			return 0;
+		}
+	}
+
+	/* Otherwise, assume a partial disk image in the most common
+	 * format (1440K, 80/2/18).
+	 */
+	*heads = 2;
+	*sectors = 18;
+	DBGC ( int13, "INT13 drive %02x guessing C/H/S xx/%d/%d based on size "
+	       "%dK\n", int13->drive, *heads, *sectors, ( blocks / 2 ) );
+	return 0;
+}
+
+/**
+ * Guess INT 13 drive geometry
+ *
+ * @v int13		Emulated drive
+ * @v scratch		Scratch area for single-sector reads
+ * @ret rc		Return status code
+ */
+static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) {
+	unsigned int guessed_heads;
+	unsigned int guessed_sectors;
+	unsigned int blocks;
+	unsigned int blocks_per_cyl;
+	int rc;
+
+	/* Don't even try when the blksize is invalid for C/H/S access */
+	if ( int13_blksize ( int13 ) != INT13_BLKSIZE )
+		return 0;
+
+	/* Guess geometry according to drive type */
+	if ( int13_is_fdd ( int13 ) ) {
+		if ( ( rc = int13_guess_geometry_fdd ( int13, &guessed_heads,
+						       &guessed_sectors )) != 0)
+			return rc;
+	} else {
+		if ( ( rc = int13_guess_geometry_hdd ( int13, scratch,
+						       &guessed_heads,
+						       &guessed_sectors )) != 0)
+			return rc;
 	}
 
 	/* Apply guesses if no geometry already specified */
 	if ( ! int13->heads )
 		int13->heads = guessed_heads;
 	if ( ! int13->sectors_per_track )
-		int13->sectors_per_track = guessed_sectors_per_track;
+		int13->sectors_per_track = guessed_sectors;
 	if ( ! int13->cylinders ) {
 		/* Avoid attempting a 64-bit divide on a 32-bit system */
-		blocks = ( ( int13->capacity.blocks <= ULONG_MAX ) ?
-			   int13->capacity.blocks : ULONG_MAX );
+		blocks = int13_capacity32 ( int13 );
 		blocks_per_cyl = ( int13->heads * int13->sectors_per_track );
 		assert ( blocks_per_cyl != 0 );
 		int13->cylinders = ( blocks / blocks_per_cyl );
@@ -441,19 +710,40 @@ static int int13_guess_geometry ( struct int13_drive *int13 ) {
 /**
  * Update BIOS drive count
  */
-static void int13_set_num_drives ( void ) {
+static void int13_sync_num_drives ( void ) {
 	struct int13_drive *int13;
+	uint8_t *counter;
+	uint8_t max_drive;
+	uint8_t required;
 
-	/* Get current drive count */
+	/* Get current drive counts */
+	get_real ( equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
 	get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
+	num_fdds = ( ( equipment_word & 0x0001 ) ?
+		     ( ( ( equipment_word >> 6 ) & 0x3 ) + 1 ) : 0 );
 
 	/* Ensure count is large enough to cover all of our emulated drives */
 	list_for_each_entry ( int13, &int13s, list ) {
-		if ( num_drives <= ( int13->drive & 0x7f ) )
-			num_drives = ( ( int13->drive & 0x7f ) + 1 );
+		counter = ( int13_is_fdd ( int13 ) ? &num_fdds : &num_drives );
+		max_drive = int13->drive;
+		if ( max_drive < int13->natural_drive )
+			max_drive = int13->natural_drive;
+		required = ( ( max_drive & 0x7f ) + 1 );
+		if ( *counter < required ) {
+			*counter = required;
+			DBGC ( int13, "INT13 drive %02x added to drive count: "
+			       "%d HDDs, %d FDDs\n",
+			       int13->drive, num_drives, num_fdds );
+		}
 	}
 
 	/* Update current drive count */
+	equipment_word &= ~( ( 0x3 << 6 ) | 0x0001 );
+	if ( num_fdds ) {
+		equipment_word |= ( 0x0001 |
+				    ( ( ( num_fdds - 1 ) & 0x3 ) << 6 ) );
+	}
+	put_real ( equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
 	put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
 }
 
@@ -461,13 +751,14 @@ static void int13_set_num_drives ( void ) {
  * Check number of drives
  */
 static void int13_check_num_drives ( void ) {
+	uint16_t check_equipment_word;
 	uint8_t check_num_drives;
 
+	get_real ( check_equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD );
 	get_real ( check_num_drives, BDA_SEG, BDA_NUM_DRIVES );
-	if ( check_num_drives != num_drives ) {
-		int13_set_num_drives();
-		DBG ( "INT13 fixing up number of drives from %d to %d\n",
-		      check_num_drives, num_drives );
+	if ( ( check_equipment_word != equipment_word ) ||
+	     ( check_num_drives != num_drives ) ) {
+		int13_sync_num_drives();
 	}
 }
 
@@ -535,20 +826,25 @@ static int int13_rw_sectors ( struct int13_drive *int13,
 	int rc;
 
 	/* Validate blocksize */
-	if ( int13->capacity.blksize != INT13_BLKSIZE ) {
+	if ( int13_blksize ( int13 ) != INT13_BLKSIZE ) {
 		DBGC ( int13, "\nINT 13 drive %02x invalid blocksize (%zd) "
 		       "for non-extended read/write\n",
-		       int13->drive, int13->capacity.blksize );
+		       int13->drive, int13_blksize ( int13 ) );
 		return -INT13_STATUS_INVALID;
 	}
-	
+
 	/* Calculate parameters */
 	cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 2 ) | ix86->regs.ch );
-	assert ( cylinder < int13->cylinders );
 	head = ix86->regs.dh;
-	assert ( head < int13->heads );
 	sector = ( ix86->regs.cl & 0x3f );
-	assert ( ( sector >= 1 ) && ( sector <= int13->sectors_per_track ) );
+	if ( ( cylinder >= int13->cylinders ) ||
+	     ( head >= int13->heads ) ||
+	     ( sector < 1 ) || ( sector > int13->sectors_per_track ) ) {
+		DBGC ( int13, "C/H/S %d/%d/%d out of range for geometry "
+		       "%d/%d/%d\n", cylinder, head, sector, int13->cylinders,
+		       int13->heads, int13->sectors_per_track );
+		return -INT13_STATUS_INVALID;
+	}
 	lba = ( ( ( ( cylinder * int13->heads ) + head )
 		  * int13->sectors_per_track ) + sector - 1 );
 	count = ix86->regs.al;
@@ -625,10 +921,27 @@ static int int13_get_parameters ( struct int13_drive *int13,
 
 	DBGC2 ( int13, "Get drive parameters\n" );
 
+	/* Validate blocksize */
+	if ( int13_blksize ( int13 ) != INT13_BLKSIZE ) {
+		DBGC ( int13, "\nINT 13 drive %02x invalid blocksize (%zd) "
+		       "for non-extended parameters\n",
+		       int13->drive, int13_blksize ( int13 ) );
+		return -INT13_STATUS_INVALID;
+	}
+
+	/* Common parameters */
 	ix86->regs.ch = ( max_cylinder & 0xff );
 	ix86->regs.cl = ( ( ( max_cylinder >> 8 ) << 6 ) | max_sector );
 	ix86->regs.dh = max_head;
-	get_real ( ix86->regs.dl, BDA_SEG, BDA_NUM_DRIVES );
+	ix86->regs.dl = ( int13_is_fdd ( int13 ) ? num_fdds : num_drives );
+
+	/* Floppy-specific parameters */
+	if ( int13_is_fdd ( int13 ) ) {
+		ix86->regs.bl = INT13_FDD_TYPE_1M44;
+		ix86->segs.es = rm_ds;
+		ix86->regs.di = __from_data16 ( &int13_fdd_params );
+	}
+
 	return 0;
 }
 
@@ -645,11 +958,15 @@ static int int13_get_disk_type ( struct int13_drive *int13,
 	uint32_t blocks;
 
 	DBGC2 ( int13, "Get disk type\n" );
-	blocks = ( ( int13->capacity.blocks <= 0xffffffffUL ) ?
-		   int13->capacity.blocks : 0xffffffffUL );
-	ix86->regs.cx = ( blocks >> 16 );
-	ix86->regs.dx = ( blocks & 0xffff );
-	return INT13_DISK_TYPE_HDD;
+
+	if ( int13_is_fdd ( int13 ) ) {
+		return INT13_DISK_TYPE_FDD;
+	} else {
+		blocks = int13_capacity32 ( int13 );
+		ix86->regs.cx = ( blocks >> 16 );
+		ix86->regs.dx = ( blocks & 0xffff );
+		return INT13_DISK_TYPE_HDD;
+	}
 }
 
 /**
@@ -698,6 +1015,13 @@ static int int13_extended_rw ( struct int13_drive *int13,
 	userptr_t buffer;
 	int rc;
 
+	/* Extended reads are not allowed on floppy drives.
+	 * ELTORITO.SYS seems to assume that we are really a CD-ROM if
+	 * we support extended reads for a floppy drive.
+	 */
+	if ( int13_is_fdd ( int13 ) )
+		return -INT13_STATUS_INVALID;
+
 	/* Get buffer size */
 	get_real ( bufsize, ix86->segs.ds,
 		   ( ix86->regs.si + offsetof ( typeof ( addr ), bufsize ) ) );
@@ -916,14 +1240,14 @@ static int int13_get_extended_parameters ( struct int13_drive *int13,
 	memset ( &params, 0, sizeof ( params ) );
 	params.flags = INT13_FL_DMA_TRANSPARENT;
 	if ( ( int13->cylinders < 1024 ) &&
-	     ( int13->capacity.blocks <= INT13_MAX_CHS_SECTORS ) ) {
+	     ( int13_capacity ( int13 ) <= INT13_MAX_CHS_SECTORS ) ) {
 		params.flags |= INT13_FL_CHS_VALID;
 	}
 	params.cylinders = int13->cylinders;
 	params.heads = int13->heads;
 	params.sectors_per_track = int13->sectors_per_track;
-	params.sectors = int13->capacity.blocks;
-	params.sector_size = int13->capacity.blksize;
+	params.sectors = int13_capacity ( int13 );
+	params.sector_size = int13_blksize ( int13 );
 	memset ( &params.dpte, 0xff, sizeof ( params.dpte ) );
 	if ( ( rc = int13_device_path_info ( int13, &params.dpi ) ) != 0 ) {
 		DBGC ( int13, "INT13 drive %02x could not provide device "
@@ -958,6 +1282,77 @@ static int int13_get_extended_parameters ( struct int13_drive *int13,
 	return 0;
 }
 
+/**
+ * INT 13, 4b - Get status or terminate CD-ROM emulation
+ *
+ * @v int13		Emulated drive
+ * @v ds:si		Specification packet
+ * @ret status		Status code
+ */
+static int int13_cdrom_status_terminate ( struct int13_drive *int13,
+					  struct i386_all_regs *ix86 ) {
+	struct int13_cdrom_specification specification;
+
+	DBGC2 ( int13, "Get CD-ROM emulation status to %04x:%04x%s\n",
+		ix86->segs.ds, ix86->regs.si,
+		( ix86->regs.al ? "" : " and terminate" ) );
+
+	/* Fail if we are not a CD-ROM */
+	if ( ! int13->is_cdrom ) {
+		DBGC ( int13, "INT13 drive %02x is not a CD-ROM\n",
+		       int13->drive );
+		return -INT13_STATUS_INVALID;
+	}
+
+	/* Build specification packet */
+	memset ( &specification, 0, sizeof ( specification ) );
+	specification.size = sizeof ( specification );
+	specification.drive = int13->drive;
+
+	/* Return specification packet */
+	copy_to_real ( ix86->segs.ds, ix86->regs.si, &specification,
+		       sizeof ( specification ) );
+
+	return 0;
+}
+
+
+/**
+ * INT 13, 4d - Read CD-ROM boot catalog
+ *
+ * @v int13		Emulated drive
+ * @v ds:si		Command packet
+ * @ret status		Status code
+ */
+static int int13_cdrom_read_boot_catalog ( struct int13_drive *int13,
+					   struct i386_all_regs *ix86 ) {
+	struct int13_cdrom_boot_catalog_command command;
+	int rc;
+
+	/* Read parameters from command packet */
+	copy_from_real ( &command, ix86->segs.ds, ix86->regs.si,
+			 sizeof ( command ) );
+	DBGC2 ( int13, "Read CD-ROM boot catalog to %08x\n", command.buffer );
+
+	/* Fail if we have no boot catalog */
+	if ( ! int13->boot_catalog ) {
+		DBGC ( int13, "INT13 drive %02x has no boot catalog\n",
+		       int13->drive );
+		return -INT13_STATUS_INVALID;
+	}
+
+	/* Read from boot catalog */
+	if ( ( rc = int13_rw ( int13, ( int13->boot_catalog + command.start ),
+			       command.count, phys_to_user ( command.buffer ),
+			       block_read ) ) != 0 ) {
+		DBGC ( int13, "INT13 drive %02x could not read boot catalog: "
+		       "%s\n", int13->drive, strerror ( rc ) );
+		return -INT13_STATUS_READ_ERROR;
+	}
+
+	return 0;
+}
+
 /**
  * INT 13 handler
  *
@@ -981,12 +1376,17 @@ static __asmcall void int13 ( struct i386_all_regs *ix86 ) {
 					bios_drive, int13->drive );
 				ix86->regs.dl = int13->drive;
 				return;
+			} else if ( ( ( bios_drive & 0x7f ) == 0x7f ) &&
+				    ( command == INT13_CDROM_STATUS_TERMINATE )
+				    && int13->is_cdrom ) {
+				/* Catch non-drive-specific CD-ROM calls */
+			} else {
+				continue;
 			}
-			continue;
 		}
 		
 		DBGC2 ( int13, "INT13,%02x (%02x): ",
-			ix86->regs.ah, int13->drive );
+			ix86->regs.ah, bios_drive );
 
 		switch ( command ) {
 		case INT13_RESET:
@@ -1025,6 +1425,12 @@ static __asmcall void int13 ( struct i386_all_regs *ix86 ) {
 		case INT13_GET_EXTENDED_PARAMETERS:
 			status = int13_get_extended_parameters ( int13, ix86 );
 			break;
+		case INT13_CDROM_STATUS_TERMINATE:
+			status = int13_cdrom_status_terminate ( int13, ix86 );
+			break;
+		case INT13_CDROM_READ_BOOT_CATALOG:
+			status = int13_cdrom_read_boot_catalog ( int13, ix86 );
+			break;
 		default:
 			DBGC2 ( int13, "*** Unrecognised INT13 ***\n" );
 			status = -INT13_STATUS_INVALID;
@@ -1083,26 +1489,28 @@ static void int13_hook_vector ( void ) {
 			     "popw 6(%%bp)\n\t"
 			     /* Fix up %dl:
 			      *
-			      * INT 13,15 : do nothing
+			      * INT 13,15 : do nothing if hard disk
 			      * INT 13,08 : load with number of drives
 			      * all others: restore original value
 			      */
 			     "cmpb $0x15, -1(%%bp)\n\t"
-			     "je 2f\n\t"
+			     "jne 2f\n\t"
+			     "testb $0x80, -4(%%bp)\n\t"
+			     "jnz 3f\n\t"
+			     "\n2:\n\t"
 			     "movb -4(%%bp), %%dl\n\t"
 			     "cmpb $0x08, -1(%%bp)\n\t"
-			     "jne 2f\n\t"
-			     "pushw %%ds\n\t"
-			     "pushw %1\n\t"
-			     "popw %%ds\n\t"
-			     "movb %c2, %%dl\n\t"
-			     "popw %%ds\n\t"
+			     "jne 3f\n\t"
+			     "testb $0x80, %%dl\n\t"
+			     "movb %%cs:num_drives, %%dl\n\t"
+			     "jnz 3f\n\t"
+			     "movb %%cs:num_fdds, %%dl\n\t"
 			     /* Return */
-			     "\n2:\n\t"
+			     "\n3:\n\t"
 			     "movw %%bp, %%sp\n\t"
 			     "popw %%bp\n\t"
 			     "iret\n\t" )
-	       : : "i" ( int13 ), "i" ( BDA_SEG ), "i" ( BDA_NUM_DRIVES ) );
+	       : : "i" ( int13 ) );
 
 	hook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper,
 			      &int13_vector );
@@ -1116,6 +1524,20 @@ static void int13_unhook_vector ( void ) {
 				&int13_vector );
 }
 
+/**
+ * Check INT13 emulated drive flow control window
+ *
+ * @v int13		Emulated drive
+ */
+static size_t int13_block_window ( struct int13_drive *int13 __unused ) {
+
+	/* We are never ready to receive data via this interface.
+	 * This prevents objects that support both block and stream
+	 * interfaces from attempting to send us stream data.
+	 */
+	return 0;
+}
+
 /**
  * Handle INT 13 emulated drive underlying block device closing
  *
@@ -1140,6 +1562,7 @@ static void int13_block_close ( struct int13_drive *int13, int rc ) {
 
 /** INT 13 drive interface operations */
 static struct interface_operation int13_block_op[] = {
+	INTF_OP ( xfer_window, struct int13_drive *, int13_block_window ),
 	INTF_OP ( intf_close, struct int13_drive *, int13_block_close ),
 };
 
@@ -1164,24 +1587,21 @@ static void int13_free ( struct refcnt *refcnt ) {
  * Hook INT 13 emulated drive
  *
  * @v uri		URI
- * @v drive		Requested drive number
- * @ret drive		Assigned drive number, or negative error
+ * @v drive		Drive number
+ * @ret rc		Return status code
  *
  * Registers the drive with the INT 13 emulation subsystem, and hooks
  * the INT 13 interrupt vector (if not already hooked).
  */
 static int int13_hook ( struct uri *uri, unsigned int drive ) {
 	struct int13_drive *int13;
-	uint8_t num_drives;
 	unsigned int natural_drive;
+	void *scratch;
 	int rc;
 
-	/* Calculate drive number */
-	get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES );
-	natural_drive = ( num_drives | 0x80 );
-	if ( drive == INT13_USE_NATURAL_DRIVE )
-		drive = natural_drive;
-	drive |= 0x80;
+	/* Calculate natural drive number */
+	int13_sync_num_drives();
+	natural_drive = ( ( drive & 0x80 ) ? ( num_drives | 0x80 ) : num_fdds );
 
 	/* Check that drive number is not in use */
 	list_for_each_entry ( int13, &int13s, list ) {
@@ -1209,10 +1629,19 @@ static int int13_hook ( struct uri *uri, unsigned int drive ) {
 
 	/* Read device capacity */
 	if ( ( rc = int13_read_capacity ( int13 ) ) != 0 )
-		return rc;
+		goto err_read_capacity;
+
+	/* Allocate scratch area */
+	scratch = malloc ( int13_blksize ( int13 ) );
+	if ( ! scratch )
+		goto err_alloc_scratch;
+
+	/* Parse parameters, if present */
+	if ( ( rc = int13_parse_iso9660 ( int13, scratch ) ) != 0 )
+		goto err_parse_iso9660;
 
 	/* Give drive a default geometry */
-	if ( ( rc = int13_guess_geometry ( int13 ) ) != 0 )
+	if ( ( rc = int13_guess_geometry ( int13, scratch ) ) != 0 )
 		goto err_guess_geometry;
 
 	DBGC ( int13, "INT13 drive %02x (naturally %02x) registered with C/H/S "
@@ -1229,11 +1658,16 @@ static int int13_hook ( struct uri *uri, unsigned int drive ) {
 	list_add ( &int13->list, &int13s );
 
 	/* Update BIOS drive count */
-	int13_set_num_drives();
+	int13_sync_num_drives();
 
-	return int13->drive;
+	free ( scratch );
+	return 0;
 
  err_guess_geometry:
+ err_parse_iso9660:
+	free ( scratch );
+ err_alloc_scratch:
+ err_read_capacity:
  err_reopen_block:
 	intf_shutdown ( &int13->block, rc );
 	ref_put ( &int13->refcnt );
@@ -1300,52 +1734,171 @@ static void int13_unhook ( unsigned int drive ) {
 }
 
 /**
- * Attempt to boot from an INT 13 drive
+ * Load and verify master boot record from INT 13 drive
  *
  * @v drive		Drive number
+ * @v address		Boot code address to fill in
  * @ret rc		Return status code
- *
- * This boots from the specified INT 13 drive by loading the Master
- * Boot Record to 0000:7c00 and jumping to it.  INT 18 is hooked to
- * capture an attempt by the MBR to boot the next device.  (This is
- * the closest thing to a return path from an MBR).
- *
- * Note that this function can never return success, by definition.
  */
-static int int13_boot ( unsigned int drive ) {
-	struct memory_map memmap;
-	int status, signature;
-	int discard_c, discard_d;
-	int rc;
-
-	DBG ( "INT13 drive %02x booting\n", drive );
-
-	/* Use INT 13 to read the boot sector */
+static int int13_load_mbr ( unsigned int drive, struct segoff *address ) {
+	uint8_t status;
+	int discard_b, discard_c, discard_d;
+	uint16_t magic;
+
+	/* Use INT 13, 02 to read the MBR */
+	address->segment = 0;
+	address->offset = 0x7c00;
 	__asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t"
-					   "pushw $0\n\t"
+					   "pushl %%ebx\n\t"
+					   "popw %%bx\n\t"
 					   "popw %%es\n\t"
 					   "stc\n\t"
 					   "sti\n\t"
 					   "int $0x13\n\t"
 					   "sti\n\t" /* BIOS bugs */
 					   "jc 1f\n\t"
-					   "xorl %%eax, %%eax\n\t"
+					   "xorw %%ax, %%ax\n\t"
 					   "\n1:\n\t"
-					   "movzwl %%es:0x7dfe, %%ebx\n\t"
 					   "popw %%es\n\t" )
-			       : "=a" ( status ), "=b" ( signature ),
+			       : "=a" ( status ), "=b" ( discard_b ),
 				 "=c" ( discard_c ), "=d" ( discard_d )
-			       : "a" ( 0x0201 ), "b" ( 0x7c00 ),
+			       : "a" ( 0x0201 ), "b" ( *address ),
 				 "c" ( 1 ), "d" ( drive ) );
-	if ( status )
+	if ( status ) {
+		DBG ( "INT13 drive %02x could not read MBR (status %02x)\n",
+		      drive, status );
 		return -EIO;
+	}
+
+	/* Check magic signature */
+	get_real ( magic, address->segment,
+		   ( address->offset +
+		     offsetof ( struct master_boot_record, magic ) ) );
+	if ( magic != INT13_MBR_MAGIC ) {
+		DBG ( "INT13 drive %02x does not contain a valid MBR\n",
+		      drive );
+		return -ENOEXEC;
+	}
+
+	return 0;
+}
+
+/** El Torito boot catalog command packet */
+static struct int13_cdrom_boot_catalog_command __data16 ( eltorito_cmd ) = {
+	.size = sizeof ( struct int13_cdrom_boot_catalog_command ),
+	.count = 1,
+	.buffer = 0x7c00,
+	.start = 0,
+};
+#define eltorito_cmd __use_data16 ( eltorito_cmd )
 
-	/* Check signature is correct */
-	if ( signature != be16_to_cpu ( 0x55aa ) ) {
-		DBG ( "INT13 drive %02x invalid disk signature %#04x (should "
-		      "be 0x55aa)\n", drive, cpu_to_be16 ( signature ) );
+/** El Torito disk address packet */
+static struct int13_disk_address __bss16 ( eltorito_address );
+#define eltorito_address __use_data16 ( eltorito_address )
+
+/**
+ * Load and verify El Torito boot record from INT 13 drive
+ *
+ * @v drive		Drive number
+ * @v address		Boot code address to fill in
+ * @ret rc		Return status code
+ */
+static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
+	struct {
+		struct eltorito_validation_entry valid;
+		struct eltorito_boot_entry boot;
+	} __attribute__ (( packed )) catalog;
+	uint8_t status;
+
+	/* Use INT 13, 4d to read the boot catalog */
+	__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
+					   "sti\n\t"
+					   "int $0x13\n\t"
+					   "sti\n\t" /* BIOS bugs */
+					   "jc 1f\n\t"
+					   "xorw %%ax, %%ax\n\t"
+					   "\n1:\n\t" )
+			       : "=a" ( status )
+			       : "a" ( 0x4d00 ), "d" ( drive ),
+				 "S" ( __from_data16 ( &eltorito_cmd ) ) );
+	if ( status ) {
+		DBG ( "INT13 drive %02x could not read El Torito boot catalog "
+		      "(status %02x)\n", drive, status );
+		return -EIO;
+	}
+	copy_from_user ( &catalog, phys_to_user ( eltorito_cmd.buffer ), 0,
+			 sizeof ( catalog ) );
+
+	/* Sanity checks */
+	if ( catalog.valid.platform_id != ELTORITO_PLATFORM_X86 ) {
+		DBG ( "INT13 drive %02x El Torito specifies unknown platform "
+		      "%02x\n", drive, catalog.valid.platform_id );
+		return -ENOEXEC;
+	}
+	if ( catalog.boot.indicator != ELTORITO_BOOTABLE ) {
+		DBG ( "INT13 drive %02x El Torito is not bootable\n", drive );
 		return -ENOEXEC;
 	}
+	if ( catalog.boot.media_type != ELTORITO_NO_EMULATION ) {
+		DBG ( "INT13 drive %02x El Torito requires emulation "
+		       "type %02x\n", drive, catalog.boot.media_type );
+		return -ENOTSUP;
+	}
+	DBG ( "INT13 drive %02x El Torito boot image at LBA %08x (count %d)\n",
+	      drive, catalog.boot.start, catalog.boot.length );
+	address->segment = ( catalog.boot.load_segment ?
+			     catalog.boot.load_segment : 0x7c0 );
+	address->offset = 0;
+	DBG ( "INT13 drive %02x El Torito boot image loads at %04x:%04x\n",
+	      drive, address->segment, address->offset );
+
+	/* Use INT 13, 42 to read the boot image */
+	eltorito_address.bufsize =
+		offsetof ( typeof ( eltorito_address ), buffer_phys );
+	eltorito_address.count = catalog.boot.length;
+	eltorito_address.buffer = *address;
+	eltorito_address.lba = catalog.boot.start;
+	__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
+					   "sti\n\t"
+					   "int $0x13\n\t"
+					   "sti\n\t" /* BIOS bugs */
+					   "jc 1f\n\t"
+					   "xorw %%ax, %%ax\n\t"
+					   "\n1:\n\t" )
+			       : "=a" ( status )
+			       : "a" ( 0x4200 ), "d" ( drive ),
+				 "S" ( __from_data16 ( &eltorito_address ) ) );
+	if ( status ) {
+		DBG ( "INT13 drive %02x could not read El Torito boot image "
+		      "(status %02x)\n", drive, status );
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * Attempt to boot from an INT 13 drive
+ *
+ * @v drive		Drive number
+ * @ret rc		Return status code
+ *
+ * This boots from the specified INT 13 drive by loading the Master
+ * Boot Record to 0000:7c00 and jumping to it.  INT 18 is hooked to
+ * capture an attempt by the MBR to boot the next device.  (This is
+ * the closest thing to a return path from an MBR).
+ *
+ * Note that this function can never return success, by definition.
+ */
+static int int13_boot ( unsigned int drive ) {
+	struct memory_map memmap;
+	struct segoff address;
+	int rc;
+
+	/* Look for a usable boot sector */
+	if ( ( ( rc = int13_load_mbr ( drive, &address ) ) != 0 ) &&
+	     ( ( rc = int13_load_eltorito ( drive, &address ) ) != 0 ) )
+		return rc;
 
 	/* Dump out memory map prior to boot, if memmap debugging is
 	 * enabled.  Not required for program flow, but we have so
@@ -1355,7 +1908,8 @@ static int int13_boot ( unsigned int drive ) {
 	get_memmap ( &memmap );
 
 	/* Jump to boot sector */
-	if ( ( rc = call_bootsector ( 0x0, 0x7c00, drive ) ) != 0 ) {
+	if ( ( rc = call_bootsector ( address.segment, address.offset,
+				      drive ) ) != 0 ) {
 		DBG ( "INT13 drive %02x boot returned: %s\n",
 		      drive, strerror ( rc ) );
 		return rc;
@@ -1428,6 +1982,7 @@ static int int13_describe ( unsigned int drive ) {
 	return 0;
 }
 
+PROVIDE_SANBOOT_INLINE ( pcbios, san_default_drive );
 PROVIDE_SANBOOT ( pcbios, san_hook, int13_hook );
 PROVIDE_SANBOOT ( pcbios, san_unhook, int13_unhook );
 PROVIDE_SANBOOT ( pcbios, san_boot, int13_boot );
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c b/roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c
index 16736e194b4d91cf5ba2cd4a886c..c382e3c369ca46e796263b8a73bc 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/memtop_umalloc.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -30,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/uaccess.h>
 #include <ipxe/hidemem.h>
 #include <ipxe/io.h>
+#include <ipxe/memblock.h>
 #include <ipxe/umalloc.h>
 
 /** Alignment of external allocated memory */
@@ -52,56 +54,20 @@ static userptr_t top = UNULL;
 /** Bottom of heap (current lowest allocated block) */
 static userptr_t bottom = UNULL;
 
+/** Remaining space on heap */
+static size_t heap_size;
+
 /**
  * Initialise external heap
  *
- * @ret rc		Return status code
  */
-static int init_eheap ( void ) {
-	struct memory_map memmap;
-	unsigned long heap_size = 0;
-	unsigned int i;
-
-	DBG ( "Allocating external heap\n" );
-
-	get_memmap ( &memmap );
-	for ( i = 0 ; i < memmap.count ; i++ ) {
-		struct memory_region *region = &memmap.regions[i];
-		unsigned long r_start, r_end;
-		unsigned long r_size;
-
-		DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
-
-		/* Truncate block to 4GB */
-		if ( region->start > UINT_MAX ) {
-			DBG ( "...starts after 4GB\n" );
-			continue;
-		}
-		r_start = region->start;
-		if ( region->end > UINT_MAX ) {
-			DBG ( "...end truncated to 4GB\n" );
-			r_end = 0; /* =4GB, given the wraparound */
-		} else {
-			r_end = region->end;
-		}
-
-		/* Use largest block */
-		r_size = ( r_end - r_start );
-		if ( r_size > heap_size ) {
-			DBG ( "...new best block found\n" );
-			top = bottom = phys_to_user ( r_end );
-			heap_size = r_size;
-		}
-	}
+static void init_eheap ( void ) {
+	userptr_t base;
 
-	if ( ! heap_size ) {
-		DBG ( "No external heap available\n" );
-		return -ENOMEM;
-	}
-
-	DBG ( "External heap grows downwards from %lx\n",
-	      user_to_phys ( top, 0 ) );
-	return 0;
+	heap_size = largest_memblock ( &base );
+	bottom = top = userptr_add ( base, heap_size );
+	DBG ( "External heap grows downwards from %lx (size %zx)\n",
+	      user_to_phys ( top, 0 ), heap_size );
 }
 
 /**
@@ -110,6 +76,7 @@ static int init_eheap ( void ) {
  */
 static void ecollect_free ( void ) {
 	struct external_memory extmem;
+	size_t len;
 
 	/* Walk the free list and collect empty blocks */
 	while ( bottom != top ) {
@@ -119,8 +86,9 @@ static void ecollect_free ( void ) {
 			break;
 		DBG ( "EXTMEM freeing [%lx,%lx)\n", user_to_phys ( bottom, 0 ),
 		      user_to_phys ( bottom, extmem.size ) );
-		bottom = userptr_add ( bottom,
-				       ( extmem.size + sizeof ( extmem ) ) );
+		len = ( extmem.size + sizeof ( extmem ) );
+		bottom = userptr_add ( bottom, len );
+		heap_size += len;
 	}
 }
 
@@ -138,13 +106,10 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
 	struct external_memory extmem;
 	userptr_t new = ptr;
 	size_t align;
-	int rc;
 
-	/* Initialise external memory allocator if necessary */
-	if ( bottom == top ) {
-		if ( ( rc = init_eheap() ) != 0 )
-			return UNULL;
-	}
+	/* (Re)initialise external memory allocator if necessary */
+	if ( bottom == top )
+		init_eheap();
 
 	/* Get block properties into extmem */
 	if ( ptr && ( ptr != UNOWHERE ) ) {
@@ -153,7 +118,12 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
 				 sizeof ( extmem ) );
 	} else {
 		/* Create a zero-length block */
+		if ( heap_size < sizeof ( extmem ) ) {
+			DBG ( "EXTMEM out of space\n" );
+			return UNULL;
+		}
 		ptr = bottom = userptr_add ( bottom, -sizeof ( extmem ) );
+		heap_size -= sizeof ( extmem );
 		DBG ( "EXTMEM allocating [%lx,%lx)\n",
 		      user_to_phys ( ptr, 0 ), user_to_phys ( ptr, 0 ) );
 		extmem.size = 0;
@@ -163,6 +133,10 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
 	/* Expand/shrink block if possible */
 	if ( ptr == bottom ) {
 		/* Update block */
+		if ( new_size > ( heap_size - extmem.size ) ) {
+			DBG ( "EXTMEM out of space\n" );
+			return UNULL;
+		}
 		new = userptr_add ( ptr, - ( new_size - extmem.size ) );
 		align = ( user_to_phys ( new, 0 ) & ( EM_ALIGN - 1 ) );
 		new_size += align;
@@ -174,8 +148,9 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
 		      user_to_phys ( new, new_size ));
 		memmove_user ( new, 0, ptr, 0, ( ( extmem.size < new_size ) ?
 						 extmem.size : new_size ) );
-		extmem.size = new_size;
 		bottom = new;
+		heap_size -= ( new_size - extmem.size );
+		extmem.size = new_size;
 	} else {
 		/* Cannot expand; can only pretend to shrink */
 		if ( new_size > extmem.size ) {
@@ -193,7 +168,8 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
 
 	/* Collect any free blocks and update hidden memory region */
 	ecollect_free();
-	hide_umalloc ( user_to_phys ( bottom, -sizeof ( extmem ) ),
+	hide_umalloc ( user_to_phys ( bottom, ( ( bottom == top ) ?
+						0 : -sizeof ( extmem ) ) ),
 		       user_to_phys ( top, 0 ) );
 
 	return ( new_size ? new : UNOWHERE );
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c b/roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c
index 511ec6232d8a94925ed595f0d6c7..61873039feb2da79cd1d8e9332b7 100644
--- a/roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/pcibios.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/rtc_entropy.c b/roms/ipxe/src/arch/i386/interface/pcbios/rtc_entropy.c
new file mode 100644
index 0000000000000000000000000000000000000000..fad421c2ab357f7427bb4eeceaa3b0d3da79a812
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/rtc_entropy.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * RTC-based entropy source
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <biosint.h>
+#include <pic8259.h>
+#include <rtc.h>
+#include <ipxe/entropy.h>
+
+/** RTC "interrupt triggered" flag */
+static uint8_t __text16 ( rtc_flag );
+#define rtc_flag __use_text16 ( rtc_flag )
+
+/** RTC interrupt handler */
+extern void rtc_isr ( void );
+
+/** Previous RTC interrupt handler */
+static struct segoff rtc_old_handler;
+
+/**
+ * Hook RTC interrupt handler
+ *
+ */
+static void rtc_hook_isr ( void ) {
+
+	/* RTC interrupt handler */
+	__asm__ __volatile__ (
+		TEXT16_CODE ( "\nrtc_isr:\n\t"
+			      /* Preserve registers */
+			      "pushw %%ax\n\t"
+			      /* Set "interrupt triggered" flag */
+			      "cs movb $0x01, %c0\n\t"
+			      /* Read RTC status register C to
+			       * acknowledge interrupt
+			       */
+			      "movb %3, %%al\n\t"
+			      "outb %%al, %1\n\t"
+			      "inb %2\n\t"
+			      /* Send EOI */
+			      "movb $0x20, %%al\n\t"
+			      "outb %%al, $0xa0\n\t"
+			      "outb %%al, $0x20\n\t"
+			      /* Restore registers and return */
+			      "popw %%ax\n\t"
+			      "iret\n\t" )
+		:
+		: "p" ( __from_text16 ( &rtc_flag ) ),
+		  "i" ( CMOS_ADDRESS ), "i" ( CMOS_DATA ),
+		  "i" ( RTC_STATUS_C ) );
+
+	hook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr,
+			      &rtc_old_handler );
+}
+
+/**
+ * Unhook RTC interrupt handler
+ *
+ */
+static void rtc_unhook_isr ( void ) {
+	int rc;
+
+	rc = unhook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr,
+				     &rtc_old_handler );
+	assert ( rc == 0 ); /* Should always be able to unhook */
+}
+
+/**
+ * Enable RTC interrupts
+ *
+ */
+static void rtc_enable_int ( void ) {
+	uint8_t status_b;
+
+	/* Set Periodic Interrupt Enable bit in status register B */
+	outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
+	status_b = inb ( CMOS_DATA );
+	outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
+	outb ( ( status_b | RTC_STATUS_B_PIE ), CMOS_DATA );
+
+	/* Re-enable NMI and reset to default address */
+	outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS );
+	inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
+}
+
+/**
+ * Disable RTC interrupts
+ *
+ */
+static void rtc_disable_int ( void ) {
+	uint8_t status_b;
+
+	/* Clear Periodic Interrupt Enable bit in status register B */
+	outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
+	status_b = inb ( CMOS_DATA );
+	outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
+	outb ( ( status_b & ~RTC_STATUS_B_PIE ), CMOS_DATA );
+
+	/* Re-enable NMI and reset to default address */
+	outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS );
+	inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
+}
+
+/**
+ * Enable entropy gathering
+ *
+ * @ret rc		Return status code
+ */
+static int rtc_entropy_enable ( void ) {
+
+	rtc_hook_isr();
+	enable_irq ( RTC_IRQ );
+	rtc_enable_int();
+
+	return 0;
+}
+
+/**
+ * Disable entropy gathering
+ *
+ */
+static void rtc_entropy_disable ( void ) {
+
+	rtc_disable_int();
+	disable_irq ( RTC_IRQ );
+	rtc_unhook_isr();
+}
+
+/**
+ * Measure a single RTC tick
+ *
+ * @ret delta		Length of RTC tick (in TSC units)
+ */
+uint8_t rtc_sample ( void ) {
+	uint32_t before;
+	uint32_t after;
+	uint32_t temp;
+
+	__asm__ __volatile__ (
+		REAL_CODE ( /* Enable interrupts */
+			    "sti\n\t"
+			    /* Wait for RTC interrupt */
+			    "cs movb %b2, %c4\n\t"
+			    "\n1:\n\t"
+			    "cs xchgb %b2, %c4\n\t" /* Serialize */
+			    "testb %b2, %b2\n\t"
+			    "jz 1b\n\t"
+			    /* Read "before" TSC */
+			    "rdtsc\n\t"
+			    /* Store "before" TSC on stack */
+			    "pushl %0\n\t"
+			    /* Wait for another RTC interrupt */
+			    "xorb %b2, %b2\n\t"
+			    "cs movb %b2, %c4\n\t"
+			    "\n1:\n\t"
+			    "cs xchgb %b2, %c4\n\t" /* Serialize */
+			    "testb %b2, %b2\n\t"
+			    "jz 1b\n\t"
+			    /* Read "after" TSC */
+			    "rdtsc\n\t"
+			    /* Retrieve "before" TSC on stack */
+			    "popl %1\n\t"
+			    /* Disable interrupts */
+			    "cli\n\t"
+			    )
+		: "=a" ( after ), "=d" ( before ), "=q" ( temp )
+		: "2" ( 0 ), "p" ( __from_text16 ( &rtc_flag ) ) );
+
+	return ( after - before );
+}
+
+PROVIDE_ENTROPY_INLINE ( rtc, min_entropy_per_sample );
+PROVIDE_ENTROPY ( rtc, entropy_enable, rtc_entropy_enable );
+PROVIDE_ENTROPY ( rtc, entropy_disable, rtc_entropy_disable );
+PROVIDE_ENTROPY_INLINE ( rtc, get_noise );
diff --git a/roms/ipxe/src/arch/i386/interface/pcbios/rtc_time.c b/roms/ipxe/src/arch/i386/interface/pcbios/rtc_time.c
new file mode 100644
index 0000000000000000000000000000000000000000..67041d4ca111b4f93d2ff6d809f47bf59fb1a56c
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/interface/pcbios/rtc_time.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * RTC-based time source
+ *
+ */
+
+#include <stdint.h>
+#include <time.h>
+#include <rtc.h>
+#include <ipxe/time.h>
+
+/**
+ * Read RTC register
+ *
+ * @v address		Register address
+ * @ret data		Data
+ */
+static unsigned int rtc_readb ( int address ) {
+	outb ( address, CMOS_ADDRESS );
+	return inb ( CMOS_DATA );
+}
+
+/**
+ * Check if RTC update is in progress
+ *
+ * @ret is_busy		RTC update is in progress
+ */
+static int rtc_is_busy ( void ) {
+	return ( rtc_readb ( RTC_STATUS_A ) & RTC_STATUS_A_UPDATE_IN_PROGRESS );
+}
+
+/**
+ * Read RTC BCD register
+ *
+ * @v address		Register address
+ * @ret value		Value
+ */
+static unsigned int rtc_readb_bcd ( int address ) {
+	unsigned int bcd;
+
+	bcd = rtc_readb ( address );
+	return ( bcd - ( 6 * ( bcd >> 4 ) ) );
+}
+
+/**
+ * Read RTC time
+ *
+ * @ret time		Time, in seconds
+ */
+static time_t rtc_read_time ( void ) {
+	unsigned int status_b;
+	int is_binary;
+	int is_24hour;
+	unsigned int ( * read_component ) ( int address );
+	struct tm tm;
+	int is_pm;
+	unsigned int hour;
+	time_t time;
+
+	/* Wait for any in-progress update to complete */
+	while ( rtc_is_busy() ) {}
+
+	/* Determine RTC mode */
+	status_b = rtc_readb ( RTC_STATUS_B );
+	is_binary = ( status_b & RTC_STATUS_B_BINARY );
+	is_24hour = ( status_b & RTC_STATUS_B_24_HOUR );
+	read_component = ( is_binary ? rtc_readb : rtc_readb_bcd );
+
+	/* Read time values */
+	tm.tm_sec = read_component ( RTC_SEC );
+	tm.tm_min = read_component ( RTC_MIN );
+	hour = read_component ( RTC_HOUR );
+	if ( ! is_24hour ) {
+		is_pm = ( hour >= 80 );
+		hour = ( ( ( ( hour & 0x7f ) % 80 ) % 12 ) +
+			 ( is_pm ? 12 : 0 ) );
+	}
+	tm.tm_hour = hour;
+	tm.tm_mday = read_component ( RTC_MDAY );
+	tm.tm_mon = ( read_component ( RTC_MON ) - 1 );
+	tm.tm_year = ( read_component ( RTC_YEAR ) +
+		       100 /* Assume we are in the 21st century, since
+			    * this code was written in 2012 */ );
+
+	DBGC ( RTC_STATUS_A, "RTCTIME is %04d-%02d-%02d %02d:%02d:%02d "
+	       "(%s,%d-hour)\n", ( tm.tm_year + 1900 ), ( tm.tm_mon + 1 ),
+	       tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
+	       ( is_binary ? "binary" : "BCD" ), ( is_24hour ? 24 : 12 ) );
+
+	/* Convert to seconds since the Epoch */
+	time = mktime ( &tm );
+
+	return time;
+}
+
+/**
+ * Get current time in seconds
+ *
+ * @ret time		Time, in seconds
+ */
+static time_t rtc_now ( void ) {
+	time_t time = 0;
+	time_t last_time;
+
+	/* Read time until we get two matching values in a row, in
+	 * case we end up reading a corrupted value in the middle of
+	 * an update.
+	 */
+	do {
+		last_time = time;
+		time = rtc_read_time();
+	} while ( time != last_time );
+
+	return time;
+}
+
+PROVIDE_TIME ( rtc, time_now, rtc_now );
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c
index f320800068b8b263a34499a537c1..b8e73a0615230c99c3faac12599a 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_call.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -41,73 +42,6 @@ extern void pxe_int_1a ( void );
 /** INT 1A hooked flag */
 static int int_1a_hooked = 0;
 
-/** A function pointer to hold any PXE API call
- *
- * Used by pxe_api_call() to avoid large swathes of duplicated code.
- */
-union pxenv_call {
-	PXENV_EXIT_t ( * any ) ( union u_PXENV_ANY * );
-	PXENV_EXIT_t ( * unknown ) ( struct s_PXENV_UNKNOWN * );
-	PXENV_EXIT_t ( * unload_stack ) ( struct s_PXENV_UNLOAD_STACK * );
-	PXENV_EXIT_t ( * get_cached_info )
-			( struct s_PXENV_GET_CACHED_INFO * );
-	PXENV_EXIT_t ( * restart_tftp ) ( struct s_PXENV_TFTP_READ_FILE * );
-	PXENV_EXIT_t ( * start_undi ) ( struct s_PXENV_START_UNDI * );
-	PXENV_EXIT_t ( * stop_undi ) ( struct s_PXENV_STOP_UNDI * );
-	PXENV_EXIT_t ( * start_base ) ( struct s_PXENV_START_BASE * );
-	PXENV_EXIT_t ( * stop_base ) ( struct s_PXENV_STOP_BASE * );
-	PXENV_EXIT_t ( * tftp_open ) ( struct s_PXENV_TFTP_OPEN * );
-	PXENV_EXIT_t ( * tftp_close ) ( struct s_PXENV_TFTP_CLOSE * );
-	PXENV_EXIT_t ( * tftp_read ) ( struct s_PXENV_TFTP_READ * );
-	PXENV_EXIT_t ( * tftp_read_file ) ( struct s_PXENV_TFTP_READ_FILE * );
-	PXENV_EXIT_t ( * tftp_get_fsize ) ( struct s_PXENV_TFTP_GET_FSIZE * );
-	PXENV_EXIT_t ( * udp_open ) ( struct s_PXENV_UDP_OPEN * );
-	PXENV_EXIT_t ( * udp_close ) ( struct s_PXENV_UDP_CLOSE * );
-	PXENV_EXIT_t ( * udp_write ) ( struct s_PXENV_UDP_WRITE * );
-	PXENV_EXIT_t ( * udp_read ) ( struct s_PXENV_UDP_READ * );
-	PXENV_EXIT_t ( * undi_startup ) ( struct s_PXENV_UNDI_STARTUP * );
-	PXENV_EXIT_t ( * undi_cleanup ) ( struct s_PXENV_UNDI_CLEANUP * );
-	PXENV_EXIT_t ( * undi_initialize )
-			( struct s_PXENV_UNDI_INITIALIZE * );
-	PXENV_EXIT_t ( * undi_reset_adapter ) ( struct s_PXENV_UNDI_RESET * );
-	PXENV_EXIT_t ( * undi_shutdown ) ( struct s_PXENV_UNDI_SHUTDOWN * );
-	PXENV_EXIT_t ( * undi_open ) ( struct s_PXENV_UNDI_OPEN * );
-	PXENV_EXIT_t ( * undi_close ) ( struct s_PXENV_UNDI_CLOSE * );
-	PXENV_EXIT_t ( * undi_transmit ) ( struct s_PXENV_UNDI_TRANSMIT * );
-	PXENV_EXIT_t ( * undi_set_mcast_address )
-			( struct s_PXENV_UNDI_SET_MCAST_ADDRESS * );
-	PXENV_EXIT_t ( * undi_set_station_address )
-			( struct s_PXENV_UNDI_SET_STATION_ADDRESS * );
-	PXENV_EXIT_t ( * undi_set_packet_filter )
-			( struct s_PXENV_UNDI_SET_PACKET_FILTER * );
-	PXENV_EXIT_t ( * undi_get_information )
-			( struct s_PXENV_UNDI_GET_INFORMATION * );
-	PXENV_EXIT_t ( * undi_get_statistics )
-			( struct s_PXENV_UNDI_GET_STATISTICS * );
-	PXENV_EXIT_t ( * undi_clear_statistics )
-			( struct s_PXENV_UNDI_CLEAR_STATISTICS * );
-	PXENV_EXIT_t ( * undi_initiate_diags )
-			( struct s_PXENV_UNDI_INITIATE_DIAGS * );
-	PXENV_EXIT_t ( * undi_force_interrupt )
-			( struct s_PXENV_UNDI_FORCE_INTERRUPT * );
-	PXENV_EXIT_t ( * undi_get_mcast_address )
-			( struct s_PXENV_UNDI_GET_MCAST_ADDRESS * );
-	PXENV_EXIT_t ( * undi_get_nic_type )
-			( struct s_PXENV_UNDI_GET_NIC_TYPE * );
-	PXENV_EXIT_t ( * undi_get_iface_info )
-			( struct s_PXENV_UNDI_GET_IFACE_INFO * );
-	PXENV_EXIT_t ( * undi_get_state ) ( struct s_PXENV_UNDI_GET_STATE * );
-	PXENV_EXIT_t ( * undi_isr ) ( struct s_PXENV_UNDI_ISR * );
-	PXENV_EXIT_t ( * file_open ) ( struct s_PXENV_FILE_OPEN * );
-	PXENV_EXIT_t ( * file_close ) ( struct s_PXENV_FILE_CLOSE * );
-	PXENV_EXIT_t ( * file_select ) ( struct s_PXENV_FILE_SELECT * );
-	PXENV_EXIT_t ( * file_read ) ( struct s_PXENV_FILE_READ * );
-	PXENV_EXIT_t ( * get_file_size ) ( struct s_PXENV_GET_FILE_SIZE * );
-	PXENV_EXIT_t ( * file_exec ) ( struct s_PXENV_FILE_EXEC * );
-	PXENV_EXIT_t ( * file_api_check ) ( struct s_PXENV_FILE_API_CHECK * );
-	PXENV_EXIT_t ( * file_exit_hook ) ( struct s_PXENV_FILE_EXIT_HOOK * );
-};
-
 /**
  * Handle an unknown PXE API call
  *
@@ -120,6 +54,26 @@ static PXENV_EXIT_t pxenv_unknown ( struct s_PXENV_UNKNOWN *pxenv_unknown ) {
 	return PXENV_EXIT_FAILURE;
 }
 
+/** Unknown PXE API call list */
+struct pxe_api_call pxenv_unknown_api __pxe_api_call =
+	PXE_API_CALL ( PXENV_UNKNOWN, pxenv_unknown, struct s_PXENV_UNKNOWN );
+
+/**
+ * Locate PXE API call
+ *
+ * @v opcode		Opcode
+ * @ret call		PXE API call, or NULL
+ */
+static struct pxe_api_call * find_pxe_api_call ( uint16_t opcode ) {
+	struct pxe_api_call *call;
+
+	for_each_table_entry ( call, PXE_API_CALLS ) {
+		if ( call->opcode == opcode )
+			return call;
+	}
+	return NULL;
+}
+
 /**
  * Dispatch PXE API call
  *
@@ -128,220 +82,30 @@ static PXENV_EXIT_t pxenv_unknown ( struct s_PXENV_UNKNOWN *pxenv_unknown ) {
  * @ret ax		PXE exit code
  */
 __asmcall void pxe_api_call ( struct i386_all_regs *ix86 ) {
-	int opcode = ix86->regs.bx;
-	userptr_t parameters = real_to_user ( ix86->segs.es, ix86->regs.di );
-	size_t param_len;
-	union u_PXENV_ANY pxenv_any;
-	union pxenv_call pxenv_call;
+	uint16_t opcode = ix86->regs.bx;
+	userptr_t uparams = real_to_user ( ix86->segs.es, ix86->regs.di );
+	struct pxe_api_call *call;
+	union u_PXENV_ANY params;
 	PXENV_EXIT_t ret;
 
-	switch ( opcode ) {
-	case PXENV_UNLOAD_STACK:
-		pxenv_call.unload_stack = pxenv_unload_stack;
-		param_len = sizeof ( pxenv_any.unload_stack );
-		break;
-	case PXENV_GET_CACHED_INFO:
-		pxenv_call.get_cached_info = pxenv_get_cached_info;
-		param_len = sizeof ( pxenv_any.get_cached_info );
-		break;
-	case PXENV_RESTART_TFTP:
-		pxenv_call.restart_tftp = pxenv_restart_tftp;
-		param_len = sizeof ( pxenv_any.restart_tftp );
-		break;
-	case PXENV_START_UNDI:
-		pxenv_call.start_undi = pxenv_start_undi;
-		param_len = sizeof ( pxenv_any.start_undi );
-		break;
-	case PXENV_STOP_UNDI:
-		pxenv_call.stop_undi = pxenv_stop_undi;
-		param_len = sizeof ( pxenv_any.stop_undi );
-		break;
-	case PXENV_START_BASE:
-		pxenv_call.start_base = pxenv_start_base;
-		param_len = sizeof ( pxenv_any.start_base );
-		break;
-	case PXENV_STOP_BASE:
-		pxenv_call.stop_base = pxenv_stop_base;
-		param_len = sizeof ( pxenv_any.stop_base );
-		break;
-	case PXENV_TFTP_OPEN:
-		pxenv_call.tftp_open = pxenv_tftp_open;
-		param_len = sizeof ( pxenv_any.tftp_open );
-		break;
-	case PXENV_TFTP_CLOSE:
-		pxenv_call.tftp_close = pxenv_tftp_close;
-		param_len = sizeof ( pxenv_any.tftp_close );
-		break;
-	case PXENV_TFTP_READ:
-		pxenv_call.tftp_read = pxenv_tftp_read;
-		param_len = sizeof ( pxenv_any.tftp_read );
-		break;
-	case PXENV_TFTP_READ_FILE:
-		pxenv_call.tftp_read_file = pxenv_tftp_read_file;
-		param_len = sizeof ( pxenv_any.tftp_read_file );
-		break;
-	case PXENV_TFTP_GET_FSIZE:
-		pxenv_call.tftp_get_fsize = pxenv_tftp_get_fsize;
-		param_len = sizeof ( pxenv_any.tftp_get_fsize );
-		break;
-	case PXENV_UDP_OPEN:
-		pxenv_call.udp_open = pxenv_udp_open;
-		param_len = sizeof ( pxenv_any.udp_open );
-		break;
-	case PXENV_UDP_CLOSE:
-		pxenv_call.udp_close = pxenv_udp_close;
-		param_len = sizeof ( pxenv_any.udp_close );
-		break;
-	case PXENV_UDP_WRITE:
-		pxenv_call.udp_write = pxenv_udp_write;
-		param_len = sizeof ( pxenv_any.udp_write );
-		break;
-	case PXENV_UDP_READ:
-		pxenv_call.udp_read = pxenv_udp_read;
-		param_len = sizeof ( pxenv_any.udp_read );
-		break;
-	case PXENV_UNDI_STARTUP:
-		pxenv_call.undi_startup = pxenv_undi_startup;
-		param_len = sizeof ( pxenv_any.undi_startup );
-		break;
-	case PXENV_UNDI_CLEANUP:
-		pxenv_call.undi_cleanup = pxenv_undi_cleanup;
-		param_len = sizeof ( pxenv_any.undi_cleanup );
-		break;
-	case PXENV_UNDI_INITIALIZE:
-		pxenv_call.undi_initialize = pxenv_undi_initialize;
-		param_len = sizeof ( pxenv_any.undi_initialize );
-		break;
-	case PXENV_UNDI_RESET_ADAPTER:
-		pxenv_call.undi_reset_adapter = pxenv_undi_reset_adapter;
-		param_len = sizeof ( pxenv_any.undi_reset_adapter );
-		break;
-	case PXENV_UNDI_SHUTDOWN:
-		pxenv_call.undi_shutdown = pxenv_undi_shutdown;
-		param_len = sizeof ( pxenv_any.undi_shutdown );
-		break;
-	case PXENV_UNDI_OPEN:
-		pxenv_call.undi_open = pxenv_undi_open;
-		param_len = sizeof ( pxenv_any.undi_open );
-		break;
-	case PXENV_UNDI_CLOSE:
-		pxenv_call.undi_close = pxenv_undi_close;
-		param_len = sizeof ( pxenv_any.undi_close );
-		break;
-	case PXENV_UNDI_TRANSMIT:
-		pxenv_call.undi_transmit = pxenv_undi_transmit;
-		param_len = sizeof ( pxenv_any.undi_transmit );
-		break;
-	case PXENV_UNDI_SET_MCAST_ADDRESS:
-		pxenv_call.undi_set_mcast_address =
-			pxenv_undi_set_mcast_address;
-		param_len = sizeof ( pxenv_any.undi_set_mcast_address );
-		break;
-	case PXENV_UNDI_SET_STATION_ADDRESS:
-		pxenv_call.undi_set_station_address =
-			pxenv_undi_set_station_address;
-		param_len = sizeof ( pxenv_any.undi_set_station_address );
-		break;
-	case PXENV_UNDI_SET_PACKET_FILTER:
-		pxenv_call.undi_set_packet_filter =
-			pxenv_undi_set_packet_filter;
-		param_len = sizeof ( pxenv_any.undi_set_packet_filter );
-		break;
-	case PXENV_UNDI_GET_INFORMATION:
-		pxenv_call.undi_get_information = pxenv_undi_get_information;
-		param_len = sizeof ( pxenv_any.undi_get_information );
-		break;
-	case PXENV_UNDI_GET_STATISTICS:
-		pxenv_call.undi_get_statistics = pxenv_undi_get_statistics;
-		param_len = sizeof ( pxenv_any.undi_get_statistics );
-		break;
-	case PXENV_UNDI_CLEAR_STATISTICS:
-		pxenv_call.undi_clear_statistics = pxenv_undi_clear_statistics;
-		param_len = sizeof ( pxenv_any.undi_clear_statistics );
-		break;
-	case PXENV_UNDI_INITIATE_DIAGS:
-		pxenv_call.undi_initiate_diags = pxenv_undi_initiate_diags;
-		param_len = sizeof ( pxenv_any.undi_initiate_diags );
-		break;
-	case PXENV_UNDI_FORCE_INTERRUPT:
-		pxenv_call.undi_force_interrupt = pxenv_undi_force_interrupt;
-		param_len = sizeof ( pxenv_any.undi_force_interrupt );
-		break;
-	case PXENV_UNDI_GET_MCAST_ADDRESS:
-		pxenv_call.undi_get_mcast_address =
-			pxenv_undi_get_mcast_address;
-		param_len = sizeof ( pxenv_any.undi_get_mcast_address );
-		break;
-	case PXENV_UNDI_GET_NIC_TYPE:
-		pxenv_call.undi_get_nic_type = pxenv_undi_get_nic_type;
-		param_len = sizeof ( pxenv_any.undi_get_nic_type );
-		break;
-	case PXENV_UNDI_GET_IFACE_INFO:
-		pxenv_call.undi_get_iface_info = pxenv_undi_get_iface_info;
-		param_len = sizeof ( pxenv_any.undi_get_iface_info );
-		break;
-	case PXENV_UNDI_ISR:
-		pxenv_call.undi_isr = pxenv_undi_isr;
-		param_len = sizeof ( pxenv_any.undi_isr );
-		break;
-	case PXENV_FILE_OPEN:
-		pxenv_call.file_open = pxenv_file_open;
-		param_len = sizeof ( pxenv_any.file_open );
-		break;
-	case PXENV_FILE_CLOSE:
-		pxenv_call.file_close = pxenv_file_close;
-		param_len = sizeof ( pxenv_any.file_close );
-		break;
-	case PXENV_FILE_SELECT:
-		pxenv_call.file_select = pxenv_file_select;
-		param_len = sizeof ( pxenv_any.file_select );
-		break;
-	case PXENV_FILE_READ:
-		pxenv_call.file_read = pxenv_file_read;
-		param_len = sizeof ( pxenv_any.file_read );
-		break;
-	case PXENV_GET_FILE_SIZE:
-		pxenv_call.get_file_size = pxenv_get_file_size;
-		param_len = sizeof ( pxenv_any.get_file_size );
-		break;
-	case PXENV_FILE_EXEC:
-		pxenv_call.file_exec = pxenv_file_exec;
-		param_len = sizeof ( pxenv_any.file_exec );
-		break;
-	case PXENV_FILE_API_CHECK:
-		pxenv_call.file_api_check = pxenv_file_api_check;
-		param_len = sizeof ( pxenv_any.file_api_check );
-		break;
-	case PXENV_FILE_EXIT_HOOK:
-		pxenv_call.file_exit_hook = pxenv_file_exit_hook;
-		param_len = sizeof ( pxenv_any.file_exit_hook );
-		break;
-	default:
-		DBG ( "PXENV_UNKNOWN_%hx", opcode );
-		pxenv_call.unknown = pxenv_unknown;
-		param_len = sizeof ( pxenv_any.unknown );
-		break;
+	/* Locate API call */
+	call = find_pxe_api_call ( opcode );
+	if ( ! call ) {
+		DBGC ( &pxe_netdev, "PXENV_UNKNOWN_%04x\n", opcode );
+		call = &pxenv_unknown_api;
 	}
 
 	/* Copy parameter block from caller */
-	copy_from_user ( &pxenv_any, parameters, 0, param_len );
+	copy_from_user ( &params, uparams, 0, call->params_len );
 
 	/* Set default status in case child routine fails to do so */
-	pxenv_any.Status = PXENV_STATUS_FAILURE;
+	params.Status = PXENV_STATUS_FAILURE;
 
 	/* Hand off to relevant API routine */
-	DBG ( "[" );
-	ret = pxenv_call.any ( &pxenv_any );
-	if ( pxenv_any.Status != PXENV_STATUS_SUCCESS ) {
-		DBG ( " %02x", pxenv_any.Status );
-	}
-	if ( ret != PXENV_EXIT_SUCCESS ) {
-		DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
-	}
-	DBG ( "]" );
-	
+	ret = call->entry ( &params );
+
 	/* Copy modified parameter block back to caller and return */
-	copy_to_user ( parameters, 0, &pxenv_any, param_len );
+	copy_to_user ( uparams, 0, &params, call->params_len );
 	ix86->regs.ax = ret;
 }
 
@@ -351,8 +115,7 @@ __asmcall void pxe_api_call ( struct i386_all_regs *ix86 ) {
  * @v ix86		Registers for PXE call
  * @ret present		Zero (PXE stack present)
  */
-int pxe_api_call_weak ( struct i386_all_regs *ix86 )
-{
+int pxe_api_call_weak ( struct i386_all_regs *ix86 ) {
 	pxe_api_call ( ix86 );
 	return 0;
 }
@@ -519,3 +282,9 @@ int pxe_start_nbp ( void ) {
 
 	return rc;
 }
+
+REQUIRE_OBJECT ( pxe_preboot );
+REQUIRE_OBJECT ( pxe_undi );
+REQUIRE_OBJECT ( pxe_udp );
+REQUIRE_OBJECT ( pxe_tftp );
+REQUIRE_OBJECT ( pxe_file );
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S b/roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S
index 0d3a57cd3c3707ec513124b0076a..6274264ff9d730dffea3c3d81f59 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_entry.S
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  *
  */
 
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_exit_hook.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_exit_hook.c
new file mode 100644
index 0000000000000000000000000000000000000000..9d18965077f3b69faf7776d2ed4aa409f41dcd89
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_exit_hook.c
@@ -0,0 +1,61 @@
+/** @file
+ *
+ * PXE exit hook
+ *
+ */
+
+/*
+ * Copyright (C) 2010 Shao Miller <shao.miller@yrdsb.edu.on.ca>.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <realmode.h>
+#include <pxe.h>
+
+/** PXE exit hook */
+extern segoff_t __data16 ( pxe_exit_hook );
+#define pxe_exit_hook __use_data16 ( pxe_exit_hook )
+
+/**
+ * FILE EXIT HOOK
+ *
+ * @v file_exit_hook			Pointer to a struct
+ *					s_PXENV_FILE_EXIT_HOOK
+ * @v s_PXENV_FILE_EXIT_HOOK::Hook	SEG16:OFF16 to jump to
+ * @ret #PXENV_EXIT_SUCCESS		Successfully set hook
+ * @ret #PXENV_EXIT_FAILURE		We're not an NBP build
+ * @ret s_PXENV_FILE_EXIT_HOOK::Status	PXE status code
+ *
+ */
+static PXENV_EXIT_t
+pxenv_file_exit_hook ( struct s_PXENV_FILE_EXIT_HOOK *file_exit_hook ) {
+	DBG ( "PXENV_FILE_EXIT_HOOK" );
+
+	/* We'll jump to the specified SEG16:OFF16 during exit */
+	pxe_exit_hook.segment = file_exit_hook->Hook.segment;
+	pxe_exit_hook.offset = file_exit_hook->Hook.offset;
+	file_exit_hook->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
+
+/** PXE file API */
+struct pxe_api_call pxe_file_api_exit_hook __pxe_api_call =
+	PXE_API_CALL ( PXENV_FILE_EXIT_HOOK, pxenv_file_exit_hook,
+		       struct s_PXENV_FILE_EXIT_HOOK );
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c
index 267625688295ade3a2f36477d3f4..6e9610294aa96810def1f88455ce 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_file.c
@@ -16,8 +16,6 @@
 
 /*
  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
- * Portions (C) 2010 Shao Miller <shao.miller@yrdsb.edu.on.ca>.
- *              [PXE exit hook logic]
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -31,7 +29,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -49,7 +48,7 @@ FEATURE ( FEATURE_MISC, "PXEXT", DHCP_EB_FEATURE_PXE_EXT, 2 );
  * @ret s_PXENV_FILE_OPEN::FileHandle	Handle of opened file
  *
  */
-PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open ) {
+static PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open ) {
 	userptr_t filename;
 	size_t filename_len;
 	int fd;
@@ -91,7 +90,7 @@ PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open ) {
  * @ret s_PXENV_FILE_CLOSE::Status	PXE status code
  *
  */
-PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE *file_close ) {
+static PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE *file_close ) {
 
 	DBG ( "PXENV_FILE_CLOSE %d", file_close->FileHandle );
 
@@ -111,7 +110,8 @@ PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE *file_close ) {
  * @ret s_PXENV_FILE_SELECT::Ready	Indication of readiness
  *
  */
-PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT *file_select ) {
+static PXENV_EXIT_t
+pxenv_file_select ( struct s_PXENV_FILE_SELECT *file_select ) {
 	fd_set fdset;
 	int ready;
 
@@ -143,7 +143,7 @@ PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT *file_select ) {
  * @ret s_PXENV_FILE_READ::BufferSize	Length of data read
  *
  */
-PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read ) {
+static PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read ) {
 	userptr_t buffer;
 	ssize_t len;
 
@@ -176,8 +176,8 @@ PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read ) {
  * @ret s_PXENV_GET_FILE_SIZE::Status	PXE status code
  * @ret s_PXENV_GET_FILE_SIZE::FileSize	Size of file
  */
-PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE
-				   *get_file_size ) {
+static PXENV_EXIT_t
+pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE *get_file_size ) {
 	ssize_t filesize;
 
 	DBG ( "PXENV_GET_FILE_SIZE %d", get_file_size->FileHandle );
@@ -205,7 +205,7 @@ PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE
  * @ret s_PXENV_FILE_EXEC::Status	PXE status code
  *
  */
-PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ) {
+static PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ) {
 	userptr_t command;
 	size_t command_len;
 	int rc;
@@ -233,8 +233,41 @@ PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ) {
 	return PXENV_EXIT_SUCCESS;
 }
 
-segoff_t __data16 ( pxe_exit_hook ) = { 0, 0 };
-#define pxe_exit_hook __use_data16 ( pxe_exit_hook )
+/**
+ * FILE CMDLINE
+ *
+ * @v file_cmdline			Pointer to a struct s_PXENV_FILE_CMDLINE
+ * @v s_PXENV_FILE_CMDLINE::Buffer	Buffer to contain command line
+ * @v s_PXENV_FILE_CMDLINE::BufferSize	Size of buffer
+ * @ret #PXENV_EXIT_SUCCESS		Command was executed successfully
+ * @ret #PXENV_EXIT_FAILURE		Command was not executed successfully
+ * @ret s_PXENV_FILE_EXEC::Status	PXE status code
+ * @ret s_PXENV_FILE_EXEC::BufferSize	Length of command line (including NUL)
+ *
+ */
+static PXENV_EXIT_t
+pxenv_file_cmdline ( struct s_PXENV_FILE_CMDLINE *file_cmdline ) {
+	userptr_t buffer;
+	size_t max_len;
+	size_t len;
+
+	DBG ( "PXENV_FILE_CMDLINE to %04x:%04x+%04x \"%s\"\n",
+	      file_cmdline->Buffer.segment, file_cmdline->Buffer.offset,
+	      file_cmdline->BufferSize, pxe_cmdline );
+
+	buffer = real_to_user ( file_cmdline->Buffer.segment,
+				file_cmdline->Buffer.offset );
+	len = file_cmdline->BufferSize;
+	max_len = ( pxe_cmdline ?
+		    ( strlen ( pxe_cmdline ) + 1 /* NUL */ ) : 0 );
+	if ( len > max_len )
+		len = max_len;
+	copy_to_user ( buffer, 0, pxe_cmdline, len );
+	file_cmdline->BufferSize = max_len;
+
+	file_cmdline->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
+}
 
 /**
  * FILE API CHECK
@@ -250,57 +283,60 @@ segoff_t __data16 ( pxe_exit_hook ) = { 0, 0 };
  * @ret s_PXENV_FILE_API_CHECK::Flags	Reserved
  *
  */
-PXENV_EXIT_t pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_check ) {
+static PXENV_EXIT_t
+pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_check ) {
+	struct pxe_api_call *call;
+	unsigned int mask = 0;
+	unsigned int offset;
+
 	DBG ( "PXENV_FILE_API_CHECK" );
 
+	/* Check for magic value */
 	if ( file_api_check->Magic != 0x91d447b2 ) {
 		file_api_check->Status = PXENV_STATUS_BAD_FUNC;
 		return PXENV_EXIT_FAILURE;
-	} else if ( file_api_check->Size <
-		    sizeof(struct s_PXENV_FILE_API_CHECK) ) {
+	}
+
+	/* Check for required parameter size */
+	if ( file_api_check->Size < sizeof ( *file_api_check ) ) {
 		file_api_check->Status = PXENV_STATUS_OUT_OF_RESOURCES;
 		return PXENV_EXIT_FAILURE;
-	} else {
-		file_api_check->Status   = PXENV_STATUS_SUCCESS;
-		file_api_check->Size     = sizeof(struct s_PXENV_FILE_API_CHECK);
-		file_api_check->Magic    = 0xe9c17b20;
-		file_api_check->Provider = 0x45585067; /* "iPXE" */
-		file_api_check->APIMask  = 0x0000007f; /* Functions e0-e6 */
-		/* Check to see if we have a PXE exit hook */
-		if ( pxe_exit_hook.segment | pxe_exit_hook.offset )
-			/* Function e7, also */
-			file_api_check->APIMask |= 0x00000080;
-		file_api_check->Flags    = 0;	       /* None defined */
-		return PXENV_EXIT_SUCCESS;
 	}
-}
 
-/**
- * FILE EXIT HOOK
- *
- * @v file_exit_hook			Pointer to a struct
- *					s_PXENV_FILE_EXIT_HOOK
- * @v s_PXENV_FILE_EXIT_HOOK::Hook	SEG16:OFF16 to jump to
- * @ret #PXENV_EXIT_SUCCESS		Successfully set hook
- * @ret #PXENV_EXIT_FAILURE		We're not an NBP build
- * @ret s_PXENV_FILE_EXIT_HOOK::Status	PXE status code
- *
- */
-PXENV_EXIT_t pxenv_file_exit_hook ( struct s_PXENV_FILE_EXIT_HOOK
-					*file_exit_hook ) {
-	DBG ( "PXENV_FILE_EXIT_HOOK" );
-
-	/* Check to see if we have a PXE exit hook */
-	if ( pxe_exit_hook.segment | pxe_exit_hook.offset ) {
-		/* We'll jump to the specified SEG16:OFF16 during exit */
-		pxe_exit_hook.segment = file_exit_hook->Hook.segment;
-		pxe_exit_hook.offset = file_exit_hook->Hook.offset;
-		file_exit_hook->Status = PXENV_STATUS_SUCCESS;
-		return PXENV_EXIT_SUCCESS;
+	/* Determine supported calls */
+	for_each_table_entry ( call, PXE_API_CALLS ) {
+		offset = ( call->opcode - PXENV_FILE_MIN );
+		if ( offset <= ( PXENV_FILE_MAX - PXENV_FILE_MIN ) )
+			mask |= ( 1 << offset );
 	}
 
-	DBG ( " not NBP" );
-	file_exit_hook->Status = PXENV_STATUS_UNSUPPORTED;
-	return PXENV_EXIT_FAILURE;
+	/* Fill in parameters */
+	file_api_check->Size = sizeof ( *file_api_check );
+	file_api_check->Magic = 0xe9c17b20;
+	file_api_check->Provider = 0x45585067; /* "iPXE" */
+	file_api_check->APIMask = mask;
+	file_api_check->Flags = 0; /* None defined */
+
+	file_api_check->Status = PXENV_STATUS_SUCCESS;
+	return PXENV_EXIT_SUCCESS;
 }
 
+/** PXE file API */
+struct pxe_api_call pxe_file_api[] __pxe_api_call = {
+	PXE_API_CALL ( PXENV_FILE_OPEN, pxenv_file_open,
+		       struct s_PXENV_FILE_OPEN ),
+	PXE_API_CALL ( PXENV_FILE_CLOSE, pxenv_file_close,
+		       struct s_PXENV_FILE_CLOSE ),
+	PXE_API_CALL ( PXENV_FILE_SELECT, pxenv_file_select,
+		       struct s_PXENV_FILE_SELECT ),
+	PXE_API_CALL ( PXENV_FILE_READ, pxenv_file_read,
+		       struct s_PXENV_FILE_READ ),
+	PXE_API_CALL ( PXENV_GET_FILE_SIZE, pxenv_get_file_size,
+		       struct s_PXENV_GET_FILE_SIZE ),
+	PXE_API_CALL ( PXENV_FILE_EXEC, pxenv_file_exec,
+		       struct s_PXENV_FILE_EXEC ),
+	PXE_API_CALL ( PXENV_FILE_CMDLINE, pxenv_file_cmdline,
+		       struct s_PXENV_FILE_CMDLINE ),
+	PXE_API_CALL ( PXENV_FILE_API_CHECK, pxenv_file_api_check,
+		       struct s_PXENV_FILE_API_CHECK ),
+};
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c
index 63858be204d8b5a0067320c5a14e..695af3b93498569e7a24232991b7 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_loader.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c
index 9e4853b0140ade0dc2c4f0171335..534352b2b5d63cf799b5d6e41e47 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_preboot.c
@@ -20,7 +20,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -89,6 +90,26 @@ static struct pxe_dhcp_packet_creator pxe_dhcp_packet_creators[] = {
 	[CACHED_INFO_BINL] = { create_fakepxebsack },
 };
 
+/**
+ * Name PXENV_GET_CACHED_INFO packet type
+ *
+ * @v packet_type	Packet type
+ * @ret name		Name of packet type
+ */
+static inline __attribute__ (( always_inline )) const char *
+pxenv_get_cached_info_name ( int packet_type ) {
+	switch ( packet_type ) {
+	case PXENV_PACKET_TYPE_DHCP_DISCOVER:
+		return "DHCPDISCOVER";
+	case PXENV_PACKET_TYPE_DHCP_ACK:
+		return "DHCPACK";
+	case PXENV_PACKET_TYPE_CACHED_REPLY:
+		return "BINL";
+	default:
+		return "<INVALID>";
+	}
+}
+
 /* The case in which the caller doesn't supply a buffer is really
  * awkward to support given that we have multiple sources of options,
  * and that we don't actually store the DHCP packets.  (We may not
@@ -110,8 +131,9 @@ static union pxe_cached_info __bss16_array ( cached_info, [NUM_CACHED_INFOS] );
  * @ret ...
  *
  */
-PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) {
-	DBG ( "PXENV_UNLOAD_STACK" );
+static PXENV_EXIT_t
+pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) {
+	DBGC ( &pxe_netdev, "PXENV_UNLOAD_STACK\n" );
 
 	unload_stack->Status = PXENV_STATUS_SUCCESS;
 	return PXENV_EXIT_SUCCESS;
@@ -121,8 +143,8 @@ PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) {
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
-				     *get_cached_info ) {
+static PXENV_EXIT_t
+pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO *get_cached_info ) {
 	struct pxe_dhcp_packet_creator *creator;
 	union pxe_cached_info *info;
 	unsigned int idx;
@@ -130,15 +152,24 @@ PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
 	userptr_t buffer;
 	int rc;
 
-	DBG ( "PXENV_GET_CACHED_INFO %d", get_cached_info->PacketType );
+	DBGC ( &pxe_netdev, "PXENV_GET_CACHED_INFO %s to %04x:%04x+%x",
+	       pxenv_get_cached_info_name ( get_cached_info->PacketType ),
+	       get_cached_info->Buffer.segment,
+	       get_cached_info->Buffer.offset, get_cached_info->BufferSize );
 
-	DBG ( " to %04x:%04x+%x", get_cached_info->Buffer.segment,
-	      get_cached_info->Buffer.offset, get_cached_info->BufferSize );
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_GET_CACHED_INFO called with no "
+		       "network device\n" );
+		get_cached_info->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
 	/* Sanity check */
         idx = ( get_cached_info->PacketType - 1 );
 	if ( idx >= NUM_CACHED_INFOS ) {
-		DBG ( " bad PacketType" );
+		DBGC ( &pxe_netdev, " bad PacketType %d\n",
+		       get_cached_info->PacketType );
 		goto err;
 	}
 	info = &cached_info[idx];
@@ -149,7 +180,8 @@ PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
 		creator = &pxe_dhcp_packet_creators[idx];
 		if ( ( rc = creator->create ( pxe_netdev, info,
 					      sizeof ( *info ) ) ) != 0 ) {
-			DBG ( " failed to build packet" );
+			DBGC ( &pxe_netdev, " failed to build packet: %s\n",
+			       strerror ( rc ) );
 			goto err;
 		}
 	}
@@ -184,23 +216,24 @@ PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
 		get_cached_info->Buffer.segment = rm_ds;
 		get_cached_info->Buffer.offset = __from_data16 ( info );
 		get_cached_info->BufferSize = sizeof ( *info );
-		DBG ( " returning %04x:%04x+%04x['%x']",
-		      get_cached_info->Buffer.segment,
-		      get_cached_info->Buffer.offset,
-		      get_cached_info->BufferSize,
-		      get_cached_info->BufferLimit );
+		DBGC ( &pxe_netdev, " using %04x:%04x+%04x['%x']",
+		       get_cached_info->Buffer.segment,
+		       get_cached_info->Buffer.offset,
+		       get_cached_info->BufferSize,
+		       get_cached_info->BufferLimit );
 	} else {
 		/* Copy packet to client buffer */
 		if ( len > sizeof ( *info ) )
 			len = sizeof ( *info );
 		if ( len < sizeof ( *info ) )
-			DBG ( " buffer may be too short" );
+			DBGC ( &pxe_netdev, " buffer may be too short" );
 		buffer = real_to_user ( get_cached_info->Buffer.segment,
 					get_cached_info->Buffer.offset );
 		copy_to_user ( buffer, 0, info, len );
 		get_cached_info->BufferSize = len;
 	}
 
+	DBGC ( &pxe_netdev, "\n" );
 	get_cached_info->Status = PXENV_STATUS_SUCCESS;
 	return PXENV_EXIT_SUCCESS;
 
@@ -213,11 +246,11 @@ PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
-				  *restart_tftp ) {
+static PXENV_EXIT_t
+pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE *restart_tftp ) {
 	PXENV_EXIT_t tftp_exit;
 
-	DBG ( "PXENV_RESTART_TFTP " );
+	DBGC ( &pxe_netdev, "PXENV_RESTART_TFTP\n" );
 
 	/* Words cannot describe the complete mismatch between the PXE
 	 * specification and any possible version of reality...
@@ -236,13 +269,13 @@ PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
+static PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
 	unsigned int bus_type;
 	unsigned int location;
 	struct net_device *netdev;
 
-	DBG ( "PXENV_START_UNDI %04x:%04x:%04x",
-	      start_undi->AX, start_undi->BX, start_undi->DX );
+	DBGC ( &pxe_netdev, "PXENV_START_UNDI %04x:%04x:%04x\n",
+	       start_undi->AX, start_undi->BX, start_undi->DX );
 
 	/* Determine bus type and location.  Use a heuristic to decide
 	 * whether we are PCI or ISAPnP
@@ -266,11 +299,13 @@ PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
 	/* Look for a matching net device */
 	netdev = find_netdev_by_location ( bus_type, location );
 	if ( ! netdev ) {
-		DBG ( " no net device found" );
+		DBGC ( &pxe_netdev, "PXENV_START_UNDI could not find matching "
+		       "net device\n" );
 		start_undi->Status = PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC;
 		return PXENV_EXIT_FAILURE;
 	}
-	DBG ( " using netdev %s", netdev->name );
+	DBGC ( &pxe_netdev, "PXENV_START_UNDI found net device %s\n",
+	       netdev->name );
 
 	/* Activate PXE */
 	pxe_activate ( netdev );
@@ -283,8 +318,8 @@ PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) {
-	DBG ( "PXENV_STOP_UNDI" );
+static PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) {
+	DBGC ( &pxe_netdev, "PXENV_STOP_UNDI\n" );
 
 	/* Deactivate PXE */
 	pxe_deactivate();
@@ -294,8 +329,8 @@ PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) {
 
 	/* Check to see if we still have any hooked interrupts */
 	if ( hooked_bios_interrupts != 0 ) {
-		DBG ( "PXENV_STOP_UNDI failed: %d interrupts still hooked\n",
-		      hooked_bios_interrupts );
+		DBGC ( &pxe_netdev, "PXENV_STOP_UNDI failed: %d interrupts "
+		       "still hooked\n", hooked_bios_interrupts );
 		stop_undi->Status = PXENV_STATUS_KEEP_UNDI;
 		return PXENV_EXIT_FAILURE;
 	}
@@ -308,8 +343,8 @@ PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) {
  *
  * Status: won't implement (requires major structural changes)
  */
-PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base ) {
-	DBG ( "PXENV_START_BASE" );
+static PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base ) {
+	DBGC ( &pxe_netdev, "PXENV_START_BASE\n" );
 
 	start_base->Status = PXENV_STATUS_UNSUPPORTED;
 	return PXENV_EXIT_FAILURE;
@@ -319,8 +354,8 @@ PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base ) {
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ) {
-	DBG ( "PXENV_STOP_BASE" );
+static PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ) {
+	DBGC ( &pxe_netdev, "PXENV_STOP_BASE\n" );
 
 	/* The only time we will be called is when the NBP is trying
 	 * to shut down the PXE stack.  There's nothing we need to do
@@ -330,3 +365,21 @@ PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ) {
 	stop_base->Status = PXENV_STATUS_SUCCESS;
 	return PXENV_EXIT_SUCCESS;
 }
+
+/** PXE preboot API */
+struct pxe_api_call pxe_preboot_api[] __pxe_api_call = {
+	PXE_API_CALL ( PXENV_UNLOAD_STACK, pxenv_unload_stack,
+		       struct s_PXENV_UNLOAD_STACK ),
+	PXE_API_CALL ( PXENV_GET_CACHED_INFO, pxenv_get_cached_info,
+		       struct s_PXENV_GET_CACHED_INFO ),
+	PXE_API_CALL ( PXENV_RESTART_TFTP, pxenv_restart_tftp,
+		       struct s_PXENV_TFTP_READ_FILE ),
+	PXE_API_CALL ( PXENV_START_UNDI, pxenv_start_undi,
+		       struct s_PXENV_START_UNDI ),
+	PXE_API_CALL ( PXENV_STOP_UNDI, pxenv_stop_undi,
+		       struct s_PXENV_STOP_UNDI ),
+	PXE_API_CALL ( PXENV_START_BASE, pxenv_start_base,
+		       struct s_PXENV_START_BASE ),
+	PXE_API_CALL ( PXENV_STOP_BASE, pxenv_stop_base,
+		       struct s_PXENV_STOP_BASE ),
+};
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c
index 7f0af7a61e1e2682af365984862d..f4801bad0da2b1022994190608d0 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_tftp.c
@@ -19,7 +19,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -70,6 +71,17 @@ static void pxe_tftp_close ( struct pxe_tftp_connection *pxe_tftp, int rc ) {
 	pxe_tftp->rc = rc;
 }
 
+/**
+ * Check flow control window
+ *
+ * @v pxe_tftp		PXE TFTP connection
+ * @ret len		Length of window
+ */
+static size_t pxe_tftp_xfer_window ( struct pxe_tftp_connection *pxe_tftp ) {
+
+	return pxe_tftp->blksize;
+}
+
 /**
  * Receive new data
  *
@@ -127,6 +139,8 @@ static int pxe_tftp_xfer_deliver ( struct pxe_tftp_connection *pxe_tftp,
 static struct interface_operation pxe_tftp_xfer_ops[] = {
 	INTF_OP ( xfer_deliver, struct pxe_tftp_connection *,
 		  pxe_tftp_xfer_deliver ),
+	INTF_OP ( xfer_window, struct pxe_tftp_connection *,
+		  pxe_tftp_xfer_window ),
 	INTF_OP ( intf_close, struct pxe_tftp_connection *, pxe_tftp_close ),
 };
 
@@ -166,19 +180,19 @@ static int pxe_tftp_open ( uint32_t ipaddress, unsigned int port,
 	/* Reset PXE TFTP connection structure */
 	memset ( &pxe_tftp, 0, sizeof ( pxe_tftp ) );
 	intf_init ( &pxe_tftp.xfer, &pxe_tftp_xfer_desc, NULL );
+	if ( blksize < TFTP_DEFAULT_BLKSIZE )
+		blksize = TFTP_DEFAULT_BLKSIZE;
+	pxe_tftp.blksize = blksize;
 	pxe_tftp.rc = -EINPROGRESS;
 
 	/* Construct URI string */
 	address.s_addr = ipaddress;
 	if ( ! port )
 		port = htons ( TFTP_PORT );
-	if ( blksize < TFTP_DEFAULT_BLKSIZE )
-		blksize = TFTP_DEFAULT_BLKSIZE;
-	snprintf ( uri_string, sizeof ( uri_string ),
-		   "tftp%s://%s:%d%s%s?blksize=%zd",
-		   sizeonly ? "size" : "",
-		   inet_ntoa ( address ), ntohs ( port ),
-		   ( ( filename[0] == '/' ) ? "" : "/" ), filename, blksize );
+	snprintf ( uri_string, sizeof ( uri_string ), "tftp%s://%s:%d%s%s",
+		   sizeonly ? "size" : "", inet_ntoa ( address ),
+		   ntohs ( port ), ( ( filename[0] == '/' ) ? "" : "/" ),
+		   filename );
 	DBG ( " %s", uri_string );
 
 	/* Open PXE TFTP connection */
@@ -233,7 +247,7 @@ static int pxe_tftp_open ( uint32_t ipaddress, unsigned int port,
  * view of the PXE API, it is conceptually impossible to issue any
  * other PXE API call "if an MTFTP connection is active".
  */
-PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {
+static PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {
 	int rc;
 
 	DBG ( "PXENV_TFTP_OPEN" );
@@ -285,7 +299,7 @@ PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {
  * call this function with a 32-bit stack segment.  (See the relevant
  * @ref pxe_x86_pmode16 "implementation note" for more details.)
  */
-PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ) {
+static PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ) {
 	DBG ( "PXENV_TFTP_CLOSE" );
 
 	pxe_tftp_close ( &pxe_tftp, 0 );
@@ -354,7 +368,7 @@ PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ) {
  * call this function with a 32-bit stack segment.  (See the relevant
  * @ref pxe_x86_pmode16 "implementation note" for more details.)
  */
-PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) {
+static PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) {
 	int rc;
 
 	DBG ( "PXENV_TFTP_READ to %04x:%04x",
@@ -531,8 +545,8 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
  * a file from a TFTP server listening on the standard TFTP port.
  * "Consistency" is not a word in Intel's vocabulary.
  */
-PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
-				    *tftp_get_fsize ) {
+static PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
+					   *tftp_get_fsize ) {
 	int rc;
 
 	DBG ( "PXENV_TFTP_GET_FSIZE" );
@@ -562,3 +576,17 @@ PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
 	tftp_get_fsize->Status = PXENV_STATUS ( rc );
 	return ( rc ? PXENV_EXIT_FAILURE : PXENV_EXIT_SUCCESS );
 }
+
+/** PXE TFTP API */
+struct pxe_api_call pxe_tftp_api[] __pxe_api_call = {
+	PXE_API_CALL ( PXENV_TFTP_OPEN, pxenv_tftp_open,
+		       struct s_PXENV_TFTP_OPEN ),
+	PXE_API_CALL ( PXENV_TFTP_CLOSE, pxenv_tftp_close,
+		       struct s_PXENV_TFTP_CLOSE ),
+	PXE_API_CALL ( PXENV_TFTP_READ, pxenv_tftp_read,
+		       struct s_PXENV_TFTP_READ ),
+	PXE_API_CALL ( PXENV_TFTP_READ_FILE, pxenv_tftp_read_file,
+		       struct s_PXENV_TFTP_READ_FILE ),
+	PXE_API_CALL ( PXENV_TFTP_GET_FSIZE, pxenv_tftp_get_fsize,
+		       struct s_PXENV_TFTP_GET_FSIZE ),
+};
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c
index 22af4ca0d317ef12ed04a1c7b8d7..32bc39c8e13fe0830813dcee43c7 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_udp.c
@@ -28,7 +28,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -159,7 +160,7 @@ static struct pxe_udp_connection pxe_udp = {
  * parameter.
  *
  */
-PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
+static PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
 	int rc;
 
 	DBG ( "PXENV_UDP_OPEN" );
@@ -202,7 +203,8 @@ PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *pxenv_udp_open ) {
  * @ref pxe_x86_pmode16 "implementation note" for more details.)
  *
  */
-PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
+static PXENV_EXIT_t
+pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
 	DBG ( "PXENV_UDP_CLOSE\n" );
 
 	/* Close UDP connection */
@@ -253,7 +255,8 @@ PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *pxenv_udp_close ) {
  * parameter.
  *
  */
-PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
+static PXENV_EXIT_t
+pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
 	struct sockaddr_in dest;
 	struct xfer_metadata meta = {
 		.src = ( struct sockaddr * ) &pxe_udp.local,
@@ -359,7 +362,7 @@ PXENV_EXIT_t pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) {
  * expects us to do so, and will fail if we don't.
  *
  */
-PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
+static PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
 	struct in_addr dest_ip_wanted = { .s_addr = pxenv_udp_read->dest_ip };
 	struct in_addr dest_ip;
 	uint16_t d_port_wanted = pxenv_udp_read->d_port;
@@ -405,3 +408,15 @@ PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) {
 	pxenv_udp_read->Status = PXENV_STATUS_FAILURE;
 	return PXENV_EXIT_FAILURE;
 }
+
+/** PXE UDP API */
+struct pxe_api_call pxe_udp_api[] __pxe_api_call = {
+	PXE_API_CALL ( PXENV_UDP_OPEN, pxenv_udp_open,
+		       struct s_PXENV_UDP_OPEN ),
+	PXE_API_CALL ( PXENV_UDP_CLOSE, pxenv_udp_close,
+		       struct s_PXENV_UDP_CLOSE ),
+	PXE_API_CALL ( PXENV_UDP_WRITE, pxenv_udp_write,
+		       struct s_PXENV_UDP_WRITE ),
+	PXE_API_CALL ( PXENV_UDP_READ, pxenv_udp_read,
+		       struct s_PXENV_UDP_READ ),
+};
diff --git a/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c b/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c
index 3938207f163a3b3bed36a1860b3f..5d2122694906efb7f296b4e388ec 100644
--- a/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c
+++ b/roms/ipxe/src/arch/i386/interface/pxe/pxe_undi.c
@@ -19,7 +19,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -58,11 +59,14 @@ struct net_device *pxe_netdev = NULL;
  * @v netdev		Network device, or NULL
  */
 void pxe_set_netdev ( struct net_device *netdev ) {
+
 	if ( pxe_netdev ) {
 		netdev_rx_unfreeze ( pxe_netdev );
 		netdev_put ( pxe_netdev );
 	}
+
 	pxe_netdev = NULL;
+
 	if ( netdev )
 		pxe_netdev = netdev_get ( netdev );
 }
@@ -75,11 +79,14 @@ void pxe_set_netdev ( struct net_device *netdev ) {
 static int pxe_netdev_open ( void ) {
 	int rc;
 
+	assert ( pxe_netdev != NULL );
+
 	if ( ( rc = netdev_open ( pxe_netdev ) ) != 0 )
 		return rc;
 
 	netdev_rx_freeze ( pxe_netdev );
 	netdev_irq ( pxe_netdev, 1 );
+
 	return 0;
 }
 
@@ -88,6 +95,8 @@ static int pxe_netdev_open ( void ) {
  *
  */
 static void pxe_netdev_close ( void ) {
+
+	assert ( pxe_netdev != NULL );
 	netdev_rx_unfreeze ( pxe_netdev );
 	netdev_irq ( pxe_netdev, 0 );
 	netdev_close ( pxe_netdev );
@@ -104,7 +113,8 @@ static void pxe_dump_mcast_list ( struct s_PXENV_UNDI_MCAST_ADDRESS *mcast ) {
 	unsigned int i;
 
 	for ( i = 0 ; i < mcast->MCastAddrCount ; i++ ) {
-		DBG ( " %s", ll_protocol->ntoa ( mcast->McastAddr[i] ) );
+		DBGC ( &pxe_netdev, " %s",
+		       ll_protocol->ntoa ( mcast->McastAddr[i] ) );
 	}
 }
 
@@ -112,8 +122,17 @@ static void pxe_dump_mcast_list ( struct s_PXENV_UNDI_MCAST_ADDRESS *mcast ) {
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) {
-	DBG ( "PXENV_UNDI_STARTUP\n" );
+static PXENV_EXIT_t
+pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) {
+	DBGC ( &pxe_netdev, "PXENV_UNDI_STARTUP\n" );
+
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_STARTUP called with no "
+		       "network device\n" );
+		undi_startup->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
 	undi_startup->Status = PXENV_STATUS_SUCCESS;
 	return PXENV_EXIT_SUCCESS;
@@ -123,9 +142,19 @@ PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) {
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) {
-	DBG ( "PXENV_UNDI_CLEANUP\n" );
+static PXENV_EXIT_t
+pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) {
+	DBGC ( &pxe_netdev, "PXENV_UNDI_CLEANUP\n" );
+
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_CLEANUP called with no "
+		       "network device\n" );
+		undi_cleanup->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
+	/* Close network device */
 	pxe_netdev_close();
 
 	undi_cleanup->Status = PXENV_STATUS_SUCCESS;
@@ -136,10 +165,18 @@ PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) {
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE
-				     *undi_initialize ) {
-	DBG ( "PXENV_UNDI_INITIALIZE protocolini %08x\n",
-	      undi_initialize->ProtocolIni );
+static PXENV_EXIT_t
+pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE *undi_initialize ) {
+	DBGC ( &pxe_netdev, "PXENV_UNDI_INITIALIZE protocolini %08x\n",
+	       undi_initialize->ProtocolIni );
+
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_INITIALIZE called with no "
+		       "network device\n" );
+		undi_initialize->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
 	undi_initialize->Status = PXENV_STATUS_SUCCESS;
 	return PXENV_EXIT_SUCCESS;
@@ -149,18 +186,27 @@ PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET
-					*undi_reset_adapter ) {
+static PXENV_EXIT_t
+pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET *undi_reset_adapter ) {
 	int rc;
 
-	DBG ( "PXENV_UNDI_RESET_ADAPTER" );
+	DBGC ( &pxe_netdev, "PXENV_UNDI_RESET_ADAPTER" );
 	pxe_dump_mcast_list ( &undi_reset_adapter->R_Mcast_Buf );
-	DBG ( "\n" );
+	DBGC ( &pxe_netdev, "\n" );
 
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_RESET_ADAPTER called with no "
+		       "network device\n" );
+		undi_reset_adapter->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
+
+	/* Close and reopen network device */
 	pxe_netdev_close();
 	if ( ( rc = pxe_netdev_open() ) != 0 ) {
-		DBG ( "PXENV_UNDI_RESET_ADAPTER could not reopen %s: %s\n",
-		      pxe_netdev->name, strerror ( rc ) );
+		DBGC ( &pxe_netdev, "PXENV_UNDI_RESET_ADAPTER could not "
+		       "reopen %s: %s\n", pxe_netdev->name, strerror ( rc ) );
 		undi_reset_adapter->Status = PXENV_STATUS ( rc );
 		return PXENV_EXIT_FAILURE;
 	}
@@ -173,10 +219,19 @@ PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN
-				   *undi_shutdown ) {
-	DBG ( "PXENV_UNDI_SHUTDOWN\n" );
+static PXENV_EXIT_t
+pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN *undi_shutdown ) {
+	DBGC ( &pxe_netdev, "PXENV_UNDI_SHUTDOWN\n" );
+
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_SHUTDOWN called with no "
+		       "network device\n" );
+		undi_shutdown->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
+	/* Close network device */
 	pxe_netdev_close();
 
 	undi_shutdown->Status = PXENV_STATUS_SUCCESS;
@@ -187,17 +242,26 @@ PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) {
+static PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) {
 	int rc;
 
-	DBG ( "PXENV_UNDI_OPEN flag %04x filter %04x",
-	      undi_open->OpenFlag, undi_open->PktFilter );
+	DBGC ( &pxe_netdev, "PXENV_UNDI_OPEN flag %04x filter %04x",
+	       undi_open->OpenFlag, undi_open->PktFilter );
 	pxe_dump_mcast_list ( &undi_open->R_Mcast_Buf );
-	DBG ( "\n" );
+	DBGC ( &pxe_netdev, "\n" );
 
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_OPEN called with no "
+		       "network device\n" );
+		undi_open->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
+
+	/* Open network device */
 	if ( ( rc = pxe_netdev_open() ) != 0 ) {
-		DBG ( "PXENV_UNDI_OPEN could not open %s: %s\n",
-		      pxe_netdev->name, strerror ( rc ) );
+		DBGC ( &pxe_netdev, "PXENV_UNDI_OPEN could not open %s: %s\n",
+		       pxe_netdev->name, strerror ( rc ) );
 		undi_open->Status = PXENV_STATUS ( rc );
 		return PXENV_EXIT_FAILURE;
 	}
@@ -210,9 +274,18 @@ PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) {
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) {
-	DBG ( "PXENV_UNDI_CLOSE\n" );
+static PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) {
+	DBGC ( &pxe_netdev, "PXENV_UNDI_CLOSE\n" );
+
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_CLOSE called with no "
+		       "network device\n" );
+		undi_close->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
+	/* Close network device */
 	pxe_netdev_close();
 
 	undi_close->Status = PXENV_STATUS_SUCCESS;
@@ -223,20 +296,28 @@ PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) {
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
-				   *undi_transmit ) {
+static PXENV_EXIT_t
+pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT *undi_transmit ) {
 	struct s_PXENV_UNDI_TBD tbd;
 	struct DataBlk *datablk;
 	struct io_buffer *iobuf;
 	struct net_protocol *net_protocol;
-	struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
+	struct ll_protocol *ll_protocol;
 	char destaddr[MAX_LL_ADDR_LEN];
 	const void *ll_dest;
 	size_t len;
 	unsigned int i;
 	int rc;
 
-	DBG2 ( "PXENV_UNDI_TRANSMIT" );
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_TRANSMIT called with no "
+		       "network device\n" );
+		undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
+
+	DBGC2 ( &pxe_netdev, "PXENV_UNDI_TRANSMIT" );
 
 	/* Forcibly enable interrupts and freeze receive queue
 	 * processing at this point, to work around callers that never
@@ -254,29 +335,33 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
 		net_protocol = NULL;
 		break;
 	default:
-		DBG2 ( " %02x invalid protocol\n", undi_transmit->Protocol );
+		DBGC2 ( &pxe_netdev, " %02x invalid protocol\n",
+			undi_transmit->Protocol );
 		undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
 		return PXENV_EXIT_FAILURE;
 	}
-	DBG2 ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) );
+	DBGC2 ( &pxe_netdev, " %s",
+		( net_protocol ? net_protocol->name : "RAW" ) );
 
 	/* Calculate total packet length */
 	copy_from_real ( &tbd, undi_transmit->TBD.segment,
 			 undi_transmit->TBD.offset, sizeof ( tbd ) );
 	len = tbd.ImmedLength;
-	DBG2 ( " %04x:%04x+%x", tbd.Xmit.segment, tbd.Xmit.offset,
-	       tbd.ImmedLength );
+	DBGC2 ( &pxe_netdev, " %04x:%04x+%x", tbd.Xmit.segment, tbd.Xmit.offset,
+		tbd.ImmedLength );
 	for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
 		datablk = &tbd.DataBlock[i];
 		len += datablk->TDDataLen;
-		DBG2 ( " %04x:%04x+%x", datablk->TDDataPtr.segment,
-		       datablk->TDDataPtr.offset, datablk->TDDataLen );
+		DBGC2 ( &pxe_netdev, " %04x:%04x+%x",
+			datablk->TDDataPtr.segment, datablk->TDDataPtr.offset,
+			datablk->TDDataLen );
 	}
 
 	/* Allocate and fill I/O buffer */
-	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + len );
+	iobuf = alloc_iob ( MAX_LL_HEADER_LEN +
+			    ( ( len > IOB_ZLEN ) ? len : IOB_ZLEN ) );
 	if ( ! iobuf ) {
-		DBG2 ( " could not allocate iobuf\n" );
+		DBGC2 ( &pxe_netdev, " could not allocate iobuf\n" );
 		undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES;
 		return PXENV_EXIT_FAILURE;
 	}
@@ -295,24 +380,26 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
 	if ( net_protocol != NULL ) {
 
 		/* Calculate destination address */
+		ll_protocol = pxe_netdev->ll_protocol;
 		if ( undi_transmit->XmitFlag == XMT_DESTADDR ) {
 			copy_from_real ( destaddr,
 					 undi_transmit->DestAddr.segment,
 					 undi_transmit->DestAddr.offset,
 					 ll_protocol->ll_addr_len );
 			ll_dest = destaddr;
-			DBG2 ( " DEST %s", ll_protocol->ntoa ( ll_dest ) );
+			DBGC2 ( &pxe_netdev, " DEST %s",
+				ll_protocol->ntoa ( ll_dest ) );
 		} else {
 			ll_dest = pxe_netdev->ll_broadcast;
-			DBG2 ( " BCAST" );
+			DBGC2 ( &pxe_netdev, " BCAST" );
 		}
 
 		/* Add link-layer header */
 		if ( ( rc = ll_protocol->push ( pxe_netdev, iobuf, ll_dest,
 						pxe_netdev->ll_addr,
 						net_protocol->net_proto ))!=0){
-			DBG2 ( " could not add link-layer header: %s\n",
-			       strerror ( rc ) );
+			DBGC2 ( &pxe_netdev, " could not add link-layer "
+				"header: %s\n", strerror ( rc ) );
 			free_iob ( iobuf );
 			undi_transmit->Status = PXENV_STATUS ( rc );
 			return PXENV_EXIT_FAILURE;
@@ -326,10 +413,10 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
 	undi_tx_count++;
 
 	/* Transmit packet */
-	DBG2 ( "\n" );
+	DBGC2 ( &pxe_netdev, "\n" );
 	if ( ( rc = netdev_tx ( pxe_netdev, iobuf ) ) != 0 ) {
-		DBG2 ( "PXENV_UNDI_TRANSMIT could not transmit: %s\n",
-		       strerror ( rc ) );
+		DBGC2 ( &pxe_netdev, "PXENV_UNDI_TRANSMIT could not transmit: "
+			"%s\n", strerror ( rc ) );
 		undi_tx_count--;
 		undi_transmit->Status = PXENV_STATUS ( rc );
 		return PXENV_EXIT_FAILURE;
@@ -343,12 +430,21 @@ PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
  *
  * Status: working (for NICs that support receive-all-multicast)
  */
-PXENV_EXIT_t
+static PXENV_EXIT_t
 pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS
 			       *undi_set_mcast_address ) {
-	DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" );
+	DBGC ( &pxe_netdev, "PXENV_UNDI_SET_MCAST_ADDRESS" );
 	pxe_dump_mcast_list ( &undi_set_mcast_address->R_Mcast_Buf );
-	DBG ( "\n" );
+	DBGC ( &pxe_netdev, "\n" );
+
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_SET_MCAST_ADDRESS called with "
+		       "no network device\n" );
+		undi_set_mcast_address->Status =
+			PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
 	undi_set_mcast_address->Status = PXENV_STATUS_SUCCESS;
 	return PXENV_EXIT_SUCCESS;
@@ -358,19 +454,29 @@ pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS
  *
  * Status: working
  */
-PXENV_EXIT_t 
+static PXENV_EXIT_t
 pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS
 				 *undi_set_station_address ) {
-	struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
+	struct ll_protocol *ll_protocol;
+
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_SET_STATION_ADDRESS called "
+		       "with no network device\n" );
+		undi_set_station_address->Status =
+			PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
-	DBG ( "PXENV_UNDI_SET_STATION_ADDRESS %s",
-	      ll_protocol->ntoa ( undi_set_station_address->StationAddress ) );
+	ll_protocol = pxe_netdev->ll_protocol;
+	DBGC ( &pxe_netdev, "PXENV_UNDI_SET_STATION_ADDRESS %s",
+	       ll_protocol->ntoa ( undi_set_station_address->StationAddress ) );
 
 	/* If adapter is open, the change will have no effect; return
 	 * an error
 	 */
 	if ( netdev_is_open ( pxe_netdev ) ) {
-		DBG ( " failed: netdev is open\n" );
+		DBGC ( &pxe_netdev, " failed: netdev is open\n" );
 		undi_set_station_address->Status =
 			PXENV_STATUS_UNDI_INVALID_STATE;
 		return PXENV_EXIT_FAILURE;
@@ -381,7 +487,7 @@ pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS
 		 &undi_set_station_address->StationAddress,
 		 ll_protocol->ll_addr_len );
 
-	DBG ( "\n" );
+	DBGC ( &pxe_netdev, "\n" );
 	undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
 	return PXENV_EXIT_SUCCESS;
 }
@@ -391,12 +497,21 @@ pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS
  * Status: won't implement (would require driver API changes for no
  * real benefit)
  */
-PXENV_EXIT_t
+static PXENV_EXIT_t
 pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER
 			       *undi_set_packet_filter ) {
 
-	DBG ( "PXENV_UNDI_SET_PACKET_FILTER %02x\n",
-	      undi_set_packet_filter->filter );
+	DBGC ( &pxe_netdev, "PXENV_UNDI_SET_PACKET_FILTER %02x\n",
+	       undi_set_packet_filter->filter );
+
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_SET_PACKET_FILTER called with "
+		       "no network device\n" );
+		undi_set_packet_filter->Status =
+			PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
 	/* Pretend that we succeeded, otherwise the 3Com DOS UNDI
 	 * driver refuses to load.  (We ignore the filter value in the
@@ -411,22 +526,33 @@ pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
-					  *undi_get_information ) {
-	struct device *dev = pxe_netdev->dev;
-	struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
-	size_t ll_addr_len = ll_protocol->ll_addr_len;
+static PXENV_EXIT_t
+pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
+			     *undi_get_information ) {
+	struct device *dev;
+	struct ll_protocol *ll_protocol;
 
-	DBG ( "PXENV_UNDI_GET_INFORMATION" );
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_GET_INFORMATION called with no "
+		       "network device\n" );
+		undi_get_information->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
+	DBGC ( &pxe_netdev, "PXENV_UNDI_GET_INFORMATION" );
+
+	/* Fill in information */
+	dev = pxe_netdev->dev;
+	ll_protocol = pxe_netdev->ll_protocol;
 	undi_get_information->BaseIo = dev->desc.ioaddr;
 	undi_get_information->IntNumber =
 		( netdev_irq_supported ( pxe_netdev ) ? dev->desc.irq : 0 );
 	/* Cheat: assume all cards can cope with this */
 	undi_get_information->MaxTranUnit = ETH_MAX_MTU;
 	undi_get_information->HwType = ntohs ( ll_protocol->ll_proto );
-	undi_get_information->HwAddrLen = ll_addr_len;
-	assert ( ll_addr_len <=
+	undi_get_information->HwAddrLen = ll_protocol->ll_addr_len;
+	assert ( ll_protocol->ll_addr_len <=
 		 sizeof ( undi_get_information->CurrentNodeAddress ) );
 	memcpy ( &undi_get_information->CurrentNodeAddress,
 		 pxe_netdev->ll_addr,
@@ -441,10 +567,10 @@ PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
 	undi_get_information->RxBufCt = 1;
 	undi_get_information->TxBufCt = 1;
 
-	DBG ( " io %04x irq %d mtu %d %s %s\n",
-	      undi_get_information->BaseIo, undi_get_information->IntNumber,
-	      undi_get_information->MaxTranUnit, ll_protocol->name,
-	      ll_protocol->ntoa ( &undi_get_information->CurrentNodeAddress ));
+	DBGC ( &pxe_netdev, " io %04x irq %d mtu %d %s %s\n",
+	       undi_get_information->BaseIo, undi_get_information->IntNumber,
+	       undi_get_information->MaxTranUnit, ll_protocol->name,
+	       ll_protocol->ntoa ( &undi_get_information->CurrentNodeAddress ));
 	undi_get_information->Status = PXENV_STATUS_SUCCESS;
 	return PXENV_EXIT_SUCCESS;
 }
@@ -453,20 +579,31 @@ PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
-					 *undi_get_statistics ) {
-	DBG ( "PXENV_UNDI_GET_STATISTICS" );
+static PXENV_EXIT_t
+pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
+			    *undi_get_statistics ) {
+
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_GET_STATISTICS called with no "
+		       "network device\n" );
+		undi_get_statistics->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
+	DBGC ( &pxe_netdev, "PXENV_UNDI_GET_STATISTICS" );
+
+	/* Report statistics */
 	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;
+	DBGC ( &pxe_netdev, " txok %d rxok %d rxcrc %d rxrsrc %d\n",
+	       undi_get_statistics->XmtGoodFrames,
+	       undi_get_statistics->RcvGoodFrames,
+	       undi_get_statistics->RcvCRCErrors,
+	       undi_get_statistics->RcvResourceErrors );
 
-	DBG ( " txok %d rxok %d rxcrc %d rxrsrc %d\n",
-	      undi_get_statistics->XmtGoodFrames,
-	      undi_get_statistics->RcvGoodFrames,
-	      undi_get_statistics->RcvCRCErrors,
-	      undi_get_statistics->RcvResourceErrors );
 	undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
 	return PXENV_EXIT_SUCCESS;
 }
@@ -475,10 +612,20 @@ PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS
-					   *undi_clear_statistics ) {
-	DBG ( "PXENV_UNDI_CLEAR_STATISTICS\n" );
+static PXENV_EXIT_t
+pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS
+			      *undi_clear_statistics ) {
+	DBGC ( &pxe_netdev, "PXENV_UNDI_CLEAR_STATISTICS\n" );
+
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_CLEAR_STATISTICS called with "
+		       "no network device\n" );
+		undi_clear_statistics->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
+	/* Clear statistics */
 	memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) );
 	memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) );
 
@@ -491,9 +638,18 @@ PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS
  * Status: won't implement (would require driver API changes for no
  * real benefit)
  */
-PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS
-					 *undi_initiate_diags ) {
-	DBG ( "PXENV_UNDI_INITIATE_DIAGS failed: unsupported\n" );
+static PXENV_EXIT_t
+pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS
+			    *undi_initiate_diags ) {
+	DBGC ( &pxe_netdev, "PXENV_UNDI_INITIATE_DIAGS failed: unsupported\n" );
+
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_INITIATE_DIAGS called with no "
+		       "network device\n" );
+		undi_initiate_diags->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
 	undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
 	return PXENV_EXIT_FAILURE;
@@ -504,9 +660,19 @@ PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS
  * Status: won't implement (would require driver API changes for no
  * perceptible benefit)
  */
-PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT
-					  *undi_force_interrupt ) {
-	DBG ( "PXENV_UNDI_FORCE_INTERRUPT failed: unsupported\n" );
+static PXENV_EXIT_t
+pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT
+			     *undi_force_interrupt ) {
+	DBGC ( &pxe_netdev,
+	       "PXENV_UNDI_FORCE_INTERRUPT failed: unsupported\n" );
+
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_FORCE_INTERRUPT called with no "
+		       "network device\n" );
+		undi_force_interrupt->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
 	undi_force_interrupt->Status = PXENV_STATUS_UNSUPPORTED;
 	return PXENV_EXIT_FAILURE;
@@ -516,23 +682,35 @@ PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT
  *
  * Status: working
  */
-PXENV_EXIT_t
+static PXENV_EXIT_t
 pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS
 			       *undi_get_mcast_address ) {
-	struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
+	struct ll_protocol *ll_protocol;
 	struct in_addr ip = { .s_addr = undi_get_mcast_address->InetAddr };
 	int rc;
 
-	DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS %s", inet_ntoa ( ip ) );
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_GET_MCAST_ADDRESS called with "
+		       "no network device\n" );
+		undi_get_mcast_address->Status =
+			PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
+	DBGC ( &pxe_netdev, "PXENV_UNDI_GET_MCAST_ADDRESS %s",
+	       inet_ntoa ( ip ) );
+
+	/* Hash address using the network device's link-layer protocol */
+	ll_protocol = pxe_netdev->ll_protocol;
 	if ( ( rc = ll_protocol->mc_hash ( AF_INET, &ip,
 				      undi_get_mcast_address->MediaAddr ))!=0){
-		DBG ( " failed: %s\n", strerror ( rc ) );
+		DBGC ( &pxe_netdev, " failed: %s\n", strerror ( rc ) );
 		undi_get_mcast_address->Status = PXENV_STATUS ( rc );
 		return PXENV_EXIT_FAILURE;
 	}
-	DBG ( "=>%s\n",
-	      ll_protocol->ntoa ( undi_get_mcast_address->MediaAddr ) );
+	DBGC ( &pxe_netdev, "=>%s\n",
+	       ll_protocol->ntoa ( undi_get_mcast_address->MediaAddr ) );
 
 	undi_get_mcast_address->Status = PXENV_STATUS_SUCCESS;
 	return PXENV_EXIT_SUCCESS;
@@ -542,15 +720,24 @@ pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
-				       *undi_get_nic_type ) {
-	struct device *dev = pxe_netdev->dev;
+static PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
+					      *undi_get_nic_type ) {
+	struct device *dev;
+
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_GET_NIC_TYPE called with "
+		       "no network device\n" );
+		undi_get_nic_type->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
 
-	DBG ( "PXENV_UNDI_GET_NIC_TYPE" );
+	DBGC ( &pxe_netdev, "PXENV_UNDI_GET_NIC_TYPE" );
 
+	/* Fill in information */
 	memset ( &undi_get_nic_type->info, 0,
 		 sizeof ( undi_get_nic_type->info ) );
-
+	dev = pxe_netdev->dev;
 	switch ( dev->desc.bus_type ) {
 	case BUS_TYPE_PCI: {
 		struct pci_nic_info *info = &undi_get_nic_type->info.pci;
@@ -567,13 +754,14 @@ PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
 		 * is possible that some NBPs will not provide space
 		 * for them, and so we must not fill them in.
 		 */
-		DBG ( " PCI %02x:%02x.%x %04x:%04x ('%04x:%04x') %02x%02x%02x "
-		      "rev %02x\n", PCI_BUS ( info->BusDevFunc ),
-		      PCI_SLOT ( info->BusDevFunc ),
-		      PCI_FUNC ( info->BusDevFunc ), info->Vendor_ID,
-		      info->Dev_ID, info->SubVendor_ID, info->SubDevice_ID,
-		      info->Base_Class, info->Sub_Class, info->Prog_Intf,
-		      info->Rev );
+		DBGC ( &pxe_netdev, " PCI %02x:%02x.%x %04x:%04x "
+		       "('%04x:%04x') %02x%02x%02x rev %02x\n",
+		       PCI_BUS ( info->BusDevFunc ),
+		       PCI_SLOT ( info->BusDevFunc ),
+		       PCI_FUNC ( info->BusDevFunc ), info->Vendor_ID,
+		       info->Dev_ID, info->SubVendor_ID, info->SubDevice_ID,
+		       info->Base_Class, info->Sub_Class, info->Prog_Intf,
+		       info->Rev );
 		break; }
 	case BUS_TYPE_ISAPNP: {
 		struct pnp_nic_info *info = &undi_get_nic_type->info.pnp;
@@ -585,12 +773,12 @@ PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
 		/* Cheat: remaining fields are probably unnecessary,
 		 * and would require adding extra code to isapnp.c.
 		 */
-		DBG ( " ISAPnP CSN %04x %08x %02x%02x%02x\n",
-		      info->CardSelNum, info->EISA_Dev_ID,
-		      info->Base_Class, info->Sub_Class, info->Prog_Intf );
+		DBGC ( &pxe_netdev, " ISAPnP CSN %04x %08x %02x%02x%02x\n",
+		       info->CardSelNum, info->EISA_Dev_ID,
+		       info->Base_Class, info->Sub_Class, info->Prog_Intf );
 		break; }
 	default:
-		DBG ( " failed: unknown bus type\n" );
+		DBGC ( &pxe_netdev, " failed: unknown bus type\n" );
 		undi_get_nic_type->Status = PXENV_STATUS_FAILURE;
 		return PXENV_EXIT_FAILURE;
 	}
@@ -603,9 +791,19 @@ PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
-					 *undi_get_iface_info ) {
-	DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
+static PXENV_EXIT_t
+pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
+			    *undi_get_iface_info ) {
+
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxe_netdev, "PXENV_UNDI_GET_IFACE_INFO called with "
+		       "no network device\n" );
+		undi_get_iface_info->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
+
+	DBGC ( &pxe_netdev, "PXENV_UNDI_GET_IFACE_INFO" );
 
 	/* Just hand back some info, doesn't really matter what it is.
 	 * Most PXE stacks seem to take this approach.
@@ -622,44 +820,47 @@ PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
 	memset ( undi_get_iface_info->Reserved, 0,
 		 sizeof(undi_get_iface_info->Reserved) );
 
-	DBG ( " %s %dbps flags %08x\n", undi_get_iface_info->IfaceType,
-	      undi_get_iface_info->LinkSpeed,
-	      undi_get_iface_info->ServiceFlags );
+	DBGC ( &pxe_netdev, " %s %dbps flags %08x\n",
+	       undi_get_iface_info->IfaceType, undi_get_iface_info->LinkSpeed,
+	       undi_get_iface_info->ServiceFlags );
 	undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
 	return PXENV_EXIT_SUCCESS;
 }
 
 /* PXENV_UNDI_GET_STATE
  *
- * Status: impossible
+ * Status: impossible due to opcode collision
  */
-PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
-				    *undi_get_state ) {
-	DBG ( "PXENV_UNDI_GET_STATE failed: unsupported\n" );
-
-	undi_get_state->Status = PXENV_STATUS_UNSUPPORTED;
-	return PXENV_EXIT_FAILURE;
-};
 
 /* PXENV_UNDI_ISR
  *
  * Status: working
  */
-PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
+static 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;
+	unsigned int flags;
 	size_t ll_hlen;
 	struct net_protocol *net_protocol;
 	unsigned int prottype;
 	int rc;
 
-	/* Use coloured debug, since UNDI ISR messages are likely to
-	 * be interspersed amongst other UNDI messages.
+	/* Use a different debug colour, since UNDI ISR messages are
+	 * likely to be interspersed amongst other UNDI messages.
 	 */
+
+	/* Sanity check */
+	if ( ! pxe_netdev ) {
+		DBGC ( &pxenv_undi_isr, "PXENV_UNDI_ISR called with "
+		       "no network device\n" );
+		undi_isr->Status = PXENV_STATUS_UNDI_INVALID_STATE;
+		return PXENV_EXIT_FAILURE;
+	}
+
 	DBGC2 ( &pxenv_undi_isr, "PXENV_UNDI_ISR" );
 
 	/* Just in case some idiot actually looks at these fields when
@@ -753,7 +954,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 ( pxe_netdev, iobuf, &ll_dest,
-						&ll_source, &net_proto )) !=0){
+						&ll_source, &net_proto,
+						&flags ) ) != 0 ) {
 			/* Assume unknown net_proto and no ll_source */
 			net_proto = 0;
 			ll_source = NULL;
@@ -788,14 +990,12 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
 		undi_isr->Frame.segment = rm_ds;
 		undi_isr->Frame.offset = __from_data16 ( basemem_packet );
 		undi_isr->ProtType = prottype;
-		if ( memcmp ( ll_dest, pxe_netdev->ll_addr,
-			      ll_protocol->ll_addr_len ) == 0 ) {
-			undi_isr->PktType = P_DIRECTED;
-		} else if ( memcmp ( ll_dest, pxe_netdev->ll_broadcast,
-				     ll_protocol->ll_addr_len ) == 0 ) {
+		if ( flags & LL_BROADCAST ) {
 			undi_isr->PktType = P_BROADCAST;
-		} else {
+		} else if ( flags & LL_MULTICAST ) {
 			undi_isr->PktType = P_MULTICAST;
+		} else {
+			undi_isr->PktType = P_DIRECTED;
 		}
 		DBGC2 ( &pxenv_undi_isr, " %04x:%04x+%x(%x) %s hlen %d",
 			undi_isr->Frame.segment, undi_isr->Frame.offset,
@@ -820,3 +1020,51 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
 	undi_isr->Status = PXENV_STATUS_SUCCESS;
 	return PXENV_EXIT_SUCCESS;
 }
+
+/** PXE UNDI API */
+struct pxe_api_call pxe_undi_api[] __pxe_api_call = {
+	PXE_API_CALL ( PXENV_UNDI_STARTUP, pxenv_undi_startup,
+		       struct s_PXENV_UNDI_STARTUP ),
+	PXE_API_CALL ( PXENV_UNDI_CLEANUP, pxenv_undi_cleanup,
+		       struct s_PXENV_UNDI_CLEANUP ),
+	PXE_API_CALL ( PXENV_UNDI_INITIALIZE, pxenv_undi_initialize,
+		       struct s_PXENV_UNDI_INITIALIZE ),
+	PXE_API_CALL ( PXENV_UNDI_RESET_ADAPTER, pxenv_undi_reset_adapter,
+		       struct s_PXENV_UNDI_RESET ),
+	PXE_API_CALL ( PXENV_UNDI_SHUTDOWN, pxenv_undi_shutdown,
+		       struct s_PXENV_UNDI_SHUTDOWN ),
+	PXE_API_CALL ( PXENV_UNDI_OPEN, pxenv_undi_open,
+		       struct s_PXENV_UNDI_OPEN ),
+	PXE_API_CALL ( PXENV_UNDI_CLOSE, pxenv_undi_close,
+		       struct s_PXENV_UNDI_CLOSE ),
+	PXE_API_CALL ( PXENV_UNDI_TRANSMIT, pxenv_undi_transmit,
+		       struct s_PXENV_UNDI_TRANSMIT ),
+	PXE_API_CALL ( PXENV_UNDI_SET_MCAST_ADDRESS,
+		       pxenv_undi_set_mcast_address,
+		       struct s_PXENV_UNDI_SET_MCAST_ADDRESS ),
+	PXE_API_CALL ( PXENV_UNDI_SET_STATION_ADDRESS,
+		       pxenv_undi_set_station_address,
+		       struct s_PXENV_UNDI_SET_STATION_ADDRESS ),
+	PXE_API_CALL ( PXENV_UNDI_SET_PACKET_FILTER,
+		       pxenv_undi_set_packet_filter,
+		       struct s_PXENV_UNDI_SET_PACKET_FILTER ),
+	PXE_API_CALL ( PXENV_UNDI_GET_INFORMATION, pxenv_undi_get_information,
+		       struct s_PXENV_UNDI_GET_INFORMATION ),
+	PXE_API_CALL ( PXENV_UNDI_GET_STATISTICS, pxenv_undi_get_statistics,
+		       struct s_PXENV_UNDI_GET_STATISTICS ),
+	PXE_API_CALL ( PXENV_UNDI_CLEAR_STATISTICS, pxenv_undi_clear_statistics,
+		       struct s_PXENV_UNDI_CLEAR_STATISTICS ),
+	PXE_API_CALL ( PXENV_UNDI_INITIATE_DIAGS, pxenv_undi_initiate_diags,
+		       struct s_PXENV_UNDI_INITIATE_DIAGS ),
+	PXE_API_CALL ( PXENV_UNDI_FORCE_INTERRUPT, pxenv_undi_force_interrupt,
+		       struct s_PXENV_UNDI_FORCE_INTERRUPT ),
+	PXE_API_CALL ( PXENV_UNDI_GET_MCAST_ADDRESS,
+		       pxenv_undi_get_mcast_address,
+		       struct s_PXENV_UNDI_GET_MCAST_ADDRESS ),
+	PXE_API_CALL ( PXENV_UNDI_GET_NIC_TYPE, pxenv_undi_get_nic_type,
+		       struct s_PXENV_UNDI_GET_NIC_TYPE ),
+	PXE_API_CALL ( PXENV_UNDI_GET_IFACE_INFO, pxenv_undi_get_iface_info,
+		       struct s_PXENV_UNDI_GET_IFACE_INFO ),
+	PXE_API_CALL ( PXENV_UNDI_ISR, pxenv_undi_isr,
+		       struct s_PXENV_UNDI_ISR ),
+};
diff --git a/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent.c b/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent.c
index e933074435486dd40cf193531caf..8b2a2c880408b8787c4281fde76b 100644
--- a/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent.c
+++ b/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c b/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c
index 8fe1572f2e0b81fcf39d662cc2d0..f372863352cb9be6f2217ed8fb60 100644
--- a/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c
+++ b/roms/ipxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/i386/interface/syslinux/com32_call.c b/roms/ipxe/src/arch/i386/interface/syslinux/com32_call.c
index 47df64cb9ba4af4319e514da9e61..8fffd0692bda100b6519cbf9c8f7 100644
--- a/roms/ipxe/src/arch/i386/interface/syslinux/com32_call.c
+++ b/roms/ipxe/src/arch/i386/interface/syslinux/com32_call.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 /**
diff --git a/roms/ipxe/src/arch/i386/interface/syslinux/com32_wrapper.S b/roms/ipxe/src/arch/i386/interface/syslinux/com32_wrapper.S
index 4cd882215aa9bd4334aa18e86fcd..69cea02e8ab40db99630f96957a2 100644
--- a/roms/ipxe/src/arch/i386/interface/syslinux/com32_wrapper.S
+++ b/roms/ipxe/src/arch/i386/interface/syslinux/com32_wrapper.S
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER )
diff --git a/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c b/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c
index 571ba9e6db3a72effad682ea81c2..fbf605f3348a80dcd9dd331b3914 100644
--- a/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c
+++ b/roms/ipxe/src/arch/i386/interface/syslinux/comboot_call.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 /**
@@ -38,12 +39,13 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/serial.h>
 #include <ipxe/init.h>
 #include <ipxe/image.h>
+#include <ipxe/version.h>
 #include <usr/imgmgmt.h>
 #include "config/console.h"
 #include "config/serial.h"
 
 /** The "SYSLINUX" version string */
-static char __data16_array ( syslinux_version, [] ) = "\r\niPXE " VERSION;
+static char __bss16_array ( syslinux_version, [32] );
 #define syslinux_version __use_data16 ( syslinux_version )
 
 /** The "SYSLINUX" copyright string */
@@ -166,6 +168,8 @@ void comboot_force_text_mode ( void ) {
  * Fetch kernel and optional initrd
  */
 static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
+	struct image *kernel;
+	struct image *initrd;
 	char *initrd_file;
 	int rc;
 
@@ -184,8 +188,7 @@ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
 		DBG ( "COMBOOT: fetching initrd '%s'\n", initrd_file );
 
 		/* Fetch initrd */
-		if ( ( rc = imgdownload_string ( initrd_file, NULL, NULL,
-						 register_and_put_image ))!=0){
+		if ( ( rc = imgdownload_string ( initrd_file, &initrd ) ) != 0){
 			DBG ( "COMBOOT: could not fetch initrd: %s\n",
 			      strerror ( rc ) );
 			return rc;
@@ -198,14 +201,20 @@ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
 
 	DBG ( "COMBOOT: fetching kernel '%s'\n", kernel_file );
 
-	/* Allocate and fetch kernel */
-	if ( ( rc = imgdownload_string ( kernel_file, NULL, cmdline,
-					 register_and_replace_image ) ) != 0 ) {
+	/* Fetch kernel */
+	if ( ( rc = imgdownload_string ( kernel_file, &kernel ) ) != 0 ) {
 		DBG ( "COMBOOT: could not fetch kernel: %s\n",
 		      strerror ( rc ) );
 		return rc;
 	}
 
+	/* Replace comboot image with kernel */
+	if ( ( rc = image_replace ( kernel ) ) != 0 ) {
+		DBG ( "COMBOOT: could not replace with kernel: %s\n",
+		      strerror ( rc ) );
+		return rc;
+	}
+
 	return 0;
 }
 
@@ -318,6 +327,10 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) {
 		/* SYSLINUX derivative ID */
 		ix86->regs.dl = BZI_LOADER_TYPE_IPXE;
 
+		/* SYSLINUX version */
+		snprintf ( syslinux_version, sizeof ( syslinux_version ),
+			   "\r\niPXE %s", product_version );
+
 		/* SYSLINUX version and copyright strings */
 		ix86->segs.es = rm_ds;
 		ix86->regs.si = ( ( unsigned ) __from_data16 ( syslinux_version ) );
diff --git a/roms/ipxe/src/arch/i386/interface/vmware/guestinfo.c b/roms/ipxe/src/arch/i386/interface/vmware/guestinfo.c
new file mode 100644
index 0000000000000000000000000000000000000000..5e08d9471152dfc6760556e31c9d026a473d891c
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/interface/vmware/guestinfo.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * VMware GuestInfo settings
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/init.h>
+#include <ipxe/settings.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/guestrpc.h>
+
+/** GuestInfo GuestRPC channel */
+static int guestinfo_channel;
+
+/**
+ * Fetch value of typed GuestInfo setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to fetch
+ * @v type		Setting type to attempt (or NULL for default)
+ * @v data		Buffer to fill with setting data
+ * @v len		Length of buffer
+ * @ret found		Setting found in GuestInfo
+ * @ret len		Length of setting data, or negative error
+ */
+static int guestinfo_fetch_type ( struct settings *settings,
+				  struct setting *setting,
+				  struct setting_type *type,
+				  void *data, size_t len, int *found ) {
+	const char *parent_name = settings->parent->name;
+	char command[ 24 /* "info-get guestinfo.ipxe." */ +
+		      strlen ( parent_name ) + 1 /* "." */ +
+		      strlen ( setting->name ) + 1 /* "." */ +
+		      ( type ? strlen ( type->name ) : 0 ) + 1 /* NUL */ ];
+	struct setting *named_setting;
+	char *info;
+	int info_len;
+	int check_len;
+	int ret;
+
+	/* Construct info-get command */
+	snprintf ( command, sizeof ( command ),
+		   "info-get guestinfo.ipxe.%s%s%s%s%s",
+		   parent_name, ( parent_name[0] ? "." : "" ), setting->name,
+		   ( type ? "." : "" ), ( type ? type->name : "" ) );
+
+	/* Check for existence and obtain length of GuestInfo value */
+	info_len = guestrpc_command ( guestinfo_channel, command, NULL, 0 );
+	if ( info_len < 0 ) {
+		ret = info_len;
+		goto err_get_info_len;
+	}
+
+	/* Mark as found */
+	*found = 1;
+
+	/* Determine default type if necessary */
+	if ( ! type ) {
+		named_setting = find_setting ( setting->name );
+		type = ( named_setting ?
+			 named_setting->type : &setting_type_string );
+	}
+	assert ( type != NULL );
+
+	/* Allocate temporary block to hold GuestInfo value */
+	info = zalloc ( info_len + 1 /* NUL */ );
+	if ( ! info ) {
+		DBGC ( settings, "GuestInfo %p could not allocate %d bytes\n",
+		       settings, info_len );
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+	info[info_len] = '\0';
+
+	/* Fetch GuestInfo value */
+	check_len = guestrpc_command ( guestinfo_channel, command,
+				       info, info_len );
+	if ( check_len < 0 ) {
+		ret = check_len;
+		goto err_get_info;
+	}
+	if ( check_len != info_len ) {
+		DBGC ( settings, "GuestInfo %p length mismatch (expected %d, "
+		       "got %d)\n", settings, info_len, check_len );
+		ret = -EIO;
+		goto err_get_info;
+	}
+	DBGC2 ( settings, "GuestInfo %p found %s = \"%s\"\n",
+		settings, &command[9] /* Skip "info-get " */, info );
+
+	/* Parse GuestInfo value according to type */
+	ret = type->parse ( info, data, len );
+	if ( ret < 0 ) {
+		DBGC ( settings, "GuestInfo %p could not parse \"%s\" as %s: "
+		       "%s\n", settings, info, type->name, strerror ( ret ) );
+		goto err_parse;
+	}
+
+ err_parse:
+ err_get_info:
+	free ( info );
+ err_alloc:
+ err_get_info_len:
+	return ret;
+}
+
+/**
+ * Fetch value of GuestInfo 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 guestinfo_fetch ( struct settings *settings,
+			     struct setting *setting,
+			     void *data, size_t len ) {
+	struct setting_type *type;
+	int found = 0;
+	int ret;
+
+	/* Try default type first */
+	ret = guestinfo_fetch_type ( settings, setting, NULL,
+				     data, len, &found );
+	if ( found )
+		return ret;
+
+	/* Otherwise, try all possible types */
+	for_each_table_entry ( type, SETTING_TYPES ) {
+		ret = guestinfo_fetch_type ( settings, setting, type,
+					     data, len, &found );
+		if ( found )
+			return ret;
+	}
+
+	/* Not found */
+	return -ENOENT;
+}
+
+/** GuestInfo settings operations */
+static struct settings_operations guestinfo_settings_operations = {
+	.fetch = guestinfo_fetch,
+};
+
+/** GuestInfo settings */
+static struct settings guestinfo_settings = {
+	.refcnt = NULL,
+	.siblings = LIST_HEAD_INIT ( guestinfo_settings.siblings ),
+	.children = LIST_HEAD_INIT ( guestinfo_settings.children ),
+	.op = &guestinfo_settings_operations,
+};
+
+/** Initialise GuestInfo settings */
+static void guestinfo_init ( void ) {
+	int rc;
+
+	/* Open GuestRPC channel */
+	guestinfo_channel = guestrpc_open();
+	if ( guestinfo_channel < 0 ) {
+		rc = guestinfo_channel;
+		DBG ( "GuestInfo could not open channel: %s\n",
+		      strerror ( rc ) );
+		return;
+	}
+
+	/* Register root GuestInfo settings */
+	if ( ( rc = register_settings ( &guestinfo_settings, NULL,
+					"vmware" ) ) != 0 ) {
+		DBG ( "GuestInfo could not register settings: %s\n",
+		      strerror ( rc ) );
+		return;
+	}
+}
+
+/** GuestInfo settings initialiser */
+struct init_fn guestinfo_init_fn __init_fn ( INIT_NORMAL ) = {
+	.initialise = guestinfo_init,
+};
+
+/**
+ * Create per-netdevice GuestInfo settings
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int guestinfo_net_probe ( struct net_device *netdev ) {
+	struct settings *settings;
+	int rc;
+
+	/* Do nothing unless we have a GuestInfo channel available */
+	if ( guestinfo_channel < 0 )
+		return 0;
+
+	/* Allocate and initialise settings block */
+	settings = zalloc ( sizeof ( *settings ) );
+	if ( ! settings ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	settings_init ( settings, &guestinfo_settings_operations, NULL, 0 );
+
+	/* Register settings */
+	if ( ( rc = register_settings ( settings, netdev_settings ( netdev ),
+					"vmware" ) ) != 0 ) {
+		DBGC ( settings, "GuestInfo %p could not register for %s: %s\n",
+		       settings, netdev->name, strerror ( rc ) );
+		goto err_register;
+	}
+	DBGC ( settings, "GuestInfo %p registered for %s\n",
+	       settings, netdev->name );
+
+	return 0;
+
+ err_register:
+	free ( settings );
+ err_alloc:
+	return rc;
+}
+
+/**
+ * Handle network device or link state change
+ *
+ * @v netdev		Network device
+ */
+static void guestinfo_net_notify ( struct net_device *netdev __unused ) {
+	/* Nothing to do */
+}
+
+/**
+ * Remove per-netdevice GuestInfo settings
+ *
+ * @v netdev		Network device
+ */
+static void guestinfo_net_remove ( struct net_device *netdev ) {
+	struct settings *parent = netdev_settings ( netdev );
+	struct settings *settings;
+
+	list_for_each_entry ( settings, &parent->children, siblings ) {
+		if ( settings->op == &guestinfo_settings_operations ) {
+			DBGC ( settings, "GuestInfo %p unregistered for %s\n",
+			       settings, netdev->name );
+			unregister_settings ( settings );
+			free ( settings );
+			return;
+		}
+	}
+}
+
+/** GuestInfo per-netdevice driver */
+struct net_driver guestinfo_net_driver __net_driver = {
+	.name = "GuestInfo",
+	.probe = guestinfo_net_probe,
+	.notify = guestinfo_net_notify,
+	.remove = guestinfo_net_remove,
+};
diff --git a/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c b/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c
new file mode 100644
index 0000000000000000000000000000000000000000..390fc5545c34ba4db1fc76ebd17f66533714a90a
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * VMware GuestRPC mechanism
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/vmware.h>
+#include <ipxe/guestrpc.h>
+
+/* Disambiguate the various error causes */
+#define EPROTO_OPEN __einfo_error ( EINFO_EPROTO_OPEN )
+#define EINFO_EPROTO_OPEN \
+	__einfo_uniqify ( EINFO_EPROTO, 0x00, "GuestRPC open failed" )
+#define EPROTO_COMMAND_LEN __einfo_error ( EINFO_EPROTO_COMMAND_LEN )
+#define EINFO_EPROTO_COMMAND_LEN \
+	__einfo_uniqify ( EINFO_EPROTO, 0x01, "GuestRPC command length failed" )
+#define EPROTO_COMMAND_DATA __einfo_error ( EINFO_EPROTO_COMMAND_DATA )
+#define EINFO_EPROTO_COMMAND_DATA \
+	__einfo_uniqify ( EINFO_EPROTO, 0x02, "GuestRPC command data failed" )
+#define EPROTO_REPLY_LEN __einfo_error ( EINFO_EPROTO_REPLY_LEN )
+#define EINFO_EPROTO_REPLY_LEN \
+	__einfo_uniqify ( EINFO_EPROTO, 0x03, "GuestRPC reply length failed" )
+#define EPROTO_REPLY_DATA __einfo_error ( EINFO_EPROTO_REPLY_DATA )
+#define EINFO_EPROTO_REPLY_DATA \
+	__einfo_uniqify ( EINFO_EPROTO, 0x04, "GuestRPC reply data failed" )
+#define EPROTO_REPLY_FINISH __einfo_error ( EINFO_EPROTO_REPLY_FINISH )
+#define EINFO_EPROTO_REPLY_FINISH \
+	__einfo_uniqify ( EINFO_EPROTO, 0x05, "GuestRPC reply finish failed" )
+#define EPROTO_CLOSE __einfo_error ( EINFO_EPROTO_CLOSE )
+#define EINFO_EPROTO_CLOSE \
+	__einfo_uniqify ( EINFO_EPROTO, 0x06, "GuestRPC close failed" )
+
+/**
+ * Open GuestRPC channel
+ *
+ * @ret channel		Channel number, or negative error
+ */
+int guestrpc_open ( void ) {
+	uint16_t channel;
+	uint32_t discard_b;
+	uint32_t status;
+
+	/* Issue GuestRPC command */
+	status = vmware_cmd_guestrpc ( 0, GUESTRPC_OPEN, GUESTRPC_MAGIC,
+				       &channel, &discard_b );
+	if ( status != GUESTRPC_OPEN_SUCCESS ) {
+		DBGC ( GUESTRPC_MAGIC, "GuestRPC open failed: status %08x\n",
+		       status );
+		return -EPROTO_OPEN;
+	}
+
+	DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d opened\n", channel );
+	return channel;
+}
+
+/**
+ * Send GuestRPC command length
+ *
+ * @v channel		Channel number
+ * @v len		Command length
+ * @ret rc		Return status code
+ */
+static int guestrpc_command_len ( int channel, size_t len ) {
+	uint16_t discard_d;
+	uint32_t discard_b;
+	uint32_t status;
+
+	/* Issue GuestRPC command */
+	status = vmware_cmd_guestrpc ( channel, GUESTRPC_COMMAND_LEN, len,
+				       &discard_d, &discard_b );
+	if ( status != GUESTRPC_COMMAND_LEN_SUCCESS ) {
+		DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d send command "
+		       "length %zd failed: status %08x\n",
+		       channel, len, status );
+		return -EPROTO_COMMAND_LEN;
+	}
+
+	return 0;
+}
+
+/**
+ * Send GuestRPC command data
+ *
+ * @v channel		Channel number
+ * @v data		Command data
+ * @ret rc		Return status code
+ */
+static int guestrpc_command_data ( int channel, uint32_t data ) {
+	uint16_t discard_d;
+	uint32_t discard_b;
+	uint32_t status;
+
+	/* Issue GuestRPC command */
+	status = vmware_cmd_guestrpc ( channel, GUESTRPC_COMMAND_DATA, data,
+				       &discard_d, &discard_b );
+	if ( status != GUESTRPC_COMMAND_DATA_SUCCESS ) {
+		DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d send command "
+		       "data %08x failed: status %08x\n",
+		       channel, data, status );
+		return -EPROTO_COMMAND_DATA;
+	}
+
+	return 0;
+}
+
+/**
+ * Receive GuestRPC reply length
+ *
+ * @v channel		Channel number
+ * @ret reply_id	Reply ID
+ * @ret len		Reply length, or negative error
+ */
+static int guestrpc_reply_len ( int channel, uint16_t *reply_id ) {
+	uint32_t len;
+	uint32_t status;
+
+	/* Issue GuestRPC command */
+	status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_LEN, 0,
+				       reply_id, &len );
+	if ( status != GUESTRPC_REPLY_LEN_SUCCESS ) {
+		DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d receive reply "
+		       "length failed: status %08x\n", channel, status );
+		return -EPROTO_REPLY_LEN;
+	}
+
+	return len;
+}
+
+/**
+ * Receive GuestRPC reply data
+ *
+ * @v channel		Channel number
+ * @v reply_id		Reply ID
+ * @ret data		Reply data
+ * @ret rc		Return status code
+ */
+static int guestrpc_reply_data ( int channel, uint16_t reply_id,
+				 uint32_t *data ) {
+	uint16_t discard_d;
+	uint32_t status;
+
+	/* Issue GuestRPC command */
+	status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_DATA, reply_id,
+				       &discard_d, data );
+	if ( status != GUESTRPC_REPLY_DATA_SUCCESS ) {
+		DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d receive reply "
+		       "%d data failed: status %08x\n",
+		       channel, reply_id, status );
+		return -EPROTO_REPLY_DATA;
+	}
+
+	return 0;
+}
+
+/**
+ * Finish receiving GuestRPC reply
+ *
+ * @v channel		Channel number
+ * @v reply_id		Reply ID
+ * @ret rc		Return status code
+ */
+static int guestrpc_reply_finish ( int channel, uint16_t reply_id ) {
+	uint16_t discard_d;
+	uint32_t discard_b;
+	uint32_t status;
+
+	/* Issue GuestRPC command */
+	status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_FINISH, reply_id,
+				       &discard_d, &discard_b );
+	if ( status != GUESTRPC_REPLY_FINISH_SUCCESS ) {
+		DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d finish reply %d "
+		       "failed: status %08x\n", channel, reply_id, status );
+		return -EPROTO_REPLY_FINISH;
+	}
+
+	return 0;
+}
+
+/**
+ * Close GuestRPC channel
+ *
+ * @v channel		Channel number
+ */
+void guestrpc_close ( int channel ) {
+	uint16_t discard_d;
+	uint32_t discard_b;
+	uint32_t status;
+
+	/* Issue GuestRPC command */
+	status = vmware_cmd_guestrpc ( channel, GUESTRPC_CLOSE, 0,
+				       &discard_d, &discard_b );
+	if ( status != GUESTRPC_CLOSE_SUCCESS ) {
+		DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d close failed: "
+		       "status %08x\n", channel, status );
+		return;
+	}
+
+	DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d closed\n", channel );
+}
+
+/**
+ * Issue GuestRPC command
+ *
+ * @v channel		Channel number
+ * @v command		Command
+ * @v reply		Reply buffer
+ * @v reply_len		Length of reply buffer
+ * @ret len		Length of reply, or negative error
+ *
+ * The actual length of the reply will be returned even if the buffer
+ * was too small.
+ */
+int guestrpc_command ( int channel, const char *command, char *reply,
+		       size_t reply_len ) {
+	const uint8_t *command_bytes = ( ( const void * ) command );
+	uint8_t *reply_bytes = ( ( void * ) reply );
+	size_t command_len = strlen ( command );
+	int orig_reply_len = reply_len;
+	uint16_t status;
+	uint8_t *status_bytes = ( ( void * ) &status );
+	size_t status_len = sizeof ( status );
+	uint32_t data;
+	uint16_t reply_id;
+	int len;
+	int remaining;
+	unsigned int i;
+	int rc;
+
+	DBGC2 ( GUESTRPC_MAGIC, "GuestRPC channel %d issuing command:\n",
+		channel );
+	DBGC2_HDA ( GUESTRPC_MAGIC, 0, command, command_len );
+
+	/* Sanity check */
+	assert ( ( reply != NULL ) || ( reply_len == 0 ) );
+
+	/* Send command length */
+	if ( ( rc = guestrpc_command_len ( channel, command_len ) ) < 0 )
+		return rc;
+
+	/* Send command data */
+	while ( command_len ) {
+		data = 0;
+		for ( i = sizeof ( data ) ; i ; i-- ) {
+			if ( command_len ) {
+				data = ( ( data & ~0xff ) |
+					 *(command_bytes++) );
+				command_len--;
+			}
+			data = ( ( data << 24 ) | ( data >> 8 ) );
+		}
+		if ( ( rc = guestrpc_command_data ( channel, data ) ) < 0 )
+			return rc;
+	}
+
+	/* Receive reply length */
+	if ( ( len = guestrpc_reply_len ( channel, &reply_id ) ) < 0 ) {
+		rc = len;
+		return rc;
+	}
+
+	/* Receive reply */
+	for ( remaining = len ; remaining > 0 ; remaining -= sizeof ( data ) ) {
+		if ( ( rc = guestrpc_reply_data ( channel, reply_id,
+						  &data ) ) < 0 ) {
+			return rc;
+		}
+		for ( i = sizeof ( data ) ; i ; i-- ) {
+			if ( status_len ) {
+				*(status_bytes++) = ( data & 0xff );
+				status_len--;
+				len--;
+			} else if ( reply_len ) {
+				*(reply_bytes++) = ( data & 0xff );
+				reply_len--;
+			}
+			data = ( ( data << 24 ) | ( data >> 8 ) );
+		}
+	}
+
+	/* Finish receiving RPC reply */
+	if ( ( rc = guestrpc_reply_finish ( channel, reply_id ) ) < 0 )
+		return rc;
+
+	DBGC2 ( GUESTRPC_MAGIC, "GuestRPC channel %d received reply (id %d, "
+		"length %d):\n", channel, reply_id, len );
+	DBGC2_HDA ( GUESTRPC_MAGIC, 0, &status, sizeof ( status ) );
+	DBGC2_HDA ( GUESTRPC_MAGIC, sizeof ( status ), reply,
+		    ( ( len < orig_reply_len ) ? len : orig_reply_len ) );
+
+	/* Check reply status */
+	if ( status != GUESTRPC_SUCCESS ) {
+		DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d command failed "
+		       "(status %04x, reply id %d, reply length %d):\n",
+		       channel, status, reply_id, len );
+		DBGC_HDA ( GUESTRPC_MAGIC, 0, command, command_len );
+		DBGC_HDA ( GUESTRPC_MAGIC, 0, &status, sizeof ( status ) );
+		DBGC_HDA ( GUESTRPC_MAGIC, sizeof ( status ), reply,
+			   ( ( len < orig_reply_len ) ? len : orig_reply_len ));
+		return -EIO;
+	}
+
+	return len;
+}
diff --git a/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c b/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c
new file mode 100644
index 0000000000000000000000000000000000000000..485105200148f8958183d54aed2bcc674610ce18
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * VMware logfile console
+ *
+ */
+
+#include <string.h>
+#include <ipxe/console.h>
+#include <ipxe/lineconsole.h>
+#include <ipxe/init.h>
+#include <ipxe/guestrpc.h>
+#include <config/console.h>
+
+/** VMware logfile console buffer size */
+#define VMCONSOLE_BUFSIZE 128
+
+/* Set default console usage if applicable */
+#if ! ( defined ( CONSOLE_VMWARE ) && CONSOLE_EXPLICIT ( CONSOLE_VMWARE ) )
+#undef CONSOLE_VMWARE
+#define CONSOLE_VMWARE ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_TUI )
+#endif
+
+/** VMware logfile console GuestRPC channel */
+static int vmconsole_channel;
+
+/** VMware logfile console line buffer */
+static struct {
+	char prefix[4];
+	char message[VMCONSOLE_BUFSIZE];
+} vmconsole_buffer = {
+	.prefix = "log ",
+};
+
+/** VMware logfile console ANSI escape sequence handlers */
+static struct ansiesc_handler vmconsole_handlers[] = {
+	{ 0, NULL }
+};
+
+/** VMware logfile line console */
+static struct line_console vmconsole_line = {
+	.buffer = vmconsole_buffer.message,
+	.len = sizeof ( vmconsole_buffer.message ),
+	.ctx = {
+		.handlers = vmconsole_handlers,
+	},
+};
+
+/** VMware logfile console recursion marker */
+static int vmconsole_entered;
+
+/**
+ * Print a character to VMware logfile console
+ *
+ * @v character		Character to be printed
+ */
+static void vmconsole_putchar ( int character ) {
+	int rc;
+
+	/* Ignore if we are already mid-logging */
+	if ( vmconsole_entered )
+		return;
+
+	/* Fill line buffer */
+	if ( line_putchar ( &vmconsole_line, character ) == 0 )
+		return;
+
+	/* Guard against re-entry */
+	vmconsole_entered = 1;
+
+	/* Send log message */
+	if ( ( rc = guestrpc_command ( vmconsole_channel,
+				       vmconsole_buffer.prefix, NULL, 0 ) ) <0){
+		DBG ( "VMware console could not send log message: %s\n",
+		      strerror ( rc ) );
+	}
+
+	/* Clear re-entry flag */
+	vmconsole_entered = 0;
+}
+
+/** VMware logfile console driver */
+struct console_driver vmconsole __console_driver = {
+	.putchar = vmconsole_putchar,
+	.disabled = 1,
+	.usage = CONSOLE_VMWARE,
+};
+
+/**
+ * Initialise VMware logfile console
+ *
+ */
+static void vmconsole_init ( void ) {
+	int rc;
+
+	/* Attempt to open console */
+	vmconsole_channel = guestrpc_open();
+	if ( vmconsole_channel < 0 ) {
+		rc = vmconsole_channel;
+		DBG ( "VMware console could not be initialised: %s\n",
+		      strerror ( rc ) );
+		return;
+	}
+
+	/* Mark console as available */
+	vmconsole.disabled = 0;
+}
+
+/**
+ * VMware logfile console initialisation function
+ */
+struct init_fn vmconsole_init_fn __init_fn ( INIT_CONSOLE ) = {
+	.initialise = vmconsole_init,
+};
diff --git a/roms/ipxe/src/arch/i386/interface/vmware/vmware.c b/roms/ipxe/src/arch/i386/interface/vmware/vmware.c
new file mode 100644
index 0000000000000000000000000000000000000000..8074e6118f525c6c306ea0f5077198f3284d955f
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/interface/vmware/vmware.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * VMware backdoor mechanism
+ *
+ * Based on the unofficial documentation at
+ *
+ *   http://sites.google.com/site/chitchatvmback/backdoor
+ *
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <ipxe/vmware.h>
+
+/**
+ * Detect VMware presence
+ *
+ * @ret rc		Return status code
+ */
+int vmware_present ( void ) {
+	uint32_t version;
+	uint32_t magic;
+	uint32_t product_type;
+
+	/* Perform backdoor call */
+	vmware_cmd_get_version ( &version, &magic, &product_type );
+
+	/* Check for VMware presence */
+	if ( magic != VMW_MAGIC ) {
+		DBGC ( VMW_MAGIC, "VMware not present\n" );
+		return -ENOENT;
+	}
+
+	DBGC ( VMW_MAGIC, "VMware product type %04x version %08x detected\n",
+	       product_type, version );
+	return 0;
+}
diff --git a/roms/ipxe/src/arch/i386/prefix/exeprefix.S b/roms/ipxe/src/arch/i386/prefix/exeprefix.S
index c7e57cee508787774b37de4c8209..cb61287d315b574103004e6f3749 100644
--- a/roms/ipxe/src/arch/i386/prefix/exeprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/exeprefix.S
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  *
  */
 
@@ -113,7 +114,7 @@ _exe_start:
 	call	alloc_basemem
 	xorl	%esi, %esi
 	movl	$EXE_DECOMPRESS_ADDRESS, %edi
-	clc
+	orl	$0xffffffff, %ebp	/* Allow arbitrary relocation */
 	call	install_prealloc
 
 	/* Set up real-mode stack */
diff --git a/roms/ipxe/src/arch/i386/prefix/kkkpxeprefix.S b/roms/ipxe/src/arch/i386/prefix/kkkpxeprefix.S
new file mode 100644
index 0000000000000000000000000000000000000000..27ed231e7d5a66ffabde887ce67a4f3bc9e4e205
--- /dev/null
+++ b/roms/ipxe/src/arch/i386/prefix/kkkpxeprefix.S
@@ -0,0 +1,19 @@
+/*****************************************************************************
+ * PXE prefix that keeps the whole PXE stack present and provides an exit hook
+ *
+ * This prefix is essentially intended solely for the case of ipxelinux.0
+ *****************************************************************************
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER )
+
+/* Since we have the whole stack, we can use cached DHCP information */
+REQUIRE_OBJECT ( pxeparent_dhcp )
+
+/* Provide the PXENV_FILE_EXIT_HOOK API call */
+REQUIRE_OBJECT ( pxe_exit_hook )
+
+#define PXELOADER_KEEP_UNDI
+#define PXELOADER_KEEP_PXE
+#define _pxe_start _kkkpxe_start
+#include "pxeprefix.S"
diff --git a/roms/ipxe/src/arch/i386/prefix/libprefix.S b/roms/ipxe/src/arch/i386/prefix/libprefix.S
index 77151a67e0bb75a63d468f29d0f9..197a86bc8e8a9b8215878a20c469 100644
--- a/roms/ipxe/src/arch/i386/prefix/libprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/libprefix.S
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  *
  */
 
@@ -49,7 +50,7 @@ FILE_LICENCE ( GPL2_OR_LATER )
 	.section ".prefix.data", "aw", @progbits
 progress_\@:
 	.asciz	"\message"
-	.size	progress_\@, . - progress\@
+	.size	progress_\@, . - progress_\@
 	.previous
 	.endm
 #endif
@@ -326,7 +327,6 @@ process_bytes:
 #ifndef KEEP_IT_REAL
 
 	/* Preserve registers */
-	pushfw
 	pushl	%eax
 	pushl	%ebp
 
@@ -397,7 +397,6 @@ process_bytes:
 	/* Restore registers and return */
 	popl	%ebp
 	popl	%eax
-	popfw
 	ret
 
 #else /* KEEP_IT_REAL */
@@ -546,8 +545,7 @@ alloc_basemem:
  * Free space allocated with alloc_basemem.
  *
  * Parameters:
- *   %ax : .text16 segment address
- *   %bx : .data16 segment address
+ *   none (.text16 segment address is implicit in %cs)
  * Returns:
  *   %ax : 0 if successfully freed
  * Corrupts:
@@ -560,14 +558,14 @@ alloc_basemem:
 free_basemem:
 	/* Preserve registers */
 	pushw	%fs
+	pushw	%ax
 
 	/* Check FBMS counter */
-	pushw	%ax
+	movw	%cs, %ax
 	shrw	$6, %ax
 	pushw	$0x40
 	popw	%fs
 	cmpw	%ax, %fs:0x13
-	popw	%ax
 	jne	1f
 
 	/* Check hooked interrupt count */
@@ -575,6 +573,7 @@ free_basemem:
 	jne	1f
 
 	/* OK to free memory */
+	movw	%cs, %ax
 	addw	$_text16_memsz_pgh, %ax
 	addw	$_data16_memsz_pgh, %ax
 	shrw	$6, %ax
@@ -582,6 +581,7 @@ free_basemem:
 	xorw	%ax, %ax
 
 1:	/* Restore registers and return */
+	popw	%ax
 	popw	%fs
 	ret
 	.size free_basemem, . - free_basemem
@@ -614,17 +614,19 @@ install:
 	/* Preserve registers */
 	pushl	%esi
 	pushl	%edi
+	pushl	%ebp
 	/* Allocate space for .text16 and .data16 */
 	call	alloc_basemem
 	/* Image source = %cs:0000 */
 	xorl	%esi, %esi
 	/* Image destination = default */
 	xorl	%edi, %edi
-	/* Allow relocation */
-	clc
+	/* Allow arbitrary relocation */
+	orl	$0xffffffff, %ebp
 	/* Install text and data segments */
 	call	install_prealloc
 	/* Restore registers and return */
+	popl	%ebp
 	popl	%edi
 	popl	%esi
 	ret
@@ -640,7 +642,9 @@ install:
  *   %bx  : .data16 segment address
  *   %esi : Image source physical address (or zero for %cs:0000)
  *   %edi : Decompression temporary area physical address (or zero for default)
- *   CF set : Avoid relocating to top of memory
+ *   %ebp : Maximum end address for relocation
+ *          - 0xffffffff for no maximum
+ *          - 0x00000000 to inhibit use of INT 15,e820 and INT 15,e801
  * Corrupts:
  *   none
  ****************************************************************************
@@ -655,27 +659,30 @@ install_prealloc:
 	pushw	%ds
 	pushw	%es
 	cld			/* Sanity: clear the direction flag asap */
-	pushfw
 
 	/* Set up %ds for (read-only) access to .prefix */
 	pushw	%cs
 	popw	%ds
 
-	/* Copy decompression temporary area physical address to %ebp */
-	movl	%edi, %ebp
+	/* Save decompression temporary area physical address */
+	pushl	%edi
 
-	/* Install .text16.early */
+	/* Install .text16.early and calculate %ecx as offset to next block */
 	progress "  .text16.early\n"
 	pushl	%esi
 	xorl	%esi, %esi
 	movw	%cs, %si
 	shll	$4, %esi
+	pushl	%esi			/* Save original %cs:0000 */
 	addl	$_text16_early_lma, %esi
 	movzwl	%ax, %edi
 	shll	$4, %edi
 	movl	$_text16_early_filesz, %ecx
 	movl	$_text16_early_memsz, %edx
 	call	install_block		/* .text16.early */
+	popl	%ecx			/* Calculate offset to next block */
+	subl	%esi, %ecx
+	negl	%ecx
 	popl	%esi
 
 #ifndef KEEP_IT_REAL
@@ -730,7 +737,7 @@ payload_death_message:
 	jnz	1f
 	movw	%cs, %si
 	shll	$4, %esi
-1:	addl	payload_lma, %esi
+1:	addl	%ecx, %esi
 
 	/* Install .text16.late and .data16 */
 	progress "  .text16.late\n"
@@ -747,6 +754,9 @@ payload_death_message:
 	/* Set up %ds for access to .data16 */
 	movw	%bx, %ds
 
+	/* Restore decompression temporary area physical address */
+	popl	%edi
+
 #ifdef KEEP_IT_REAL
 	/* Initialise libkir */
 	movw	%ax, (init_libkir_vector+2)
@@ -754,7 +764,7 @@ payload_death_message:
 #else
 	/* Find a suitable decompression temporary area, if none specified */
 	pushl	%eax
-	testl	%ebp, %ebp
+	testl	%edi, %edi
 	jnz	1f
 	/* Use INT 15,88 to find the highest available address via INT
 	 * 15,88.  This limits us to around 64MB, which should avoid
@@ -762,14 +772,14 @@ payload_death_message:
 	 */
 	movb	$0x88, %ah
 	int	$0x15
-	movw	%ax, %bp
-	addl	$0x400, %ebp
-	subl	$_textdata_memsz_kb, %ebp
-	shll	$10, %ebp
+	movw	%ax, %di
+	addl	$0x400, %edi
+	subl	$_textdata_memsz_kb, %edi
+	shll	$10, %edi
 	/* Sanity check: if we have ended up below 1MB, use 1MB */
-	cmpl	$0x100000, %ebp
+	cmpl	$0x100000, %edi
 	jae	1f
-	movl	$0x100000, %ebp
+	movl	$0x100000, %edi
 1:	popl	%eax
 
 	/* Install .text and .data to temporary area in high memory,
@@ -777,21 +787,23 @@ payload_death_message:
 	 * properly.
 	 */
 	progress "  .textdata\n"
-	movl	%ebp, %edi
+	pushl	%edi
 	movl	$_textdata_filesz, %ecx
 	movl	$_textdata_memsz, %edx
 	call	install_block
+	popl	%edi
 
 	/* Initialise librm at current location */
 	progress "  init_librm\n"
 	movw	%ax, (init_librm_vector+2)
-	movl	%ebp, %edi
 	lcall	*init_librm_vector
 
-	/* Skip relocation if CF was set on entry */
-	popfw
-	pushfw
-	jc	skip_relocate
+	/* Inhibit INT 15,e820 and INT 15,e801 if applicable */
+	testl	%ebp, %ebp
+	jnz	1f
+	incb	memmap_post
+	decl	%ebp
+1:
 
 	/* Call relocate() to determine target address for relocation.
 	 * relocate() will return with %esi, %edi and %ecx set up
@@ -815,7 +827,6 @@ payload_death_message:
 	/* Initialise librm at new location */
 	progress "  init_librm\n"
 	lcall	*init_librm_vector
-skip_relocate:
 #endif
 
 	/* Close access to payload */
@@ -824,7 +835,6 @@ skip_relocate:
 	lcall	*close_payload_vector
 
 	/* Restore registers */
-	popfw
 	popw	%es
 	popw	%ds
 	popal
@@ -855,17 +865,6 @@ close_payload_vector:
 	.word 0
 	.size close_payload_vector, . - close_payload_vector
 
-	/* Payload address */
-	.section ".prefix.lib", "awx", @progbits
-payload_lma:
-	.long 0
-	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
-	.ascii	"ADHL"
-	.long	payload_lma
-	.long	1
-	.long	0
-	.previous
-
 	/* Dummy routines to open and close payload */
 	.section ".text16.early.data", "aw", @progbits
 	.weak	open_payload
@@ -883,8 +882,7 @@ close_payload:
  * Uninstall all text and data segments.
  *
  * Parameters:
- *   %ax  : .text16 segment address
- *   %bx  : .data16 segment address
+ *   none (.text16 segment address is implicit in %cs)
  * Returns:
  *   none
  * Corrupts:
@@ -919,6 +917,10 @@ uninstall:
 	.ascii	"PAYL"
 	.long	0
 	.long	0
+	.long	_payload_align
+	.ascii	"COPY"
+	.long	_pprefix_lma
+	.long	_pprefix_filesz
 	.long	_max_align
 	.ascii	PACK_OR_COPY
 	.long	_text16_late_lma
@@ -932,3 +934,6 @@ uninstall:
 	.long	_textdata_lma
 	.long	_textdata_filesz
 	.long	_max_align
+
+	.weak	_payload_align
+	.equ	_payload_align, 1
diff --git a/roms/ipxe/src/arch/i386/prefix/linuxprefix.S b/roms/ipxe/src/arch/i386/prefix/linuxprefix.S
deleted file mode 100644
index 398d3cb213f6887a481aec7e69ed955e67a59bb8..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/arch/i386/prefix/linuxprefix.S
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <linux/unistd.h>
-
-	.section ".text"
-	.code32
-	.globl _linux_start
-	.type _linux_start, @function
-
-_linux_start:
-	xorl	%ebp, %ebp
-
-	popl	%esi       // save argc
-	movl	%esp, %edi // save argv
-
-	andl	$~15, %esp // 16-byte align the stack
-
-	pushl	%edi // argv -> C arg2
-	pushl	%esi // argc -> C arg1
-
-	call	save_args
-
-	/* Our main doesn't use any arguments */
-	call	main
-
-	movl	%eax, %ebx // rc -> syscall arg1
-	movl	$__NR_exit, %eax
-	int	$0x80
-
-	.size _linux_start, . - _linux_start
diff --git a/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S b/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S
index f87ef85a9d5b59cd7a9af75306f4..690031f0d254859d8292e7c3353f 100644
--- a/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/lkrnprefix.S
@@ -160,7 +160,7 @@ relocatable_kernel:
 pad2:
 	.byte	0, 0, 0
 cmdline_size:
-	.long	0
+	.long	0x7ff
 hardware_subarch:
 	.long	0
 hardware_subarch_data:
@@ -188,16 +188,61 @@ setup_code:
 	We're now at the beginning of the kernel proper.
  */
 run_ipxe:
-	/* Set up stack just below 0x7c00 */
+	/* Set up stack just below 0x7c00 and clear direction flag */
 	xorw	%ax, %ax
 	movw	%ax, %ss
 	movw	$0x7c00, %sp
+	cld
 
 	/* Retrieve command-line pointer */
-	movl	%es:cmd_line_ptr, %edx
+	movl	%ds:cmd_line_ptr, %edx
+	testl	%edx, %edx
+	jz	no_cmd_line
+
+	/* Set up %es:%di to point to command line */
+	movl	%edx, %edi
+	andl	$0xf, %edi
+	rorl	$4, %edx
+	movw	%dx, %es
+
+	/* Find length of command line */
+	pushw	%di
+	movw	$0xffff, %cx
+	repnz scasb
+	notw	%cx
+	popw	%si
+
+	/* Make space for command line on stack */
+	movw	%sp, %di
+	subw	%cx, %di
+	andw	$~0xf, %di
+	movw	%di, %sp
+
+	/* Copy command line to stack */
+	pushw	%ds
+	pushw	%es
+	popw	%ds
+	pushw	%ss
+	popw	%es
+	rep movsb
+	popw	%ds
+
+	/* Store new command-line pointer */
+	movzwl	%sp, %edx
+no_cmd_line:
+
+	/* Calculate maximum relocation address */
+	movl	ramdisk_image, %ebp
+	testl	%ebp, %ebp
+	jnz	1f
+	orl	$0xffffffff, %ebp /* Allow arbitrary relocation if no initrd */
+1:
 
 	/* Install iPXE */
-	call	install
+	call	alloc_basemem
+	xorl	%esi, %esi
+	xorl	%edi, %edi
+	call	install_prealloc
 
 	/* Set up real-mode stack */
 	movw	%bx, %ss
@@ -209,12 +254,20 @@ run_ipxe:
 	lret
 	.section ".text16", "awx", @progbits
 1:
+	/* Retrieve initrd pointer and size */
+	movl	ramdisk_image, %ebp
+	movl	ramdisk_size, %ecx
+
 	/* Set up %ds for access to .data16 */
 	movw	%bx, %ds
 
 	/* Store command-line pointer */
 	movl	%edx, cmdline_phys
 
+	/* Store initrd pointer and size */
+	movl	%ebp, initrd_phys
+	movl	%ecx, initrd_len
+
 	/* Run iPXE */
 	pushl	$main
 	pushw	%cs
diff --git a/roms/ipxe/src/arch/i386/prefix/mromprefix.S b/roms/ipxe/src/arch/i386/prefix/mromprefix.S
index 7bbe44c4ea1ceed59df97b1fb2b9..058663c4018f7edfcc25c58afd62 100644
--- a/roms/ipxe/src/arch/i386/prefix/mromprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/mromprefix.S
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  *
  */
 
@@ -30,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER )
 #define PCI_BAR_EXPROM			0x30
 
 #define ROMPREFIX_EXCLUDE_PAYLOAD 1
+#define ROMPREFIX_MORE_IMAGES 1
 #define _rom_start _mrom_start
 #include "romprefix.S"
 
@@ -46,8 +48,10 @@ FILE_LICENCE ( GPL2_OR_LATER )
  * Parameters:
  *   %ds:0000 : Prefix
  *   %esi : Buffer for copy of image source (or zero if no buffer available)
+ *   %ecx : Expected offset within buffer of first payload block
  * Returns:
  *   %esi : Valid image source address (buffered or unbuffered)
+ *   %ecx : Actual offset within buffer of first payload block
  *   CF set on error
  */
 	.section ".text16.early", "awx", @progbits
@@ -56,23 +60,25 @@ open_payload:
 	/* Preserve registers */
 	pushl	%eax
 	pushw	%bx
-	pushl	%ecx
 	pushl	%edx
 	pushl	%edi
 	pushw	%bp
+	pushw	%es
 	pushw	%ds
 
-	/* Retrieve bus:dev.fn and image source length from .prefix */
+	/* Retrieve bus:dev.fn from .prefix */
 	movw	init_pci_busdevfn, %bx
-	movl	image_source_len_dword, %ecx
 
 	/* Set up %ds for access to .text16.early */
 	pushw	%cs
 	popw	%ds
 
-	/* Store bus:dev.fn and image source length to .text16.early */
+	/* Set up %es for access to flat address space */
+	xorw	%ax, %ax
+	movw	%ax, %es
+
+	/* Store bus:dev.fn to .text16.early */
 	movw	%bx, payload_pci_busdevfn
-	movl	%ecx, rom_bar_copy_len_dword
 
 	/* Get expansion ROM BAR current value */
 	movw	$PCI_BAR_EXPROM, %di
@@ -149,6 +155,18 @@ find_mem_bar:
 	movw	$PCI_BAR_EXPROM, %di
 	call	pci_write_config_dword
 
+	/* Locate our ROM image */
+1:	addr32 es cmpw $0xaa55, (%eax)
+	stc
+	jne	99f
+	addr32 es cmpl $_build_id, build_id(%eax)
+	je	2f
+	addr32 es movzbl 2(%eax), %ecx
+	shll	$9, %ecx
+	addl	%ecx, %eax
+	jmp	1b
+2:
+
 	/* Copy payload to buffer, or set buffer address to BAR address */
 	testl	%esi, %esi
 	jz	1f
@@ -159,27 +177,32 @@ find_mem_bar:
 	 * properly support flat real mode, it will die horribly.)
 	 */
 	pushl	%esi
-	pushw	%es
 	movl	%esi, %edi
 	movl	%eax, %esi
-	movl	rom_bar_copy_len_dword, %ecx
-	xorw	%ax, %ax
-	movw	%ax, %es
+	addr32 es movzbl 2(%esi), %ecx
+	shll	$7, %ecx
+	addr32 es movzbl 2(%esi,%ecx,4), %edx
+	shll	$7, %edx
+	addl	%edx, %ecx
 	addr32 es rep movsl
-	popw	%es
 	popl	%esi
 	jmp	2f
 1:	/* We have no buffer; set %esi to the BAR address */
 	movl	%eax, %esi
 2:
 
+	/* Locate first payload block (after the dummy ROM header) */
+	addr32 es movzbl 2(%esi), %ecx
+	shll	$9, %ecx
+	addl	$_pprefix_skip, %ecx
+
 	clc
 	/* Restore registers and return */
 99:	popw	%ds
+	popw	%es
 	popw	%bp
 	popl	%edi
 	popl	%edx
-	popl	%ecx
 	popw	%bx
 	popl	%eax
 	lret
@@ -200,11 +223,6 @@ rom_bar_size:
 	.long	0
 	.size	rom_bar_size, . - rom_bar_size
 
-	.section ".text16.early.data", "aw", @progbits
-rom_bar_copy_len_dword:
-	.long	0
-	.size	rom_bar_copy_len_dword, . - rom_bar_copy_len_dword
-
 	.section ".text16.early.data", "aw", @progbits
 stolen_bar_register:
 	.word	0
@@ -419,16 +437,68 @@ pci_set_mem_access:
 	ret
 	.size	pci_set_mem_access, . - pci_set_mem_access
 
-/* Image source area length (in dwords)
+/* Payload prefix
  *
+ * We include a dummy ROM header to cover the "hidden" portion of the
+ * overall ROM image.
  */
-	.section ".prefix", "ax", @progbits
-image_source_len_dword:
+	.globl	_payload_align
+	.equ	_payload_align, 512
+	.section ".pprefix", "ax", @progbits
+	.org	0x00
+mromheader:
+	.word	0xaa55			/* BIOS extension signature */
+mromheader_size: .byte 0		/* Size in 512-byte blocks */
+	.org	0x18
+	.word	mpciheader
+	.org	0x1a
+	.word	0
+	.size	mromheader, . - mromheader
+
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	"APPB"
+	.long	mromheader_size
+	.long	512
 	.long	0
-	.size	image_source_len_dword, . - image_source_len_dword
+	.previous
+
+mpciheader:
+	.ascii	"PCIR"			/* Signature */
+	.word	pci_vendor_id		/* Vendor identification */
+	.word	pci_device_id		/* Device identification */
+	.word	0x0000			/* Device list pointer */
+	.word	mpciheader_len		/* PCI data structure length */
+	.byte	0x03			/* PCI data structure revision */
+	.byte	0x02, 0x00, 0x00	/* Class code */
+mpciheader_image_length:
+	.word	0			/* Image length */
+	.word	0x0001			/* Revision level */
+	.byte	0xff			/* Code type */
+	.byte	0x80			/* Last image indicator */
+mpciheader_runtime_length:
+	.word	0			/* Maximum run-time image length */
+	.word	0x0000			/* Configuration utility code header */
+	.word	0x0000			/* DMTF CLP entry point */
+	.equ	mpciheader_len, . - mpciheader
+	.size	mpciheader, . - mpciheader
+
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	"APPW"
+	.long	mpciheader_image_length
+	.long	512
+	.long	0
+	.ascii	"APPW"
+	.long	mpciheader_runtime_length
+	.long	512
+	.long	0
+	.previous
+
+/* Fix up additional image source size
+ *
+ */
 	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
-	.ascii	"ADDL"
-	.long	image_source_len_dword
-	.long	4
+	.ascii	"ADPW"
+	.long	extra_size
+	.long	512
 	.long	0
 	.previous
diff --git a/roms/ipxe/src/arch/i386/prefix/nbiprefix.S b/roms/ipxe/src/arch/i386/prefix/nbiprefix.S
index 20d224d69b724aa00bc5f14260a3..06e7df5b747bc791e57ea3608cfb 100644
--- a/roms/ipxe/src/arch/i386/prefix/nbiprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/nbiprefix.S
@@ -54,6 +54,10 @@ _nbi_start:
 	/* Install iPXE */
 	call	install
 
+	/* Set up real-mode stack */
+	movw	%bx, %ss
+	movw	$_estack16, %sp
+
 	/* Jump to .text16 segment */
 	pushw	%ax
 	pushw	$1f
diff --git a/roms/ipxe/src/arch/i386/prefix/pxeprefix.S b/roms/ipxe/src/arch/i386/prefix/pxeprefix.S
index b7468cdf05b50a10a7600d1e5f97..05db9894cc00b57f9c9b5d51747f 100644
--- a/roms/ipxe/src/arch/i386/prefix/pxeprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/pxeprefix.S
@@ -5,6 +5,7 @@ FILE_LICENCE ( GPL2_OR_LATER )
 #define PXENV_UNDI_GET_IFACE_INFO	0x0013
 #define	PXENV_STOP_UNDI			0x0015
 #define PXENV_UNLOAD_STACK		0x0070
+#define PXENV_FILE_CMDLINE		0x00e8
 
 #define PXE_HACK_EB54			0x0001
 
@@ -19,6 +20,8 @@ FILE_LICENCE ( GPL2_OR_LATER )
 #define EB_MAGIC_1 ( 'E' + ( 't' << 8 ) + ( 'h' << 16 ) + ( 'e' << 24 ) )
 #define EB_MAGIC_2 ( 'r' + ( 'b' << 8 ) + ( 'o' << 16 ) + ( 'o' << 24 ) )
 
+#define PREFIX_STACK_SIZE 2048
+
 /*****************************************************************************
  * Entry point:	set operating context, print welcome message
  *****************************************************************************
@@ -46,10 +49,11 @@ _pxe_start:
 	movw	%ax, %ds
 	movw	$0x40, %ax		/* BIOS data segment access */
 	movw	%ax, %fs
-	/* Set up stack just below 0x7c00 */
-	xorw	%ax, %ax
+	/* Set up temporary stack immediately after the iPXE image */
+	movw	%cs, %ax
+	addw	image_size_pgh, %ax
 	movw	%ax, %ss
-	movl	$0x7c00, %esp
+	movl	$PREFIX_STACK_SIZE, %esp
 	/* Clear direction flag, for the sake of sanity */
 	cld
 	/* Print welcome message */
@@ -60,6 +64,18 @@ _pxe_start:
 10:	.asciz	"PXE->EB:"
 	.previous
 
+	/* Image size (for stack placement calculation) */
+	.section ".prefix.data", "aw", @progbits
+image_size_pgh:
+	.word	0
+	.previous
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	"ADDW"
+	.long	image_size_pgh
+	.long	16
+	.long	0
+	.previous
+
 /*****************************************************************************
  * Find us a usable !PXE or PXENV+ entry point
  *****************************************************************************
@@ -366,6 +382,35 @@ get_iface_type:
 99:	movb	$0x0a, %al
 	call	print_character
 
+
+/*****************************************************************************
+ * Check for a command line
+ *****************************************************************************
+ */
+get_cmdline:
+	/* Issue PXENV_FILE_CMDLINE */
+	xorl	%esi, %esi
+	movw	%ss, %si
+	movw	%si, ( pxe_parameter_structure + 0x06 )
+	movw	$PREFIX_STACK_SIZE, ( pxe_parameter_structure + 0x04 )
+	movw	$0xffff, ( pxe_parameter_structure + 0x02 )
+	movw	$PXENV_FILE_CMDLINE, %bx
+	call	pxe_call
+	jc	99f  /* Suppress errors; this is an iPXE extension API call */
+	/* Check for non-NULL command line */
+	movw	( pxe_parameter_structure + 0x02 ), %ax
+	testw	%ax, %ax
+	jz	99f
+	/* Record command line */
+	shll	$4, %esi
+	addl	$PREFIX_STACK_SIZE, %esi
+	movl	%esi, pxe_cmdline
+99:
+	.section ".prefix.data", "aw", @progbits
+pxe_cmdline:
+	.long	0
+	.previous
+
 /*****************************************************************************
  * Leave NIC in a safe state
  *****************************************************************************
@@ -713,6 +758,9 @@ run_ipxe:
 	movw	pxe_ss,	%di
 	movl	pxe_esp, %ebp
 
+	/* Retrieve PXE command line, if any */
+	movl	pxe_cmdline, %esi
+
 	/* Jump to .text16 segment with %ds pointing to .data16 */
 	movw	%bx, %ds
 	pushw	%ax
@@ -721,11 +769,10 @@ run_ipxe:
 	.section ".text16", "ax", @progbits
 1:
 	/* Update the exit hook */
-	movw	%cs,pxe_exit_hook+2
-	push	%ax
-	mov	$2f,%ax
-	mov	%ax,pxe_exit_hook
-	pop	%ax
+	movw	%cs, ( pxe_exit_hook + 2 )
+
+	/* Store command-line pointer */
+	movl	%esi, cmdline_phys
 
 	/* Run main program */
 	pushl	$main
@@ -743,7 +790,14 @@ run_ipxe:
 	/* Jump to hook if applicable */
 	ljmpw	*pxe_exit_hook
 
-2:	/* Check PXE stack magic */
+	.section ".data16", "aw", @progbits
+	.globl	pxe_exit_hook
+pxe_exit_hook:
+	.word	exit_ipxe, 0
+	.previous
+
+exit_ipxe:
+	/* Check PXE stack magic */
 	popl	%eax
 	cmpl	$STACK_MAGIC, %eax
 	jne	1f
diff --git a/roms/ipxe/src/arch/i386/prefix/romprefix.S b/roms/ipxe/src/arch/i386/prefix/romprefix.S
index dd602ddb7108fb6afa0805a31220..091673d3c885e9301b0ab47baa43 100644
--- a/roms/ipxe/src/arch/i386/prefix/romprefix.S
+++ b/roms/ipxe/src/arch/i386/prefix/romprefix.S
@@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER )
 	( PMM_HANDLE_BASE | 0x00001000 )
 #define PMM_HANDLE_BASE_DECOMPRESS_TO \
 	( PMM_HANDLE_BASE | 0x00002000 )
+#define PCI_FUNC_MASK 0x07
 
 /* ROM banner timeout.  Based on the configurable BANNER_TIMEOUT in
  * config.h, but converted to a number of (18Hz) timer ticks, and
@@ -39,6 +40,14 @@ FILE_LICENCE ( GPL2_OR_LATER )
 #else
 #define	ZINFO_TYPE_ADxB "ADDB"
 #define	ZINFO_TYPE_ADxW "ADDW"
+#endif
+
+/* Allow ROM to be marked as containing multiple images
+ */
+#if ROMPREFIX_MORE_IMAGES
+#define INDICATOR 0x00
+#else
+#define INDICATOR 0x80
 #endif
 
 	.text
@@ -55,6 +64,8 @@ romheader_size:	.byte 0			/* Size in 512-byte blocks */
 	jmp	init			/* Initialisation vector */
 checksum:
 	.byte	0
+	.org	0x10
+	.word	ipxeheader
 	.org	0x16
 	.word	undiheader
 	.org	0x18
@@ -70,9 +81,6 @@ checksum:
 	.long	0
 	.previous
 
-build_id:
-	.long	_build_id		/* Randomly-generated build ID */
-
 pciheader:
 	.ascii	"PCIR"			/* Signature */
 	.word	pci_vendor_id		/* Vendor identification */ 
@@ -85,7 +93,7 @@ pciheader_image_length:
 	.word	0			/* Image length */
 	.word	0x0001			/* Revision level */
 	.byte	0x00			/* Code type */
-	.byte	0x80			/* Last image indicator */
+	.byte	INDICATOR		/* Last image indicator */
 pciheader_runtime_length:
 	.word	0			/* Maximum run-time image length */
 	.word	0x0000			/* Configuration utility code header */
@@ -104,6 +112,11 @@ pciheader_runtime_length:
 	.long	0
 	.previous
 
+	/* PnP doesn't require any particular alignment, but IBM
+	 * BIOSes will scan on 16-byte boundaries rather than using
+	 * the offset stored at 0x1a
+	 */
+	.align	16
 pnpheader:
 	.ascii	"$PnP"			/* Signature */
 	.byte	0x01			/* Structure revision */
@@ -162,6 +175,25 @@ undiheader:
 	.equ undiheader_len, . - undiheader
 	.size undiheader, . - undiheader
 
+ipxeheader:
+	.ascii	"iPXE"			/* Signature */
+	.byte	ipxeheader_len		/* Length of structure */
+	.byte	0			/* Checksum */
+shrunk_rom_size:
+	.byte	0			/* Shrunk size (in 512-byte blocks) */
+	.byte	0			/* Reserved */
+build_id:
+	.long	_build_id		/* Randomly-generated build ID */
+	.equ ipxeheader_len, . - ipxeheader
+	.size ipxeheader, . - ipxeheader
+
+	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
+	.ascii	"ADHB"
+	.long	shrunk_rom_size
+	.long	512
+	.long	0
+	.previous
+
 /* Initialisation (called once during POST)
  *
  * Determine whether or not this is a PnP system via a signature
@@ -286,6 +318,7 @@ pnp_scan:
 	call	print_message
 	jmp	pnp_done
 no_pnp:	/* Not PnP-compliant - hook INT 19 */
+#ifdef NONPNP_HOOK_INT19
 	movw	$init_message_int19, %si
 	xorw	%di, %di
 	call	print_message
@@ -296,6 +329,7 @@ no_pnp:	/* Not PnP-compliant - hook INT 19 */
 	pushw	%gs /* %gs contains runtime %cs */
 	pushw	$int19_entry
 	popl	%es:( 0x19 * 4 )
+#endif /* NONPNP_HOOK_INT19 */
 pnp_done:
 
 	/* Check for PMM */
@@ -319,14 +353,19 @@ pmm_scan:
 	call	print_message
 	/* We have PMM and so a 1kB stack: preserve whole registers */
 	pushal
-	/* Allocate image source PMM block */
-	movzwl	image_source_size, %ecx
+	/* Allocate image source PMM block.  Round up the size to the
+	 * nearest 4kB (8 512-byte sectors) to work around AMI BIOS bugs.
+	 */
+	movzbl	romheader_size, %ecx
+	addw	extra_size, %cx
+	addw	$0x0007, %cx	/* Round up to multiple of 8 512-byte sectors */
+	andw	$0xfff8, %cx
 	shll	$5, %ecx
 	movl	$PMM_HANDLE_BASE_IMAGE_SOURCE, %ebx
 	movw	$get_pmm_image_source, %bp
 	call	get_pmm
 	movl	%esi, image_source
-	jc	1f
+	jz	1f
 	/* Copy ROM to image source PMM block */
 	pushw	%es
 	xorw	%ax, %ax
@@ -334,8 +373,8 @@ pmm_scan:
 	movl	%esi, %edi
 	xorl	%esi, %esi
 	movzbl	romheader_size, %ecx
-	shll	$9, %ecx
-	addr32 rep movsb	/* PMM presence implies flat real mode */
+	shll	$7, %ecx
+	addr32 rep movsl	/* PMM presence implies flat real mode */
 	popw	%es
 	/* Shrink ROM */
 	movb	shrunk_rom_size, %al
@@ -384,6 +423,9 @@ no_pmm:
 	xorw	%di, %di
 	cs rep	movsb
 
+	/* Skip prompt if this is not the first PCI function */
+	testb	$PCI_FUNC_MASK, init_pci_busdevfn
+	jnz	no_shell
 	/* Prompt for POST-time shell */
 	movw	$init_message_prompt, %si
 	xorw	%di, %di
@@ -402,15 +444,19 @@ no_pmm:
 	movw	$init_message_done, %si
 	call	print_message
 	popf
-	jnz	2f
+	jnz	no_shell
 	/* Ctrl-B was pressed: invoke iPXE.  The keypress will be
 	 * picked up by the initial shell prompt, and we will drop
 	 * into a shell.
 	 */
-	stc			/* Inhibit relocation */
+	xorl	%ebp, %ebp	/* Inhibit use of INT 15,e820 and INT 15,e801 */
 	pushw	%cs
 	call	exec
-2:
+no_shell:
+	movb	$( '\n' ), %al
+	xorw	%di, %di
+	call	print_character
+
 	/* Restore registers */
 	popw	%gs
 	popw	%fs
@@ -432,13 +478,13 @@ no_pmm:
  *  %es:0000 : PMM structure
  * Returns:
  *  %ebx : PMM handle
- *  %esi : allocated block address, or zero (with CF set) if allocation failed
+ *  %esi : allocated block address, or zero (with ZF set) if allocation failed
  */
 get_pmm:
 	/* Preserve registers */
 	pushl	%eax
 	pushw	%di
-	movw	$' ', %di
+	movw	$( ' ' ), %di
 get_pmm_find:
 	/* Try to find existing block */
 	pushl	%ebx		/* PMM handle */
@@ -448,7 +494,10 @@ get_pmm_find:
 	pushw	%dx
 	pushw	%ax
 	popl	%esi
-	testl	%esi, %esi
+	/* Treat 0xffffffff (not supported) as 0x00000000 (not found) */
+	incl	%esi
+	jz	get_pmm_allocate
+	decl	%esi
 	jz	get_pmm_allocate
 	/* Block found - check acceptability */
 	call	*%bp
@@ -467,20 +516,21 @@ get_pmm_allocate:
 	pushw	%dx
 	pushw	%ax
 	popl	%esi
-	movw	$'+', %di	/* Indicate allocation attempt */
-	testl	%esi, %esi
-	jnz	get_pmm_done
-	stc
+	movw	$( '+' ), %di	/* Indicate allocation attempt */
 get_pmm_done:
 	/* Print block address */
-	pushfw
 	movw	%di, %ax
 	xorw	%di, %di
 	call	print_character
 	movl	%esi, %eax
 	call	print_hex_dword
-	popfw
-	/* Restore registers and return */
+	/* Treat 0xffffffff (not supported) as 0x00000000 (allocation
+	 * failed), and set ZF to indicate a zero result.
+	 */
+	incl	%esi
+	jz	1f
+	decl	%esi
+1:	/* Restore registers and return */
 	popw	%di
 	popl	%eax
 	ret
@@ -553,7 +603,7 @@ init_message_done:
  *
  */
 init_pci_busdevfn:
-	.word	0xffff
+	.word	0
 	.size	init_pci_busdevfn, . - init_pci_busdevfn
 
 /* Image source area
@@ -566,31 +616,12 @@ image_source:
 	.long	0
 	.size	image_source, . - image_source
 
-/* Image source size (in 512-byte sectors)
+/* Additional image source size (in 512-byte sectors)
  *
  */
-image_source_size:
+extra_size:
 	.word	0
-	.size	image_source_size, . - image_source_size
-	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
-	.ascii	"ADDW"
-	.long	image_source_size
-	.long	512
-	.long	0
-	.previous
-
-/* Shrunk ROM size (in 512-byte sectors)
- *
- */
-shrunk_rom_size:
-	.byte	0
-	.size	shrunk_rom_size, . - shrunk_rom_size
-	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
-	.ascii	"ADHB"
-	.long	shrunk_rom_size
-	.long	512
-	.long	0
-	.previous
+	.size	extra_size, . - extra_size
 
 /* Temporary decompression area
  *
@@ -607,7 +638,7 @@ decompress_to:
  * Called by the PnP BIOS when it wants to boot us.
  */
 bev_entry:
-	clc			/* Allow relocation */
+	orl	$0xffffffff, %ebp	/* Allow arbitrary relocation */
 	pushw	%cs
 	call	exec
 	lret
@@ -642,7 +673,7 @@ int19_entry:
 	/* Leave keypress in buffer and start iPXE.  The keypress will
 	 * cause the usual initial Ctrl-B prompt to be skipped.
 	 */
-	clc			/* Allow relocation */
+	orl	$0xffffffff, %ebp	/* Allow arbitrary relocation */
 	pushw	%cs
 	call	exec
 1:	/* Try to call original INT 19 vector */
@@ -674,9 +705,6 @@ exec:	/* Set %ds = %cs */
 	pushw	%cs
 	popw	%ds
 
-	/* Preserve state of CF */
-	lahf
-
 	/* Print message as soon as possible */
 	movw	$prodstr, %si
 	xorw	%di, %di
@@ -686,8 +714,8 @@ exec:	/* Set %ds = %cs */
 
 	/* Store magic word on BIOS stack and remember BIOS %ss:sp */
 	pushl	$STACK_MAGIC
-	movw	%ss, %dx
-	movw	%sp, %bp
+	movw	%ss, %cx
+	movw	%sp, %dx
 
 	/* Obtain a reasonably-sized temporary stack */
 	xorw	%bx, %bx
@@ -695,10 +723,7 @@ exec:	/* Set %ds = %cs */
 	movw	$0x7c00, %sp
 
 	/* Install iPXE */
-	sahf
-	pushfw
 	call	alloc_basemem
-	popfw
 	movl	image_source, %esi
 	movl	decompress_to, %edi
 	call	install_prealloc
@@ -721,14 +746,14 @@ exec:	/* Set %ds = %cs */
 	pushl	$main
 	pushw	%cs
 	call	prot_call
-	popl	%ecx /* discard */
+	popl	%eax /* discard */
 
 	/* Uninstall iPXE */
 	call	uninstall
 
 	/* Restore BIOS stack */
-	movw	%dx, %ss
-	movw	%bp, %sp
+	movw	%cx, %ss
+	movw	%dx, %sp
 
 	/* Check magic word on BIOS stack */
 	popl	%eax
diff --git a/roms/ipxe/src/arch/i386/prefix/undiloader.S b/roms/ipxe/src/arch/i386/prefix/undiloader.S
index 951b5c1ce843bd5ae71ba60c7f57..ccdd816e6686a8120d4f3e43ae7a 100644
--- a/roms/ipxe/src/arch/i386/prefix/undiloader.S
+++ b/roms/ipxe/src/arch/i386/prefix/undiloader.S
@@ -14,6 +14,7 @@ undiloader:
 	/* Save registers */
 	pushl	%esi
 	pushl	%edi
+	pushl	%ebp
 	pushw	%ds
 	pushw	%es
 	pushw	%bx
@@ -30,7 +31,7 @@ undiloader:
 	movw	%es:14(%di), %ax
 	movl	image_source, %esi
 	movl	decompress_to, %edi
-	clc			/* Allow relocation */
+	orl	$0xffffffff, %ebp	/* Allow arbitrary relocation */
 	call	install_prealloc
 	popw	%di
 	/* Call UNDI loader C code */
@@ -46,6 +47,7 @@ undiloader:
 	popw	%bx
 	popw	%es
 	popw	%ds
+	popl	%ebp
 	popl	%edi
 	popl	%esi
 	lret
diff --git a/roms/ipxe/src/arch/i386/scripts/i386.lds b/roms/ipxe/src/arch/i386/scripts/i386.lds
index c5bc631fa92473063d2191ad2e82..fb763656ce4522eda0e97cb13ffd 100644
--- a/roms/ipxe/src/arch/i386/scripts/i386.lds
+++ b/roms/ipxe/src/arch/i386/scripts/i386.lds
@@ -1,4 +1,4 @@
-/* -*- sh -*- */
+/* -*- ld-script -*- */
 
 /*
  * Linker script for i386 images
@@ -39,8 +39,8 @@ SECTIONS {
     } .bss.prefix (NOLOAD) : AT ( _end_lma ) {
 	_eprefix = .;
     }
-    _prefix_filesz	= ABSOLUTE ( _mprefix - _prefix );
-    _prefix_memsz	= ABSOLUTE ( _eprefix - _prefix );
+    _prefix_filesz	= ABSOLUTE ( _mprefix ) - ABSOLUTE ( _prefix );
+    _prefix_memsz	= ABSOLUTE ( _eprefix ) - ABSOLUTE ( _prefix );
 
     /*
      * The 16-bit (real-mode) code section
@@ -63,11 +63,11 @@ SECTIONS {
     } .bss.text16 (NOLOAD) : AT ( _end_lma ) {
 	_etext16 = .;
     }
-    _text16_early_filesz = ABSOLUTE ( _etext16_early - _text16 );
-    _text16_early_memsz	= ABSOLUTE ( _etext16_early - _text16 );
-    _text16_late_filesz	= ABSOLUTE ( _mtext16 - _text16_late );
-    _text16_late_memsz	= ABSOLUTE ( _etext16 - _text16_late );
-    _text16_memsz	= ABSOLUTE ( _etext16 - _text16 );
+    _text16_early_filesz = ABSOLUTE ( _etext16_early ) - ABSOLUTE ( _text16 );
+    _text16_early_memsz	= ABSOLUTE ( _etext16_early ) - ABSOLUTE ( _text16 );
+    _text16_late_filesz	= ABSOLUTE ( _mtext16 ) - ABSOLUTE ( _text16_late );
+    _text16_late_memsz	= ABSOLUTE ( _etext16 ) - ABSOLUTE ( _text16_late );
+    _text16_memsz	= ABSOLUTE ( _etext16 ) - ABSOLUTE ( _text16 );
 
     /*
      * The 16-bit (real-mode) data section
@@ -89,8 +89,8 @@ SECTIONS {
 	*(.stack16.*)
 	_edata16 = .;
     }
-    _data16_filesz	= ABSOLUTE ( _mdata16 - _data16 );
-    _data16_memsz	= ABSOLUTE ( _edata16 - _data16 );
+    _data16_filesz	= ABSOLUTE ( _mdata16 ) - ABSOLUTE ( _data16 );
+    _data16_memsz	= ABSOLUTE ( _edata16 ) - ABSOLUTE ( _data16 );
 
     /*
      * The 32-bit sections
@@ -118,8 +118,25 @@ SECTIONS {
 	*(.stack.*)
 	_etextdata = .;
     }
-    _textdata_filesz	= ABSOLUTE ( _mtextdata - _textdata );
-    _textdata_memsz	= ABSOLUTE ( _etextdata - _textdata );
+    _textdata_filesz	= ABSOLUTE ( _mtextdata ) - ABSOLUTE ( _textdata );
+    _textdata_memsz	= ABSOLUTE ( _etextdata ) - ABSOLUTE ( _textdata );
+
+    /*
+     * Payload prefix
+     *
+     * If present, this will be placed between .text16.early and .text16.late.
+     *
+     */
+    .pprefix 0x0 : AT ( _pprefix_lma ) {
+	_pprefix = .;
+	KEEP(*(.pprefix))
+	KEEP(*(.pprefix.*))
+	_mpprefix = .;
+    } .bss.pprefix (NOLOAD) : AT ( _end_lma ) {
+	_epprefix = .;
+    }
+    _pprefix_filesz	= ABSOLUTE ( _mpprefix ) - ABSOLUTE ( _pprefix );
+    _pprefix_memsz	= ABSOLUTE ( _epprefix ) - ABSOLUTE ( _pprefix );
 
     /*
      * Compressor information block
@@ -134,8 +151,8 @@ SECTIONS {
     } .bss.zinfo (NOLOAD) : AT ( _end_lma ) {
 	_ezinfo = .;
     }
-    _zinfo_filesz	= ABSOLUTE ( _mzinfo - _zinfo );
-    _zinfo_memsz	= ABSOLUTE ( _ezinfo - _zinfo );
+    _zinfo_filesz	= ABSOLUTE ( _mzinfo ) - ABSOLUTE ( _zinfo );
+    _zinfo_memsz	= ABSOLUTE ( _ezinfo ) - ABSOLUTE ( _zinfo );
 
     /*
      * Weak symbols that need zero values if not otherwise defined
@@ -187,8 +204,14 @@ SECTIONS {
     _text16_early_lma	= .;
     .			+= _text16_early_filesz;
 
+    .			= ALIGN ( _max_align );
+    .			= ALIGN ( _payload_align );
+    _pprefix_lma	= .;
+    .			+= _pprefix_filesz;
+
     .			= ALIGN ( _max_align );
     _payload_lma	= .;
+    _pprefix_skip	= ABSOLUTE ( _payload_lma ) - ABSOLUTE ( _pprefix_lma );
     _text16_late_lma	= .;
     .			+= _text16_late_filesz;
 
diff --git a/roms/ipxe/src/arch/i386/transitions/liba20.S b/roms/ipxe/src/arch/i386/transitions/liba20.S
index 594d62010be04cd68d7258fc6086..6846975255a1da2493abd5bd9556 100644
--- a/roms/ipxe/src/arch/i386/transitions/liba20.S
+++ b/roms/ipxe/src/arch/i386/transitions/liba20.S
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  *
  */
 
@@ -96,8 +97,11 @@ test_a20_long:
 	.section ".text16.early", "awx", @progbits
 	.code16
 enable_a20_bios:
-	/* Preserve registers */
-	pushw	%ax
+
+	/* Preserve registers.  Be very paranoid, since some BIOSes
+	 * are reported to clobber %ebx
+	 */
+	pushal
 
 	/* Attempt INT 15,2401 */
 	movw	$0x2401, %ax
@@ -108,7 +112,7 @@ enable_a20_bios:
 	call	test_a20_short
 
 99:	/* Restore registers and return */
-	popw	%ax
+	popal
 	ret
 	.size	enable_a20_bios, . - enable_a20_bios
 
diff --git a/roms/ipxe/src/arch/i386/transitions/librm.S b/roms/ipxe/src/arch/i386/transitions/librm.S
index 5eb82b44ba658cfc7494399375a3..02d25b22c0c2e23e2fa1541a12fd 100644
--- a/roms/ipxe/src/arch/i386/transitions/librm.S
+++ b/roms/ipxe/src/arch/i386/transitions/librm.S
@@ -97,18 +97,18 @@ init_librm:
 	pushl	%eax
 	pushl	%ebx
 
-	/* Store _virt_offset and set up virtual_cs and virtual_ds segments */
+	/* Store virt_offset and set up virtual_cs and virtual_ds segments */
 	movl	%edi, %eax
 	movw	$virtual_cs, %bx
 	call	set_seg_base
 	movw	$virtual_ds, %bx
 	call	set_seg_base	
-	movl	%edi, _virt_offset
+	movl	%edi, rm_virt_offset
 
 	/* Negate virt_offset */
 	negl	%edi
 		
-	/* Store rm_cs and _text16, set up real_cs segment */
+	/* Store rm_cs and text16, set up real_cs segment */
 	xorl	%eax, %eax
 	movw	%cs, %ax
 	movw	%ax, rm_cs
@@ -116,9 +116,9 @@ init_librm:
 	movw	$real_cs, %bx
 	call	set_seg_base
 	addr32 leal	(%eax, %edi), %ebx
-	movl	%ebx, _text16
+	movl	%ebx, rm_text16
 
-	/* Store rm_ds and _data16, set up real_ds segment */
+	/* Store rm_ds and data16, set up real_ds segment */
 	xorl	%eax, %eax
 	movw	%ds, %ax
 	movw	%ax, %cs:rm_ds
@@ -126,7 +126,7 @@ init_librm:
 	movw	$real_ds, %bx
 	call	set_seg_base
 	addr32 leal	(%eax, %edi), %ebx
-	movl	%ebx, _data16
+	movl	%ebx, rm_data16
 
 	/* Set GDT and IDT base */
 	movl	%eax, gdt_base
@@ -182,12 +182,12 @@ real_to_prot:
 	movw	%cs:rm_ds, %ax
 	movw	%ax, %ds
 
-	/* Add _virt_offset, _text16 and _data16 to stack to be
+	/* Add virt_offset, text16 and data16 to stack to be
 	 * copied, and also copy the return address.
 	 */
-	pushl	_virt_offset
-	pushl	_text16
-	pushl	_data16
+	pushl	rm_virt_offset
+	pushl	rm_text16
+	pushl	rm_data16
 	addw	$16, %cx /* %ecx must be less than 64kB anyway */
 
 	/* Real-mode %ss:%sp => %ebp:%edx and virtual address => %esi */
@@ -197,7 +197,7 @@ real_to_prot:
 	movl	%ebp, %eax
 	shll	$4, %eax
 	addr32 leal (%eax,%edx), %esi
-	subl	_virt_offset, %esi
+	subl	rm_virt_offset, %esi
 
 	/* Switch to protected mode */
 	cli
@@ -557,9 +557,9 @@ pm_esp:	.long _estack
  */
 	/* Internal copies, created by init_librm (which runs in real mode) */
 	.section ".data16", "aw", @progbits
-_virt_offset:	.long 0
-_text16:	.long 0
-_data16:	.long 0
+rm_virt_offset:	.long 0
+rm_text16:	.long 0
+rm_data16:	.long 0
 
 	/* Externally-visible copies, created by real_to_prot */
 	.section ".data", "aw", @progbits
diff --git a/roms/ipxe/src/arch/x86/Makefile b/roms/ipxe/src/arch/x86/Makefile
index 37e03aafa316bfacfab21194c461..cdd397d40093230f55b59b427e45 100644
--- a/roms/ipxe/src/arch/x86/Makefile
+++ b/roms/ipxe/src/arch/x86/Makefile
@@ -7,6 +7,7 @@ INCDIRS		+= arch/x86/include
 SRCDIRS		+= arch/x86/core
 SRCDIRS		+= arch/x86/interface/efi
 SRCDIRS		+= arch/x86/prefix
+SRCDIRS		+= arch/x86/hci/commands
 
 # breaks building some of the linux-related objects
 CFLAGS		+= -Ulinux
diff --git a/roms/ipxe/src/arch/x86/core/cpuid.c b/roms/ipxe/src/arch/x86/core/cpuid.c
new file mode 100644
index 0000000000000000000000000000000000000000..96f794095b3d12a6e647208b8a7a15c6b2ae34ea
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/core/cpuid.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <ipxe/cpuid.h>
+
+/** @file
+ *
+ * x86 CPU feature detection
+ *
+ */
+
+/**
+ * Check whether or not CPUID instruction is supported
+ *
+ * @ret is_supported	CPUID instruction is supported
+ */
+static int cpuid_is_supported ( void ) {
+	unsigned long original;
+	unsigned long inverted;
+
+	__asm__ ( "pushf\n\t"
+		  "pushf\n\t"
+		  "pop %0\n\t"
+		  "mov %0,%1\n\t"
+		  "xor %2,%1\n\t"
+		  "push %1\n\t"
+		  "popf\n\t"
+		  "pushf\n\t"
+		  "pop %1\n\t"
+		  "popf\n\t"
+		  : "=&r" ( original ), "=&r" ( inverted )
+		  : "ir" ( CPUID_FLAG ) );
+	return ( ( original ^ inverted ) & CPUID_FLAG );
+}
+
+/**
+ * Issue CPUID instruction
+ *
+ * @v operation		CPUID operation
+ * @v eax		Output via %eax
+ * @v ebx		Output via %ebx
+ * @v ecx		Output via %ecx
+ * @v edx		Output via %edx
+ */
+static inline __attribute__ (( always_inline )) void
+cpuid ( uint32_t operation, uint32_t *eax, uint32_t *ebx, uint32_t *ecx,
+	uint32_t *edx ) {
+
+	__asm__ ( "cpuid"
+		  : "=a" ( *eax ), "=b" ( *ebx ), "=c" ( *ecx ), "=d" ( *edx )
+		  : "0" ( operation ) );
+}
+
+/**
+ * Get Intel-defined x86 CPU features
+ *
+ * @v features		x86 CPU features to fill in
+ */
+static void x86_intel_features ( struct x86_features *features ) {
+	uint32_t max_level;
+	uint32_t discard_a;
+	uint32_t discard_b;
+	uint32_t discard_c;
+	uint32_t discard_d;
+
+	/* Check that features are available via CPUID */
+	cpuid ( CPUID_VENDOR_ID, &max_level, &discard_b, &discard_c,
+		&discard_d );
+	if ( max_level < CPUID_FEATURES ) {
+		DBGC ( features, "CPUID has no Intel-defined features (max "
+		       "level %08x)\n", max_level );
+		return;
+	}
+
+	/* Get features */
+	cpuid ( CPUID_FEATURES, &discard_a, &discard_b,
+		&features->intel.ecx, &features->intel.edx );
+	DBGC ( features, "CPUID Intel features: %%ecx=%08x, %%edx=%08x\n",
+	       features->intel.ecx, features->intel.edx );
+
+}
+
+/**
+ * Get AMD-defined x86 CPU features
+ *
+ * @v features		x86 CPU features to fill in
+ */
+static void x86_amd_features ( struct x86_features *features ) {
+	uint32_t max_level;
+	uint32_t discard_a;
+	uint32_t discard_b;
+	uint32_t discard_c;
+	uint32_t discard_d;
+
+	/* Check that features are available via CPUID */
+	cpuid ( CPUID_AMD_MAX_FN, &max_level, &discard_b, &discard_c,
+		&discard_d );
+	if ( ( max_level & CPUID_AMD_CHECK_MASK ) != CPUID_AMD_CHECK ) {
+		DBGC ( features, "CPUID has no extended functions\n" );
+		return;
+	}
+	if ( max_level < CPUID_AMD_FEATURES ) {
+		DBGC ( features, "CPUID has no AMD-defined features (max "
+		       "level %08x)\n", max_level );
+		return;
+	}
+
+	/* Get features */
+	cpuid ( CPUID_AMD_FEATURES, &discard_a, &discard_b,
+		&features->amd.ecx, &features->amd.edx );
+	DBGC ( features, "CPUID AMD features: %%ecx=%08x, %%edx=%08x\n",
+	       features->amd.ecx, features->amd.edx );
+}
+
+/**
+ * Get x86 CPU features
+ *
+ * @v features		x86 CPU features to fill in
+ */
+void x86_features ( struct x86_features *features ) {
+
+	/* Clear all features */
+	memset ( features, 0, sizeof ( *features ) );
+
+	/* Check that CPUID instruction is available */
+	if ( ! cpuid_is_supported() ) {
+		DBGC ( features, "CPUID instruction is not supported\n" );
+		return;
+	}
+
+	/* Get Intel-defined features */
+	x86_intel_features ( features );
+
+	/* Get AMD-defined features */
+	x86_amd_features ( features );
+}
diff --git a/roms/ipxe/src/arch/x86/core/debugcon.c b/roms/ipxe/src/arch/x86/core/debugcon.c
new file mode 100644
index 0000000000000000000000000000000000000000..b89480aa5e18345de2deafc01b1b2ba0e1650a3d
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/core/debugcon.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Debug port console
+ *
+ * The debug port is supported by bochs (via the "port_e9_hack"
+ * configuration file directive) and by qemu (via the "-debugcon"
+ * command-line option).
+ */
+
+#include <stdint.h>
+#include <ipxe/io.h>
+#include <ipxe/console.h>
+#include <ipxe/init.h>
+#include <config/console.h>
+
+/** Debug port */
+#define DEBUG_PORT 0xe9
+
+/** Debug port installation check magic value */
+#define DEBUG_PORT_CHECK 0xe9
+
+/* Set default console usage if applicable */
+#if ! ( defined ( CONSOLE_DEBUGCON ) && CONSOLE_EXPLICIT ( CONSOLE_DEBUGCON ) )
+#undef CONSOLE_DEBUGCON
+#define CONSOLE_DEBUGCON ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_TUI )
+#endif
+
+/**
+ * Print a character to debug port console
+ *
+ * @v character		Character to be printed
+ */
+static void debugcon_putchar ( int character ) {
+
+	/* Write character to debug port */
+	outb ( character, DEBUG_PORT );
+}
+
+/** Debug port console driver */
+struct console_driver debugcon_console __console_driver = {
+	.putchar = debugcon_putchar,
+	.usage = CONSOLE_DEBUGCON,
+};
+
+/**
+ * Initialise debug port console
+ *
+ */
+static void debugcon_init ( void ) {
+	uint8_t check;
+
+	/* Check if console is present */
+	check = inb ( DEBUG_PORT );
+	if ( check != DEBUG_PORT_CHECK ) {
+		DBG ( "Debug port not present; disabling console\n" );
+		debugcon_console.disabled = 1;
+	}
+}
+
+/**
+ * Debug port console initialisation function
+ */
+struct init_fn debugcon_init_fn __init_fn ( INIT_EARLY ) = {
+	.initialise = debugcon_init,
+};
diff --git a/roms/ipxe/src/arch/x86/core/pcidirect.c b/roms/ipxe/src/arch/x86/core/pcidirect.c
index a07f7d4baed0d06371adf5d98589..dbc8317b87f70011d3ebe8c6e936 100644
--- a/roms/ipxe/src/arch/x86/core/pcidirect.c
+++ b/roms/ipxe/src/arch/x86/core/pcidirect.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/x86/core/x86_bigint.c b/roms/ipxe/src/arch/x86/core/x86_bigint.c
new file mode 100644
index 0000000000000000000000000000000000000000..418ac23092748f2716f7d3c3c56383e594bb9a75
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/core/x86_bigint.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <ipxe/bigint.h>
+
+/** @file
+ *
+ * Big integer support
+ */
+
+/**
+ * Multiply big integers
+ *
+ * @v multiplicand0	Element 0 of big integer to be multiplied
+ * @v multiplier0	Element 0 of big integer to be multiplied
+ * @v result0		Element 0 of big integer to hold result
+ * @v size		Number of elements
+ */
+void bigint_multiply_raw ( const uint32_t *multiplicand0,
+			   const uint32_t *multiplier0,
+			   uint32_t *result0, unsigned int size ) {
+	const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
+		( ( const void * ) multiplicand0 );
+	const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
+		( ( const void * ) multiplier0 );
+	bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result =
+		( ( void * ) result0 );
+	unsigned int i;
+	unsigned int j;
+	uint32_t multiplicand_element;
+	uint32_t multiplier_element;
+	uint32_t *result_elements;
+	uint32_t discard_a;
+	uint32_t discard_d;
+	long index;
+
+	/* Zero result */
+	memset ( result, 0, sizeof ( *result ) );
+
+	/* Multiply integers one element at a time */
+	for ( i = 0 ; i < size ; i++ ) {
+		multiplicand_element = multiplicand->element[i];
+		for ( j = 0 ; j < size ; j++ ) {
+			multiplier_element = multiplier->element[j];
+			result_elements = &result->element[ i + j ];
+			/* Perform a single multiply, and add the
+			 * resulting double-element into the result,
+			 * carrying as necessary.  The carry can
+			 * never overflow beyond the end of the
+			 * result, since:
+			 *
+			 *     a < 2^{n}, b < 2^{n} => ab < 2^{2n}
+			 */
+			__asm__ __volatile__ ( "mull %4\n\t"
+					       "addl %%eax, (%5,%2,4)\n\t"
+					       "adcl %%edx, 4(%5,%2,4)\n\t"
+					       "\n1:\n\t"
+					       "adcl $0, 8(%5,%2,4)\n\t"
+					       "inc %2\n\t"
+						       /* Does not affect CF */
+					       "jc 1b\n\t"
+					       : "=&a" ( discard_a ),
+						 "=&d" ( discard_d ),
+						 "=&r" ( index )
+					       : "0" ( multiplicand_element ),
+						 "g" ( multiplier_element ),
+						 "r" ( result_elements ),
+						 "2" ( 0 ) );
+		}
+	}
+}
diff --git a/roms/ipxe/src/arch/x86/core/x86_io.c b/roms/ipxe/src/arch/x86/core/x86_io.c
new file mode 100644
index 0000000000000000000000000000000000000000..9b2d2d9358484ef7762bf52231c1ecf7b66fa02e
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/core/x86_io.c
@@ -0,0 +1,102 @@
+/*
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/io.h>
+#include <ipxe/x86_io.h>
+
+/** @file
+ *
+ * iPXE 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 __unused uint64_t i386_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 __unused void i386_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_INLINE ( x86, writeb );
+PROVIDE_IOAPI_INLINE ( x86, writew );
+PROVIDE_IOAPI_INLINE ( x86, writel );
+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 );
+#ifdef __x86_64__
+PROVIDE_IOAPI_INLINE ( x86, readq );
+PROVIDE_IOAPI_INLINE ( x86, writeq );
+#else
+PROVIDE_IOAPI ( x86, readq, i386_readq );
+PROVIDE_IOAPI ( x86, writeq, i386_writeq );
+#endif
diff --git a/roms/ipxe/src/arch/x86/core/x86_string.c b/roms/ipxe/src/arch/x86/core/x86_string.c
index 5838ebace29de5e3904d7926ba74..d48347c962a9bece82c1368e0a49 100644
--- a/roms/ipxe/src/arch/x86/core/x86_string.c
+++ b/roms/ipxe/src/arch/x86/core/x86_string.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 /** @file
@@ -34,7 +35,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
  * @v len		Length
  * @ret dest		Destination address
  */
-void * __memcpy ( void *dest, const void *src, size_t len ) {
+void * __attribute__ (( noinline )) __memcpy ( void *dest, const void *src,
+					       size_t len ) {
 	void *edi = dest;
 	const void *esi = src;
 	int discard_ecx;
@@ -43,21 +45,146 @@ void * __memcpy ( void *dest, const void *src, size_t len ) {
 	 * moves.  Using movsl rather than movsb speeds these up by
 	 * around 32%.
 	 */
-	if ( len >> 2 ) {
-		__asm__ __volatile__ ( "rep movsl"
-				       : "=&D" ( edi ), "=&S" ( esi ),
-				         "=&c" ( discard_ecx )
-				       : "0" ( edi ), "1" ( esi ),
-				         "2" ( len >> 2 )
-				       : "memory" );
-	}
-	if ( len & 0x02 ) {
-		__asm__ __volatile__ ( "movsw" : "=&D" ( edi ), "=&S" ( esi )
-				       : "0" ( edi ), "1" ( esi ) : "memory" );
-	}
-	if ( len & 0x01 ) {
-		__asm__ __volatile__ ( "movsb" : "=&D" ( edi ), "=&S" ( esi )
-				       : "0" ( edi ), "1" ( esi ) : "memory" );
+	__asm__ __volatile__ ( "rep movsl"
+			       : "=&D" ( edi ), "=&S" ( esi ),
+				 "=&c" ( discard_ecx )
+			       : "0" ( edi ), "1" ( esi ), "2" ( len >> 2 )
+			       : "memory" );
+	__asm__ __volatile__ ( "rep movsb"
+			       : "=&D" ( edi ), "=&S" ( esi ),
+				 "=&c" ( discard_ecx )
+			       : "0" ( edi ), "1" ( esi ), "2" ( len & 3 )
+			       : "memory" );
+	return dest;
+}
+
+/**
+ * Copy memory area backwards
+ *
+ * @v dest		Destination address
+ * @v src		Source address
+ * @v len		Length
+ * @ret dest		Destination address
+ */
+void * __attribute__ (( noinline )) __memcpy_reverse ( void *dest,
+						       const void *src,
+						       size_t len ) {
+	void *edi = ( dest + len - 1 );
+	const void *esi = ( src + len - 1 );
+	int discard_ecx;
+
+	/* Assume memmove() is not performance-critical, and perform a
+	 * bytewise copy for simplicity.
+	 */
+	__asm__ __volatile__ ( "std\n\t"
+			       "rep movsb\n\t"
+			       "cld\n\t"
+			       : "=&D" ( edi ), "=&S" ( esi ),
+				 "=&c" ( discard_ecx )
+			       : "0" ( edi ), "1" ( esi ),
+				 "2" ( len )
+			       : "memory" );
+	return dest;
+}
+
+
+/**
+ * Copy (possibly overlapping) memory area
+ *
+ * @v dest		Destination address
+ * @v src		Source address
+ * @v len		Length
+ * @ret dest		Destination address
+ */
+void * __memmove ( void *dest, const void *src, size_t len ) {
+
+	if ( dest <= src ) {
+		return __memcpy ( dest, src, len );
+	} else {
+		return __memcpy_reverse ( dest, src, len );
 	}
+}
+
+/**
+ * Swap memory areas
+ *
+ * @v dest		Destination address
+ * @v src		Source address
+ * @v len		Length
+ * @ret dest		Destination address
+ */
+void * memswap ( void *dest, void *src, size_t len ) {
+	size_t discard_c;
+	int discard;
+
+	__asm__ __volatile__ ( "\n1:\n\t"
+			       "dec %2\n\t"
+			       "js 2f\n\t"
+			       "movb (%0,%2), %b3\n\t"
+			       "xchgb (%1,%2), %b3\n\t"
+			       "movb %b3, (%0,%2)\n\t"
+			       "jmp 1b\n\t"
+			       "2:\n\t"
+			       : "=r" ( src ), "=r" ( dest ),
+				 "=&c" ( discard_c ), "=&q" ( discard )
+			       : "0" ( src ), "1" ( dest ), "2" ( len )
+			       : "memory" );
+
 	return dest;
 }
+
+/**
+ * Calculate length of string
+ *
+ * @v string		String
+ * @ret len		Length (excluding NUL)
+ */
+size_t strlen ( const char *string ) {
+	const char *discard_D;
+	size_t len_plus_one;
+
+	__asm__ __volatile__ ( "repne scasb\n\t"
+			       "not %1\n\t"
+			       : "=&D" ( discard_D ), "=&c" ( len_plus_one )
+			       : "0" ( string ), "1" ( -1UL ), "a" ( 0 ) );
+
+	return ( len_plus_one - 1 );
+}
+
+/**
+ * Compare strings (up to a specified length)
+ *
+ * @v str1		First string
+ * @v str2		Second string
+ * @v len		Maximum length
+ * @ret diff		Difference
+ */
+int strncmp ( const char *str1, const char *str2, size_t len ) {
+	const void *discard_S;
+	const void *discard_D;
+	size_t discard_c;
+	int diff;
+
+	__asm__ __volatile__ ( "\n1:\n\t"
+			       "dec %2\n\t"
+			       "js 2f\n\t"
+			       "lodsb\n\t"
+			       "scasb\n\t"
+			       "jne 3f\n\t"
+			       "testb %b3, %b3\n\t"
+			       "jnz 1b\n\t"
+			       /* Equal */
+			       "\n2:\n\t"
+			       "xor %3, %3\n\t"
+			       "jmp 4f\n\t"
+			       /* Not equal; CF indicates difference */
+			       "\n3:\n\t"
+			       "sbb %3, %3\n\t"
+			       "orb $1, %b3\n\t"
+			       "\n4:\n\t"
+			       : "=&S" ( discard_S ), "=&D" ( discard_D ),
+				 "=&c" ( discard_c ), "=&a" ( diff )
+			       : "0" ( str1 ), "1" ( str2 ), "2" ( len ) );
+
+	return diff;
+}
diff --git a/roms/ipxe/src/arch/x86/core/x86_tcpip.c b/roms/ipxe/src/arch/x86/core/x86_tcpip.c
new file mode 100644
index 0000000000000000000000000000000000000000..8a4ce5152cde146aa7f0ce8fcfec0f4f7da7e1e8
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/core/x86_tcpip.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * TCP/IP checksum
+ *
+ */
+
+#include <limits.h>
+#include <ipxe/tcpip.h>
+
+extern char x86_tcpip_loop_end[];
+
+/**
+ * Calculate continued TCP/IP checkum
+ *
+ * @v partial		Checksum of already-summed data, in network byte order
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret cksum		Updated checksum, in network byte order
+ */
+uint16_t x86_tcpip_continue_chksum ( uint16_t partial,
+				     const void *data, size_t len ) {
+	unsigned long sum = ( ( ~partial ) & 0xffff );
+	unsigned long initial_word_count;
+	unsigned long loop_count;
+	unsigned long loop_partial_count;
+	unsigned long final_word_count;
+	unsigned long final_byte;
+	unsigned long discard_S;
+	unsigned long discard_c;
+	unsigned long discard_a;
+	unsigned long discard_r1;
+	unsigned long discard_r2;
+
+	/* Calculate number of initial 16-bit words required to bring
+	 * the main loop into alignment.  (We don't care about the
+	 * speed for data aligned to less than 16 bits, since this
+	 * situation won't occur in practice.)
+	 */
+	if ( len >= sizeof ( sum ) ) {
+		initial_word_count = ( ( -( ( intptr_t ) data ) &
+					 ( sizeof ( sum ) - 1 ) ) >> 1 );
+	} else {
+		initial_word_count = 0;
+	}
+	len -= ( initial_word_count * 2 );
+
+	/* Calculate number of iterations of the main loop.  This loop
+	 * processes native machine words (32-bit or 64-bit), and is
+	 * unrolled 16 times.  We calculate an overall iteration
+	 * count, and a starting point for the first iteration.
+	 */
+	loop_count = ( len / ( sizeof ( sum ) * 16 ) );
+	loop_partial_count =
+		( ( len % ( sizeof ( sum ) * 16 ) ) / sizeof ( sum ) );
+
+	/* Calculate number of 16-bit words remaining after the main
+	 * loop completes.
+	 */
+	final_word_count = ( ( len % sizeof ( sum ) ) / 2 );
+
+	/* Calculate whether or not a final byte remains at the end */
+	final_byte = ( len & 1 );
+
+	/* Calculate the checksum */
+	__asm__ ( /* Calculate position at which to jump into the
+		   * unrolled loop.
+		   */
+		  "imul $( -x86_tcpip_loop_step_size ), %4\n\t"
+		  "add %5, %4\n\t"
+
+		  /* Clear carry flag before starting checksumming */
+		  "clc\n\t"
+
+		  /* Checksum initial words */
+		  "jmp 2f\n\t"
+		  "\n1:\n\t"
+		  "lodsw\n\t"
+		  "adcw %w2, %w0\n\t"
+		  "\n2:\n\t"
+		  "loop 1b\n\t"
+
+		  /* Main "lods;adc" loop, unrolled x16 */
+		  "mov %12, %3\n\t"
+		  "jmp *%4\n\t"
+		  "\nx86_tcpip_loop_start:\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "lods%z2\n\tadc %2, %0\n\t"
+		  "\nx86_tcpip_loop_end:\n\t"
+		  "loop x86_tcpip_loop_start\n\t"
+		  ".equ x86_tcpip_loop_step_size, "
+		  "  ( ( x86_tcpip_loop_end - x86_tcpip_loop_start ) >> 4 )\n\t"
+
+		  /* Checksum remaining whole words */
+		  "mov %13, %3\n\t"
+		  "jmp 2f\n\t"
+		  "\n1:\n\t"
+		  "lodsw\n\t"
+		  "adcw %w2, %w0\n\t"
+		  "\n2:\n\t"
+		  "loop 1b\n\t"
+
+		  /* Checksum final byte if applicable */
+		  "mov %14, %3\n\t"
+		  "loop 1f\n\t"
+		  "adcb (%1), %b0\n\t"
+		  "adcb $0, %h0\n\t"
+		  "\n1:\n\t"
+
+		  /* Fold down to a uint16_t */
+		  "push %0\n\t"
+		  "popw %w0\n\t"
+		  "popw %w2\n\t"
+		  "adcw %w2, %w0\n\t"
+#if ULONG_MAX > 0xffffffffUL /* 64-bit only */
+		  "popw %w2\n\t"
+		  "adcw %w2, %w0\n\t"
+		  "popw %w2\n\t"
+		  "adcw %w2, %w0\n\t"
+#endif /* 64-bit only */
+
+		  /* Consume CF */
+		  "adcw $0, %w0\n\t"
+		  "adcw $0, %w0\n\t"
+
+		  : "=&Q" ( sum ), "=&S" ( discard_S ), "=&a" ( discard_a ),
+		    "=&c" ( discard_c ), "=&r" ( discard_r1 ),
+		    "=&r" ( discard_r2 )
+		  : "0" ( sum ), "1" ( data ), "2" ( 0 ),
+		    "3" ( initial_word_count + 1 ), "4" ( loop_partial_count ),
+		    "5" ( x86_tcpip_loop_end ), "g" ( loop_count + 1 ),
+		    "g" ( final_word_count + 1 ), "g" ( final_byte ) );
+
+	return ( ~sum & 0xffff );
+}
diff --git a/roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c b/roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c
new file mode 100644
index 0000000000000000000000000000000000000000..981143308a925957a5bb5755b60f2348bdcf68a6
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/hci/commands/cpuid_cmd.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ipxe/cpuid.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+
+/** @file
+ *
+ * x86 CPU feature detection command
+ *
+ */
+
+/** "cpuid" options */
+struct cpuid_options {
+	/** Check AMD-defined features (%eax=0x80000001) */
+	int amd;
+	/** Check features defined via %ecx */
+	int ecx;
+};
+
+/** "cpuid" option list */
+static struct option_descriptor cpuid_opts[] = {
+	OPTION_DESC ( "ext", 'e', no_argument,
+		      struct cpuid_options, amd, parse_flag ),
+	/* "--amd" retained for backwards compatibility */
+	OPTION_DESC ( "amd", 'a', no_argument,
+		      struct cpuid_options, amd, parse_flag ),
+	OPTION_DESC ( "ecx", 'c', no_argument,
+		      struct cpuid_options, ecx, parse_flag ),
+};
+
+/** "cpuid" command descriptor */
+static struct command_descriptor cpuid_cmd =
+	COMMAND_DESC ( struct cpuid_options, cpuid_opts, 1, 1,
+		       "[--ext] [--ecx] <bit>" );
+
+/**
+ * The "cpuid" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int cpuid_exec ( int argc, char **argv ) {
+	struct cpuid_options opts;
+	struct x86_features features;
+	struct x86_feature_registers *feature_regs;
+	uint32_t feature_reg;
+	unsigned int bit;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &cpuid_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse bit number */
+	if ( ( rc = parse_integer ( argv[optind], &bit ) ) != 0 )
+		return rc;
+
+	/* Get CPU features */
+	x86_features ( &features );
+
+	/* Extract relevant feature register */
+	feature_regs = ( opts.amd ? &features.amd : &features.intel );
+	feature_reg = ( opts.ecx ? feature_regs->ecx : feature_regs->edx );
+
+	/* Check presence of specified feature */
+	return ( ( feature_reg & ( 1 << bit ) ) ? 0 : -ENOENT );
+}
+
+/** x86 CPU feature detection command */
+struct command cpuid_command __command = {
+	.name = "cpuid",
+	.exec = cpuid_exec,
+};
diff --git a/roms/ipxe/src/arch/x86/include/bits/bigint.h b/roms/ipxe/src/arch/x86/include/bits/bigint.h
new file mode 100644
index 0000000000000000000000000000000000000000..d3449af5a96ed33764e47cb8cc2bfbd04448b8a1
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/include/bits/bigint.h
@@ -0,0 +1,318 @@
+#ifndef _BITS_BIGINT_H
+#define _BITS_BIGINT_H
+
+/** @file
+ *
+ * Big integer support
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+
+/** Element of a big integer */
+typedef uint32_t bigint_element_t;
+
+/**
+ * Initialise big integer
+ *
+ * @v value0		Element 0 of big integer to initialise
+ * @v size		Number of elements
+ * @v data		Raw data
+ * @v len		Length of raw data
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_init_raw ( uint32_t *value0, unsigned int size,
+		  const void *data, size_t len ) {
+	long pad_len = ( sizeof ( bigint_t ( size ) ) - len );
+	void *discard_D;
+	long discard_c;
+
+	/* Copy raw data in reverse order, padding with zeros */
+	__asm__ __volatile__ ( "\n1:\n\t"
+			       "movb -1(%2,%1), %%al\n\t"
+			       "stosb\n\t"
+			       "loop 1b\n\t"
+			       "xorl %%eax, %%eax\n\t"
+			       "mov %3, %1\n\t"
+			       "rep stosb\n\t"
+			       : "=&D" ( discard_D ), "=&c" ( discard_c )
+			       : "r" ( data ), "g" ( pad_len ), "0" ( value0 ),
+				 "1" ( len )
+			       : "eax" );
+}
+
+/**
+ * Add big integers
+ *
+ * @v addend0		Element 0 of big integer to add
+ * @v value0		Element 0 of big integer to be added to
+ * @v size		Number of elements
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
+		 unsigned int size ) {
+	long index;
+	void *discard_S;
+	long discard_c;
+
+	__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
+			       "\n1:\n\t"
+			       "lodsl\n\t"
+			       "adcl %%eax, (%3,%0,4)\n\t"
+			       "inc %0\n\t" /* Does not affect CF */
+			       "loop 1b\n\t"
+			       : "=&r" ( index ), "=&S" ( discard_S ),
+				 "=&c" ( discard_c )
+			       : "r" ( value0 ), "1" ( addend0 ), "2" ( size )
+			       : "eax" );
+}
+
+/**
+ * Subtract big integers
+ *
+ * @v subtrahend0	Element 0 of big integer to subtract
+ * @v value0		Element 0 of big integer to be subtracted from
+ * @v size		Number of elements
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
+		      unsigned int size ) {
+	long index;
+	void *discard_S;
+	long discard_c;
+
+	__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
+			       "\n1:\n\t"
+			       "lodsl\n\t"
+			       "sbbl %%eax, (%3,%0,4)\n\t"
+			       "inc %0\n\t" /* Does not affect CF */
+			       "loop 1b\n\t"
+			       : "=&r" ( index ), "=&S" ( discard_S ),
+				 "=&c" ( discard_c )
+			       : "r" ( value0 ), "1" ( subtrahend0 ),
+				 "2" ( size )
+			       : "eax" );
+}
+
+/**
+ * Rotate big integer left
+ *
+ * @v value0		Element 0 of big integer
+ * @v size		Number of elements
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_rol_raw ( uint32_t *value0, unsigned int size ) {
+	long index;
+	long discard_c;
+
+	__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
+			       "\n1:\n\t"
+			       "rcll $1, (%2,%0,4)\n\t"
+			       "inc %0\n\t" /* Does not affect CF */
+			       "loop 1b\n\t"
+			       : "=&r" ( index ), "=&c" ( discard_c )
+			       : "r" ( value0 ), "1" ( size ) );
+}
+
+/**
+ * Rotate big integer right
+ *
+ * @v value0		Element 0 of big integer
+ * @v size		Number of elements
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_ror_raw ( uint32_t *value0, unsigned int size ) {
+	long discard_c;
+
+	__asm__ __volatile__ ( "clc\n\t"
+			       "\n1:\n\t"
+			       "rcrl $1, -4(%1,%0,4)\n\t"
+			       "loop 1b\n\t"
+			       : "=&c" ( discard_c )
+			       : "r" ( value0 ), "0" ( size ) );
+}
+
+/**
+ * Test if big integer is equal to zero
+ *
+ * @v value0		Element 0 of big integer
+ * @v size		Number of elements
+ * @ret is_zero		Big integer is equal to zero
+ */
+static inline __attribute__ (( always_inline, pure )) int
+bigint_is_zero_raw ( const uint32_t *value0, unsigned int size ) {
+	void *discard_D;
+	long discard_c;
+	int result;
+
+	__asm__ __volatile__ ( "xor %0, %0\n\t" /* Set ZF */
+			       "repe scasl\n\t"
+			       "sete %b0\n\t"
+			       : "=&a" ( result ), "=&D" ( discard_D ),
+				 "=&c" ( discard_c )
+			       : "1" ( value0 ), "2" ( size ) );
+	return result;
+}
+
+/**
+ * Compare big integers
+ *
+ * @v value0		Element 0 of big integer
+ * @v reference0	Element 0 of reference big integer
+ * @v size		Number of elements
+ * @ret geq		Big integer is greater than or equal to the reference
+ */
+static inline __attribute__ (( always_inline, pure )) int
+bigint_is_geq_raw ( const uint32_t *value0, const uint32_t *reference0,
+		    unsigned int size ) {
+	const bigint_t ( size ) __attribute__ (( may_alias )) *value =
+		( ( const void * ) value0 );
+	const bigint_t ( size ) __attribute__ (( may_alias )) *reference =
+		( ( const void * ) reference0 );
+	void *discard_S;
+	void *discard_D;
+	long discard_c;
+	int result;
+
+	__asm__ __volatile__ ( "std\n\t"
+			       "\n1:\n\t"
+			       "lodsl\n\t"
+			       "scasl\n\t"
+			       "loope 1b\n\t"
+			       "setae %b0\n\t"
+			       "cld\n\t"
+			       : "=q" ( result ), "=&S" ( discard_S ),
+				 "=&D" ( discard_D ), "=&c" ( discard_c )
+			       : "0" ( 0 ), "1" ( &value->element[ size - 1 ] ),
+				 "2" ( &reference->element[ size - 1 ] ),
+				 "3" ( size )
+			       : "eax" );
+	return result;
+}
+
+/**
+ * Test if bit is set in big integer
+ *
+ * @v value0		Element 0 of big integer
+ * @v size		Number of elements
+ * @v bit		Bit to test
+ * @ret is_set		Bit is set
+ */
+static inline __attribute__ (( always_inline )) int
+bigint_bit_is_set_raw ( const uint32_t *value0, unsigned int size,
+			unsigned int bit ) {
+	const bigint_t ( size ) __attribute__ (( may_alias )) *value =
+		( ( const void * ) value0 );
+	unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) );
+	unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) );
+
+	return ( value->element[index] & ( 1 << subindex ) );
+}
+
+/**
+ * Find highest bit set in big integer
+ *
+ * @v value0		Element 0 of big integer
+ * @v size		Number of elements
+ * @ret max_bit		Highest bit set + 1 (or 0 if no bits set)
+ */
+static inline __attribute__ (( always_inline )) int
+bigint_max_set_bit_raw ( const uint32_t *value0, unsigned int size ) {
+	long discard_c;
+	int result;
+
+	__asm__ __volatile__ ( "\n1:\n\t"
+			       "bsrl -4(%2,%1,4), %0\n\t"
+			       "loopz 1b\n\t"
+			       "rol %1\n\t" /* Does not affect ZF */
+			       "rol %1\n\t"
+			       "leal 1(%k0,%k1,8), %k0\n\t"
+			       "jnz 2f\n\t"
+			       "xor %0, %0\n\t"
+			       "\n2:\n\t"
+			       : "=&r" ( result ), "=&c" ( discard_c )
+			       : "r" ( value0 ), "1" ( size ) );
+	return result;
+}
+
+/**
+ * Grow big integer
+ *
+ * @v source0		Element 0 of source big integer
+ * @v source_size	Number of elements in source big integer
+ * @v dest0		Element 0 of destination big integer
+ * @v dest_size		Number of elements in destination big integer
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
+		  uint32_t *dest0, unsigned int dest_size ) {
+	long pad_size = ( dest_size - source_size );
+	void *discard_D;
+	void *discard_S;
+	long discard_c;
+
+	__asm__ __volatile__ ( "rep movsl\n\t"
+			       "xorl %%eax, %%eax\n\t"
+			       "mov %3, %2\n\t"
+			       "rep stosl\n\t"
+			       : "=&D" ( discard_D ), "=&S" ( discard_S ),
+				 "=&c" ( discard_c )
+			       : "g" ( pad_size ), "0" ( dest0 ),
+				 "1" ( source0 ), "2" ( source_size )
+			       : "eax" );
+}
+
+/**
+ * Shrink big integer
+ *
+ * @v source0		Element 0 of source big integer
+ * @v source_size	Number of elements in source big integer
+ * @v dest0		Element 0 of destination big integer
+ * @v dest_size		Number of elements in destination big integer
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused,
+		    uint32_t *dest0, unsigned int dest_size ) {
+	void *discard_D;
+	void *discard_S;
+	long discard_c;
+
+	__asm__ __volatile__ ( "rep movsl\n\t"
+			       : "=&D" ( discard_D ), "=&S" ( discard_S ),
+				 "=&c" ( discard_c )
+			       : "0" ( dest0 ), "1" ( source0 ),
+				 "2" ( dest_size )
+			       : "eax" );
+}
+
+/**
+ * Finalise big integer
+ *
+ * @v value0		Element 0 of big integer to finalise
+ * @v size		Number of elements
+ * @v out		Output buffer
+ * @v len		Length of output buffer
+ */
+static inline __attribute__ (( always_inline )) void
+bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
+		  void *out, size_t len ) {
+	void *discard_D;
+	long discard_c;
+
+	/* Copy raw data in reverse order */
+	__asm__ __volatile__ ( "\n1:\n\t"
+			       "movb -1(%2,%1), %%al\n\t"
+			       "stosb\n\t"
+			       "loop 1b\n\t"
+			       : "=&D" ( discard_D ), "=&c" ( discard_c )
+			       : "r" ( value0 ), "0" ( out ), "1" ( len )
+			       : "eax" );
+}
+
+extern void bigint_multiply_raw ( const uint32_t *multiplicand0,
+				  const uint32_t *multiplier0,
+				  uint32_t *value0, unsigned int size );
+
+#endif /* _BITS_BIGINT_H */
diff --git a/roms/ipxe/src/arch/x86/include/bits/errfile.h b/roms/ipxe/src/arch/x86/include/bits/errfile.h
new file mode 100644
index 0000000000000000000000000000000000000000..7b9f3702e8e2698e8472e4e1f63a5b8d5efc01d0
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/include/bits/errfile.h
@@ -0,0 +1,50 @@
+#ifndef _BITS_ERRFILE_H
+#define _BITS_ERRFILE_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @addtogroup errfile Error file identifiers
+ * @{
+ */
+
+#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_bios_smbios	( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 )
+#define ERRFILE_biosint		( ERRFILE_ARCH | ERRFILE_CORE | 0x00040000 )
+#define ERRFILE_int13		( ERRFILE_ARCH | ERRFILE_CORE | 0x00050000 )
+#define ERRFILE_pxeparent	( ERRFILE_ARCH | ERRFILE_CORE | 0x00060000 )
+#define ERRFILE_runtime		( ERRFILE_ARCH | ERRFILE_CORE | 0x00070000 )
+#define ERRFILE_vmware		( ERRFILE_ARCH | ERRFILE_CORE | 0x00080000 )
+#define ERRFILE_guestrpc	( ERRFILE_ARCH | ERRFILE_CORE | 0x00090000 )
+#define ERRFILE_guestinfo	( ERRFILE_ARCH | ERRFILE_CORE | 0x000a0000 )
+
+#define ERRFILE_bootsector     ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
+#define ERRFILE_bzimage	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
+#define ERRFILE_eltorito       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00020000 )
+#define ERRFILE_multiboot      ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00030000 )
+#define ERRFILE_nbi	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00040000 )
+#define ERRFILE_pxe_image      ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00050000 )
+#define ERRFILE_elfboot	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00060000 )
+#define ERRFILE_comboot        ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00070000 )
+#define ERRFILE_com32          ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00080000 )
+#define ERRFILE_comboot_resolv ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00090000 )
+#define ERRFILE_comboot_call   ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000a0000 )
+#define ERRFILE_sdi	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000b0000 )
+#define ERRFILE_initrd	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000c0000 )
+
+#define ERRFILE_undi		 ( ERRFILE_ARCH | ERRFILE_NET | 0x00000000 )
+#define ERRFILE_undiload	 ( ERRFILE_ARCH | ERRFILE_NET | 0x00010000 )
+#define ERRFILE_undinet		 ( ERRFILE_ARCH | ERRFILE_NET | 0x00020000 )
+#define ERRFILE_undionly	 ( ERRFILE_ARCH | ERRFILE_NET | 0x00030000 )
+#define ERRFILE_undirom		 ( ERRFILE_ARCH | ERRFILE_NET | 0x00040000 )
+
+#define ERRFILE_timer_rdtsc   ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00000000 )
+#define ERRFILE_timer_bios    ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00010000 )
+
+#define ERRFILE_cpuid_cmd      ( ERRFILE_ARCH | ERRFILE_OTHER | 0x00000000 )
+
+/** @} */
+
+#endif /* _BITS_ERRFILE_H */
diff --git a/roms/ipxe/src/arch/x86/include/bits/io.h b/roms/ipxe/src/arch/x86/include/bits/io.h
new file mode 100644
index 0000000000000000000000000000000000000000..cb1b67a6ff7620d1c9cdd4d7471bc6eb4cbba62c
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/include/bits/io.h
@@ -0,0 +1,14 @@
+#ifndef _BITS_IO_H
+#define _BITS_IO_H
+
+/** @file
+ *
+ * x86-specific I/O API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/x86_io.h>
+
+#endif /* _BITS_IO_H */
diff --git a/roms/ipxe/src/arch/x86/include/bits/string.h b/roms/ipxe/src/arch/x86/include/bits/string.h
index f35cdab1c7deaca34d32d9cd099f..dce99498328209d3925ee0b47246 100644
--- a/roms/ipxe/src/arch/x86/include/bits/string.h
+++ b/roms/ipxe/src/arch/x86/include/bits/string.h
@@ -1,44 +1,46 @@
-#ifndef ETHERBOOT_BITS_STRING_H
-#define ETHERBOOT_BITS_STRING_H
+#ifndef X86_BITS_STRING_H
+#define X86_BITS_STRING_H
+
 /*
- * Taken from Linux /usr/include/asm/string.h
- * All except memcpy, memmove, memset and memcmp removed.
+ * Copyright (C) 2007 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.
  *
- * Non-standard memswap() function added because it saves quite a bit
- * of code (mbrown@fensystems.co.uk).
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
-/*
- * This string-include defines all string functions as inline
- * functions. Use gcc. It also assumes ds=es=data space, this should be
- * normal. Most of the string-functions are rather heavily hand-optimized,
- * see especially strtok,strstr,str[c]spn. They should work, but are not
- * very easy to understand. Everything is done entirely within the register
- * set, making the functions fast and clean. String instructions have been
- * used through-out, making for "slightly" unclear code :-)
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Optimised string operations
  *
- *		NO Copyright (C) 1991, 1992 Linus Torvalds,
- *		consider these trivial functions to be PD.
  */
 
-FILE_LICENCE ( PUBLIC_DOMAIN );
-
 #define __HAVE_ARCH_MEMCPY
 
 extern void * __memcpy ( void *dest, const void *src, size_t len );
+extern void * __memcpy_reverse ( void *dest, const void *src, size_t len );
 
-#if 0
-static inline __attribute__ (( always_inline )) void *
-__memcpy ( void *dest, const void *src, size_t len ) {
-	int d0, d1, d2;
-	__asm__ __volatile__ ( "rep ; movsb"
-			       : "=&c" ( d0 ), "=&S" ( d1 ), "=&D" ( d2 )
-			       : "0" ( len ), "1" ( src ), "2" ( dest )
-			       : "memory" );
-	return dest; 
-}
-#endif
-
+/**
+ * Copy memory area (where length is a compile-time constant)
+ *
+ * @v dest		Destination address
+ * @v src		Source address
+ * @v len		Length
+ * @ret dest		Destination address
+ */
 static inline __attribute__ (( always_inline )) void *
 __constant_memcpy ( void *dest, const void *src, size_t len ) {
 	union {
@@ -150,103 +152,81 @@ __constant_memcpy ( void *dest, const void *src, size_t len ) {
 	return dest;
 }
 
-#define memcpy( dest, src, len )			\
-	( __builtin_constant_p ( (len) ) ?		\
-	  __constant_memcpy ( (dest), (src), (len) ) :	\
-	  __memcpy ( (dest), (src), (len) ) )
+/**
+ * Copy memory area
+ *
+ * @v dest		Destination address
+ * @v src		Source address
+ * @v len		Length
+ * @ret dest		Destination address
+ */
+static inline __attribute__ (( always_inline )) void *
+memcpy ( void *dest, const void *src, size_t len ) {
+	if ( __builtin_constant_p ( len ) ) {
+		return __constant_memcpy ( dest, src, len );
+	} else {
+		return __memcpy ( dest, src, len );
+	}
+}
 
 #define __HAVE_ARCH_MEMMOVE
-static inline void * memmove(void * dest,const void * src, size_t n)
-{
-int d0, d1, d2;
-if (dest<src)
-__asm__ __volatile__(
-	"cld\n\t"
-	"rep\n\t"
-	"movsb"
-	: "=&c" (d0), "=&S" (d1), "=&D" (d2)
-	:"0" (n),"1" (src),"2" (dest)
-	: "memory");
-else
-__asm__ __volatile__(
-	"std\n\t"
-	"rep\n\t"
-	"movsb\n\t"
-	"cld"
-	: "=&c" (d0), "=&S" (d1), "=&D" (d2)
-	:"0" (n),
-	 "1" (n-1+(const char *)src),
-	 "2" (n-1+(char *)dest)
-	:"memory");
-return dest;
+
+extern void * __memmove ( void *dest, const void *src, size_t len );
+
+/**
+ * Copy (possibly overlapping) memory area
+ *
+ * @v dest		Destination address
+ * @v src		Source address
+ * @v len		Length
+ * @ret dest		Destination address
+ */
+static inline __attribute__ (( always_inline )) void *
+memmove ( void *dest, const void *src, size_t len ) {
+	ssize_t offset = ( dest - src );
+
+	if ( __builtin_constant_p ( offset ) ) {
+		if ( offset <= 0 ) {
+			return memcpy ( dest, src, len );
+		} else {
+			return __memcpy_reverse ( dest, src, len );
+		}
+	} else {
+		return __memmove ( dest, src, len );
+	}
 }
 
 #define __HAVE_ARCH_MEMSET
-static inline void * memset(void *s, int c,size_t count)
-{
-int d0, d1;
-__asm__ __volatile__(
-	"cld\n\t"
-	"rep\n\t"
-	"stosb"
-	: "=&c" (d0), "=&D" (d1)
-	:"a" (c),"1" (s),"0" (count)
-	:"memory");
-return s;
+
+/**
+ * Fill memory region
+ *
+ * @v dest		Destination address
+ * @v fill		Fill pattern
+ * @v len		Length
+ * @ret dest		Destination address
+ */
+static inline void * memset ( void *dest, int fill, size_t len ) {
+	void *discard_D;
+	size_t discard_c;
+
+	__asm__ __volatile__ ( "rep stosb"
+			       : "=&D" ( discard_D ), "=&c" ( discard_c )
+			       : "0" ( dest ), "1" ( len ), "a" ( fill )
+			       : "memory" );
+	return dest;
 }
 
 #define __HAVE_ARCH_MEMSWAP
-static inline void * memswap(void *dest, void *src, size_t n)
-{
-long d0, d1, d2, d3;
-__asm__ __volatile__(
-	"\n1:\t"
-	"movb (%2),%%al\n\t"
-	"xchgb (%1),%%al\n\t"
-	"inc %1\n\t"
-	"stosb\n\t"
-	"loop 1b"
-	: "=&c" (d0), "=&S" (d1), "=&D" (d2), "=&a" (d3)
-	: "0" (n), "1" (src), "2" (dest)
-	: "memory" );
-return dest;
-}
+
+extern void * memswap ( void *dest, void *src, size_t len );
 
 #define __HAVE_ARCH_STRNCMP
-static inline int strncmp(const char * cs,const char * ct,size_t count)
-{
-register int __res;
-int d0, d1, d2;
-__asm__ __volatile__(
-	"1:\tdecl %3\n\t"
-	"js 2f\n\t"
-	"lodsb\n\t"
-	"scasb\n\t"
-	"jne 3f\n\t"
-	"testb %%al,%%al\n\t"
-	"jne 1b\n"
-	"2:\txorl %%eax,%%eax\n\t"
-	"jmp 4f\n"
-	"3:\tsbbl %%eax,%%eax\n\t"
-	"orb $1,%%al\n"
-	"4:"
-		     :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
-		     :"1" (cs),"2" (ct),"3" (count));
-return __res;
-}
+
+extern int strncmp ( const char *str1, const char *str2, size_t len );
 
 #define __HAVE_ARCH_STRLEN
-static inline size_t strlen(const char * s)
-{
-int d0;
-register int __res;
-__asm__ __volatile__(
-	"repne\n\t"
-	"scasb\n\t"
-	"notl %0\n\t"
-	"decl %0"
-	:"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffff));
-return __res;
-}
 
-#endif /* ETHERBOOT_BITS_STRING_H */
+extern size_t strlen ( const char *string );
+
+#endif /* X86_BITS_STRING_H */
diff --git a/roms/ipxe/src/arch/x86/include/bits/tcpip.h b/roms/ipxe/src/arch/x86/include/bits/tcpip.h
new file mode 100644
index 0000000000000000000000000000000000000000..a4b335eb134c098708de13975999337a218ae652
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/include/bits/tcpip.h
@@ -0,0 +1,17 @@
+#ifndef _BITS_TCPIP_H
+#define _BITS_TCPIP_H
+
+/** @file
+ *
+ * Transport-network layer interface
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+extern uint16_t x86_tcpip_continue_chksum ( uint16_t partial,
+					    const void *data, size_t len );
+
+#define tcpip_continue_chksum x86_tcpip_continue_chksum
+
+#endif /* _BITS_TCPIP_H */
diff --git a/roms/ipxe/src/arch/x86/include/ipxe/cpuid.h b/roms/ipxe/src/arch/x86/include/ipxe/cpuid.h
new file mode 100644
index 0000000000000000000000000000000000000000..9705137c6a26b4ec3aff40ecd89951abd4f0b399
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/include/ipxe/cpuid.h
@@ -0,0 +1,53 @@
+#ifndef _IPXE_CPUID_H
+#define _IPXE_CPUID_H
+
+/** @file
+ *
+ * x86 CPU feature detection
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/** An x86 CPU feature register set */
+struct x86_feature_registers {
+	/** Features returned via %ecx */
+	uint32_t ecx;
+	/** Features returned via %edx */
+	uint32_t edx;
+};
+
+/** x86 CPU features */
+struct x86_features {
+	/** Intel-defined features (%eax=0x00000001) */
+	struct x86_feature_registers intel;
+	/** AMD-defined features (%eax=0x80000001) */
+	struct x86_feature_registers amd;
+};
+
+/** CPUID support flag */
+#define CPUID_FLAG 0x00200000UL
+
+/** Get vendor ID and largest standard function */
+#define CPUID_VENDOR_ID 0x00000000UL
+
+/** Get standard features */
+#define CPUID_FEATURES 0x00000001UL
+
+/** Get largest extended function */
+#define CPUID_AMD_MAX_FN 0x80000000UL
+
+/** Extended function existence check */
+#define CPUID_AMD_CHECK 0x80000000UL
+
+/** Extended function existence check mask */
+#define CPUID_AMD_CHECK_MASK 0xffff0000UL
+
+/** Get extended features */
+#define CPUID_AMD_FEATURES 0x80000001UL
+
+extern void x86_features ( struct x86_features *features );
+
+#endif /* _IPXE_CPUID_H */
diff --git a/roms/ipxe/src/arch/x86/include/ipxe/x86_io.h b/roms/ipxe/src/arch/x86/include/ipxe/x86_io.h
new file mode 100644
index 0000000000000000000000000000000000000000..adb00a6867d401ea96f4026a1b53516ffabad8bc
--- /dev/null
+++ b/roms/ipxe/src/arch/x86/include/ipxe/x86_io.h
@@ -0,0 +1,159 @@
+#ifndef _IPXE_X86_IO_H
+#define _IPXE_X86_IO_H
+
+/** @file
+ *
+ * iPXE I/O API for x86
+ *
+ * x86 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
+ * under i386, 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.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#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 native word size
+ *
+ */
+
+#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 );
+#ifdef __x86_64__
+X86_READX ( readq, uint64_t );
+#endif
+
+#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 );
+#ifdef __x86_64__
+X86_WRITEX ( writeq, uint64_t );
+#endif
+
+/*
+ * 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 /* _IPXE_X86_IO_H */
diff --git a/roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c b/roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c
index b6bee6276e3b93b2d7152f1b5de0..b05421fabf3bbda209c2905e2516 100644
--- a/roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c
+++ b/roms/ipxe/src/arch/x86/interface/efi/efix86_nap.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c b/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c
index a96c5c439b0afb4891698b731405..8a31df56d45fecd5182fdd3085c8 100644
--- a/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c
+++ b/roms/ipxe/src/arch/x86/prefix/efidrvprefix.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/x86/prefix/efiprefix.c b/roms/ipxe/src/arch/x86/prefix/efiprefix.c
index 1515c6fc48aac7d6cbe4f3235d16..bfa94d404de17bcb31777912795b 100644
--- a/roms/ipxe/src/arch/x86/prefix/efiprefix.c
+++ b/roms/ipxe/src/arch/x86/prefix/efiprefix.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/arch/x86_64/Makefile b/roms/ipxe/src/arch/x86_64/Makefile
index d2c2ff53d91dc4d2e8517583e734..b687f3407970eba6fd343810125e 100644
--- a/roms/ipxe/src/arch/x86_64/Makefile
+++ b/roms/ipxe/src/arch/x86_64/Makefile
@@ -26,6 +26,18 @@ CFLAGS		+= -fshort-wchar
 #
 CFLAGS			+= -Ui386
 
+# Add -maccumulate-outgoing-args if required by this version of gcc
+#
+ifeq ($(CCTYPE),gcc)
+MS_ABI_TEST_CODE := extern void __attribute__ (( ms_abi )) ms_abi(); \
+		    void sysv_abi ( void ) { ms_abi(); }
+MS_ABI_TEST = $(ECHO) '$(MS_ABI_TEST_CODE)' | \
+	      $(CC) -m64 -mno-accumulate-outgoing-args -x c -c - -o /dev/null \
+		    >/dev/null 2>&1
+MS_ABI_FLAGS := $(shell $(MS_ABI_TEST) || $(ECHO) '-maccumulate-outgoing-args')
+WORKAROUND_CFLAGS += $(MS_ABI_FLAGS)
+endif
+
 # x86_64-specific directories containing source files
 #
 SRCDIRS		+= arch/x86_64/prefix
diff --git a/roms/ipxe/src/arch/x86_64/core/linux/linuxprefix.S b/roms/ipxe/src/arch/x86_64/core/linux/linuxprefix.S
new file mode 100644
index 0000000000000000000000000000000000000000..ec8a9decdd01547072550866645b10c15ff1138f
--- /dev/null
+++ b/roms/ipxe/src/arch/x86_64/core/linux/linuxprefix.S
@@ -0,0 +1,25 @@
+#include <linux/unistd.h>
+
+	.section ".text"
+	.code64
+	.globl _linux_start
+	.type _linux_start, @function
+
+_linux_start:
+	xorq	%rbp, %rbp
+
+	popq	%rdi       // argc -> C arg1
+	movq	%rsp, %rsi // argv -> C arg2
+
+	andq	$~15, %rsp // 16-byte align the stack
+
+	call	save_args
+
+	/* Our main doesn't use any arguments */
+	call	main
+
+	movq	%rax, %rdi // rc -> syscall arg1
+	movq	$__NR_exit, %rax
+	syscall
+
+	.size _linux_start, . - _linux_start
diff --git a/roms/ipxe/src/arch/x86_64/include/bits/byteswap.h b/roms/ipxe/src/arch/x86_64/include/bits/byteswap.h
index 9ed85e8f8af80b5b114c8ac5a151..2e472d98ad02d834b10cc344afe0 100644
--- a/roms/ipxe/src/arch/x86_64/include/bits/byteswap.h
+++ b/roms/ipxe/src/arch/x86_64/include/bits/byteswap.h
@@ -1,22 +1,47 @@
 #ifndef _BITS_BYTESWAP_H
 #define _BITS_BYTESWAP_H
 
+/** @file
+ *
+ * Byte-order swapping functions
+ *
+ */
+
+#include <stdint.h>
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
 static inline __attribute__ (( always_inline, const )) uint16_t
 __bswap_variable_16 ( uint16_t x ) {
 	__asm__ ( "xchgb %b0,%h0" : "=Q" ( x ) : "0" ( x ) );
 	return x;
 }
 
+static inline __attribute__ (( always_inline )) void
+__bswap_16s ( uint16_t *x ) {
+	__asm__ ( "rorw $8, %0" : "+m" ( *x ) );
+}
+
 static inline __attribute__ (( always_inline, const )) uint32_t
 __bswap_variable_32 ( uint32_t x ) {
 	__asm__ ( "bswapl %k0" : "=r" ( x ) : "0" ( x ) );
 	return x;
 }
 
+static inline __attribute__ (( always_inline )) void
+__bswap_32s ( uint32_t *x ) {
+	__asm__ ( "bswapl %k0" : "=r" ( *x ) : "0" ( *x ) );
+}
+
 static inline __attribute__ (( always_inline, const )) uint64_t
 __bswap_variable_64 ( uint64_t x ) {
 	__asm__ ( "bswapq %q0" : "=r" ( x ) : "0" ( x ) );
 	return x;
 }
 
+static inline __attribute__ (( always_inline )) void
+__bswap_64s ( uint64_t *x ) {
+	__asm__ ( "bswapq %q0" : "=r" ( *x ) : "0" ( *x ) );
+}
+
 #endif /* _BITS_BYTESWAP_H */
diff --git a/roms/ipxe/src/arch/x86_64/include/bits/entropy.h b/roms/ipxe/src/arch/x86_64/include/bits/entropy.h
new file mode 100644
index 0000000000000000000000000000000000000000..9c64c833b6b136b815d69cfe202f2e59254f56e1
--- /dev/null
+++ b/roms/ipxe/src/arch/x86_64/include/bits/entropy.h
@@ -0,0 +1,12 @@
+#ifndef _BITS_ENTROPY_H
+#define _BITS_ENTROPY_H
+
+/** @file
+ *
+ * x86_64-specific entropy API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#endif /* _BITS_ENTROPY_H */
diff --git a/roms/ipxe/src/arch/x86_64/include/bits/errfile.h b/roms/ipxe/src/arch/x86_64/include/bits/errfile.h
deleted file mode 100644
index dcda26ba408a6c6614e3d2bc83bff0afbe9c5bff..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/arch/x86_64/include/bits/errfile.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef _BITS_ERRFILE_H
-#define _BITS_ERRFILE_H
-
-/**
- * @addtogroup errfile Error file identifiers
- * @{
- */
-
-/** @} */
-
-#endif /* _BITS_ERRFILE_H */
diff --git a/roms/ipxe/src/arch/x86_64/include/bits/io.h b/roms/ipxe/src/arch/x86_64/include/bits/io.h
deleted file mode 100644
index 921fdcc05e076f9e88d83461051b950312e1ad5d..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/arch/x86_64/include/bits/io.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _BITS_IO_H
-#define _BITS_IO_H
-
-/** @file
- *
- * x86_64-specific I/O API implementations
- *
- */
-
-#endif /* _BITS_IO_H */
diff --git a/roms/ipxe/src/arch/x86_64/include/bits/time.h b/roms/ipxe/src/arch/x86_64/include/bits/time.h
new file mode 100644
index 0000000000000000000000000000000000000000..59b355359d3af33ccff4f109613c9e4372ba1641
--- /dev/null
+++ b/roms/ipxe/src/arch/x86_64/include/bits/time.h
@@ -0,0 +1,12 @@
+#ifndef _BITS_TIME_H
+#define _BITS_TIME_H
+
+/** @file
+ *
+ * x86_64-specific time API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#endif /* _BITS_TIME_H */
diff --git a/roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h b/roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h
index af41b195ea5259c33fe2be21242c..9a4790fdce37b09285d7a58ccb49 100644
--- a/roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h
+++ b/roms/ipxe/src/arch/x86_64/include/efi/ipxe/dhcp_arch.h
@@ -30,10 +30,11 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 #define DHCP_ARCH_VENDOR_CLASS_ID \
 	DHCP_STRING ( 'P', 'X', 'E', 'C', 'l', 'i', 'e', 'n', 't', ':',      \
-		      'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '7', ':', \
+		      'A', 'r', 'c', 'h', ':', '0', '0', '0', '0', '9', ':', \
 		      'U', 'N', 'D', 'I', ':', '0', '0', '3', '0', '1', '0' )
 
-#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_WORD ( 7 )
+#define DHCP_ARCH_CLIENT_ARCHITECTURE \
+	DHCP_WORD ( DHCP_CLIENT_ARCHITECTURE_X86_64 )
 
 #define DHCP_ARCH_CLIENT_NDI DHCP_OPTION ( 1 /* UNDI */ , 3, 10 /* v3.10 */ )
 
diff --git a/roms/ipxe/src/arch/x86_64/prefix/linuxprefix.S b/roms/ipxe/src/arch/x86_64/prefix/linuxprefix.S
deleted file mode 100644
index 713b9e38dd36ca54a3410771ece9ce664a8372cc..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/arch/x86_64/prefix/linuxprefix.S
+++ /dev/null
@@ -1,25 +0,0 @@
-#include <linux/unistd.h>
-
-	.section ".text"
-	.code64
-	.globl _linux_start
-	.type _linux_start, @function
-
-_linux_start:
-	xorq	%rbp, %rbp
-
-	popq	%rdi       // argc -> C arg1
-	movq	%rsp, %rsi // argv -> C arg2
-
-	andq	$~15, %rsp // 16-byte align the stack
-
-	call	save_args
-
-	/* Our main doesn't use any arguments */
-	call	main
-
-	movq	%rax, %rdi // rc -> syscall arg1
-	movq	$__NR_exit, %rax
-	syscall
-
-	.size _start, . - _start
diff --git a/roms/ipxe/src/config/colour.h b/roms/ipxe/src/config/colour.h
new file mode 100644
index 0000000000000000000000000000000000000000..d32d46dc5a24045a4ba8cf5285a64d3e25a29840
--- /dev/null
+++ b/roms/ipxe/src/config/colour.h
@@ -0,0 +1,32 @@
+#ifndef CONFIG_COLOUR_H
+#define CONFIG_COLOUR_H
+
+/** @file
+ *
+ * Display colour configuration
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#define COLOR_NORMAL_FG		COLOR_WHITE
+#define COLOR_NORMAL_BG		COLOR_BLUE
+
+#define COLOR_SELECT_FG		COLOR_WHITE
+#define COLOR_SELECT_BG		COLOR_RED
+
+#define COLOR_SEPARATOR_FG	COLOR_CYAN
+#define COLOR_SEPARATOR_BG	COLOR_BLUE
+
+#define COLOR_EDIT_FG		COLOR_BLACK
+#define COLOR_EDIT_BG		COLOR_CYAN
+
+#define COLOR_ALERT_FG		COLOR_WHITE
+#define COLOR_ALERT_BG		COLOR_RED
+
+#define COLOR_URL_FG		COLOR_CYAN
+#define COLOR_URL_BG		COLOR_BLUE
+
+#include <config/local/colour.h>
+
+#endif /* CONFIG_COLOUR_H */
diff --git a/roms/ipxe/src/config/config.c b/roms/ipxe/src/config/config.c
index 2c3555ead414e846c4e6dcb154f2..bd1d98856a05d3800e9fa16c2602 100644
--- a/roms/ipxe/src/config/config.c
+++ b/roms/ipxe/src/config/config.c
@@ -71,21 +71,27 @@ REQUIRE_OBJECT ( serial_console );
 #ifdef CONSOLE_DIRECT_VGA
 REQUIRE_OBJECT ( video_subr );
 #endif
-#ifdef CONSOLE_BTEXT
-REQUIRE_OBJECT ( btext );
-#endif
 #ifdef CONSOLE_PC_KBD
 REQUIRE_OBJECT ( pc_kbd );
 #endif
 #ifdef CONSOLE_SYSLOG
 REQUIRE_OBJECT ( syslog );
 #endif
+#ifdef CONSOLE_SYSLOGS
+REQUIRE_OBJECT ( syslogs );
+#endif
 #ifdef CONSOLE_EFI
 REQUIRE_OBJECT ( efi_console );
 #endif
 #ifdef CONSOLE_LINUX
 REQUIRE_OBJECT ( linux_console );
 #endif
+#ifdef CONSOLE_VMWARE
+REQUIRE_OBJECT ( vmconsole );
+#endif
+#ifdef CONSOLE_DEBUGCON
+REQUIRE_OBJECT ( debugcon );
+#endif
 
 /*
  * Drag in all requested network protocols
@@ -122,9 +128,6 @@ REQUIRE_OBJECT ( https );
 #ifdef DOWNLOAD_PROTO_FTP
 REQUIRE_OBJECT ( ftp );
 #endif
-#ifdef DOWNLOAD_PROTO_TFTM
-REQUIRE_OBJECT ( tftm );
-#endif
 #ifdef DOWNLOAD_PROTO_SLAM
 REQUIRE_OBJECT ( slam );
 #endif
@@ -155,18 +158,9 @@ REQUIRE_OBJECT ( nbi );
 #ifdef IMAGE_ELF
 REQUIRE_OBJECT ( elfboot );
 #endif
-#ifdef IMAGE_FREEBSD
-REQUIRE_OBJECT ( freebsd );
-#endif
 #ifdef IMAGE_MULTIBOOT
 REQUIRE_OBJECT ( multiboot );
 #endif
-#ifdef IMAGE_AOUT
-REQUIRE_OBJECT ( aout );
-#endif
-#ifdef IMAGE_WINCE
-REQUIRE_OBJECT ( wince );
-#endif
 #ifdef IMAGE_PXE
 REQUIRE_OBJECT ( pxe_image );
 #endif
@@ -190,6 +184,9 @@ REQUIRE_OBJECT ( comboot_resolv );
 #ifdef IMAGE_EFI
 REQUIRE_OBJECT ( efi_image );
 #endif
+#ifdef IMAGE_SDI
+REQUIRE_OBJECT ( sdi );
+#endif
 
 /*
  * Drag in all requested commands
@@ -214,12 +211,18 @@ REQUIRE_OBJECT ( route_cmd );
 #ifdef IMAGE_CMD
 REQUIRE_OBJECT ( image_cmd );
 #endif
+#ifdef IMAGE_TRUST_CMD
+REQUIRE_OBJECT ( image_trust_cmd );
+#endif
 #ifdef DHCP_CMD
 REQUIRE_OBJECT ( dhcp_cmd );
 #endif
 #ifdef SANBOOT_CMD
 REQUIRE_OBJECT ( sanboot_cmd );
 #endif
+#ifdef MENU_CMD
+REQUIRE_OBJECT ( menu_cmd );
+#endif
 #ifdef LOGIN_CMD
 REQUIRE_OBJECT ( login_cmd );
 #endif
@@ -241,6 +244,15 @@ REQUIRE_OBJECT ( vlan_cmd );
 #ifdef REBOOT_CMD
 REQUIRE_OBJECT ( reboot_cmd );
 #endif
+#ifdef CPUID_CMD
+REQUIRE_OBJECT ( cpuid_cmd );
+#endif
+#ifdef SYNC_CMD
+REQUIRE_OBJECT ( sync_cmd );
+#endif
+#ifdef NSLOOKUP_CMD
+REQUIRE_OBJECT ( nslookup_cmd );
+#endif
 
 /*
  * Drag in miscellaneous objects
@@ -274,13 +286,16 @@ REQUIRE_OBJECT ( tap );
 #endif
 
 /*
- * Drag in relevant BOFM entry points
+ * Drag in relevant sideband entry points
  */
 #ifdef CONFIG_BOFM
 #ifdef BOFM_EFI
 REQUIRE_OBJECT ( efi_bofm );
 #endif /* BOFM_EFI */
 #endif /* CONFIG_BOFM */
+#ifdef VMWARE_SETTINGS
+REQUIRE_OBJECT ( guestinfo );
+#endif /* VMWARE_SETTINGS */
 
 /*
  * Drag in selected keyboard map
diff --git a/roms/ipxe/src/config/console.h b/roms/ipxe/src/config/console.h
index afc89569c517e903dc4d89562f92..04be02dc402f64f375e19c793807 100644
--- a/roms/ipxe/src/config/console.h
+++ b/roms/ipxe/src/config/console.h
@@ -17,12 +17,16 @@ FILE_LICENCE ( GPL2_OR_LATER );
 //#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 */
 //#define	CONSOLE_SYSLOG		/* Syslog console */
+//#define	CONSOLE_SYSLOGS		/* Encrypted syslog console */
+//#define	CONSOLE_VMWARE		/* VMware logfile console */
+//#define	CONSOLE_DEBUGCON	/* Debug port console */
 
 #define	KEYBOARD_MAP	us
 
+#define	LOG_LEVEL	LOG_NONE
+
 #include <config/local/console.h>
 
 #endif /* CONFIG_CONSOLE_H */
diff --git a/roms/ipxe/src/config/defaults/efi.h b/roms/ipxe/src/config/defaults/efi.h
index 693f55ad98c913dc6cb9d1fcc4ba..923360ae8088ff94c5d0f7c23812 100644
--- a/roms/ipxe/src/config/defaults/efi.h
+++ b/roms/ipxe/src/config/defaults/efi.h
@@ -8,7 +8,7 @@
  */
 
 #define UACCESS_EFI
-#define IOAPI_EFI
+#define IOAPI_X86
 #define PCIAPI_EFI
 #define CONSOLE_EFI
 #define TIMER_EFI
@@ -17,6 +17,8 @@
 #define SMBIOS_EFI
 #define SANBOOT_NULL
 #define BOFM_EFI
+#define ENTROPY_NULL
+#define TIME_NULL
 
 #define	IMAGE_EFI		/* EFI image support */
 #define	IMAGE_SCRIPT		/* iPXE script image support */
diff --git a/roms/ipxe/src/config/defaults/linux.h b/roms/ipxe/src/config/defaults/linux.h
index 647dc0a530c001aee1995a6f9f02..50897560d6dab58f7aca79c568cf 100644
--- a/roms/ipxe/src/config/defaults/linux.h
+++ b/roms/ipxe/src/config/defaults/linux.h
@@ -14,6 +14,8 @@
 #define NAP_LINUX
 #define SMBIOS_LINUX
 #define SANBOOT_NULL
+#define ENTROPY_LINUX
+#define TIME_LINUX
 
 #define DRIVERS_LINUX
 
diff --git a/roms/ipxe/src/config/defaults/pcbios.h b/roms/ipxe/src/config/defaults/pcbios.h
index 7846f8f07531b5ac37e86c456de8..c52fca972f6832e4e8e632ec6bb7 100644
--- a/roms/ipxe/src/config/defaults/pcbios.h
+++ b/roms/ipxe/src/config/defaults/pcbios.h
@@ -18,13 +18,14 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define UMALLOC_MEMTOP
 #define SMBIOS_PCBIOS
 #define SANBOOT_PCBIOS
+#define ENTROPY_RTC
+#define TIME_RTC
 
 #define	IMAGE_ELF		/* ELF image support */
 #define	IMAGE_MULTIBOOT		/* MultiBoot image support */
 #define	IMAGE_PXE		/* PXE image support */
 #define IMAGE_SCRIPT		/* iPXE script image support */
 #define IMAGE_BZIMAGE		/* Linux bzImage image support */
-#define IMAGE_COMBOOT		/* SYSLINUX COMBOOT image support */
 
 #define PXE_STACK		/* PXE stack in iPXE - required for PXELINUX */
 #define PXE_MENU		/* PXE menu booting */
@@ -34,4 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define	SANBOOT_PROTO_IB_SRP	/* Infiniband SCSI RDMA protocol */
 #define	SANBOOT_PROTO_FCP	/* Fibre Channel protocol */
 
+#define	REBOOT_CMD		/* Reboot command */
+#define	CPUID_CMD		/* x86 CPU feature detection command */
+
 #endif /* CONFIG_DEFAULTS_PCBIOS_H */
diff --git a/roms/ipxe/src/config/entropy.h b/roms/ipxe/src/config/entropy.h
new file mode 100644
index 0000000000000000000000000000000000000000..7de2f67375cb3de74e15bd728d3d2012574a551e
--- /dev/null
+++ b/roms/ipxe/src/config/entropy.h
@@ -0,0 +1,16 @@
+#ifndef CONFIG_ENTROPY_H
+#define CONFIG_ENTROPY_H
+
+/** @file
+ *
+ * Entropy API configuration
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <config/defaults.h>
+
+#include <config/local/entropy.h>
+
+#endif /* CONFIG_ENTROPY_H */
diff --git a/roms/ipxe/src/config/general.h b/roms/ipxe/src/config/general.h
index 9eb88651412716f1eae285e33bbe..9f0bb521b580cf34d58eeb00c5a7 100644
--- a/roms/ipxe/src/config/general.h
+++ b/roms/ipxe/src/config/general.h
@@ -58,7 +58,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #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 */
 
 /*
@@ -95,15 +94,13 @@ FILE_LICENCE ( GPL2_OR_LATER );
  */
 //#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		/* iPXE script image support */
 //#define	IMAGE_BZIMAGE		/* Linux bzImage image support */
 //#define	IMAGE_COMBOOT		/* SYSLINUX COMBOOT image support */
 //#define	IMAGE_EFI		/* EFI image support */
+//#define	IMAGE_SDI		/* SDI image support */
 
 /*
  * Command-line commands to include
@@ -119,13 +116,23 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define IMAGE_CMD		/* Image management commands */
 #define DHCP_CMD		/* DHCP management commands */
 #define SANBOOT_CMD		/* SAN boot commands */
+#define MENU_CMD		/* Menu commands */
 #define LOGIN_CMD		/* Login command */
-#undef	TIME_CMD		/* Time commands */
-#undef	DIGEST_CMD		/* Image crypto digest commands */
-#undef	LOTEST_CMD		/* Loopback testing commands */
-#undef	VLAN_CMD		/* VLAN commands */
-#undef	PXE_CMD			/* PXE commands */
-#undef	REBOOT_CMD		/* Reboot command */
+#define SYNC_CMD		/* Sync command */
+//#define NSLOOKUP_CMD		/* DNS resolving command */
+//#define TIME_CMD		/* Time commands */
+//#define DIGEST_CMD		/* Image crypto digest commands */
+//#define LOTEST_CMD		/* Loopback testing commands */
+//#define VLAN_CMD		/* VLAN commands */
+//#define PXE_CMD		/* PXE commands */
+//#define REBOOT_CMD		/* Reboot command */
+//#define IMAGE_TRUST_CMD	/* Image trust management commands */
+
+/*
+ * ROM-specific options
+ *
+ */
+#undef	NONPNP_HOOK_INT19	/* Hook INT19 on non-PnP BIOSes */
 
 /*
  * Error message tables to include
diff --git a/roms/ipxe/src/config/sideband.h b/roms/ipxe/src/config/sideband.h
index 5385dd72195358ccdc2319b51977..52339993eb59d4d131d1134efcb4 100644
--- a/roms/ipxe/src/config/sideband.h
+++ b/roms/ipxe/src/config/sideband.h
@@ -10,5 +10,8 @@
 FILE_LICENCE ( GPL2_OR_LATER );
 
 //#define	CONFIG_BOFM	/* IBM's BladeCenter Open Fabric Manager */
+//#define	VMWARE_SETTINGS	/* VMware GuestInfo settings */
+
+#include <config/local/sideband.h>
 
 #endif /* CONFIG_SIDEBAND_H */
diff --git a/roms/ipxe/src/config/time.h b/roms/ipxe/src/config/time.h
new file mode 100644
index 0000000000000000000000000000000000000000..0576211fd28190fcb3d453c0bac17e5bed3d31cc
--- /dev/null
+++ b/roms/ipxe/src/config/time.h
@@ -0,0 +1,16 @@
+#ifndef CONFIG_TIME_H
+#define CONFIG_TIME_H
+
+/** @file
+ *
+ * Time API configuration
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <config/defaults.h>
+
+#include <config/local/time.h>
+
+#endif /* CONFIG_TIME_H */
diff --git a/roms/ipxe/src/core/acpi.c b/roms/ipxe/src/core/acpi.c
index 223765f763abdc31dbe7f4587bd3..330f50631baafddfbd533bc7fd57 100644
--- a/roms/ipxe/src/core/acpi.c
+++ b/roms/ipxe/src/core/acpi.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/ansiesc.c b/roms/ipxe/src/core/ansiesc.c
index 05bbb8695d6ffc50cbb4417936cc..32e9d7c9f87743a3b9141a1d2004 100644
--- a/roms/ipxe/src/core/ansiesc.c
+++ b/roms/ipxe/src/core/ansiesc.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/assert.c b/roms/ipxe/src/core/assert.c
new file mode 100644
index 0000000000000000000000000000000000000000..0791ea7b94c879ca76a7c2b826321e5d82bd8857
--- /dev/null
+++ b/roms/ipxe/src/core/assert.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Assertions
+ *
+ */
+
+#include <assert.h>
+
+/** Number of assertion failures triggered */
+unsigned int assertion_failures = 0;
diff --git a/roms/ipxe/src/core/base16.c b/roms/ipxe/src/core/base16.c
index 14de7957b62a0b555329e6693abf..1f0e536c5a4ff0b36c6b07cacba7 100644
--- a/roms/ipxe/src/core/base16.c
+++ b/roms/ipxe/src/core/base16.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/base64.c b/roms/ipxe/src/core/base64.c
index 7514c1faceca69b42cb5b9cfa201..bdaf70957f1d4e558d53844d9d76 100644
--- a/roms/ipxe/src/core/base64.c
+++ b/roms/ipxe/src/core/base64.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -54,11 +55,16 @@ void base64_encode ( const uint8_t *raw, size_t len, char *encoded ) {
 	uint8_t *encoded_bytes = ( ( uint8_t * ) encoded );
 	size_t raw_bit_len = ( 8 * len );
 	unsigned int bit;
+	unsigned int byte;
+	unsigned int shift;
 	unsigned int tmp;
 
 	for ( bit = 0 ; bit < raw_bit_len ; bit += 6 ) {
-		tmp = ( ( raw_bytes[ bit / 8 ] << ( bit % 8 ) ) |
-			( raw_bytes[ bit / 8 + 1 ] >> ( 8 - ( bit % 8 ) ) ) );
+		byte = ( bit / 8 );
+		shift = ( bit % 8 );
+		tmp = ( raw_bytes[byte] << shift );
+		if ( ( byte + 1 ) < len )
+			tmp |= ( raw_bytes[ byte + 1 ] >> ( 8 - shift ) );
 		tmp = ( ( tmp >> 2 ) & 0x3f );
 		*(encoded_bytes++) = base64[tmp];
 	}
diff --git a/roms/ipxe/src/core/basename.c b/roms/ipxe/src/core/basename.c
index a481c54f49b9286256bcaf8cb5fc..b534a788668481399b7789df632d 100644
--- a/roms/ipxe/src/core/basename.c
+++ b/roms/ipxe/src/core/basename.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/bitmap.c b/roms/ipxe/src/core/bitmap.c
index e9b6d90413441556366ac7d8c149..0d115232726d05116282d36879b1 100644
--- a/roms/ipxe/src/core/bitmap.c
+++ b/roms/ipxe/src/core/bitmap.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/blockdev.c b/roms/ipxe/src/core/blockdev.c
index 182765e30720e70caa6f4ca77888..9d118cb2f1859ec6a7d498ed3c1d 100644
--- a/roms/ipxe/src/core/blockdev.c
+++ b/roms/ipxe/src/core/blockdev.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/btext.c b/roms/ipxe/src/core/btext.c
deleted file mode 100644
index 4fb7378d9d940eefbaa708be7ea98229b5aa7725..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/core/btext.c
+++ /dev/null
@@ -1,5039 +0,0 @@
-#if 0
-
-/*
- * Procedures for drawing on the screen early on in the boot process.
- *
- * Benjamin Herrenschmidt <benh@kernel.crashing.org>
- *
- *   move to LinuxBIOS by LYH yhlu@tyan.com
- *   move to Etherboot by LYH
- */
-
-#include <ipxe/console.h>
-#include <ipxe/init.h>
-#include <ipxe/pci.h>
-
-#undef __BIG_ENDIAN
-#if 0
-#define __LITTLE_ENDIAN 
-#endif
-
-#include "btext.h"
-
-//#define NO_SCROLL
-
-#ifndef NO_SCROLL
-static void scrollscreen(void);
-#endif
-
-static void draw_byte(const unsigned char c, u32 locX, u32 locY);
-#if 0
-static void draw_byte_32(const unsigned char *bits, u32 *base, u32 rb);
-static void draw_byte_16(const unsigned char *bits, u32 *base, u32 rb);
-#endif
-static void draw_byte_8(const unsigned char *bits, u32 *base, u32 rb);
-
-static u32 g_loc_X;
-static u32 g_loc_Y;
-static u32 g_max_loc_X;
-static u32 g_max_loc_Y;
-
-#define CHAR_256 0
-
-#if CHAR_256==1
-#define cmapsz	(16*256)
-#else
-#define cmapsz  (16*96)
-#endif
-
-static const unsigned char vga_font[cmapsz];
-
-u32 boot_text_mapped;
-
-boot_infos_t disp_bi;
-
-#define BTEXT		
-#define BTDATA	
-
-
-/* This function will enable the early boot text when doing OF booting. This
- * way, xmon output should work too
- */
-static void
-btext_setup_display(u32 width, u32 height, u32 depth, u32 pitch,
-		    unsigned long address)
-{
-	boot_infos_t* bi = &disp_bi;
-
-	g_loc_X = 0;
-	g_loc_Y = 0;
-	g_max_loc_X = width / 8;
-	g_max_loc_Y = height / 16;
-//	bi->logicalDisplayBase = (unsigned char *)address;
-	bi->dispDeviceBase = address;
-	bi->dispDeviceRowBytes = pitch;
-	bi->dispDeviceDepth = depth;
-	bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
-	bi->dispDeviceRect[2] = width;
-	bi->dispDeviceRect[3] = height;
-	boot_text_mapped = 0;
-}
-
-/* Here's a small text engine to use during early boot
- * or for debugging purposes
- *
- * todo:
- *
- *  - build some kind of vgacon with it to enable early printk
- *  - move to a separate file
- *  - add a few video driver hooks to keep in sync with display
- *    changes.
- */
-
-static void 
-map_boot_text(void)
-{
-	boot_infos_t *bi = &disp_bi;
-	
-	if (bi->dispDeviceBase == 0)
-		return;
-
-	boot_text_mapped = 0;	
-
-	bi->logicalDisplayBase = phys_to_virt(bi->dispDeviceBase);
-	
-	boot_text_mapped = 1;
-}
-
-/* Calc the base address of a given point (x,y) */
-static unsigned char * BTEXT
-calc_base(boot_infos_t *bi, u32 x, u32 y)
-{
-	unsigned char *base;
-	base = bi->logicalDisplayBase;
-#if 0
-	/* Ummm... which moron wrote this? */
-	if (base == 0)
-		base = bi->dispDeviceBase;
-#endif
-	base += (x + bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3);
-	base += (y + bi->dispDeviceRect[1]) * bi->dispDeviceRowBytes;
-	return base;
-}
-
-
-static void BTEXT btext_clearscreen(void)
-{
-	boot_infos_t* bi	= &disp_bi;
-	u32 *base	= (u32 *)calc_base(bi, 0, 0);
-	u32 width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
-					(bi->dispDeviceDepth >> 3)) >> 2;
-	u32 i,j;
-
-	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
-	{
-		u32 *ptr = base;
-		for(j=width; j; --j)
-			*(ptr++) = 0;
-		base += (bi->dispDeviceRowBytes >> 2);
-	}
-}
-
-#if 0
-__inline__ void dcbst(const void* addr)
-{
-	__asm__ __volatile__ ("dcbst 0,%0" :: "r" (addr));
-}
-
-static void BTEXT btext_flushscreen(void)
-{
-	boot_infos_t* bi	= &disp_bi;
-	u32  *base	= (unsigned long *)calc_base(bi, 0, 0);
-	u32 width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
-					(bi->dispDeviceDepth >> 3)) >> 2;
-	u32 i,j;
-
-	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
-	{
-		u32 *ptr = base;
-		for(j=width; j>0; j-=8) {
-			dcbst(ptr);
-			ptr += 8;
-		}
-		base += (bi->dispDeviceRowBytes >> 2);
-	}
-}
-#endif
-
-
-#ifndef NO_SCROLL
-static BTEXT void
-scrollscreen(void)
-{
-	boot_infos_t* bi		= &disp_bi;
-	u32 *src		= (u32 *)calc_base(bi,0,16);
-	u32 *dst		= (u32 *)calc_base(bi,0,0);
-	u32 width		= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
-						(bi->dispDeviceDepth >> 3)) >> 2;
-	u32 i,j;
-
-	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++)
-	{
-		u32 *src_ptr = src;
-		u32 *dst_ptr = dst;
-		for(j=width; j; --j)
-			*(dst_ptr++) = *(src_ptr++);
-		src += (bi->dispDeviceRowBytes >> 2);
-		dst += (bi->dispDeviceRowBytes >> 2);
-	}
-	for (i=0; i<16; i++)
-	{
-		u32 *dst_ptr = dst;
-		for(j=width; j; --j)
-			*(dst_ptr++) = 0;
-		dst += (bi->dispDeviceRowBytes >> 2);
-	}
-}
-#endif /* ndef NO_SCROLL */
-
-static void BTEXT btext_drawchar(char c)
-{
-	u32 cline = 0;
-
-	if (!boot_text_mapped)
-		return;
-
-	switch (c) {
-	case '\b':
-		if (g_loc_X > 0)
-			--g_loc_X;
-		break;
-	case '\t':
-		g_loc_X = (g_loc_X & -8) + 8;
-		break;
-	case '\r':
-		g_loc_X = 0;
-		break;
-	case '\n':
-		g_loc_X = 0;
-		g_loc_Y++;
-		cline = 1;
-		break;
-	default:
-		draw_byte(c, g_loc_X++, g_loc_Y);
-	}
-	if (g_loc_X >= g_max_loc_X) {
-		g_loc_X = 0;
-		g_loc_Y++;
-		cline = 1;
-	}
-#ifndef NO_SCROLL
-	while (g_loc_Y >= g_max_loc_Y) {
-		scrollscreen();
-		g_loc_Y--;
-	}
-#else
-	/* wrap around from bottom to top of screen so we don't
-	   waste time scrolling each line.  -- paulus. */
-	if (g_loc_Y >= g_max_loc_Y)
-		g_loc_Y = 0;
-	if (cline) {
-		for (x = 0; x < g_max_loc_X; ++x)
-			draw_byte(' ', x, g_loc_Y);
-	}
-#endif
-}
-#if 0
-static void BTEXT
-btext_drawstring(const char *c)
-{
-	if (!boot_text_mapped)
-		return;
-	while (*c)
-		btext_drawchar(*c++);
-}
-static void BTEXT
-btext_drawhex(u32 v)
-{
-	static char hex_table[] = "0123456789abcdef";
-
-	if (!boot_text_mapped)
-		return;
-	btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]);
-	btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]);
-	btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]);
-	btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]);
-	btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]);
-	btext_drawchar(hex_table[(v >>  8) & 0x0000000FUL]);
-	btext_drawchar(hex_table[(v >>  4) & 0x0000000FUL]);
-	btext_drawchar(hex_table[(v >>  0) & 0x0000000FUL]);
-	btext_drawchar(' ');
-}
-#endif
-
-static void BTEXT
-draw_byte(const unsigned char c, u32 locX, u32 locY)
-{
-	boot_infos_t* bi	= &disp_bi;
-	unsigned char *base	= calc_base(bi, locX << 3, locY << 4);
-#if CHAR_256==1
-        unsigned const char *font     = &vga_font[(((u32)c)) * 16];
-#else
-	unsigned const char *font	= &vga_font[(((u32)c-0x20)) * 16];
-#endif
-
-	u32 rb			= bi->dispDeviceRowBytes;
-
-	switch(bi->dispDeviceDepth) {
-#if 0
-	case 24:
-	case 32:
-		draw_byte_32(font, (u32 *)base, rb);
-		break;
-	case 15:
-	case 16:
-		draw_byte_16(font, (u32 *)base, rb);
-		break;
-#endif
-	case 8:
-		draw_byte_8(font, (u32 *)base, rb);
-		break;
-	}
-}
-static u32 expand_bits_8[16] BTDATA = {
-#if defined(__BIG_ENDIAN)
-    0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
-    0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
-    0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
-    0xffff0000,0xffff00ff,0xffffff00,0xffffffff
-#elif defined(__LITTLE_ENDIAN)
-    0x00000000,0xff000000,0x00ff0000,0xffff0000,
-    0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
-    0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
-    0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
-#else
-#error FIXME: No endianness??
-#endif                      
-};
-#if 0
-static const u32 expand_bits_16[4] BTDATA = {
-#if defined(__BIG_ENDIAN)
-    0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
-#elif defined(__LITTLE_ENDIAN)
-    0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
-#else
-#error FIXME: No endianness??
-#endif
-};
-#endif
-#if 0
-static void BTEXT
-draw_byte_32(const unsigned char *font, u32 *base, u32 rb)
-{
-	u32 l, bits;
-	u32 fg = 0xFFFFFFFF;
-	u32 bg = 0x00000000;
-
-	for (l = 0; l < 16; ++l)
-	{
-		bits = *font++;
-		base[0] = (-(bits >> 7) & fg) ^ bg;
-		base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
-		base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
-		base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
-		base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
-		base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
-		base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
-		base[7] = (-(bits & 1) & fg) ^ bg;
-		base = (u32 *) ((char *)base + rb);
-	}
-}
-
-static void BTEXT
-draw_byte_16(const unsigned char *font, u32 *base, u32 rb)
-{
-	u32 l, bits;
-	u32 fg = 0xFFFFFFFF;
-	u32 bg = 0x00000000;
-	u32 *eb = expand_bits_16;
-
-	for (l = 0; l < 16; ++l)
-	{
-		bits = *font++;
-		base[0] = (eb[bits >> 6] & fg) ^ bg;
-		base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
-		base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
-		base[3] = (eb[bits & 3] & fg) ^ bg;
-		base = (u32 *) ((char *)base + rb);
-	}
-}
-#endif
-static void BTEXT
-draw_byte_8(const unsigned char *font, u32 *base, u32 rb)
-{
-	u32 l, bits;
-	u32 fg = 0x0F0F0F0F;
-	u32 bg = 0x00000000;
-	u32 *eb = expand_bits_8;
-
-	for (l = 0; l < 16; ++l)
-	{
-		bits = *font++;
-		base[0] = (eb[bits >> 4] & fg) ^ bg;
-		base[1] = (eb[bits & 0xf] & fg) ^ bg;
-		base = (u32 *) ((char *)base + rb);
-	}
-}
-
-static void btext_init(void)
-{
-#if 0
-// for debug
-#define frame_buffer 0xfc000000
-#else
-    uint32_t frame_buffer;//  0xfc000000
-
-    struct pci_device dev;
-
-    #warning "pci_find_device_x no longer exists; use find_pci_device instead"
-    /*    pci_find_device_x(0x1002, 0x4752, 0, &dev); */
-    if(dev.vendor==0) return; // no fb
-
-    frame_buffer = (uint32_t)dev.membase;
-#endif
-
-	btext_setup_display(640, 480, 8, 640,frame_buffer);
-	btext_clearscreen();
-	map_boot_text();
-}
-static void btext_putc(int c)
-{	
-        btext_drawchar((unsigned char)c);
-}
-
-struct console_driver btext_console __console_driver = {
-	.putchar = btext_putc,
-	.disabled = 1,
-};
-
-//come from linux/drivers/video/font-8x16.c
-/**********************************************/
-/*                                            */
-/*       Font file generated by cpi2fnt       */
-/*                                            */
-/**********************************************/
-
-
-static const unsigned char vga_font[cmapsz] BTDATA = {
-#if CHAR_256==1
-	/* 0 0x00 '^@' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 1 0x01 '^A' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x81, /* 10000001 */
-	0xa5, /* 10100101 */
-	0x81, /* 10000001 */
-	0x81, /* 10000001 */
-	0xbd, /* 10111101 */
-	0x99, /* 10011001 */
-	0x81, /* 10000001 */
-	0x81, /* 10000001 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 2 0x02 '^B' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0xff, /* 11111111 */
-	0xdb, /* 11011011 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xc3, /* 11000011 */
-	0xe7, /* 11100111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 3 0x03 '^C' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x6c, /* 01101100 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0x7c, /* 01111100 */
-	0x38, /* 00111000 */
-	0x10, /* 00010000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 4 0x04 '^D' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x7c, /* 01111100 */
-	0xfe, /* 11111110 */
-	0x7c, /* 01111100 */
-	0x38, /* 00111000 */
-	0x10, /* 00010000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 5 0x05 '^E' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0xe7, /* 11100111 */
-	0xe7, /* 11100111 */
-	0xe7, /* 11100111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 6 0x06 '^F' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x7e, /* 01111110 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 7 0x07 '^G' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 8 0x08 '^H' */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xe7, /* 11100111 */
-	0xc3, /* 11000011 */
-	0xc3, /* 11000011 */
-	0xe7, /* 11100111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-
-	/* 9 0x09 '^I' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x42, /* 01000010 */
-	0x42, /* 01000010 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 10 0x0a '^J' */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xc3, /* 11000011 */
-	0x99, /* 10011001 */
-	0xbd, /* 10111101 */
-	0xbd, /* 10111101 */
-	0x99, /* 10011001 */
-	0xc3, /* 11000011 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-
-	/* 11 0x0b '^K' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1e, /* 00011110 */
-	0x0e, /* 00001110 */
-	0x1a, /* 00011010 */
-	0x32, /* 00110010 */
-	0x78, /* 01111000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x78, /* 01111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 12 0x0c '^L' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 13 0x0d '^M' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3f, /* 00111111 */
-	0x33, /* 00110011 */
-	0x3f, /* 00111111 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x70, /* 01110000 */
-	0xf0, /* 11110000 */
-	0xe0, /* 11100000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 14 0x0e '^N' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7f, /* 01111111 */
-	0x63, /* 01100011 */
-	0x7f, /* 01111111 */
-	0x63, /* 01100011 */
-	0x63, /* 01100011 */
-	0x63, /* 01100011 */
-	0x63, /* 01100011 */
-	0x67, /* 01100111 */
-	0xe7, /* 11100111 */
-	0xe6, /* 11100110 */
-	0xc0, /* 11000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 15 0x0f '^O' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xdb, /* 11011011 */
-	0x3c, /* 00111100 */
-	0xe7, /* 11100111 */
-	0x3c, /* 00111100 */
-	0xdb, /* 11011011 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 16 0x10 '^P' */
-	0x00, /* 00000000 */
-	0x80, /* 10000000 */
-	0xc0, /* 11000000 */
-	0xe0, /* 11100000 */
-	0xf0, /* 11110000 */
-	0xf8, /* 11111000 */
-	0xfe, /* 11111110 */
-	0xf8, /* 11111000 */
-	0xf0, /* 11110000 */
-	0xe0, /* 11100000 */
-	0xc0, /* 11000000 */
-	0x80, /* 10000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 17 0x11 '^Q' */
-	0x00, /* 00000000 */
-	0x02, /* 00000010 */
-	0x06, /* 00000110 */
-	0x0e, /* 00001110 */
-	0x1e, /* 00011110 */
-	0x3e, /* 00111110 */
-	0xfe, /* 11111110 */
-	0x3e, /* 00111110 */
-	0x1e, /* 00011110 */
-	0x0e, /* 00001110 */
-	0x06, /* 00000110 */
-	0x02, /* 00000010 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 18 0x12 '^R' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 19 0x13 '^S' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 20 0x14 '^T' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7f, /* 01111111 */
-	0xdb, /* 11011011 */
-	0xdb, /* 11011011 */
-	0xdb, /* 11011011 */
-	0x7b, /* 01111011 */
-	0x1b, /* 00011011 */
-	0x1b, /* 00011011 */
-	0x1b, /* 00011011 */
-	0x1b, /* 00011011 */
-	0x1b, /* 00011011 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 21 0x15 '^U' */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0x60, /* 01100000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x0c, /* 00001100 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 22 0x16 '^V' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 23 0x17 '^W' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 24 0x18 '^X' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 25 0x19 '^Y' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 26 0x1a '^Z' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0xfe, /* 11111110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 27 0x1b '^[' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xfe, /* 11111110 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 28 0x1c '^\' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 29 0x1d '^]' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x28, /* 00101000 */
-	0x6c, /* 01101100 */
-	0xfe, /* 11111110 */
-	0x6c, /* 01101100 */
-	0x28, /* 00101000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 30 0x1e '^^' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x38, /* 00111000 */
-	0x7c, /* 01111100 */
-	0x7c, /* 01111100 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 31 0x1f '^_' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0x7c, /* 01111100 */
-	0x7c, /* 01111100 */
-	0x38, /* 00111000 */
-	0x38, /* 00111000 */
-	0x10, /* 00010000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-#endif
-	/* 32 0x20 ' ' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 33 0x21 '!' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 34 0x22 '"' */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x24, /* 00100100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 35 0x23 '#' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0xfe, /* 11111110 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0xfe, /* 11111110 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 36 0x24 '$' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc2, /* 11000010 */
-	0xc0, /* 11000000 */
-	0x7c, /* 01111100 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x86, /* 10000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 37 0x25 '%' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc2, /* 11000010 */
-	0xc6, /* 11000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc6, /* 11000110 */
-	0x86, /* 10000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 38 0x26 '&' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 39 0x27 ''' */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 40 0x28 '(' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 41 0x29 ')' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 42 0x2a '*' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0xff, /* 11111111 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 43 0x2b '+' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 44 0x2c ',' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 45 0x2d '-' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 46 0x2e '.' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 47 0x2f '/' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x02, /* 00000010 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc0, /* 11000000 */
-	0x80, /* 10000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 48 0x30 '0' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 49 0x31 '1' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x38, /* 00111000 */
-	0x78, /* 01111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 50 0x32 '2' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 51 0x33 '3' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x3c, /* 00111100 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 52 0x34 '4' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x0c, /* 00001100 */
-	0x1c, /* 00011100 */
-	0x3c, /* 00111100 */
-	0x6c, /* 01101100 */
-	0xcc, /* 11001100 */
-	0xfe, /* 11111110 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x1e, /* 00011110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 53 0x35 '5' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xfc, /* 11111100 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 54 0x36 '6' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x60, /* 01100000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xfc, /* 11111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 55 0x37 '7' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 56 0x38 '8' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 57 0x39 '9' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7e, /* 01111110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x78, /* 01111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 58 0x3a ':' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 59 0x3b ';' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 60 0x3c '<' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x06, /* 00000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 61 0x3d '=' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 62 0x3e '>' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 63 0x3f '?' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 64 0x40 '@' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xde, /* 11011110 */
-	0xde, /* 11011110 */
-	0xde, /* 11011110 */
-	0xdc, /* 11011100 */
-	0xc0, /* 11000000 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 65 0x41 'A' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 66 0x42 'B' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfc, /* 11111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0xfc, /* 11111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 67 0x43 'C' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0xc2, /* 11000010 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc2, /* 11000010 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 68 0x44 'D' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xf8, /* 11111000 */
-	0x6c, /* 01101100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x6c, /* 01101100 */
-	0xf8, /* 11111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 69 0x45 'E' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x66, /* 01100110 */
-	0x62, /* 01100010 */
-	0x68, /* 01101000 */
-	0x78, /* 01111000 */
-	0x68, /* 01101000 */
-	0x60, /* 01100000 */
-	0x62, /* 01100010 */
-	0x66, /* 01100110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 70 0x46 'F' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x66, /* 01100110 */
-	0x62, /* 01100010 */
-	0x68, /* 01101000 */
-	0x78, /* 01111000 */
-	0x68, /* 01101000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0xf0, /* 11110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 71 0x47 'G' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0xc2, /* 11000010 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xde, /* 11011110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x66, /* 01100110 */
-	0x3a, /* 00111010 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 72 0x48 'H' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 73 0x49 'I' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 74 0x4a 'J' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1e, /* 00011110 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x78, /* 01111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 75 0x4b 'K' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xe6, /* 11100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x6c, /* 01101100 */
-	0x78, /* 01111000 */
-	0x78, /* 01111000 */
-	0x6c, /* 01101100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0xe6, /* 11100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 76 0x4c 'L' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xf0, /* 11110000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x62, /* 01100010 */
-	0x66, /* 01100110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 77 0x4d 'M' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xee, /* 11101110 */
-	0xfe, /* 11111110 */
-	0xfe, /* 11111110 */
-	0xd6, /* 11010110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 78 0x4e 'N' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xe6, /* 11100110 */
-	0xf6, /* 11110110 */
-	0xfe, /* 11111110 */
-	0xde, /* 11011110 */
-	0xce, /* 11001110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 79 0x4f 'O' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 80 0x50 'P' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfc, /* 11111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0xf0, /* 11110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 81 0x51 'Q' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xd6, /* 11010110 */
-	0xde, /* 11011110 */
-	0x7c, /* 01111100 */
-	0x0c, /* 00001100 */
-	0x0e, /* 00001110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 82 0x52 'R' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfc, /* 11111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x6c, /* 01101100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0xe6, /* 11100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 83 0x53 'S' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x60, /* 01100000 */
-	0x38, /* 00111000 */
-	0x0c, /* 00001100 */
-	0x06, /* 00000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 84 0x54 'T' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x5a, /* 01011010 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 85 0x55 'U' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 86 0x56 'V' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x10, /* 00010000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 87 0x57 'W' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xfe, /* 11111110 */
-	0xee, /* 11101110 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 88 0x58 'X' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x7c, /* 01111100 */
-	0x38, /* 00111000 */
-	0x38, /* 00111000 */
-	0x7c, /* 01111100 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 89 0x59 'Y' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 90 0x5a 'Z' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0x86, /* 10000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc2, /* 11000010 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 91 0x5b '[' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 92 0x5c '\' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x80, /* 10000000 */
-	0xc0, /* 11000000 */
-	0xe0, /* 11100000 */
-	0x70, /* 01110000 */
-	0x38, /* 00111000 */
-	0x1c, /* 00011100 */
-	0x0e, /* 00001110 */
-	0x06, /* 00000110 */
-	0x02, /* 00000010 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 93 0x5d ']' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 94 0x5e '^' */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 95 0x5f '_' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 96 0x60 '`' */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 97 0x61 'a' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 98 0x62 'b' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xe0, /* 11100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x78, /* 01111000 */
-	0x6c, /* 01101100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 99 0x63 'c' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 100 0x64 'd' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1c, /* 00011100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x3c, /* 00111100 */
-	0x6c, /* 01101100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 101 0x65 'e' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 102 0x66 'f' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1c, /* 00011100 */
-	0x36, /* 00110110 */
-	0x32, /* 00110010 */
-	0x30, /* 00110000 */
-	0x78, /* 01111000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x78, /* 01111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 103 0x67 'g' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x7c, /* 01111100 */
-	0x0c, /* 00001100 */
-	0xcc, /* 11001100 */
-	0x78, /* 01111000 */
-	0x00, /* 00000000 */
-
-	/* 104 0x68 'h' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xe0, /* 11100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x6c, /* 01101100 */
-	0x76, /* 01110110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0xe6, /* 11100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 105 0x69 'i' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 106 0x6a 'j' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x00, /* 00000000 */
-	0x0e, /* 00001110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-
-	/* 107 0x6b 'k' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xe0, /* 11100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x66, /* 01100110 */
-	0x6c, /* 01101100 */
-	0x78, /* 01111000 */
-	0x78, /* 01111000 */
-	0x6c, /* 01101100 */
-	0x66, /* 01100110 */
-	0xe6, /* 11100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 108 0x6c 'l' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 109 0x6d 'm' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xec, /* 11101100 */
-	0xfe, /* 11111110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 110 0x6e 'n' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xdc, /* 11011100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 111 0x6f 'o' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 112 0x70 'p' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xdc, /* 11011100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0xf0, /* 11110000 */
-	0x00, /* 00000000 */
-
-	/* 113 0x71 'q' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x7c, /* 01111100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x1e, /* 00011110 */
-	0x00, /* 00000000 */
-
-	/* 114 0x72 'r' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xdc, /* 11011100 */
-	0x76, /* 01110110 */
-	0x66, /* 01100110 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0xf0, /* 11110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 115 0x73 's' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0x60, /* 01100000 */
-	0x38, /* 00111000 */
-	0x0c, /* 00001100 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 116 0x74 't' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0xfc, /* 11111100 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x36, /* 00110110 */
-	0x1c, /* 00011100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 117 0x75 'u' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 118 0x76 'v' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 119 0x77 'w' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xd6, /* 11010110 */
-	0xfe, /* 11111110 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 120 0x78 'x' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x38, /* 00111000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 121 0x79 'y' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7e, /* 01111110 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0xf8, /* 11111000 */
-	0x00, /* 00000000 */
-
-	/* 122 0x7a 'z' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xcc, /* 11001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 123 0x7b '{' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x0e, /* 00001110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x70, /* 01110000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x0e, /* 00001110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 124 0x7c '|' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 125 0x7d '}' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x70, /* 01110000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x0e, /* 00001110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x70, /* 01110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 126 0x7e '~' */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 127 0x7f '' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-#if CHAR_256256==1
-	/* 128 0x80 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0xc2, /* 11000010 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc2, /* 11000010 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x70, /* 01110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 129 0x81 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 130 0x82 '�' */
-	0x00, /* 00000000 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 131 0x83 '�' */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 132 0x84 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 133 0x85 '�' */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 134 0x86 '�' */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 135 0x87 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x18, /* 00011000 */
-	0x70, /* 01110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 136 0x88 '�' */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 137 0x89 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 138 0x8a '�' */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 139 0x8b '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 140 0x8c '�' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 141 0x8d '�' */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 142 0x8e '�' */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 143 0x8f '�' */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 144 0x90 '�' */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x66, /* 01100110 */
-	0x62, /* 01100010 */
-	0x68, /* 01101000 */
-	0x78, /* 01111000 */
-	0x68, /* 01101000 */
-	0x62, /* 01100010 */
-	0x66, /* 01100110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 145 0x91 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xec, /* 11101100 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x7e, /* 01111110 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0x6e, /* 01101110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 146 0x92 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3e, /* 00111110 */
-	0x6c, /* 01101100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xfe, /* 11111110 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xce, /* 11001110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 147 0x93 '�' */
-	0x00, /* 00000000 */
-	0x10, /* 00010000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 148 0x94 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 149 0x95 '�' */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 150 0x96 '�' */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x78, /* 01111000 */
-	0xcc, /* 11001100 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 151 0x97 '�' */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 152 0x98 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7e, /* 01111110 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x78, /* 01111000 */
-	0x00, /* 00000000 */
-
-	/* 153 0x99 '�' */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 154 0x9a '�' */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 155 0x9b '�' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 156 0x9c '�' */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x64, /* 01100100 */
-	0x60, /* 01100000 */
-	0xf0, /* 11110000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0xe6, /* 11100110 */
-	0xfc, /* 11111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 157 0x9d '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 158 0x9e '�' */
-	0x00, /* 00000000 */
-	0xf8, /* 11111000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xf8, /* 11111000 */
-	0xc4, /* 11000100 */
-	0xcc, /* 11001100 */
-	0xde, /* 11011110 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 159 0x9f '�' */
-	0x00, /* 00000000 */
-	0x0e, /* 00001110 */
-	0x1b, /* 00011011 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xd8, /* 11011000 */
-	0x70, /* 01110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 160 0xa0 '�' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0x0c, /* 00001100 */
-	0x7c, /* 01111100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 161 0xa1 '�' */
-	0x00, /* 00000000 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 162 0xa2 '�' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 163 0xa3 '�' */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x00, /* 00000000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 164 0xa4 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-	0xdc, /* 11011100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 165 0xa5 '�' */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-	0xc6, /* 11000110 */
-	0xe6, /* 11100110 */
-	0xf6, /* 11110110 */
-	0xfe, /* 11111110 */
-	0xde, /* 11011110 */
-	0xce, /* 11001110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 166 0xa6 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x3e, /* 00111110 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 167 0xa7 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 168 0xa8 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc0, /* 11000000 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x7c, /* 01111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 169 0xa9 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 170 0xaa '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 171 0xab '�' */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0xe0, /* 11100000 */
-	0x62, /* 01100010 */
-	0x66, /* 01100110 */
-	0x6c, /* 01101100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xdc, /* 11011100 */
-	0x86, /* 10000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x3e, /* 00111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 172 0xac '�' */
-	0x00, /* 00000000 */
-	0x60, /* 01100000 */
-	0xe0, /* 11100000 */
-	0x62, /* 01100010 */
-	0x66, /* 01100110 */
-	0x6c, /* 01101100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x66, /* 01100110 */
-	0xce, /* 11001110 */
-	0x9a, /* 10011010 */
-	0x3f, /* 00111111 */
-	0x06, /* 00000110 */
-	0x06, /* 00000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 173 0xad '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 174 0xae '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x36, /* 00110110 */
-	0x6c, /* 01101100 */
-	0xd8, /* 11011000 */
-	0x6c, /* 01101100 */
-	0x36, /* 00110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 175 0xaf '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xd8, /* 11011000 */
-	0x6c, /* 01101100 */
-	0x36, /* 00110110 */
-	0x6c, /* 01101100 */
-	0xd8, /* 11011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 176 0xb0 '�' */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-	0x11, /* 00010001 */
-	0x44, /* 01000100 */
-
-	/* 177 0xb1 '�' */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-	0x55, /* 01010101 */
-	0xaa, /* 10101010 */
-
-	/* 178 0xb2 '�' */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-	0xdd, /* 11011101 */
-	0x77, /* 01110111 */
-
-	/* 179 0xb3 '�' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 180 0xb4 '�' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 181 0xb5 '�' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 182 0xb6 '�' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xf6, /* 11110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 183 0xb7 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 184 0xb8 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 185 0xb9 '�' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xf6, /* 11110110 */
-	0x06, /* 00000110 */
-	0xf6, /* 11110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 186 0xba '�' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 187 0xbb '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x06, /* 00000110 */
-	0xf6, /* 11110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 188 0xbc '�' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xf6, /* 11110110 */
-	0x06, /* 00000110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 189 0xbd '�' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 190 0xbe '�' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 191 0xbf '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xf8, /* 11111000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 192 0xc0 '�' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 193 0xc1 '�' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 194 0xc2 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 195 0xc3 '�' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 196 0xc4 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 197 0xc5 '�' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 198 0xc6 '�' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 199 0xc7 '�' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x37, /* 00110111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 200 0xc8 '�' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x37, /* 00110111 */
-	0x30, /* 00110000 */
-	0x3f, /* 00111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 201 0xc9 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3f, /* 00111111 */
-	0x30, /* 00110000 */
-	0x37, /* 00110111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 202 0xca '�' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xf7, /* 11110111 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 203 0xcb '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0xf7, /* 11110111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 204 0xcc '�' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x37, /* 00110111 */
-	0x30, /* 00110000 */
-	0x37, /* 00110111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 205 0xcd '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 206 0xce '�' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xf7, /* 11110111 */
-	0x00, /* 00000000 */
-	0xf7, /* 11110111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 207 0xcf '�' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 208 0xd0 '�' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 209 0xd1 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 210 0xd2 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 211 0xd3 '�' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x3f, /* 00111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 212 0xd4 '�' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 213 0xd5 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 214 0xd6 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x3f, /* 00111111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 215 0xd7 '�' */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0xff, /* 11111111 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-
-	/* 216 0xd8 '�' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-	0x18, /* 00011000 */
-	0xff, /* 11111111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 217 0xd9 '�' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xf8, /* 11111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 218 0xda '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1f, /* 00011111 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 219 0xdb '�' */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-
-	/* 220 0xdc '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-
-	/* 221 0xdd '�' */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-	0xf0, /* 11110000 */
-
-	/* 222 0xde '�' */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-	0x0f, /* 00001111 */
-
-	/* 223 0xdf '�' */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0xff, /* 11111111 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 224 0xe0 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0xdc, /* 11011100 */
-	0x76, /* 01110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 225 0xe1 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x78, /* 01111000 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xcc, /* 11001100 */
-	0xd8, /* 11011000 */
-	0xcc, /* 11001100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xcc, /* 11001100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 226 0xe2 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0xc0, /* 11000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 227 0xe3 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 228 0xe4 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 229 0xe5 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0x70, /* 01110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 230 0xe6 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x7c, /* 01111100 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0xc0, /* 11000000 */
-	0x00, /* 00000000 */
-
-	/* 231 0xe7 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 232 0xe8 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 233 0xe9 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xfe, /* 11111110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 234 0xea '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0xee, /* 11101110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 235 0xeb '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1e, /* 00011110 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x3e, /* 00111110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x66, /* 01100110 */
-	0x3c, /* 00111100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 236 0xec '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0xdb, /* 11011011 */
-	0xdb, /* 11011011 */
-	0xdb, /* 11011011 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 237 0xed '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x03, /* 00000011 */
-	0x06, /* 00000110 */
-	0x7e, /* 01111110 */
-	0xdb, /* 11011011 */
-	0xdb, /* 11011011 */
-	0xf3, /* 11110011 */
-	0x7e, /* 01111110 */
-	0x60, /* 01100000 */
-	0xc0, /* 11000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 238 0xee '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x1c, /* 00011100 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x7c, /* 01111100 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x1c, /* 00011100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 239 0xef '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7c, /* 01111100 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0xc6, /* 11000110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 240 0xf0 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0xfe, /* 11111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 241 0xf1 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x7e, /* 01111110 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 242 0xf2 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x06, /* 00000110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 243 0xf3 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x30, /* 00110000 */
-	0x60, /* 01100000 */
-	0x30, /* 00110000 */
-	0x18, /* 00011000 */
-	0x0c, /* 00001100 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 244 0xf4 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x0e, /* 00001110 */
-	0x1b, /* 00011011 */
-	0x1b, /* 00011011 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-
-	/* 245 0xf5 '�' */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0xd8, /* 11011000 */
-	0x70, /* 01110000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 246 0xf6 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 247 0xf7 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-	0x76, /* 01110110 */
-	0xdc, /* 11011100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 248 0xf8 '�' */
-	0x00, /* 00000000 */
-	0x38, /* 00111000 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x38, /* 00111000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 249 0xf9 '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 250 0xfa '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x18, /* 00011000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 251 0xfb '�' */
-	0x00, /* 00000000 */
-	0x0f, /* 00001111 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0x0c, /* 00001100 */
-	0xec, /* 11101100 */
-	0x6c, /* 01101100 */
-	0x6c, /* 01101100 */
-	0x3c, /* 00111100 */
-	0x1c, /* 00011100 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 252 0xfc '�' */
-	0x00, /* 00000000 */
-	0x6c, /* 01101100 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x36, /* 00110110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 253 0xfd '�' */
-	0x00, /* 00000000 */
-	0x3c, /* 00111100 */
-	0x66, /* 01100110 */
-	0x0c, /* 00001100 */
-	0x18, /* 00011000 */
-	0x32, /* 00110010 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 254 0xfe '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x7e, /* 01111110 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-
-	/* 255 0xff '�' */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-	0x00, /* 00000000 */
-#endif
-};
-
-#endif
diff --git a/roms/ipxe/src/core/console.c b/roms/ipxe/src/core/console.c
index f27edf468b9c209b65b7f40b7cf9..a26a3ef6398a9685c89a645e5024 100644
--- a/roms/ipxe/src/core/console.c
+++ b/roms/ipxe/src/core/console.c
@@ -7,6 +7,9 @@
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
+/** Current console usage */
+int console_usage = CONSOLE_USAGE_STDOUT;
+
 /**
  * Write a single character to each console device.
  *
@@ -26,7 +29,9 @@ void putchar ( int character ) {
 		putchar ( '\r' );
 
 	for_each_table_entry ( console, CONSOLES ) {
-		if ( ( ! console->disabled ) && console->putchar )
+		if ( ( ! console->disabled ) &&
+		     ( console_usage & console->usage ) &&
+		     console->putchar )
 			console->putchar ( character );
 	}
 }
diff --git a/roms/ipxe/src/core/cpio.c b/roms/ipxe/src/core/cpio.c
index 5b7b3aa1d81b3845cdbcf429368d..3a5f4d2b69ae92b6390b85d96a06 100644
--- a/roms/ipxe/src/core/cpio.c
+++ b/roms/ipxe/src/core/cpio.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/ctype.c b/roms/ipxe/src/core/ctype.c
index 6185bb2fa968cbca5919218cf9f8..c812346a00fd82a49fdd83c7584d 100644
--- a/roms/ipxe/src/core/ctype.c
+++ b/roms/ipxe/src/core/ctype.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/cwuri.c b/roms/ipxe/src/core/cwuri.c
index 893e2050b39cd71c9598e792d0cd..5865552a03803582d89974aaca72 100644
--- a/roms/ipxe/src/core/cwuri.c
+++ b/roms/ipxe/src/core/cwuri.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/debug.c b/roms/ipxe/src/core/debug.c
index 73e74d9c35de6c9f0e08b567ea0a..627d5d9a11483c45938fc073bc10 100644
--- a/roms/ipxe/src/core/debug.c
+++ b/roms/ipxe/src/core/debug.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -21,17 +22,38 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <stdio.h>
 #include <stdint.h>
 #include <stdarg.h>
-#include <ipxe/io.h>
 #include <ipxe/console.h>
 
+/**
+ * Print debug message
+ *
+ * @v fmt		Format string
+ * @v ...		Arguments
+ */
+void dbg_printf ( const char *fmt, ... ) {
+	int saved_usage;
+	va_list args;
+
+	/* Mark console as in use for debugging messages */
+	saved_usage = console_set_usage ( CONSOLE_USAGE_DEBUG );
+
+	/* Print message */
+	va_start ( args, fmt );
+	vprintf ( fmt, args );
+	va_end ( args );
+
+	/* Restore console usage */
+	console_set_usage ( saved_usage );
+}
+
 /**
  * Pause until a key is pressed
  *
  */
 void dbg_pause ( void ) {
-	printf ( "\nPress a key..." );
+	dbg_printf ( "\nPress a key..." );
 	getchar();
-	printf ( "\r              \r" );
+	dbg_printf ( "\r              \r" );
 }
 
 /**
@@ -39,9 +61,9 @@ void dbg_pause ( void ) {
  *
  */
 void dbg_more ( void ) {
-	printf ( "---more---" );
+	dbg_printf ( "---more---" );
 	getchar();
-	printf ( "\r          \r" );
+	dbg_printf ( "\r          \r" );
 }
 
 /**
@@ -58,27 +80,27 @@ static void dbg_hex_dump_da_row ( unsigned long dispaddr, const void *data,
 	unsigned int i;
 	uint8_t byte;
 
-	printf ( "%08lx :", ( dispaddr + offset ) );
+	dbg_printf ( "%08lx :", ( dispaddr + offset ) );
 	for ( i = offset ; i < ( offset + 16 ) ; i++ ) {
 		if ( i >= len ) {
-			printf ( "   " );
+			dbg_printf ( "   " );
 			continue;
 		}
-		printf ( "%c%02x",
-			 ( ( ( i % 16 ) == 8 ) ? '-' : ' ' ), bytes[i] );
+		dbg_printf ( "%c%02x",
+			     ( ( ( i % 16 ) == 8 ) ? '-' : ' ' ), bytes[i] );
 	}
-	printf ( " : " );
+	dbg_printf ( " : " );
 	for ( i = offset ; i < ( offset + 16 ) ; i++ ) {
 		if ( i >= len ) {
-			printf ( " " );
+			dbg_printf ( " " );
 			continue;
 		}
 		byte = bytes[i];
 		if ( ( byte < 0x20 ) || ( byte >= 0x7f ) )
 			byte = '.';
-		printf ( "%c", byte );
+		dbg_printf ( "%c", byte );
 	}
-	printf ( "\n" );
+	dbg_printf ( "\n" );
 }
 
 /**
@@ -158,8 +180,8 @@ static int dbg_autocolour ( unsigned long stream ) {
  * @v stream		Message stream ID
  */
 void dbg_autocolourise ( unsigned long stream ) {
-	printf ( "\033[%dm",
-		 ( stream ? ( 31 + dbg_autocolour ( stream ) ) : 0 ) );
+	dbg_printf ( "\033[%dm",
+		     ( stream ? ( 31 + dbg_autocolour ( stream ) ) : 0 ) );
 }
 
 /**
@@ -167,5 +189,5 @@ void dbg_autocolourise ( unsigned long stream ) {
  *
  */
 void dbg_decolourise ( void ) {
-	printf ( "\033[0m" );
+	dbg_printf ( "\033[0m" );
 }
diff --git a/roms/ipxe/src/core/debug_md5.c b/roms/ipxe/src/core/debug_md5.c
index 6214f61176e48971ec5e1592b33c..f049ac7578e84cd7ce2def31571b 100644
--- a/roms/ipxe/src/core/debug_md5.c
+++ b/roms/ipxe/src/core/debug_md5.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/device.c b/roms/ipxe/src/core/device.c
index dc182e032505a4c87785f6f6ad48..330f95c5adfe55b31f023ba3da0b 100644
--- a/roms/ipxe/src/core/device.c
+++ b/roms/ipxe/src/core/device.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/downloader.c b/roms/ipxe/src/core/downloader.c
index 4dc0aa02a27fda41755ac0be67fd..4f3fc2c81eea2e3189d4349eafcb 100644
--- a/roms/ipxe/src/core/downloader.c
+++ b/roms/ipxe/src/core/downloader.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -21,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <stdlib.h>
 #include <stdarg.h>
 #include <errno.h>
+#include <syslog.h>
 #include <ipxe/iobuf.h>
 #include <ipxe/xfer.h>
 #include <ipxe/open.h>
@@ -73,6 +75,15 @@ static void downloader_free ( struct refcnt *refcnt ) {
  */
 static void downloader_finished ( struct downloader *downloader, int rc ) {
 
+	/* Log download status */
+	if ( rc == 0 ) {
+		syslog ( LOG_NOTICE, "Downloaded \"%s\"\n",
+			 downloader->image->name );
+	} else {
+		syslog ( LOG_ERR, "Download of \"%s\" failed: %s\n",
+			 downloader->image->name, strerror ( rc ) );
+	}
+
 	/* Shut down interfaces */
 	intf_shutdown ( &downloader->xfer, rc );
 	intf_shutdown ( &downloader->job, rc );
@@ -101,7 +112,7 @@ static int downloader_ensure_size ( struct downloader *downloader,
 	if ( ! new_buffer ) {
 		DBGC ( downloader, "Downloader %p could not extend buffer to "
 		       "%zd bytes\n", downloader, len );
-		return -ENOBUFS;
+		return -ENOSPC;
 	}
 	downloader->image->data = new_buffer;
 	downloader->image->len = len;
@@ -173,6 +184,8 @@ static int downloader_xfer_deliver ( struct downloader *downloader,
 
  done:
 	free_iob ( iobuf );
+	if ( rc != 0 )
+		downloader_finished ( downloader, rc );
 	return rc;
 }
 
diff --git a/roms/ipxe/src/core/edd.c b/roms/ipxe/src/core/edd.c
index 8ba24b17ffd866899b3901bb1623..d574ea6c029de78edf452aede988 100644
--- a/roms/ipxe/src/core/edd.c
+++ b/roms/ipxe/src/core/edd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/exec.c b/roms/ipxe/src/core/exec.c
index 18d3477ecc8134647b3a7a258262..843a51db7a014909944df9342cf8 100644
--- a/roms/ipxe/src/core/exec.c
+++ b/roms/ipxe/src/core/exec.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -31,6 +32,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/command.h>
 #include <ipxe/parseopt.h>
 #include <ipxe/settings.h>
+#include <ipxe/console.h>
+#include <ipxe/keys.h>
+#include <ipxe/process.h>
+#include <ipxe/nap.h>
 #include <ipxe/shell.h>
 
 /** @file
@@ -55,18 +60,22 @@ static int stop_state;
 int execv ( const char *command, char * const argv[] ) {
 	struct command *cmd;
 	int argc;
+	int rc;
 
 	/* Count number of arguments */
 	for ( argc = 0 ; argv[argc] ; argc++ ) {}
 
 	/* An empty command is deemed to do nothing, successfully */
-	if ( command == NULL )
-		return 0;
+	if ( command == NULL ) {
+		rc = 0;
+		goto done;
+	}
 
 	/* Sanity checks */
 	if ( argc == 0 ) {
 		DBG ( "%s: empty argument list\n", command );
-		return -EINVAL;
+		rc = -EINVAL;
+		goto done;
 	}
 
 	/* Reset getopt() library ready for use by the command.  This
@@ -78,12 +87,24 @@ int execv ( const char *command, char * const argv[] ) {
 
 	/* Hand off to command implementation */
 	for_each_table_entry ( cmd, COMMANDS ) {
-		if ( strcmp ( command, cmd->name ) == 0 )
-			return cmd->exec ( argc, ( char ** ) argv );
+		if ( strcmp ( command, cmd->name ) == 0 ) {
+			rc = cmd->exec ( argc, ( char ** ) argv );
+			goto done;
+		}
 	}
 
 	printf ( "%s: command not found\n", command );
-	return -ENOEXEC;
+	rc = -ENOEXEC;
+
+ done:
+	/* Store error number, if an error occurred */
+	if ( rc ) {
+		errno = rc;
+		if ( errno < 0 )
+			errno = -errno;
+	}
+
+	return rc;
 }
 
 /**
@@ -354,7 +375,7 @@ char * concat_args ( char **args ) {
 	ptr = string;
 	for ( arg = args ; *arg ; arg++ ) {
 		ptr += sprintf ( ptr, "%s%s",
-				 ( ( ptr == string ) ? "" : " " ), *arg );
+				 ( ( arg == args ) ? "" : " " ), *arg );
 	}
 	assert ( ptr < ( string + len ) );
 
@@ -490,3 +511,91 @@ struct command isset_command __command = {
 	.name = "isset",
 	.exec = isset_exec,
 };
+
+/** "iseq" options */
+struct iseq_options {};
+
+/** "iseq" option list */
+static struct option_descriptor iseq_opts[] = {};
+
+/** "iseq" command descriptor */
+static struct command_descriptor iseq_cmd =
+	COMMAND_DESC ( struct iseq_options, iseq_opts, 2, 2,
+		       "<value1> <value2>" );
+
+/**
+ * "iseq" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int iseq_exec ( int argc, char **argv ) {
+	struct iseq_options opts;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &iseq_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Return success iff arguments are equal */
+	return ( ( strcmp ( argv[optind], argv[ optind + 1 ] ) == 0 ) ?
+		 0 : -ERANGE );
+}
+
+/** "iseq" command */
+struct command iseq_command __command = {
+	.name = "iseq",
+	.exec = iseq_exec,
+};
+
+/** "sleep" options */
+struct sleep_options {};
+
+/** "sleep" option list */
+static struct option_descriptor sleep_opts[] = {};
+
+/** "sleep" command descriptor */
+static struct command_descriptor sleep_cmd =
+	COMMAND_DESC ( struct sleep_options, sleep_opts, 1, 1, "<seconds>" );
+
+/**
+ * "sleep" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int sleep_exec ( int argc, char **argv ) {
+	struct sleep_options opts;
+	unsigned int seconds;
+	unsigned long start;
+	unsigned long delay;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &sleep_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse number of seconds */
+	if ( ( rc = parse_integer ( argv[optind], &seconds ) ) != 0 )
+		return rc;
+
+	/* Delay for specified number of seconds */
+	start = currticks();
+	delay = ( seconds * TICKS_PER_SEC );
+	while ( ( currticks() - start ) <= delay ) {
+		step();
+		if ( iskey() && ( getchar() == CTRL_C ) )
+			return -ECANCELED;
+		cpu_nap();
+	}
+
+	return 0;
+}
+
+/** "sleep" command */
+struct command sleep_command __command = {
+	.name = "sleep",
+	.exec = sleep_exec,
+};
diff --git a/roms/ipxe/src/core/fnrec.c b/roms/ipxe/src/core/fnrec.c
index 05d63aaa84b2d3472025e44508f5..3453c8b6af307828ddc2738f9653 100644
--- a/roms/ipxe/src/core/fnrec.c
+++ b/roms/ipxe/src/core/fnrec.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/gdbserial.c b/roms/ipxe/src/core/gdbserial.c
index ed217add0848c6dea2040afd19d0..6f78c88bfa88a167e220a08dd481 100644
--- a/roms/ipxe/src/core/gdbserial.c
+++ b/roms/ipxe/src/core/gdbserial.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/gdbstub.c b/roms/ipxe/src/core/gdbstub.c
index 34e6a037347f1dc4095f4b964ae7..cbe328f9f46253b75a9905b94e5c 100644
--- a/roms/ipxe/src/core/gdbstub.c
+++ b/roms/ipxe/src/core/gdbstub.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/gdbudp.c b/roms/ipxe/src/core/gdbudp.c
index 9cb6572b7ebb5bdade898834d2b8..5977547c8f5eed52c7c5684850ab 100644
--- a/roms/ipxe/src/core/gdbudp.c
+++ b/roms/ipxe/src/core/gdbudp.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/getkey.c b/roms/ipxe/src/core/getkey.c
index d692b1bc85e35271b8bdadb558cf..d69cfb44b9c404a31a39236260cb 100644
--- a/roms/ipxe/src/core/getkey.c
+++ b/roms/ipxe/src/core/getkey.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -23,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/process.h>
 #include <ipxe/keys.h>
 #include <ipxe/timer.h>
+#include <ipxe/nap.h>
 
 /** @file
  *
@@ -45,6 +47,7 @@ static int getchar_timeout ( unsigned long timeout ) {
 		step();
 		if ( iskey() )
 			return getchar();
+		cpu_nap();
 	}
 
 	return -1;
diff --git a/roms/ipxe/src/core/getopt.c b/roms/ipxe/src/core/getopt.c
index b67da0c1301a26675751ebe064c9..abc1edd6cbf644ef957ef9ed16fc 100644
--- a/roms/ipxe/src/core/getopt.c
+++ b/roms/ipxe/src/core/getopt.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -239,6 +240,11 @@ int getopt_long ( int argc, char * const argv[], const char *optstring,
 
 	/* Check for long options */
 	if ( *(opttext++) == '-' ) {
+		/* "--" indicates end of options */
+		if ( *opttext == '\0' ) {
+			optind++;
+			return -1;
+		}
 		for ( longopt = longopts ; longopt->name ; longopt++ ) {
 			if ( ! match_long_option ( argc, argv, opttext,
 						   longopt, &option ) )
diff --git a/roms/ipxe/src/core/hw.c b/roms/ipxe/src/core/hw.c
index aca558099c1fec7a88ea35d922f0..91736a65294c181029d46546e88a 100644
--- a/roms/ipxe/src/core/hw.c
+++ b/roms/ipxe/src/core/hw.c
@@ -26,15 +26,7 @@ static void hw_finished ( struct hw *hw, int rc ) {
 	process_del ( &hw->process );
 }
 
-static struct interface_operation hw_xfer_operations[] = {
-	INTF_OP ( intf_close, struct hw *, hw_finished ),
-};
-
-static struct interface_descriptor hw_xfer_desc =
-	INTF_DESC ( struct hw, xfer, hw_xfer_operations );
-
-static void hw_step ( struct process *process ) {
-	struct hw *hw = container_of ( process, struct hw, process );
+static void hw_step ( struct hw *hw ) {
 	int rc;
 
 	if ( xfer_window ( &hw->xfer ) ) {
@@ -43,6 +35,17 @@ static void hw_step ( struct process *process ) {
 	}
 }
 
+static struct interface_operation hw_xfer_operations[] = {
+	INTF_OP ( xfer_window_changed, struct hw *, hw_step ),
+	INTF_OP ( intf_close, struct hw *, hw_finished ),
+};
+
+static struct interface_descriptor hw_xfer_desc =
+	INTF_DESC ( struct hw, xfer, hw_xfer_operations );
+
+static struct process_descriptor hw_process_desc =
+	PROC_DESC_ONCE ( struct hw, process, hw_step );
+
 static int hw_open ( struct interface *xfer, struct uri *uri __unused ) {
 	struct hw *hw;
 
@@ -52,7 +55,7 @@ static int hw_open ( struct interface *xfer, struct uri *uri __unused ) {
 		return -ENOMEM;
 	ref_init ( &hw->refcnt, NULL );
 	intf_init ( &hw->xfer, &hw_xfer_desc, &hw->refcnt );
-	process_init ( &hw->process, hw_step, &hw->refcnt );
+	process_init ( &hw->process, &hw_process_desc, &hw->refcnt );
 
 	/* Attach parent interface, mortalise self, and return */
 	intf_plug_plug ( &hw->xfer, xfer );
diff --git a/roms/ipxe/src/core/image.c b/roms/ipxe/src/core/image.c
index 86c264c26634b2626e4c6bdd3347..4101ff3b5de61ddd1232d3fc83a3 100644
--- a/roms/ipxe/src/core/image.c
+++ b/roms/ipxe/src/core/image.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -25,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <errno.h>
 #include <assert.h>
 #include <libgen.h>
+#include <syslog.h>
 #include <ipxe/list.h>
 #include <ipxe/umalloc.h>
 #include <ipxe/uri.h>
@@ -36,12 +38,28 @@ FILE_LICENCE ( GPL2_OR_LATER );
  *
  */
 
+/* Disambiguate the various error causes */
+#define EACCES_UNTRUSTED \
+	__einfo_error ( EINFO_EACCES_UNTRUSTED )
+#define EINFO_EACCES_UNTRUSTED \
+	__einfo_uniqify ( EINFO_EACCES, 0x01, "Untrusted image" )
+#define EACCES_PERMANENT \
+	__einfo_error ( EINFO_EACCES_PERMANENT )
+#define EINFO_EACCES_PERMANENT \
+	__einfo_uniqify ( EINFO_EACCES, 0x02, "Trust requirement is permanent" )
+
 /** List of registered images */
 struct list_head images = LIST_HEAD_INIT ( images );
 
 /** Currently-executing image */
 struct image *current_image;
 
+/** Current image trust requirement */
+static int require_trusted_images = 0;
+
+/** Prevent changes to image trust requirement */
+static int require_trusted_images_permanent = 0;
+
 /**
  * Free executable image
  *
@@ -50,48 +68,70 @@ struct image *current_image;
 static void free_image ( struct refcnt *refcnt ) {
 	struct image *image = container_of ( refcnt, struct image, refcnt );
 
+	DBGC ( image, "IMAGE %s freed\n", image->name );
+	free ( image->name );
 	free ( image->cmdline );
 	uri_put ( image->uri );
 	ufree ( image->data );
 	image_put ( image->replacement );
 	free ( image );
-	DBGC ( image, "IMAGE %s freed\n", image->name );
 }
 
 /**
  * Allocate executable image
  *
+ * @v uri		URI, or NULL
  * @ret image		Executable image
  */
-struct image * alloc_image ( void ) {
+struct image * alloc_image ( struct uri *uri ) {
+	const char *name;
 	struct image *image;
+	int rc;
 
+	/* Allocate image */
 	image = zalloc ( sizeof ( *image ) );
-	if ( image ) {
-		ref_init ( &image->refcnt, free_image );
+	if ( ! image )
+		goto err_alloc;
+
+	/* Initialise image */
+	ref_init ( &image->refcnt, free_image );
+	if ( uri ) {
+		image->uri = uri_get ( uri );
+		if ( uri->path ) {
+			name = basename ( ( char * ) uri->path );
+			if ( ( rc = image_set_name ( image, name ) ) != 0 )
+				goto err_set_name;
+		}
 	}
+
 	return image;
+
+ err_set_name:
+	image_put ( image );
+ err_alloc:
+	return NULL;
 }
 
 /**
- * Set image URI
+ * Set image name
  *
  * @v image		Image
- * @v URI		New image URI
- *
- * If no name is set, the name will be updated to the base name of the
- * URI path (if any).
+ * @v name		New image name
+ * @ret rc		Return status code
  */
-void image_set_uri ( struct image *image, struct uri *uri ) {
-	const char *path = uri->path;
+int image_set_name ( struct image *image, const char *name ) {
+	char *name_copy;
 
-	/* Replace URI reference */
-	uri_put ( image->uri );
-	image->uri = uri_get ( uri );
+	/* Duplicate name */
+	name_copy = strdup ( name );
+	if ( ! name_copy )
+		return -ENOMEM;
 
-	/* Set name if none already specified */
-	if ( path && ( ! image->name[0] ) )
-		image_set_name ( image, basename ( ( char * ) path ) );
+	/* Replace existing name */
+	free ( image->name );
+	image->name = name_copy;
+
+	return 0;
 }
 
 /**
@@ -121,11 +161,14 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) {
  */
 int register_image ( struct image *image ) {
 	static unsigned int imgindex = 0;
+	char name[8]; /* "imgXXXX" */
+	int rc;
 
 	/* Create image name if it doesn't already have one */
-	if ( ! image->name[0] ) {
-		snprintf ( image->name, sizeof ( image->name ), "img%d",
-			   imgindex++ );
+	if ( ! image->name ) {
+		snprintf ( name, sizeof ( name ), "img%d", imgindex++ );
+		if ( ( rc = image_set_name ( image, name ) ) != 0 )
+			return rc;
 	}
 
 	/* Avoid ending up with multiple "selected" images on
@@ -152,6 +195,10 @@ int register_image ( struct image *image ) {
  */
 void unregister_image ( struct image *image ) {
 
+	/* Do nothing unless image is registered */
+	if ( ! ( image->flags & IMAGE_REGISTERED ) )
+		return;
+
 	DBGC ( image, "IMAGE %s unregistered\n", image->name );
 	list_del ( &image->list );
 	image->flags &= ~IMAGE_REGISTERED;
@@ -217,17 +264,13 @@ int image_probe ( struct image *image ) {
  */
 int image_exec ( struct image *image ) {
 	struct image *saved_current_image;
-	struct image *replacement;
+	struct image *replacement = NULL;
 	struct uri *old_cwuri;
 	int rc;
 
 	/* Sanity check */
 	assert ( image->flags & IMAGE_REGISTERED );
 
-	/* Check that this image can be executed */
-	if ( ( rc = image_probe ( image ) ) != 0 )
-		return rc;
-
 	/* Switch current working directory to be that of the image itself */
 	old_cwuri = uri_get ( cwuri );
 	churi ( image->uri );
@@ -241,6 +284,20 @@ int image_exec ( struct image *image ) {
 	 */
 	current_image = image_get ( image );
 
+	/* Check that this image can be selected for execution */
+	if ( ( rc = image_select ( image ) ) != 0 )
+		goto err;
+
+	/* Check that image is trusted (if applicable) */
+	if ( require_trusted_images && ! ( image->flags & IMAGE_TRUSTED ) ) {
+		DBGC ( image, "IMAGE %s is not trusted\n", image->name );
+		rc = -EACCES_UNTRUSTED;
+		goto err;
+	}
+
+	/* Record boot attempt */
+	syslog ( LOG_NOTICE, "Executing \"%s\"\n", image->name );
+
 	/* Try executing the image */
 	if ( ( rc = image->type->exec ( image ) ) != 0 ) {
 		DBGC ( image, "IMAGE %s could not execute: %s\n",
@@ -248,6 +305,15 @@ int image_exec ( struct image *image ) {
 		/* Do not return yet; we still have clean-up to do */
 	}
 
+	/* Record result of boot attempt */
+	if ( rc == 0 ) {
+		syslog ( LOG_NOTICE, "Execution of \"%s\" completed\n",
+			 image->name );
+	} else {
+		syslog ( LOG_ERR, "Execution of \"%s\" failed: %s\n",
+			 image->name, strerror ( rc ) );
+	}
+
 	/* Pick up replacement image before we drop the original
 	 * image's temporary reference.  The replacement image must
 	 * already be registered, so we don't need to hold a temporary
@@ -257,6 +323,19 @@ int image_exec ( struct image *image ) {
 	if ( replacement )
 		assert ( replacement->flags & IMAGE_REGISTERED );
 
+ err:
+	/* Unregister image if applicable */
+	if ( image->flags & IMAGE_AUTO_UNREGISTER )
+		unregister_image ( image );
+
+	/* Debug message for tail-recursion.  Placed here because the
+	 * image_put() may end up freeing the image.
+	 */
+	if ( replacement ) {
+		DBGC ( image, "IMAGE %s replacing self with IMAGE %s\n",
+		       image->name, replacement->name );
+	}
+
 	/* Drop temporary reference to the original image */
 	image_put ( image );
 
@@ -268,12 +347,8 @@ int image_exec ( struct image *image ) {
 	uri_put ( old_cwuri );
 
 	/* Tail-recurse into replacement image, if one exists */
-	if ( replacement ) {
-		DBGC ( image, "IMAGE %s replacing self with IMAGE %s\n",
-		       image->name, replacement->name );
-		if ( ( rc = image_exec ( replacement ) ) != 0 )
-			return rc;
-	}
+	if ( replacement )
+		return image_exec ( replacement );
 
 	return rc;
 }
@@ -302,6 +377,10 @@ int image_replace ( struct image *replacement ) {
 		return rc;
 	}
 
+	/* Check that the replacement image can be executed */
+	if ( ( rc = image_probe ( replacement ) ) != 0 )
+		return rc;
+
 	/* Clear any existing replacement */
 	image_put ( image->replacement );
 
@@ -351,3 +430,27 @@ struct image * image_find_selected ( void ) {
 	}
 	return NULL;
 }
+
+/**
+ * Change image trust requirement
+ *
+ * @v require_trusted	Require trusted images
+ * @v permanent		Make trust requirement permanent
+ * @ret rc		Return status code
+ */
+int image_set_trust ( int require_trusted, int permanent ) {
+
+	/* Update trust requirement, if permitted to do so */
+	if ( ! require_trusted_images_permanent ) {
+		require_trusted_images = require_trusted;
+		require_trusted_images_permanent = permanent;
+	}
+
+	/* Fail if we attempted to change the trust requirement but
+	 * were not permitted to do so.
+	 */
+	if ( require_trusted_images != require_trusted )
+		return -EACCES_PERMANENT;
+
+	return 0;
+}
diff --git a/roms/ipxe/src/core/init.c b/roms/ipxe/src/core/init.c
index 4dc706f63062a3beaeefca18c37c..5627441946b703ac130e5df01741 100644
--- a/roms/ipxe/src/core/init.c
+++ b/roms/ipxe/src/core/init.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/interface.c b/roms/ipxe/src/core/interface.c
index c69875ea6db37945a0d4a1a2a3dd..97caac8049d32326ec2182e4a7e9 100644
--- a/roms/ipxe/src/core/interface.c
+++ b/roms/ipxe/src/core/interface.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/iobuf.c b/roms/ipxe/src/core/iobuf.c
index d776d606e890ad40123cbe423c95..afc91d150873d59edde42233a9fa 100644
--- a/roms/ipxe/src/core/iobuf.c
+++ b/roms/ipxe/src/core/iobuf.c
@@ -13,12 +13,14 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
+#include <strings.h>
 #include <errno.h>
 #include <ipxe/malloc.h>
 #include <ipxe/iobuf.h>
@@ -29,36 +31,81 @@ FILE_LICENCE ( GPL2_OR_LATER );
  *
  */
 
+/**
+ * Allocate I/O buffer with specified alignment and offset
+ *
+ * @v len	Required length of buffer
+ * @v align	Physical alignment
+ * @v offset	Offset from physical alignment
+ * @ret iobuf	I/O buffer, or NULL if none available
+ *
+ * @c align will be rounded up to the nearest power of two.
+ */
+struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) {
+	struct io_buffer *iobuf;
+	void *data;
+
+	/* Align buffer length to ensure that struct io_buffer is aligned */
+	len = ( len + __alignof__ ( *iobuf ) - 1 ) &
+		~( __alignof__ ( *iobuf ) - 1 );
+
+	/* Round up alignment to the nearest power of two */
+	align = ( 1 << fls ( align - 1 ) );
+
+	/* Allocate buffer plus descriptor as a single unit, unless
+	 * doing so will push the total size over the alignment
+	 * boundary.
+	 */
+	if ( ( len + sizeof ( *iobuf ) ) <= align ) {
+
+		/* Allocate memory for buffer plus descriptor */
+		data = malloc_dma_offset ( len + sizeof ( *iobuf ), align,
+					   offset );
+		if ( ! data )
+			return NULL;
+		iobuf = ( data + len );
+
+	} else {
+
+		/* Allocate memory for buffer */
+		data = malloc_dma_offset ( len, align, offset );
+		if ( ! data )
+			return NULL;
+
+		/* Allocate memory for descriptor */
+		iobuf = malloc ( sizeof ( *iobuf ) );
+		if ( ! iobuf ) {
+			free_dma ( data, len );
+			return NULL;
+		}
+	}
+
+	/* Populate descriptor */
+	iobuf->head = iobuf->data = iobuf->tail = data;
+	iobuf->end = ( data + len );
+
+	return iobuf;
+}
+
 /**
  * Allocate I/O buffer
  *
  * @v len	Required length of buffer
  * @ret iobuf	I/O buffer, or NULL if none available
  *
- * The I/O buffer will be physically aligned to a multiple of
- * @c IOBUF_SIZE.
+ * The I/O buffer will be physically aligned on its own size (rounded
+ * up to the nearest power of two).
  */
 struct io_buffer * alloc_iob ( size_t len ) {
-	struct io_buffer *iobuf = NULL;
-	void *data;
 
 	/* Pad to minimum length */
 	if ( len < IOB_ZLEN )
 		len = IOB_ZLEN;
 
-	/* Align buffer length */
-	len = ( len + __alignof__( *iobuf ) - 1 ) &
-		~( __alignof__( *iobuf ) - 1 );
-	
-	/* Allocate memory for buffer plus descriptor */
-	data = malloc_dma ( len + sizeof ( *iobuf ), IOB_ALIGN );
-	if ( ! data )
-		return NULL;
-
-	iobuf = ( struct io_buffer * ) ( data + len );
-	iobuf->head = iobuf->data = iobuf->tail = data;
-	iobuf->end = iobuf;
-	return iobuf;
+	/* Align buffer on its own size to avoid potential problems
+	 * with boundary-crossing DMA.
+	 */
+	return alloc_iob_raw ( len, len, 0 );
 }
 
 /**
@@ -67,12 +114,29 @@ struct io_buffer * alloc_iob ( size_t len ) {
  * @v iobuf	I/O buffer
  */
 void free_iob ( struct io_buffer *iobuf ) {
-	if ( iobuf ) {
-		assert ( iobuf->head <= iobuf->data );
-		assert ( iobuf->data <= iobuf->tail );
-		assert ( iobuf->tail <= iobuf->end );
-		free_dma ( iobuf->head,
-			   ( iobuf->end - iobuf->head ) + sizeof ( *iobuf ) );
+	size_t len;
+
+	/* Allow free_iob(NULL) to be valid */
+	if ( ! iobuf )
+		return;
+
+	/* Sanity checks */
+	assert ( iobuf->head <= iobuf->data );
+	assert ( iobuf->data <= iobuf->tail );
+	assert ( iobuf->tail <= iobuf->end );
+
+	/* Free buffer */
+	len = ( iobuf->end - iobuf->head );
+	if ( iobuf->end == iobuf ) {
+
+		/* Descriptor is inline */
+		free_dma ( iobuf->head, ( len + sizeof ( *iobuf ) ) );
+
+	} else {
+
+		/* Descriptor is detached */
+		free_dma ( iobuf->head, len );
+		free ( iobuf );
 	}
 }
 
@@ -94,3 +158,45 @@ int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len ) {
 	return -ENOBUFS;
 }
 
+/**
+ * Concatenate I/O buffers into a single buffer
+ *
+ * @v list	List of I/O buffers
+ * @ret iobuf	Concatenated I/O buffer, or NULL on allocation failure
+ *
+ * After a successful concatenation, the list will be empty.
+ */
+struct io_buffer * iob_concatenate ( struct list_head *list ) {
+	struct io_buffer *iobuf;
+	struct io_buffer *tmp;
+	struct io_buffer *concatenated;
+	size_t len = 0;
+
+	/* If the list contains only a single entry, avoid an
+	 * unnecessary additional allocation.
+	 */
+	if ( list_is_singular ( list ) ) {
+		iobuf = list_first_entry ( list, struct io_buffer, list );
+		INIT_LIST_HEAD ( list );
+		return iobuf;
+	}
+
+	/* Calculate total length */
+	list_for_each_entry ( iobuf, list, list )
+		len += iob_len ( iobuf );
+
+	/* Allocate new I/O buffer */
+	concatenated = alloc_iob_raw ( len, __alignof__ ( *iobuf ), 0 );
+	if ( ! concatenated )
+		return NULL;
+
+	/* Move data to new I/O buffer */
+	list_for_each_entry_safe ( iobuf, tmp, list, list ) {
+		list_del ( &iobuf->list );
+		memcpy ( iob_put ( concatenated, iob_len ( iobuf ) ),
+			 iobuf->data, iob_len ( iobuf ) );
+		free_iob ( iobuf );
+	}
+
+	return concatenated;
+}
diff --git a/roms/ipxe/src/core/job.c b/roms/ipxe/src/core/job.c
index ac4e43e7bb590361b47f6f34e6b6..64d184ec313810735d1da11c932c 100644
--- a/roms/ipxe/src/core/job.c
+++ b/roms/ipxe/src/core/job.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/linebuf.c b/roms/ipxe/src/core/linebuf.c
index f152bccb0174f3d740bfa3975efa..8fb2f86a767c66419c8ef1f9b061 100644
--- a/roms/ipxe/src/core/linebuf.c
+++ b/roms/ipxe/src/core/linebuf.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/lineconsole.c b/roms/ipxe/src/core/lineconsole.c
new file mode 100644
index 0000000000000000000000000000000000000000..1b6791cf3d78a6261ea5a31e100810cc9b5b5e97
--- /dev/null
+++ b/roms/ipxe/src/core/lineconsole.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Line-based console
+ *
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <ipxe/ansiesc.h>
+#include <ipxe/lineconsole.h>
+
+/**
+ * Print a character to a line-based console
+ *
+ * @v character		Character to be printed
+ * @ret print		Print line
+ */
+size_t line_putchar ( struct line_console *line, int character ) {
+
+	/* Strip ANSI escape sequences */
+	character = ansiesc_process ( &line->ctx, character );
+	if ( character < 0 )
+		return 0;
+
+	/* Ignore carriage return */
+	if ( character == '\r' )
+		return 0;
+
+	/* Treat newline as a terminator */
+	if ( character == '\n' )
+		character = 0;
+
+	/* Add character to buffer */
+	line->buffer[line->index++] = character;
+
+	/* Do nothing more unless we reach end-of-line (or end-of-buffer) */
+	if ( ( character != 0 ) &&
+	     ( line->index < ( line->len - 1 /* NUL */ ) ) ) {
+		return 0;
+	}
+
+	/* Reset to start of buffer */
+	line->index = 0;
+
+	return 1;
+}
diff --git a/roms/ipxe/src/core/list.c b/roms/ipxe/src/core/list.c
new file mode 100644
index 0000000000000000000000000000000000000000..77579d69aba9c0de31ecd214e8e9958a683daf9e
--- /dev/null
+++ b/roms/ipxe/src/core/list.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Linked lists
+ *
+ */
+
+#include <ipxe/list.h>
+
+void extern_list_add ( struct list_head *new, struct list_head *head ) {
+	inline_list_add ( new, head );
+}
+
+void extern_list_add_tail ( struct list_head *new, struct list_head *head ) {
+	inline_list_add_tail ( new, head );
+}
+
+void extern_list_del ( struct list_head *list ) {
+	inline_list_del ( list );
+}
+
+int extern_list_empty ( const struct list_head *list ) {
+	return inline_list_empty ( list );
+}
+
+int extern_list_is_singular ( const struct list_head *list ) {
+	return inline_list_is_singular ( list );
+}
+
+int extern_list_is_last ( const struct list_head *list,
+			  const struct list_head *head ) {
+	return inline_list_is_last ( list, head );
+}
+
+void extern_list_cut_position ( struct list_head *new,
+				struct list_head *list,
+				struct list_head *entry ) {
+	inline_list_cut_position ( new, list, entry );
+}
+
+void extern_list_splice ( const struct list_head *list,
+			  struct list_head *entry ) {
+	inline_list_splice ( list, entry );
+}
+
+void extern_list_splice_tail ( const struct list_head *list,
+			       struct list_head *entry ) {
+	inline_list_splice_tail ( list, entry );
+}
+
+void extern_list_splice_init ( struct list_head *list,
+			       struct list_head *entry ) {
+	inline_list_splice_init ( list, entry );
+}
+
+void extern_list_splice_tail_init ( struct list_head *list,
+				    struct list_head *entry ) {
+	inline_list_splice_tail_init ( list, entry );
+}
+
+int extern_list_contains ( struct list_head *entry,
+			   struct list_head *head ) {
+	return inline_list_contains ( entry, head );
+}
diff --git a/roms/ipxe/src/core/log.c b/roms/ipxe/src/core/log.c
new file mode 100644
index 0000000000000000000000000000000000000000..f160b4fc8958ec4b270cf976e05b6f047dd0ac23
--- /dev/null
+++ b/roms/ipxe/src/core/log.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * System logger
+ *
+ */
+
+#include <stdarg.h>
+#include <syslog.h>
+#include <ipxe/console.h>
+
+/**
+ * Write message to system log
+ *
+ * @v fmt		Format string
+ * @v args		Arguments
+ */
+void log_vprintf ( const char *fmt, va_list args ) {
+	int saved_usage;
+
+	/* Mark console as in use for log messages */
+	saved_usage = console_set_usage ( CONSOLE_USAGE_LOG );
+
+	/* Print message */
+	vprintf ( fmt, args );
+
+	/* Restore console usage */
+	console_set_usage ( saved_usage );
+}
+
+/**
+ * Write message to system log
+ *
+ * @v fmt		Format string
+ * @v ...		Arguments
+ */
+void log_printf ( const char *fmt, ... ) {
+	va_list args;
+
+	va_start ( args, fmt );
+	log_vprintf ( fmt, args );
+	va_end ( args );
+}
diff --git a/roms/ipxe/src/core/main.c b/roms/ipxe/src/core/main.c
index 9fd4a76ff8c075fed134f2536960..8ad912d43e8202456ac4a97a8287 100644
--- a/roms/ipxe/src/core/main.c
+++ b/roms/ipxe/src/core/main.c
@@ -14,53 +14,18 @@ Literature dealing with the network protocols:
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
+#include <stddef.h>
 #include <stdio.h>
-#include <stdlib.h>
 #include <ipxe/init.h>
-#include <ipxe/features.h>
-#include <ipxe/shell.h>
-#include <ipxe/image.h>
-#include <ipxe/keys.h>
-#include <usr/prompt.h>
 #include <usr/autoboot.h>
 #include <config/general.h>
 
-#define NORMAL	"\033[0m"
-#define BOLD	"\033[1m"
-#define CYAN	"\033[36m"
-
-/** The "scriptlet" setting */
-struct setting scriptlet_setting __setting ( SETTING_MISC ) = {
-	.name = "scriptlet",
-	.description = "Boot scriptlet",
-	.tag = DHCP_EB_SCRIPTLET,
-	.type = &setting_type_string,
-};
-
-/**
- * Prompt for shell entry
- *
- * @ret	enter_shell		User wants to enter shell
- */
-static int shell_banner ( void ) {
-
-	/* Skip prompt if timeout is zero */
-	if ( BANNER_TIMEOUT <= 0 )
-		return 0;
-
-	return ( prompt ( "\nPress Ctrl-B for the iPXE command line...",
-			  ( BANNER_TIMEOUT * 100 ), CTRL_B ) == 0 );
-}
-
 /**
  * Main entry point
  *
  * @ret rc		Return status code
  */
 __asmcall int main ( void ) {
-	struct feature *feature;
-	struct image *image;
-	char *scriptlet;
 
 	/* Some devices take an unreasonably long time to initialise */
 	printf ( PRODUCT_SHORT_NAME " initialising devices..." );
@@ -68,49 +33,7 @@ __asmcall int main ( void ) {
 	startup();
 	printf ( "ok\n" );
 
-	/*
-	 * Print welcome banner
-	 *
-	 *
-	 * If you wish to brand this build of iPXE, 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 iPXE or http://ipxe.org, we prefer you not to
-	 * do so.
-	 *
-	 */
-	printf ( NORMAL "\n\n" PRODUCT_NAME "\n" BOLD "iPXE " VERSION
-		 NORMAL " -- Open Source Network Boot Firmware -- "
-		 CYAN "http://ipxe.org" NORMAL "\n"
-		 "Features:" );
-	for_each_table_entry ( feature, FEATURES )
-		printf ( " %s", feature->name );
-	printf ( "\n" );
-
-	/* Boot system */
-	if ( ( image = first_image() ) != NULL ) {
-		/* We have an embedded image; execute it */
-		image_exec ( image );
-	} else if ( shell_banner() ) {
-		/* User wants shell; just give them a shell */
-		shell();
-	} else {
-		fetch_string_setting_copy ( NULL, &scriptlet_setting,
-					    &scriptlet );
-		if ( scriptlet ) {
-			/* User has defined a scriptlet; execute it */
-			system ( scriptlet );
-			free ( scriptlet );
-		} else {
-			/* Try booting.  If booting fails, offer the
-			 * user another chance to enter the shell.
-			 */
-			autoboot();
-			if ( shell_banner() )
-				shell();
-		}
-	}
+	ipxe ( NULL );
 
 	shutdown_exit();
 
diff --git a/roms/ipxe/src/core/malloc.c b/roms/ipxe/src/core/malloc.c
index d694f5559aabcc458e9c1367a3e3..56ca7edc625aedde6a4e44537b20 100644
--- a/roms/ipxe/src/core/malloc.c
+++ b/roms/ipxe/src/core/malloc.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -91,9 +92,9 @@ size_t freemem;
 /**
  * Heap size
  *
- * Currently fixed at 128kB.
+ * Currently fixed at 512kB.
  */
-#define HEAP_SIZE ( 128 * 1024 )
+#define HEAP_SIZE ( 512 * 1024 )
 
 /** The heap itself */
 static char heap[HEAP_SIZE] __attribute__ (( aligned ( __alignof__(void *) )));
@@ -105,11 +106,36 @@ static char heap[HEAP_SIZE] __attribute__ (( aligned ( __alignof__(void *) )));
 static inline void valgrind_make_blocks_defined ( void ) {
 	struct memory_block *block;
 
-	if ( RUNNING_ON_VALGRIND > 0 ) {
-		VALGRIND_MAKE_MEM_DEFINED ( &free_blocks,
-					    sizeof ( free_blocks ) );
-		list_for_each_entry ( block, &free_blocks, list )
-			VALGRIND_MAKE_MEM_DEFINED ( block, sizeof ( *block ) );
+	if ( RUNNING_ON_VALGRIND <= 0 )
+		return;
+
+	/* Traverse free block list, marking each block structure as
+	 * defined.  Some contortions are necessary to avoid errors
+	 * from list_check().
+	 */
+
+	/* Mark block list itself as defined */
+	VALGRIND_MAKE_MEM_DEFINED ( &free_blocks, sizeof ( free_blocks ) );
+
+	/* Mark areas accessed by list_check() as defined */
+	VALGRIND_MAKE_MEM_DEFINED ( &free_blocks.prev->next,
+				    sizeof ( free_blocks.prev->next ) );
+	VALGRIND_MAKE_MEM_DEFINED ( free_blocks.next,
+				    sizeof ( *free_blocks.next ) );
+	VALGRIND_MAKE_MEM_DEFINED ( &free_blocks.next->next->prev,
+				    sizeof ( free_blocks.next->next->prev ) );
+
+	/* Mark each block in list as defined */
+	list_for_each_entry ( block, &free_blocks, list ) {
+
+		/* Mark block as defined */
+		VALGRIND_MAKE_MEM_DEFINED ( block, sizeof ( *block ) );
+
+		/* Mark areas accessed by list_check() as defined */
+		VALGRIND_MAKE_MEM_DEFINED ( block->list.next,
+					    sizeof ( *block->list.next ) );
+		VALGRIND_MAKE_MEM_DEFINED ( &block->list.next->next->prev,
+				      sizeof ( block->list.next->next->prev ) );
 	}
 }
 
@@ -119,14 +145,45 @@ static inline void valgrind_make_blocks_defined ( void ) {
  */
 static inline void valgrind_make_blocks_noaccess ( void ) {
 	struct memory_block *block;
-	struct memory_block *tmp;
+	struct memory_block *prev = NULL;
+
+	if ( RUNNING_ON_VALGRIND <= 0 )
+		return;
+
+	/* Traverse free block list, marking each block structure as
+	 * inaccessible.  Some contortions are necessary to avoid
+	 * errors from list_check().
+	 */
+
+	/* Mark each block in list as inaccessible */
+	list_for_each_entry ( block, &free_blocks, list ) {
 
-	if ( RUNNING_ON_VALGRIND > 0 ) {
-		list_for_each_entry_safe ( block, tmp, &free_blocks, list )
-			VALGRIND_MAKE_MEM_NOACCESS ( block, sizeof ( *block ) );
-		VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks,
-					     sizeof ( free_blocks ) );
+		/* Mark previous block (if any) as inaccessible. (Current
+		 * block will be accessed by list_check().)
+		 */
+		if ( prev )
+			VALGRIND_MAKE_MEM_NOACCESS ( prev, sizeof ( *prev ) );
+		prev = block;
+
+		/* At the end of the list, list_check() will end up
+		 * accessing the first list item.  Temporarily mark
+		 * this area as defined.
+		 */
+		VALGRIND_MAKE_MEM_DEFINED ( &free_blocks.next->prev,
+					    sizeof ( free_blocks.next->prev ) );
 	}
+	/* Mark last block (if any) as inaccessible */
+	if ( prev )
+		VALGRIND_MAKE_MEM_NOACCESS ( prev, sizeof ( *prev ) );
+
+	/* Mark as inaccessible the area that was temporarily marked
+	 * as defined to avoid errors from list_check().
+	 */
+	VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks.next->prev,
+				     sizeof ( free_blocks.next->prev ) );
+
+	/* Mark block list itself as inaccessible */
+	VALGRIND_MAKE_MEM_NOACCESS ( &free_blocks, sizeof ( free_blocks ) );
 }
 
 /**
@@ -136,12 +193,26 @@ static inline void valgrind_make_blocks_noaccess ( void ) {
  */
 static unsigned int discard_cache ( void ) {
 	struct cache_discarder *discarder;
-	unsigned int discarded = 0;
+	unsigned int discarded;
 
 	for_each_table_entry ( discarder, CACHE_DISCARDERS ) {
-		discarded += discarder->discard();
+		discarded = discarder->discard();
+		if ( discarded )
+			return discarded;
 	}
-	return discarded;
+	return 0;
+}
+
+/**
+ * Discard all cached data
+ *
+ */
+static void discard_all_cache ( void ) {
+	unsigned int discarded;
+
+	do {
+		discarded = discard_cache();
+	} while ( discarded );
 }
 
 /**
@@ -149,6 +220,7 @@ static unsigned int discard_cache ( void ) {
  *
  * @v size		Requested size
  * @v align		Physical alignment
+ * @v offset		Offset from physical alignment
  * @ret ptr		Memory block, or NULL
  *
  * Allocates a memory block @b physically aligned as requested.  No
@@ -156,7 +228,7 @@ static unsigned int discard_cache ( void ) {
  *
  * @c align must be a power of two.  @c size may not be zero.
  */
-void * alloc_memblock ( size_t size, size_t align ) {
+void * alloc_memblock ( size_t size, size_t align, size_t offset ) {
 	struct memory_block *block;
 	size_t align_mask;
 	size_t pre_size;
@@ -173,12 +245,13 @@ void * alloc_memblock ( size_t size, size_t align ) {
 	size = ( size + MIN_MEMBLOCK_SIZE - 1 ) & ~( MIN_MEMBLOCK_SIZE - 1 );
 	align_mask = ( align - 1 ) | ( MIN_MEMBLOCK_SIZE - 1 );
 
-	DBG ( "Allocating %#zx (aligned %#zx)\n", size, align );
+	DBG ( "Allocating %#zx (aligned %#zx+%zx)\n", size, align, offset );
 	while ( 1 ) {
 		/* Search through blocks for the first one with enough space */
 		list_for_each_entry ( block, &free_blocks, list ) {
-			pre_size = ( - virt_to_phys ( block ) ) & align_mask;
-			post_size = block->size - pre_size - size;
+			pre_size = ( ( offset - virt_to_phys ( block ) )
+				     & align_mask );
+			post_size = ( block->size - pre_size - size );
 			if ( post_size >= 0 ) {
 				/* Split block into pre-block, block, and
 				 * post-block.  After this split, the "pre"
@@ -347,7 +420,7 @@ void * realloc ( void *old_ptr, size_t new_size ) {
 	if ( new_size ) {
 		new_total_size = ( new_size +
 				   offsetof ( struct autosized_block, data ) );
-		new_block = alloc_memblock ( new_total_size, 1 );
+		new_block = alloc_memblock ( new_total_size, 1, 0 );
 		if ( ! new_block )
 			return NULL;
 		VALGRIND_MAKE_MEM_UNDEFINED ( new_block, offsetof ( struct autosized_block, data ) );
@@ -458,6 +531,19 @@ struct init_fn heap_init_fn __init_fn ( INIT_EARLY ) = {
 	.initialise = init_heap,
 };
 
+/**
+ * Discard all cached data on shutdown
+ *
+ */
+static void shutdown_cache ( int booting __unused ) {
+	discard_all_cache();
+}
+
+/** Memory allocator shutdown function */
+struct startup_fn heap_startup_fn __startup_fn ( STARTUP_EARLY ) = {
+	.shutdown = shutdown_cache,
+};
+
 #if 0
 #include <stdio.h>
 /**
diff --git a/roms/ipxe/src/core/memblock.c b/roms/ipxe/src/core/memblock.c
new file mode 100644
index 0000000000000000000000000000000000000000..1fd89b871dcf485a0075ce2138d967da92495be6
--- /dev/null
+++ b/roms/ipxe/src/core/memblock.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Largest memory block
+ *
+ */
+
+#include <stdint.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/io.h>
+#include <ipxe/memblock.h>
+
+/**
+ * Find largest usable memory region
+ *
+ * @ret start		Start of region
+ * @ret len		Length of region
+ */
+size_t largest_memblock ( userptr_t *start ) {
+	struct memory_map memmap;
+	struct memory_region *region;
+	physaddr_t max = ~( ( physaddr_t ) 0 );
+	physaddr_t region_start;
+	physaddr_t region_end;
+	size_t region_len;
+	unsigned int i;
+	size_t len = 0;
+
+	/* Avoid returning uninitialised data on error */
+	*start = UNULL;
+
+	/* Scan through all memory regions */
+	get_memmap ( &memmap );
+	for ( i = 0 ; i < memmap.count ; i++ ) {
+		region = &memmap.regions[i];
+		DBG ( "Considering [%llx,%llx)\n", region->start, region->end );
+
+		/* Truncate block to maximum physical address */
+		if ( region->start > max ) {
+			DBG ( "...starts after maximum address %lx\n", max );
+			continue;
+		}
+		region_start = region->start;
+		if ( region->end > max ) {
+			DBG ( "...end truncated to maximum address %lx\n", max);
+			region_end = 0; /* =max, given the wraparound */
+		} else {
+			region_end = region->end;
+		}
+		region_len = ( region_end - region_start );
+
+		/* Use largest block */
+		if ( region_len > len ) {
+			DBG ( "...new best block found\n" );
+			*start = phys_to_user ( region_start );
+			len = region_len;
+		}
+	}
+
+	return len;
+}
diff --git a/roms/ipxe/src/core/menu.c b/roms/ipxe/src/core/menu.c
new file mode 100644
index 0000000000000000000000000000000000000000..8d42e1f835d588e35d89bc743baaa546fe34b84d
--- /dev/null
+++ b/roms/ipxe/src/core/menu.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Menu selection
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ipxe/list.h>
+#include <ipxe/menu.h>
+
+/** List of all menus */
+static LIST_HEAD ( menus );
+
+/**
+ * Create menu
+ *
+ * @v name		Menu name, or NULL
+ * @v title		Menu title, or NULL
+ * @ret menu		Menu, or NULL on failure
+ */
+struct menu * create_menu ( const char *name, const char *title ) {
+	size_t name_len;
+	size_t title_len;
+	size_t len;
+	struct menu *menu;
+	char *name_copy;
+	char *title_copy;
+
+	/* Destroy any existing menu of this name */
+	menu = find_menu ( name );
+	if ( menu )
+		destroy_menu ( menu );
+
+	/* Use empty title if none given */
+	if ( ! title )
+		title = "";
+
+	/* Allocate menu */
+	name_len = ( name ? ( strlen ( name ) + 1 /* NUL */ ) : 0 );
+	title_len = ( strlen ( title ) + 1 /* NUL */ );
+	len = ( sizeof ( *menu ) + name_len + title_len );
+	menu = zalloc ( len );
+	if ( ! menu )
+		return NULL;
+	name_copy = ( ( void * ) ( menu + 1 ) );
+	title_copy = ( name_copy + name_len );
+
+	/* Initialise menu */
+	if ( name ) {
+		strcpy ( name_copy, name );
+		menu->name = name_copy;
+	}
+	strcpy ( title_copy, title );
+	menu->title = title_copy;
+	INIT_LIST_HEAD ( &menu->items );
+
+	/* Add to list of menus */
+	list_add_tail ( &menu->list, &menus );
+
+	DBGC ( menu, "MENU %s created with title \"%s\"\n",
+	       menu->name, menu->title );
+
+	return menu;
+}
+
+/**
+ * Add menu item
+ *
+ * @v menu		Menu
+ * @v label		Label, or NULL
+ * @v text		Text, or NULL
+ * @v shortcut		Shortcut key
+ * @v is_default	Item is the default item
+ * @ret item		Menu item, or NULL on failure
+ */
+struct menu_item * add_menu_item ( struct menu *menu, const char *label,
+				   const char *text, int shortcut,
+				   int is_default ) {
+	size_t label_len;
+	size_t text_len;
+	size_t len;
+	struct menu_item *item;
+	char *label_copy;
+	char *text_copy;
+
+	/* Use empty text if none given */
+	if ( ! text )
+		text = "";
+
+	/* Allocate item */
+	label_len = ( label ? ( strlen ( label ) + 1 /* NUL */ ) : 0 );
+	text_len = ( strlen ( text ) + 1 /* NUL */ );
+	len = ( sizeof ( *item ) + label_len + text_len );
+	item = zalloc ( len );
+	if ( ! item )
+		return NULL;
+	label_copy = ( ( void * ) ( item + 1 ) );
+	text_copy = ( label_copy + label_len );
+
+	/* Initialise item */
+	if ( label ) {
+		strcpy ( label_copy, label );
+		item->label = label_copy;
+	}
+	strcpy ( text_copy, text );
+	item->text = text_copy;
+	item->shortcut = shortcut;
+	item->is_default = is_default;
+
+	/* Add to list of items */
+	list_add_tail ( &item->list, &menu->items );
+
+	return item;
+}
+
+/**
+ * Destroy menu
+ *
+ * @v menu		Menu
+ */
+void destroy_menu ( struct menu *menu ) {
+	struct menu_item *item;
+	struct menu_item *tmp;
+
+	/* Remove from list of menus */
+	list_del ( &menu->list );
+
+	/* Free items */
+	list_for_each_entry_safe ( item, tmp, &menu->items, list ) {
+		list_del ( &item->list );
+		free ( item );
+	}
+
+	/* Free menu */
+	free ( menu );
+}
+
+/**
+ * Find menu
+ *
+ * @v name		Menu name, or NULL
+ * @ret menu		Menu, or NULL if not found
+ */
+struct menu * find_menu ( const char *name ) {
+	struct menu *menu;
+
+	list_for_each_entry ( menu, &menus, list ) {
+		if ( ( menu->name == name ) ||
+		     ( strcmp ( menu->name, name ) == 0 ) ) {
+			return menu;
+		}
+	}
+
+	return NULL;
+}
diff --git a/roms/ipxe/src/core/misc.c b/roms/ipxe/src/core/misc.c
index 8f56e1fb44ae5a54cc2aa6b0d4d6..11342481a73c12cfad1163d16d98 100644
--- a/roms/ipxe/src/core/misc.c
+++ b/roms/ipxe/src/core/misc.c
@@ -35,8 +35,17 @@ int inet_aton ( const char *cp, struct in_addr *inp ) {
 
 unsigned long strtoul ( const char *p, char **endp, int base ) {
 	unsigned long ret = 0;
+	int negative = 0;
 	unsigned int charval;
 
+	while ( isspace ( *p ) )
+		p++;
+
+	if ( *p == '-' ) {
+		negative = 1;
+		p++;
+	}
+
 	base = strtoul_base ( &p, base );
 
 	while ( 1 ) {
@@ -47,6 +56,9 @@ unsigned long strtoul ( const char *p, char **endp, int base ) {
 		p++;
 	}
 
+	if ( negative )
+		ret = -ret;
+
 	if ( endp )
 		*endp = ( char * ) p;
 
diff --git a/roms/ipxe/src/core/monojob.c b/roms/ipxe/src/core/monojob.c
index 7431f88a3a16333b3611784860dc..d262f70b25cd1268f9c0a0174112 100644
--- a/roms/ipxe/src/core/monojob.c
+++ b/roms/ipxe/src/core/monojob.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -53,37 +54,52 @@ struct interface monojob = INTF_INIT ( monojob_intf_desc );
 /**
  * Wait for single foreground job to complete
  *
- * @v string		Job description to display
+ * @v string		Job description to display, or NULL to be silent
  * @ret rc		Job final status code
  */
 int monojob_wait ( const char *string ) {
 	struct job_progress progress;
 	int key;
 	int rc;
+	unsigned long last_keycheck;
 	unsigned long last_progress;
+	unsigned long now;
 	unsigned long elapsed;
 	unsigned long completed;
 	unsigned long total;
 	unsigned int percentage;
 	int shown_percentage = 0;
 
-	printf ( "%s...", string );
+	if ( string )
+		printf ( "%s...", string );
 	monojob_rc = -EINPROGRESS;
-	last_progress = currticks();
+	last_keycheck = last_progress = currticks();
 	while ( monojob_rc == -EINPROGRESS ) {
+
+		/* Allow job to progress */
 		step();
-		if ( iskey() ) {
-			key = getchar();
-			switch ( key ) {
-			case CTRL_C:
-				monojob_close ( &monojob, -ECANCELED );
-				break;
-			default:
-				break;
+		now = currticks();
+
+		/* Check for keypresses.  This can be time-consuming,
+		 * so check only once per clock tick.
+		 */
+		if ( now != last_keycheck ) {
+			if ( iskey() ) {
+				key = getchar();
+				switch ( key ) {
+				case CTRL_C:
+					monojob_close ( &monojob, -ECANCELED );
+					break;
+				default:
+					break;
+				}
 			}
+			last_keycheck = now;
 		}
-		elapsed = ( currticks() - last_progress );
-		if ( elapsed >= TICKS_PER_SEC ) {
+
+		/* Display progress, if applicable */
+		elapsed = ( now - last_progress );
+		if ( string && ( elapsed >= TICKS_PER_SEC ) ) {
 			if ( shown_percentage )
 				printf ( "\b\b\b\b    \b\b\b\b" );
 			job_progress ( &monojob, &progress );
@@ -98,7 +114,7 @@ int monojob_wait ( const char *string ) {
 				printf ( "." );
 				shown_percentage = 0;
 			}
-			last_progress = currticks();
+			last_progress = now;
 		}
 	}
 	rc = monojob_rc;
@@ -106,10 +122,13 @@ int monojob_wait ( const char *string ) {
 	if ( shown_percentage )
 		printf ( "\b\b\b\b    \b\b\b\b" );
 
-	if ( rc ) {
-		printf ( " %s\n", strerror ( rc ) );
-	} else {
-		printf ( " ok\n" );
+	if ( string ) {
+		if ( rc ) {
+			printf ( " %s\n", strerror ( rc ) );
+		} else {
+			printf ( " ok\n" );
+		}
 	}
+
 	return rc;
 }
diff --git a/roms/ipxe/src/core/null_sanboot.c b/roms/ipxe/src/core/null_sanboot.c
index 9cdb16290487743ce77c3998fde3..18c0dea84ce4974ef8e708902c0d 100644
--- a/roms/ipxe/src/core/null_sanboot.c
+++ b/roms/ipxe/src/core/null_sanboot.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -38,6 +39,7 @@ static int null_san_describe ( unsigned int drive __unused ) {
 	return -EOPNOTSUPP;
 }
 
+PROVIDE_SANBOOT_INLINE ( null, san_default_drive );
 PROVIDE_SANBOOT ( null, san_hook, null_san_hook );
 PROVIDE_SANBOOT ( null, san_unhook, null_san_unhook );
 PROVIDE_SANBOOT ( null, san_boot, null_san_boot );
diff --git a/roms/ipxe/src/core/null_time.c b/roms/ipxe/src/core/null_time.c
new file mode 100644
index 0000000000000000000000000000000000000000..506c70b52aa5459e5f41edbdb893b15b970ea6d4
--- /dev/null
+++ b/roms/ipxe/src/core/null_time.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Nonexistent time source
+ *
+ */
+
+#include <ipxe/time.h>
+
+PROVIDE_TIME_INLINE ( null, time_now );
diff --git a/roms/ipxe/src/core/nvo.c b/roms/ipxe/src/core/nvo.c
index ea58badef3e837c560802aaccaff..5383fe5c3681a052fef0538ecc30 100644
--- a/roms/ipxe/src/core/nvo.c
+++ b/roms/ipxe/src/core/nvo.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -191,8 +192,8 @@ static int nvo_save ( struct nvo_block *nvo ) {
  * @v setting		Setting
  * @ret applies		Setting applies within this settings block
  */
-static int nvo_applies ( struct settings *settings __unused,
-			 struct setting *setting ) {
+int nvo_applies ( struct settings *settings __unused,
+		  struct setting *setting ) {
 
 	return dhcpopt_applies ( setting->tag );
 }
@@ -295,7 +296,8 @@ int register_nvo ( struct nvo_block *nvo, struct settings *parent ) {
 		goto err_load;
 
 	/* Register settings */
-	if ( ( rc = register_settings ( &nvo->settings, parent, "nvo" ) ) != 0 )
+	if ( ( rc = register_settings ( &nvo->settings, parent,
+					NVO_SETTINGS_NAME ) ) != 0 )
 		goto err_register;
 
 	DBGC ( nvo, "NVO %p registered\n", nvo );
diff --git a/roms/ipxe/src/core/open.c b/roms/ipxe/src/core/open.c
index b026efcd98f5173417a7bd8c3377..b479c2975f0ef7eb370844b4e5d1 100644
--- a/roms/ipxe/src/core/open.c
+++ b/roms/ipxe/src/core/open.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/parseopt.c b/roms/ipxe/src/core/parseopt.c
index 24a57624466b18ac290e432fcde3..659d20ee955f2003b75154072a1e 100644
--- a/roms/ipxe/src/core/parseopt.c
+++ b/roms/ipxe/src/core/parseopt.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -26,7 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <errno.h>
 #include <getopt.h>
 #include <ipxe/netdevice.h>
-#include <ipxe/image.h>
+#include <ipxe/menu.h>
 #include <ipxe/parseopt.h>
 
 /** @file
@@ -40,6 +41,17 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define EINFO_ECANCELED_NO_OP \
 	__einfo_uniqify ( EINFO_ECANCELED, 0x01, "Nothing to do" )
 
+/* Disambiguate the various error codes */
+#define EINVAL_INTEGER __einfo_error ( EINFO_EINVAL_INTEGER )
+#define EINFO_EINVAL_INTEGER \
+	__einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid integer value" )
+#define EINVAL_UNKNOWN_OPTION __einfo_error ( EINFO_EINVAL_UNKNOWN_OPTION )
+#define EINFO_EINVAL_UNKNOWN_OPTION \
+	__einfo_uniqify ( EINFO_EINVAL, 0x02, "Unrecognised option" )
+#define EINVAL_MISSING_ARGUMENT __einfo_error ( EINFO_EINVAL_MISSING_ARGUMENT )
+#define EINFO_EINVAL_MISSING_ARGUMENT \
+	__einfo_uniqify ( EINFO_EINVAL, 0x03, "Missing argument" )
+
 /**
 * Parse string value
  *
@@ -75,7 +87,7 @@ int parse_integer ( const char *text, unsigned int *value ) {
 	*value = strtoul ( text, &endp, 0 );
 	if ( *endp ) {
 		printf ( "\"%s\": invalid integer value\n", text );
-		return -EINVAL;
+		return -EINVAL_INTEGER;
 	}
 
 	return 0;
@@ -104,21 +116,22 @@ int parse_netdev ( const char *text, struct net_device **netdev ) {
 }
 
 /**
- * Parse image name
+ * Parse menu name
  *
  * @v text		Text
- * @ret image		Image
+ * @ret menu		Menu
  * @ret rc		Return status code
  */
-int parse_image ( const char *text, struct image **image ) {
+int parse_menu ( const char *text, struct menu **menu ) {
 
-	/* Sanity check */
-	assert ( text != NULL );
-
-	/* Find network device */
-	*image = find_image ( text );
-	if ( ! *image ) {
-		printf ( "\"%s\": no such image\n", text );
+	/* Find menu */
+	*menu = find_menu ( text );
+	if ( ! *menu ) {
+		if ( text ) {
+			printf ( "\"%s\": no such menu\n", text );
+		} else {
+			printf ( "No default menu\n" );
+		}
 		return -ENOENT;
 	}
 
@@ -140,6 +153,25 @@ int parse_flag ( const char *text __unused, int *flag ) {
 	return 0;
 }
 
+/**
+ * Parse key
+ *
+ * @v text		Text
+ * @ret key		Key
+ * @ret rc		Return status code
+ */
+int parse_key ( const char *text, unsigned int *key ) {
+
+	/* Interpret single characters as being a literal key character */
+	if ( text[0] && ! text[1] ) {
+		*key = text[0];
+		return 0;
+	}
+
+	/* Otherwise, interpret as an integer */
+	return parse_integer ( text, key );
+}
+
 /**
  * Print command usage message
  *
@@ -152,16 +184,16 @@ void print_usage ( struct command_descriptor *cmd, char **argv ) {
 }
 
 /**
- * Parse command-line options
+ * Reparse command-line options
  *
  * @v argc		Argument count
  * @v argv		Argument list
  * @v cmd		Command descriptor
- * @v opts		Options
+ * @v opts		Options (already initialised with default values)
  * @ret rc		Return status code
  */
-int parse_options ( int argc, char **argv, struct command_descriptor *cmd,
-		    void *opts ) {
+int reparse_options ( int argc, char **argv, struct command_descriptor *cmd,
+		      void *opts ) {
 	struct option longopts[ cmd->num_options + 1 /* help */ + 1 /* end */ ];
 	char shortopts[ cmd->num_options * 3 /* possible "::" */ + 1 /* "h" */
 			+ 1 /* NUL */ ];
@@ -193,9 +225,6 @@ int parse_options ( int argc, char **argv, struct command_descriptor *cmd,
 	DBGC ( cmd,  "Command \"%s\" has options \"%s\", %d-%d args, len %d\n",
 	       argv[0], shortopts, cmd->min_args, cmd->max_args, cmd->len );
 
-	/* Clear options */
-	memset ( opts, 0, cmd->len );
-
 	/* Parse options */
 	while ( ( c = getopt_long ( argc, argv, shortopts, longopts,
 				    NULL ) ) >= 0 ) {
@@ -205,10 +234,13 @@ int parse_options ( int argc, char **argv, struct command_descriptor *cmd,
 			print_usage ( cmd, argv );
 			return -ECANCELED_NO_OP;
 		case '?' :
+			/* Print usage message */
+			print_usage ( cmd, argv );
+			return -EINVAL_UNKNOWN_OPTION;
 		case ':' :
 			/* Print usage message */
 			print_usage ( cmd, argv );
-			return -EINVAL;
+			return -EINVAL_MISSING_ARGUMENT;
 		default:
 			/* Search for an option to parse */
 			for ( i = 0 ; i < cmd->num_options ; i++ ) {
@@ -233,3 +265,21 @@ int parse_options ( int argc, char **argv, struct command_descriptor *cmd,
 
 	return 0;
 }
+
+/**
+ * Parse command-line options
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @v cmd		Command descriptor
+ * @v opts		Options (may be uninitialised)
+ * @ret rc		Return status code
+ */
+int parse_options ( int argc, char **argv, struct command_descriptor *cmd,
+		    void *opts ) {
+
+	/* Clear options */
+	memset ( opts, 0, cmd->len );
+
+	return reparse_options ( argc, argv, cmd, opts );
+}
diff --git a/roms/ipxe/src/core/pcmcia.c b/roms/ipxe/src/core/pcmcia.c
index 2d8ceb6f5779f3eb4ec0dd355e7e..5fd21f4a9720c9b02cbbc22e013f 100644
--- a/roms/ipxe/src/core/pcmcia.c
+++ b/roms/ipxe/src/core/pcmcia.c
@@ -34,7 +34,6 @@ FILE_LICENCE ( GPL2_ONLY );
 #define CODE_STATUS "alpha"
 #define	CODE_VERSION "0.1.3"
 #include <pcmcia-opts.h>
-#include <ipxe/console.h>
 #include <ipxe/init.h>
 
 int	sockets; /* AHTODO: Phase this out! */
diff --git a/roms/ipxe/src/core/pending.c b/roms/ipxe/src/core/pending.c
new file mode 100644
index 0000000000000000000000000000000000000000..c2671a688a9ce646e4a87ffd4d40469e60e8440a
--- /dev/null
+++ b/roms/ipxe/src/core/pending.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <errno.h>
+#include <ipxe/process.h>
+#include <ipxe/timer.h>
+#include <ipxe/pending.h>
+
+/** @file
+ *
+ * Pending operations
+ *
+ */
+
+/** Total count of pending operations */
+static int pending_total;
+
+/**
+ * Mark an operation as pending
+ *
+ * @v pending		Pending operation
+ */
+void pending_get ( struct pending_operation *pending ) {
+
+	pending->count++;
+	pending_total++;
+	DBGC ( pending, "PENDING %p incremented to %d (total %d)\n",
+	       pending, pending->count, pending_total );
+}
+
+/**
+ * Mark an operation as no longer pending
+ *
+ * @v pending		Pending operation
+ */
+void pending_put ( struct pending_operation *pending ) {
+
+	if ( pending->count ) {
+		pending_total--;
+		pending->count--;
+		DBGC ( pending, "PENDING %p decremented to %d (total %d)\n",
+		       pending, pending->count, pending_total );
+	}
+}
+
+/**
+ * Wait for pending operations to complete
+ *
+ * @v timeout		Timeout period, in ticks (0=indefinite)
+ * @ret rc		Return status code
+ */
+int pending_wait ( unsigned long timeout ) {
+	unsigned long start = currticks();
+
+	do {
+		if ( pending_total == 0 )
+			return 0;
+		step();
+	} while ( ( timeout == 0 ) || ( ( currticks() - start ) < timeout ) );
+
+	return -ETIMEDOUT;
+}
diff --git a/roms/ipxe/src/core/posix_io.c b/roms/ipxe/src/core/posix_io.c
index 38bd727b0263d396407df178d81d..8460d0f5159208f924140f9cec43 100644
--- a/roms/ipxe/src/core/posix_io.c
+++ b/roms/ipxe/src/core/posix_io.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/process.c b/roms/ipxe/src/core/process.c
index a3297856458fa0e6f76e5dabbba6..d341a2c37249a42fdc155ea956fb 100644
--- a/roms/ipxe/src/core/process.c
+++ b/roms/ipxe/src/core/process.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -33,6 +34,16 @@ FILE_LICENCE ( GPL2_OR_LATER );
 /** Process run queue */
 static LIST_HEAD ( run_queue );
 
+/**
+ * Get pointer to object containing process
+ *
+ * @v process		Process
+ * @ret object		Containing object
+ */
+void * process_object ( struct process *process ) {
+	return ( ( ( void * ) process ) - process->desc->offset );
+}
+
 /**
  * Add process to process list
  *
@@ -43,13 +54,13 @@ static LIST_HEAD ( run_queue );
  */
 void process_add ( struct process *process ) {
 	if ( ! process_running ( process ) ) {
-		DBGC ( process, "PROCESS %p (%p) starting\n",
-		       process, process->step );
+		DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
+		       " starting\n", PROC_DBG ( process ) );
 		ref_get ( process->refcnt );
 		list_add_tail ( &process->list, &run_queue );
 	} else {
-		DBGC ( process, "PROCESS %p (%p) already started\n",
-		       process, process->step );
+		DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
+		       " already started\n", PROC_DBG ( process ) );
 	}
 }
 
@@ -63,14 +74,14 @@ void process_add ( struct process *process ) {
  */
 void process_del ( struct process *process ) {
 	if ( process_running ( process ) ) {
-		DBGC ( process, "PROCESS %p (%p) stopping\n",
-		       process, process->step );
+		DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
+		       " stopping\n", PROC_DBG ( process ) );
 		list_del ( &process->list );
 		INIT_LIST_HEAD ( &process->list );
 		ref_put ( process->refcnt );
 	} else {
-		DBGC ( process, "PROCESS %p (%p) already stopped\n",
-		       process, process->step );
+		DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
+		       " already stopped\n", PROC_DBG ( process ) );
 	}
 }
 
@@ -82,17 +93,25 @@ void process_del ( struct process *process ) {
  */
 void step ( void ) {
 	struct process *process;
+	struct process_descriptor *desc;
+	void *object;
 
 	if ( ( process = list_first_entry ( &run_queue, struct process,
 					    list ) ) ) {
-		list_del ( &process->list );
-		list_add_tail ( &process->list, &run_queue );
 		ref_get ( process->refcnt ); /* Inhibit destruction mid-step */
-		DBGC2 ( process, "PROCESS %p (%p) executing\n",
-			process, process->step );
-		process->step ( process );
-		DBGC2 ( process, "PROCESS %p (%p) finished executing\n",
-			process, process->step );
+		desc = process->desc;
+		object = process_object ( process );
+		if ( desc->reschedule ) {
+			list_del ( &process->list );
+			list_add_tail ( &process->list, &run_queue );
+		} else {
+			process_del ( process );
+		}
+		DBGC2 ( PROC_COL ( process ), "PROCESS " PROC_FMT
+			" executing\n", PROC_DBG ( process ) );
+		desc->step ( object );
+		DBGC2 ( PROC_COL ( process ), "PROCESS " PROC_FMT
+			" finished executing\n", PROC_DBG ( process ) );
 		ref_put ( process->refcnt ); /* Allow destruction */
 	}
 }
diff --git a/roms/ipxe/src/core/refcnt.c b/roms/ipxe/src/core/refcnt.c
index 6117d741d6deb7817fdc175400ba..68a86120e1ca08fa2064c77b1fb4 100644
--- a/roms/ipxe/src/core/refcnt.c
+++ b/roms/ipxe/src/core/refcnt.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/resolv.c b/roms/ipxe/src/core/resolv.c
index 91f0c15cecadbdb8581902f022d3..86f19ee2d357aec688fcbebee4e9 100644
--- a/roms/ipxe/src/core/resolv.c
+++ b/roms/ipxe/src/core/resolv.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -86,16 +87,16 @@ struct numeric_resolv {
 	int rc;
 };
 
-static void numeric_step ( struct process *process ) {
-	struct numeric_resolv *numeric =
-		container_of ( process, struct numeric_resolv, process );
+static void numeric_step ( struct numeric_resolv *numeric ) {
 
-	process_del ( process );
 	if ( numeric->rc == 0 )
 		resolv_done ( &numeric->resolv, &numeric->sa );
 	intf_shutdown ( &numeric->resolv, numeric->rc );
 }
 
+static struct process_descriptor numeric_process_desc =
+	PROC_DESC_ONCE ( struct numeric_resolv, process, numeric_step );
+
 static int numeric_resolv ( struct interface *resolv,
 			    const char *name, struct sockaddr *sa ) {
 	struct numeric_resolv *numeric;
@@ -107,7 +108,8 @@ static int numeric_resolv ( struct interface *resolv,
 		return -ENOMEM;
 	ref_init ( &numeric->refcnt, NULL );
 	intf_init ( &numeric->resolv, &null_intf_desc, &numeric->refcnt );
-	process_init ( &numeric->process, numeric_step, &numeric->refcnt );
+	process_init ( &numeric->process, &numeric_process_desc,
+		       &numeric->refcnt );
 	memcpy ( &numeric->sa, sa, sizeof ( numeric->sa ) );
 
 	DBGC ( numeric, "NUMERIC %p attempting to resolve \"%s\"\n",
diff --git a/roms/ipxe/src/core/serial.c b/roms/ipxe/src/core/serial.c
index a5551b136f4205c3baeae1927a69..8f5a159c44d8a615de2f16652b8c 100644
--- a/roms/ipxe/src/core/serial.c
+++ b/roms/ipxe/src/core/serial.c
@@ -93,6 +93,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define uart_writeb(val,addr) outb((val),(addr))
 #endif
 
+/* Boolean for the state of serial driver initialization */
+int serial_initialized = 0;
+
 /*
  * void serial_putc(int ch);
  *	Write character `ch' to port UART_BASE.
@@ -207,7 +210,6 @@ static void serial_init ( void ) {
 	/* Set clear to send, so flow control works... */
 	uart_writeb((1<<1), UART_BASE + UART_MCR);
 
-
 	/* Flush the input buffer. */
 	do {
 		/* rx buffer reg
@@ -217,6 +219,9 @@ static void serial_init ( void ) {
 		/* line status reg */
 		status = uart_readb(UART_BASE + UART_LSR);
 	} while(status & UART_LSR_DR);
+
+	/* Note that serial support has been initialized */
+	serial_initialized = 1;
  out:
 	return;
 }
diff --git a/roms/ipxe/src/core/serial_console.c b/roms/ipxe/src/core/serial_console.c
index b05a06b1740b2a3e162ef0c88f17..3852a308c9b9a3100e1eea1d8417 100644
--- a/roms/ipxe/src/core/serial_console.c
+++ b/roms/ipxe/src/core/serial_console.c
@@ -1,6 +1,7 @@
 #include <ipxe/init.h>
 #include <ipxe/serial.h>
 #include <ipxe/console.h>
+#include <config/console.h>
 
 /** @file
  *
@@ -8,12 +9,21 @@
  *
  */
 
+/* Set default console usage if applicable */
+#if ! ( defined ( CONSOLE_SERIAL ) && CONSOLE_EXPLICIT ( CONSOLE_SERIAL ) )
+#undef CONSOLE_SERIAL
+#define CONSOLE_SERIAL ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
+#endif
+
 struct console_driver serial_console __console_driver;
 
 static void serial_console_init ( void ) {
-	/* Serial driver initialization should already be done,
-	 * time to enable the serial console. */
-	serial_console.disabled = 0;
+	/*
+	 * Check if serial driver initialization is done.
+	 * If so, it's time to enable the serial console.
+	 */
+	if ( serial_initialized )
+		serial_console.disabled = 0;
 }
 
 struct console_driver serial_console __console_driver = {
@@ -21,6 +31,7 @@ struct console_driver serial_console __console_driver = {
 	.getchar = serial_getc,
 	.iskey = serial_ischar,
 	.disabled = 1,
+	.usage = CONSOLE_SERIAL,
 };
 
 /**
diff --git a/roms/ipxe/src/core/settings.c b/roms/ipxe/src/core/settings.c
index 0a8c5f68e21b77ebd044a950fa5c..656ae19fe642b55914f9a80888d9 100644
--- a/roms/ipxe/src/core/settings.c
+++ b/roms/ipxe/src/core/settings.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -31,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/dhcp.h>
 #include <ipxe/uuid.h>
 #include <ipxe/uri.h>
+#include <ipxe/init.h>
 #include <ipxe/settings.h>
 
 /** @file
@@ -178,6 +180,11 @@ int generic_settings_fetch ( struct settings *settings,
 	if ( len > generic->data_len )
 		len = generic->data_len;
 	memcpy ( data, generic_setting_data ( generic ), len );
+
+	/* Set setting type, if not yet specified */
+	if ( ! setting->type )
+		setting->type = generic->setting.type;
+
 	return generic->data_len;
 }
 
@@ -258,8 +265,8 @@ static void autovivified_settings_free ( struct refcnt *refcnt ) {
  * @v name		Name within this parent
  * @ret settings	Settings block, or NULL
  */
-static struct settings * find_child_settings ( struct settings *parent,
-					       const char *name ) {
+struct settings * find_child_settings ( struct settings *parent,
+					const char *name ) {
 	struct settings *settings;
 
 	/* Treat empty name as meaning "this block" */
@@ -612,8 +619,12 @@ static int fetch_setting_and_origin ( struct settings *settings,
 	if ( setting_applies ( settings, setting ) &&
 	     ( ( ret = settings->op->fetch ( settings, setting,
 					     data, len ) ) >= 0 ) ) {
+		/* Record origin, if applicable */
 		if ( origin )
 			*origin = settings;
+		/* Default to string setting type, if not yet specified */
+		if ( ! setting->type )
+			setting->type = &setting_type_string;
 		return ret;
 	}
 
@@ -676,6 +687,46 @@ int fetch_setting_len ( struct settings *settings, struct setting *setting ) {
 	return fetch_setting ( settings, setting, NULL, 0 );
 }
 
+/**
+ * Fetch copy of setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v data		Buffer to allocate and fill with setting data
+ * @ret len		Length of setting, or negative error
+ *
+ * The caller is responsible for eventually freeing the allocated
+ * buffer.
+ *
+ * To allow the caller to distinguish between a non-existent setting
+ * and an error in allocating memory for the copy, this function will
+ * return success (and a NULL buffer pointer) for a non-existent
+ * setting.
+ */
+int fetch_setting_copy ( struct settings *settings, struct setting *setting,
+			 void **data ) {
+	int len;
+	int check_len = 0;
+
+	/* Avoid returning uninitialised data on error */
+	*data = NULL;
+
+	/* Fetch setting length, and return success if non-existent */
+	len = fetch_setting_len ( settings, setting );
+	if ( len < 0 )
+		return 0;
+
+	/* Allocate buffer */
+	*data = malloc ( len );
+	if ( ! *data )
+		return -ENOMEM;
+
+	/* Fetch setting */
+	check_len = fetch_setting ( settings, setting, *data, len );
+	assert ( check_len == len );
+	return len;
+}
+
 /**
  * Fetch value of string setting
  *
@@ -776,6 +827,41 @@ int fetch_ipv4_setting ( struct settings *settings, struct setting *setting,
 	return fetch_ipv4_array_setting ( settings, setting, inp, 1 );
 }
 
+/**
+ * Extract numeric value of setting
+ *
+ * @v raw		Raw setting data
+ * @v len		Length of raw setting data
+ * @ret signed_value	Value, when interpreted as a signed integer
+ * @ret unsigned_value	Value, when interpreted as an unsigned integer
+ * @ret len		Length of setting, or negative error
+ */
+static int numeric_setting_value ( const void *raw, size_t len,
+				   signed long *signed_value,
+				   unsigned long *unsigned_value ) {
+	const uint8_t *unsigned_bytes = raw;
+	const int8_t *signed_bytes = raw;
+	int is_negative;
+	unsigned int i;
+	uint8_t byte;
+
+	/* Range check */
+	if ( len > sizeof ( long ) )
+		return -ERANGE;
+
+	/* Convert to host-ordered longs */
+	is_negative = ( len && ( signed_bytes[0] < 0 ) );
+	*signed_value = ( is_negative ? -1L : 0 );
+	*unsigned_value = 0;
+	for ( i = 0 ; i < len ; i++ ) {
+		byte = unsigned_bytes[i];
+		*signed_value = ( ( *signed_value << 8 ) | byte );
+		*unsigned_value = ( ( *unsigned_value << 8 ) | byte );
+	}
+
+	return len;
+}
+
 /**
  * Fetch value of signed integer setting
  *
@@ -786,30 +872,20 @@ int fetch_ipv4_setting ( struct settings *settings, struct setting *setting,
  */
 int fetch_int_setting ( struct settings *settings, struct setting *setting,
 			long *value ) {
-	union {
-		uint8_t u8[ sizeof ( long ) ];
-		int8_t s8[ sizeof ( long ) ];
-	} buf;
+	unsigned long dummy;
+	long tmp;
 	int len;
-	int i;
 
 	/* Avoid returning uninitialised data on error */
 	*value = 0;
 
 	/* Fetch raw (network-ordered, variable-length) setting */
-	len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) );
+	len = fetch_setting ( settings, setting, &tmp, sizeof ( tmp ) );
 	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] );
-	}
 
-	return len;
+	/* Extract numeric value */
+	return numeric_setting_value ( &tmp, len, value, &dummy );
 }
 
 /**
@@ -822,22 +898,20 @@ int fetch_int_setting ( struct settings *settings, struct setting *setting,
  */
 int fetch_uint_setting ( struct settings *settings, struct setting *setting,
 			 unsigned long *value ) {
-	long svalue;
+	signed long dummy;
+	long tmp;
 	int len;
 
 	/* Avoid returning uninitialised data on error */
 	*value = 0;
 
-	/* Fetch as a signed long */
-	len = fetch_int_setting ( settings, setting, &svalue );
+	/* Fetch raw (network-ordered, variable-length) setting */
+	len = fetch_setting ( settings, setting, &tmp, sizeof ( tmp ) );
 	if ( len < 0 )
 		return len;
 
-	/* Mask off sign-extended bits */
-	assert ( len <= ( int ) sizeof ( long ) );
-	*value = ( svalue & ( -1UL >> ( 8 * ( sizeof ( long ) - len ) ) ) );
-
-	return len;
+	/* Extract numeric value */
+	return numeric_setting_value ( &tmp, len, &dummy, value );
 }
 
 /**
@@ -929,27 +1003,83 @@ int setting_cmp ( struct setting *a, struct setting *b ) {
  */
 
 /**
- * Store value of typed setting
+ * Fetch and format value of setting
+ *
+ * @v settings		Settings block, or NULL to search all blocks
+ * @v setting		Setting to fetch
+ * @v type		Settings type
+ * @v buf		Buffer to contain formatted value
+ * @v len		Length of buffer
+ * @ret len		Length of formatted value, or negative error
+ */
+int fetchf_setting ( struct settings *settings, struct setting *setting,
+		     char *buf, size_t len ) {
+	int raw_len;
+	int check_len;
+	int rc;
+
+	/* Fetch raw value */
+	raw_len = fetch_setting_len ( settings, setting );
+	if ( raw_len < 0 ) {
+		rc = raw_len;
+		return rc;
+	} else {
+		uint8_t raw[raw_len];
+
+		/* Fetch raw value */
+		check_len = fetch_setting ( settings, setting, raw,
+					    sizeof ( raw ) );
+		if ( check_len < 0 )
+			return check_len;
+		assert ( check_len == raw_len );
+
+		/* Format value */
+		return setting->type->format ( raw, sizeof ( raw ), buf, len );
+	}
+}
+
+/**
+ * Store formatted value of setting
  *
  * @v settings		Settings block
  * @v setting		Setting to store
- * @v type		Settings type
  * @v value		Formatted setting data, or NULL
  * @ret rc		Return status code
  */
 int storef_setting ( struct settings *settings, struct setting *setting,
 		     const char *value ) {
+	int raw_len;
+	int check_len;
+	int rc;
 
-	/* NULL value implies deletion.  Avoid imposing the burden of
-	 * checking for NULL values on each typed setting's storef()
-	 * method.
-	 */
-	if ( ! value )
+	/* NULL value or empty string implies deletion */
+	if ( ( ! value ) || ( ! value[0] ) )
 		return delete_setting ( settings, setting );
-		
-	return setting->type->storef ( settings, setting, value );
+
+	/* Parse formatted value */
+	raw_len = setting->type->parse ( value, NULL, 0 );
+	if ( raw_len < 0 ) {
+		rc = raw_len;
+		return rc;
+	} else {
+		uint8_t raw[raw_len];
+
+		/* Parse formatted value */
+		check_len = setting->type->parse ( value, raw, sizeof ( raw ) );
+		assert ( check_len == raw_len );
+
+		/* Store raw value */
+		return store_setting ( settings, setting, raw, sizeof ( raw ) );
+	}
 }
 
+/******************************************************************************
+ *
+ * Named settings
+ *
+ ******************************************************************************
+ */
+
 /**
  * Find named setting
  *
@@ -1011,6 +1141,7 @@ static struct setting_type * find_setting_type ( const char *name ) {
  * @v get_child		Function to find or create child settings block
  * @v settings		Settings block to fill in
  * @v setting		Setting to fill in
+ * @v default_type	Default type to use, if none specified
  * @v tmp_name		Buffer for copy of setting name
  * @ret rc		Return status code
  *
@@ -1026,6 +1157,7 @@ parse_setting_name ( const char *name,
 		     struct settings * ( * get_child ) ( struct settings *,
 							 const char * ),
 		     struct settings **settings, struct setting *setting,
+		     struct setting_type *default_type,
 		     char *tmp_name ) {
 	char *settings_name;
 	char *setting_name;
@@ -1036,7 +1168,7 @@ parse_setting_name ( const char *name,
 	*settings = &settings_root;
 	memset ( setting, 0, sizeof ( *setting ) );
 	setting->name = "";
-	setting->type = &setting_type_string;
+	setting->type = default_type;
 
 	/* Split name into "[settings_name/]setting_name[:type_name]" */
 	strcpy ( tmp_name, name );
@@ -1105,14 +1237,45 @@ int setting_name ( struct settings *settings, struct setting *setting,
 			  setting->name, setting->type->name );
 }
 
+/**
+ * Store value of named setting
+ *
+ * @v name		Name of setting
+ * @v default_type	Default type to use, if none specified
+ * @v data		Setting data, or NULL to clear setting
+ * @v len		Length of setting data
+ * @ret rc		Return status code
+ */
+int store_named_setting ( const char *name, struct setting_type *default_type,
+			  const void *data, size_t len ) {
+	struct settings *settings;
+	struct setting setting;
+	char tmp_name[ strlen ( name ) + 1 ];
+	int rc;
+
+	/* Parse setting name */
+	if ( ( rc = parse_setting_name ( name, autovivify_child_settings,
+					 &settings, &setting, default_type,
+					 tmp_name ) ) != 0 )
+		return rc;
+
+	/* Store setting */
+	if ( ( rc = store_setting ( settings, &setting, data, len ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
 /**
  * Parse and store value of named setting
  *
  * @v name		Name of setting
+ * @v default_type	Default type to use, if none specified
  * @v value		Formatted setting data, or NULL
  * @ret rc		Return status code
  */
-int storef_named_setting ( const char *name, const char *value ) {
+int storef_named_setting ( const char *name, struct setting_type *default_type,
+			   const char *value ) {
 	struct settings *settings;
 	struct setting setting;
 	char tmp_name[ strlen ( name ) + 1 ];
@@ -1120,7 +1283,8 @@ int storef_named_setting ( const char *name, const char *value ) {
 
 	/* Parse setting name */
 	if ( ( rc = parse_setting_name ( name, autovivify_child_settings,
-					 &settings, &setting, tmp_name )) != 0)
+					 &settings, &setting, default_type,
+					 tmp_name ) ) != 0 )
 		return rc;
 
 	/* Store setting */
@@ -1151,8 +1315,8 @@ int fetchf_named_setting ( const char *name,
 	int rc;
 
 	/* Parse setting name */
-	if ( ( rc = parse_setting_name ( name, find_child_settings,
-					 &settings, &setting, tmp_name )) != 0)
+	if ( ( rc = parse_setting_name ( name, find_child_settings, &settings,
+					 &setting, NULL, tmp_name ) ) != 0 )
 		return rc;
 
 	/* Fetch setting */
@@ -1168,6 +1332,45 @@ int fetchf_named_setting ( const char *name,
 	return len;
 }
 
+/**
+ * Fetch and format copy of value of named setting
+ *
+ * @v name		Name of setting
+ * @v data		Buffer to allocate and fill with formatted value
+ * @ret len		Length of formatted value, or negative error
+ *
+ * The caller is responsible for eventually freeing the allocated
+ * buffer.
+ *
+ * To allow the caller to distinguish between a non-existent setting
+ * and an error in allocating memory for the copy, this function will
+ * return success (and a NULL buffer pointer) for a non-existent
+ * setting.
+ */
+int fetchf_named_setting_copy ( const char *name, char **data ) {
+	int len;
+	int check_len;
+
+	/* Avoid returning uninitialised data on error */
+	*data = NULL;
+
+	/* Fetch formatted value length, and return success if non-existent */
+	len = fetchf_named_setting ( name, NULL, 0, NULL, 0 );
+	if ( len < 0 )
+		return 0;
+
+	/* Allocate buffer */
+	*data = malloc ( len + 1 /* NUL */ );
+	if ( ! *data )
+		return -ENOMEM;
+
+	/* Fetch formatted value */
+	check_len = fetchf_named_setting ( name, NULL, 0, *data,
+					   ( len + 1 /* NUL */ ) );
+	assert ( check_len == len );
+	return len;
+}
+
 /******************************************************************************
  *
  * Setting types
@@ -1176,302 +1379,334 @@ int fetchf_named_setting ( const char *name,
  */
 
 /**
- * Parse and store value of string setting
+ * Parse string setting value
  *
- * @v settings		Settings block
- * @v setting		Setting to store
- * @v value		Formatted setting data
- * @ret rc		Return status code
+ * @v value		Formatted setting value
+ * @v buf		Buffer to contain raw value
+ * @v len		Length of buffer
+ * @ret len		Length of raw value, or negative error
  */
-static int storef_string ( struct settings *settings, struct setting *setting,
-			   const char *value ) {
-	return store_setting ( settings, setting, value, strlen ( value ) );
+static int parse_string_setting ( const char *value, void *buf, size_t len ) {
+	size_t raw_len = strlen ( value ); /* Exclude terminating NUL */
+
+	/* Copy string to buffer */
+	if ( len > raw_len )
+		len = raw_len;
+	memcpy ( buf, value, len );
+
+	return raw_len;
 }
 
 /**
- * Fetch and format value of string setting
+ * Format string setting value
  *
- * @v settings		Settings block, or NULL to search all blocks
- * @v setting		Setting to fetch
+ * @v raw		Raw setting value
+ * @v raw_len		Length of raw setting value
  * @v buf		Buffer to contain formatted value
  * @v len		Length of buffer
  * @ret len		Length of formatted value, or negative error
  */
-static int fetchf_string ( struct settings *settings, struct setting *setting,
-			   char *buf, size_t len ) {
-	return fetch_string_setting ( settings, setting, buf, len );
+static int format_string_setting ( const void *raw, size_t raw_len, char *buf,
+				   size_t len ) {
+
+	/* Copy string to buffer, and terminate */
+	memset ( buf, 0, len );
+	if ( len > raw_len )
+		len = raw_len;
+	memcpy ( buf, raw, len );
+
+	return raw_len;
 }
 
 /** A string setting type */
 struct setting_type setting_type_string __setting_type = {
 	.name = "string",
-	.storef = storef_string,
-	.fetchf = fetchf_string,
+	.parse = parse_string_setting,
+	.format = format_string_setting,
 };
 
 /**
- * Parse and store value of URI-encoded string setting
+ * Parse URI-encoded string setting value
  *
- * @v settings		Settings block
- * @v setting		Setting to store
- * @v value		Formatted setting data
- * @ret rc		Return status code
+ * @v value		Formatted setting value
+ * @v buf		Buffer to contain raw value
+ * @v len		Length of buffer
+ * @ret len		Length of raw value, or negative error
  */
-static int storef_uristring ( struct settings *settings,
-			      struct setting *setting,
-			      const char *value ) {
-	char buf[ strlen ( value ) + 1 ]; /* Decoding never expands string */
-	size_t len;
+static int parse_uristring_setting ( const char *value, void *buf,
+				     size_t len ) {
+	char tmp[ len + 1 /* NUL */ ];
+	size_t raw_len;
+
+	/* Decode to temporary buffer (including NUL) */
+	raw_len = uri_decode ( value, tmp, sizeof ( tmp ) );
 
-	len = uri_decode ( value, buf, sizeof ( buf ) );
-	return store_setting ( settings, setting, buf, len );
+	/* Copy to output buffer (excluding NUL) */
+	if ( len > raw_len )
+		len = raw_len;
+	memcpy ( buf, tmp, len );
+
+	return raw_len;
 }
 
 /**
- * Fetch and format value of URI-encoded string setting
+ * Format URI-encoded string setting value
  *
- * @v settings		Settings block, or NULL to search all blocks
- * @v setting		Setting to fetch
+ * @v raw		Raw setting value
+ * @v raw_len		Length of raw setting value
  * @v buf		Buffer to contain formatted value
  * @v len		Length of buffer
  * @ret len		Length of formatted value, or negative error
  */
-static int fetchf_uristring ( struct settings *settings,
-			      struct setting *setting,
-			      char *buf, size_t len ) {
-	ssize_t raw_len;
+static int format_uristring_setting ( const void *raw, size_t raw_len,
+				      char *buf, size_t len ) {
+	char tmp[ raw_len + 1 /* NUL */ ];
 
-	/* We need to always retrieve the full raw string to know the
-	 * length of the encoded string.
-	 */
-	raw_len = fetch_setting ( settings, setting, NULL, 0 );
-	if ( raw_len < 0 )
-		return raw_len;
-
-	{
-		char raw_buf[ raw_len + 1 ];
-       
-		fetch_string_setting ( settings, setting, raw_buf,
-				       sizeof ( raw_buf ) );
-		return uri_encode ( raw_buf, buf, len, URI_FRAGMENT );
-	}
+	/* Copy to temporary buffer and terminate */
+	memcpy ( tmp, raw, raw_len );
+	tmp[raw_len] = '\0';
+
+	/* Encode directly into output buffer */
+	return uri_encode ( tmp, buf, len, URI_FRAGMENT );
 }
 
 /** A URI-encoded string setting type */
 struct setting_type setting_type_uristring __setting_type = {
 	.name = "uristring",
-	.storef = storef_uristring,
-	.fetchf = fetchf_uristring,
+	.parse = parse_uristring_setting,
+	.format = format_uristring_setting,
 };
 
 /**
- * Parse and store value of IPv4 address setting
+ * Parse IPv4 address setting value
  *
- * @v settings		Settings block
- * @v setting		Setting to store
- * @v value		Formatted setting data
- * @ret rc		Return status code
+ * @v value		Formatted setting value
+ * @v buf		Buffer to contain raw value
+ * @v len		Length of buffer
+ * @ret len		Length of raw value, or negative error
  */
-static int storef_ipv4 ( struct settings *settings, struct setting *setting,
-			 const char *value ) {
+static int parse_ipv4_setting ( const char *value, void *buf, size_t len ) {
 	struct in_addr ipv4;
 
+	/* Parse IPv4 address */
 	if ( inet_aton ( value, &ipv4 ) == 0 )
 		return -EINVAL;
-	return store_setting ( settings, setting, &ipv4, sizeof ( ipv4 ) );
+
+	/* Copy to buffer */
+	if ( len > sizeof ( ipv4 ) )
+		len = sizeof ( ipv4 );
+	memcpy ( buf, &ipv4, len );
+
+	return ( sizeof ( ipv4 ) );
 }
 
 /**
- * Fetch and format value of IPv4 address setting
+ * Format IPv4 address setting value
  *
- * @v settings		Settings block, or NULL to search all blocks
- * @v setting		Setting to fetch
+ * @v raw		Raw setting value
+ * @v raw_len		Length of raw setting value
  * @v buf		Buffer to contain formatted value
  * @v len		Length of buffer
  * @ret len		Length of formatted value, or negative error
  */
-static int fetchf_ipv4 ( struct settings *settings, struct setting *setting,
-			 char *buf, size_t len ) {
-	struct in_addr ipv4;
-	int raw_len;
+static int format_ipv4_setting ( const void *raw, size_t raw_len, char *buf,
+				 size_t len ) {
+	const struct in_addr *ipv4 = raw;
 
-	if ( ( raw_len = fetch_ipv4_setting ( settings, setting, &ipv4 ) ) < 0)
-		return raw_len;
-	return snprintf ( buf, len, "%s", inet_ntoa ( ipv4 ) );
+	if ( raw_len < sizeof ( *ipv4 ) )
+		return -EINVAL;
+	return snprintf ( buf, len, "%s", inet_ntoa ( *ipv4 ) );
 }
 
 /** An IPv4 address setting type */
 struct setting_type setting_type_ipv4 __setting_type = {
 	.name = "ipv4",
-	.storef = storef_ipv4,
-	.fetchf = fetchf_ipv4,
+	.parse = parse_ipv4_setting,
+	.format = format_ipv4_setting,
 };
 
 /**
- * Parse and store value of integer setting
+ * Parse integer setting value
  *
- * @v settings		Settings block
- * @v setting		Setting to store
- * @v value		Formatted setting data
+ * @v value		Formatted setting value
+ * @v buf		Buffer to contain raw value
+ * @v len		Length of buffer
  * @v size		Integer size, in bytes
- * @ret rc		Return status code
+ * @ret len		Length of raw value, or negative error
  */
-static int storef_int ( struct settings *settings, struct setting *setting,
-			const char *value, unsigned int size ) {
+static int parse_int_setting ( const char *value, void *buf, size_t len,
+			       unsigned int size ) {
 	union {
 		uint32_t num;
 		uint8_t bytes[4];
 	} u;
 	char *endp;
 
+	/* Parse value */
 	u.num = htonl ( strtoul ( value, &endp, 0 ) );
 	if ( *endp )
 		return -EINVAL;
-	return store_setting ( settings, setting, 
-			       &u.bytes[ sizeof ( u ) - size ], size );
+
+	/* Copy to buffer */
+	if ( len > size )
+		len = size;
+	memcpy ( buf, &u.bytes[ sizeof ( u ) - size ], len );
+
+	return size;
 }
 
 /**
- * Parse and store value of 8-bit integer setting
+ * Parse 8-bit integer setting value
  *
- * @v settings		Settings block
- * @v setting		Setting to store
- * @v value		Formatted setting data
+ * @v value		Formatted setting value
+ * @v buf		Buffer to contain raw value
+ * @v len		Length of buffer
  * @v size		Integer size, in bytes
- * @ret rc		Return status code
+ * @ret len		Length of raw value, or negative error
  */
-static int storef_int8 ( struct settings *settings, struct setting *setting,
-			 const char *value ) {
-	return storef_int ( settings, setting, value, 1 );
+static int parse_int8_setting ( const char *value, void *buf, size_t len ) {
+	return parse_int_setting ( value, buf, len, sizeof ( uint8_t ) );
 }
 
 /**
- * Parse and store value of 16-bit integer setting
+ * Parse 16-bit integer setting value
  *
- * @v settings		Settings block
- * @v setting		Setting to store
- * @v value		Formatted setting data
+ * @v value		Formatted setting value
+ * @v buf		Buffer to contain raw value
+ * @v len		Length of buffer
  * @v size		Integer size, in bytes
- * @ret rc		Return status code
+ * @ret len		Length of raw value, or negative error
  */
-static int storef_int16 ( struct settings *settings, struct setting *setting,
-			  const char *value ) {
-	return storef_int ( settings, setting, value, 2 );
+static int parse_int16_setting ( const char *value, void *buf, size_t len ) {
+	return parse_int_setting ( value, buf, len, sizeof ( uint16_t ) );
 }
 
 /**
- * Parse and store value of 32-bit integer setting
+ * Parse 32-bit integer setting value
  *
- * @v settings		Settings block
- * @v setting		Setting to store
- * @v value		Formatted setting data
+ * @v value		Formatted setting value
+ * @v buf		Buffer to contain raw value
+ * @v len		Length of buffer
  * @v size		Integer size, in bytes
- * @ret rc		Return status code
+ * @ret len		Length of raw value, or negative error
  */
-static int storef_int32 ( struct settings *settings, struct setting *setting,
-			  const char *value ) {
-	return storef_int ( settings, setting, value, 4 );
+static int parse_int32_setting ( const char *value, void *buf, size_t len ) {
+	return parse_int_setting ( value, buf, len, sizeof ( uint32_t ) );
 }
 
 /**
- * Fetch and format value of signed integer setting
+ * Format signed integer setting value
  *
- * @v settings		Settings block, or NULL to search all blocks
- * @v setting		Setting to fetch
+ * @v raw		Raw setting value
+ * @v raw_len		Length of raw setting value
  * @v buf		Buffer to contain formatted value
  * @v len		Length of buffer
  * @ret len		Length of formatted value, or negative error
  */
-static int fetchf_int ( struct settings *settings, struct setting *setting,
-			char *buf, size_t len ) {
-	long value;
-	int rc;
+static int format_int_setting ( const void *raw, size_t raw_len, char *buf,
+				size_t len ) {
+	signed long value;
+	unsigned long dummy;
+	int check_len;
 
-	if ( ( rc = fetch_int_setting ( settings, setting, &value ) ) < 0 )
-		return rc;
+	/* Extract numeric value */
+	check_len = numeric_setting_value ( raw, raw_len, &value, &dummy );
+	if ( check_len < 0 )
+		return check_len;
+	assert ( check_len == ( int ) raw_len );
+
+	/* Format value */
 	return snprintf ( buf, len, "%ld", value );
 }
 
 /**
- * Fetch and format value of unsigned integer setting
+ * Format unsigned integer setting value
  *
- * @v settings		Settings block, or NULL to search all blocks
- * @v setting		Setting to fetch
+ * @v raw		Raw setting value
+ * @v raw_len		Length of raw setting value
  * @v buf		Buffer to contain formatted value
  * @v len		Length of buffer
  * @ret len		Length of formatted value, or negative error
  */
-static int fetchf_uint ( struct settings *settings, struct setting *setting,
-			 char *buf, size_t len ) {
+static int format_uint_setting ( const void *raw, size_t raw_len, char *buf,
+				 size_t len ) {
+	signed long dummy;
 	unsigned long value;
-	int rc;
+	int check_len;
 
-	if ( ( rc = fetch_uint_setting ( settings, setting, &value ) ) < 0 )
-		return rc;
+	/* Extract numeric value */
+	check_len = numeric_setting_value ( raw, raw_len, &dummy, &value );
+	if ( check_len < 0 )
+		return check_len;
+	assert ( check_len == ( int ) raw_len );
+
+	/* Format value */
 	return snprintf ( buf, len, "%#lx", value );
 }
 
 /** A signed 8-bit integer setting type */
 struct setting_type setting_type_int8 __setting_type = {
 	.name = "int8",
-	.storef = storef_int8,
-	.fetchf = fetchf_int,
+	.parse = parse_int8_setting,
+	.format = format_int_setting,
 };
 
 /** A signed 16-bit integer setting type */
 struct setting_type setting_type_int16 __setting_type = {
 	.name = "int16",
-	.storef = storef_int16,
-	.fetchf = fetchf_int,
+	.parse = parse_int16_setting,
+	.format = format_int_setting,
 };
 
 /** A signed 32-bit integer setting type */
 struct setting_type setting_type_int32 __setting_type = {
 	.name = "int32",
-	.storef = storef_int32,
-	.fetchf = fetchf_int,
+	.parse = parse_int32_setting,
+	.format = format_int_setting,
 };
 
 /** An unsigned 8-bit integer setting type */
 struct setting_type setting_type_uint8 __setting_type = {
 	.name = "uint8",
-	.storef = storef_int8,
-	.fetchf = fetchf_uint,
+	.parse = parse_int8_setting,
+	.format = format_uint_setting,
 };
 
 /** An unsigned 16-bit integer setting type */
 struct setting_type setting_type_uint16 __setting_type = {
 	.name = "uint16",
-	.storef = storef_int16,
-	.fetchf = fetchf_uint,
+	.parse = parse_int16_setting,
+	.format = format_uint_setting,
 };
 
 /** An unsigned 32-bit integer setting type */
 struct setting_type setting_type_uint32 __setting_type = {
 	.name = "uint32",
-	.storef = storef_int32,
-	.fetchf = fetchf_uint,
+	.parse = parse_int32_setting,
+	.format = format_uint_setting,
 };
 
 /**
- * Parse and store value of hex string setting
+ * Parse hex string setting value
  *
- * @v settings		Settings block
- * @v setting		Setting to store
- * @v value		Formatted setting data
- * @ret rc		Return status code
+ * @v value		Formatted setting value
+ * @v buf		Buffer to contain raw value
+ * @v len		Length of buffer
+ * @ret len		Length of raw value, or negative error
  */
-static int storef_hex ( struct settings *settings, struct setting *setting,
-			const char *value ) {
+static int parse_hex_setting ( const char *value, void *buf, size_t len ) {
 	char *ptr = ( char * ) value;
-	uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */
-	unsigned int len = 0;
+	uint8_t *bytes = buf;
+	unsigned int count = 0;
+	uint8_t byte;
 
 	while ( 1 ) {
-		bytes[len++] = strtoul ( ptr, &ptr, 16 );
+		byte = strtoul ( ptr, &ptr, 16 );
+		if ( count++ < len )
+			*bytes++ = byte;
 		switch ( *ptr ) {
 		case '\0' :
-			return store_setting ( settings, setting, bytes, len );
+			return count;
 		case ':' :
 		case '-' :
 			ptr++;
@@ -1483,128 +1718,112 @@ static int storef_hex ( struct settings *settings, struct setting *setting,
 }
 
 /**
- * Fetch and format value of hex string setting
+ * Format hex string setting value
  *
- * @v settings		Settings block, or NULL to search all blocks
- * @v setting		Setting to fetch
+ * @v raw		Raw setting value
+ * @v raw_len		Length of raw setting value
  * @v buf		Buffer to contain formatted value
  * @v len		Length of buffer
  * @v delimiter		Byte delimiter
  * @ret len		Length of formatted value, or negative error
  */
-static int fetchf_hex ( struct settings *settings, struct setting *setting,
-			char *buf, size_t len, const char *delimiter ) {
-	int raw_len;
-	int check_len;
+static int format_hex_setting ( const void *raw, size_t raw_len, char *buf,
+				size_t len, const char *delimiter ) {
+	const uint8_t *bytes = raw;
 	int used = 0;
-	int i;
-
-	raw_len = fetch_setting_len ( settings, setting );
-	if ( raw_len < 0 )
-		return raw_len;
-
-	{
-		uint8_t raw[raw_len];
-
-		check_len = fetch_setting ( settings, setting, raw,
-					    sizeof ( raw ) );
-		if ( check_len < 0 )
-			return check_len;
-		assert ( check_len == raw_len );
-		
-		if ( len )
-			buf[0] = 0; /* Ensure that a terminating NUL exists */
-		for ( i = 0 ; i < raw_len ; i++ ) {
-			used += ssnprintf ( ( buf + used ), ( len - used ),
-					    "%s%02x", ( used ? delimiter : "" ),
-					    raw[i] );
-		}
-		return used;
+	unsigned int i;
+
+	if ( len )
+		buf[0] = 0; /* Ensure that a terminating NUL exists */
+	for ( i = 0 ; i < raw_len ; i++ ) {
+		used += ssnprintf ( ( buf + used ), ( len - used ),
+				    "%s%02x", ( used ? delimiter : "" ),
+				    bytes[i] );
 	}
+	return used;
 }
 
 /**
- * Fetch and format value of hex string setting (using colon delimiter)
+ * Format hex string setting value (using colon delimiter)
  *
- * @v settings		Settings block, or NULL to search all blocks
- * @v setting		Setting to fetch
+ * @v raw		Raw setting value
+ * @v raw_len		Length of raw setting value
  * @v buf		Buffer to contain formatted value
  * @v len		Length of buffer
  * @ret len		Length of formatted value, or negative error
  */
-static int fetchf_hex_colon ( struct settings *settings,
-			      struct setting *setting,
-			      char *buf, size_t len ) {
-	return fetchf_hex ( settings, setting, buf, len, ":" );
+static int format_hex_colon_setting ( const void *raw, size_t raw_len,
+				      char *buf, size_t len ) {
+	return format_hex_setting ( raw, raw_len, buf, len, ":" );
 }
 
 /**
- * Fetch and format value of hex string setting (using hyphen delimiter)
+ * Format hex string setting value (using hyphen delimiter)
  *
- * @v settings		Settings block, or NULL to search all blocks
- * @v setting		Setting to fetch
+ * @v raw		Raw setting value
+ * @v raw_len		Length of raw setting value
  * @v buf		Buffer to contain formatted value
  * @v len		Length of buffer
  * @ret len		Length of formatted value, or negative error
  */
-static int fetchf_hex_hyphen ( struct settings *settings,
-			       struct setting *setting,
-			       char *buf, size_t len ) {
-	return fetchf_hex ( settings, setting, buf, len, "-" );
+static int format_hex_hyphen_setting ( const void *raw, size_t raw_len,
+				       char *buf, size_t len ) {
+	return format_hex_setting ( raw, raw_len, buf, len, "-" );
 }
 
 /** A hex-string setting (colon-delimited) */
 struct setting_type setting_type_hex __setting_type = {
 	.name = "hex",
-	.storef = storef_hex,
-	.fetchf = fetchf_hex_colon,
+	.parse = parse_hex_setting,
+	.format = format_hex_colon_setting,
 };
 
 /** A hex-string setting (hyphen-delimited) */
 struct setting_type setting_type_hexhyp __setting_type = {
 	.name = "hexhyp",
-	.storef = storef_hex,
-	.fetchf = fetchf_hex_hyphen,
+	.parse = parse_hex_setting,
+	.format = format_hex_hyphen_setting,
 };
 
 /**
- * Parse and store value of UUID setting
+ * Parse UUID setting value
  *
- * @v settings		Settings block
- * @v setting		Setting to store
- * @v value		Formatted setting data
- * @ret rc		Return status code
+ * @v value		Formatted setting value
+ * @v buf		Buffer to contain raw value
+ * @v len		Length of buffer
+ * @ret len		Length of raw value, or negative error
  */
-static int storef_uuid ( struct settings *settings __unused,
-			 struct setting *setting __unused,
-			 const char *value __unused ) {
+static int parse_uuid_setting ( const char *value __unused,
+				void *buf __unused, size_t len __unused ) {
 	return -ENOTSUP;
 }
 
 /**
- * Fetch and format value of UUID setting
+ * Format UUID setting value
  *
- * @v settings		Settings block, or NULL to search all blocks
- * @v setting		Setting to fetch
+ * @v raw		Raw setting value
+ * @v raw_len		Length of raw setting value
  * @v buf		Buffer to contain formatted value
  * @v len		Length of buffer
  * @ret len		Length of formatted value, or negative error
  */
-static int fetchf_uuid ( struct settings *settings, struct setting *setting,
-			 char *buf, size_t len ) {
-	union uuid uuid;
-	int raw_len;
+static int format_uuid_setting ( const void *raw, size_t raw_len, char *buf,
+				 size_t len ) {
+	const union uuid *uuid = raw;
+
+	/* Range check */
+	if ( raw_len != sizeof ( *uuid ) )
+		return -ERANGE;
 
-	if ( ( raw_len = fetch_uuid_setting ( settings, setting, &uuid ) ) < 0)
-		return raw_len;
-	return snprintf ( buf, len, "%s", uuid_ntoa ( &uuid ) );
+	/* Format value */
+	return snprintf ( buf, len, "%s", uuid_ntoa ( uuid ) );
 }
 
 /** UUID setting type */
 struct setting_type setting_type_uuid __setting_type = {
 	.name = "uuid",
-	.storef = storef_uuid,
-	.fetchf = fetchf_uuid,
+	.parse = parse_uuid_setting,
+	.format = format_uuid_setting,
 };
 
 /******************************************************************************
@@ -1703,6 +1922,22 @@ struct setting hostname_setting __setting ( SETTING_HOST ) = {
 	.type = &setting_type_string,
 };
 
+/** Domain name setting */
+struct setting domain_setting __setting ( SETTING_IPv4_EXTRA ) = {
+	.name = "domain",
+	.description = "DNS domain",
+	.tag = DHCP_DOMAIN_NAME,
+	.type = &setting_type_string,
+};
+
+/** TFTP server setting */
+struct setting next_server_setting __setting ( SETTING_BOOT ) = {
+	.name = "next-server",
+	.description = "TFTP server",
+	.tag = DHCP_EB_SIADDR,
+	.type = &setting_type_ipv4,
+};
+
 /** Filename setting */
 struct setting filename_setting __setting ( SETTING_BOOT ) = {
 	.name = "filename",
@@ -1742,3 +1977,122 @@ struct setting priority_setting __setting ( SETTING_MISC ) = {
 	.tag = DHCP_EB_PRIORITY,
 	.type = &setting_type_int8,
 };
+
+/******************************************************************************
+ *
+ * Built-in settings block
+ *
+ ******************************************************************************
+ */
+
+/** Built-in setting tag magic */
+#define BUILTIN_SETTING_TAG_MAGIC 0xb1
+
+/**
+ * Construct built-in setting tag
+ *
+ * @v id		Unique identifier
+ * @ret tag		Setting tag
+ */
+#define BUILTIN_SETTING_TAG( id ) ( ( BUILTIN_SETTING_TAG_MAGIC << 24 ) | (id) )
+
+/** "errno" setting tag */
+#define BUILTIN_SETTING_TAG_ERRNO BUILTIN_SETTING_TAG ( 0x01 )
+
+/** Error number setting */
+struct setting errno_setting __setting ( SETTING_MISC ) = {
+	.name = "errno",
+	.description = "Last error",
+	.tag = BUILTIN_SETTING_TAG_ERRNO,
+	.type = &setting_type_uint32,
+};
+
+/**
+ * Fetch error number setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to fetch
+ * @v data		Setting data, or NULL to clear setting
+ * @v len		Length of setting data
+ * @ret rc		Return status code
+ */
+static int errno_fetch ( struct settings *settings __unused,
+			 struct setting *setting __unused,
+			 void *data, size_t len ) {
+	uint32_t content;
+
+	/* Return current error */
+	content = htonl ( errno );
+	if ( len > sizeof ( content ) )
+		len = sizeof ( content );
+	memcpy ( data, &content, len );
+	return sizeof ( content );
+}
+
+/**
+ * Fetch built-in setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting to fetch
+ * @v data		Setting data, or NULL to clear setting
+ * @v len		Length of setting data
+ * @ret rc		Return status code
+ */
+static int builtin_fetch ( struct settings *settings __unused,
+			   struct setting *setting,
+			   void *data, size_t len ) {
+
+	if ( setting_cmp ( setting, &errno_setting ) == 0 ) {
+		return errno_fetch ( settings, setting, data, len );
+	} else {
+		return -ENOENT;
+	}
+}
+
+/**
+ * Check applicability of built-in setting
+ *
+ * @v settings		Settings block
+ * @v setting		Setting
+ * @ret applies		Setting applies within this settings block
+ */
+static int builtin_applies ( struct settings *settings __unused,
+			     struct setting *setting ) {
+	unsigned int tag_magic;
+
+	/* Check tag magic */
+	tag_magic = ( setting->tag >> 24 );
+	return ( tag_magic == BUILTIN_SETTING_TAG_MAGIC );
+}
+
+/** Built-in settings operations */
+static struct settings_operations builtin_settings_operations = {
+	.applies = builtin_applies,
+	.fetch = builtin_fetch,
+};
+
+/** Built-in settings */
+static struct settings builtin_settings = {
+	.refcnt = NULL,
+	.tag_magic = BUILTIN_SETTING_TAG ( 0 ),
+	.siblings = LIST_HEAD_INIT ( builtin_settings.siblings ),
+	.children = LIST_HEAD_INIT ( builtin_settings.children ),
+	.op = &builtin_settings_operations,
+};
+
+/** Initialise built-in settings */
+static void builtin_init ( void ) {
+	int rc;
+
+	if ( ( rc = register_settings ( &builtin_settings, NULL,
+					"builtin" ) ) != 0 ) {
+		DBG ( "Could not register built-in settings: %s\n",
+		      strerror ( rc ) );
+		return;
+	}
+}
+
+/** Built-in settings initialiser */
+struct init_fn builtin_init_fn __init_fn ( INIT_NORMAL ) = {
+	.initialise = builtin_init,
+};
diff --git a/roms/ipxe/src/core/strtoull.c b/roms/ipxe/src/core/strtoull.c
index b1ceeb45b0ecd9c144c2f47a8399..00986eef0ef9470d8049b51660b6 100644
--- a/roms/ipxe/src/core/strtoull.c
+++ b/roms/ipxe/src/core/strtoull.c
@@ -29,8 +29,17 @@ FILE_LICENCE ( GPL2_OR_LATER );
  */
 unsigned long long strtoull ( const char *p, char **endp, int base ) {
 	unsigned long long ret = 0;
+	int negative = 0;
 	unsigned int charval;
 
+	while ( isspace ( *p ) )
+		p++;
+
+	if ( *p == '-' ) {
+		negative = 1;
+		p++;
+	}
+
 	base = strtoul_base ( &p, base );
 
 	while ( 1 ) {
@@ -41,6 +50,9 @@ unsigned long long strtoull ( const char *p, char **endp, int base ) {
 		p++;
 	}
 
+	if ( negative )
+		ret = -ret;
+
 	if ( endp )
 		*endp = ( char * ) p;
 
diff --git a/roms/ipxe/src/core/time.c b/roms/ipxe/src/core/time.c
new file mode 100644
index 0000000000000000000000000000000000000000..f70e1981dfc108c13aab3c70af625b31918b16d4
--- /dev/null
+++ b/roms/ipxe/src/core/time.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <time.h>
+
+/** @file
+ *
+ * Date and time
+ *
+ * POSIX:2008 section 4.15 defines "seconds since the Epoch" as an
+ * abstract measure approximating the number of seconds that have
+ * elapsed since the Epoch, excluding leap seconds.  The formula given
+ * is
+ *
+ *    tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
+ *    (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
+ *    ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
+ *
+ * This calculation assumes that leap years occur in each year that is
+ * either divisible by 4 but not divisible by 100, or is divisible by
+ * 400.
+ */
+
+/** Days of week (for debugging) */
+static const char *weekdays[] = {
+	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+
+/**
+ * Determine whether or not year is a leap year
+ *
+ * @v tm_year		Years since 1900
+ * @v is_leap_year	Year is a leap year
+ */
+static int is_leap_year ( int tm_year ) {
+	int leap_year = 0;
+
+	if ( ( tm_year % 4 ) == 0 )
+		leap_year = 1;
+	if ( ( tm_year % 100 ) == 0 )
+		leap_year = 0;
+	if ( ( tm_year % 400 ) == 100 )
+		leap_year = 1;
+
+	return leap_year;
+}
+
+/**
+ * Calculate number of leap years since 1900
+ *
+ * @v tm_year		Years since 1900
+ * @v num_leap_years	Number of leap years
+ */
+static int leap_years_to_end ( int tm_year ) {
+	int leap_years = 0;
+
+	leap_years += ( tm_year / 4 );
+	leap_years -= ( tm_year / 100 );
+	leap_years += ( ( tm_year + 300 ) / 400 );
+
+	return leap_years;
+}
+
+/**
+ * Calculate day of week
+ *
+ * @v tm_year		Years since 1900
+ * @v tm_mon		Month of year [0,11]
+ * @v tm_day		Day of month [1,31]
+ */
+static int day_of_week ( int tm_year, int tm_mon, int tm_mday ) {
+	static const uint8_t offset[12] =
+		{ 1, 4, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 };
+	int pseudo_year = tm_year;
+
+	if ( tm_mon < 2 )
+		pseudo_year--;
+	return ( ( pseudo_year + leap_years_to_end ( pseudo_year ) +
+		   offset[tm_mon] + tm_mday ) % 7 );
+}
+
+/** Days from start of year until start of months (in non-leap years) */
+static const uint16_t days_to_month_start[] =
+	{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+
+/**
+ * Calculate seconds since the Epoch
+ *
+ * @v tm		Broken-down time
+ * @ret time		Seconds since the Epoch
+ */
+time_t mktime ( struct tm *tm ) {
+	int days_since_epoch;
+	int seconds_since_day;
+	time_t seconds;
+
+	/* Calculate day of year */
+	tm->tm_yday = ( ( tm->tm_mday - 1 ) +
+			days_to_month_start[ tm->tm_mon ] );
+	if ( ( tm->tm_mon >= 2 ) && is_leap_year ( tm->tm_year ) )
+		tm->tm_yday++;
+
+	/* Calculate day of week */
+	tm->tm_wday = day_of_week ( tm->tm_year, tm->tm_mon, tm->tm_mday );
+
+	/* Calculate seconds since the Epoch */
+	days_since_epoch = ( tm->tm_yday + ( 365 * tm->tm_year ) - 25567 +
+			     leap_years_to_end ( tm->tm_year - 1 ) );
+	seconds_since_day =
+		( ( ( ( tm->tm_hour * 60 ) + tm->tm_min ) * 60 ) + tm->tm_sec );
+	seconds = ( ( ( ( time_t ) days_since_epoch ) * ( ( time_t ) 86400 ) ) +
+		    seconds_since_day );
+
+	DBGC ( &weekdays, "TIME %04d-%02d-%02d %02d:%02d:%02d => %lld (%s, "
+	       "day %d)\n", ( tm->tm_year + 1900 ), ( tm->tm_mon + 1 ),
+	       tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, seconds,
+	       weekdays[ tm->tm_wday ], tm->tm_yday );
+
+	return seconds;
+}
diff --git a/roms/ipxe/src/core/timer.c b/roms/ipxe/src/core/timer.c
index 096d07ec0e0efdce0bdfe29b9313..18c2b28493ac2eec9a61e7b5e3f4 100644
--- a/roms/ipxe/src/core/timer.c
+++ b/roms/ipxe/src/core/timer.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/uri.c b/roms/ipxe/src/core/uri.c
index ff49e47a534b421b6ea6e0421095..e952688262f78304c6ea4af7c25b 100644
--- a/roms/ipxe/src/core/uri.c
+++ b/roms/ipxe/src/core/uri.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/core/uuid.c b/roms/ipxe/src/core/uuid.c
index d98553f0fe9b7ff69d5b58b34926..27a249da8ba40015e40e75c69721 100644
--- a/roms/ipxe/src/core/uuid.c
+++ b/roms/ipxe/src/core/uuid.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -35,7 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
  * @v uuid		UUID
  * @ret string		UUID in canonical form
  */
-char * uuid_ntoa ( union uuid *uuid ) {
+char * uuid_ntoa ( const union uuid *uuid ) {
 	static char buf[37]; /* "00000000-0000-0000-0000-000000000000" */
 
 	sprintf ( buf, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
diff --git a/roms/ipxe/src/core/version.c b/roms/ipxe/src/core/version.c
new file mode 100644
index 0000000000000000000000000000000000000000..1aa22d8ecf0c266699baa00d5782355f0a51272b
--- /dev/null
+++ b/roms/ipxe/src/core/version.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Version number
+ *
+ */
+
+#include <ipxe/features.h>
+#include <ipxe/version.h>
+
+/** Version number feature */
+FEATURE_VERSION ( VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH );
+
+/** Product major version */
+const int product_major_version = VERSION_MAJOR;
+
+/** Product minor version */
+const int product_minor_version = VERSION_MINOR;
+
+/** Product version string */
+const char *product_version = VERSION;
diff --git a/roms/ipxe/src/core/vsprintf.c b/roms/ipxe/src/core/vsprintf.c
index b46d9c4191711cf11722e863c3df..5cc7231087091eb3d759b84dc5e8 100644
--- a/roms/ipxe/src/core/vsprintf.c
+++ b/roms/ipxe/src/core/vsprintf.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -21,8 +22,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <stddef.h>
 #include <stdarg.h>
 #include <stdio.h>
-#include <ipxe/console.h>
 #include <errno.h>
+#include <wchar.h>
 #include <ipxe/vsprintf.h>
 
 /** @file */
@@ -60,12 +61,21 @@ static uint8_t type_sizes[] = {
  */
 #define ALT_FORM 0x02
 
+/**
+ * Use zero padding
+ *
+ * Note that this value is set to 0x10 since that allows the pad
+ * character to be calculated as @c 0x20|(flags&ZPAD)
+ */
+#define ZPAD 0x10
+
 /**
  * Format a hexadecimal number
  *
  * @v end		End of buffer to contain number
  * @v num		Number to format
  * @v width		Minimum field width
+ * @v flags		Format flags
  * @ret ptr		End of buffer
  *
  * Fills a buffer in reverse order with a formatted hexadecimal
@@ -79,18 +89,18 @@ static uint8_t type_sizes[] = {
 static char * format_hex ( char *end, unsigned long long num, int width,
 			   int flags ) {
 	char *ptr = end;
-	int case_mod;
+	int case_mod = ( flags & LCASE );
+	int pad = ( ( flags & ZPAD ) | ' ' );
 
 	/* Generate the number */
-	case_mod = flags & LCASE;
 	do {
 		*(--ptr) = "0123456789ABCDEF"[ num & 0xf ] | case_mod;
 		num >>= 4;
 	} while ( num );
 
-	/* Zero-pad to width */
+	/* Pad to width */
 	while ( ( end - ptr ) < width )
-		*(--ptr) = '0';
+		*(--ptr) = pad;
 
 	/* Add "0x" or "0X" if alternate form specified */
 	if ( flags & ALT_FORM ) {
@@ -107,6 +117,7 @@ static char * format_hex ( char *end, unsigned long long num, int width,
  * @v end		End of buffer to contain number
  * @v num		Number to format
  * @v width		Minimum field width
+ * @v flags		Format flags
  * @ret ptr		End of buffer
  *
  * Fills a buffer in reverse order with a formatted decimal number.
@@ -115,9 +126,12 @@ static char * format_hex ( char *end, unsigned long long num, int width,
  * There must be enough space in the buffer to contain the largest
  * number that this function can format.
  */
-static char * format_decimal ( char *end, signed long num, int width ) {
+static char * format_decimal ( char *end, signed long num, int width,
+			       int flags ) {
 	char *ptr = end;
 	int negative = 0;
+	int zpad = ( flags & ZPAD );
+	int pad = ( zpad | ' ' );
 
 	/* Generate the number */
 	if ( num < 0 ) {
@@ -130,12 +144,16 @@ static char * format_decimal ( char *end, signed long num, int width ) {
 	} while ( num );
 
 	/* Add "-" if necessary */
-	if ( negative )
+	if ( negative && ( ! zpad ) )
 		*(--ptr) = '-';
 
-	/* Space-pad to width */
+	/* Pad to width */
 	while ( ( end - ptr ) < width )
-		*(--ptr) = ' ';
+		*(--ptr) = pad;
+
+	/* Add "-" if necessary */
+	if ( negative && zpad )
+		*ptr = '-';
 
 	return ptr;
 }
@@ -169,6 +187,7 @@ size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
 	char *ptr;
 	char tmp_buf[32]; /* 32 is enough for all numerical formats.
 			   * Insane width fields could overflow this buffer. */
+	wchar_t *wptr;
 
 	/* Initialise context */
 	ctx->len = 0;
@@ -186,7 +205,7 @@ size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
 			if ( *fmt == '#' ) {
 				flags |= ALT_FORM;
 			} else if ( *fmt == '0' ) {
-				/* We always 0-pad hex and space-pad decimal */
+				flags |= ZPAD;
 			} else {
 				/* End of flag characters */
 				break;
@@ -218,11 +237,26 @@ size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
 		/* Process conversion specifier */
 		ptr = tmp_buf + sizeof ( tmp_buf ) - 1;
 		*ptr = '\0';
+		wptr = NULL;
 		if ( *fmt == 'c' ) {
-			cputchar ( ctx, va_arg ( args, unsigned int ) );
+			if ( length < &type_sizes[LONG_LEN] ) {
+				cputchar ( ctx, va_arg ( args, unsigned int ) );
+			} else {
+				wchar_t wc;
+				size_t len;
+
+				wc = va_arg ( args, wint_t );
+				len = wcrtomb ( tmp_buf, wc, NULL );
+				tmp_buf[len] = '\0';
+				ptr = tmp_buf;
+			}
 		} else if ( *fmt == 's' ) {
-			ptr = va_arg ( args, char * );
-			if ( ! ptr )
+			if ( length < &type_sizes[LONG_LEN] ) {
+				ptr = va_arg ( args, char * );
+			} else {
+				wptr = va_arg ( args, wchar_t * );
+			}
+			if ( ( ptr == NULL ) && ( wptr == NULL ) )
 				ptr = "<NULL>";
 		} else if ( *fmt == 'p' ) {
 			intptr_t ptrval;
@@ -250,13 +284,22 @@ size_t vcprintf ( struct printf_context *ctx, const char *fmt, va_list args ) {
 			} else {
 				decimal = va_arg ( args, signed int );
 			}
-			ptr = format_decimal ( ptr, decimal, width );
+			ptr = format_decimal ( ptr, decimal, width, flags );
 		} else {
 			*(--ptr) = *fmt;
 		}
 		/* Write out conversion result */
-		for ( ; *ptr ; ptr++ ) {
-			cputchar ( ctx, *ptr );
+		if ( wptr == NULL ) {
+			for ( ; *ptr ; ptr++ ) {
+				cputchar ( ctx, *ptr );
+			}
+		} else {
+			for ( ; *wptr ; wptr++ ) {
+				size_t len = wcrtomb ( tmp_buf, *wptr, NULL );
+				for ( ptr = tmp_buf ; len-- ; ptr++ ) {
+					cputchar ( ctx, *ptr );
+				}
+			}
 		}
 	}
 
diff --git a/roms/ipxe/src/core/wchar.c b/roms/ipxe/src/core/wchar.c
new file mode 100644
index 0000000000000000000000000000000000000000..7fabca470091b0b70ef6c1666c5a4bec1835b35d
--- /dev/null
+++ b/roms/ipxe/src/core/wchar.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Wide-character strings
+ *
+ */
+
+#include <wchar.h>
+
+/**
+ * Calculate length of wide-character string
+ *
+ * @v string		String
+ * @ret len		Length (excluding terminating NUL)
+ */
+size_t wcslen ( const wchar_t *string ) {
+	size_t len = 0;
+
+	while ( *(string++) )
+		len++;
+	return len;
+}
diff --git a/roms/ipxe/src/core/xfer.c b/roms/ipxe/src/core/xfer.c
index a755d438a350b8f6a0849d209948..8d4bc9f53e1852cae7d571be8051 100644
--- a/roms/ipxe/src/core/xfer.c
+++ b/roms/ipxe/src/core/xfer.c
@@ -13,12 +13,14 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <string.h>
+#include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
 #include <ipxe/iobuf.h>
@@ -54,6 +56,7 @@ static struct xfer_metadata dummy_metadata;
  * @ret rc		Return status code
  */
 int xfer_vredirect ( struct interface *intf, int type, va_list args ) {
+	struct interface tmp = INTF_INIT ( null_intf_desc );
 	struct interface *dest;
 	xfer_vredirect_TYPE ( void * ) *op =
 		intf_get_dest_op_no_passthru ( intf, xfer_vredirect, &dest );
@@ -66,8 +69,22 @@ int xfer_vredirect ( struct interface *intf, int type, va_list args ) {
 	if ( op ) {
 		rc = op ( object, type, args );
 	} else {
-		/* Default is to reopen the interface as instructed */
+		/* Default is to reopen the interface as instructed,
+		 * then send xfer_window_changed() messages to both
+		 * new child and parent interfaces.  Since our
+		 * original child interface is likely to be closed and
+		 * unplugged as a result of the call to
+		 * xfer_vreopen(), we create a temporary interface in
+		 * order to be able to send xfer_window_changed() to
+		 * the parent.
+		 */
+		intf_plug ( &tmp, dest );
 		rc = xfer_vreopen ( dest, type, args );
+		if ( rc == 0 ) {
+			xfer_window_changed ( dest );
+			xfer_window_changed ( &tmp );
+		}
+		intf_unplug ( &tmp );
 	}
 
 	if ( rc != 0 ) {
@@ -282,17 +299,28 @@ int xfer_deliver_raw ( struct interface *intf, const void *data, size_t len ) {
  */
 int xfer_vprintf ( struct interface *intf, const char *format,
 		   va_list args ) {
-	size_t len;
 	va_list args_tmp;
+	char *buf;
+	int len;
+	int rc;
 
+	/* Create temporary string */
 	va_copy ( args_tmp, args );
-	len = vsnprintf ( NULL, 0, format, args );
-	{
-		char buf[len + 1];
-		vsnprintf ( buf, sizeof ( buf ), format, args_tmp );
-		va_end ( args_tmp );
-		return xfer_deliver_raw ( intf, buf, len );
+	len = vasprintf ( &buf, format, args );
+	if ( len < 0 ) {
+		rc = len;
+		goto err_asprintf;
 	}
+	va_end ( args_tmp );
+
+	/* Transmit string */
+	if ( ( rc = xfer_deliver_raw ( intf, buf, len ) ) != 0 )
+		goto err_deliver;
+
+ err_deliver:
+	free ( buf );
+ err_asprintf:
+	return rc;
 }
 
 /**
diff --git a/roms/ipxe/src/core/xferbuf.c b/roms/ipxe/src/core/xferbuf.c
new file mode 100644
index 0000000000000000000000000000000000000000..a0457feeec3172abcd9ec70b8cf60efd53ac0387
--- /dev/null
+++ b/roms/ipxe/src/core/xferbuf.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/xfer.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xferbuf.h>
+
+/** @file
+ *
+ * Data transfer buffer
+ *
+ */
+
+/**
+ * Finish using data transfer buffer
+ *
+ * @v xferbuf		Data transfer buffer
+ */
+void xferbuf_done ( struct xfer_buffer *xferbuf ) {
+	free ( xferbuf->data );
+	xferbuf->data = NULL;
+	xferbuf->len = 0;
+	xferbuf->pos = 0;
+}
+
+/**
+ * Ensure that data transfer buffer is large enough for the specified size
+ *
+ * @v xferbuf		Data transfer buffer
+ * @v len		Required minimum size
+ * @ret rc		Return status code
+ */
+static int xferbuf_ensure_size ( struct xfer_buffer *xferbuf, size_t len ) {
+	void *new_data;
+
+	/* If buffer is already large enough, do nothing */
+	if ( len <= xferbuf->len )
+		return 0;
+
+	/* Extend buffer */
+	new_data = realloc ( xferbuf->data, len );
+	if ( ! new_data ) {
+		DBGC ( xferbuf, "XFERBUF %p could not extend buffer to "
+		       "%zd bytes\n", xferbuf, len );
+		return -ENOSPC;
+	}
+	xferbuf->data = new_data;
+	xferbuf->len = len;
+
+	return 0;
+}
+
+/**
+ * Add received data to data transfer buffer
+ *
+ * @v xferbuf		Data transfer buffer
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+int xferbuf_deliver ( struct xfer_buffer *xferbuf, struct io_buffer *iobuf,
+		      struct xfer_metadata *meta ) {
+	size_t len;
+	size_t max;
+	int rc;
+
+	/* Calculate new buffer position */
+	if ( meta->flags & XFER_FL_ABS_OFFSET )
+		xferbuf->pos = 0;
+	xferbuf->pos += meta->offset;
+
+	/* Ensure that we have enough buffer space for this data */
+	len = iob_len ( iobuf );
+	max = ( xferbuf->pos + len );
+	if ( ( rc = xferbuf_ensure_size ( xferbuf, max ) ) != 0 )
+		goto done;
+
+	/* Copy data to buffer */
+	memcpy ( ( xferbuf->data + xferbuf->pos ), iobuf->data, len );
+
+	/* Update current buffer position */
+	xferbuf->pos += len;
+
+ done:
+	free_iob ( iobuf );
+	return rc;
+}
diff --git a/roms/ipxe/src/crypto/aes_wrap.c b/roms/ipxe/src/crypto/aes_wrap.c
index 46ef016f5401dfb72e32fc17dcf1..c09480e5a98ce902893f3f682710 100644
--- a/roms/ipxe/src/crypto/aes_wrap.c
+++ b/roms/ipxe/src/crypto/aes_wrap.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -48,7 +49,7 @@ int aes_wrap ( const void *kek, const void *src, void *dest, int nblk )
 	cipher_setkey ( &aes_algorithm, aes_ctx, kek, 16 );
 
 	/* Set up */
-	memset ( A, 0xA6, sizeof ( A ) );
+	memset ( A, 0xA6, 8 );
 	memmove ( dest + 8, src, nblk * 8 );
 
 	/* Wrap */
diff --git a/roms/ipxe/src/crypto/arc4.c b/roms/ipxe/src/crypto/arc4.c
index ab3325c83c47f40d876ce775762f..91a73201954296d9f354bfe323fb 100644
--- a/roms/ipxe/src/crypto/arc4.c
+++ b/roms/ipxe/src/crypto/arc4.c
@@ -15,7 +15,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/crypto/asn1.c b/roms/ipxe/src/crypto/asn1.c
index a54d31d0c36e982ca4b4e2f83878..6d880704f3b369d6b65bb8a52f84 100644
--- a/roms/ipxe/src/crypto/asn1.c
+++ b/roms/ipxe/src/crypto/asn1.c
@@ -13,14 +13,20 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
 #include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
 #include <errno.h>
+#include <time.h>
+#include <ipxe/tables.h>
 #include <ipxe/asn1.h>
 
 /** @file
@@ -29,43 +35,88 @@ FILE_LICENCE ( GPL2_OR_LATER );
  *
  */
 
+/* Disambiguate the various error causes */
+#define EINVAL_ASN1_EMPTY \
+	__einfo_error ( EINFO_EINVAL_ASN1_EMPTY )
+#define EINFO_EINVAL_ASN1_EMPTY \
+	__einfo_uniqify ( EINFO_EINVAL, 0x01, "Empty or underlength cursor" )
+#define EINVAL_ASN1_LEN_LEN \
+	__einfo_error ( EINFO_EINVAL_ASN1_LEN_LEN )
+#define EINFO_EINVAL_ASN1_LEN_LEN \
+	__einfo_uniqify ( EINFO_EINVAL, 0x02, "Length field overruns cursor" )
+#define EINVAL_ASN1_LEN \
+	__einfo_error ( EINFO_EINVAL_ASN1_LEN )
+#define EINFO_EINVAL_ASN1_LEN \
+	__einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" )
+#define EINVAL_ASN1_BOOLEAN \
+	__einfo_error ( EINFO_EINVAL_ASN1_BOOLEAN )
+#define EINFO_EINVAL_ASN1_BOOLEAN \
+	__einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid boolean" )
+#define EINVAL_ASN1_INTEGER \
+	__einfo_error ( EINFO_EINVAL_ASN1_INTEGER )
+#define EINFO_EINVAL_ASN1_INTEGER \
+	__einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid integer" )
+#define EINVAL_ASN1_TIME \
+	__einfo_error ( EINFO_EINVAL_ASN1_TIME )
+#define EINFO_EINVAL_ASN1_TIME \
+	__einfo_uniqify ( EINFO_EINVAL, 0x05, "Invalid time" )
+#define EINVAL_ASN1_ALGORITHM \
+	__einfo_error ( EINFO_EINVAL_ASN1_ALGORITHM )
+#define EINFO_EINVAL_ASN1_ALGORITHM \
+	__einfo_uniqify ( EINFO_EINVAL, 0x06, "Invalid algorithm" )
+#define EINVAL_BIT_STRING \
+	__einfo_error ( EINFO_EINVAL_BIT_STRING )
+#define EINFO_EINVAL_BIT_STRING \
+	__einfo_uniqify ( EINFO_EINVAL, 0x07, "Invalid bit string" )
+#define ENOTSUP_ALGORITHM \
+	__einfo_error ( EINFO_ENOTSUP_ALGORITHM )
+#define EINFO_ENOTSUP_ALGORITHM \
+	__einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported algorithm" )
+#define ENOTTY_ALGORITHM \
+	__einfo_error ( EINFO_ENOTTY_ALGORITHM )
+#define EINFO_ENOTTY_ALGORITHM \
+	__einfo_uniqify ( EINFO_ENOTTY, 0x01, "Inappropriate algorithm" )
+
+/**
+ * Invalidate ASN.1 object cursor
+ *
+ * @v cursor		ASN.1 object cursor
+ */
+void asn1_invalidate_cursor ( struct asn1_cursor *cursor ) {
+	static uint8_t asn1_invalid_object[] = { ASN1_END, 0 };
+
+	cursor->data = asn1_invalid_object;
+	cursor->len = 0;
+}
+
 /**
  * Start parsing ASN.1 object
  *
  * @v cursor		ASN.1 object cursor
- * @v type		Expected type
+ * @v type		Expected type, or ASN1_ANY
  * @ret len		Length of object body, or negative error
  *
  * The object cursor will be updated to point to the start of the
  * object body (i.e. the first byte following the length byte(s)), and
  * the length of the object body (i.e. the number of bytes until the
  * following object tag, if any) is returned.
- *
- * If any error occurs (i.e. if the object is not of the expected
- * type, or if we overflow beyond the end of the ASN.1 object), then
- * the cursor will be invalidated and a negative value will be
- * returned.
  */
-static int asn1_start ( struct asn1_cursor *cursor,
-			       unsigned int type ) {
+static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) {
 	unsigned int len_len;
 	unsigned int len;
-	int rc;
 
 	/* Sanity check */
 	if ( cursor->len < 2 /* Tag byte and first length byte */ ) {
 		if ( cursor->len )
 			DBGC ( cursor, "ASN1 %p too short\n", cursor );
-		rc = -EINVAL;
-		goto notfound;
+		return -EINVAL_ASN1_EMPTY;
 	}
 
 	/* Check the tag byte */
-	if ( *( ( uint8_t * ) cursor->data ) != type ) {
+	if ( ( type != ASN1_ANY ) && ( type != asn1_type ( cursor ) ) ) {
 		DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
 		       cursor, type, *( ( uint8_t * ) cursor->data ) );
-		rc = -ENXIO;
-		goto notfound;
+		return -ENXIO;
 	}
 	cursor->data++;
 	cursor->len--;
@@ -82,8 +133,7 @@ static int asn1_start ( struct asn1_cursor *cursor,
 	if ( cursor->len < len_len ) {
 		DBGC ( cursor, "ASN1 %p bad length field length %d (max "
 		       "%zd)\n", cursor, len_len, cursor->len );
-		rc = -EINVAL;
-		goto notfound;
+		return -EINVAL_ASN1_LEN_LEN;
 	}
 
 	/* Extract the length and sanity check */
@@ -96,23 +146,17 @@ static int asn1_start ( struct asn1_cursor *cursor,
 	if ( cursor->len < len ) {
 		DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
 		       cursor, len, cursor->len );
-		rc = -EINVAL;
-		goto notfound;
+		return -EINVAL_ASN1_LEN;
 	}
 
 	return len;
-
- notfound:
-	cursor->data = NULL;
-	cursor->len = 0;
-	return rc;
 }
 
 /**
  * Enter ASN.1 object
  *
  * @v cursor		ASN.1 object cursor
- * @v type		Expected type
+ * @v type		Expected type, or ASN1_ANY
  * @ret rc		Return status code
  *
  * The object cursor will be updated to point to the body of the
@@ -123,8 +167,10 @@ int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
 	int len;
 
 	len = asn1_start ( cursor, type );
-	if ( len < 0 )
+	if ( len < 0 ) {
+		asn1_invalidate_cursor ( cursor );
 		return len;
+	}
 
 	cursor->len = len;
 	DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
@@ -134,17 +180,17 @@ int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
 }
 
 /**
- * Skip ASN.1 object
+ * Skip ASN.1 object if present
  *
  * @v cursor		ASN.1 object cursor
- * @v type		Expected type
+ * @v type		Expected type, or ASN1_ANY
  * @ret rc		Return status code
  *
  * The object cursor will be updated to point to the next ASN.1
- * object.  If any error occurs, the object cursor will be
- * invalidated.
+ * object.  If any error occurs, the object cursor will not be
+ * modified.
  */
-int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
+int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) {
 	int len;
 
 	len = asn1_start ( cursor, type );
@@ -158,9 +204,644 @@ int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
 
 	if ( ! cursor->len ) {
 		DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
-		cursor->data = NULL;
 		return -ENOENT;
 	}
 
 	return 0;
 }
+
+/**
+ * Skip ASN.1 object
+ *
+ * @v cursor		ASN.1 object cursor
+ * @v type		Expected type, or ASN1_ANY
+ * @ret rc		Return status code
+ *
+ * The object cursor will be updated to point to the next ASN.1
+ * object.  If any error occurs, the object cursor will be
+ * invalidated.
+ */
+int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
+	int rc;
+
+	if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) != 0 ) {
+		asn1_invalidate_cursor ( cursor );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Shrink ASN.1 cursor to fit object
+ *
+ * @v cursor		ASN.1 object cursor
+ * @v type		Expected type, or ASN1_ANY
+ * @ret rc		Return status code
+ *
+ * The object cursor will be shrunk to contain only the current ASN.1
+ * object.  If any error occurs, the object cursor will be
+ * invalidated.
+ */
+int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type ) {
+	struct asn1_cursor temp;
+	const void *end;
+	int len;
+
+	/* Find end of object */
+	memcpy ( &temp, cursor, sizeof ( temp ) );
+	len = asn1_start ( &temp, type );
+	if ( len < 0 ) {
+		asn1_invalidate_cursor ( cursor );
+		return len;
+	}
+	end = ( temp.data + len );
+
+	/* Shrink original cursor to contain only its first object */
+	cursor->len = ( end - cursor->data );
+
+	return 0;
+}
+
+/**
+ * Enter ASN.1 object of any type
+ *
+ * @v cursor		ASN.1 object cursor
+ * @ret rc		Return status code
+ */
+int asn1_enter_any ( struct asn1_cursor *cursor ) {
+	return asn1_enter ( cursor, ASN1_ANY );
+}
+
+/**
+ * Skip ASN.1 object of any type
+ *
+ * @v cursor		ASN.1 object cursor
+ * @ret rc		Return status code
+ */
+int asn1_skip_any ( struct asn1_cursor *cursor ) {
+	return asn1_skip ( cursor, ASN1_ANY );
+}
+
+/**
+ * Shrink ASN.1 object of any type
+ *
+ * @v cursor		ASN.1 object cursor
+ * @ret rc		Return status code
+ */
+int asn1_shrink_any ( struct asn1_cursor *cursor ) {
+	return asn1_shrink ( cursor, ASN1_ANY );
+}
+
+/**
+ * Parse value of ASN.1 boolean
+ *
+ * @v cursor		ASN.1 object cursor
+ * @ret value		Value, or negative error
+ */
+int asn1_boolean ( const struct asn1_cursor *cursor ) {
+	struct asn1_cursor contents;
+	const struct {
+		uint8_t value;
+	} __attribute__ (( packed )) *boolean;
+
+	/* Enter boolean */
+	memcpy ( &contents, cursor, sizeof ( contents ) );
+	asn1_enter ( &contents, ASN1_BOOLEAN );
+	if ( contents.len != sizeof ( *boolean ) )
+		return -EINVAL_ASN1_BOOLEAN;
+
+	/* Extract value */
+	boolean = contents.data;
+	return boolean->value;
+}
+
+/**
+ * Parse value of ASN.1 integer
+ *
+ * @v cursor		ASN.1 object cursor
+ * @v value		Value to fill in
+ * @ret rc		Return status code
+ */
+int asn1_integer ( const struct asn1_cursor *cursor, int *value ) {
+	struct asn1_cursor contents;
+	uint8_t high_byte;
+	int rc;
+
+	/* Enter integer */
+	memcpy ( &contents, cursor, sizeof ( contents ) );
+	if ( ( rc = asn1_enter ( &contents, ASN1_INTEGER ) ) != 0 )
+		return rc;
+	if ( contents.len < 1 )
+		return -EINVAL_ASN1_INTEGER;
+
+	/* Initialise value according to sign byte */
+	*value = *( ( int8_t * ) contents.data );
+	contents.data++;
+	contents.len--;
+
+	/* Process value */
+	while ( contents.len ) {
+		high_byte = ( (*value) >> ( 8 * ( sizeof ( *value ) - 1 ) ) );
+		if ( ( high_byte != 0x00 ) && ( high_byte != 0xff ) ) {
+			DBGC ( cursor, "ASN1 %p integer overflow\n", cursor );
+			return -EINVAL_ASN1_INTEGER;
+		}
+		*value = ( ( *value << 8 ) | *( ( uint8_t * ) contents.data ) );
+		contents.data++;
+		contents.len--;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse ASN.1 bit string
+ *
+ * @v cursor		ASN.1 cursor
+ * @v bits		Bit string to fill in
+ * @ret rc		Return status code
+ */
+int asn1_bit_string ( const struct asn1_cursor *cursor,
+		      struct asn1_bit_string *bits ) {
+	struct asn1_cursor contents;
+	const struct {
+		uint8_t unused;
+		uint8_t data[0];
+	} __attribute__ (( packed )) *bit_string;
+	size_t len;
+	unsigned int unused;
+	uint8_t unused_mask;
+	const uint8_t *last;
+	int rc;
+
+	/* Enter bit string */
+	memcpy ( &contents, cursor, sizeof ( contents ) );
+	if ( ( rc = asn1_enter ( &contents, ASN1_BIT_STRING ) ) != 0 ) {
+		DBGC ( cursor, "ASN1 %p cannot locate bit string:\n", cursor );
+		DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+		return rc;
+	}
+
+	/* Validity checks */
+	if ( contents.len < sizeof ( *bit_string ) ) {
+		DBGC ( cursor, "ASN1 %p invalid bit string:\n", cursor );
+		DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+		return -EINVAL_BIT_STRING;
+	}
+	bit_string = contents.data;
+	len = ( contents.len - offsetof ( typeof ( *bit_string ), data ) );
+	unused = bit_string->unused;
+	unused_mask = ( 0xff >> ( 8 - unused ) );
+	last = ( bit_string->data + len - 1 );
+	if ( ( unused >= 8 ) ||
+	     ( ( unused > 0 ) && ( len == 0 ) ) ||
+	     ( ( *last & unused_mask ) != 0 ) ) {
+		DBGC ( cursor, "ASN1 %p invalid bit string:\n", cursor );
+		DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+		return -EINVAL_BIT_STRING;
+	}
+
+	/* Populate bit string */
+	bits->data = &bit_string->data;
+	bits->len = len;
+	bits->unused = unused;
+
+	return 0;
+}
+
+/**
+ * Parse ASN.1 bit string that must be an integral number of bytes
+ *
+ * @v cursor		ASN.1 cursor
+ * @v bits		Bit string to fill in
+ * @ret rc		Return status code
+ */
+int asn1_integral_bit_string ( const struct asn1_cursor *cursor,
+			       struct asn1_bit_string *bits ) {
+	int rc;
+
+	/* Parse bit string */
+	if ( ( rc = asn1_bit_string ( cursor, bits ) ) != 0 )
+		return rc;
+
+	/* Check that there are no unused bits at end of string */
+	if ( bits->unused ) {
+		DBGC ( cursor, "ASN1 %p invalid integral bit string:\n",
+		       cursor );
+		DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+		return -EINVAL_BIT_STRING;
+	}
+
+	return 0;
+}
+
+/**
+ * Compare two ASN.1 objects
+ *
+ * @v cursor1		ASN.1 object cursor
+ * @v cursor2		ASN.1 object cursor
+ * @ret difference	Difference as returned by memcmp()
+ *
+ * Note that invalid and empty cursors will compare as equal with each
+ * other.
+ */
+int asn1_compare ( const struct asn1_cursor *cursor1,
+		   const struct asn1_cursor *cursor2 ) {
+	int difference;
+
+	difference = ( cursor2->len - cursor1->len );
+	return ( difference ? difference :
+		 memcmp ( cursor1->data, cursor2->data, cursor1->len ) );
+}
+
+/**
+ * Identify ASN.1 algorithm by OID
+ *
+ * @v cursor		ASN.1 object cursor
+
+ * @ret algorithm	Algorithm, or NULL
+ */
+static struct asn1_algorithm *
+asn1_find_algorithm ( const struct asn1_cursor *cursor ) {
+	struct asn1_algorithm *algorithm;
+
+	for_each_table_entry ( algorithm, ASN1_ALGORITHMS ) {
+		if ( asn1_compare ( &algorithm->oid, cursor ) == 0 )
+			return algorithm;
+	}
+
+	return NULL;
+}
+
+/**
+ * Parse ASN.1 OID-identified algorithm
+ *
+ * @v cursor		ASN.1 object cursor
+ * @ret algorithm	Algorithm
+ * @ret rc		Return status code
+ */
+int asn1_algorithm ( const struct asn1_cursor *cursor,
+		     struct asn1_algorithm **algorithm ) {
+	struct asn1_cursor contents;
+	int rc;
+
+	/* Enter signatureAlgorithm */
+	memcpy ( &contents, cursor, sizeof ( contents ) );
+	asn1_enter ( &contents, ASN1_SEQUENCE );
+
+	/* Enter algorithm */
+	if ( ( rc = asn1_enter ( &contents, ASN1_OID ) ) != 0 ) {
+		DBGC ( cursor, "ASN1 %p cannot locate algorithm OID:\n",
+		       cursor );
+		DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+		return -EINVAL_ASN1_ALGORITHM;
+	}
+
+	/* Identify algorithm */
+	*algorithm = asn1_find_algorithm ( &contents );
+	if ( ! *algorithm ) {
+		DBGC ( cursor, "ASN1 %p unrecognised algorithm:\n", cursor );
+		DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+		return -ENOTSUP_ALGORITHM;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse ASN.1 OID-identified public-key algorithm
+ *
+ * @v cursor		ASN.1 object cursor
+ * @ret algorithm	Algorithm
+ * @ret rc		Return status code
+ */
+int asn1_pubkey_algorithm ( const struct asn1_cursor *cursor,
+			    struct asn1_algorithm **algorithm ) {
+	int rc;
+
+	/* Parse algorithm */
+	if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 )
+		return rc;
+
+	/* Check algorithm has a public key */
+	if ( ! (*algorithm)->pubkey ) {
+		DBGC ( cursor, "ASN1 %p algorithm %s is not a public-key "
+		       "algorithm:\n", cursor, (*algorithm)->name );
+		DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+		return -ENOTTY_ALGORITHM;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse ASN.1 OID-identified digest algorithm
+ *
+ * @v cursor		ASN.1 object cursor
+ * @ret algorithm	Algorithm
+ * @ret rc		Return status code
+ */
+int asn1_digest_algorithm ( const struct asn1_cursor *cursor,
+			    struct asn1_algorithm **algorithm ) {
+	int rc;
+
+	/* Parse algorithm */
+	if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 )
+		return rc;
+
+	/* Check algorithm has a digest */
+	if ( ! (*algorithm)->digest ) {
+		DBGC ( cursor, "ASN1 %p algorithm %s is not a digest "
+		       "algorithm:\n", cursor, (*algorithm)->name );
+		DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+		return -ENOTTY_ALGORITHM;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse ASN.1 OID-identified signature algorithm
+ *
+ * @v cursor		ASN.1 object cursor
+ * @ret algorithm	Algorithm
+ * @ret rc		Return status code
+ */
+int asn1_signature_algorithm ( const struct asn1_cursor *cursor,
+			       struct asn1_algorithm **algorithm ) {
+	int rc;
+
+	/* Parse algorithm */
+	if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 )
+		return rc;
+
+	/* Check algorithm has a public key */
+	if ( ! (*algorithm)->pubkey ) {
+		DBGC ( cursor, "ASN1 %p algorithm %s is not a signature "
+		       "algorithm:\n", cursor, (*algorithm)->name );
+		DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+		return -ENOTTY_ALGORITHM;
+	}
+
+	/* Check algorithm has a digest */
+	if ( ! (*algorithm)->digest ) {
+		DBGC ( cursor, "ASN1 %p algorithm %s is not a signature "
+		       "algorithm:\n", cursor, (*algorithm)->name );
+		DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+		return -ENOTTY_ALGORITHM;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse ASN.1 GeneralizedTime
+ *
+ * @v cursor		ASN.1 cursor
+ * @v time		Time to fill in
+ * @ret rc		Return status code
+ *
+ * RFC 5280 section 4.1.2.5 places several restrictions on the allowed
+ * formats for UTCTime and GeneralizedTime, and mandates the
+ * interpretation of centuryless year values.
+ */
+int asn1_generalized_time ( const struct asn1_cursor *cursor, time_t *time ) {
+	struct asn1_cursor contents;
+	unsigned int have_century;
+	unsigned int type;
+	union {
+		struct {
+			uint8_t century;
+			uint8_t year;
+			uint8_t month;
+			uint8_t day;
+			uint8_t hour;
+			uint8_t minute;
+			uint8_t second;
+		} __attribute__ (( packed )) named;
+		uint8_t raw[7];
+	} pairs;
+	struct tm tm;
+	const uint8_t *data;
+	size_t remaining;
+	unsigned int tens;
+	unsigned int units;
+	unsigned int i;
+	int rc;
+
+	/* Determine time format utcTime/generalizedTime */
+	memcpy ( &contents, cursor, sizeof ( contents ) );
+	type = asn1_type ( &contents );
+	switch ( type ) {
+	case ASN1_UTC_TIME:
+		have_century = 0;
+		break;
+	case ASN1_GENERALIZED_TIME:
+		have_century = 1;
+		break;
+	default:
+		DBGC ( cursor, "ASN1 %p invalid time type %02x\n",
+		       cursor, type );
+		DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+		return -EINVAL_ASN1_TIME;
+	}
+
+	/* Enter utcTime/generalizedTime */
+	if ( ( rc = asn1_enter ( &contents, type ) ) != 0 ) {
+		DBGC ( cursor, "ASN1 %p cannot locate %s time:\n", cursor,
+		       ( ( type == ASN1_UTC_TIME ) ? "UTC" : "generalized" ) );
+		DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+		return rc;
+	}
+
+	/* Parse digit string a pair at a time */
+	memset ( &pairs, 0, sizeof ( pairs ) );
+	data = contents.data;
+	remaining = contents.len;
+	for ( i = ( have_century ? 0 : 1 ) ; i < sizeof ( pairs.raw ) ; i++ ) {
+		if ( remaining < 2 ) {
+			/* Some certificates violate the X.509 RFC by
+			 * omitting the "seconds" value.
+			 */
+			if ( i == ( sizeof ( pairs.raw ) - 1 ) )
+				break;
+			DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
+			DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+			return -EINVAL_ASN1_TIME;
+		}
+		tens = data[0];
+		units = data[1];
+		if ( ! ( isdigit ( tens ) && isdigit ( units ) ) ) {
+			DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
+			DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+			return -EINVAL_ASN1_TIME;
+		}
+		pairs.raw[i] = ( ( 10 * ( tens - '0' ) ) + ( units - '0' ) );
+		data += 2;
+		remaining -= 2;
+	}
+
+	/* Determine century if applicable */
+	if ( ! have_century )
+		pairs.named.century = ( ( pairs.named.year >= 50 ) ? 19 : 20 );
+
+	/* Check for trailing "Z" */
+	if ( ( remaining != 1 ) || ( data[0] != 'Z' ) ) {
+		DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
+		DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+		return -EINVAL_ASN1_TIME;
+	}
+
+	/* Fill in time */
+	tm.tm_year = ( ( ( pairs.named.century - 19 ) * 100 ) +
+		       pairs.named.year );
+	tm.tm_mon = ( pairs.named.month - 1 );
+	tm.tm_mday = pairs.named.day;
+	tm.tm_hour = pairs.named.hour;
+	tm.tm_min = pairs.named.minute;
+	tm.tm_sec = pairs.named.second;
+
+	/* Convert to seconds since the Epoch */
+	*time = mktime ( &tm );
+
+	return 0;
+}
+
+/**
+ * Construct ASN.1 header
+ *
+ * @v header		ASN.1 builder header
+ * @v type		Type
+ * @v len		Content length
+ * @ret header_len	Header length
+ */
+static size_t asn1_header ( struct asn1_builder_header *header,
+			    unsigned int type, size_t len ) {
+	unsigned int header_len = 2;
+	unsigned int len_len = 0;
+	size_t temp;
+
+	/* Construct header */
+	header->type = type;
+	if ( len < 0x80 ) {
+		header->length[0] = len;
+	} else {
+		for ( temp = len ; temp ; temp >>= 8 )
+			len_len++;
+		header->length[0] = ( 0x80 | len_len );
+		header_len += len_len;
+		for ( temp = len ; temp ; temp >>= 8 )
+			header->length[len_len--] = ( temp & 0xff );
+	}
+
+	return header_len;
+}
+
+/**
+ * Grow ASN.1 builder
+ *
+ * @v builder		ASN.1 builder
+ * @v extra		Extra space to prepend
+ * @ret rc		Return status code
+ */
+static int asn1_grow ( struct asn1_builder *builder, size_t extra ) {
+	size_t new_len;
+	void *new;
+
+	/* As with the ASN1 parsing functions, make errors permanent */
+	if ( builder->len && ! builder->data )
+		return -ENOMEM;
+
+	/* Reallocate data buffer */
+	new_len = ( builder->len + extra );
+	new = realloc ( builder->data, new_len );
+	if ( ! new ) {
+		free ( builder->data );
+		builder->data = NULL;
+		return -ENOMEM;
+	}
+	builder->data = new;
+
+	/* Move existing data to end of buffer */
+	memmove ( ( builder->data + extra ), builder->data, builder->len );
+	builder->len = new_len;
+
+	return 0;
+}
+
+/**
+ * Prepend raw data to ASN.1 builder
+ *
+ * @v builder		ASN.1 builder
+ * @v data		Data to prepend
+ * @v len		Length of data to prepend
+ * @ret rc		Return status code
+ */
+int asn1_prepend_raw ( struct asn1_builder *builder, const void *data,
+		       size_t len ) {
+	int rc;
+
+	/* Grow buffer */
+	if ( ( rc = asn1_grow ( builder, len ) ) != 0 )
+		return rc;
+
+	/* Populate data buffer */
+	memcpy ( builder->data, data, len );
+
+	return 0;
+}
+
+/**
+ * Prepend data to ASN.1 builder
+ *
+ * @v builder		ASN.1 builder
+ * @v type		Type
+ * @v data		Data to prepend
+ * @v len		Length of data to prepend
+ * @ret rc		Return status code
+ */
+int asn1_prepend ( struct asn1_builder *builder, unsigned int type,
+		   const void *data, size_t len ) {
+	struct asn1_builder_header header;
+	size_t header_len;
+	int rc;
+
+	/* Construct header */
+	header_len = asn1_header ( &header, type, len );
+
+	/* Grow buffer */
+	if ( ( rc = asn1_grow ( builder, header_len + len ) ) != 0 )
+		return rc;
+
+	/* Populate data buffer */
+	memcpy ( builder->data, &header, header_len );
+	memcpy ( ( builder->data + header_len ), data, len );
+
+	return 0;
+}
+
+/**
+ * Wrap ASN.1 builder
+ *
+ * @v builder		ASN.1 builder
+ * @v type		Type
+ * @ret rc		Return status code
+ */
+int asn1_wrap ( struct asn1_builder *builder, unsigned int type ) {
+	struct asn1_builder_header header;
+	size_t header_len;
+	int rc;
+
+	/* Construct header */
+	header_len = asn1_header ( &header, type, builder->len );
+
+	/* Grow buffer */
+	if ( ( rc = asn1_grow ( builder, header_len ) ) != 0 )
+		return rc;
+
+	/* Populate data buffer */
+	memcpy ( builder->data, &header, header_len );
+
+	return 0;
+}
diff --git a/roms/ipxe/src/crypto/axtls/aes.c b/roms/ipxe/src/crypto/axtls/aes.c
index 87faaa1d2f30500334ee61452330..bd99a7097cc60ca5f167dd890aa7 100644
--- a/roms/ipxe/src/crypto/axtls/aes.c
+++ b/roms/ipxe/src/crypto/axtls/aes.c
@@ -1,23 +1,33 @@
 /*
- *  Copyright(C) 2006 Cameron Rich
+ * Copyright (c) 2007, Cameron Rich
  *
- *  This library is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU Lesser General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ * All rights reserved.
  *
- *  This library 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 Lesser General Public License for more details.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
  *
- *  You should have received a copy of the GNU Lesser General Public License
- *  along with this library; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * * 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 axTLS project 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.
  */
 
-FILE_LICENCE ( GPL2_OR_LATER );
-
 /**
  * AES implementation - this is a small code version. There are much faster
  * versions around but they are much larger in size (i.e. they use large 
@@ -25,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
  */
 
 #include <string.h>
+#include "os_port.h"
 #include "crypto.h"
 
 /* all commented out in skeleton mode */
@@ -64,10 +75,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
 			(f8)^=rot2(f4), \
 			(f8)^rot1(f9))
 
-/* some macros to do endian independent byte extraction */
-#define n2l(c,l) l=ntohl(*c); c++
-#define l2n(l,c) *c++=htonl(l)
-
 /*
  * AES S-box
  */
@@ -154,11 +161,15 @@ static const unsigned char Rcon[30]=
 	0xb3,0x7d,0xfa,0xef,0xc5,0x91,
 };
 
+/* ----- static functions ----- */
+static void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
+static void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
+
 /* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial
    x^8+x^4+x^3+x+1 */
 static unsigned char AES_xtime(uint32_t x)
 {
-	return x = (x&0x80) ? (x<<1)^0x1b : x<<1;
+	return (x&0x80) ? (x<<1)^0x1b : x<<1;
 }
 
 /**
@@ -247,7 +258,7 @@ void AES_convert_key(AES_CTX *ctx)
     k = ctx->ks;
     k += 4;
 
-    for (i=ctx->rounds*4; i>4; i--)
+    for (i= ctx->rounds*4; i > 4; i--)
     {
         w= *k;
         w = inv_mix_col(w,t1,t2,t3,t4);
@@ -255,52 +266,43 @@ void AES_convert_key(AES_CTX *ctx)
     }
 }
 
-#if 0
 /**
  * Encrypt a byte sequence (with a block size 16) using the AES cipher.
  */
 void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
 {
-    uint32_t tin0, tin1, tin2, tin3;
-    uint32_t tout0, tout1, tout2, tout3;
-    uint32_t tin[4];
-    uint32_t *iv = (uint32_t *)ctx->iv;
-    uint32_t *msg_32 = (uint32_t *)msg;
-    uint32_t *out_32 = (uint32_t *)out;
-
-    n2l(iv, tout0);
-    n2l(iv, tout1);
-    n2l(iv, tout2);
-    n2l(iv, tout3);
-    iv -= 4;
+    int i;
+    uint32_t tin[4], tout[4], iv[4];
 
-    for (length -= 16; length >= 0; length -= 16)
+    memcpy(iv, ctx->iv, AES_IV_SIZE);
+    for (i = 0; i < 4; i++)
+        tout[i] = ntohl(iv[i]);
+
+    for (length -= AES_BLOCKSIZE; length >= 0; length -= AES_BLOCKSIZE)
     {
-        n2l(msg_32, tin0);
-        n2l(msg_32, tin1);
-        n2l(msg_32, tin2);
-        n2l(msg_32, tin3);
-        tin[0] = tin0^tout0;
-        tin[1] = tin1^tout1;
-        tin[2] = tin2^tout2;
-        tin[3] = tin3^tout3;
+        uint32_t msg_32[4];
+        uint32_t out_32[4];
+        memcpy(msg_32, msg, AES_BLOCKSIZE);
+        msg += AES_BLOCKSIZE;
+
+        for (i = 0; i < 4; i++)
+            tin[i] = ntohl(msg_32[i])^tout[i];
 
         AES_encrypt(ctx, tin);
 
-        tout0 = tin[0]; 
-        l2n(tout0, out_32);
-        tout1 = tin[1]; 
-        l2n(tout1, out_32);
-        tout2 = tin[2]; 
-        l2n(tout2, out_32);
-        tout3 = tin[3]; 
-        l2n(tout3, out_32);
+        for (i = 0; i < 4; i++)
+        {
+            tout[i] = tin[i];
+            out_32[i] = htonl(tout[i]);
+        }
+
+        memcpy(out, out_32, AES_BLOCKSIZE);
+        out += AES_BLOCKSIZE;
     }
 
-    l2n(tout0, iv);
-    l2n(tout1, iv);
-    l2n(tout2, iv);
-    l2n(tout3, iv);
+    for (i = 0; i < 4; i++)
+        iv[i] = htonl(tout[i]);
+    memcpy(ctx->iv, iv, AES_IV_SIZE);
 }
 
 /**
@@ -308,61 +310,48 @@ void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
  */
 void AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
 {
-    uint32_t tin0, tin1, tin2, tin3;
-    uint32_t xor0,xor1,xor2,xor3;
-    uint32_t tout0,tout1,tout2,tout3;
-    uint32_t data[4];
-    uint32_t *iv = (uint32_t *)ctx->iv;
-    uint32_t *msg_32 = (uint32_t *)msg;
-    uint32_t *out_32 = (uint32_t *)out;
-
-    n2l(iv ,xor0);
-    n2l(iv, xor1);
-    n2l(iv, xor2);
-    n2l(iv, xor3);
-    iv -= 4;
-
-    for (length-=16; length >= 0; length -= 16)
+    int i;
+    uint32_t tin[4], xor[4], tout[4], data[4], iv[4];
+
+    memcpy(iv, ctx->iv, AES_IV_SIZE);
+    for (i = 0; i < 4; i++)
+        xor[i] = ntohl(iv[i]);
+
+    for (length -= 16; length >= 0; length -= 16)
     {
-        n2l(msg_32, tin0);
-        n2l(msg_32, tin1);
-        n2l(msg_32, tin2);
-        n2l(msg_32, tin3);
+        uint32_t msg_32[4];
+        uint32_t out_32[4];
+        memcpy(msg_32, msg, AES_BLOCKSIZE);
+        msg += AES_BLOCKSIZE;
 
-        data[0] = tin0;
-        data[1] = tin1;
-        data[2] = tin2;
-        data[3] = tin3;
+        for (i = 0; i < 4; i++)
+        {
+            tin[i] = ntohl(msg_32[i]);
+            data[i] = tin[i];
+        }
 
         AES_decrypt(ctx, data);
 
-        tout0 = data[0]^xor0;
-        tout1 = data[1]^xor1;
-        tout2 = data[2]^xor2;
-        tout3 = data[3]^xor3;
-
-        xor0 = tin0;
-        xor1 = tin1;
-        xor2 = tin2;
-        xor3 = tin3;
+        for (i = 0; i < 4; i++)
+        {
+            tout[i] = data[i]^xor[i];
+            xor[i] = tin[i];
+            out_32[i] = htonl(tout[i]);
+        }
 
-        l2n(tout0, out_32);
-        l2n(tout1, out_32);
-        l2n(tout2, out_32);
-        l2n(tout3, out_32);
+        memcpy(out, out_32, AES_BLOCKSIZE);
+        out += AES_BLOCKSIZE;
     }
 
-    l2n(xor0, iv);
-    l2n(xor1, iv);
-    l2n(xor2, iv);
-    l2n(xor3, iv);
+    for (i = 0; i < 4; i++)
+        iv[i] = htonl(xor[i]);
+    memcpy(ctx->iv, iv, AES_IV_SIZE);
 }
-#endif
 
 /**
  * Encrypt a single block (16 bytes) of data
  */
-void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
+static void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
 {
     /* To make this code smaller, generate the sbox entries on the fly.
      * This will have a really heavy effect upon performance.
@@ -375,9 +364,7 @@ void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
 
     /* Pre-round key addition */
     for (row = 0; row < 4; row++)
-    {
         data[row] ^= *(k++);
-    }
 
     /* Encrypt one block. */
     for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
@@ -395,12 +382,10 @@ void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
             {
                 tmp1 = a0 ^ a1 ^ a2 ^ a3;
                 old_a0 = a0;
-
                 a0 ^= tmp1 ^ AES_xtime(a0 ^ a1);
                 a1 ^= tmp1 ^ AES_xtime(a1 ^ a2);
                 a2 ^= tmp1 ^ AES_xtime(a2 ^ a3);
                 a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0);
-
             }
 
             tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3);
@@ -409,32 +394,28 @@ void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
         /* KeyAddition - note that it is vital that this loop is separate from
            the MixColumn operation, which must be atomic...*/ 
         for (row = 0; row < 4; row++)
-        {
             data[row] = tmp[row] ^ *(k++);
-        }
     }
 }
 
 /**
  * Decrypt a single block (16 bytes) of data
  */
-void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
+static void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
 { 
     uint32_t tmp[4];
     uint32_t xt0,xt1,xt2,xt3,xt4,xt5,xt6;
     uint32_t a0, a1, a2, a3, row;
     int curr_rnd;
     int rounds = ctx->rounds;
-    uint32_t *k = (uint32_t*)ctx->ks + ((rounds+1)*4);
+    const uint32_t *k = ctx->ks + ((rounds+1)*4);
 
     /* pre-round key addition */
     for (row=4; row > 0;row--)
-    {
         data[row-1] ^= *(--k);
-    }
 
     /* Decrypt one block */
-    for (curr_rnd=0; curr_rnd < rounds; curr_rnd++)
+    for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
     {
         /* Perform ByteSub and ShiftRow operations together */
         for (row = 4; row > 0; row--)
@@ -469,9 +450,7 @@ void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
         }
 
         for (row = 4; row > 0; row--)
-        {
             data[row-1] = tmp[row-1] ^ *(--k);
-        }
     }
 }
 
diff --git a/roms/ipxe/src/crypto/axtls/bigint.c b/roms/ipxe/src/crypto/axtls/bigint.c
deleted file mode 100644
index 49cad971e9e28e88e79907e318c621ebdce241f5..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/crypto/axtls/bigint.c
+++ /dev/null
@@ -1,1496 +0,0 @@
-/*
- *  Copyright(C) 2006 Cameron Rich
- *
- *  This library is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU Lesser General Public License as published by
- *  the Free Software Foundation; either version 2.1 of the License, or
- *  (at your option) any later version.
- *
- *  This library 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 Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public License
- *  along with this library; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * @defgroup bigint_api Big Integer API
- * @brief The bigint implementation as used by the axTLS project.
- *
- * The bigint library is for RSA encryption/decryption as well as signing.
- * This code tries to minimise use of malloc/free by maintaining a small 
- * cache. A bigint context may maintain state by being made "permanent". 
- * It be be later released with a bi_depermanent() and bi_free() call.
- *
- * It supports the following reduction techniques:
- * - Classical
- * - Barrett
- * - Montgomery
- *
- * It also implements the following:
- * - Karatsuba multiplication
- * - Squaring
- * - Sliding window exponentiation
- * - Chinese Remainder Theorem (implemented in rsa.c).
- *
- * All the algorithms used are pretty standard, and designed for different
- * data bus sizes. Negative numbers are not dealt with at all, so a subtraction
- * may need to be tested for negativity.
- *
- * This library steals some ideas from Jef Poskanzer
- * <http://cs.marlboro.edu/term/cs-fall02/algorithms/crypto/RSA/bigint>
- * and GMP <http://www.swox.com/gmp>. It gets most of its implementation
- * detail from "The Handbook of Applied Cryptography"
- * <http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf>
- * @{
- */
-
-#include <stdlib.h>
-#include <limits.h>
-#include <string.h>
-#include <stdio.h>
-#include <time.h>
-#include "bigint.h"
-#include "crypto.h"
-
-static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i);
-static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom);
-static bigint __malloc *alloc(BI_CTX *ctx, int size);
-static bigint *trim(bigint *bi);
-static void more_comps(bigint *bi, int n);
-#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
-    defined(CONFIG_BIGINT_MONTGOMERY)
-static bigint *comp_right_shift(bigint *biR, int num_shifts);
-static bigint *comp_left_shift(bigint *biR, int num_shifts);
-#endif
-
-#ifdef CONFIG_BIGINT_CHECK_ON
-static void check(const bigint *bi);
-#endif
-
-/**
- * @brief Start a new bigint context.
- * @return A bigint context.
- */
-BI_CTX *bi_initialize(void)
-{
-    /* calloc() sets everything to zero */
-    BI_CTX *ctx = (BI_CTX *)calloc(1, sizeof(BI_CTX));
-   
-    /* the radix */
-    ctx->bi_radix = alloc(ctx, 2); 
-    ctx->bi_radix->comps[0] = 0;
-    ctx->bi_radix->comps[1] = 1;
-    bi_permanent(ctx->bi_radix);
-    return ctx;
-}
-
-/**
- * @brief Close the bigint context and free any resources.
- *
- * Free up any used memory - a check is done if all objects were not 
- * properly freed.
- * @param ctx [in]   The bigint session context.
- */
-void bi_terminate(BI_CTX *ctx)
-{
-    bigint *p, *pn;
-
-    bi_depermanent(ctx->bi_radix); 
-    bi_free(ctx, ctx->bi_radix);
-
-    if (ctx->active_count != 0)
-    {
-#ifdef CONFIG_SSL_FULL_MODE
-        printf("bi_terminate: there were %d un-freed bigints\n",
-                       ctx->active_count);
-#endif
-        abort();
-    }
-
-    for (p = ctx->free_list; p != NULL; p = pn)
-    {
-        pn = p->next;
-        free(p->comps);
-        free(p);
-    }
-
-    free(ctx);
-}
-
-/**
- * @brief Increment the number of references to this object. 
- * It does not do a full copy.
- * @param bi [in]   The bigint to copy.
- * @return A reference to the same bigint.
- */
-bigint *bi_copy(bigint *bi)
-{
-    check(bi);
-    if (bi->refs != PERMANENT)
-        bi->refs++;
-    return bi;
-}
-
-/**
- * @brief Simply make a bigint object "unfreeable" if bi_free() is called on it.
- *
- * For this object to be freed, bi_depermanent() must be called.
- * @param bi [in]   The bigint to be made permanent.
- */
-void bi_permanent(bigint *bi)
-{
-    check(bi);
-    if (bi->refs != 1)
-    {
-#ifdef CONFIG_SSL_FULL_MODE
-        printf("bi_permanent: refs was not 1\n");
-#endif
-        abort();
-    }
-
-    bi->refs = PERMANENT;
-}
-
-/**
- * @brief Take a permanent object and make it eligible for freedom.
- * @param bi [in]   The bigint to be made back to temporary.
- */
-void bi_depermanent(bigint *bi)
-{
-    check(bi);
-    if (bi->refs != PERMANENT)
-    {
-#ifdef CONFIG_SSL_FULL_MODE
-        printf("bi_depermanent: bigint was not permanent\n");
-#endif
-        abort();
-    }
-
-    bi->refs = 1;
-}
-
-/**
- * @brief Free a bigint object so it can be used again. 
- *
- * The memory itself it not actually freed, just tagged as being available 
- * @param ctx [in]   The bigint session context.
- * @param bi [in]    The bigint to be freed.
- */
-void bi_free(BI_CTX *ctx, bigint *bi)
-{
-    check(bi);
-    if (bi->refs == PERMANENT)
-    {
-        return;
-    }
-
-    if (--bi->refs > 0)
-    {
-        return;
-    }
-
-    bi->next = ctx->free_list;
-    ctx->free_list = bi;
-    ctx->free_count++;
-
-    if (--ctx->active_count < 0)
-    {
-#ifdef CONFIG_SSL_FULL_MODE
-        printf("bi_free: active_count went negative "
-                "- double-freed bigint?\n");
-#endif
-        abort();
-    }
-}
-
-/**
- * @brief Convert an (unsigned) integer into a bigint.
- * @param ctx [in]   The bigint session context.
- * @param i [in]     The (unsigned) integer to be converted.
- * 
- */
-bigint *int_to_bi(BI_CTX *ctx, comp i)
-{
-    bigint *biR = alloc(ctx, 1);
-    biR->comps[0] = i;
-    return biR;
-}
-
-/**
- * @brief Do a full copy of the bigint object.
- * @param ctx [in]   The bigint session context.
- * @param bi  [in]   The bigint object to be copied.
- */
-bigint *bi_clone(BI_CTX *ctx, const bigint *bi)
-{
-    bigint *biR = alloc(ctx, bi->size);
-    check(bi);
-    memcpy(biR->comps, bi->comps, bi->size*COMP_BYTE_SIZE);
-    return biR;
-}
-
-/**
- * @brief Perform an addition operation between two bigints.
- * @param ctx [in]  The bigint session context.
- * @param bia [in]  A bigint.
- * @param bib [in]  Another bigint.
- * @return The result of the addition.
- */
-bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib)
-{
-    int n;
-    comp carry = 0;
-    comp *pa, *pb;
-
-    check(bia);
-    check(bib);
-
-    n = max(bia->size, bib->size);
-    more_comps(bia, n+1);
-    more_comps(bib, n);
-    pa = bia->comps;
-    pb = bib->comps;
-
-    do
-    {
-        comp  sl, rl, cy1;
-        sl = *pa + *pb++;
-        rl = sl + carry;
-        cy1 = sl < *pa;
-        carry = cy1 | (rl < sl);
-        *pa++ = rl;
-    } while (--n != 0);
-
-    *pa = carry;                  /* do overflow */
-    bi_free(ctx, bib);
-    return trim(bia);
-}
-
-/**
- * @brief Perform a subtraction operation between two bigints.
- * @param ctx [in]  The bigint session context.
- * @param bia [in]  A bigint.
- * @param bib [in]  Another bigint.
- * @param is_negative [out] If defined, indicates that the result was negative.
- * is_negative may be null.
- * @return The result of the subtraction. The result is always positive.
- */
-bigint *bi_subtract(BI_CTX *ctx, 
-        bigint *bia, bigint *bib, int *is_negative)
-{
-    int n = bia->size;
-    comp *pa, *pb, carry = 0;
-
-    check(bia);
-    check(bib);
-
-    more_comps(bib, n);
-    pa = bia->comps;
-    pb = bib->comps;
-
-    do 
-    {
-        comp sl, rl, cy1;
-        sl = *pa - *pb++;
-        rl = sl - carry;
-        cy1 = sl > *pa;
-        carry = cy1 | (rl > sl);
-        *pa++ = rl;
-    } while (--n != 0);
-
-    if (is_negative)    /* indicate a negative result */
-    {
-        *is_negative = carry;
-    }
-
-    bi_free(ctx, trim(bib));    /* put bib back to the way it was */
-    return trim(bia);
-}
-
-/**
- * Perform a multiply between a bigint an an (unsigned) integer
- */
-static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b)
-{
-    int j = 0, n = bia->size;
-    bigint *biR = alloc(ctx, n + 1);
-    comp carry = 0;
-    comp *r = biR->comps;
-    comp *a = bia->comps;
-
-    check(bia);
-
-    /* clear things to start with */
-    memset(r, 0, ((n+1)*COMP_BYTE_SIZE));
-
-    do
-    {
-        long_comp tmp = *r + (long_comp)a[j]*b + carry;
-        *r++ = (comp)tmp;              /* downsize */
-        carry = (comp)(tmp >> COMP_BIT_SIZE);
-    } while (++j < n);
-
-    *r = carry;
-    bi_free(ctx, bia);
-    return trim(biR);
-}
-
-/**
- * @brief Does both division and modulo calculations. 
- *
- * Used extensively when doing classical reduction.
- * @param ctx [in]  The bigint session context.
- * @param u [in]    A bigint which is the numerator.
- * @param v [in]    Either the denominator or the modulus depending on the mode.
- * @param is_mod [n] Determines if this is a normal division (0) or a reduction
- * (1).
- * @return  The result of the division/reduction.
- */
-bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod)
-{
-    int n = v->size, m = u->size-n;
-    int j = 0, orig_u_size = u->size;
-    uint8_t mod_offset = ctx->mod_offset;
-    comp d;
-    bigint *quotient, *tmp_u;
-    comp q_dash;
-
-    check(u);
-    check(v);
-
-    /* if doing reduction and we are < mod, then return mod */
-    if (is_mod && bi_compare(v, u) > 0)
-    {
-        bi_free(ctx, v);
-        return u;
-    }
-
-    quotient = alloc(ctx, m+1);
-    tmp_u = alloc(ctx, n+1);
-    v = trim(v);        /* make sure we have no leading 0's */
-    d = (comp)((long_comp)COMP_RADIX/(V1+1));
-
-    /* clear things to start with */
-    memset(quotient->comps, 0, ((quotient->size)*COMP_BYTE_SIZE));
-
-    /* normalise */
-    if (d > 1)
-    {
-        u = bi_int_multiply(ctx, u, d);
-
-        if (is_mod)
-        {
-            v = ctx->bi_normalised_mod[mod_offset];
-        }
-        else
-        {
-            v = bi_int_multiply(ctx, v, d);
-        }
-    }
-
-    if (orig_u_size == u->size)  /* new digit position u0 */
-    {
-        more_comps(u, orig_u_size + 1);
-    }
-
-    do
-    {
-        /* get a temporary short version of u */
-        memcpy(tmp_u->comps, &u->comps[u->size-n-1-j], (n+1)*COMP_BYTE_SIZE);
-
-        /* calculate q' */
-        if (U(0) == V1)
-        {
-            q_dash = COMP_RADIX-1;
-        }
-        else
-        {
-            q_dash = (comp)(((long_comp)U(0)*COMP_RADIX + U(1))/V1);
-        }
-
-        if (v->size > 1 && V2)
-        {
-            /* we are implementing the following:
-            if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - 
-                    q_dash*V1)*COMP_RADIX) + U(2))) ... */
-            comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) - 
-                                        (long_comp)q_dash*V1);
-            if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2))
-            {
-                q_dash--;
-            }
-        }
-
-        /* multiply and subtract */
-        if (q_dash)
-        {
-            int is_negative;
-            tmp_u = bi_subtract(ctx, tmp_u, 
-                    bi_int_multiply(ctx, bi_copy(v), q_dash), &is_negative);
-            more_comps(tmp_u, n+1);
-
-            Q(j) = q_dash; 
-
-            /* add back */
-            if (is_negative)
-            {
-                Q(j)--;
-                tmp_u = bi_add(ctx, tmp_u, bi_copy(v));
-
-                /* lop off the carry */
-                tmp_u->size--;
-                v->size--;
-            }
-        }
-        else
-        {
-            Q(j) = 0; 
-        }
-
-        /* copy back to u */
-        memcpy(&u->comps[u->size-n-1-j], tmp_u->comps, (n+1)*COMP_BYTE_SIZE);
-    } while (++j <= m);
-
-    bi_free(ctx, tmp_u);
-    bi_free(ctx, v);
-
-    if (is_mod)     /* get the remainder */
-    {
-        bi_free(ctx, quotient);
-        return bi_int_divide(ctx, trim(u), d);
-    }
-    else            /* get the quotient */
-    {
-        bi_free(ctx, u);
-        return trim(quotient);
-    }
-}
-
-/*
- * Perform an integer divide on a bigint.
- */
-static bigint *bi_int_divide(BI_CTX *ctx __unused, bigint *biR, comp denom)
-{
-    int i = biR->size - 1;
-    long_comp r = 0;
-
-    check(biR);
-
-    do
-    {
-        r = (r<<COMP_BIT_SIZE) + biR->comps[i];
-        biR->comps[i] = (comp)(r / denom);
-        r %= denom;
-    } while (--i != 0);
-
-    return trim(biR);
-}
-
-#ifdef CONFIG_BIGINT_MONTGOMERY
-/**
- * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1, 
- * where B^-1(B-1) mod N=1. Actually, only the least significant part of 
- * N' is needed, hence the definition N0'=N' mod b. We reproduce below the 
- * simple algorithm from an article by Dusse and Kaliski to efficiently 
- * find N0' from N0 and b */
-static comp modular_inverse(bigint *bim)
-{
-    int i;
-    comp t = 1;
-    comp two_2_i_minus_1 = 2;   /* 2^(i-1) */
-    long_comp two_2_i = 4;      /* 2^i */
-    comp N = bim->comps[0];
-
-    for (i = 2; i <= COMP_BIT_SIZE; i++)
-    {
-        if ((long_comp)N*t%two_2_i >= two_2_i_minus_1)
-        {
-            t += two_2_i_minus_1;
-        }
-
-        two_2_i_minus_1 <<= 1;
-        two_2_i <<= 1;
-    }
-
-    return (comp)(COMP_RADIX-t);
-}
-#endif
-
-#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \
-    defined(CONFIG_BIGINT_MONTGOMERY)
-/**
- * Take each component and shift down (in terms of components) 
- */
-static bigint *comp_right_shift(bigint *biR, int num_shifts)
-{
-    int i = biR->size-num_shifts;
-    comp *x = biR->comps;
-    comp *y = &biR->comps[num_shifts];
-
-    check(biR);
-
-    if (i <= 0)     /* have we completely right shifted? */
-    {
-        biR->comps[0] = 0;  /* return 0 */
-        biR->size = 1;
-        return biR;
-    }
-
-    do
-    {
-        *x++ = *y++;
-    } while (--i > 0);
-
-    biR->size -= num_shifts;
-    return biR;
-}
-
-/**
- * Take each component and shift it up (in terms of components) 
- */
-static bigint *comp_left_shift(bigint *biR, int num_shifts)
-{
-    int i = biR->size-1;
-    comp *x, *y;
-
-    check(biR);
-
-    if (num_shifts <= 0)
-    {
-        return biR;
-    }
-
-    more_comps(biR, biR->size + num_shifts);
-
-    x = &biR->comps[i+num_shifts];
-    y = &biR->comps[i];
-
-    do
-    {
-        *x-- = *y--;
-    } while (i--);
-
-    memset(biR->comps, 0, num_shifts*COMP_BYTE_SIZE); /* zero LS comps */
-    return biR;
-}
-#endif
-
-/**
- * @brief Allow a binary sequence to be imported as a bigint.
- * @param ctx [in]  The bigint session context.
- * @param data [in] The data to be converted.
- * @param size [in] The number of bytes of data.
- * @return A bigint representing this data.
- */
-bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int size)
-{
-    bigint *biR = alloc(ctx, (size+COMP_BYTE_SIZE-1)/COMP_BYTE_SIZE);
-    int i, j = 0, offset = 0;
-
-    memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
-
-    for (i = size-1; i >= 0; i--)
-    {
-        biR->comps[offset] += data[i] << (j*8);
-
-        if (++j == COMP_BYTE_SIZE)
-        {
-            j = 0;
-            offset ++;
-        }
-    }
-
-    return trim(biR);
-}
-
-#ifdef CONFIG_SSL_FULL_MODE
-/**
- * @brief The testharness uses this code to import text hex-streams and 
- * convert them into bigints.
- * @param ctx [in]  The bigint session context.
- * @param data [in] A string consisting of hex characters. The characters must
- * be in upper case.
- * @return A bigint representing this data.
- */
-bigint *bi_str_import(BI_CTX *ctx, const char *data)
-{
-    int size = strlen(data);
-    bigint *biR = alloc(ctx, (size+COMP_NUM_NIBBLES-1)/COMP_NUM_NIBBLES);
-    int i, j = 0, offset = 0;
-    memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
-
-    for (i = size-1; i >= 0; i--)
-    {
-        int num = (data[i] <= '9') ? (data[i] - '0') : (data[i] - 'A' + 10);
-        biR->comps[offset] += num << (j*4);
-
-        if (++j == COMP_NUM_NIBBLES)
-        {
-            j = 0;
-            offset ++;
-        }
-    }
-
-    return biR;
-}
-
-void bi_print(const char *label, bigint *x)
-{
-    int i, j;
-
-    if (x == NULL)
-    {
-        printf("%s: (null)\n", label);
-        return;
-    }
-
-    printf("%s: (size %d)\n", label, x->size);
-    for (i = x->size-1; i >= 0; i--)
-    {
-        for (j = COMP_NUM_NIBBLES-1; j >= 0; j--)
-        {
-            comp mask = 0x0f << (j*4);
-            comp num = (x->comps[i] & mask) >> (j*4);
-            putc((num <= 9) ? (num + '0') : (num + 'A' - 10), stdout);
-        }
-    }  
-
-    printf("\n");
-}
-#endif
-
-/**
- * @brief Take a bigint and convert it into a byte sequence. 
- *
- * This is useful after a decrypt operation.
- * @param ctx [in]  The bigint session context.
- * @param x [in]  The bigint to be converted.
- * @param data [out] The converted data as a byte stream.
- * @param size [in] The maximum size of the byte stream. Unused bytes will be
- * zeroed.
- */
-void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size)
-{
-    int i, j, k = size-1;
-
-    check(x);
-    memset(data, 0, size);  /* ensure all leading 0's are cleared */
-
-    for (i = 0; i < x->size; i++)
-    {
-        for (j = 0; j < COMP_BYTE_SIZE; j++)
-        {
-            comp mask = 0xff << (j*8);
-            int num = (x->comps[i] & mask) >> (j*8);
-            data[k--] = num;
-
-            if (k < 0)
-            {
-                break;
-            }
-        }
-    }
-
-    bi_free(ctx, x);
-}
-
-/**
- * @brief Pre-calculate some of the expensive steps in reduction. 
- *
- * This function should only be called once (normally when a session starts).
- * When the session is over, bi_free_mod() should be called. bi_mod_power()
- * relies on this function being called.
- * @param ctx [in]  The bigint session context.
- * @param bim [in]  The bigint modulus that will be used.
- * @param mod_offset [in] There are three moduluii that can be stored - the
- * standard modulus, and its two primes p and q. This offset refers to which
- * modulus we are referring to.
- * @see bi_free_mod(), bi_mod_power().
- */
-void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset)
-{
-    int k = bim->size;
-    comp d = (comp)((long_comp)COMP_RADIX/(bim->comps[k-1]+1));
-#ifdef CONFIG_BIGINT_MONTGOMERY
-    bigint *R, *R2;
-#endif
-
-    ctx->bi_mod[mod_offset] = bim;
-    bi_permanent(ctx->bi_mod[mod_offset]);
-    ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d);
-    bi_permanent(ctx->bi_normalised_mod[mod_offset]);
-
-#if defined(CONFIG_BIGINT_MONTGOMERY)
-    /* set montgomery variables */
-    R = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k-1);     /* R */
-    R2 = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k*2-1);  /* R^2 */
-    ctx->bi_RR_mod_m[mod_offset] = bi_mod(ctx, R2);             /* R^2 mod m */
-    ctx->bi_R_mod_m[mod_offset] = bi_mod(ctx, R);               /* R mod m */
-
-    bi_permanent(ctx->bi_RR_mod_m[mod_offset]);
-    bi_permanent(ctx->bi_R_mod_m[mod_offset]);
-
-    ctx->N0_dash[mod_offset] = modular_inverse(ctx->bi_mod[mod_offset]);
-
-#elif defined (CONFIG_BIGINT_BARRETT)
-    ctx->bi_mu[mod_offset] = 
-        bi_divide(ctx, comp_left_shift(
-            bi_clone(ctx, ctx->bi_radix), k*2-1), ctx->bi_mod[mod_offset], 0);
-    bi_permanent(ctx->bi_mu[mod_offset]);
-#endif
-}
-
-/**
- * @brief Used when cleaning various bigints at the end of a session.
- * @param ctx [in]  The bigint session context.
- * @param mod_offset [in] The offset to use.
- * @see bi_set_mod().
- */
-void bi_free_mod(BI_CTX *ctx, int mod_offset)
-{
-    bi_depermanent(ctx->bi_mod[mod_offset]);
-    bi_free(ctx, ctx->bi_mod[mod_offset]);
-#if defined (CONFIG_BIGINT_MONTGOMERY)
-    bi_depermanent(ctx->bi_RR_mod_m[mod_offset]);
-    bi_depermanent(ctx->bi_R_mod_m[mod_offset]);
-    bi_free(ctx, ctx->bi_RR_mod_m[mod_offset]);
-    bi_free(ctx, ctx->bi_R_mod_m[mod_offset]);
-#elif defined(CONFIG_BIGINT_BARRETT)
-    bi_depermanent(ctx->bi_mu[mod_offset]); 
-    bi_free(ctx, ctx->bi_mu[mod_offset]);
-#endif
-    bi_depermanent(ctx->bi_normalised_mod[mod_offset]); 
-    bi_free(ctx, ctx->bi_normalised_mod[mod_offset]);
-}
-
-/** 
- * Perform a standard multiplication between two bigints.
- */
-static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)
-{
-    int i, j, i_plus_j;
-    int n = bia->size; 
-    int t = bib->size;
-    bigint *biR = alloc(ctx, n + t);
-    comp *sr = biR->comps;
-    comp *sa = bia->comps;
-    comp *sb = bib->comps;
-
-    check(bia);
-    check(bib);
-
-    /* clear things to start with */
-    memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE));
-    i = 0;
-
-    do 
-    {
-        comp carry = 0;
-        comp b = *sb++;
-        i_plus_j = i;
-        j = 0;
-
-        do
-        {
-            long_comp tmp = sr[i_plus_j] + (long_comp)sa[j]*b + carry;
-            sr[i_plus_j++] = (comp)tmp;              /* downsize */
-            carry = (comp)(tmp >> COMP_BIT_SIZE);
-        } while (++j < n);
-
-        sr[i_plus_j] = carry;
-    } while (++i < t);
-
-    bi_free(ctx, bia);
-    bi_free(ctx, bib);
-    return trim(biR);
-}
-
-#ifdef CONFIG_BIGINT_KARATSUBA
-/*
- * Karatsuba improves on regular multiplication due to only 3 multiplications 
- * being done instead of 4. The additional additions/subtractions are O(N) 
- * rather than O(N^2) and so for big numbers it saves on a few operations 
- */
-static bigint *karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square)
-{
-    bigint *x0, *x1;
-    bigint *p0, *p1, *p2;
-    int m;
-
-    if (is_square)
-    {
-        m = (bia->size + 1)/2;
-    }
-    else
-    {
-        m = (max(bia->size, bib->size) + 1)/2;
-    }
-
-    x0 = bi_clone(ctx, bia);
-    x0->size = m;
-    x1 = bi_clone(ctx, bia);
-    comp_right_shift(x1, m);
-    bi_free(ctx, bia);
-
-    /* work out the 3 partial products */
-    if (is_square)
-    {
-        p0 = bi_square(ctx, bi_copy(x0));
-        p2 = bi_square(ctx, bi_copy(x1));
-        p1 = bi_square(ctx, bi_add(ctx, x0, x1));
-    }
-    else /* normal multiply */
-    {
-        bigint *y0, *y1;
-        y0 = bi_clone(ctx, bib);
-        y0->size = m;
-        y1 = bi_clone(ctx, bib);
-        comp_right_shift(y1, m);
-        bi_free(ctx, bib);
-
-        p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0));
-        p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1));
-        p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1));
-    }
-
-    p1 = bi_subtract(ctx, 
-            bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), NULL);
-
-    comp_left_shift(p1, m);
-    comp_left_shift(p2, 2*m);
-    return bi_add(ctx, p1, bi_add(ctx, p0, p2));
-}
-#endif
-
-/**
- * @brief Perform a multiplication operation between two bigints.
- * @param ctx [in]  The bigint session context.
- * @param bia [in]  A bigint.
- * @param bib [in]  Another bigint.
- * @return The result of the multiplication.
- */
-bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)
-{
-    check(bia);
-    check(bib);
-
-#ifdef CONFIG_BIGINT_KARATSUBA
-    if (min(bia->size, bib->size) < MUL_KARATSUBA_THRESH)
-    {
-        return regular_multiply(ctx, bia, bib);
-    }
-
-    return karatsuba(ctx, bia, bib, 0);
-#else
-    return regular_multiply(ctx, bia, bib);
-#endif
-}
-
-#ifdef CONFIG_BIGINT_SQUARE
-/*
- * Perform the actual square operion. It takes into account overflow.
- */
-static bigint *regular_square(BI_CTX *ctx, bigint *bi)
-{
-    int t = bi->size;
-    int i = 0, j;
-    bigint *biR = alloc(ctx, t*2);
-    comp *w = biR->comps;
-    comp *x = bi->comps;
-    comp carry;
-
-    memset(w, 0, biR->size*COMP_BYTE_SIZE);
-
-    do
-    {
-        long_comp tmp = w[2*i] + (long_comp)x[i]*x[i];
-        comp u = 0;
-        w[2*i] = (comp)tmp;
-        carry = (comp)(tmp >> COMP_BIT_SIZE);
-
-        for (j = i+1; j < t; j++)
-        {
-            long_comp xx = (long_comp)x[i]*x[j];
-            long_comp blob = (long_comp)w[i+j]+carry;
-
-            if (u)                  /* previous overflow */
-            {
-                blob += COMP_RADIX;
-            }
-
-            u = 0;
-            if (xx & COMP_BIG_MSB)  /* check for overflow */
-            {
-                u = 1;
-            }
-
-            tmp = 2*xx + blob;
-            w[i+j] = (comp)tmp;
-            carry = (comp)(tmp >> COMP_BIT_SIZE);
-        }
-
-        w[i+t] += carry;
-
-        if (u)
-        {
-            w[i+t+1] = 1;   /* add carry */
-        }
-    } while (++i < t);
-
-    bi_free(ctx, bi);
-    return trim(biR);
-}
-
-/**
- * @brief Perform a square operation on a bigint.
- * @param ctx [in]  The bigint session context.
- * @param bia [in]  A bigint.
- * @return The result of the multiplication.
- */
-bigint *bi_square(BI_CTX *ctx, bigint *bia)
-{
-    check(bia);
-
-#ifdef CONFIG_BIGINT_KARATSUBA
-    if (bia->size < SQU_KARATSUBA_THRESH) 
-    {
-        return regular_square(ctx, bia);
-    }
-
-    return karatsuba(ctx, bia, NULL, 1);
-#else
-    return regular_square(ctx, bia);
-#endif
-}
-#endif
-
-/**
- * @brief Compare two bigints.
- * @param bia [in]  A bigint.
- * @param bib [in]  Another bigint.
- * @return -1 if smaller, 1 if larger and 0 if equal.
- */
-int bi_compare(bigint *bia, bigint *bib)
-{
-    int r, i;
-
-    check(bia);
-    check(bib);
-
-    if (bia->size > bib->size)
-        r = 1;
-    else if (bia->size < bib->size)
-        r = -1;
-    else
-    {
-        comp *a = bia->comps; 
-        comp *b = bib->comps; 
-
-        /* Same number of components.  Compare starting from the high end
-         * and working down. */
-        r = 0;
-        i = bia->size - 1;
-
-        do 
-        {
-            if (a[i] > b[i])
-            { 
-                r = 1;
-                break; 
-            }
-            else if (a[i] < b[i])
-            { 
-                r = -1;
-                break; 
-            }
-        } while (--i >= 0);
-    }
-
-    return r;
-}
-
-/*
- * Allocate and zero more components.  Does not consume bi. 
- */
-static void more_comps(bigint *bi, int n)
-{
-    if (n > bi->max_comps)
-    {
-        bi->max_comps = max(bi->max_comps * 2, n);
-        bi->comps = (comp*)realloc(bi->comps, bi->max_comps * COMP_BYTE_SIZE);
-    }
-
-    if (n > bi->size)
-    {
-        memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE);
-    }
-
-    bi->size = n;
-}
-
-/*
- * Make a new empty bigint. It may just use an old one if one is available.
- * Otherwise get one off the heap.
- */
-static bigint *alloc(BI_CTX *ctx, int size)
-{
-    bigint *biR;
-
-    /* Can we recycle an old bigint? */
-    if (ctx->free_list != NULL)
-    {
-        biR = ctx->free_list;
-        ctx->free_list = biR->next;
-        ctx->free_count--;
-
-        if (biR->refs != 0)
-        {
-#ifdef CONFIG_SSL_FULL_MODE
-            printf("alloc: refs was not 0\n");
-#endif
-            abort();    /* create a stack trace from a core dump */
-        }
-
-        more_comps(biR, size);
-    }
-    else
-    {
-        /* No free bigints available - create a new one. */
-        biR = (bigint *)malloc(sizeof(bigint));
-        biR->comps = (comp*)malloc(size * COMP_BYTE_SIZE);
-        biR->max_comps = size;  /* give some space to spare */
-    }
-
-    biR->size = size;
-    biR->refs = 1;
-    biR->next = NULL;
-    ctx->active_count++;
-    return biR;
-}
-
-/*
- * Work out the highest '1' bit in an exponent. Used when doing sliding-window
- * exponentiation.
- */
-static int find_max_exp_index(bigint *biexp)
-{
-    int i = COMP_BIT_SIZE-1;
-    comp shift = COMP_RADIX/2;
-    comp test = biexp->comps[biexp->size-1];    /* assume no leading zeroes */
-
-    check(biexp);
-
-    do
-    {
-        if (test & shift)
-        {
-            return i+(biexp->size-1)*COMP_BIT_SIZE;
-        }
-
-        shift >>= 1;
-    } while (--i != 0);
-
-    return -1;      /* error - must have been a leading 0 */
-}
-
-/*
- * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window
- * exponentiation.
- */
-static int exp_bit_is_one(bigint *biexp, int offset)
-{
-    comp test = biexp->comps[offset / COMP_BIT_SIZE];
-    int num_shifts = offset % COMP_BIT_SIZE;
-    comp shift = 1;
-    int i;
-
-    check(biexp);
-
-    for (i = 0; i < num_shifts; i++)
-    {
-        shift <<= 1;
-    }
-
-    return test & shift;
-}
-
-#ifdef CONFIG_BIGINT_CHECK_ON
-/*
- * Perform a sanity check on bi.
- */
-static void check(const bigint *bi)
-{
-    if (bi->refs <= 0)
-    {
-        printf("check: zero or negative refs in bigint\n");
-        abort();
-    }
-
-    if (bi->next != NULL)
-    {
-        printf("check: attempt to use a bigint from "
-                "the free list\n");
-        abort();
-    }
-}
-#endif
-
-/*
- * Delete any leading 0's (and allow for 0).
- */
-static bigint *trim(bigint *bi)
-{
-    check(bi);
-
-    while (bi->comps[bi->size-1] == 0 && bi->size > 1)
-    {
-        bi->size--;
-    }
-
-    return bi;
-}
-
-#if defined(CONFIG_BIGINT_MONTGOMERY)
-/**
- * @brief Perform a single montgomery reduction.
- * @param ctx [in]  The bigint session context.
- * @param bixy [in]  A bigint.
- * @return The result of the montgomery reduction.
- */
-bigint *bi_mont(BI_CTX *ctx, bigint *bixy)
-{
-    int i = 0, n;
-    uint8_t mod_offset = ctx->mod_offset;
-    bigint *bim = ctx->bi_mod[mod_offset];
-    comp mod_inv = ctx->N0_dash[mod_offset];
-
-    check(bixy);
-
-    if (ctx->use_classical)     /* just use classical instead */
-    {
-        return bi_mod(ctx, bixy);
-    }
-
-    n = bim->size;
-
-    do
-    {
-        bixy = bi_add(ctx, bixy, comp_left_shift(
-                    bi_int_multiply(ctx, bim, bixy->comps[i]*mod_inv), i));
-    } while (++i < n);
-
-    comp_right_shift(bixy, n);
-
-    if (bi_compare(bixy, bim) >= 0)
-    {
-        bixy = bi_subtract(ctx, bixy, bim, NULL);
-    }
-
-    return bixy;
-}
-
-#elif defined(CONFIG_BIGINT_BARRETT)
-/*
- * Stomp on the most significant components to give the illusion of a "mod base
- * radix" operation 
- */
-static bigint *comp_mod(bigint *bi, int mod)
-{
-    check(bi);
-
-    if (bi->size > mod)
-    {
-        bi->size = mod;
-    }
-
-    return bi;
-}
-
-/*
- * Barrett reduction has no need for some parts of the product, so ignore bits
- * of the multiply. This routine gives Barrett its big performance
- * improvements over Classical/Montgomery reduction methods. 
- */
-static bigint *partial_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, 
-        int inner_partial, int outer_partial)
-{
-    int i = 0, j, n = bia->size, t = bib->size;
-    bigint *biR;
-    comp carry;
-    comp *sr, *sa, *sb;
-
-    check(bia);
-    check(bib);
-
-    biR = alloc(ctx, n + t);
-    sa = bia->comps;
-    sb = bib->comps;
-    sr = biR->comps;
-
-    if (inner_partial)
-    {
-        memset(sr, 0, inner_partial*COMP_BYTE_SIZE); 
-    }
-    else    /* outer partial */
-    {
-        if (n < outer_partial || t < outer_partial) /* should we bother? */
-        {
-            bi_free(ctx, bia);
-            bi_free(ctx, bib);
-            biR->comps[0] = 0;      /* return 0 */
-            biR->size = 1;
-            return biR;
-        }
-
-        memset(&sr[outer_partial], 0, (n+t-outer_partial)*COMP_BYTE_SIZE);
-    }
-
-    do 
-    {
-        comp *a = sa;
-        comp b = *sb++;
-        long_comp tmp;
-        int i_plus_j = i;
-        carry = 0;
-        j = n;
-
-        if (outer_partial && i_plus_j < outer_partial)
-        {
-            i_plus_j = outer_partial;
-            a = &sa[outer_partial-i];
-            j = n-(outer_partial-i);
-        }
-
-        do
-        {
-            if (inner_partial && i_plus_j >= inner_partial) 
-            {
-                break;
-            }
-
-            tmp = sr[i_plus_j] + ((long_comp)*a++)*b + carry;
-            sr[i_plus_j++] = (comp)tmp;              /* downsize */
-            carry = (comp)(tmp >> COMP_BIT_SIZE);
-        } while (--j != 0);
-
-        sr[i_plus_j] = carry;
-    } while (++i < t);
-
-    bi_free(ctx, bia);
-    bi_free(ctx, bib);
-    return trim(biR);
-}
-
-/**
- * @brief Perform a single Barrett reduction.
- * @param ctx [in]  The bigint session context.
- * @param bi [in]  A bigint.
- * @return The result of the Barrett reduction.
- */
-bigint *bi_barrett(BI_CTX *ctx, bigint *bi)
-{
-    bigint *q1, *q2, *q3, *r1, *r2, *r;
-    uint8_t mod_offset = ctx->mod_offset;
-    bigint *bim = ctx->bi_mod[mod_offset];
-    int k = bim->size;
-
-    check(bi);
-    check(bim);
-
-    /* use Classical method instead  - Barrett cannot help here */
-    if (bi->size > k*2)
-    {
-        return bi_mod(ctx, bi);
-    }
-
-    q1 = comp_right_shift(bi_clone(ctx, bi), k-1);
-
-    /* do outer partial multiply */
-    q2 = partial_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k-1); 
-    q3 = comp_right_shift(q2, k+1);
-    r1 = comp_mod(bi, k+1);
-
-    /* do inner partial multiply */
-    r2 = comp_mod(partial_multiply(ctx, q3, bim, k+1, 0), k+1);
-    r = bi_subtract(ctx, r1, r2, NULL);
-
-    /* if (r >= m) r = r - m; */
-    if (bi_compare(r, bim) >= 0)
-    {
-        r = bi_subtract(ctx, r, bim, NULL);
-    }
-
-    return r;
-}
-#endif /* CONFIG_BIGINT_BARRETT */
-
-#ifdef CONFIG_BIGINT_SLIDING_WINDOW
-/*
- * Work out g1, g3, g5, g7... etc for the sliding-window algorithm 
- */
-static void precompute_slide_window(BI_CTX *ctx, int window, bigint *g1)
-{
-    int k = 1, i;
-    bigint *g2;
-
-    for (i = 0; i < window-1; i++)   /* compute 2^(window-1) */
-    {
-        k <<= 1;
-    }
-
-    ctx->g = (bigint **)malloc(k*sizeof(bigint *));
-    ctx->g[0] = bi_clone(ctx, g1);
-    bi_permanent(ctx->g[0]);
-    g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0]));   /* g^2 */
-
-    for (i = 1; i < k; i++)
-    {
-        ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i-1], bi_copy(g2)));
-        bi_permanent(ctx->g[i]);
-    }
-
-    bi_free(ctx, g2);
-    ctx->window = k;
-}
-#endif
-
-/**
- * @brief Perform a modular exponentiation.
- *
- * This function requires bi_set_mod() to have been called previously. This is 
- * one of the optimisations used for performance.
- * @param ctx [in]  The bigint session context.
- * @param bi  [in]  The bigint on which to perform the mod power operation.
- * @param biexp [in] The bigint exponent.
- * @see bi_set_mod().
- */
-bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp)
-{
-    int i = find_max_exp_index(biexp), j, window_size = 1;
-    bigint *biR = int_to_bi(ctx, 1);
-
-#if defined(CONFIG_BIGINT_MONTGOMERY)
-    uint8_t mod_offset = ctx->mod_offset;
-    if (!ctx->use_classical)
-    {
-        /* preconvert */
-        bi = bi_mont(ctx, 
-                bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset]));    /* x' */
-        bi_free(ctx, biR);
-        biR = ctx->bi_R_mod_m[mod_offset];                              /* A */
-    }
-#endif
-
-    check(bi);
-    check(biexp);
-
-#ifdef CONFIG_BIGINT_SLIDING_WINDOW
-    for (j = i; j > 32; j /= 5) /* work out an optimum size */
-        window_size++;
-
-    /* work out the slide constants */
-    precompute_slide_window(ctx, window_size, bi);
-#else   /* just one constant */
-    ctx->g = (bigint **)malloc(sizeof(bigint *));
-    ctx->g[0] = bi_clone(ctx, bi);
-    ctx->window = 1;
-    bi_permanent(ctx->g[0]);
-#endif
-
-    /* if sliding-window is off, then only one bit will be done at a time and
-     * will reduce to standard left-to-right exponentiation */
-    do
-    {
-        if (exp_bit_is_one(biexp, i))
-        {
-            int l = i-window_size+1;
-            int part_exp = 0;
-
-            if (l < 0)  /* LSB of exponent will always be 1 */
-                l = 0;
-            else
-            {
-                while (exp_bit_is_one(biexp, l) == 0)
-                    l++;    /* go back up */
-            }
-
-            /* build up the section of the exponent */
-            for (j = i; j >= l; j--)
-            {
-                biR = bi_residue(ctx, bi_square(ctx, biR));
-                if (exp_bit_is_one(biexp, j))
-                    part_exp++;
-
-                if (j != l)
-                    part_exp <<= 1;
-            }
-
-            part_exp = (part_exp-1)/2;  /* adjust for array */
-            biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp]));
-            i = l-1;
-        }
-        else    /* square it */
-        {
-            biR = bi_residue(ctx, bi_square(ctx, biR));
-            i--;
-        }
-    } while (i >= 0);
-     
-    /* cleanup */
-    for (i = 0; i < ctx->window; i++)
-    {
-        bi_depermanent(ctx->g[i]);
-        bi_free(ctx, ctx->g[i]);
-    }
-
-    free(ctx->g);
-    bi_free(ctx, bi);
-    bi_free(ctx, biexp);
-#if defined CONFIG_BIGINT_MONTGOMERY
-    return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */
-#else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */
-    return biR;
-#endif
-}
-
-#ifdef CONFIG_SSL_CERT_VERIFICATION
-/**
- * @brief Perform a modular exponentiation using a temporary modulus.
- *
- * We need this function to check the signatures of certificates. The modulus
- * of this function is temporary as it's just used for authentication.
- * @param ctx [in]  The bigint session context.
- * @param bi  [in]  The bigint to perform the exp/mod.
- * @param bim [in]  The temporary modulus.
- * @param biexp [in] The bigint exponent.
- * @see bi_set_mod().
- */
-bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp)
-{
-    bigint *biR, *tmp_biR;
-
-    /* Set up a temporary bigint context and transfer what we need between
-     * them. We need to do this since we want to keep the original modulus
-     * which is already in this context. This operation is only called when
-     * doing peer verification, and so is not expensive :-) */
-    BI_CTX *tmp_ctx = bi_initialize();
-    bi_set_mod(tmp_ctx, bi_clone(tmp_ctx, bim), BIGINT_M_OFFSET);
-    tmp_biR = bi_mod_power(tmp_ctx, 
-                bi_clone(tmp_ctx, bi), 
-                bi_clone(tmp_ctx, biexp));
-    biR = bi_clone(ctx, tmp_biR);
-    bi_free(tmp_ctx, tmp_biR);
-    bi_free_mod(tmp_ctx, BIGINT_M_OFFSET);
-    bi_terminate(tmp_ctx);
-
-    bi_free(ctx, bi);
-    bi_free(ctx, bim);
-    bi_free(ctx, biexp);
-    return biR;
-}
-#endif
-/** @} */
diff --git a/roms/ipxe/src/crypto/axtls/bigint.h b/roms/ipxe/src/crypto/axtls/bigint.h
index f5f3353110735c9d993ce1abaee2..1f38c53d63adac8d0d198b61a219 100644
--- a/roms/ipxe/src/crypto/axtls/bigint.h
+++ b/roms/ipxe/src/crypto/axtls/bigint.h
@@ -1,44 +1,43 @@
 /*
- *  Copyright(C) 2006 Cameron Rich
+ * Copyright (c) 2007, Cameron Rich
  *
- *  This library is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU Lesser General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ * All rights reserved.
  *
- *  This library 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 Lesser General Public License for more details.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
  *
- *  You should have received a copy of the GNU Lesser General Public License
- *  along with this library; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * * 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 axTLS project 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.
  */
 
-FILE_LICENCE ( GPL2_OR_LATER );
-
 #ifndef BIGINT_HEADER
 #define BIGINT_HEADER
 
-/* enable features based on a 'super-set' capbaility. */
-#if defined(CONFIG_SSL_FULL_MODE) 
-#define CONFIG_SSL_ENABLE_CLIENT
-#define CONFIG_SSL_CERT_VERIFICATION
-#elif defined(CONFIG_SSL_ENABLE_CLIENT)
-#define CONFIG_SSL_CERT_VERIFICATION
-#endif
-
-#include "os_port.h"
-#include "bigint_impl.h"
+#include "crypto.h"
 
-#ifndef CONFIG_BIGINT_CHECK_ON
-#define check(A)                /**< disappears in normal production mode */
-#endif
 BI_CTX *bi_initialize(void);
 void bi_terminate(BI_CTX *ctx);
 void bi_permanent(bigint *bi);
 void bi_depermanent(bigint *bi);
+void bi_clear_cache(BI_CTX *ctx);
 void bi_free(BI_CTX *ctx, bigint *bi);
 bigint *bi_copy(bigint *bi);
 bigint *bi_clone(BI_CTX *ctx, const bigint *bi);
@@ -90,4 +89,11 @@ bigint *bi_square(BI_CTX *ctx, bigint *bi);
 #define bi_square(A, B)     bi_multiply(A, bi_copy(B), B)
 #endif
 
+#ifdef CONFIG_BIGINT_CRT
+bigint *bi_crt(BI_CTX *ctx, bigint *bi,
+        bigint *dP, bigint *dQ,
+        bigint *p, bigint *q,
+        bigint *qInv);
+#endif
+
 #endif
diff --git a/roms/ipxe/src/crypto/axtls/bigint_impl.h b/roms/ipxe/src/crypto/axtls/bigint_impl.h
index 762a7ccbb2754fc6e4ecf8623826..09d8550ea2c4be851d01860e9aa2 100644
--- a/roms/ipxe/src/crypto/axtls/bigint_impl.h
+++ b/roms/ipxe/src/crypto/axtls/bigint_impl.h
@@ -1,19 +1,31 @@
 /*
- *  Copyright(C) 2006 Cameron Rich
+ * Copyright (c) 2007, Cameron Rich
  *
- *  This library is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU Lesser General Public License as published by
- *  the Free Software Foundation; either version 2.1 of the License, or
- *  (at your option) any later version.
+ * All rights reserved.
  *
- *  This library 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 Lesser General Public License for more details.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
  *
- *  You should have received a copy of the GNU Lesser General Public License
- *  along with this library; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * * 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 axTLS project 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.
  */
 
 #ifndef BIGINT_IMPL_HEADER
@@ -30,20 +42,39 @@
 #endif
 
 /* Architecture specific functions for big ints */
+#if defined(CONFIG_INTEGER_8BIT)
+#define COMP_RADIX          256U       /**< Max component + 1 */
+#define COMP_MAX            0xFFFFU/**< (Max dbl comp -1) */
+#define COMP_BIT_SIZE       8   /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE      1   /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES    2   /**< Used For diagnostics only. */
+typedef uint8_t comp;	        /**< A single precision component. */
+typedef uint16_t long_comp;     /**< A double precision component. */
+typedef int16_t slong_comp;     /**< A signed double precision component. */
+#elif defined(CONFIG_INTEGER_16BIT)
+#define COMP_RADIX          65536U       /**< Max component + 1 */
+#define COMP_MAX            0xFFFFFFFFU/**< (Max dbl comp -1) */
+#define COMP_BIT_SIZE       16  /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE      2   /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES    4   /**< Used For diagnostics only. */
+typedef uint16_t comp;	        /**< A single precision component. */
+typedef uint32_t long_comp;     /**< A double precision component. */
+typedef int32_t slong_comp;     /**< A signed double precision component. */
+#else /* regular 32 bit */
 #ifdef WIN32
 #define COMP_RADIX          4294967296i64         
-#define COMP_BIG_MSB        0x8000000000000000i64 
+#define COMP_MAX            0xFFFFFFFFFFFFFFFFui64
 #else
 #define COMP_RADIX          4294967296ULL         /**< Max component + 1 */
-#define COMP_BIG_MSB        0x8000000000000000ULL /**< (Max dbl comp + 1)/ 2 */
+#define COMP_MAX            0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */
 #endif
 #define COMP_BIT_SIZE       32  /**< Number of bits in a component. */
 #define COMP_BYTE_SIZE      4   /**< Number of bytes in a component. */
 #define COMP_NUM_NIBBLES    8   /**< Used For diagnostics only. */
-
 typedef uint32_t comp;	        /**< A single precision component. */
 typedef uint64_t long_comp;     /**< A double precision component. */
 typedef int64_t slong_comp;     /**< A signed double precision component. */
+#endif
 
 /**
  * @struct  _bigint
@@ -97,9 +128,4 @@ typedef struct /**< A big integer "session" context. */
 
 #define PERMANENT           0x7FFF55AA  /**< A magic number for permanents. */
 
-#define V1      v->comps[v->size-1]                 /**< v1 for division */
-#define V2      v->comps[v->size-2]                 /**< v2 for division */
-#define U(j)    tmp_u->comps[tmp_u->size-j-1]       /**< uj for division */
-#define Q(j)    quotient->comps[quotient->size-j-1] /**< qj for division */
-
 #endif
diff --git a/roms/ipxe/src/crypto/axtls/config.h b/roms/ipxe/src/crypto/axtls/config.h
new file mode 100644
index 0000000000000000000000000000000000000000..32fa3bf039cd2ad04151eec514c933bddfcff81a
--- /dev/null
+++ b/roms/ipxe/src/crypto/axtls/config.h
@@ -0,0 +1,13 @@
+#ifndef AXTLS_CONFIG_H
+#define AXTLS_CONFIG_H
+
+/**
+ * @file config.h
+ *
+ * Trick the axtls code into building within our build environment.
+ */
+
+#define CONFIG_SSL_ENABLE_CLIENT 1
+#define CONFIG_BIGINT_CLASSICAL 1
+
+#endif
diff --git a/roms/ipxe/src/crypto/axtls/crypto.h b/roms/ipxe/src/crypto/axtls/crypto.h
index a9893cf35a60a231a22cb8daac17..2c4cda4de4afc3694b078f3cee42 100644
--- a/roms/ipxe/src/crypto/axtls/crypto.h
+++ b/roms/ipxe/src/crypto/axtls/crypto.h
@@ -1,23 +1,33 @@
 /*
- *  Copyright(C) 2006 Cameron Rich
+ * Copyright (c) 2007, Cameron Rich
  *
- *  This library is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU Lesser General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ * All rights reserved.
  *
- *  This library 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 Lesser General Public License for more details.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
  *
- *  You should have received a copy of the GNU Lesser General Public License
- *  along with this library; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * * 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 axTLS project 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.
  */
 
-FILE_LICENCE ( GPL2_OR_LATER );
-
 /**
  * @file crypto.h
  */
@@ -29,20 +39,40 @@ FILE_LICENCE ( GPL2_OR_LATER );
 extern "C" {
 #endif
 
+#include "config.h"
+#include "bigint_impl.h"
 #include "bigint.h"
 
+#ifndef STDCALL
+#define STDCALL
+#endif
+#ifndef EXP_FUNC
+#define EXP_FUNC
+#endif
+
+
+/* enable features based on a 'super-set' capbaility. */
+#if defined(CONFIG_SSL_FULL_MODE)
+#define CONFIG_SSL_ENABLE_CLIENT
+#define CONFIG_SSL_CERT_VERIFICATION
+#elif defined(CONFIG_SSL_ENABLE_CLIENT)
+#define CONFIG_SSL_CERT_VERIFICATION
+#endif
+
 /**************************************************************************
  * AES declarations 
  **************************************************************************/
 
 #define AES_MAXROUNDS			14
+#define AES_BLOCKSIZE           16
+#define AES_IV_SIZE             16
 
 typedef struct aes_key_st 
 {
     uint16_t rounds;
     uint16_t key_size;
     uint32_t ks[(AES_MAXROUNDS+1)*8];
-    uint8_t iv[16];
+    uint8_t iv[AES_IV_SIZE];
 } AES_CTX;
 
 typedef enum
@@ -57,8 +87,6 @@ void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg,
         uint8_t *out, int length);
 void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length);
 void AES_convert_key(AES_CTX *ctx);
-void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
-void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
 
 /**************************************************************************
  * RC4 declarations 
@@ -66,7 +94,7 @@ void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
 
 typedef struct 
 {
-    int x, y, m[256];
+    uint8_t x, y, m[256];
 } RC4_CTX;
 
 void RC4_setup(RC4_CTX *s, const uint8_t *key, int length);
@@ -84,22 +112,38 @@ void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length);
  */
 typedef struct 
 {
-    uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest  */
-    uint32_t Length_Low;            /* Message length in bits      */
-    uint32_t Length_High;           /* Message length in bits      */
+    uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */
+    uint32_t Length_Low;            /* Message length in bits */
+    uint32_t Length_High;           /* Message length in bits */
     uint16_t Message_Block_Index;   /* Index into message block array   */
-    uint8_t Message_Block[64];      /* 512-bit message blocks      */
+    uint8_t Message_Block[64];      /* 512-bit message blocks */
 } SHA1_CTX;
 
-void SHA1Init(SHA1_CTX *);
-void SHA1Update(SHA1_CTX *, const uint8_t * msg, int len);
-void SHA1Final(SHA1_CTX *, uint8_t *digest);
+void SHA1_Init(SHA1_CTX *);
+void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len);
+void SHA1_Final(uint8_t *digest, SHA1_CTX *);
 
 /**************************************************************************
- * MD5 declarations 
+ * MD2 declarations
  **************************************************************************/
 
-/* MD5 context. */
+#define MD2_SIZE 16
+
+typedef struct
+{
+    unsigned char cksum[16];    /* checksum of the data block */
+    unsigned char state[48];    /* intermediate digest state */
+    unsigned char buffer[16];   /* data block being processed */
+    int left;                   /* amount of data in buffer */
+} MD2_CTX;
+
+EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx);
+EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen);
+EXP_FUNC void STDCALL MD2_Final(uint8_t *digest, MD2_CTX *ctx);
+
+/**************************************************************************
+ * MD5 declarations
+ **************************************************************************/
 
 #define MD5_SIZE    16
 
@@ -110,9 +154,9 @@ typedef struct
   uint8_t buffer[64];       /* input buffer */
 } MD5_CTX;
 
-void MD5Init(MD5_CTX *);
-void MD5Update(MD5_CTX *, const uint8_t *msg, int len);
-void MD5Final(MD5_CTX *, uint8_t *digest);
+EXP_FUNC void STDCALL MD5_Init(MD5_CTX *);
+EXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len);
+EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *);
 
 /**************************************************************************
  * HMAC declarations 
@@ -122,19 +166,6 @@ void hmac_md5(const uint8_t *msg, int length, const uint8_t *key,
 void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, 
         int key_len, uint8_t *digest);
 
-/**************************************************************************
- * RNG declarations 
- **************************************************************************/
-void RNG_initialize(const uint8_t *seed_buf, int size);
-void RNG_terminate(void);
-void get_random(int num_rand_bytes, uint8_t *rand_data);
-//void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
-
-#include <string.h>
-static inline void get_random_NZ(int num_rand_bytes, uint8_t *rand_data) {
-	memset ( rand_data, 0x01, num_rand_bytes );
-}
-
 /**************************************************************************
  * RSA declarations 
  **************************************************************************/
@@ -152,7 +183,6 @@ typedef struct
     bigint *qInv;           /* q^-1 mod p */
 #endif
     int num_octets;
-    bigint *sig_m;         /* signature modulus */
     BI_CTX *bi_ctx;
 } RSA_CTX;
 
@@ -175,125 +205,22 @@ void RSA_free(RSA_CTX *ctx);
 int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
         int is_decryption);
 bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg);
-#ifdef CONFIG_SSL_CERT_VERIFICATION
-bigint *RSA_raw_sign_verify(RSA_CTX *c, bigint *bi_msg);
+#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
 bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
         bigint *modulus, bigint *pub_exp);
-bigint *RSA_public(const RSA_CTX *c, bigint *bi_msg);
+bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg);
 int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, 
         uint8_t *out_data, int is_signing);
 void RSA_print(const RSA_CTX *ctx);
 #endif
 
 /**************************************************************************
- * ASN1 declarations 
- **************************************************************************/
-#define X509_OK                             0
-#define X509_NOT_OK                         -1
-#define X509_VFY_ERROR_NO_TRUSTED_CERT      -2
-#define X509_VFY_ERROR_BAD_SIGNATURE        -3      
-#define X509_VFY_ERROR_NOT_YET_VALID        -4
-#define X509_VFY_ERROR_EXPIRED              -5
-#define X509_VFY_ERROR_SELF_SIGNED          -6
-#define X509_VFY_ERROR_INVALID_CHAIN        -7
-#define X509_VFY_ERROR_UNSUPPORTED_DIGEST   -8
-#define X509_INVALID_PRIV_KEY               -9
-
-/*
- * The Distinguished Name
- */
-#define X509_NUM_DN_TYPES                   3
-#define X509_COMMON_NAME                    0
-#define X509_ORGANIZATION                   1
-#define X509_ORGANIZATIONAL_TYPE            2
-
-#define ASN1_INTEGER            0x02
-#define ASN1_BIT_STRING         0x03
-#define ASN1_OCTET_STRING       0x04
-#define ASN1_NULL               0x05
-#define ASN1_OID                0x06
-#define ASN1_PRINTABLE_STR      0x13
-#define ASN1_TELETEX_STR        0x14
-#define ASN1_IA5_STR            0x16
-#define ASN1_UTC_TIME           0x17
-#define ASN1_SEQUENCE           0x30
-#define ASN1_SET                0x31
-#define ASN1_IMPLICIT_TAG       0x80
-#define ASN1_EXPLICIT_TAG       0xa0
-
-#define SALT_SIZE               8
-
-struct _x509_ctx
-{
-    char *ca_cert_dn[X509_NUM_DN_TYPES];
-    char *cert_dn[X509_NUM_DN_TYPES];
-#if defined(_WIN32_WCE)
-    long not_before;
-    long not_after;
-#else
-    time_t not_before;
-    time_t not_after;
-#endif
-    uint8_t *signature;
-    uint16_t sig_len;
-    uint8_t sig_type;
-    RSA_CTX *rsa_ctx;
-    bigint *digest;
-    struct _x509_ctx *next;
-};
-
-typedef struct _x509_ctx X509_CTX;
-
-#ifdef CONFIG_SSL_CERT_VERIFICATION
-typedef struct 
-{
-    X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS];
-} CA_CERT_CTX;
-#endif
-
-int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx);
-int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type);
-int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type);
-int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object);
-int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx);
-void x509_free(X509_CTX *x509_ctx);
-#ifdef CONFIG_SSL_CERT_VERIFICATION
-int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);
-const uint8_t *x509_get_signature(const uint8_t *asn1_signature, int *len);
-#endif
-#ifdef CONFIG_SSL_FULL_MODE
-void x509_print(CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);
-void x509_display_error(int error);
-#endif
-
-/**************************************************************************
- * MISC declarations 
+ * RNG declarations
  **************************************************************************/
-
-extern const char * const unsupported_str;
-
-typedef void (*crypt_func)(void *, const uint8_t *, uint8_t *, int);
-typedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key, 
-        int key_len, uint8_t *digest);
-
-typedef struct
-{
-    uint8_t *pre_data;	/* include the ssl record bytes */
-    uint8_t *data;	/* the regular ssl data */
-    int max_len;
-    int index;
-} BUF_MEM;
-
-BUF_MEM buf_new(void);
-void buf_grow(BUF_MEM *bm, int len);
-void buf_free(BUF_MEM *bm);
-int get_file(const char *filename, uint8_t **buf);
-
-#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG)
-void print_blob(const char *format, const uint8_t *data, int size, ...);
-#else
-    #define print_blob(...)
-#endif
+EXP_FUNC void STDCALL RNG_initialize(const uint8_t *seed_buf, int size);
+EXP_FUNC void STDCALL RNG_terminate(void);
+EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data);
+void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
 
 #ifdef __cplusplus
 }
diff --git a/roms/ipxe/src/crypto/axtls/os_port.h b/roms/ipxe/src/crypto/axtls/os_port.h
index babdbfad833862ca9c093a71940e..76313e204be79577220fc27ce6d6 100644
--- a/roms/ipxe/src/crypto/axtls/os_port.h
+++ b/roms/ipxe/src/crypto/axtls/os_port.h
@@ -1,61 +1,54 @@
+#ifndef AXTLS_OS_PORT_H
+#define AXTLS_OS_PORT_H
+
 /**
  * @file os_port.h
  *
  * Trick the axtls code into building within our build environment.
  */
 
-#ifndef HEADER_OS_PORT_H
-#define HEADER_OS_PORT_H
-
 #include <stdint.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <time.h>
-#include <sys/time.h>
 #include <byteswap.h>
 
-#define STDCALL
-#define EXP_FUNC
-#define TTY_FLUSH()
+/** All imported axTLS files are licensed using the three-clause BSD licence */
+FILE_LICENCE ( BSD3 );
 
 /** We can't actually abort, since we are effectively a kernel... */
 #define abort() assert ( 0 )
 
-/** crypto_misc.c has a bad #ifdef */
-static inline void close ( int fd __unused ) {
-	/* Do nothing */
+/** rsa.c uses alloca() */
+#define alloca( size ) __builtin_alloca ( size )
+
+#include <ipxe/random_nz.h>
+static inline void get_random_NZ ( int num_rand_bytes, uint8_t *rand_data ) {
+	/* AXTLS does not check for failures when generating random
+	 * data.  Rely on the fact that get_random_nz() does not
+	 * request prediction resistance (and so cannot introduce new
+	 * failures) and therefore any potential failure must already
+	 * have been encountered by e.g. tls_generate_random(), which
+	 * does check for failures.
+	 */
+	get_random_nz ( rand_data, num_rand_bytes );
 }
 
-typedef void FILE;
-
-static inline FILE * fopen ( const char *filename __unused,
-			     const char *mode __unused ) {
-	return NULL;
-}
+/* Expose AES_encrypt() and AES_decrypt() in aes.o */
+#define aes 1
+#if OBJECT
 
-static inline int fseek ( FILE *stream __unused, long offset __unused,
-			  int whence __unused ) {
-	return -1;
-}
+struct aes_key_st;
 
-static inline long ftell ( FILE *stream __unused ) {
-	return -1;
-}
+static void AES_encrypt ( const struct aes_key_st *ctx, uint32_t *data );
+static void AES_decrypt ( const struct aes_key_st *ctx, uint32_t *data );
 
-static inline size_t fread ( void *ptr __unused, size_t size __unused,
-			     size_t nmemb __unused, FILE *stream __unused ) {
-	return -1;
+void axtls_aes_encrypt ( void *ctx, uint32_t *data ) {
+	AES_encrypt ( ctx, data );
 }
 
-static inline int fclose ( FILE *stream __unused ) {
-	return -1;
+void axtls_aes_decrypt ( void *ctx, uint32_t *data ) {
+	AES_decrypt ( ctx, data );
 }
 
-#define CONFIG_SSL_CERT_VERIFICATION 1
-#define CONFIG_SSL_MAX_CERTS 1
-#define CONFIG_X509_MAX_CA_CERTS 1
-#define CONFIG_SSL_EXPIRY_TIME 24
-#define CONFIG_SSL_ENABLE_CLIENT 1
-#define CONFIG_BIGINT_CLASSICAL 1
+#endif
+#undef aes
 
 #endif 
diff --git a/roms/ipxe/src/crypto/axtls/rsa.c b/roms/ipxe/src/crypto/axtls/rsa.c
deleted file mode 100644
index 389eda577818aa8d2c596663ed88c6562a4e3b44..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/crypto/axtls/rsa.c
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- *  Copyright(C) 2006 Cameron Rich
- *
- *  This library is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU Lesser General Public License as published by
- *  the Free Software Foundation; either version 2.1 of the License, or
- *  (at your option) any later version.
- *
- *  This library 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 Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public License
- *  along with this library; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * Implements the RSA public encryption algorithm. Uses the bigint library to
- * perform its calculations.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <stdlib.h>
-#include "crypto.h"
-
-#ifdef CONFIG_BIGINT_CRT
-static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi);
-#endif
-
-void RSA_priv_key_new(RSA_CTX **ctx, 
-        const uint8_t *modulus, int mod_len,
-        const uint8_t *pub_exp, int pub_len,
-        const uint8_t *priv_exp, int priv_len
-#if CONFIG_BIGINT_CRT
-      , const uint8_t *p, int p_len,
-        const uint8_t *q, int q_len,
-        const uint8_t *dP, int dP_len,
-        const uint8_t *dQ, int dQ_len,
-        const uint8_t *qInv, int qInv_len
-#endif
-    )
-{
-    RSA_CTX *rsa_ctx;
-    BI_CTX *bi_ctx;
-    RSA_pub_key_new(ctx, modulus, mod_len, pub_exp, pub_len);
-    rsa_ctx = *ctx;
-    bi_ctx = rsa_ctx->bi_ctx;
-    rsa_ctx->d = bi_import(bi_ctx, priv_exp, priv_len);
-    bi_permanent(rsa_ctx->d);
-
-#ifdef CONFIG_BIGINT_CRT
-    rsa_ctx->p = bi_import(bi_ctx, p, p_len);
-    rsa_ctx->q = bi_import(bi_ctx, q, q_len);
-    rsa_ctx->dP = bi_import(bi_ctx, dP, dP_len);
-    rsa_ctx->dQ = bi_import(bi_ctx, dQ, dQ_len);
-    rsa_ctx->qInv = bi_import(bi_ctx, qInv, qInv_len);
-    bi_permanent(rsa_ctx->dP);
-    bi_permanent(rsa_ctx->dQ);
-    bi_permanent(rsa_ctx->qInv);
-    bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET);
-    bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET);
-#endif
-}
-
-void RSA_pub_key_new(RSA_CTX **ctx, 
-        const uint8_t *modulus, int mod_len,
-        const uint8_t *pub_exp, int pub_len)
-{
-    RSA_CTX *rsa_ctx;
-    BI_CTX *bi_ctx = bi_initialize();
-    *ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX));
-    rsa_ctx = *ctx;
-    rsa_ctx->bi_ctx = bi_ctx;
-    rsa_ctx->num_octets = (mod_len & 0xFFF0);
-    rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len);
-    bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET);
-    rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len);
-    bi_permanent(rsa_ctx->e);
-}
-
-/**
- * Free up any RSA context resources.
- */
-void RSA_free(RSA_CTX *rsa_ctx)
-{
-    BI_CTX *bi_ctx;
-    if (rsa_ctx == NULL)                /* deal with ptrs that are null */
-        return;
-
-    bi_ctx = rsa_ctx->bi_ctx;
-
-    bi_depermanent(rsa_ctx->e);
-    bi_free(bi_ctx, rsa_ctx->e);
-    bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET);
-
-    if (rsa_ctx->d)
-    {
-        bi_depermanent(rsa_ctx->d);
-        bi_free(bi_ctx, rsa_ctx->d);
-#ifdef CONFIG_BIGINT_CRT
-        bi_depermanent(rsa_ctx->dP);
-        bi_depermanent(rsa_ctx->dQ);
-        bi_depermanent(rsa_ctx->qInv);
-        bi_free(bi_ctx, rsa_ctx->dP);
-        bi_free(bi_ctx, rsa_ctx->dQ);
-        bi_free(bi_ctx, rsa_ctx->qInv);
-        bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET);
-        bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET);
-#endif
-    }
-
-    bi_terminate(bi_ctx);
-    free(rsa_ctx);
-}
-
-/**
- * @brief Use PKCS1.5 for decryption/verification.
- * @param ctx [in] The context
- * @param in_data [in] The data to encrypt (must be < modulus size-11)
- * @param out_data [out] The encrypted data.
- * @param is_decryption [in] Decryption or verify operation.
- * @return  The number of bytes that were originally encrypted. -1 on error.
- * @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
- */
-int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, 
-                            uint8_t *out_data, int is_decryption)
-{
-    int byte_size = ctx->num_octets;
-    uint8_t *block;
-    int i, size;
-    bigint *decrypted_bi, *dat_bi;
-
-    memset(out_data, 0, byte_size); /* initialise */
-
-    /* decrypt */
-    dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size);
-#ifdef CONFIG_SSL_CERT_VERIFICATION
-    decrypted_bi = is_decryption ?  /* decrypt or verify? */
-            RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi);
-#else   /* always a decryption */
-    decrypted_bi = RSA_private(ctx, dat_bi);
-#endif
-
-    /* convert to a normal block */
-    block = (uint8_t *)malloc(byte_size);
-    bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size);
-
-    i = 10; /* start at the first possible non-padded byte */
-
-#ifdef CONFIG_SSL_CERT_VERIFICATION
-    if (is_decryption == 0) /* PKCS1.5 signing pads with "0xff"s */
-    {
-        while (block[i++] == 0xff && i < byte_size);
-
-        if (block[i-2] != 0xff)
-            i = byte_size;     /*ensure size is 0 */   
-    }
-    else                    /* PKCS1.5 encryption padding is random */
-#endif
-    {
-        while (block[i++] && i < byte_size);
-    }
-    size = byte_size - i;
-
-    /* get only the bit we want */
-    if (size > 0)
-        memcpy(out_data, &block[i], size);
-    
-    free(block);
-    return size ? size : -1;
-}
-
-/**
- * Performs m = c^d mod n
- */
-bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg)
-{
-#ifdef CONFIG_BIGINT_CRT
-    return bi_crt(c, bi_msg);
-#else
-    BI_CTX *ctx = c->bi_ctx;
-    ctx->mod_offset = BIGINT_M_OFFSET;
-    return bi_mod_power(ctx, bi_msg, c->d);
-#endif
-}
-
-#ifdef CONFIG_BIGINT_CRT
-/**
- * Use the Chinese Remainder Theorem to quickly perform RSA decrypts.
- * This should really be in bigint.c (and was at one stage), but needs 
- * access to the RSA_CTX context...
- */
-static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi)
-{
-    BI_CTX *ctx = rsa->bi_ctx;
-    bigint *m1, *m2, *h;
-
-    /* Montgomery has a condition the 0 < x, y < m and these products violate
-     * that condition. So disable Montgomery when using CRT */
-#if defined(CONFIG_BIGINT_MONTGOMERY)
-    ctx->use_classical = 1;
-#endif
-    ctx->mod_offset = BIGINT_P_OFFSET;
-    m1 = bi_mod_power(ctx, bi_copy(bi), rsa->dP);
-
-    ctx->mod_offset = BIGINT_Q_OFFSET;
-    m2 = bi_mod_power(ctx, bi, rsa->dQ);
-
-    h = bi_subtract(ctx, bi_add(ctx, m1, rsa->p), bi_copy(m2), NULL);
-    h = bi_multiply(ctx, h, rsa->qInv);
-    ctx->mod_offset = BIGINT_P_OFFSET;
-    h = bi_residue(ctx, h);
-#if defined(CONFIG_BIGINT_MONTGOMERY)
-    ctx->use_classical = 0;         /* reset for any further operation */
-#endif
-    return bi_add(ctx, m2, bi_multiply(ctx, rsa->q, h));
-}
-#endif
-
-#ifdef CONFIG_SSL_FULL_MODE
-/**
- * Used for diagnostics.
- */
-void RSA_print(const RSA_CTX *rsa_ctx) 
-{
-    if (rsa_ctx == NULL)
-        return;
-
-    printf("-----------------   RSA DEBUG   ----------------\n");
-    printf("Size:\t%d\n", rsa_ctx->num_octets);
-    bi_print("Modulus", rsa_ctx->m);
-    bi_print("Public Key", rsa_ctx->e);
-    bi_print("Private Key", rsa_ctx->d);
-}
-#endif
-
-#ifdef CONFIG_SSL_CERT_VERIFICATION
-/**
- * Performs c = m^e mod n
- */
-bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg)
-{
-    c->bi_ctx->mod_offset = BIGINT_M_OFFSET;
-    return bi_mod_power(c->bi_ctx, bi_msg, c->e);
-}
-
-/**
- * Use PKCS1.5 for encryption/signing.
- * see http://www.rsasecurity.com/rsalabs/node.asp?id=2125
- */
-int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, 
-        uint8_t *out_data, int is_signing)
-{
-    int byte_size = ctx->num_octets;
-    int num_pads_needed = byte_size-in_len-3;
-    bigint *dat_bi, *encrypt_bi;
-
-    /* note: in_len+11 must be > byte_size */
-    out_data[0] = 0;     /* ensure encryption block is < modulus */
-
-    if (is_signing)
-    {
-        out_data[1] = 1;        /* PKCS1.5 signing pads with "0xff"'s */
-        memset(&out_data[2], 0xff, num_pads_needed);
-    }
-    else /* randomize the encryption padding with non-zero bytes */   
-    {
-        out_data[1] = 2;
-        get_random_NZ(num_pads_needed, &out_data[2]);
-    }
-
-    out_data[2+num_pads_needed] = 0;
-    memcpy(&out_data[3+num_pads_needed], in_data, in_len);
-
-    /* now encrypt it */
-    dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size);
-    encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) : 
-        RSA_public(ctx, dat_bi);
-    bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size);
-    return byte_size;
-}
-
-#if 0
-/**
- * Take a signature and decrypt it.
- */
-bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
-        bigint *modulus, bigint *pub_exp)
-{
-    uint8_t *block;
-    int i, size;
-    bigint *decrypted_bi, *dat_bi;
-    bigint *bir = NULL;
-
-    block = (uint8_t *)malloc(sig_len);
-
-    /* decrypt */
-    dat_bi = bi_import(ctx, sig, sig_len);
-    ctx->mod_offset = BIGINT_M_OFFSET;
-
-    /* convert to a normal block */
-    decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp);
-
-    bi_export(ctx, decrypted_bi, block, sig_len);
-    ctx->mod_offset = BIGINT_M_OFFSET;
-
-    i = 10; /* start at the first possible non-padded byte */
-    while (block[i++] && i < sig_len);
-    size = sig_len - i;
-
-    /* get only the bit we want */
-    if (size > 0)
-    {
-        int len;
-        const uint8_t *sig_ptr = x509_get_signature(&block[i], &len);
-
-        if (sig_ptr)
-        {
-            bir = bi_import(ctx, sig_ptr, len);
-        }
-    }
-
-    free(block);
-    return bir;
-}
-#endif
-
-#endif  /* CONFIG_SSL_CERT_VERIFICATION */
diff --git a/roms/ipxe/src/crypto/axtls/sha1.c b/roms/ipxe/src/crypto/axtls/sha1.c
deleted file mode 100644
index 9a42801f25079262f04464f29b084ed5e1d6513f..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/crypto/axtls/sha1.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- *  Copyright(C) 2006 Cameron Rich
- *
- *  This library is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU Lesser General Public License as published by
- *  the Free Software Foundation; either version 2.1 of the License, or
- *  (at your option) any later version.
- *
- *  This library 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 Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public License
- *  along with this library; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-/**
- * SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995.
- * This code was originally taken from RFC3174
- */
-
-#include <string.h>
-#include "crypto.h"
-
-/*
- *  Define the SHA1 circular left shift macro
- */
-#define SHA1CircularShift(bits,word) \
-                (((word) << (bits)) | ((word) >> (32-(bits))))
-
-/* ----- static functions ----- */
-static void SHA1PadMessage(SHA1_CTX *ctx);
-static void SHA1ProcessMessageBlock(SHA1_CTX *ctx);
-
-/**
- * Initialize the SHA1 context 
- */
-void SHA1Init(SHA1_CTX *ctx)
-{
-    ctx->Length_Low             = 0;
-    ctx->Length_High            = 0;
-    ctx->Message_Block_Index    = 0;
-    ctx->Intermediate_Hash[0]   = 0x67452301;
-    ctx->Intermediate_Hash[1]   = 0xEFCDAB89;
-    ctx->Intermediate_Hash[2]   = 0x98BADCFE;
-    ctx->Intermediate_Hash[3]   = 0x10325476;
-    ctx->Intermediate_Hash[4]   = 0xC3D2E1F0;
-}
-
-/**
- * Accepts an array of octets as the next portion of the message.
- */
-void SHA1Update(SHA1_CTX *ctx, const uint8_t *msg, int len)
-{
-    while (len--)
-    {
-        ctx->Message_Block[ctx->Message_Block_Index++] = (*msg & 0xFF);
-
-        ctx->Length_Low += 8;
-        if (ctx->Length_Low == 0)
-        {
-            ctx->Length_High++;
-        }
-
-        if (ctx->Message_Block_Index == 64)
-        {
-            SHA1ProcessMessageBlock(ctx);
-        }
-
-        msg++;
-    }
-}
-
-/**
- * Return the 160-bit message digest into the user's array
- */
-void SHA1Final(SHA1_CTX *ctx, uint8_t *digest)
-{
-    int i;
-
-    SHA1PadMessage(ctx);
-    memset(ctx->Message_Block, 0, 64);
-    ctx->Length_Low = 0;    /* and clear length */
-    ctx->Length_High = 0;
-
-    for  (i = 0; i < SHA1_SIZE; i++)
-    {
-        digest[i] = ctx->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) );
-    }
-}
-
-/**
- * Process the next 512 bits of the message stored in the array.
- */
-static void SHA1ProcessMessageBlock(SHA1_CTX *ctx)
-{
-    const uint32_t K[] =    {       /* Constants defined in SHA-1   */
-                            0x5A827999,
-                            0x6ED9EBA1,
-                            0x8F1BBCDC,
-                            0xCA62C1D6
-                            };
-    int        t;                 /* Loop counter                */
-    uint32_t      temp;              /* Temporary word value        */
-    uint32_t      W[80];             /* Word sequence               */
-    uint32_t      A, B, C, D, E;     /* Word buffers                */
-
-    /*
-     *  Initialize the first 16 words in the array W
-     */
-    for  (t = 0; t < 16; t++)
-    {
-        W[t] = ctx->Message_Block[t * 4] << 24;
-        W[t] |= ctx->Message_Block[t * 4 + 1] << 16;
-        W[t] |= ctx->Message_Block[t * 4 + 2] << 8;
-        W[t] |= ctx->Message_Block[t * 4 + 3];
-    }
-
-    for (t = 16; t < 80; t++)
-    {
-       W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
-    }
-
-    A = ctx->Intermediate_Hash[0];
-    B = ctx->Intermediate_Hash[1];
-    C = ctx->Intermediate_Hash[2];
-    D = ctx->Intermediate_Hash[3];
-    E = ctx->Intermediate_Hash[4];
-
-    for (t = 0; t < 20; t++)
-    {
-        temp =  SHA1CircularShift(5,A) +
-                ((B & C) | ((~B) & D)) + E + W[t] + K[0];
-        E = D;
-        D = C;
-        C = SHA1CircularShift(30,B);
-
-        B = A;
-        A = temp;
-    }
-
-    for (t = 20; t < 40; t++)
-    {
-        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
-        E = D;
-        D = C;
-        C = SHA1CircularShift(30,B);
-        B = A;
-        A = temp;
-    }
-
-    for (t = 40; t < 60; t++)
-    {
-        temp = SHA1CircularShift(5,A) +
-               ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
-        E = D;
-        D = C;
-        C = SHA1CircularShift(30,B);
-        B = A;
-        A = temp;
-    }
-
-    for (t = 60; t < 80; t++)
-    {
-        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
-        E = D;
-        D = C;
-        C = SHA1CircularShift(30,B);
-        B = A;
-        A = temp;
-    }
-
-    ctx->Intermediate_Hash[0] += A;
-    ctx->Intermediate_Hash[1] += B;
-    ctx->Intermediate_Hash[2] += C;
-    ctx->Intermediate_Hash[3] += D;
-    ctx->Intermediate_Hash[4] += E;
-    ctx->Message_Block_Index = 0;
-}
-
-/*
- * According to the standard, the message must be padded to an even
- * 512 bits.  The first padding bit must be a '1'.  The last 64
- * bits represent the length of the original message.  All bits in
- * between should be 0.  This function will pad the message
- * according to those rules by filling the Message_Block array
- * accordingly.  It will also call the ProcessMessageBlock function
- * provided appropriately.  When it returns, it can be assumed that
- * the message digest has been computed.
- *
- * @param ctx [in, out] The SHA1 context
- */
-static void SHA1PadMessage(SHA1_CTX *ctx)
-{
-    /*
-     *  Check to see if the current message block is too small to hold
-     *  the initial padding bits and length.  If so, we will pad the
-     *  block, process it, and then continue padding into a second
-     *  block.
-     */
-    if (ctx->Message_Block_Index > 55)
-    {
-        ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
-        while(ctx->Message_Block_Index < 64)
-        {
-            ctx->Message_Block[ctx->Message_Block_Index++] = 0;
-        }
-
-        SHA1ProcessMessageBlock(ctx);
-
-        while (ctx->Message_Block_Index < 56)
-        {
-            ctx->Message_Block[ctx->Message_Block_Index++] = 0;
-        }
-    }
-    else
-    {
-        ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;
-        while(ctx->Message_Block_Index < 56)
-        {
-
-            ctx->Message_Block[ctx->Message_Block_Index++] = 0;
-        }
-    }
-
-    /*
-     *  Store the message length as the last 8 octets
-     */
-    ctx->Message_Block[56] = ctx->Length_High >> 24;
-    ctx->Message_Block[57] = ctx->Length_High >> 16;
-    ctx->Message_Block[58] = ctx->Length_High >> 8;
-    ctx->Message_Block[59] = ctx->Length_High;
-    ctx->Message_Block[60] = ctx->Length_Low >> 24;
-    ctx->Message_Block[61] = ctx->Length_Low >> 16;
-    ctx->Message_Block[62] = ctx->Length_Low >> 8;
-    ctx->Message_Block[63] = ctx->Length_Low;
-    SHA1ProcessMessageBlock(ctx);
-}
diff --git a/roms/ipxe/src/crypto/axtls_aes.c b/roms/ipxe/src/crypto/axtls_aes.c
index b73a572526f12eb27e57c40c4931..7f93c0ed749da189cc3133681910 100644
--- a/roms/ipxe/src/crypto/axtls_aes.c
+++ b/roms/ipxe/src/crypto/axtls_aes.c
@@ -13,13 +13,15 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <string.h>
 #include <errno.h>
+#include <assert.h>
 #include <byteswap.h>
 #include <ipxe/crypto.h>
 #include <ipxe/cbc.h>
@@ -119,7 +121,7 @@ static void aes_encrypt ( void *ctx, const void *src, void *dst,
 	assert ( len == AES_BLOCKSIZE );
 	if ( aes_ctx->decrypting )
 		assert ( 0 );
-	aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, AES_encrypt );
+	aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, axtls_aes_encrypt );
 }
 
 /**
@@ -139,7 +141,7 @@ static void aes_decrypt ( void *ctx, const void *src, void *dst,
 		AES_convert_key ( &aes_ctx->axtls_ctx );
 		aes_ctx->decrypting = 1;
 	}
-	aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, AES_decrypt );
+	aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, axtls_aes_decrypt );
 }
 
 /** Basic AES algorithm */
diff --git a/roms/ipxe/src/crypto/axtls_sha1.c b/roms/ipxe/src/crypto/axtls_sha1.c
deleted file mode 100644
index 3eb8912d323559de960c5da89b99ee8fcfd6e642..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/crypto/axtls_sha1.c
+++ /dev/null
@@ -1,25 +0,0 @@
-#include "crypto/axtls/crypto.h"
-#include <ipxe/crypto.h>
-#include <ipxe/sha1.h>
-
-static void sha1_init ( void *ctx ) {
-	SHA1Init ( ctx );
-}
-
-static void sha1_update ( void *ctx, const void *data, size_t len ) {
-	SHA1Update ( ctx, data, len );
-}
-
-static void sha1_final ( void *ctx, void *out ) {
-	SHA1Final ( ctx, out );
-}
-
-struct digest_algorithm sha1_algorithm = {
-	.name		= "sha1",
-	.ctxsize	= SHA1_CTX_SIZE,
-	.blocksize	= 64,
-	.digestsize	= SHA1_DIGEST_SIZE,
-	.init		= sha1_init,
-	.update		= sha1_update,
-	.final		= sha1_final,
-};
diff --git a/roms/ipxe/src/crypto/bigint.c b/roms/ipxe/src/crypto/bigint.c
new file mode 100644
index 0000000000000000000000000000000000000000..340128e2fcd6b855635acf93f6a0848afc6e0d31
--- /dev/null
+++ b/roms/ipxe/src/crypto/bigint.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <ipxe/bigint.h>
+
+/** @file
+ *
+ * Big integer support
+ */
+
+/**
+ * Perform modular multiplication of big integers
+ *
+ * @v multiplicand0	Element 0 of big integer to be multiplied
+ * @v multiplier0	Element 0 of big integer to be multiplied
+ * @v modulus0		Element 0 of big integer modulus
+ * @v result0		Element 0 of big integer to hold result
+ * @v size		Number of elements in base, modulus, and result
+ * @v tmp		Temporary working space
+ */
+void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0,
+			       const bigint_element_t *multiplier0,
+			       const bigint_element_t *modulus0,
+			       bigint_element_t *result0,
+			       unsigned int size, void *tmp ) {
+	const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
+		( ( const void * ) multiplicand0 );
+	const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
+		( ( const void * ) multiplier0 );
+	const bigint_t ( size ) __attribute__ (( may_alias )) *modulus =
+		( ( const void * ) modulus0 );
+	bigint_t ( size ) __attribute__ (( may_alias )) *result =
+		( ( void * ) result0 );
+	struct {
+		bigint_t ( size * 2 ) result;
+		bigint_t ( size * 2 ) modulus;
+	} *temp = tmp;
+	int rotation;
+	int i;
+
+	/* Sanity check */
+	assert ( sizeof ( *temp ) == bigint_mod_multiply_tmp_len ( modulus ) );
+
+	/* Perform multiplication */
+	bigint_multiply ( multiplicand, multiplier, &temp->result );
+
+	/* Rescale modulus to match result */
+	bigint_grow ( modulus, &temp->modulus );
+	rotation = ( bigint_max_set_bit ( &temp->result ) -
+		     bigint_max_set_bit ( &temp->modulus ) );
+	for ( i = 0 ; i < rotation ; i++ )
+		bigint_rol ( &temp->modulus );
+
+	/* Subtract multiples of modulus */
+	for ( i = 0 ; i <= rotation ; i++ ) {
+		if ( bigint_is_geq ( &temp->result, &temp->modulus ) )
+			bigint_subtract ( &temp->modulus, &temp->result );
+		bigint_ror ( &temp->modulus );
+	}
+
+	/* Resize result */
+	bigint_shrink ( &temp->result, result );
+
+	/* Sanity check */
+	assert ( bigint_is_geq ( modulus, result ) );
+}
+
+/**
+ * Perform modular exponentiation of big integers
+ *
+ * @v base0		Element 0 of big integer base
+ * @v modulus0		Element 0 of big integer modulus
+ * @v exponent0		Element 0 of big integer exponent
+ * @v result0		Element 0 of big integer to hold result
+ * @v size		Number of elements in base, modulus, and result
+ * @v exponent_size	Number of elements in exponent
+ * @v tmp		Temporary working space
+ */
+void bigint_mod_exp_raw ( const bigint_element_t *base0,
+			  const bigint_element_t *modulus0,
+			  const bigint_element_t *exponent0,
+			  bigint_element_t *result0,
+			  unsigned int size, unsigned int exponent_size,
+			  void *tmp ) {
+	const bigint_t ( size ) __attribute__ (( may_alias )) *base =
+		( ( const void * ) base0 );
+	const bigint_t ( size ) __attribute__ (( may_alias )) *modulus =
+		( ( const void * ) modulus0 );
+	const bigint_t ( exponent_size ) __attribute__ (( may_alias ))
+		*exponent = ( ( const void * ) exponent0 );
+	bigint_t ( size ) __attribute__ (( may_alias )) *result =
+		( ( void * ) result0 );
+	size_t mod_multiply_len = bigint_mod_multiply_tmp_len ( modulus );
+	struct {
+		bigint_t ( size ) base;
+		bigint_t ( exponent_size ) exponent;
+		uint8_t mod_multiply[mod_multiply_len];
+	} *temp = tmp;
+	static const uint8_t start[1] = { 0x01 };
+
+	memcpy ( &temp->base, base, sizeof ( temp->base ) );
+	memcpy ( &temp->exponent, exponent, sizeof ( temp->exponent ) );
+	bigint_init ( result, start, sizeof ( start ) );
+
+	while ( ! bigint_is_zero ( &temp->exponent ) ) {
+		if ( bigint_bit_is_set ( &temp->exponent, 0 ) ) {
+			bigint_mod_multiply ( result, &temp->base, modulus,
+					      result, temp->mod_multiply );
+		}
+		bigint_ror ( &temp->exponent );
+		bigint_mod_multiply ( &temp->base, &temp->base, modulus,
+				      &temp->base, temp->mod_multiply );
+	}
+}
diff --git a/roms/ipxe/src/crypto/cbc.c b/roms/ipxe/src/crypto/cbc.c
index c00ebb0a73f65711c2faf43257cf..9bf0e8b49cb1bd53c4fff68727bd 100644
--- a/roms/ipxe/src/crypto/cbc.c
+++ b/roms/ipxe/src/crypto/cbc.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -87,13 +88,15 @@ void cbc_encrypt ( void *ctx, const void *src, void *dst, size_t len,
 void cbc_decrypt ( void *ctx, const void *src, void *dst, size_t len,
 		   struct cipher_algorithm *raw_cipher, void *cbc_ctx ) {
 	size_t blocksize = raw_cipher->blocksize;
+	uint8_t next_cbc_ctx[blocksize];
 
 	assert ( ( len % blocksize ) == 0 );
 
 	while ( len ) {
+		memcpy ( next_cbc_ctx, src, blocksize );
 		cipher_decrypt ( raw_cipher, ctx, src, dst, blocksize );
 		cbc_xor ( cbc_ctx, dst, blocksize );
-		memcpy ( cbc_ctx, src, blocksize );
+		memcpy ( cbc_ctx, next_cbc_ctx, blocksize );
 		dst += blocksize;
 		src += blocksize;
 		len -= blocksize;
diff --git a/roms/ipxe/src/crypto/chap.c b/roms/ipxe/src/crypto/chap.c
index 492d221602579514d6590b8344c3..db64371c7076ca7960540b08f8f9 100644
--- a/roms/ipxe/src/crypto/chap.c
+++ b/roms/ipxe/src/crypto/chap.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/crypto/clientcert.c b/roms/ipxe/src/crypto/clientcert.c
new file mode 100644
index 0000000000000000000000000000000000000000..5ce1f6c1a2ad6a8058560cba69e30522524f8fc2
--- /dev/null
+++ b/roms/ipxe/src/crypto/clientcert.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/settings.h>
+#include <ipxe/clientcert.h>
+
+/** @file
+ *
+ * Client certificate store
+ *
+ * Life would in theory be easier if we could use a single file to
+ * hold both the certificate and corresponding private key.
+ * Unfortunately, the only common format which supports this is
+ * PKCS#12 (aka PFX), which is too ugly to be allowed anywhere near my
+ * codebase.  See, for reference and amusement:
+ *
+ *    http://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html
+ *
+ */
+
+/* Sanity checks */
+#if defined(CERTIFICATE) && ! defined(PRIVATE_KEY)
+#warning "Attempting to embed certificate with no corresponding private key"
+#endif
+#if defined(PRIVATE_KEY) && ! defined(CERTIFICATE)
+#warning "Attempting to embed private key with no corresponding certificate"
+#endif
+
+/* Allow client certificates to be overridden if not explicitly specified */
+#ifdef CERTIFICATE
+#define ALLOW_CERT_OVERRIDE 0
+#else
+#define ALLOW_CERT_OVERRIDE 1
+#endif
+
+/* Raw client certificate data */
+extern char client_certificate_data[];
+extern char client_certificate_len[];
+__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"
+	  "\nclient_certificate_data:\n\t"
+#ifdef CERTIFICATE
+	  ".incbin \"" CERTIFICATE "\"\n\t"
+#endif /* CERTIFICATE */
+	  ".size client_certificate_data, ( . - client_certificate_data )\n\t"
+	  ".equ client_certificate_len, ( . - client_certificate_data )\n\t"
+	  ".previous\n\t" );
+
+/* Raw client private key data */
+extern char client_private_key_data[];
+extern char client_private_key_len[];
+__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"
+	  "\nclient_private_key_data:\n\t"
+#ifdef PRIVATE_KEY
+	  ".incbin \"" PRIVATE_KEY "\"\n\t"
+#endif /* PRIVATE_KEY */
+	  ".size client_private_key_data, ( . - client_private_key_data )\n\t"
+	  ".equ client_private_key_len, ( . - client_private_key_data )\n\t"
+	  ".previous\n\t" );
+
+/** Client certificate */
+struct client_certificate client_certificate = {
+	.data = client_certificate_data,
+	.len = ( ( size_t ) client_certificate_len ),
+};
+
+/** Client private key */
+struct client_private_key client_private_key = {
+	.data = client_private_key_data,
+	.len = ( ( size_t ) client_private_key_len ),
+};
+
+/** Client certificate setting */
+static struct setting cert_setting __setting ( SETTING_CRYPTO ) = {
+	.name = "cert",
+	.description = "Client certificate",
+	.tag = DHCP_EB_CERT,
+	.type = &setting_type_hex,
+};
+
+/** Client private key setting */
+static struct setting privkey_setting __setting ( SETTING_CRYPTO ) = {
+	.name = "privkey",
+	.description = "Client private key",
+	.tag = DHCP_EB_KEY,
+	.type = &setting_type_hex,
+};
+
+/**
+ * Apply client certificate store configuration settings
+ *
+ * @ret rc		Return status code
+ */
+static int clientcert_apply_settings ( void ) {
+	static void *cert = NULL;
+	static void *key = NULL;
+	int len;
+	int rc;
+
+	/* Allow client certificate to be overridden only if
+	 * not explicitly specified at build time.
+	 */
+	if ( ALLOW_CERT_OVERRIDE ) {
+
+		/* Restore default client certificate */
+		client_certificate.data = client_certificate_data;
+		client_certificate.len = ( ( size_t ) client_certificate_len );
+
+		/* Fetch new client certificate, if any */
+		free ( cert );
+		len = fetch_setting_copy ( NULL, &cert_setting, &cert );
+		if ( len < 0 ) {
+			rc = len;
+			DBGC ( &client_certificate, "CLIENTCERT cannot fetch "
+			       "client certificate: %s\n", strerror ( rc ) );
+			return rc;
+		}
+		if ( cert ) {
+			client_certificate.data = cert;
+			client_certificate.len = len;
+		}
+
+		/* Restore default client private key */
+		client_private_key.data = client_private_key_data;
+		client_private_key.len = ( ( size_t ) client_private_key_len );
+
+		/* Fetch new client private key, if any */
+		free ( key );
+		len = fetch_setting_copy ( NULL, &privkey_setting, &key );
+		if ( len < 0 ) {
+			rc = len;
+			DBGC ( &client_certificate, "CLIENTCERT cannot fetch "
+			       "client private key: %s\n", strerror ( rc ) );
+			return rc;
+		}
+		if ( key ) {
+			client_private_key.data = key;
+			client_private_key.len = len;
+		}
+	}
+
+	/* Debug */
+	if ( have_client_certificate() ) {
+		DBGC ( &client_certificate, "CLIENTCERT using %s "
+		       "certificate:\n", ( cert ? "external" : "built-in" ) );
+		DBGC_HDA ( &client_certificate, 0, client_certificate.data,
+			   client_certificate.len );
+		DBGC ( &client_certificate, "CLIENTCERT using %s private "
+		       "key:\n", ( key ? "external" : "built-in" ) );
+		DBGC_HDA ( &client_certificate, 0, client_private_key.data,
+			   client_private_key.len );
+	} else {
+		DBGC ( &client_certificate, "CLIENTCERT has no certificate\n" );
+	}
+
+	return 0;
+}
+
+/** Client certificate store settings applicator */
+struct settings_applicator clientcert_applicator __settings_applicator = {
+	.apply = clientcert_apply_settings,
+};
diff --git a/roms/ipxe/src/crypto/cms.c b/roms/ipxe/src/crypto/cms.c
new file mode 100644
index 0000000000000000000000000000000000000000..c0c8d144f1070401530721d68dfab3abaffd090a
--- /dev/null
+++ b/roms/ipxe/src/crypto/cms.c
@@ -0,0 +1,705 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Cryptographic Message Syntax (PKCS #7)
+ *
+ * The format of CMS messages is defined in RFC 5652.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <ipxe/asn1.h>
+#include <ipxe/x509.h>
+#include <ipxe/malloc.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/cms.h>
+
+/* Disambiguate the various error causes */
+#define EACCES_NON_SIGNING \
+	__einfo_error ( EINFO_EACCES_NON_SIGNING )
+#define EINFO_EACCES_NON_SIGNING \
+	__einfo_uniqify ( EINFO_EACCES, 0x01, "Not a signing certificate" )
+#define EACCES_NON_CODE_SIGNING \
+	__einfo_error ( EINFO_EACCES_NON_CODE_SIGNING )
+#define EINFO_EACCES_NON_CODE_SIGNING \
+	__einfo_uniqify ( EINFO_EACCES, 0x02, "Not a code-signing certificate" )
+#define EACCES_WRONG_NAME \
+	__einfo_error ( EINFO_EACCES_WRONG_NAME )
+#define EINFO_EACCES_WRONG_NAME \
+	__einfo_uniqify ( EINFO_EACCES, 0x04, "Incorrect certificate name" )
+#define EACCES_NO_SIGNATURES \
+	__einfo_error ( EINFO_EACCES_NO_SIGNATURES )
+#define EINFO_EACCES_NO_SIGNATURES \
+	__einfo_uniqify ( EINFO_EACCES, 0x05, "No signatures present" )
+#define EINVAL_DIGEST \
+	__einfo_error ( EINFO_EINVAL_DIGEST )
+#define EINFO_EINVAL_DIGEST \
+	__einfo_uniqify ( EINFO_EINVAL, 0x01, "Not a digest algorithm" )
+#define EINVAL_PUBKEY \
+	__einfo_error ( EINFO_EINVAL_PUBKEY )
+#define EINFO_EINVAL_PUBKEY \
+	__einfo_uniqify ( EINFO_EINVAL, 0x02, "Not a public-key algorithm" )
+#define ENOTSUP_SIGNEDDATA \
+	__einfo_error ( EINFO_ENOTSUP_SIGNEDDATA )
+#define EINFO_ENOTSUP_SIGNEDDATA \
+	__einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Not a digital signature" )
+
+/** "pkcs7-signedData" object identifier */
+static uint8_t oid_signeddata[] = { ASN1_OID_SIGNEDDATA };
+
+/** "pkcs7-signedData" object identifier cursor */
+static struct asn1_cursor oid_signeddata_cursor =
+	ASN1_OID_CURSOR ( oid_signeddata );
+
+/**
+ * Parse CMS signature content type
+ *
+ * @v sig		CMS signature
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int cms_parse_content_type ( struct cms_signature *sig,
+				    const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+
+	/* Enter contentType */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_OID );
+
+	/* Check OID is pkcs7-signedData */
+	if ( asn1_compare ( &cursor, &oid_signeddata_cursor ) != 0 ) {
+		DBGC ( sig, "CMS %p does not contain signedData:\n", sig );
+		DBGC_HDA ( sig, 0, raw->data, raw->len );
+		return -ENOTSUP_SIGNEDDATA;
+	}
+
+	DBGC ( sig, "CMS %p contains signedData\n", sig );
+	return 0;
+}
+
+/**
+ * Parse CMS signature certificate list
+ *
+ * @v sig		CMS signature
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int cms_parse_certificates ( struct cms_signature *sig,
+				    const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+	struct x509_certificate *cert;
+	int rc;
+
+	/* Enter certificates */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+
+	/* Add each certificate */
+	while ( cursor.len ) {
+
+		/* Add certificate to chain */
+		if ( ( rc = x509_append_raw ( sig->certificates, cursor.data,
+					      cursor.len ) ) != 0 ) {
+			DBGC ( sig, "CMS %p could not append certificate: %s\n",
+			       sig, strerror ( rc) );
+			DBGC_HDA ( sig, 0, cursor.data, cursor.len );
+			return rc;
+		}
+		cert = x509_last ( sig->certificates );
+		DBGC ( sig, "CMS %p found certificate %s\n",
+		       sig, cert->subject.name );
+
+		/* Move to next certificate */
+		asn1_skip_any ( &cursor );
+	}
+
+	return 0;
+}
+
+/**
+ * Identify CMS signature certificate by issuer and serial number
+ *
+ * @v sig		CMS signature
+ * @v issuer		Issuer
+ * @v serial		Serial number
+ * @ret cert		X.509 certificate, or NULL if not found
+ */
+static struct x509_certificate *
+cms_find_issuer_serial ( struct cms_signature *sig,
+			 const struct asn1_cursor *issuer,
+			 const struct asn1_cursor *serial ) {
+	struct x509_link *link;
+	struct x509_certificate *cert;
+
+	/* Scan through certificate list */
+	list_for_each_entry ( link, &sig->certificates->links, list ) {
+
+		/* Check issuer and serial number */
+		cert = link->cert;
+		if ( ( asn1_compare ( issuer, &cert->issuer.raw ) == 0 ) &&
+		     ( asn1_compare ( serial, &cert->serial.raw ) == 0 ) )
+			return cert;
+	}
+
+	return NULL;
+}
+
+/**
+ * Parse CMS signature signer identifier
+ *
+ * @v sig		CMS signature
+ * @v info		Signer information to fill in
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int cms_parse_signer_identifier ( struct cms_signature *sig,
+					 struct cms_signer_info *info,
+					 const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+	struct asn1_cursor serial;
+	struct asn1_cursor issuer;
+	struct x509_certificate *cert;
+	int rc;
+
+	/* Enter issuerAndSerialNumber */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Identify issuer */
+	memcpy ( &issuer, &cursor, sizeof ( issuer ) );
+	if ( ( rc = asn1_shrink ( &issuer, ASN1_SEQUENCE ) ) != 0 ) {
+		DBGC ( sig, "CMS %p/%p could not locate issuer: %s\n",
+		       sig, info, strerror ( rc ) );
+		DBGC_HDA ( sig, 0, raw->data, raw->len );
+		return rc;
+	}
+	DBGC ( sig, "CMS %p/%p issuer is:\n", sig, info );
+	DBGC_HDA ( sig, 0, issuer.data, issuer.len );
+	asn1_skip_any ( &cursor );
+
+	/* Identify serialNumber */
+	memcpy ( &serial, &cursor, sizeof ( serial ) );
+	if ( ( rc = asn1_shrink ( &serial, ASN1_INTEGER ) ) != 0 ) {
+		DBGC ( sig, "CMS %p/%p could not locate serialNumber: %s\n",
+		       sig, info, strerror ( rc ) );
+		DBGC_HDA ( sig, 0, raw->data, raw->len );
+		return rc;
+	}
+	DBGC ( sig, "CMS %p/%p serial number is:\n", sig, info );
+	DBGC_HDA ( sig, 0, serial.data, serial.len );
+
+	/* Identify certificate */
+	cert = cms_find_issuer_serial ( sig, &issuer, &serial );
+	if ( ! cert ) {
+		DBGC ( sig, "CMS %p/%p could not identify signer's "
+		       "certificate\n", sig, info );
+		return -ENOENT;
+	}
+
+	/* Append certificate to chain */
+	if ( ( rc = x509_append ( info->chain, cert ) ) != 0 ) {
+		DBGC ( sig, "CMS %p/%p could not append certificate: %s\n",
+		       sig, info, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Append remaining certificates to chain */
+	if ( ( rc = x509_auto_append ( info->chain,
+				       sig->certificates ) ) != 0 ) {
+		DBGC ( sig, "CMS %p/%p could not append certificates: %s\n",
+		       sig, info, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse CMS signature digest algorithm
+ *
+ * @v sig		CMS signature
+ * @v info		Signer information to fill in
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int cms_parse_digest_algorithm ( struct cms_signature *sig,
+					struct cms_signer_info *info,
+					const struct asn1_cursor *raw ) {
+	struct asn1_algorithm *algorithm;
+	int rc;
+
+	/* Identify algorithm */
+	if ( ( rc = asn1_digest_algorithm ( raw, &algorithm ) ) != 0 ) {
+		DBGC ( sig, "CMS %p/%p could not identify digest algorithm: "
+		       "%s\n", sig, info, strerror ( rc ) );
+		DBGC_HDA ( sig, 0, raw->data, raw->len );
+		return rc;
+	}
+
+	/* Record digest algorithm */
+	info->digest = algorithm->digest;
+	DBGC ( sig, "CMS %p/%p digest algorithm is %s\n",
+	       sig, info, algorithm->name );
+
+	return 0;
+}
+
+/**
+ * Parse CMS signature algorithm
+ *
+ * @v sig		CMS signature
+ * @v info		Signer information to fill in
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int cms_parse_signature_algorithm ( struct cms_signature *sig,
+					   struct cms_signer_info *info,
+					   const struct asn1_cursor *raw ) {
+	struct asn1_algorithm *algorithm;
+	int rc;
+
+	/* Identify algorithm */
+	if ( ( rc = asn1_pubkey_algorithm ( raw, &algorithm ) ) != 0 ) {
+		DBGC ( sig, "CMS %p/%p could not identify public-key "
+		       "algorithm: %s\n", sig, info, strerror ( rc ) );
+		DBGC_HDA ( sig, 0, raw->data, raw->len );
+		return rc;
+	}
+
+	/* Record signature algorithm */
+	info->pubkey = algorithm->pubkey;
+	DBGC ( sig, "CMS %p/%p public-key algorithm is %s\n",
+	       sig, info, algorithm->name );
+
+	return 0;
+}
+
+/**
+ * Parse CMS signature value
+ *
+ * @v sig		CMS signature
+ * @v info		Signer information to fill in
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int cms_parse_signature_value ( struct cms_signature *sig,
+				       struct cms_signer_info *info,
+				       const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Enter signature */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	if ( ( rc = asn1_enter ( &cursor, ASN1_OCTET_STRING ) ) != 0 ) {
+		DBGC ( sig, "CMS %p/%p could not locate signature:\n",
+		       sig, info );
+		DBGC_HDA ( sig, 0, raw->data, raw->len );
+		return rc;
+	}
+
+	/* Record signature */
+	info->signature_len = cursor.len;
+	info->signature = malloc ( info->signature_len );
+	if ( ! info->signature )
+		return -ENOMEM;
+	memcpy ( info->signature, cursor.data, info->signature_len );
+	DBGC ( sig, "CMS %p/%p signature value is:\n", sig, info );
+	DBGC_HDA ( sig, 0, info->signature, info->signature_len );
+
+	return 0;
+}
+
+/**
+ * Parse CMS signature signer information
+ *
+ * @v sig		CMS signature
+ * @v info		Signer information to fill in
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int cms_parse_signer_info ( struct cms_signature *sig,
+				   struct cms_signer_info *info,
+				   const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Enter signerInfo */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Skip version */
+	asn1_skip ( &cursor, ASN1_INTEGER );
+
+	/* Parse sid */
+	if ( ( rc = cms_parse_signer_identifier ( sig, info, &cursor ) ) != 0 )
+		return rc;
+	asn1_skip_any ( &cursor );
+
+	/* Parse digestAlgorithm */
+	if ( ( rc = cms_parse_digest_algorithm ( sig, info, &cursor ) ) != 0 )
+		return rc;
+	asn1_skip_any ( &cursor );
+
+	/* Skip signedAttrs, if present */
+	asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+
+	/* Parse signatureAlgorithm */
+	if ( ( rc = cms_parse_signature_algorithm ( sig, info, &cursor ) ) != 0)
+		return rc;
+	asn1_skip_any ( &cursor );
+
+	/* Parse signature */
+	if ( ( rc = cms_parse_signature_value ( sig, info, &cursor ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Parse CMS signature from ASN.1 data
+ *
+ * @v sig		CMS signature
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int cms_parse ( struct cms_signature *sig,
+		       const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+	struct cms_signer_info *info;
+	int rc;
+
+	/* Enter contentInfo */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Parse contentType */
+
+	if ( ( rc = cms_parse_content_type ( sig, &cursor ) ) != 0 )
+		return rc;
+	asn1_skip_any ( &cursor );
+
+	/* Enter content */
+	asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+
+	/* Enter signedData */
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Skip version */
+	asn1_skip ( &cursor, ASN1_INTEGER );
+
+	/* Skip digestAlgorithms */
+	asn1_skip ( &cursor, ASN1_SET );
+
+	/* Skip encapContentInfo */
+	asn1_skip ( &cursor, ASN1_SEQUENCE );
+
+	/* Parse certificates */
+	if ( ( rc = cms_parse_certificates ( sig, &cursor ) ) != 0 )
+		return rc;
+	asn1_skip_any ( &cursor );
+
+	/* Skip crls, if present */
+	asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 1 ) );
+
+	/* Enter signerInfos */
+	asn1_enter ( &cursor, ASN1_SET );
+
+	/* Add each signerInfo.  Errors are handled by ensuring that
+	 * cms_put() will always be able to free any allocated memory.
+	 */
+	while ( cursor.len ) {
+
+		/* Allocate signer information block */
+		info = zalloc ( sizeof ( *info ) );
+		if ( ! info )
+			return -ENOMEM;
+		list_add ( &info->list, &sig->info );
+
+		/* Allocate certificate chain */
+		info->chain = x509_alloc_chain();
+		if ( ! info->chain )
+			return -ENOMEM;
+
+		/* Parse signerInfo */
+		if ( ( rc = cms_parse_signer_info ( sig, info,
+						    &cursor ) ) != 0 )
+			return rc;
+		asn1_skip_any ( &cursor );
+	}
+
+	return 0;
+}
+
+/**
+ * Free CMS signature
+ *
+ * @v refcnt		Reference count
+ */
+static void cms_free ( struct refcnt *refcnt ) {
+	struct cms_signature *sig =
+		container_of ( refcnt, struct cms_signature, refcnt );
+	struct cms_signer_info *info;
+	struct cms_signer_info *tmp;
+
+	list_for_each_entry_safe ( info, tmp, &sig->info, list ) {
+		list_del ( &info->list );
+		x509_chain_put ( info->chain );
+		free ( info->signature );
+		free ( info );
+	}
+	x509_chain_put ( sig->certificates );
+	free ( sig );
+}
+
+/**
+ * Create CMS signature
+ *
+ * @v data		Raw signature data
+ * @v len		Length of raw data
+ * @ret sig		CMS signature
+ * @ret rc		Return status code
+ *
+ * On success, the caller holds a reference to the CMS signature, and
+ * is responsible for ultimately calling cms_put().
+ */
+int cms_signature ( const void *data, size_t len, struct cms_signature **sig ) {
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Allocate and initialise signature */
+	*sig = zalloc ( sizeof ( **sig ) );
+	if ( ! *sig ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	ref_init ( &(*sig)->refcnt, cms_free );
+	INIT_LIST_HEAD ( &(*sig)->info );
+
+	/* Allocate certificate list */
+	(*sig)->certificates = x509_alloc_chain();
+	if ( ! (*sig)->certificates ) {
+		rc = -ENOMEM;
+		goto err_alloc_chain;
+	}
+
+	/* Initialise cursor */
+	cursor.data = data;
+	cursor.len = len;
+	asn1_shrink_any ( &cursor );
+
+	/* Parse signature */
+	if ( ( rc = cms_parse ( *sig, &cursor ) ) != 0 )
+		goto err_parse;
+
+	return 0;
+
+ err_parse:
+ err_alloc_chain:
+	cms_put ( *sig );
+ err_alloc:
+	return rc;
+}
+
+/**
+ * Calculate digest of CMS-signed data
+ *
+ * @v sig		CMS signature
+ * @v info		Signer information
+ * @v data		Signed data
+ * @v len		Length of signed data
+ * @v out		Digest output
+ */
+static void cms_digest ( struct cms_signature *sig,
+			 struct cms_signer_info *info,
+			 userptr_t data, size_t len, void *out ) {
+	struct digest_algorithm *digest = info->digest;
+	uint8_t ctx[ digest->ctxsize ];
+	uint8_t block[ digest->blocksize ];
+	size_t offset = 0;
+	size_t frag_len;
+
+	/* Initialise digest */
+	digest_init ( digest, ctx );
+
+	/* Process data one block at a time */
+	while ( len ) {
+		frag_len = len;
+		if ( frag_len > sizeof ( block ) )
+			frag_len = sizeof ( block );
+		copy_from_user ( block, data, offset, frag_len );
+		digest_update ( digest, ctx, block, frag_len );
+		offset += frag_len;
+		len -= frag_len;
+	}
+
+	/* Finalise digest */
+	digest_final ( digest, ctx, out );
+
+	DBGC ( sig, "CMS %p/%p digest value:\n", sig, info );
+	DBGC_HDA ( sig, 0, out, digest->digestsize );
+}
+
+/**
+ * Verify digest of CMS-signed data
+ *
+ * @v sig		CMS signature
+ * @v info		Signer information
+ * @v cert		Corresponding certificate
+ * @v data		Signed data
+ * @v len		Length of signed data
+ * @ret rc		Return status code
+ */
+static int cms_verify_digest ( struct cms_signature *sig,
+			       struct cms_signer_info *info,
+			       struct x509_certificate *cert,
+			       userptr_t data, size_t len ) {
+	struct digest_algorithm *digest = info->digest;
+	struct pubkey_algorithm *pubkey = info->pubkey;
+	struct x509_public_key *public_key = &cert->subject.public_key;
+	uint8_t digest_out[ digest->digestsize ];
+	uint8_t ctx[ pubkey->ctxsize ];
+	int rc;
+
+	/* Generate digest */
+	cms_digest ( sig, info, data, len, digest_out );
+
+	/* Initialise public-key algorithm */
+	if ( ( rc = pubkey_init ( pubkey, ctx, public_key->raw.data,
+				  public_key->raw.len ) ) != 0 ) {
+		DBGC ( sig, "CMS %p/%p could not initialise public key: %s\n",
+		       sig, info, strerror ( rc ) );
+		goto err_init;
+	}
+
+	/* Verify digest */
+	if ( ( rc = pubkey_verify ( pubkey, ctx, digest, digest_out,
+				    info->signature,
+				    info->signature_len ) ) != 0 ) {
+		DBGC ( sig, "CMS %p/%p signature verification failed: %s\n",
+		       sig, info, strerror ( rc ) );
+		goto err_verify;
+	}
+
+ err_verify:
+	pubkey_final ( pubkey, ctx );
+ err_init:
+	return rc;
+}
+
+/**
+ * Verify CMS signature signer information
+ *
+ * @v sig		CMS signature
+ * @v info		Signer information
+ * @v data		Signed data
+ * @v len		Length of signed data
+ * @v time		Time at which to validate certificates
+ * @v root		Root certificate store, or NULL to use default
+ * @ret rc		Return status code
+ */
+static int cms_verify_signer_info ( struct cms_signature *sig,
+				    struct cms_signer_info *info,
+				    userptr_t data, size_t len,
+				    time_t time, struct x509_root *root ) {
+	struct x509_certificate *cert;
+	int rc;
+
+	/* Validate certificate chain */
+	if ( ( rc = x509_validate_chain ( info->chain, time, root ) ) != 0 ) {
+		DBGC ( sig, "CMS %p/%p could not validate chain: %s\n",
+		       sig, info, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Extract code-signing certificate */
+	cert = x509_first ( info->chain );
+	assert ( cert != NULL );
+
+	/* Check that certificate can create digital signatures */
+	if ( ! ( cert->extensions.usage.bits & X509_DIGITAL_SIGNATURE ) ) {
+		DBGC ( sig, "CMS %p/%p certificate cannot create signatures\n",
+		       sig, info );
+		return -EACCES_NON_SIGNING;
+	}
+
+	/* Check that certificate can sign code */
+	if ( ! ( cert->extensions.ext_usage.bits & X509_CODE_SIGNING ) ) {
+		DBGC ( sig, "CMS %p/%p certificate is not code-signing\n",
+		       sig, info );
+		return -EACCES_NON_CODE_SIGNING;
+	}
+
+	/* Verify digest */
+	if ( ( rc = cms_verify_digest ( sig, info, cert, data, len ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Verify CMS signature
+ *
+ * @v sig		CMS signature
+ * @v data		Signed data
+ * @v len		Length of signed data
+ * @v name		Required common name, or NULL to check all signatures
+ * @v time		Time at which to validate certificates
+ * @v root		Root certificate store, or NULL to use default
+ * @ret rc		Return status code
+ */
+int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
+		 const char *name, time_t time, struct x509_root *root ) {
+	struct cms_signer_info *info;
+	struct x509_certificate *cert;
+	int count = 0;
+	int rc;
+
+	/* Verify using all signerInfos */
+	list_for_each_entry ( info, &sig->info, list ) {
+		cert = x509_first ( info->chain );
+		if ( name && ( ( cert->subject.name == NULL ) ||
+			       ( strcmp ( cert->subject.name, name ) != 0 ) ) )
+			continue;
+		if ( ( rc = cms_verify_signer_info ( sig, info, data, len,
+						     time, root ) ) != 0 )
+			return rc;
+		count++;
+	}
+
+	/* Check that we have verified at least one signature */
+	if ( count == 0 ) {
+		if ( name ) {
+			DBGC ( sig, "CMS %p had no signatures matching name "
+			       "%s\n", sig, name );
+			return -EACCES_WRONG_NAME;
+		} else {
+			DBGC ( sig, "CMS %p had no signatures\n", sig );
+			return -EACCES_NO_SIGNATURES;
+		}
+	}
+
+	return 0;
+}
diff --git a/roms/ipxe/src/crypto/crandom.c b/roms/ipxe/src/crypto/crandom.c
deleted file mode 100644
index 1886f9b7ee6809a5154d91f1e99411dffc12875c..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/crypto/crandom.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
- *
- * 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_LICENCE ( GPL2_OR_LATER );
-
-/** @file
- *
- * Cryptographically strong random number generator
- *
- * Currently the cryptographic part is not implemented, and this just
- * uses random().
- */
-
-#include <ipxe/crypto.h>
-#include <stdlib.h>
-
-/**
- * Get cryptographically strong random bytes
- *
- * @v buf	Buffer in which to store random bytes
- * @v len	Number of random bytes to generate
- *
- * @b WARNING: This function is currently underimplemented, and does
- * not give numbers any stronger than random()!
- */
-void get_random_bytes ( void *buf, size_t len )
-{
-	u8 *bufp = buf;
-
-	/*
-	 * Somewhat arbitrarily, choose the 0x00FF0000-masked byte
-	 * returned by random() as having good entropy. PRNGs often
-	 * don't provide good entropy in lower bits, and the top byte
-	 * might show a pattern because of sign issues.
-	 */
-
-	while ( len-- ) {
-		*bufp++ = ( random() >> 16 ) & 0xFF;
-	}
-}
diff --git a/roms/ipxe/src/crypto/crc32.c b/roms/ipxe/src/crypto/crc32.c
index 71ec1d66cd73fcd41716570befdc..cfef68c0217fe3e9024605fbfdfe 100644
--- a/roms/ipxe/src/crypto/crc32.c
+++ b/roms/ipxe/src/crypto/crc32.c
@@ -15,7 +15,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/crypto/crypto_null.c b/roms/ipxe/src/crypto/crypto_null.c
index c9c32ae99b1e9c03f06ebcb2e541..ba05f726987415e6234fa8bbdc1d 100644
--- a/roms/ipxe/src/crypto/crypto_null.c
+++ b/roms/ipxe/src/crypto/crypto_null.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -81,7 +82,56 @@ struct cipher_algorithm cipher_null = {
 	.decrypt = cipher_null_decrypt,
 };
 
+static int pubkey_null_init ( void *ctx __unused, const void *key __unused,
+			      size_t key_len __unused ) {
+	return 0;
+}
+
+static size_t pubkey_null_max_len ( void *ctx __unused ) {
+	return 0;
+}
+
+static int pubkey_null_encrypt ( void *ctx __unused,
+				 const void *plaintext __unused,
+				 size_t plaintext_len __unused,
+				 void *ciphertext __unused ) {
+	return 0;
+}
+
+static int pubkey_null_decrypt ( void *ctx __unused,
+				 const void *ciphertext __unused,
+				 size_t ciphertext_len __unused,
+				 void *plaintext __unused ) {
+	return 0;
+}
+
+static int pubkey_null_sign ( void *ctx __unused,
+			      struct digest_algorithm *digest __unused,
+			      const void *value __unused,
+			      void *signature __unused ) {
+	return 0;
+}
+
+static int pubkey_null_verify ( void *ctx __unused,
+				struct digest_algorithm *digest __unused,
+				const void *value __unused,
+				const void *signature __unused ,
+				size_t signature_len __unused ) {
+	return 0;
+}
+
+static void pubkey_null_final ( void *ctx __unused ) {
+	/* Do nothing */
+}
+
 struct pubkey_algorithm pubkey_null = {
 	.name = "null",
 	.ctxsize = 0,
+	.init = pubkey_null_init,
+	.max_len = pubkey_null_max_len,
+	.encrypt = pubkey_null_encrypt,
+	.decrypt = pubkey_null_decrypt,
+	.sign = pubkey_null_sign,
+	.verify = pubkey_null_verify,
+	.final = pubkey_null_final,
 };
diff --git a/roms/ipxe/src/crypto/drbg.c b/roms/ipxe/src/crypto/drbg.c
new file mode 100644
index 0000000000000000000000000000000000000000..9e0175d25dbcb7a5d7be038f86fc58a74bec6a56
--- /dev/null
+++ b/roms/ipxe/src/crypto/drbg.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * DRBG mechanism
+ *
+ * This mechanism is designed to comply with ANS X9.82 Part 3-2007
+ * Section 9.  This standard is not freely available, but most of the
+ * text appears to be shared with NIST SP 800-90, which can be
+ * downloaded from
+ *
+ *     http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
+ *
+ * Where possible, references are given to both documents.  In the
+ * case of any disagreement, ANS X9.82 takes priority over NIST SP
+ * 800-90.  (In particular, note that some algorithms that are
+ * Approved by NIST SP 800-90 are not Approved by ANS X9.82.)
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/entropy.h>
+#include <ipxe/drbg.h>
+
+/**
+ * Instantiate DRBG
+ *
+ * @v state		Algorithm state to be initialised
+ * @v personal		Personalisation string
+ * @v personal_len	Length of personalisation string
+ * @ret rc		Return status code
+ *
+ * This is the Instantiate_function defined in ANS X9.82 Part 3-2007
+ * Section 9.2 (NIST SP 800-90 Section 9.1).
+ *
+ * Only a single security strength is supported, and prediction
+ * resistance is always enabled.  The nonce is accounted for by
+ * increasing the entropy input, as per ANS X9.82 Part 3-2007 Section
+ * 8.4.2 (NIST SP 800-90 Section 8.6.7).
+ */
+int drbg_instantiate ( struct drbg_state *state, const void *personal,
+		       size_t personal_len ) {
+	unsigned int entropy_bits = ( ( 3 * DRBG_SECURITY_STRENGTH + 1 ) / 2 );
+	size_t min_len = DRBG_MIN_ENTROPY_LEN_BYTES;
+	size_t max_len = DRBG_MAX_ENTROPY_LEN_BYTES;
+	uint8_t data[max_len];
+	int len;
+	int rc;
+
+	DBGC ( state, "DRBG %p instantiate\n", state );
+
+	/* Sanity checks */
+	assert ( state != NULL );
+
+	/* 1.  If requested_instantiation_security_strength >
+	 *     highest_supported_security_strength, then return an
+	 *     ERROR_FLAG
+	 */
+	if ( DRBG_SECURITY_STRENGTH > DRBG_MAX_SECURITY_STRENGTH ) {
+		DBGC ( state, "DRBG %p cannot support security strength %d\n",
+		       state, DRBG_SECURITY_STRENGTH );
+		return -ENOTSUP;
+	}
+
+	/* 2.  If prediction_resistance_flag is set, and prediction
+	 *     resistance is not supported, then return an ERROR_FLAG
+	 *
+	 * (Nothing to do since prediction resistance is always
+	 * supported.)
+	 */
+
+	/* 3.  If the length of the personalization_string >
+	 *     max_personalization_string_length, return an ERROR_FLAG
+	 */
+	if ( personal_len > DRBG_MAX_PERSONAL_LEN_BYTES ) {
+		DBGC ( state, "DRBG %p personalisation string too long (%zd "
+		       "bytes)\n", state, personal_len );
+		return -ERANGE;
+	}
+
+	/* 4.  Set security_strength to the nearest security strength
+	 *     greater than or equal to
+	 *     requested_instantiation_security_strength.
+	 *
+	 * (Nothing to do since we support only a single security
+	 * strength.)
+	 */
+
+	/* 5.  Using the security_strength, select appropriate DRBG
+	 *     mechanism parameters.
+	 *
+	 * (Nothing to do since we support only a single security
+	 * strength.)
+	 */
+
+	/* 6.  ( status, entropy_input ) = Get_entropy_input (
+	 *     security_strength, min_length, max_length,
+	 *     prediction_resistance_request )
+	 * 7.  If an ERROR is returned in step 6, return a
+	 *     CATASTROPHIC_ERROR_FLAG.
+	 * 8.  Obtain a nonce.
+	 */
+	len = get_entropy_input ( entropy_bits, data, min_len,
+				  sizeof ( data ) );
+	if ( len < 0 ) {
+		rc = len;
+		DBGC ( state, "DRBG %p could not get entropy input: %s\n",
+		       state, strerror ( rc ) );
+		return rc;
+	}
+	assert ( len >= ( int ) min_len );
+	assert ( len <= ( int ) sizeof ( data ) );
+
+	/* 9.  initial_working_state = Instantiate_algorithm (
+	 *     entropy_input, nonce, personalization_string ).
+	 */
+	drbg_instantiate_algorithm ( state, data, len, personal, personal_len );
+
+	/* 10.  Get a state_handle for a currently empty state.  If an
+	 *      empty internal state cannot be found, return an
+	 *      ERROR_FLAG.
+	 * 11.  Set the internal state indicated by state_handle to
+	 *      the initial values for the internal state (i.e. set
+	 *      the working_state to the values returned as
+	 *      initial_working_state in step 9 and any other values
+	 *      required for the working_state, and set the
+	 *      administrative information to the appropriate values.
+	 *
+	 * (Almost nothing to do since the memory to hold the state
+	 * was passed in by the caller and has already been updated
+	 * in-situ.)
+	 */
+	state->reseed_required = 0;
+	state->valid = 1;
+
+	/* 12.  Return SUCCESS and state_handle. */
+	return 0;
+}
+
+/**
+ * Reseed DRBG
+ *
+ * @v state		Algorithm state
+ * @v additional	Additional input
+ * @v additional_len	Length of additional input
+ * @ret rc		Return status code
+ *
+ * This is the Reseed_function defined in ANS X9.82 Part 3-2007
+ * Section 9.3 (NIST SP 800-90 Section 9.2).
+ *
+ * Prediction resistance is always enabled.
+ */
+int drbg_reseed ( struct drbg_state *state, const void *additional,
+		  size_t additional_len ) {
+	unsigned int entropy_bits = DRBG_SECURITY_STRENGTH;
+	size_t min_len = DRBG_MIN_ENTROPY_LEN_BYTES;
+	size_t max_len = DRBG_MAX_ENTROPY_LEN_BYTES;
+	uint8_t data[max_len];
+	int len;
+	int rc;
+
+	DBGC ( state, "DRBG %p reseed\n", state );
+
+	/* Sanity checks */
+	assert ( state != NULL );
+
+	/* 1.  Using state_handle, obtain the current internal state.
+	 *     If state_handle indicates an invalid or empty internal
+	 *     state, return an ERROR_FLAG.
+	 *
+	 * (Almost nothing to do since the memory holding the internal
+	 * state was passed in by the caller.)
+	 */
+	if ( ! state->valid ) {
+		DBGC ( state, "DRBG %p not valid\n", state );
+		return -EINVAL;
+	}
+
+	/* 2.  If prediction_resistance_request is set, and
+	 *     prediction_resistance_flag is not set, then return an
+	 *     ERROR_FLAG.
+	 *
+	 * (Nothing to do since prediction resistance is always
+	 * supported.)
+	 */
+
+	/* 3.  If the length of the additional_input >
+	 *     max_additional_input_length, return an ERROR_FLAG.
+	 */
+	if ( additional_len > DRBG_MAX_ADDITIONAL_LEN_BYTES ) {
+		DBGC ( state, "DRBG %p additional input too long (%zd bytes)\n",
+		       state, additional_len );
+		return -ERANGE;
+	}
+
+	/* 4.  ( status, entropy_input ) = Get_entropy_input (
+	 *     security_strength, min_length, max_length,
+	 *     prediction_resistance_request ).
+	 *
+	 * 5.  If an ERROR is returned in step 4, return a
+	 *     CATASTROPHIC_ERROR_FLAG.
+	 */
+	len = get_entropy_input ( entropy_bits, data, min_len,
+				  sizeof ( data ) );
+	if ( len < 0 ) {
+		rc = len;
+		DBGC ( state, "DRBG %p could not get entropy input: %s\n",
+		       state, strerror ( rc ) );
+		return rc;
+	}
+
+	/* 6.  new_working_state = Reseed_algorithm ( working_state,
+	 *     entropy_input, additional_input ).
+	 */
+	drbg_reseed_algorithm ( state, data, len, additional, additional_len );
+
+	/* 7.  Replace the working_state in the internal state
+	 *     indicated by state_handle with the values of
+	 *     new_working_state obtained in step 6.
+	 *
+	 * (Nothing to do since the state has already been updated in-situ.)
+	 */
+
+	/* 8.  Return SUCCESS. */
+	return 0;
+}
+
+/**
+ * Generate pseudorandom bits using DRBG
+ *
+ * @v state		Algorithm state
+ * @v additional	Additional input
+ * @v additional_len	Length of additional input
+ * @v prediction_resist	Prediction resistance is required
+ * @v data		Output buffer
+ * @v len		Length of output buffer
+ * @ret rc		Return status code
+ *
+ * This is the Generate_function defined in ANS X9.82 Part 3-2007
+ * Section 9.4 (NIST SP 800-90 Section 9.3).
+ *
+ * Requests must be for an integral number of bytes.  Only a single
+ * security strength is supported.  Prediction resistance is supported
+ * if requested.
+ */
+int drbg_generate ( struct drbg_state *state, const void *additional,
+		    size_t additional_len, int prediction_resist,
+		    void *data, size_t len ) {
+	int rc;
+
+	DBGC ( state, "DRBG %p generate\n", state );
+
+	/* Sanity checks */
+	assert ( state != NULL );
+	assert ( data != NULL );
+
+	/* 1.  Using state_handle, obtain the current internal state
+	 *     for the instantiation.  If state_handle indicates an
+	 *     invalid or empty internal state, then return an ERROR_FLAG.
+	 *
+	 * (Almost nothing to do since the memory holding the internal
+	 * state was passed in by the caller.)
+	 */
+	if ( ! state->valid ) {
+		DBGC ( state, "DRBG %p not valid\n", state );
+		return -EINVAL;
+	}
+
+	/* 2.  If requested_number_of_bits >
+	 *     max_number_of_bits_per_request, then return an
+	 *     ERROR_FLAG.
+	 */
+	if ( len > DRBG_MAX_GENERATED_LEN_BYTES ) {
+		DBGC ( state, "DRBG %p request too long (%zd bytes)\n",
+		       state, len );
+		return -ERANGE;
+	}
+
+	/* 3.  If requested_security_strength > the security_strength
+	 *     indicated in the internal state, then return an
+	 *     ERROR_FLAG.
+	 *
+	 * (Nothing to do since only a single security strength is
+	 * supported.)
+	 */
+
+	/* 4.  If the length of the additional_input >
+	 *     max_additional_input_length, then return an ERROR_FLAG.
+	 */
+	if ( additional_len > DRBG_MAX_ADDITIONAL_LEN_BYTES ) {
+		DBGC ( state, "DRBG %p additional input too long (%zd bytes)\n",
+		       state, additional_len );
+		return -ERANGE;
+	}
+
+	/* 5.  If prediction_resistance_request is set, and
+	 *     prediction_resistance_flag is not set, then return an
+	 *     ERROR_FLAG.
+	 *
+	 * (Nothing to do since prediction resistance is always
+	 * supported.)
+	 */
+
+	/* 6.  Clear the reseed_required_flag. */
+	state->reseed_required = 0;
+
+ step_7:
+	/* 7.  If reseed_required_flag is set, or if
+	 *     prediction_resistance_request is set, then
+	 */
+	if ( state->reseed_required || prediction_resist ) {
+
+		/* 7.1  status = Reseed_function ( state_handle,
+		 *      prediction_resistance_request,
+		 *      additional_input )
+		 * 7.2  If status indicates an ERROR, then return
+		 *      status.
+		 */
+		if ( ( rc = drbg_reseed ( state, additional,
+					  additional_len ) ) != 0 ) {
+			DBGC ( state, "DRBG %p could not reseed: %s\n",
+			       state, strerror ( rc ) );
+			return rc;
+		}
+
+		/* 7.3  Using state_handle, obtain the new internal
+		 *      state.
+		 *
+		 * (Nothing to do since the internal state has been
+		 * updated in-situ.)
+		 */
+
+		/* 7.4  additional_input = the Null string. */
+		additional = NULL;
+		additional_len = 0;
+
+		/* 7.5  Clear the reseed_required_flag. */
+		state->reseed_required = 0;
+	}
+
+	/* 8.  ( status, pseudorandom_bits, new_working_state ) =
+	 *     Generate_algorithm ( working_state,
+	 *     requested_number_of_bits, additional_input ).
+	 */
+	rc = drbg_generate_algorithm ( state, additional, additional_len,
+				       data, len );
+
+	/* 9.  If status indicates that a reseed is required before
+	 *     the requested bits can be generated, then
+	 */
+	if ( rc != 0 ) {
+
+		/* 9.1  Set the reseed_required_flag. */
+		state->reseed_required = 1;
+
+		/* 9.2  If the prediction_resistance_flag is set, then
+		 *      set the prediction_resistance_request
+		 *      indication.
+		 */
+		prediction_resist = 1;
+
+		/* 9.3  Go to step 7. */
+		goto step_7;
+	}
+
+	/* 10.  Replace the old working_state in the internal state
+	 *      indicated by state_handle with the values of
+	 *      new_working_state.
+	 *
+	 * (Nothing to do since the working state has already been
+	 * updated in-situ.)
+	 */
+
+	/* 11.  Return SUCCESS and pseudorandom_bits. */
+	return 0;
+}
+
+/**
+ * Uninstantiate DRBG
+ *
+ * @v state		Algorithm state
+ *
+ * This is the Uninstantiate_function defined in ANS X9.82 Part 3-2007
+ * Section 9.5 (NIST SP 800-90 Section 9.4).
+ */
+void drbg_uninstantiate ( struct drbg_state *state ) {
+
+	DBGC ( state, "DRBG %p uninstantiate\n", state );
+
+	/* Sanity checks */
+	assert ( state != NULL );
+
+	/* 1.  If state_handle indicates an invalid state, then return
+	 *     an ERROR_FLAG.
+	 *
+	 * (Nothing to do since the memory holding the internal state
+	 * was passed in by the caller.)
+	 */
+
+	/* 2.  Erase the contents of the internal state indicated by
+	 *     state_handle.
+	 */
+	memset ( state, 0, sizeof ( *state ) );
+
+	/* 3.  Return SUCCESS. */
+}
diff --git a/roms/ipxe/src/crypto/entropy.c b/roms/ipxe/src/crypto/entropy.c
new file mode 100644
index 0000000000000000000000000000000000000000..c7045840e723b8ec91bab116af3d8591c7bce9cd
--- /dev/null
+++ b/roms/ipxe/src/crypto/entropy.c
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Entropy source
+ *
+ * This algorithm is designed to comply with ANS X9.82 Part 4 (April
+ * 2011 Draft) Section 13.3.  This standard is unfortunately not
+ * freely available.
+ */
+
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/crypto.h>
+#include <ipxe/hash_df.h>
+#include <ipxe/entropy.h>
+
+/* Disambiguate the various error causes */
+#define EPIPE_REPETITION_COUNT_TEST \
+	__einfo_error ( EINFO_EPIPE_REPETITION_COUNT_TEST )
+#define EINFO_EPIPE_REPETITION_COUNT_TEST \
+	__einfo_uniqify ( EINFO_EPIPE, 0x01, "Repetition count test failed" )
+#define EPIPE_ADAPTIVE_PROPORTION_TEST \
+	__einfo_error ( EINFO_EPIPE_ADAPTIVE_PROPORTION_TEST )
+#define EINFO_EPIPE_ADAPTIVE_PROPORTION_TEST \
+	__einfo_uniqify ( EINFO_EPIPE, 0x02, "Adaptive proportion test failed" )
+
+/**
+ * Calculate cutoff value for the repetition count test
+ *
+ * @ret cutoff		Cutoff value
+ *
+ * This is the cutoff value for the Repetition Count Test defined in
+ * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.2.
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+repetition_count_cutoff ( void ) {
+	double max_repetitions;
+	unsigned int cutoff;
+
+	/* The cutoff formula for the repetition test is:
+	 *
+	 *   C = ( 1 + ( -log2(W) / H_min ) )
+	 *
+	 * where W is set at 2^(-30) (in ANS X9.82 Part 2 (October
+	 * 2011 Draft) Section 8.5.2.1.3.1).
+	 */
+	max_repetitions = ( 1 + ( 30 / min_entropy_per_sample() ) );
+
+	/* Round up to a whole number of repetitions.  We don't have
+	 * the ceil() function available, so do the rounding by hand.
+	 */
+	cutoff = max_repetitions;
+	if ( cutoff < max_repetitions )
+		cutoff++;
+	linker_assert ( ( cutoff >= max_repetitions ), rounding_error );
+
+	/* Floating-point operations are not allowed in iPXE since we
+	 * never set up a suitable environment.  Abort the build
+	 * unless the calculated number of repetitions is a
+	 * compile-time constant.
+	 */
+	linker_assert ( __builtin_constant_p ( cutoff ),
+			repetition_count_cutoff_not_constant );
+
+	return cutoff;
+}
+
+/**
+ * Perform repetition count test
+ *
+ * @v sample		Noise sample
+ * @ret rc		Return status code
+ *
+ * This is the Repetition Count Test defined in ANS X9.82 Part 2
+ * (October 2011 Draft) Section 8.5.2.1.2.
+ */
+static int repetition_count_test ( noise_sample_t sample ) {
+	static noise_sample_t most_recent_sample;
+	static unsigned int repetition_count = 0;
+
+	/* A = the most recently seen sample value
+	 * B = the number of times that value A has been seen in a row
+	 * C = the cutoff value above which the repetition test should fail
+	 */
+
+	/* 1.  For each new sample processed:
+	 *
+	 * (Note that the test for "repetition_count > 0" ensures that
+	 * the initial value of most_recent_sample is treated as being
+	 * undefined.)
+	 */
+	if ( ( sample == most_recent_sample ) && ( repetition_count > 0 ) ) {
+
+		/* a) If the new sample = A, then B is incremented by one. */
+		repetition_count++;
+
+		/*    i.  If B >= C, then an error condition is raised
+		 *        due to a failure of the test
+		 */
+		if ( repetition_count >= repetition_count_cutoff() )
+			return -EPIPE_REPETITION_COUNT_TEST;
+
+	} else {
+
+		/* b) Else:
+		 *    i.  A = new sample
+		 */
+		most_recent_sample = sample;
+
+		/*    ii. B = 1 */
+		repetition_count = 1;
+	}
+
+	return 0;
+}
+
+/**
+ * Window size for the adaptive proportion test
+ *
+ * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.1 allows
+ * five possible window sizes: 16, 64, 256, 4096 and 65536.
+ *
+ * We expect to generate relatively few (<256) entropy samples during
+ * a typical iPXE run; the use of a large window size would mean that
+ * the test would never complete a single cycle.  We use a window size
+ * of 64, which is the smallest window size that permits values of
+ * H_min down to one bit per sample.
+ */
+#define ADAPTIVE_PROPORTION_WINDOW_SIZE 64
+
+/**
+ * Combine adaptive proportion test window size and min-entropy
+ *
+ * @v n			N (window size)
+ * @v h			H (min-entropy)
+ * @ret n_h		(N,H) combined value
+ */
+#define APC_N_H( n, h ) ( ( (n) << 8 ) | (h) )
+
+/**
+ * Define a row of the adaptive proportion cutoff table
+ *
+ * @v h			H (min-entropy)
+ * @v c16		Cutoff for N=16
+ * @v c64		Cutoff for N=64
+ * @v c256		Cutoff for N=256
+ * @v c4096		Cutoff for N=4096
+ * @v c65536		Cutoff for N=65536
+ */
+#define APC_TABLE_ROW( h, c16, c64, c256, c4096, c65536)	   \
+	case APC_N_H ( 16, h ) :	return c16;		   \
+	case APC_N_H ( 64, h ) :	return c64;   		   \
+	case APC_N_H ( 256, h ) :	return c256;		   \
+	case APC_N_H ( 4096, h ) :	return c4096;		   \
+	case APC_N_H ( 65536, h ) :	return c65536;
+
+/** Value used to represent "N/A" in adaptive proportion cutoff table */
+#define APC_NA 0
+
+/**
+ * Look up value in adaptive proportion test cutoff table
+ *
+ * @v n			N (window size)
+ * @v h			H (min-entropy)
+ * @ret cutoff		Cutoff
+ *
+ * This is the table of cutoff values defined in ANS X9.82 Part 2
+ * (October 2011 Draft) Section 8.5.2.1.3.1.2.
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+adaptive_proportion_cutoff_lookup ( unsigned int n, unsigned int h ) {
+	switch ( APC_N_H ( n, h ) ) {
+		APC_TABLE_ROW (  1, APC_NA,     51,    168,   2240,  33537 );
+		APC_TABLE_ROW (  2, APC_NA,     35,    100,   1193,  17053 );
+		APC_TABLE_ROW (  3,     10,     24,     61,    643,   8705 );
+		APC_TABLE_ROW (  4,      8,     16,     38,    354,   4473 );
+		APC_TABLE_ROW (  5,      6,     12,     25,    200,   2321 );
+		APC_TABLE_ROW (  6,      5,      9,     17,    117,   1220 );
+		APC_TABLE_ROW (  7,      4,      7,     15,     71,    653 );
+		APC_TABLE_ROW (  8,      4,      5,      9,     45,    358 );
+		APC_TABLE_ROW (  9,      3,      4,      7,     30,    202 );
+		APC_TABLE_ROW ( 10,      3,      4,      5,     21,    118 );
+		APC_TABLE_ROW ( 11,      2,      3,      4,     15,     71 );
+		APC_TABLE_ROW ( 12,      2,      3,      4,     11,     45 );
+		APC_TABLE_ROW ( 13,      2,      2,      3,      9,     30 );
+		APC_TABLE_ROW ( 14,      2,      2,      3,      7,     21 );
+		APC_TABLE_ROW ( 15,      1,      2,      2,      6,     15 );
+		APC_TABLE_ROW ( 16,      1,      2,      2,      5,     11 );
+		APC_TABLE_ROW ( 17,      1,      1,      2,      4,      9 );
+		APC_TABLE_ROW ( 18,      1,      1,      2,      4,      7 );
+		APC_TABLE_ROW ( 19,      1,      1,      1,      3,      6 );
+		APC_TABLE_ROW ( 20,      1,      1,      1,      3,      5 );
+	default:
+		return APC_NA;
+	}
+}
+
+/**
+ * Calculate cutoff value for the adaptive proportion test
+ *
+ * @ret cutoff		Cutoff value
+ *
+ * This is the cutoff value for the Adaptive Proportion Test defined
+ * in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.2.
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+adaptive_proportion_cutoff ( void ) {
+	unsigned int h;
+	unsigned int n;
+	unsigned int cutoff;
+
+	/* Look up cutoff value in cutoff table */
+	n = ADAPTIVE_PROPORTION_WINDOW_SIZE;
+	h = min_entropy_per_sample();
+	cutoff = adaptive_proportion_cutoff_lookup ( n, h );
+
+	/* Fail unless cutoff value is a build-time constant */
+	linker_assert ( __builtin_constant_p ( cutoff ),
+			adaptive_proportion_cutoff_not_constant );
+
+	/* Fail if cutoff value is N/A */
+	linker_assert ( ( cutoff != APC_NA ),
+			adaptive_proportion_cutoff_not_applicable );
+
+	return cutoff;
+}
+
+/**
+ * Perform adaptive proportion test
+ *
+ * @v sample		Noise sample
+ * @ret rc		Return status code
+ *
+ * This is the Adaptive Proportion Test for the Most Common Value
+ * defined in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.
+ */
+static int adaptive_proportion_test ( noise_sample_t sample ) {
+	static noise_sample_t current_counted_sample;
+	static unsigned int sample_count = ADAPTIVE_PROPORTION_WINDOW_SIZE;
+	static unsigned int repetition_count;
+
+	/* A = the sample value currently being counted
+	 * B = the number of samples examined in this run of the test so far
+	 * N = the total number of samples that must be observed in
+	 *     one run of the test, also known as the "window size" of
+	 *     the test
+	 * B = the current number of times that S (sic) has been seen
+	 *     in the W (sic) samples examined so far
+	 * C = the cutoff value above which the repetition test should fail
+	 * W = the probability of a false positive: 2^-30
+	 */
+
+	/* 1.  The entropy source draws the current sample from the
+	 *     noise source.
+	 *
+	 * (Nothing to do; we already have the current sample.)
+	 */
+
+	/* 2.  If S = N, then a new run of the test begins: */
+	if ( sample_count == ADAPTIVE_PROPORTION_WINDOW_SIZE ) {
+
+		/* a.  A = the current sample */
+		current_counted_sample = sample;
+
+		/* b.  S = 0 */
+		sample_count = 0;
+
+		/* c. B = 0 */
+		repetition_count = 0;
+
+	} else {
+
+		/* Else: (the test is already running)
+		 * a.  S = S + 1
+		 */
+		sample_count++;
+
+		/* b.  If A = the current sample, then: */
+		if ( sample == current_counted_sample ) {
+
+			/* i.   B = B + 1 */
+			repetition_count++;
+
+			/* ii.  If S (sic) > C then raise an error
+			 *      condition, because the test has
+			 *      detected a failure
+			 */
+			if ( repetition_count > adaptive_proportion_cutoff() )
+				return -EPIPE_ADAPTIVE_PROPORTION_TEST;
+
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Get entropy sample
+ *
+ * @ret entropy		Entropy sample
+ * @ret rc		Return status code
+ *
+ * This is the GetEntropy function defined in ANS X9.82 Part 2
+ * (October 2011 Draft) Section 6.5.1.
+ */
+static int get_entropy ( entropy_sample_t *entropy ) {
+	static int rc = 0;
+	noise_sample_t noise;
+
+	/* Any failure is permanent */
+	if ( rc != 0 )
+		return rc;
+
+	/* Get noise sample */
+	if ( ( rc = get_noise ( &noise ) ) != 0 )
+		return rc;
+
+	/* Perform Repetition Count Test and Adaptive Proportion Test
+	 * as mandated by ANS X9.82 Part 2 (October 2011 Draft)
+	 * Section 8.5.2.1.1.
+	 */
+	if ( ( rc = repetition_count_test ( noise ) ) != 0 )
+		return rc;
+	if ( ( rc = adaptive_proportion_test ( noise ) ) != 0 )
+		return rc;
+
+	/* We do not use any optional conditioning component */
+	*entropy = noise;
+
+	return 0;
+}
+
+/**
+ * Calculate number of samples required for startup tests
+ *
+ * @ret num_samples	Number of samples required
+ *
+ * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.5 requires
+ * that at least one full cycle of the continuous tests must be
+ * performed at start-up.
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+startup_test_count ( void ) {
+	unsigned int num_samples;
+
+	/* At least max(N,C) samples shall be generated by the noise
+	 * source for start-up testing.
+	 */
+	num_samples = repetition_count_cutoff();
+	if ( num_samples < adaptive_proportion_cutoff() )
+		num_samples = adaptive_proportion_cutoff();
+	linker_assert ( __builtin_constant_p ( num_samples ),
+			startup_test_count_not_constant );
+
+	return num_samples;
+}
+
+/**
+ * Create next nonce value
+ *
+ * @ret nonce		Nonce
+ *
+ * This is the MakeNextNonce function defined in ANS X9.82 Part 4
+ * (April 2011 Draft) Section 13.3.4.2.
+ */
+static uint32_t make_next_nonce ( void ) {
+	static uint32_t nonce;
+
+	/* The simplest implementation of a nonce uses a large counter */
+	nonce++;
+
+	return nonce;
+}
+
+/**
+ * Obtain entropy input temporary buffer
+ *
+ * @v num_samples	Number of entropy samples
+ * @v tmp		Temporary buffer
+ * @v tmp_len		Length of temporary buffer
+ * @ret rc		Return status code
+ *
+ * This is (part of) the implementation of the Get_entropy_input
+ * function (using an entropy source as the source of entropy input
+ * and condensing each entropy source output after each GetEntropy
+ * call) as defined in ANS X9.82 Part 4 (April 2011 Draft) Section
+ * 13.3.4.2.
+ *
+ * To minimise code size, the number of samples required is calculated
+ * at compilation time.
+ */
+int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp,
+			    size_t tmp_len ) {
+	static unsigned int startup_tested = 0;
+	struct {
+		uint32_t nonce;
+		entropy_sample_t sample;
+	} __attribute__ (( packed )) data;;
+	uint8_t df_buf[tmp_len];
+	unsigned int i;
+	int rc;
+
+	/* Enable entropy gathering */
+	if ( ( rc = entropy_enable() ) != 0 )
+		return rc;
+
+	/* Perform mandatory startup tests, if not yet performed */
+	for ( ; startup_tested < startup_test_count() ; startup_tested++ ) {
+		if ( ( rc = get_entropy ( &data.sample ) ) != 0 )
+			goto err_get_entropy;
+	}
+
+	/* 3.  entropy_total = 0
+	 *
+	 * (Nothing to do; the number of entropy samples required has
+	 * already been precalculated.)
+	 */
+
+	/* 4.  tmp = a fixed n-bit value, such as 0^n */
+	memset ( tmp, 0, tmp_len );
+
+	/* 5.  While ( entropy_total < min_entropy ) */
+	while ( num_samples-- ) {
+		/* 5.1.  ( status, entropy_bitstring, assessed_entropy )
+		 *       = GetEntropy()
+		 * 5.2.  If status indicates an error, return ( status, Null )
+		 */
+		if ( ( rc = get_entropy ( &data.sample ) ) != 0 )
+			goto err_get_entropy;
+
+		/* 5.3.  nonce = MakeNextNonce() */
+		data.nonce = make_next_nonce();
+
+		/* 5.4.  tmp = tmp XOR
+		 *             df ( ( nonce || entropy_bitstring ), n )
+		 */
+		hash_df ( &entropy_hash_df_algorithm, &data, sizeof ( data ),
+			  df_buf, sizeof ( df_buf ) );
+		for ( i = 0 ; i < tmp_len ; i++ )
+			tmp[i] ^= df_buf[i];
+
+		/* 5.5.  entropy_total = entropy_total + assessed_entropy
+		 *
+		 * (Nothing to do; the number of entropy samples
+		 * required has already been precalculated.)
+		 */
+	}
+
+	/* Disable entropy gathering */
+	entropy_disable();
+
+	return 0;
+
+ err_get_entropy:
+	entropy_disable();
+	return rc;
+}
diff --git a/roms/ipxe/src/crypto/hash_df.c b/roms/ipxe/src/crypto/hash_df.c
new file mode 100644
index 0000000000000000000000000000000000000000..adf1d87e405295f45f8941574122758d5d2c0d53
--- /dev/null
+++ b/roms/ipxe/src/crypto/hash_df.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Hash-based derivation function (Hash_df)
+ *
+ * This algorithm is designed to comply with ANS X9.82 Part 3-2007
+ * Section 10.5.2.  This standard is not freely available, but most of
+ * the text appears to be shared with NIST SP 800-90, which can be
+ * downloaded from
+ *
+ *     http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
+ *
+ * Where possible, references are given to both documents.  In the
+ * case of any disagreement, ANS X9.82 takes priority over NIST SP
+ * 800-90.  (In particular, note that some algorithms that are
+ * Approved by NIST SP 800-90 are not Approved by ANS X9.82.)
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/crypto.h>
+#include <ipxe/hash_df.h>
+
+/**
+ * Distribute entropy throughout a buffer
+ *
+ * @v hash		Underlying hash algorithm
+ * @v input		Input data
+ * @v input_len		Length of input data, in bytes
+ * @v output		Output buffer
+ * @v output_len	Length of output buffer, in bytes
+ *
+ * This is the Hash_df function defined in ANS X9.82 Part 3-2007
+ * Section 10.5.2 (NIST SP 800-90 Section 10.4.1).
+ *
+ * The number of bits requested is implicit in the length of the
+ * output buffer.  Requests must be for an integral number of bytes.
+ *
+ * The output buffer is filled incrementally with each iteration of
+ * the central loop, rather than constructing an overall "temp" and
+ * then taking the leftmost(no_of_bits_to_return) bits.
+ *
+ * There is no way for the Hash_df function to fail.  The returned
+ * status SUCCESS is implicit.
+ */
+void hash_df ( struct digest_algorithm *hash, const void *input,
+	       size_t input_len, void *output, size_t output_len ) {
+	uint8_t context[hash->ctxsize];
+	uint8_t digest[hash->digestsize];
+	size_t frag_len;
+	struct {
+		uint8_t pad[3];
+		uint8_t counter;
+		uint32_t no_of_bits_to_return;
+	} __attribute__ (( packed )) prefix;
+	void *temp;
+	size_t remaining;
+
+	DBGC ( &hash_df, "HASH_DF input:\n" );
+	DBGC_HDA ( &hash_df, 0, input, input_len );
+
+	/* Sanity checks */
+	assert ( input != NULL );
+	assert ( output != NULL );
+
+	/* 1.  temp = the Null string
+	 * 2.  len = ceil ( no_of_bits_to_return / outlen )
+	 *
+	 * (Nothing to do.  We fill the output buffer incrementally,
+	 * rather than constructing the complete "temp" in-memory.
+	 * "len" is implicit in the number of iterations required to
+	 * fill the output buffer, and so is not calculated
+	 * explicitly.)
+	 */
+
+	/* 3.  counter = an 8-bit binary value representing the integer "1" */
+	prefix.counter = 1;
+
+	/* 4.  For i = 1 to len do */
+	for ( temp = output, remaining = output_len ; remaining > 0 ; ) {
+
+		/* Comment: in step 5.1 (sic), no_of_bits_to_return is
+		 * used as a 32-bit string.
+		 *
+		 * 4.1  temp = temp || Hash ( counter || no_of_bits_to_return
+		 *                            || input_string )
+		 */
+		prefix.no_of_bits_to_return = htonl ( output_len * 8 );
+		digest_init ( hash, context );
+		digest_update ( hash, context, &prefix.counter,
+				( sizeof ( prefix ) -
+				  offsetof ( typeof ( prefix ), counter ) ) );
+		digest_update ( hash, context, input, input_len );
+		digest_final ( hash, context, digest );
+
+		/* 4.2  counter = counter + 1 */
+		prefix.counter++;
+
+		/* 5.    requested_bits = Leftmost ( no_of_bits_to_return )
+		 *       of temp
+		 *
+		 * (We fill the output buffer incrementally.)
+		 */
+		frag_len = sizeof ( digest );
+		if ( frag_len > remaining )
+			frag_len = remaining;
+		memcpy ( temp, digest, frag_len );
+		temp += frag_len;
+		remaining -= frag_len;
+	}
+
+	/* 6.  Return SUCCESS and requested_bits */
+	DBGC ( &hash_df, "HASH_DF output:\n" );
+	DBGC_HDA ( &hash_df, 0, output, output_len );
+	return;
+}
diff --git a/roms/ipxe/src/crypto/hmac.c b/roms/ipxe/src/crypto/hmac.c
index 6b61dc4494ae9f964ed70abc8349..e9459198cd46f1f6eeaec5029534 100644
--- a/roms/ipxe/src/crypto/hmac.c
+++ b/roms/ipxe/src/crypto/hmac.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/crypto/hmac_drbg.c b/roms/ipxe/src/crypto/hmac_drbg.c
new file mode 100644
index 0000000000000000000000000000000000000000..1e5f732e27f90ccaf764bfeb98e2b1f943e14c03
--- /dev/null
+++ b/roms/ipxe/src/crypto/hmac_drbg.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * HMAC_DRBG algorithm
+ *
+ * This algorithm is designed to comply with ANS X9.82 Part 3-2007
+ * Section 10.2.2.2.  This standard is not freely available, but most
+ * of the text appears to be shared with NIST SP 800-90, which can be
+ * downloaded from
+ *
+ *     http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
+ *
+ * Where possible, references are given to both documents.  In the
+ * case of any disagreement, ANS X9.82 takes priority over NIST SP
+ * 800-90.  (In particular, note that some algorithms that are
+ * Approved by NIST SP 800-90 are not Approved by ANS X9.82.)
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/crypto.h>
+#include <ipxe/hmac.h>
+#include <ipxe/hmac_drbg.h>
+
+/**
+ * Update the HMAC_DRBG key
+ *
+ * @v hash		Underlying hash algorithm
+ * @v state		HMAC_DRBG internal state
+ * @v data		Provided data
+ * @v len		Length of provided data
+ * @v single		Single byte used in concatenation
+ *
+ * This function carries out the operation
+ *
+ *     K = HMAC ( K, V || single || provided_data )
+ *
+ * as used by hmac_drbg_update()
+ */
+static void hmac_drbg_update_key ( struct digest_algorithm *hash,
+				   struct hmac_drbg_state *state,
+				   const void *data, size_t len,
+				   const uint8_t single ) {
+	uint8_t context[ hash->ctxsize ];
+	size_t out_len = hash->digestsize;
+
+	DBGC ( state, "HMAC_DRBG_%s %p provided data :\n", hash->name, state );
+	DBGC_HDA ( state, 0, data, len );
+
+	/* Sanity checks */
+	assert ( hash != NULL );
+	assert ( state != NULL );
+	assert ( ( data != NULL ) || ( len == 0 ) );
+	assert ( ( single == 0x00 ) || ( single == 0x01 ) );
+
+	/* K = HMAC ( K, V || single || provided_data ) */
+	hmac_init ( hash, context, state->key, &out_len );
+	assert ( out_len == hash->digestsize );
+	hmac_update ( hash, context, state->value, out_len );
+	hmac_update ( hash, context, &single, sizeof ( single ) );
+	hmac_update ( hash, context, data, len );
+	hmac_final ( hash, context, state->key, &out_len, state->key );
+	assert ( out_len == hash->digestsize );
+
+	DBGC ( state, "HMAC_DRBG_%s %p K = HMAC ( K, V || %#02x || "
+	       "provided_data ) :\n", hash->name, state, single );
+	DBGC_HDA ( state, 0, state->key, out_len );
+}
+
+/**
+ * Update the HMAC_DRBG value
+ *
+ * @v hash		Underlying hash algorithm
+ * @v state		HMAC_DRBG internal state
+ * @v data		Provided data
+ * @v len		Length of provided data
+ * @v single		Single byte used in concatenation
+ *
+ * This function carries out the operation
+ *
+ *     V = HMAC ( K, V )
+ *
+ * as used by hmac_drbg_update() and hmac_drbg_generate()
+ */
+static void hmac_drbg_update_value ( struct digest_algorithm *hash,
+				     struct hmac_drbg_state *state ) {
+	uint8_t context[ hash->ctxsize ];
+	size_t out_len = hash->digestsize;
+
+	/* Sanity checks */
+	assert ( hash != NULL );
+	assert ( state != NULL );
+
+	/* V = HMAC ( K, V ) */
+	hmac_init ( hash, context, state->key, &out_len );
+	assert ( out_len == hash->digestsize );
+	hmac_update ( hash, context, state->value, out_len );
+	hmac_final ( hash, context, state->key, &out_len, state->value );
+	assert ( out_len == hash->digestsize );
+
+	DBGC ( state, "HMAC_DRBG_%s %p V = HMAC ( K, V ) :\n",
+	       hash->name, state );
+	DBGC_HDA ( state, 0, state->value, out_len );
+}
+
+/**
+ * Update HMAC_DRBG internal state
+ *
+ * @v hash		Underlying hash algorithm
+ * @v state		HMAC_DRBG internal state
+ * @v data		Provided data
+ * @v len		Length of provided data
+ *
+ * This is the HMAC_DRBG_Update function defined in ANS X9.82 Part
+ * 3-2007 Section 10.2.2.2.2 (NIST SP 800-90 Section 10.1.2.2).
+ *
+ * The key and value are updated in-place within the HMAC_DRBG
+ * internal state.
+ */
+static void hmac_drbg_update ( struct digest_algorithm *hash,
+			       struct hmac_drbg_state *state,
+			       const void *data, size_t len ) {
+
+	DBGC ( state, "HMAC_DRBG_%s %p update\n", hash->name, state );
+
+	/* Sanity checks */
+	assert ( hash != NULL );
+	assert ( state != NULL );
+	assert ( ( data != NULL ) || ( len == 0 ) );
+
+	/* 1.  K = HMAC ( K, V || 0x00 || provided_data ) */
+	hmac_drbg_update_key ( hash, state, data, len, 0x00 );
+
+	/* 2.  V = HMAC ( K, V ) */
+	hmac_drbg_update_value ( hash, state );
+
+	/* 3.  If ( provided_data = Null ), then return K and V */
+	if ( ! len )
+		return;
+
+	/* 4.  K = HMAC ( K, V || 0x01 || provided_data ) */
+	hmac_drbg_update_key ( hash, state, data, len, 0x01 );
+
+	/* 5.  V = HMAC ( K, V ) */
+	hmac_drbg_update_value ( hash, state );
+
+	/* 6.  Return K and V */
+}
+
+/**
+ * Instantiate HMAC_DRBG
+ *
+ * @v hash		Underlying hash algorithm
+ * @v state		HMAC_DRBG internal state to be initialised
+ * @v entropy		Entropy input
+ * @v entropy_len	Length of entropy input
+ * @v personal		Personalisation string
+ * @v personal_len	Length of personalisation string
+ *
+ * This is the HMAC_DRBG_Instantiate_algorithm function defined in ANS
+ * X9.82 Part 3-2007 Section 10.2.2.2.3 (NIST SP 800-90 Section
+ * 10.1.2.3).
+ *
+ * The nonce must be included within the entropy input (i.e. the
+ * entropy input must contain at least 3/2 * security_strength bits of
+ * entropy, as per ANS X9.82 Part 3-2007 Section 8.4.2 (NIST SP 800-90
+ * Section 8.6.7).
+ *
+ * The key, value and reseed counter are updated in-place within the
+ * HMAC_DRBG internal state.
+ */
+void hmac_drbg_instantiate ( struct digest_algorithm *hash,
+			     struct hmac_drbg_state *state,
+			     const void *entropy, size_t entropy_len,
+			     const void *personal, size_t personal_len ){
+	size_t out_len = hash->digestsize;
+
+	DBGC ( state, "HMAC_DRBG_%s %p instantiate\n", hash->name, state );
+
+	/* Sanity checks */
+	assert ( hash != NULL );
+	assert ( state != NULL );
+	assert ( entropy != NULL );
+	assert ( ( personal != NULL ) || ( personal_len == 0 ) );
+
+	/* 1.  seed_material = entropy_input || nonce ||
+	 *     personalisation_string
+	 */
+
+	/* 2.  Key = 0x00 00..00 */
+	memset ( state->key, 0x00, out_len );
+
+	/* 3.  V = 0x01 01...01 */
+	memset ( state->value, 0x01, out_len );
+
+	/* 4.  ( Key, V ) = HMAC_DBRG_Update ( seed_material, Key, V )
+	 * 5.  reseed_counter = 1
+	 * 6.  Return V, Key and reseed_counter as the
+	 *     initial_working_state
+	 */
+	hmac_drbg_reseed ( hash, state, entropy, entropy_len,
+			   personal, personal_len );
+}
+
+/**
+ * Reseed HMAC_DRBG
+ *
+ * @v hash		Underlying hash algorithm
+ * @v state		HMAC_DRBG internal state
+ * @v entropy		Entropy input
+ * @v entropy_len	Length of entropy input
+ * @v additional	Additional input
+ * @v additional_len	Length of additional input
+ *
+ * This is the HMAC_DRBG_Reseed_algorithm function defined in ANS X9.82
+ * Part 3-2007 Section 10.2.2.2.4 (NIST SP 800-90 Section 10.1.2.4).
+ *
+ * The key, value and reseed counter are updated in-place within the
+ * HMAC_DRBG internal state.
+ */
+void hmac_drbg_reseed ( struct digest_algorithm *hash,
+			struct hmac_drbg_state *state,
+			const void *entropy, size_t entropy_len,
+			const void *additional, size_t additional_len ) {
+	uint8_t seed_material[ entropy_len + additional_len ];
+
+	DBGC ( state, "HMAC_DRBG_%s %p (re)seed\n", hash->name, state );
+
+	/* Sanity checks */
+	assert ( hash != NULL );
+	assert ( state != NULL );
+	assert ( entropy != NULL );
+	assert ( ( additional != NULL ) || ( additional_len == 0 ) );
+
+	/* 1.  seed_material = entropy_input || additional_input */
+	memcpy ( seed_material, entropy, entropy_len );
+	memcpy ( ( seed_material + entropy_len ), additional, additional_len );
+	DBGC ( state, "HMAC_DRBG_%s %p seed material :\n", hash->name, state );
+	DBGC_HDA ( state, 0, seed_material, sizeof ( seed_material ) );
+
+	/* 2.  ( Key, V ) = HMAC_DBRG_Update ( seed_material, Key, V ) */
+	hmac_drbg_update ( hash, state, seed_material,
+			   sizeof ( seed_material ) );
+
+	/* 3.  reseed_counter = 1 */
+	state->reseed_counter = 1;
+
+	/* 4.  Return V, Key and reseed_counter as the new_working_state */
+}
+
+/**
+ * Generate pseudorandom bits using HMAC_DRBG
+ *
+ * @v hash		Underlying hash algorithm
+ * @v state		HMAC_DRBG internal state
+ * @v additional	Additional input
+ * @v additional_len	Length of additional input
+ * @v data		Output buffer
+ * @v len		Length of output buffer
+ * @ret rc		Return status code
+ *
+ * This is the HMAC_DRBG_Generate_algorithm function defined in ANS X9.82
+ * Part 3-2007 Section 10.2.2.2.5 (NIST SP 800-90 Section 10.1.2.5).
+ *
+ * Requests must be for an integral number of bytes.
+ *
+ * The key, value and reseed counter are updated in-place within the
+ * HMAC_DRBG internal state.
+ *
+ * Note that the only permitted error is "reseed required".
+ */
+int hmac_drbg_generate ( struct digest_algorithm *hash,
+			 struct hmac_drbg_state *state,
+			 const void *additional, size_t additional_len,
+			 void *data, size_t len ) {
+	size_t out_len = hash->digestsize;
+	void *orig_data = data;
+	size_t orig_len = len;
+	size_t frag_len;
+
+	DBGC ( state, "HMAC_DRBG_%s %p generate\n", hash->name, state );
+
+	/* Sanity checks */
+	assert ( hash != NULL );
+	assert ( state != NULL );
+	assert ( data != NULL );
+	assert ( ( additional != NULL ) || ( additional_len == 0 ) );
+
+	/* 1.  If reseed_counter > reseed_interval, then return an
+	 *     indication that a reseed is required
+	 */
+	if ( state->reseed_counter > HMAC_DRBG_RESEED_INTERVAL ) {
+		DBGC ( state, "HMAC_DRBG_%s %p reseed interval exceeded\n",
+		       hash->name, state );
+		return -ESTALE;
+	}
+
+	/* 2.  If additional_input != Null, then
+	 *     ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V )
+	 */
+	if ( additional_len )
+		hmac_drbg_update ( hash, state, additional, additional_len );
+
+	/* 3.  temp = Null
+	 * 4.  While ( len ( temp ) < requested_number_of_bits ) do:
+	 */
+	while ( len ) {
+
+		/* 4.1  V = HMAC ( Key, V ) */
+		hmac_drbg_update_value ( hash, state );
+
+		/* 4.2.  temp = temp || V
+		 * 5.    returned_bits = Leftmost requested_number_of_bits
+		 *       of temp
+		 */
+		frag_len = len;
+		if ( frag_len > out_len )
+			frag_len = out_len;
+		memcpy ( data, state->value, frag_len );
+		data += frag_len;
+		len -= frag_len;
+	}
+
+	/* 6.  ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V ) */
+	hmac_drbg_update ( hash, state, additional, additional_len );
+
+	/* 7.  reseed_counter = reseed_counter + 1 */
+	state->reseed_counter++;
+
+	DBGC ( state, "HMAC_DRBG_%s %p generated :\n", hash->name, state );
+	DBGC_HDA ( state, 0, orig_data, orig_len );
+
+	/* 8.  Return SUCCESS, returned_bits, and the new values of
+	 *     Key, V and reseed_counter as the new_working_state
+	 */
+	return 0;
+}
diff --git a/roms/ipxe/src/crypto/md5.c b/roms/ipxe/src/crypto/md5.c
index ef322ad2ac45d24ca04db6709051..122c7d59e8eb5888493eb4ce030f 100644
--- a/roms/ipxe/src/crypto/md5.c
+++ b/roms/ipxe/src/crypto/md5.c
@@ -1,234 +1,298 @@
-/* 
- * Cryptographic API.
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
  *
- * MD5 Message Digest Algorithm (RFC1321).
+ * 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.
  *
- * Derived from cryptoapi implementation, originally based on the
- * public domain implementation written by Colin Plumb in 1993.
- *
- * Reduced object size by around 50% compared to the original Linux
- * version for use in Etherboot by Michael Brown.
- *
- * Copyright (c) Cryptoapi developers.
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
- * Copyright (c) 2006 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
+/** @file
+ *
+ * MD5 algorithm
+ *
+ */
+
 #include <stdint.h>
 #include <string.h>
 #include <byteswap.h>
+#include <assert.h>
+#include <ipxe/rotate.h>
 #include <ipxe/crypto.h>
+#include <ipxe/asn1.h>
 #include <ipxe/md5.h>
 
-struct md5_step {
-	u32 ( * f ) ( u32 b, u32 c, u32 d );
-	u8 coefficient;
-	u8 constant;
+/** MD5 variables */
+struct md5_variables {
+	/* This layout matches that of struct md5_digest_data,
+	 * allowing for efficient endianness-conversion,
+	 */
+	uint32_t a;
+	uint32_t b;
+	uint32_t c;
+	uint32_t d;
+	uint32_t w[16];
+} __attribute__ (( packed ));
+
+/** MD5 constants */
+static const uint32_t k[64] = {
+	0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
+	0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+	0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
+	0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+	0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
+	0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+	0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
+	0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+	0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
+	0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+	0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+};
+
+/** MD5 shift amounts */
+static const uint8_t r[64] = {
+	7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
+	5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
+	4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
+	6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
 };
 
-static u32 f1(u32 b, u32 c, u32 d)
-{
-	return ( d ^ ( b & ( c ^ d ) ) );
+/**
+ * f(b,c,d) for steps 0 to 15
+ *
+ * @v v		MD5 variables
+ * @ret f	f(b,c,d)
+ */
+static uint32_t md5_f_0_15 ( struct md5_variables *v ) {
+	return ( v->d ^ ( v->b & ( v->c ^ v->d ) ) );
 }
 
-static u32 f2(u32 b, u32 c, u32 d)
-{
-	return ( c ^ ( d & ( b ^ c ) ) );
+/**
+ * f(b,c,d) for steps 16 to 31
+ *
+ * @v v		MD5 variables
+ * @ret f	f(b,c,d)
+ */
+static uint32_t md5_f_16_31 ( struct md5_variables *v ) {
+	return ( v->c ^ ( v->d & ( v->b ^ v->c ) ) );
 }
 
-static u32 f3(u32 b, u32 c, u32 d)
-{
-	return ( b ^ c ^ d );
+/**
+ * f(b,c,d) for steps 32 to 47
+ *
+ * @v v		MD5 variables
+ * @ret f	f(b,c,d)
+ */
+static uint32_t md5_f_32_47 ( struct md5_variables *v ) {
+	return ( v->b ^ v->c ^ v->d );
 }
 
-static u32 f4(u32 b, u32 c, u32 d)
-{
-	return ( c ^ ( b | ~d ) );
+/**
+ * f(b,c,d) for steps 48 to 63
+ *
+ * @v v		MD5 variables
+ * @ret f	f(b,c,d)
+ */
+static uint32_t md5_f_48_63 ( struct md5_variables *v ) {
+	return ( v->c ^ ( v->b | (~v->d) ) );
 }
 
-static struct md5_step md5_steps[4] = {
-	{
-		.f = f1,
-		.coefficient = 1,
-		.constant = 0,
-	},
-	{
-		.f = f2,
-		.coefficient = 5,
-		.constant = 1,
-	},
-	{
-		.f = f3,
-		.coefficient = 3,
-		.constant = 5,
-	},
-	{
-		.f = f4,
-		.coefficient = 7,
-		.constant = 0,
-	}
+/** An MD5 step function */
+struct md5_step {
+	/**
+	 * Calculate f(b,c,d)
+	 *
+	 * @v v		MD5 variables
+	 * @ret f	f(b,c,d)
+	 */
+	uint32_t ( * f ) ( struct md5_variables *v );
+	/** Coefficient of i in g=ni+m */
+	uint8_t coefficient;
+	/** Constant term in g=ni+m */
+	uint8_t constant;
 };
 
-static const u8 r[64] = {
-	7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
-	5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
-	4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
-	6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
+/** MD5 steps */
+static struct md5_step md5_steps[4] = {
+	/** 0 to 15 */
+	{ .f = md5_f_0_15,	.coefficient = 1,	.constant = 0 },
+	/** 16 to 31 */
+	{ .f = md5_f_16_31,	.coefficient = 5,	.constant = 1 },
+	/** 32 to 47 */
+	{ .f = md5_f_32_47,	.coefficient = 3,	.constant = 5 },
+	/** 48 to 63 */
+	{ .f = md5_f_48_63,	.coefficient = 7,	.constant = 0 },
 };
 
-static const u32 k[64] = {
-	0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL,
-	0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL,
-	0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL,
-	0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL,
-	0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL,
-	0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL,
-	0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL,
-	0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL,
-	0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL,
-	0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL,
-	0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL,
-	0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL,
-	0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL,
-	0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL,
-	0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL,
-	0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL,
-};
+/**
+ * Initialise MD5 algorithm
+ *
+ * @v ctx		MD5 context
+ */
+static void md5_init ( void *ctx ) {
+	struct md5_context *context = ctx;
 
-static void md5_transform(u32 *hash, const u32 *in)
-{
-	u32 a, b, c, d, f, g, temp;
-	int i;
-	struct md5_step *step;
+	context->ddd.dd.digest.h[0] = cpu_to_le32 ( 0x67452301 );
+	context->ddd.dd.digest.h[1] = cpu_to_le32 ( 0xefcdab89 );
+	context->ddd.dd.digest.h[2] = cpu_to_le32 ( 0x98badcfe );
+	context->ddd.dd.digest.h[3] = cpu_to_le32 ( 0x10325476 );
+	context->len = 0;
+}
 
-	a = hash[0];
-	b = hash[1];
-	c = hash[2];
-	d = hash[3];
+/**
+ * Calculate MD5 digest of accumulated data
+ *
+ * @v context		MD5 context
+ */
+static void md5_digest ( struct md5_context *context ) {
+        union {
+		union md5_digest_data_dwords ddd;
+		struct md5_variables v;
+	} u;
+	uint32_t *a = &u.v.a;
+	uint32_t *b = &u.v.b;
+	uint32_t *c = &u.v.c;
+	uint32_t *d = &u.v.d;
+	uint32_t *w = u.v.w;
+	uint32_t f;
+	uint32_t g;
+	uint32_t temp;
+	struct md5_step *step;
+	unsigned int i;
 
-	for ( i = 0 ; i < 64 ; i++ ) {
-		step = &md5_steps[i >> 4];
-		f = step->f ( b, c, d );
-		g = ( ( i * step->coefficient + step->constant ) & 0xf );
-		temp = d;
-		d = c;
-		c = b;
-		a += ( f + k[i] + in[g] );
-		a = ( ( a << r[i] ) | ( a >> ( 32-r[i] ) ) );
-		b += a;
-		a = temp;
-	}
+	/* Sanity checks */
+	assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
+	linker_assert ( &u.ddd.dd.digest.h[0] == a, md5_bad_layout );
+	linker_assert ( &u.ddd.dd.digest.h[1] == b, md5_bad_layout );
+	linker_assert ( &u.ddd.dd.digest.h[2] == c, md5_bad_layout );
+	linker_assert ( &u.ddd.dd.digest.h[3] == d, md5_bad_layout );
+	linker_assert ( &u.ddd.dd.data.dword[0] == w, md5_bad_layout );
 
-	hash[0] += a;
-	hash[1] += b;
-	hash[2] += c;
-	hash[3] += d;
-}
+	DBGC ( context, "MD5 digesting:\n" );
+	DBGC_HDA ( context, 0, &context->ddd.dd.digest,
+		   sizeof ( context->ddd.dd.digest ) );
+	DBGC_HDA ( context, context->len, &context->ddd.dd.data,
+		   sizeof ( context->ddd.dd.data ) );
 
-/* XXX: this stuff can be optimized */
-static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
-{
-	while (words--) {
-		le32_to_cpus(buf);
-		buf++;
+	/* Convert h[0..3] to host-endian, and initialise a, b, c, d,
+	 * and w[0..15]
+	 */
+	for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) /
+			    sizeof ( u.ddd.dword[0] ) ) ; i++ ) {
+		le32_to_cpus ( &context->ddd.dword[i] );
+		u.ddd.dword[i] = context->ddd.dword[i];
 	}
-}
 
-static inline void cpu_to_le32_array(u32 *buf, unsigned int words)
-{
-	while (words--) {
-		cpu_to_le32s(buf);
-		buf++;
+	/* Main loop */
+	for ( i = 0 ; i < 64 ; i++ ) {
+		step = &md5_steps[ i / 16 ];
+		f = step->f ( &u.v );
+		g = ( ( ( step->coefficient * i ) + step->constant ) % 16 );
+		temp = *d;
+		*d = *c;
+		*c = *b;
+		*b = ( *b + rol32 ( ( *a + f + k[i] + w[g] ), r[i] ) );
+		*a = temp;
+		DBGC2 ( context, "%2d : %08x %08x %08x %08x\n",
+			i, *a, *b, *c, *d );
 	}
-}
 
-static inline void md5_transform_helper(struct md5_ctx *ctx)
-{
-	le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32));
-	md5_transform(ctx->hash, ctx->block);
-}
-
-static void md5_init(void *context)
-{
-	struct md5_ctx *mctx = context;
+	/* Add chunk to hash and convert back to big-endian */
+	for ( i = 0 ; i < 4 ; i++ ) {
+		context->ddd.dd.digest.h[i] =
+			cpu_to_le32 ( context->ddd.dd.digest.h[i] +
+				      u.ddd.dd.digest.h[i] );
+	}
 
-	mctx->hash[0] = 0x67452301;
-	mctx->hash[1] = 0xefcdab89;
-	mctx->hash[2] = 0x98badcfe;
-	mctx->hash[3] = 0x10325476;
-	mctx->byte_count = 0;
+	DBGC ( context, "MD5 digested:\n" );
+	DBGC_HDA ( context, 0, &context->ddd.dd.digest,
+		   sizeof ( context->ddd.dd.digest ) );
 }
 
-static void md5_update(void *context, const void *data, size_t len)
-{
-	struct md5_ctx *mctx = context;
-	const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
-
-	mctx->byte_count += len;
+/**
+ * Accumulate data with MD5 algorithm
+ *
+ * @v ctx		MD5 context
+ * @v data		Data
+ * @v len		Length of data
+ */
+static void md5_update ( void *ctx, const void *data, size_t len ) {
+	struct md5_context *context = ctx;
+	const uint8_t *byte = data;
+	size_t offset;
 
-	if (avail > len) {
-		memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
-		       data, len);
-		return;
+	/* Accumulate data a byte at a time, performing the digest
+	 * whenever we fill the data buffer
+	 */
+	while ( len-- ) {
+		offset = ( context->len % sizeof ( context->ddd.dd.data ) );
+		context->ddd.dd.data.byte[offset] = *(byte++);
+		context->len++;
+		if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 )
+			md5_digest ( context );
 	}
+}
 
-	memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
-	       data, avail);
+/**
+ * Generate MD5 digest
+ *
+ * @v ctx		MD5 context
+ * @v out		Output buffer
+ */
+static void md5_final ( void *ctx, void *out ) {
+	struct md5_context *context = ctx;
+	uint64_t len_bits;
+	uint8_t pad;
 
-	md5_transform_helper(mctx);
-	data += avail;
-	len -= avail;
+	/* Record length before pre-processing */
+	len_bits = cpu_to_le64 ( ( ( uint64_t ) context->len ) * 8 );
 
-	while (len >= sizeof(mctx->block)) {
-		memcpy(mctx->block, data, sizeof(mctx->block));
-		md5_transform_helper(mctx);
-		data += sizeof(mctx->block);
-		len -= sizeof(mctx->block);
-	}
+	/* Pad with a single "1" bit followed by as many "0" bits as required */
+	pad = 0x80;
+	do {
+		md5_update ( ctx, &pad, sizeof ( pad ) );
+		pad = 0x00;
+	} while ( ( context->len % sizeof ( context->ddd.dd.data ) ) !=
+		  offsetof ( typeof ( context->ddd.dd.data ), final.len ) );
 
-	memcpy(mctx->block, data, len);
-}
-
-static void md5_final(void *context, void *out)
-{
-	struct md5_ctx *mctx = context;
-	const unsigned int offset = mctx->byte_count & 0x3f;
-	char *p = (char *)mctx->block + offset;
-	int padding = 56 - (offset + 1);
-
-	*p++ = 0x80;
-	if (padding < 0) {
-		memset(p, 0x00, padding + sizeof (u64));
-		md5_transform_helper(mctx);
-		p = (char *)mctx->block;
-		padding = 56;
-	}
+	/* Append length (in bits) */
+	md5_update ( ctx, &len_bits, sizeof ( len_bits ) );
+	assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
 
-	memset(p, 0, padding);
-	mctx->block[14] = mctx->byte_count << 3;
-	mctx->block[15] = mctx->byte_count >> 29;
-	le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
-	                  sizeof(u64)) / sizeof(u32));
-	md5_transform(mctx->hash, mctx->block);
-	cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32));
-	memcpy(out, mctx->hash, sizeof(mctx->hash));
-	memset(mctx, 0, sizeof(*mctx));
+	/* Copy out final digest */
+	memcpy ( out, &context->ddd.dd.digest,
+		 sizeof ( context->ddd.dd.digest ) );
 }
 
+/** MD5 algorithm */
 struct digest_algorithm md5_algorithm = {
 	.name		= "md5",
-	.ctxsize	= MD5_CTX_SIZE,
-	.blocksize	= ( MD5_BLOCK_WORDS * 4 ),
-	.digestsize	= MD5_DIGEST_SIZE,
+	.ctxsize	= sizeof ( struct md5_context ),
+	.blocksize	= sizeof ( union md5_block ),
+	.digestsize	= sizeof ( struct md5_digest ),
 	.init		= md5_init,
 	.update		= md5_update,
 	.final		= md5_final,
 };
+
+/** "md5" object identifier */
+static uint8_t oid_md5[] = { ASN1_OID_MD5 };
+
+/** "md5" OID-identified algorithm */
+struct asn1_algorithm oid_md5_algorithm __asn1_algorithm = {
+	.name = "md5",
+	.digest = &md5_algorithm,
+	.oid = ASN1_OID_CURSOR ( oid_md5 ),
+};
diff --git a/roms/ipxe/src/crypto/null_entropy.c b/roms/ipxe/src/crypto/null_entropy.c
new file mode 100644
index 0000000000000000000000000000000000000000..c56d5e76f513e4242ae08982c67a71080560d50b
--- /dev/null
+++ b/roms/ipxe/src/crypto/null_entropy.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Nonexistent entropy source
+ *
+ *
+ * This source provides no entropy and must NOT be used in a
+ * security-sensitive environment.
+ */
+
+#include <ipxe/entropy.h>
+
+PROVIDE_ENTROPY_INLINE ( null, min_entropy_per_sample );
+PROVIDE_ENTROPY_INLINE ( null, entropy_enable );
+PROVIDE_ENTROPY_INLINE ( null, entropy_disable );
+PROVIDE_ENTROPY_INLINE ( null, get_noise );
diff --git a/roms/ipxe/src/crypto/ocsp.c b/roms/ipxe/src/crypto/ocsp.c
new file mode 100644
index 0000000000000000000000000000000000000000..ab75dea35ad866128c669a1f8b03f03141bedd0c
--- /dev/null
+++ b/roms/ipxe/src/crypto/ocsp.c
@@ -0,0 +1,824 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/asn1.h>
+#include <ipxe/x509.h>
+#include <ipxe/sha1.h>
+#include <ipxe/base64.h>
+#include <ipxe/uri.h>
+#include <ipxe/ocsp.h>
+
+/** @file
+ *
+ * Online Certificate Status Protocol
+ *
+ */
+
+/* Disambiguate the various error causes */
+#define EACCES_CERT_STATUS						\
+	__einfo_error ( EINFO_EACCES_CERT_STATUS )
+#define EINFO_EACCES_CERT_STATUS					\
+	__einfo_uniqify ( EINFO_EACCES, 0x01,				\
+			  "Certificate status not good" )
+#define EACCES_CERT_MISMATCH						\
+	__einfo_error ( EINFO_EACCES_CERT_MISMATCH )
+#define EINFO_EACCES_CERT_MISMATCH					\
+	__einfo_uniqify ( EINFO_EACCES, 0x02,				\
+			  "Certificate ID mismatch" )
+#define EACCES_NON_OCSP_SIGNING						\
+	__einfo_error ( EINFO_EACCES_NON_OCSP_SIGNING )
+#define EINFO_EACCES_NON_OCSP_SIGNING					\
+	__einfo_uniqify ( EINFO_EACCES, 0x03,				\
+			  "Not an OCSP signing certificate" )
+#define EACCES_STALE							\
+	__einfo_error ( EINFO_EACCES_STALE )
+#define EINFO_EACCES_STALE						\
+	__einfo_uniqify ( EINFO_EACCES, 0x04,				\
+			  "Stale (or premature) OCSP repsonse" )
+#define EPROTO_MALFORMED_REQUEST					\
+	__einfo_error ( EINFO_EPROTO_MALFORMED_REQUEST )
+#define EINFO_EPROTO_MALFORMED_REQUEST					\
+	__einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_MALFORMED_REQUEST,	\
+			  "Illegal confirmation request" )
+#define EPROTO_INTERNAL_ERROR						\
+	__einfo_error ( EINFO_EPROTO_INTERNAL_ERROR )
+#define EINFO_EPROTO_INTERNAL_ERROR					\
+	__einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_INTERNAL_ERROR,	\
+			  "Internal error in issuer" )
+#define EPROTO_TRY_LATER						\
+	__einfo_error ( EINFO_EPROTO_TRY_LATER )
+#define EINFO_EPROTO_TRY_LATER						\
+	__einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_TRY_LATER,		\
+			  "Try again later" )
+#define EPROTO_SIG_REQUIRED						\
+	__einfo_error ( EINFO_EPROTO_SIG_REQUIRED )
+#define EINFO_EPROTO_SIG_REQUIRED					\
+	__einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_SIG_REQUIRED,	\
+			  "Must sign the request" )
+#define EPROTO_UNAUTHORIZED						\
+	__einfo_error ( EINFO_EPROTO_UNAUTHORIZED )
+#define EINFO_EPROTO_UNAUTHORIZED					\
+	__einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_UNAUTHORIZED,	\
+			  "Request unauthorized" )
+#define EPROTO_STATUS( status )						\
+	EUNIQ ( EPROTO, (status), EPROTO_MALFORMED_REQUEST,		\
+		EPROTO_INTERNAL_ERROR, EPROTO_TRY_LATER,		\
+		EPROTO_SIG_REQUIRED, EPROTO_UNAUTHORIZED )
+
+/** OCSP digest algorithm */
+#define ocsp_digest_algorithm sha1_algorithm
+
+/** OCSP digest algorithm identifier */
+static const uint8_t ocsp_algorithm_id[] =
+	{ OCSP_ALGORITHM_IDENTIFIER ( ASN1_OID_SHA1 ) };
+
+/** OCSP basic response type */
+static const uint8_t oid_basic_response_type[] = { ASN1_OID_OCSP_BASIC };
+
+/** OCSP basic response type cursor */
+static struct asn1_cursor oid_basic_response_type_cursor =
+	ASN1_OID_CURSOR ( oid_basic_response_type );
+
+/**
+ * Free OCSP check
+ *
+ * @v refcnt		Reference count
+ */
+static void ocsp_free ( struct refcnt *refcnt ) {
+	struct ocsp_check *ocsp =
+		container_of ( refcnt, struct ocsp_check, refcnt );
+
+	x509_put ( ocsp->cert );
+	x509_put ( ocsp->issuer );
+	free ( ocsp->uri_string );
+	free ( ocsp->request.builder.data );
+	free ( ocsp->response.data );
+	x509_put ( ocsp->response.signer );
+	free ( ocsp );
+}
+
+/**
+ * Build OCSP request
+ *
+ * @v ocsp		OCSP check
+ * @ret rc		Return status code
+ */
+static int ocsp_request ( struct ocsp_check *ocsp ) {
+	struct digest_algorithm *digest = &ocsp_digest_algorithm;
+	struct asn1_builder *builder = &ocsp->request.builder;
+	struct asn1_cursor *cert_id = &ocsp->request.cert_id;
+	uint8_t digest_ctx[digest->ctxsize];
+	uint8_t name_digest[digest->digestsize];
+	uint8_t pubkey_digest[digest->digestsize];
+	int rc;
+
+	/* Generate digests */
+	digest_init ( digest, digest_ctx );
+	digest_update ( digest, digest_ctx, ocsp->cert->issuer.raw.data,
+			ocsp->cert->issuer.raw.len );
+	digest_final ( digest, digest_ctx, name_digest );
+	digest_init ( digest, digest_ctx );
+	digest_update ( digest, digest_ctx,
+			ocsp->issuer->subject.public_key.raw_bits.data,
+			ocsp->issuer->subject.public_key.raw_bits.len );
+	digest_final ( digest, digest_ctx, pubkey_digest );
+
+	/* Construct request */
+	if ( ( rc = ( asn1_prepend_raw ( builder, ocsp->cert->serial.raw.data,
+					 ocsp->cert->serial.raw.len ),
+		      asn1_prepend ( builder, ASN1_OCTET_STRING,
+				     pubkey_digest, sizeof ( pubkey_digest ) ),
+		      asn1_prepend ( builder, ASN1_OCTET_STRING,
+				     name_digest, sizeof ( name_digest ) ),
+		      asn1_prepend ( builder, ASN1_SEQUENCE,
+				     ocsp_algorithm_id,
+				     sizeof ( ocsp_algorithm_id ) ),
+		      asn1_wrap ( builder, ASN1_SEQUENCE ),
+		      asn1_wrap ( builder, ASN1_SEQUENCE ),
+		      asn1_wrap ( builder, ASN1_SEQUENCE ),
+		      asn1_wrap ( builder, ASN1_SEQUENCE ),
+		      asn1_wrap ( builder, ASN1_SEQUENCE ) ) ) != 0 ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" could not build request: %s\n",
+		       ocsp, ocsp->cert->subject.name, strerror ( rc ) );
+		return rc;
+	}
+	DBGC2 ( ocsp, "OCSP %p \"%s\" request is:\n",
+		ocsp, ocsp->cert->subject.name );
+	DBGC2_HDA ( ocsp, 0, builder->data, builder->len );
+
+	/* Parse certificate ID for comparison with response */
+	cert_id->data = builder->data;
+	cert_id->len = builder->len;
+	if ( ( rc = ( asn1_enter ( cert_id, ASN1_SEQUENCE ),
+		      asn1_enter ( cert_id, ASN1_SEQUENCE ),
+		      asn1_enter ( cert_id, ASN1_SEQUENCE ),
+		      asn1_enter ( cert_id, ASN1_SEQUENCE ) ) ) != 0 ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" could not locate certID: %s\n",
+		       ocsp, ocsp->cert->subject.name, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Build OCSP URI string
+ *
+ * @v ocsp		OCSP check
+ * @ret rc		Return status code
+ */
+static int ocsp_uri_string ( struct ocsp_check *ocsp ) {
+	char *base_uri_string;
+	char *base64_request;
+	size_t base64_request_len;
+	size_t uri_string_len;
+	size_t prefix_len;
+	int rc;
+
+	/* Sanity check */
+	base_uri_string = ocsp->cert->extensions.auth_info.ocsp.uri;
+	if ( ! base_uri_string ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" has no OCSP URI\n",
+		       ocsp, ocsp->cert->subject.name );
+		rc = -ENOTTY;
+		goto err_no_uri;
+	}
+
+	/* Base64-encode the request */
+	base64_request_len = ( base64_encoded_len ( ocsp->request.builder.len )
+			       + 1 /* NUL */ );
+	base64_request = malloc ( base64_request_len );
+	if ( ! base64_request ) {
+		rc = -ENOMEM;
+		goto err_alloc_base64;
+	}
+	base64_encode ( ocsp->request.builder.data, ocsp->request.builder.len,
+			base64_request );
+
+	/* Allocate URI string */
+	uri_string_len = ( strlen ( base_uri_string ) + 1 /* "/" */ +
+			   uri_encode ( base64_request, NULL, 0, URI_FRAGMENT )
+			   + 1 /* NUL */ );
+	ocsp->uri_string = malloc ( uri_string_len );
+	if ( ! ocsp->uri_string ) {
+		rc = -ENOMEM;
+		goto err_alloc_uri;
+	}
+
+	/* Construct URI string */
+	prefix_len = snprintf ( ocsp->uri_string, uri_string_len,
+				"%s/", base_uri_string );
+	uri_encode ( base64_request, ( ocsp->uri_string + prefix_len ),
+		     ( uri_string_len - prefix_len ), URI_FRAGMENT );
+	DBGC2 ( ocsp, "OCSP %p \"%s\" URI is %s\n",
+		ocsp, ocsp->cert->subject.name, ocsp->uri_string );
+
+	/* Free base64-encoded request */
+	free ( base64_request );
+	base64_request = NULL;
+
+	return 0;
+
+ err_alloc_uri:
+	free ( base64_request );
+ err_alloc_base64:
+ err_no_uri:
+	return rc;
+}
+
+/**
+ * Create OCSP check
+ *
+ * @v cert		Certificate to check
+ * @v issuer		Issuing certificate
+ * @ret ocsp		OCSP check
+ * @ret rc		Return status code
+ */
+int ocsp_check ( struct x509_certificate *cert,
+		 struct x509_certificate *issuer,
+		 struct ocsp_check **ocsp ) {
+	int rc;
+
+	/* Sanity checks */
+	assert ( cert != NULL );
+	assert ( issuer != NULL );
+	assert ( issuer->valid );
+
+	/* Allocate and initialise check */
+	*ocsp = zalloc ( sizeof ( **ocsp ) );
+	if ( ! *ocsp ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	ref_init ( &(*ocsp)->refcnt, ocsp_free );
+	(*ocsp)->cert = x509_get ( cert );
+	(*ocsp)->issuer = x509_get ( issuer );
+
+	/* Build request */
+	if ( ( rc = ocsp_request ( *ocsp ) ) != 0 )
+		goto err_request;
+
+	/* Build URI string */
+	if ( ( rc = ocsp_uri_string ( *ocsp ) ) != 0 )
+		goto err_uri_string;
+
+	return 0;
+
+ err_uri_string:
+ err_request:
+	ocsp_put ( *ocsp );
+ err_alloc:
+	*ocsp = NULL;
+	return rc;
+}
+
+/**
+ * Parse OCSP response status
+ *
+ * @v ocsp		OCSP check
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int ocsp_parse_response_status ( struct ocsp_check *ocsp,
+					const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+	uint8_t status;
+	int rc;
+
+	/* Enter responseStatus */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	if ( ( rc = asn1_enter ( &cursor, ASN1_ENUMERATED ) ) != 0 ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" could not locate responseStatus: "
+		       "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc ));
+		return rc;
+	}
+
+	/* Extract response status */
+	if ( cursor.len != sizeof ( status ) ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" invalid status:\n",
+		       ocsp, ocsp->cert->subject.name );
+		DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
+		return -EINVAL;
+	}
+	memcpy ( &status, cursor.data, sizeof ( status ) );
+
+	/* Check response status */
+	if ( status != OCSP_STATUS_SUCCESSFUL ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" response status %d\n",
+		       ocsp, ocsp->cert->subject.name, status );
+		return EPROTO_STATUS ( status );
+	}
+
+	return 0;
+}
+
+/**
+ * Parse OCSP response type
+ *
+ * @v ocsp		OCSP check
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int ocsp_parse_response_type ( struct ocsp_check *ocsp,
+				      const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+
+	/* Enter responseType */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_OID );
+
+	/* Check responseType is "basic" */
+	if ( asn1_compare ( &oid_basic_response_type_cursor, &cursor ) != 0 ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" response type not supported:\n",
+		       ocsp, ocsp->cert->subject.name );
+		DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse OCSP certificate ID
+ *
+ * @v ocsp		OCSP check
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int ocsp_parse_cert_id ( struct ocsp_check *ocsp,
+				const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+
+	/* Check certID matches request */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_shrink_any ( &cursor );
+	if ( asn1_compare ( &cursor, &ocsp->request.cert_id ) != 0 ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" certID mismatch:\n",
+		       ocsp, ocsp->cert->subject.name );
+		DBGC_HDA ( ocsp, 0, ocsp->request.cert_id.data,
+			   ocsp->request.cert_id.len );
+		DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
+		return -EACCES_CERT_MISMATCH;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse OCSP responses
+ *
+ * @v ocsp		OCSP check
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int ocsp_parse_responses ( struct ocsp_check *ocsp,
+				  const struct asn1_cursor *raw ) {
+	struct ocsp_response *response = &ocsp->response;
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Enter responses */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Enter first singleResponse */
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Parse certID */
+	if ( ( rc = ocsp_parse_cert_id ( ocsp, &cursor ) ) != 0 )
+		return rc;
+	asn1_skip_any ( &cursor );
+
+	/* Check certStatus */
+	if ( asn1_type ( &cursor ) != ASN1_IMPLICIT_TAG ( 0 ) ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" non-good certStatus:\n",
+		       ocsp, ocsp->cert->subject.name );
+		DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
+		return -EACCES_CERT_STATUS;
+	}
+	asn1_skip_any ( &cursor );
+
+	/* Parse thisUpdate */
+	if ( ( rc = asn1_generalized_time ( &cursor,
+					    &response->this_update ) ) != 0 ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" could not parse thisUpdate: %s\n",
+		       ocsp, ocsp->cert->subject.name, strerror ( rc ) );
+		return rc;
+	}
+	DBGC2 ( ocsp, "OCSP %p \"%s\" this update was at time %lld\n",
+		ocsp, ocsp->cert->subject.name, response->this_update );
+	asn1_skip_any ( &cursor );
+
+	/* Parse nextUpdate, if present */
+	if ( asn1_type ( &cursor ) == ASN1_EXPLICIT_TAG ( 0 ) ) {
+		asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+		if ( ( rc = asn1_generalized_time ( &cursor,
+					     &response->next_update ) ) != 0 ) {
+			DBGC ( ocsp, "OCSP %p \"%s\" could not parse "
+			       "nextUpdate: %s\n", ocsp,
+			       ocsp->cert->subject.name, strerror ( rc ) );
+			return rc;
+		}
+		DBGC2 ( ocsp, "OCSP %p \"%s\" next update is at time %lld\n",
+			ocsp, ocsp->cert->subject.name, response->next_update );
+	} else {
+		/* If no nextUpdate is present, this indicates that
+		 * "newer revocation information is available all the
+		 * time".  Actually, this indicates that there is no
+		 * point to performing the OCSP check, since an
+		 * attacker could replay the response at any future
+		 * time and it would still be valid.
+		 */
+		DBGC ( ocsp, "OCSP %p \"%s\" responder is a moron\n",
+		       ocsp, ocsp->cert->subject.name );
+		response->next_update = time ( NULL );
+	}
+
+	return 0;
+}
+
+/**
+ * Parse OCSP response data
+ *
+ * @v ocsp		OCSP check
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int ocsp_parse_tbs_response_data ( struct ocsp_check *ocsp,
+					  const struct asn1_cursor *raw ) {
+	struct ocsp_response *response = &ocsp->response;
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Record raw tbsResponseData */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_shrink_any ( &cursor );
+	memcpy ( &response->tbs, &cursor, sizeof ( response->tbs ) );
+
+	/* Enter tbsResponseData */
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Skip version, if present */
+	asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+
+	/* Skip responderID */
+	asn1_skip_any ( &cursor );
+
+	/* Skip producedAt */
+	asn1_skip_any ( &cursor );
+
+	/* Parse responses */
+	if ( ( rc = ocsp_parse_responses ( ocsp, &cursor ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Parse OCSP certificates
+ *
+ * @v ocsp		OCSP check
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int ocsp_parse_certs ( struct ocsp_check *ocsp,
+			      const struct asn1_cursor *raw ) {
+	struct ocsp_response *response = &ocsp->response;
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Enter certs */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Parse certificate, if present.  The data structure permits
+	 * multiple certificates, but the protocol requires that the
+	 * OCSP signing certificate must either be the issuer itself,
+	 * or must be directly issued by the issuer (see RFC2560
+	 * section 4.2.2.2 "Authorized Responders").
+	 */
+	if ( ( cursor.len != 0 ) &&
+	     ( ( rc = x509_certificate ( cursor.data, cursor.len,
+					 &response->signer ) ) != 0 ) ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" could not parse certificate: "
+		       "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc ));
+		DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
+		return rc;
+	}
+	DBGC2 ( ocsp, "OCSP %p \"%s\" response is signed by \"%s\"\n", ocsp,
+		ocsp->cert->subject.name, response->signer->subject.name );
+
+	return 0;
+}
+
+/**
+ * Parse OCSP basic response
+ *
+ * @v ocsp		OCSP check
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int ocsp_parse_basic_response ( struct ocsp_check *ocsp,
+				       const struct asn1_cursor *raw ) {
+	struct ocsp_response *response = &ocsp->response;
+	struct asn1_algorithm **algorithm = &response->algorithm;
+	struct asn1_bit_string *signature = &response->signature;
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Enter BasicOCSPResponse */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Parse tbsResponseData */
+	if ( ( rc = ocsp_parse_tbs_response_data ( ocsp, &cursor ) ) != 0 )
+		return rc;
+	asn1_skip_any ( &cursor );
+
+	/* Parse signatureAlgorithm */
+	if ( ( rc = asn1_signature_algorithm ( &cursor, algorithm ) ) != 0 ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" cannot parse signature "
+		       "algorithm: %s\n",
+		       ocsp, ocsp->cert->subject.name, strerror ( rc ) );
+		return rc;
+	}
+	DBGC2 ( ocsp, "OCSP %p \"%s\" signature algorithm is %s\n",
+		ocsp, ocsp->cert->subject.name, (*algorithm)->name );
+	asn1_skip_any ( &cursor );
+
+	/* Parse signature */
+	if ( ( rc = asn1_integral_bit_string ( &cursor, signature ) ) != 0 ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" cannot parse signature: %s\n",
+		       ocsp, ocsp->cert->subject.name, strerror ( rc ) );
+		return rc;
+	}
+	asn1_skip_any ( &cursor );
+
+	/* Parse certs, if present */
+	if ( ( asn1_type ( &cursor ) == ASN1_EXPLICIT_TAG ( 0 ) ) &&
+	     ( ( rc = ocsp_parse_certs ( ocsp, &cursor ) ) != 0 ) )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Parse OCSP response bytes
+ *
+ * @v ocsp		OCSP check
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int ocsp_parse_response_bytes ( struct ocsp_check *ocsp,
+				       const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Enter responseBytes */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Parse responseType */
+	if ( ( rc = ocsp_parse_response_type ( ocsp, &cursor ) ) != 0 )
+		return rc;
+	asn1_skip_any ( &cursor );
+
+	/* Enter response */
+	asn1_enter ( &cursor, ASN1_OCTET_STRING );
+
+	/* Parse response */
+	if ( ( rc = ocsp_parse_basic_response ( ocsp, &cursor ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Parse OCSP response
+ *
+ * @v ocsp		OCSP check
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int ocsp_parse_response ( struct ocsp_check *ocsp,
+				 const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Enter OCSPResponse */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Parse responseStatus */
+	if ( ( rc = ocsp_parse_response_status ( ocsp, &cursor ) ) != 0 )
+		return rc;
+	asn1_skip_any ( &cursor );
+
+	/* Parse responseBytes */
+	if ( ( rc = ocsp_parse_response_bytes ( ocsp, &cursor ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Receive OCSP response
+ *
+ * @v ocsp		OCSP check
+ * @v data		Response data
+ * @v len		Length of response data
+ * @ret rc		Return status code
+ */
+int ocsp_response ( struct ocsp_check *ocsp, const void *data, size_t len ) {
+	struct ocsp_response *response = &ocsp->response;
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Duplicate data */
+	x509_put ( response->signer );
+	response->signer = NULL;
+	free ( response->data );
+	response->data = malloc ( len );
+	if ( ! response->data )
+		return -ENOMEM;
+	memcpy ( response->data, data, len );
+	cursor.data = response->data;
+	cursor.len = len;
+
+	/* Parse response */
+	if ( ( rc = ocsp_parse_response ( ocsp, &cursor ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * OCSP dummy root certificate store
+ *
+ * OCSP validation uses no root certificates, since it takes place
+ * only when there already exists a validated issuer certificate.
+ */
+static struct x509_root ocsp_root = {
+	.digest = &ocsp_digest_algorithm,
+	.count = 0,
+	.fingerprints = NULL,
+};
+
+/**
+ * Check OCSP response signature
+ *
+ * @v ocsp		OCSP check
+ * @v signer		Signing certificate
+ * @ret rc		Return status code
+ */
+static int ocsp_check_signature ( struct ocsp_check *ocsp,
+				  struct x509_certificate *signer ) {
+	struct ocsp_response *response = &ocsp->response;
+	struct digest_algorithm *digest = response->algorithm->digest;
+	struct pubkey_algorithm *pubkey = response->algorithm->pubkey;
+	struct x509_public_key *public_key = &signer->subject.public_key;
+	uint8_t digest_ctx[ digest->ctxsize ];
+	uint8_t digest_out[ digest->digestsize ];
+	uint8_t pubkey_ctx[ pubkey->ctxsize ];
+	int rc;
+
+	/* Generate digest */
+	digest_init ( digest, digest_ctx );
+	digest_update ( digest, digest_ctx, response->tbs.data,
+			response->tbs.len );
+	digest_final ( digest, digest_ctx, digest_out );
+
+	/* Initialise public-key algorithm */
+	if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data,
+				  public_key->raw.len ) ) != 0 ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" could not initialise public key: "
+		       "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc ));
+		goto err_init;
+	}
+
+	/* Verify digest */
+	if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out,
+				    response->signature.data,
+				    response->signature.len ) ) != 0 ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" signature verification failed: "
+		       "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc ));
+		goto err_verify;
+	}
+
+	DBGC2 ( ocsp, "OCSP %p \"%s\" signature is correct\n",
+		ocsp, ocsp->cert->subject.name );
+
+ err_verify:
+	pubkey_final ( pubkey, pubkey_ctx );
+ err_init:
+	return rc;
+}
+
+/**
+ * Validate OCSP response
+ *
+ * @v ocsp		OCSP check
+ * @v time		Time at which to validate response
+ * @ret rc		Return status code
+ */
+int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) {
+	struct ocsp_response *response = &ocsp->response;
+	struct x509_certificate *signer = response->signer;
+	int rc;
+
+	/* Sanity checks */
+	assert ( response->data != NULL );
+	assert ( signer != NULL );
+
+	/* Validate signer, if applicable.  If the signer is not the
+	 * issuer, then it must be signed directly by the issuer.
+	 */
+	if ( signer != ocsp->issuer ) {
+		/* Forcibly invalidate the signer, since we need to
+		 * ensure that it was signed by our issuer (and not
+		 * some other issuer).  This prevents a sub-CA's OCSP
+		 * certificate from fraudulently signing OCSP
+		 * responses from the parent CA.
+		 */
+		x509_invalidate ( signer );
+		if ( ( rc = x509_validate ( signer, ocsp->issuer, time,
+					    &ocsp_root ) ) != 0 ) {
+			DBGC ( ocsp, "OCSP %p \"%s\" could not validate "
+			       "signer \"%s\": %s\n", ocsp,
+			       ocsp->cert->subject.name, signer->subject.name,
+			       strerror ( rc ) );
+			return rc;
+		}
+
+		/* If signer is not the issuer, then it must have the
+		 * extendedKeyUsage id-kp-OCSPSigning.
+		 */
+		if ( ! ( signer->extensions.ext_usage.bits &
+			 X509_OCSP_SIGNING ) ) {
+			DBGC ( ocsp, "OCSP %p \"%s\" signer \"%s\" is "
+			       "not an OCSP-signing certificate\n", ocsp,
+			       ocsp->cert->subject.name, signer->subject.name );
+			return -EACCES_NON_OCSP_SIGNING;
+		}
+	}
+
+	/* Check OCSP response signature */
+	if ( ( rc = ocsp_check_signature ( ocsp, signer ) ) != 0 )
+		return rc;
+
+	/* Check OCSP response is valid at the specified time
+	 * (allowing for some margin of error).
+	 */
+	if ( response->this_update > ( time + X509_ERROR_MARGIN_TIME ) ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" response is not yet valid (at "
+		       "time %lld)\n", ocsp, ocsp->cert->subject.name, time );
+		return -EACCES_STALE;
+	}
+	if ( response->next_update < ( time - X509_ERROR_MARGIN_TIME ) ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" response is stale (at time "
+		       "%lld)\n", ocsp, ocsp->cert->subject.name, time );
+		return -EACCES_STALE;
+	}
+	DBGC2 ( ocsp, "OCSP %p \"%s\" response is valid (at time %lld)\n",
+		ocsp, ocsp->cert->subject.name, time );
+
+	/* Mark certificate as passing OCSP verification */
+	ocsp->cert->extensions.auth_info.ocsp.good = 1;
+
+	/* Validate certificate against issuer */
+	if ( ( rc = x509_validate ( ocsp->cert, ocsp->issuer, time,
+				    &ocsp_root ) ) != 0 ) {
+		DBGC ( ocsp, "OCSP %p \"%s\" could not validate certificate: "
+		       "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc ));
+		return rc;
+	}
+	DBGC ( ocsp, "OCSP %p \"%s\" successfully validated using \"%s\"\n",
+	       ocsp, ocsp->cert->subject.name, signer->subject.name );
+
+	return 0;
+}
diff --git a/roms/ipxe/src/crypto/random_nz.c b/roms/ipxe/src/crypto/random_nz.c
new file mode 100644
index 0000000000000000000000000000000000000000..f1d2e187d05c3c4179ac03fffa0430a393760802
--- /dev/null
+++ b/roms/ipxe/src/crypto/random_nz.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Random non-zero bytes
+ *
+ * The RSA algorithm requires the generation of random non-zero bytes,
+ * i.e. bytes in the range [0x01,0xff].
+ *
+ * This algorithm is designed to comply with ANS X9.82 Part 1-2006
+ * Section 9.2.1.  This standard is not freely available, but most of
+ * the text appears to be shared with NIST SP 800-90, which can be
+ * downloaded from
+ *
+ *     http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
+ *
+ * Where possible, references are given to both documents.  In the
+ * case of any disagreement, ANS X9.82 takes priority over NIST SP
+ * 800-90.  (In particular, note that some algorithms that are
+ * Approved by NIST SP 800-90 are not Approved by ANS X9.82.)
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <ipxe/rbg.h>
+#include <ipxe/random_nz.h>
+
+/**
+ * Get random non-zero bytes
+ *
+ * @v data		Output buffer
+ * @v len		Length of output buffer
+ * @ret rc		Return status code
+ *
+ * This algorithm is designed to be isomorphic to the Simple Discard
+ * Method described in ANS X9.82 Part 1-2006 Section 9.2.1 (NIST SP
+ * 800-90 Section B.5.1.1).
+ */
+int get_random_nz ( void *data, size_t len ) {
+	uint8_t *bytes = data;
+	int rc;
+
+	while ( len ) {
+
+		/* Generate random byte */
+		if ( ( rc = rbg_generate ( NULL, 0, 0, bytes, 1 ) ) != 0 )
+			return rc;
+
+		/* Move to next byte if this byte is acceptable */
+		if ( *bytes != 0 ) {
+			bytes++;
+			len--;
+		}
+	}
+
+	return 0;
+}
diff --git a/roms/ipxe/src/crypto/rbg.c b/roms/ipxe/src/crypto/rbg.c
new file mode 100644
index 0000000000000000000000000000000000000000..e2d06978c71d61f36496bc318a1be18a14733fc1
--- /dev/null
+++ b/roms/ipxe/src/crypto/rbg.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * RBG mechanism
+ *
+ * This mechanism is designed to comply with ANS X9.82 Part 4 (April
+ * 2011 Draft) Section 10.  This standard is unfortunately not freely
+ * available.
+ *
+ * The chosen RBG design is that of a DRBG with a live entropy source
+ * with no conditioning function.  Only a single security strength is
+ * supported.  No seedfile is used since there may be no non-volatile
+ * storage available.  The system UUID is used as the personalisation
+ * string.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <ipxe/init.h>
+#include <ipxe/settings.h>
+#include <ipxe/uuid.h>
+#include <ipxe/crypto.h>
+#include <ipxe/drbg.h>
+#include <ipxe/rbg.h>
+
+/** The RBG */
+struct random_bit_generator rbg;
+
+/**
+ * Start up RBG
+ *
+ * @ret rc		Return status code
+ *
+ * This is the RBG_Startup function defined in ANS X9.82 Part 4 (April
+ * 2011 Draft) Section 9.1.2.2.
+ */
+static int rbg_startup ( void ) {
+	union uuid uuid;
+	int len;
+	int rc;
+
+	/* Try to obtain system UUID for use as personalisation
+	 * string, in accordance with ANS X9.82 Part 3-2007 Section
+	 * 8.5.2.  If no UUID is available, proceed without a
+	 * personalisation string.
+	 */
+	if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting, &uuid ) ) < 0 ) {
+		rc = len;
+		DBGC ( &rbg, "RBG could not fetch personalisation string: "
+		       "%s\n", strerror ( rc ) );
+		len = 0;
+	}
+
+	/* Instantiate DRBG */
+	if ( ( rc = drbg_instantiate ( &rbg.state, &uuid, len ) ) != 0 ) {
+		DBGC ( &rbg, "RBG could not instantiate DRBG: %s\n",
+		       strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Shut down RBG
+ *
+ */
+static void rbg_shutdown ( void ) {
+
+	/* Uninstantiate DRBG */
+	drbg_uninstantiate ( &rbg.state );
+}
+
+/** RBG startup function */
+static void rbg_startup_fn ( void ) {
+
+	/* Start up RBG.  There is no way to report an error at this
+	 * stage, but a failed startup will result in an invalid DRBG
+	 * that refuses to generate bits.
+	 */
+	rbg_startup();
+}
+
+/** RBG shutdown function */
+static void rbg_shutdown_fn ( int booting __unused ) {
+
+	/* Shut down RBG */
+	rbg_shutdown();
+}
+
+/** RBG startup table entry */
+struct startup_fn startup_rbg __startup_fn ( STARTUP_NORMAL ) = {
+	.startup = rbg_startup_fn,
+	.shutdown = rbg_shutdown_fn,
+};
diff --git a/roms/ipxe/src/crypto/rootcert.c b/roms/ipxe/src/crypto/rootcert.c
new file mode 100644
index 0000000000000000000000000000000000000000..30ca170f50681c8b022e7e12a66b1a45cb63a4bb
--- /dev/null
+++ b/roms/ipxe/src/crypto/rootcert.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <ipxe/crypto.h>
+#include <ipxe/sha256.h>
+#include <ipxe/x509.h>
+#include <ipxe/settings.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/init.h>
+#include <ipxe/rootcert.h>
+
+/** @file
+ *
+ * Root certificate store
+ *
+ */
+
+/** Length of a root certificate fingerprint */
+#define FINGERPRINT_LEN SHA256_DIGEST_SIZE
+
+/* Allow trusted certificates to be overridden if not explicitly specified */
+#ifdef TRUSTED
+#define ALLOW_TRUST_OVERRIDE 0
+#else
+#define ALLOW_TRUST_OVERRIDE 1
+#endif
+
+/* Use iPXE root CA if no trusted certificates are explicitly specified */
+#ifndef TRUSTED
+#define TRUSTED								\
+	/* iPXE root CA */						\
+	0x9f, 0xaf, 0x71, 0x7b, 0x7f, 0x8c, 0xa2, 0xf9, 0x3c, 0x25,	\
+	0x6c, 0x79, 0xf8, 0xac, 0x55, 0x91, 0x89, 0x5d, 0x66, 0xd1,	\
+	0xff, 0x3b, 0xee, 0x63, 0x97, 0xa7, 0x0d, 0x29, 0xc6, 0x5e,	\
+	0xed, 0x1a,
+#endif
+
+/** Root certificate fingerprints */
+static const uint8_t fingerprints[] = { TRUSTED };
+
+/** Root certificate fingerprint setting */
+static struct setting trust_setting __setting ( SETTING_CRYPTO ) = {
+	.name = "trust",
+	.description = "Trusted root certificate fingerprints",
+	.tag = DHCP_EB_TRUST,
+	.type = &setting_type_hex,
+};
+
+/** Root certificates */
+struct x509_root root_certificates = {
+	.digest = &sha256_algorithm,
+	.count = ( sizeof ( fingerprints ) / FINGERPRINT_LEN ),
+	.fingerprints = fingerprints,
+};
+
+/**
+ * Initialise root certificate
+ *
+ * The list of trusted root certificates can be specified at build
+ * time using the TRUST= build parameter.  If no certificates are
+ * specified, then the default iPXE root CA certificate is trusted.
+ *
+ * If no certificates were explicitly specified, then we allow the
+ * list of trusted root certificate fingerprints to be overridden
+ * using the "trust" setting, but only at the point of iPXE
+ * initialisation.  This prevents untrusted sources of settings
+ * (e.g. DHCP) from subverting the chain of trust, while allowing
+ * trustworthy sources (e.g. VMware GuestInfo or non-volatile stored
+ * options) to specify the trusted root certificate without requiring
+ * a rebuild.
+ */
+static void rootcert_init ( void ) {
+	void *external = NULL;
+	int len;
+	int rc;
+
+	/* Allow trusted root certificates to be overridden only if
+	 * not explicitly specified at build time.
+	 */
+	if ( ALLOW_TRUST_OVERRIDE ) {
+
+		/* Fetch copy of "trust" setting, if it exists.  This
+		 * memory will never be freed.
+		 */
+		len = fetch_setting_copy ( NULL, &trust_setting, &external );
+		if ( len < 0 ) {
+			rc = len;
+			DBGC ( &root_certificates, "ROOTCERT cannot fetch "
+			       "trusted root certificate fingerprints: %s\n",
+			       strerror ( rc ) );
+			/* No way to prevent startup; fail safe by
+			 * trusting no certificates.
+			 */
+			root_certificates.count = 0;
+			return;
+		}
+
+		/* Use certificates from "trust" setting, if present */
+		if ( external ) {
+			root_certificates.fingerprints = external;
+			root_certificates.count = ( len / FINGERPRINT_LEN );
+		}
+	}
+
+	DBGC ( &root_certificates, "ROOTCERT using %d %s certificate(s):\n",
+	       root_certificates.count, ( external ? "external" : "built-in" ));
+	DBGC_HDA ( &root_certificates, 0, root_certificates.fingerprints,
+		   ( root_certificates.count * FINGERPRINT_LEN ) );
+}
+
+/** Root certificate initialiser */
+struct init_fn rootcert_init_fn __init_fn ( INIT_LATE ) = {
+	.initialise = rootcert_init,
+};
diff --git a/roms/ipxe/src/crypto/rsa.c b/roms/ipxe/src/crypto/rsa.c
new file mode 100644
index 0000000000000000000000000000000000000000..1a5cf6cd51f1aa116f328125e933976d740ba7e0
--- /dev/null
+++ b/roms/ipxe/src/crypto/rsa.c
@@ -0,0 +1,642 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/asn1.h>
+#include <ipxe/crypto.h>
+#include <ipxe/bigint.h>
+#include <ipxe/random_nz.h>
+#include <ipxe/md5.h>
+#include <ipxe/sha1.h>
+#include <ipxe/sha256.h>
+#include <ipxe/rsa.h>
+
+/** @file
+ *
+ * RSA public-key cryptography
+ *
+ * RSA is documented in RFC 3447.
+ */
+
+/* Disambiguate the various error causes */
+#define EACCES_VERIFY \
+	__einfo_error ( EINFO_EACCES_VERIFY )
+#define EINFO_EACCES_VERIFY \
+	__einfo_uniqify ( EINFO_EACCES, 0x01, "RSA signature incorrect" )
+
+/** "rsaEncryption" object identifier */
+static uint8_t oid_rsa_encryption[] = { ASN1_OID_RSAENCRYPTION };
+
+/** "md5WithRSAEncryption" object identifier */
+static uint8_t oid_md5_with_rsa_encryption[] =
+	{ ASN1_OID_MD5WITHRSAENCRYPTION };
+
+/** "sha1WithRSAEncryption" object identifier */
+static uint8_t oid_sha1_with_rsa_encryption[] =
+	{ ASN1_OID_SHA1WITHRSAENCRYPTION };
+
+/** "sha256WithRSAEncryption" object identifier */
+static uint8_t oid_sha256_with_rsa_encryption[] =
+	{ ASN1_OID_SHA256WITHRSAENCRYPTION };
+
+/** "rsaEncryption" OID-identified algorithm */
+struct asn1_algorithm rsa_encryption_algorithm __asn1_algorithm = {
+	.name = "rsaEncryption",
+	.pubkey = &rsa_algorithm,
+	.digest = NULL,
+	.oid = ASN1_OID_CURSOR ( oid_rsa_encryption ),
+};
+
+/** "md5WithRSAEncryption" OID-identified algorithm */
+struct asn1_algorithm md5_with_rsa_encryption_algorithm __asn1_algorithm = {
+	.name = "md5WithRSAEncryption",
+	.pubkey = &rsa_algorithm,
+	.digest = &md5_algorithm,
+	.oid = ASN1_OID_CURSOR ( oid_md5_with_rsa_encryption ),
+};
+
+/** "sha1WithRSAEncryption" OID-identified algorithm */
+struct asn1_algorithm sha1_with_rsa_encryption_algorithm __asn1_algorithm = {
+	.name = "sha1WithRSAEncryption",
+	.pubkey = &rsa_algorithm,
+	.digest = &sha1_algorithm,
+	.oid = ASN1_OID_CURSOR ( oid_sha1_with_rsa_encryption ),
+};
+
+/** "sha256WithRSAEncryption" OID-identified algorithm */
+struct asn1_algorithm sha256_with_rsa_encryption_algorithm __asn1_algorithm = {
+	.name = "sha256WithRSAEncryption",
+	.pubkey = &rsa_algorithm,
+	.digest = &sha256_algorithm,
+	.oid = ASN1_OID_CURSOR ( oid_sha256_with_rsa_encryption ),
+};
+
+/** MD5 digestInfo prefix */
+static const uint8_t rsa_md5_prefix_data[] =
+	{ RSA_DIGESTINFO_PREFIX ( MD5_DIGEST_SIZE, ASN1_OID_MD5 ) };
+
+/** SHA-1 digestInfo prefix */
+static const uint8_t rsa_sha1_prefix_data[] =
+	{ RSA_DIGESTINFO_PREFIX ( SHA1_DIGEST_SIZE, ASN1_OID_SHA1 ) };
+
+/** SHA-256 digestInfo prefix */
+static const uint8_t rsa_sha256_prefix_data[] =
+	{ RSA_DIGESTINFO_PREFIX ( SHA256_DIGEST_SIZE, ASN1_OID_SHA256 ) };
+
+/** MD5 digestInfo prefix */
+struct rsa_digestinfo_prefix rsa_md5_prefix __rsa_digestinfo_prefix = {
+	.digest = &md5_algorithm,
+	.data = rsa_md5_prefix_data,
+	.len = sizeof ( rsa_md5_prefix_data ),
+};
+
+/** SHA-1 digestInfo prefix */
+struct rsa_digestinfo_prefix rsa_sha1_prefix __rsa_digestinfo_prefix = {
+	.digest = &sha1_algorithm,
+	.data = rsa_sha1_prefix_data,
+	.len = sizeof ( rsa_sha1_prefix_data ),
+};
+
+/** SHA-256 digestInfo prefix */
+struct rsa_digestinfo_prefix rsa_sha256_prefix __rsa_digestinfo_prefix = {
+	.digest = &sha256_algorithm,
+	.data = rsa_sha256_prefix_data,
+	.len = sizeof ( rsa_sha256_prefix_data ),
+};
+
+/**
+ * Identify RSA prefix
+ *
+ * @v digest		Digest algorithm
+ * @ret prefix		RSA prefix, or NULL
+ */
+static struct rsa_digestinfo_prefix *
+rsa_find_prefix ( struct digest_algorithm *digest ) {
+	struct rsa_digestinfo_prefix *prefix;
+
+	for_each_table_entry ( prefix, RSA_DIGESTINFO_PREFIXES ) {
+		if ( prefix->digest == digest )
+			return prefix;
+	}
+	return NULL;
+}
+
+/**
+ * Free RSA dynamic storage
+ *
+ * @v context		RSA context
+ */
+static void rsa_free ( struct rsa_context *context ) {
+
+	free ( context->dynamic );
+	context->dynamic = NULL;
+}
+
+/**
+ * Allocate RSA dynamic storage
+ *
+ * @v context		RSA context
+ * @v modulus_len	Modulus length
+ * @v exponent_len	Exponent length
+ * @ret rc		Return status code
+ */
+static int rsa_alloc ( struct rsa_context *context, size_t modulus_len,
+		       size_t exponent_len ) {
+	unsigned int size = bigint_required_size ( modulus_len );
+	unsigned int exponent_size = bigint_required_size ( exponent_len );
+	bigint_t ( size ) *modulus;
+	bigint_t ( exponent_size ) *exponent;
+	size_t tmp_len = bigint_mod_exp_tmp_len ( modulus, exponent );
+	struct {
+		bigint_t ( size ) modulus;
+		bigint_t ( exponent_size ) exponent;
+		bigint_t ( size ) input;
+		bigint_t ( size ) output;
+		uint8_t tmp[tmp_len];
+	} __attribute__ (( packed )) *dynamic;
+
+	/* Free any existing dynamic storage */
+	rsa_free ( context );
+
+	/* Allocate dynamic storage */
+	dynamic = malloc ( sizeof ( *dynamic ) );
+	if ( ! dynamic )
+		return -ENOMEM;
+
+	/* Assign dynamic storage */
+	context->dynamic = dynamic;
+	context->modulus0 = &dynamic->modulus.element[0];
+	context->size = size;
+	context->max_len = modulus_len;
+	context->exponent0 = &dynamic->exponent.element[0];
+	context->exponent_size = exponent_size;
+	context->input0 = &dynamic->input.element[0];
+	context->output0 = &dynamic->output.element[0];
+	context->tmp = &dynamic->tmp;
+
+	return 0;
+}
+
+/**
+ * Parse RSA integer
+ *
+ * @v context		RSA context
+ * @v integer		Integer to fill in
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int rsa_parse_integer ( struct rsa_context *context,
+			       struct asn1_cursor *integer,
+			       const struct asn1_cursor *raw ) {
+
+	/* Enter integer */
+	memcpy ( integer, raw, sizeof ( *integer ) );
+	asn1_enter ( integer, ASN1_INTEGER );
+
+	/* Skip initial sign byte if applicable */
+	if ( ( integer->len > 1 ) &&
+	     ( *( ( uint8_t * ) integer->data ) == 0x00 ) ) {
+		integer->data++;
+		integer->len--;
+	}
+
+	/* Fail if cursor or integer are invalid */
+	if ( ! integer->len ) {
+		DBGC ( context, "RSA %p invalid integer:\n", context );
+		DBGC_HDA ( context, 0, raw->data, raw->len );
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * Initialise RSA cipher
+ *
+ * @v ctx		RSA context
+ * @v key		Key
+ * @v key_len		Length of key
+ * @ret rc		Return status code
+ */
+static int rsa_init ( void *ctx, const void *key, size_t key_len ) {
+	struct rsa_context *context = ctx;
+	struct asn1_bit_string bits;
+	struct asn1_cursor modulus;
+	struct asn1_cursor exponent;
+	struct asn1_cursor cursor;
+	int is_private;
+	int rc;
+
+	/* Initialise context */
+	memset ( context, 0, sizeof ( *context ) );
+
+	/* Initialise cursor */
+	cursor.data = key;
+	cursor.len = key_len;
+
+	/* Enter subjectPublicKeyInfo/RSAPrivateKey */
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Determine key format */
+	if ( asn1_type ( &cursor ) == ASN1_INTEGER ) {
+		/* Private key */
+		is_private = 1;
+
+		/* Skip version */
+		asn1_skip_any ( &cursor );
+
+	} else {
+		/* Public key */
+		is_private = 0;
+
+		/* Skip algorithm */
+		asn1_skip ( &cursor, ASN1_SEQUENCE );
+
+		/* Enter subjectPublicKey */
+		if ( ( rc = asn1_integral_bit_string ( &cursor, &bits ) ) != 0 )
+			goto err_parse;
+		cursor.data = bits.data;
+		cursor.len = bits.len;
+
+		/* Enter RSAPublicKey */
+		asn1_enter ( &cursor, ASN1_SEQUENCE );
+	}
+
+	/* Extract modulus */
+	if ( ( rc = rsa_parse_integer ( context, &modulus, &cursor ) ) != 0 )
+		goto err_parse;
+	asn1_skip_any ( &cursor );
+
+	/* Skip public exponent, if applicable */
+	if ( is_private )
+		asn1_skip ( &cursor, ASN1_INTEGER );
+
+	/* Extract publicExponent/privateExponent */
+	if ( ( rc = rsa_parse_integer ( context, &exponent, &cursor ) ) != 0 )
+		goto err_parse;
+
+	DBGC ( context, "RSA %p modulus:\n", context );
+	DBGC_HDA ( context, 0, modulus.data, modulus.len );
+	DBGC ( context, "RSA %p exponent:\n", context );
+	DBGC_HDA ( context, 0, exponent.data, exponent.len );
+
+	/* Allocate dynamic storage */
+	if ( ( rc = rsa_alloc ( context, modulus.len, exponent.len ) ) != 0 )
+		goto err_alloc;
+
+	/* Construct big integers */
+	bigint_init ( ( ( bigint_t ( context->size ) * ) context->modulus0 ),
+		      modulus.data, modulus.len );
+	bigint_init ( ( ( bigint_t ( context->exponent_size ) * )
+			context->exponent0 ), exponent.data, exponent.len );
+
+	return 0;
+
+	rsa_free ( context );
+ err_alloc:
+ err_parse:
+	return rc;
+}
+
+/**
+ * Calculate RSA maximum output length
+ *
+ * @v ctx		RSA context
+ * @ret max_len		Maximum output length
+ */
+static size_t rsa_max_len ( void *ctx ) {
+	struct rsa_context *context = ctx;
+
+	return context->max_len;
+}
+
+/**
+ * Perform RSA cipher operation
+ *
+ * @v context		RSA context
+ * @v in		Input buffer
+ * @v out		Output buffer
+ */
+static void rsa_cipher ( struct rsa_context *context,
+			 const void *in, void *out ) {
+	bigint_t ( context->size ) *input = ( ( void * ) context->input0 );
+	bigint_t ( context->size ) *output = ( ( void * ) context->output0 );
+	bigint_t ( context->size ) *modulus = ( ( void * ) context->modulus0 );
+	bigint_t ( context->exponent_size ) *exponent =
+		( ( void * ) context->exponent0 );
+
+	/* Initialise big integer */
+	bigint_init ( input, in, context->max_len );
+
+	/* Perform modular exponentiation */
+	bigint_mod_exp ( input, modulus, exponent, output, context->tmp );
+
+	/* Copy out result */
+	bigint_done ( output, out, context->max_len );
+}
+
+/**
+ * Encrypt using RSA
+ *
+ * @v ctx		RSA context
+ * @v plaintext		Plaintext
+ * @v plaintext_len	Length of plaintext
+ * @v ciphertext	Ciphertext
+ * @ret ciphertext_len	Length of ciphertext, or negative error
+ */
+static int rsa_encrypt ( void *ctx, const void *plaintext,
+			 size_t plaintext_len, void *ciphertext ) {
+	struct rsa_context *context = ctx;
+	void *temp;
+	uint8_t *encoded;
+	size_t max_len = ( context->max_len - 11 );
+	size_t random_nz_len = ( max_len - plaintext_len + 8 );
+	int rc;
+
+	/* Sanity check */
+	if ( plaintext_len > max_len ) {
+		DBGC ( context, "RSA %p plaintext too long (%zd bytes, max "
+		       "%zd)\n", context, plaintext_len, max_len );
+		return -ERANGE;
+	}
+	DBGC ( context, "RSA %p encrypting:\n", context );
+	DBGC_HDA ( context, 0, plaintext, plaintext_len );
+
+	/* Construct encoded message (using the big integer output
+	 * buffer as temporary storage)
+	 */
+	temp = context->output0;
+	encoded = temp;
+	encoded[0] = 0x00;
+	encoded[1] = 0x02;
+	if ( ( rc = get_random_nz ( &encoded[2], random_nz_len ) ) != 0 ) {
+		DBGC ( context, "RSA %p could not generate random data: %s\n",
+		       context, strerror ( rc ) );
+		return rc;
+	}
+	encoded[ 2 + random_nz_len ] = 0x00;
+	memcpy ( &encoded[ context->max_len - plaintext_len ],
+		 plaintext, plaintext_len );
+
+	/* Encipher the encoded message */
+	rsa_cipher ( context, encoded, ciphertext );
+	DBGC ( context, "RSA %p encrypted:\n", context );
+	DBGC_HDA ( context, 0, ciphertext, context->max_len );
+
+	return context->max_len;
+}
+
+/**
+ * Decrypt using RSA
+ *
+ * @v ctx		RSA context
+ * @v ciphertext	Ciphertext
+ * @v ciphertext_len	Ciphertext length
+ * @v plaintext		Plaintext
+ * @ret plaintext_len	Plaintext length, or negative error
+ */
+static int rsa_decrypt ( void *ctx, const void *ciphertext,
+			 size_t ciphertext_len, void *plaintext ) {
+	struct rsa_context *context = ctx;
+	void *temp;
+	uint8_t *encoded;
+	uint8_t *end;
+	uint8_t *zero;
+	uint8_t *start;
+	size_t plaintext_len;
+
+	/* Sanity check */
+	if ( ciphertext_len != context->max_len ) {
+		DBGC ( context, "RSA %p ciphertext incorrect length (%zd "
+		       "bytes, should be %zd)\n",
+		       context, ciphertext_len, context->max_len );
+		return -ERANGE;
+	}
+	DBGC ( context, "RSA %p decrypting:\n", context );
+	DBGC_HDA ( context, 0, ciphertext, ciphertext_len );
+
+	/* Decipher the message (using the big integer input buffer as
+	 * temporary storage)
+	 */
+	temp = context->input0;
+	encoded = temp;
+	rsa_cipher ( context, ciphertext, encoded );
+
+	/* Parse the message */
+	end = ( encoded + context->max_len );
+	if ( ( encoded[0] != 0x00 ) || ( encoded[1] != 0x02 ) )
+		goto invalid;
+	zero = memchr ( &encoded[2], 0, ( end - &encoded[2] ) );
+	if ( ! zero )
+		goto invalid;
+	start = ( zero + 1 );
+	plaintext_len = ( end - start );
+
+	/* Copy out message */
+	memcpy ( plaintext, start, plaintext_len );
+	DBGC ( context, "RSA %p decrypted:\n", context );
+	DBGC_HDA ( context, 0, plaintext, plaintext_len );
+
+	return plaintext_len;
+
+ invalid:
+	DBGC ( context, "RSA %p invalid decrypted message:\n", context );
+	DBGC_HDA ( context, 0, encoded, context->max_len );
+	return -EINVAL;
+}
+
+/**
+ * Encode RSA digest
+ *
+ * @v context		RSA context
+ * @v digest		Digest algorithm
+ * @v value		Digest value
+ * @v encoded		Encoded digest
+ * @ret rc		Return status code
+ */
+static int rsa_encode_digest ( struct rsa_context *context,
+			       struct digest_algorithm *digest,
+			       const void *value, void *encoded ) {
+	struct rsa_digestinfo_prefix *prefix;
+	size_t digest_len = digest->digestsize;
+	uint8_t *temp = encoded;
+	size_t digestinfo_len;
+	size_t max_len;
+	size_t pad_len;
+
+	/* Identify prefix */
+	prefix = rsa_find_prefix ( digest );
+	if ( ! prefix ) {
+		DBGC ( context, "RSA %p has no prefix for %s\n",
+		       context, digest->name );
+		return -ENOTSUP;
+	}
+	digestinfo_len = ( prefix->len + digest_len );
+
+	/* Sanity check */
+	max_len = ( context->max_len - 11 );
+	if ( digestinfo_len > max_len ) {
+		DBGC ( context, "RSA %p %s digestInfo too long (%zd bytes, max"
+		       "%zd)\n",
+		       context, digest->name, digestinfo_len, max_len );
+		return -ERANGE;
+	}
+	DBGC ( context, "RSA %p encoding %s digest:\n",
+	       context, digest->name );
+	DBGC_HDA ( context, 0, value, digest_len );
+
+	/* Construct encoded message */
+	*(temp++) = 0x00;
+	*(temp++) = 0x01;
+	pad_len = ( max_len - digestinfo_len + 8 );
+	memset ( temp, 0xff, pad_len );
+	temp += pad_len;
+	*(temp++) = 0x00;
+	memcpy ( temp, prefix->data, prefix->len );
+	temp += prefix->len;
+	memcpy ( temp, value, digest_len );
+	temp += digest_len;
+	assert ( temp == ( encoded + context->max_len ) );
+	DBGC ( context, "RSA %p encoded %s digest:\n", context, digest->name );
+	DBGC_HDA ( context, 0, encoded, context->max_len );
+
+	return 0;
+}
+
+/**
+ * Sign digest value using RSA
+ *
+ * @v ctx		RSA context
+ * @v digest		Digest algorithm
+ * @v value		Digest value
+ * @v signature		Signature
+ * @ret signature_len	Signature length, or negative error
+ */
+static int rsa_sign ( void *ctx, struct digest_algorithm *digest,
+		      const void *value, void *signature ) {
+	struct rsa_context *context = ctx;
+	void *temp;
+	int rc;
+
+	DBGC ( context, "RSA %p signing %s digest:\n", context, digest->name );
+	DBGC_HDA ( context, 0, value, digest->digestsize );
+
+	/* Encode digest (using the big integer output buffer as
+	 * temporary storage)
+	 */
+	temp = context->output0;
+	if ( ( rc = rsa_encode_digest ( context, digest, value, temp ) ) != 0 )
+		return rc;
+
+	/* Encipher the encoded digest */
+	rsa_cipher ( context, temp, signature );
+	DBGC ( context, "RSA %p signed %s digest:\n", context, digest->name );
+	DBGC_HDA ( context, 0, signature, context->max_len );
+
+	return context->max_len;
+}
+
+/**
+ * Verify signed digest value using RSA
+ *
+ * @v ctx		RSA context
+ * @v digest		Digest algorithm
+ * @v value		Digest value
+ * @v signature		Signature
+ * @v signature_len	Signature length
+ * @ret rc		Return status code
+ */
+static int rsa_verify ( void *ctx, struct digest_algorithm *digest,
+			const void *value, const void *signature,
+			size_t signature_len ) {
+	struct rsa_context *context = ctx;
+	void *temp;
+	void *expected;
+	void *actual;
+	int rc;
+
+	/* Sanity check */
+	if ( signature_len != context->max_len ) {
+		DBGC ( context, "RSA %p signature incorrect length (%zd "
+		       "bytes, should be %zd)\n",
+		       context, signature_len, context->max_len );
+		return -ERANGE;
+	}
+	DBGC ( context, "RSA %p verifying %s digest:\n",
+	       context, digest->name );
+	DBGC_HDA ( context, 0, value, digest->digestsize );
+	DBGC_HDA ( context, 0, signature, signature_len );
+
+	/* Decipher the signature (using the big integer input buffer
+	 * as temporary storage)
+	 */
+	temp = context->input0;
+	expected = temp;
+	rsa_cipher ( context, signature, expected );
+	DBGC ( context, "RSA %p deciphered signature:\n", context );
+	DBGC_HDA ( context, 0, expected, context->max_len );
+
+	/* Encode digest (using the big integer output buffer as
+	 * temporary storage)
+	 */
+	temp = context->output0;
+	actual = temp;
+	if ( ( rc = rsa_encode_digest ( context, digest, value, actual ) ) !=0 )
+		return rc;
+
+	/* Verify the signature */
+	if ( memcmp ( actual, expected, context->max_len ) != 0 ) {
+		DBGC ( context, "RSA %p signature verification failed\n",
+		       context );
+		return -EACCES_VERIFY;
+	}
+
+	DBGC ( context, "RSA %p signature verified successfully\n", context );
+	return 0;
+}
+
+/**
+ * Finalise RSA cipher
+ *
+ * @v ctx		RSA context
+ */
+static void rsa_final ( void *ctx ) {
+	struct rsa_context *context = ctx;
+
+	rsa_free ( context );
+}
+
+/** RSA public-key algorithm */
+struct pubkey_algorithm rsa_algorithm = {
+	.name		= "rsa",
+	.ctxsize	= sizeof ( struct rsa_context ),
+	.init		= rsa_init,
+	.max_len	= rsa_max_len,
+	.encrypt	= rsa_encrypt,
+	.decrypt	= rsa_decrypt,
+	.sign		= rsa_sign,
+	.verify		= rsa_verify,
+	.final		= rsa_final,
+};
diff --git a/roms/ipxe/src/crypto/sha1.c b/roms/ipxe/src/crypto/sha1.c
new file mode 100644
index 0000000000000000000000000000000000000000..e1bef669ee96a014bf272268354dbd51cca30f1f
--- /dev/null
+++ b/roms/ipxe/src/crypto/sha1.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * SHA-1 algorithm
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <byteswap.h>
+#include <assert.h>
+#include <ipxe/rotate.h>
+#include <ipxe/crypto.h>
+#include <ipxe/asn1.h>
+#include <ipxe/sha1.h>
+
+/** SHA-1 variables */
+struct sha1_variables {
+	/* This layout matches that of struct sha1_digest_data,
+	 * allowing for efficient endianness-conversion,
+	 */
+	uint32_t a;
+	uint32_t b;
+	uint32_t c;
+	uint32_t d;
+	uint32_t e;
+	uint32_t w[80];
+} __attribute__ (( packed ));
+
+/**
+ * f(a,b,c,d) for steps 0 to 19
+ *
+ * @v v		SHA-1 variables
+ * @ret f	f(a,b,c,d)
+ */
+static uint32_t sha1_f_0_19 ( struct sha1_variables *v ) {
+	return ( ( v->b & v->c ) | ( (~v->b) & v->d ) );
+}
+
+/**
+ * f(a,b,c,d) for steps 20 to 39 and 60 to 79
+ *
+ * @v v		SHA-1 variables
+ * @ret f	f(a,b,c,d)
+ */
+static uint32_t sha1_f_20_39_60_79 ( struct sha1_variables *v ) {
+	return ( v->b ^ v->c ^ v->d );
+}
+
+/**
+ * f(a,b,c,d) for steps 40 to 59
+ *
+ * @v v		SHA-1 variables
+ * @ret f	f(a,b,c,d)
+ */
+static uint32_t sha1_f_40_59 ( struct sha1_variables *v ) {
+	return ( ( v->b & v->c ) | ( v->b & v->d ) | ( v->c & v->d ) );
+}
+
+/** An SHA-1 step function */
+struct sha1_step {
+	/**
+	 * Calculate f(a,b,c,d)
+	 *
+	 * @v v		SHA-1 variables
+	 * @ret f	f(a,b,c,d)
+	 */
+	uint32_t ( * f ) ( struct sha1_variables *v );
+	/** Constant k */
+	uint32_t k;
+};
+
+/** SHA-1 steps */
+static struct sha1_step sha1_steps[4] = {
+	/** 0 to 19 */
+	{ .f = sha1_f_0_19,		.k = 0x5a827999 },
+	/** 20 to 39 */
+	{ .f = sha1_f_20_39_60_79,	.k = 0x6ed9eba1 },
+	/** 40 to 59 */
+	{ .f = sha1_f_40_59,		.k = 0x8f1bbcdc },
+	/** 60 to 79 */
+	{ .f = sha1_f_20_39_60_79,	.k = 0xca62c1d6 },
+};
+
+/**
+ * Initialise SHA-1 algorithm
+ *
+ * @v ctx		SHA-1 context
+ */
+static void sha1_init ( void *ctx ) {
+	struct sha1_context *context = ctx;
+
+	context->ddd.dd.digest.h[0] = cpu_to_be32 ( 0x67452301 );
+	context->ddd.dd.digest.h[1] = cpu_to_be32 ( 0xefcdab89 );
+	context->ddd.dd.digest.h[2] = cpu_to_be32 ( 0x98badcfe );
+	context->ddd.dd.digest.h[3] = cpu_to_be32 ( 0x10325476 );
+	context->ddd.dd.digest.h[4] = cpu_to_be32 ( 0xc3d2e1f0 );
+	context->len = 0;
+}
+
+/**
+ * Calculate SHA-1 digest of accumulated data
+ *
+ * @v context		SHA-1 context
+ */
+static void sha1_digest ( struct sha1_context *context ) {
+        union {
+		union sha1_digest_data_dwords ddd;
+		struct sha1_variables v;
+	} u;
+	uint32_t *a = &u.v.a;
+	uint32_t *b = &u.v.b;
+	uint32_t *c = &u.v.c;
+	uint32_t *d = &u.v.d;
+	uint32_t *e = &u.v.e;
+	uint32_t *w = u.v.w;
+	uint32_t f;
+	uint32_t k;
+	uint32_t temp;
+	struct sha1_step *step;
+	unsigned int i;
+
+	/* Sanity checks */
+	assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
+	linker_assert ( &u.ddd.dd.digest.h[0] == a, sha1_bad_layout );
+	linker_assert ( &u.ddd.dd.digest.h[1] == b, sha1_bad_layout );
+	linker_assert ( &u.ddd.dd.digest.h[2] == c, sha1_bad_layout );
+	linker_assert ( &u.ddd.dd.digest.h[3] == d, sha1_bad_layout );
+	linker_assert ( &u.ddd.dd.digest.h[4] == e, sha1_bad_layout );
+	linker_assert ( &u.ddd.dd.data.dword[0] == w, sha1_bad_layout );
+
+	DBGC ( context, "SHA1 digesting:\n" );
+	DBGC_HDA ( context, 0, &context->ddd.dd.digest,
+		   sizeof ( context->ddd.dd.digest ) );
+	DBGC_HDA ( context, context->len, &context->ddd.dd.data,
+		   sizeof ( context->ddd.dd.data ) );
+
+	/* Convert h[0..4] to host-endian, and initialise a, b, c, d,
+	 * e, and w[0..15]
+	 */
+	for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) /
+			    sizeof ( u.ddd.dword[0] ) ) ; i++ ) {
+		be32_to_cpus ( &context->ddd.dword[i] );
+		u.ddd.dword[i] = context->ddd.dword[i];
+	}
+
+	/* Initialise w[16..79] */
+	for ( i = 16 ; i < 80 ; i++ )
+		w[i] = rol32 ( ( w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16] ), 1 );
+
+	/* Main loop */
+	for ( i = 0 ; i < 80 ; i++ ) {
+		step = &sha1_steps[ i / 20 ];
+		f = step->f ( &u.v );
+		k = step->k;
+		temp = ( rol32 ( *a, 5 ) + f + *e + k + w[i] );
+		*e = *d;
+		*d = *c;
+		*c = rol32 ( *b, 30 );
+		*b = *a;
+		*a = temp;
+		DBGC2 ( context, "%2d : %08x %08x %08x %08x %08x\n",
+			i, *a, *b, *c, *d, *e );
+	}
+
+	/* Add chunk to hash and convert back to big-endian */
+	for ( i = 0 ; i < 5 ; i++ ) {
+		context->ddd.dd.digest.h[i] =
+			cpu_to_be32 ( context->ddd.dd.digest.h[i] +
+				      u.ddd.dd.digest.h[i] );
+	}
+
+	DBGC ( context, "SHA1 digested:\n" );
+	DBGC_HDA ( context, 0, &context->ddd.dd.digest,
+		   sizeof ( context->ddd.dd.digest ) );
+}
+
+/**
+ * Accumulate data with SHA-1 algorithm
+ *
+ * @v ctx		SHA-1 context
+ * @v data		Data
+ * @v len		Length of data
+ */
+static void sha1_update ( void *ctx, const void *data, size_t len ) {
+	struct sha1_context *context = ctx;
+	const uint8_t *byte = data;
+	size_t offset;
+
+	/* Accumulate data a byte at a time, performing the digest
+	 * whenever we fill the data buffer
+	 */
+	while ( len-- ) {
+		offset = ( context->len % sizeof ( context->ddd.dd.data ) );
+		context->ddd.dd.data.byte[offset] = *(byte++);
+		context->len++;
+		if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 )
+			sha1_digest ( context );
+	}
+}
+
+/**
+ * Generate SHA-1 digest
+ *
+ * @v ctx		SHA-1 context
+ * @v out		Output buffer
+ */
+static void sha1_final ( void *ctx, void *out ) {
+	struct sha1_context *context = ctx;
+	uint64_t len_bits;
+	uint8_t pad;
+
+	/* Record length before pre-processing */
+	len_bits = cpu_to_be64 ( ( ( uint64_t ) context->len ) * 8 );
+
+	/* Pad with a single "1" bit followed by as many "0" bits as required */
+	pad = 0x80;
+	do {
+		sha1_update ( ctx, &pad, sizeof ( pad ) );
+		pad = 0x00;
+	} while ( ( context->len % sizeof ( context->ddd.dd.data ) ) !=
+		  offsetof ( typeof ( context->ddd.dd.data ), final.len ) );
+
+	/* Append length (in bits) */
+	sha1_update ( ctx, &len_bits, sizeof ( len_bits ) );
+	assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
+
+	/* Copy out final digest */
+	memcpy ( out, &context->ddd.dd.digest,
+		 sizeof ( context->ddd.dd.digest ) );
+}
+
+/** SHA-1 algorithm */
+struct digest_algorithm sha1_algorithm = {
+	.name		= "sha1",
+	.ctxsize	= sizeof ( struct sha1_context ),
+	.blocksize	= sizeof ( union sha1_block ),
+	.digestsize	= sizeof ( struct sha1_digest ),
+	.init		= sha1_init,
+	.update		= sha1_update,
+	.final		= sha1_final,
+};
+
+/** "sha1" object identifier */
+static uint8_t oid_sha1[] = { ASN1_OID_SHA1 };
+
+/** "sha1" OID-identified algorithm */
+struct asn1_algorithm oid_sha1_algorithm __asn1_algorithm = {
+	.name = "sha1",
+	.digest = &sha1_algorithm,
+	.oid = ASN1_OID_CURSOR ( oid_sha1 ),
+};
diff --git a/roms/ipxe/src/crypto/sha1extra.c b/roms/ipxe/src/crypto/sha1extra.c
index 74445e9d1977390f4d6ceda0f3e3..cec0d35e5bf4251c0b56d3b604cf 100644
--- a/roms/ipxe/src/crypto/sha1extra.c
+++ b/roms/ipxe/src/crypto/sha1extra.c
@@ -13,11 +13,13 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
+#include <string.h>
 #include <ipxe/crypto.h>
 #include <ipxe/sha1.h>
 #include <ipxe/hmac.h>
@@ -46,7 +48,7 @@ void prf_sha1 ( const void *key, size_t key_len, const char *label,
 	u8 keym[key_len];	/* modifiable copy of key */
 	u8 in[strlen ( label ) + 1 + data_len + 1]; /* message to HMAC */
 	u8 *in_blknr;		/* pointer to last byte of in, block number */
-	u8 out[SHA1_SIZE];	/* HMAC-SHA1 result */
+	u8 out[SHA1_DIGEST_SIZE]; /* HMAC-SHA1 result */
 	u8 sha1_ctx[SHA1_CTX_SIZE]; /* SHA1 context */
 	const size_t label_len = strlen ( label );
 
@@ -67,14 +69,14 @@ void prf_sha1 ( const void *key, size_t key_len, const char *label,
 		hmac_update ( &sha1_algorithm, sha1_ctx, in, sizeof ( in ) );
 		hmac_final ( &sha1_algorithm, sha1_ctx, keym, &key_len, out );
 
-		if ( prf_len <= SHA1_SIZE ) {
+		if ( prf_len <= sizeof ( out ) ) {
 			memcpy ( prf, out, prf_len );
 			break;
 		}
 
-		memcpy ( prf, out, SHA1_SIZE );
-		prf_len -= SHA1_SIZE;
-		prf += SHA1_SIZE;
+		memcpy ( prf, out, sizeof ( out ) );
+		prf_len -= sizeof ( out );
+		prf += sizeof ( out );
 	}
 }
 
@@ -97,30 +99,31 @@ static void pbkdf2_sha1_f ( const void *passphrase, size_t pass_len,
 {
 	u8 pass[pass_len];	/* modifiable passphrase */
 	u8 in[salt_len + 4];	/* input buffer to first round */
-	u8 last[SHA1_SIZE];	/* output of round N, input of N+1 */
+	u8 last[SHA1_DIGEST_SIZE]; /* output of round N, input of N+1 */
 	u8 sha1_ctx[SHA1_CTX_SIZE];
 	u8 *next_in = in;	/* changed to `last' after first round */
 	int next_size = sizeof ( in );
-	int i, j;
+	int i;
+	unsigned int j;
 
 	blocknr = htonl ( blocknr );
 
 	memcpy ( pass, passphrase, pass_len );
 	memcpy ( in, salt, salt_len );
 	memcpy ( in + salt_len, &blocknr, 4 );
-	memset ( block, 0, SHA1_SIZE );
+	memset ( block, 0, sizeof ( last ) );
 
 	for ( i = 0; i < iterations; i++ ) {
 		hmac_init ( &sha1_algorithm, sha1_ctx, pass, &pass_len );
 		hmac_update ( &sha1_algorithm, sha1_ctx, next_in, next_size );
 		hmac_final ( &sha1_algorithm, sha1_ctx, pass, &pass_len, last );
 
-		for ( j = 0; j < SHA1_SIZE; j++ ) {
+		for ( j = 0; j < sizeof ( last ); j++ ) {
 			block[j] ^= last[j];
 		}
 
 		next_in = last;
-		next_size = SHA1_SIZE;
+		next_size = sizeof ( last );
 	}
 }
 
@@ -146,20 +149,20 @@ void pbkdf2_sha1 ( const void *passphrase, size_t pass_len,
 		   const void *salt, size_t salt_len,
 		   int iterations, void *key, size_t key_len )
 {
-	u32 blocks = ( key_len + SHA1_SIZE - 1 ) / SHA1_SIZE;
+	u32 blocks = ( key_len + SHA1_DIGEST_SIZE - 1 ) / SHA1_DIGEST_SIZE;
 	u32 blk;
-	u8 buf[SHA1_SIZE];
+	u8 buf[SHA1_DIGEST_SIZE];
 
 	for ( blk = 1; blk <= blocks; blk++ ) {
 		pbkdf2_sha1_f ( passphrase, pass_len, salt, salt_len,
 				iterations, blk, buf );
-		if ( key_len <= SHA1_SIZE ) {
+		if ( key_len <= sizeof ( buf ) ) {
 			memcpy ( key, buf, key_len );
 			break;
 		}
 
-		memcpy ( key, buf, SHA1_SIZE );
-		key_len -= SHA1_SIZE;
-		key += SHA1_SIZE;
+		memcpy ( key, buf, sizeof ( buf ) );
+		key_len -= sizeof ( buf );
+		key += sizeof ( buf );
 	}
 }
diff --git a/roms/ipxe/src/crypto/sha256.c b/roms/ipxe/src/crypto/sha256.c
new file mode 100644
index 0000000000000000000000000000000000000000..36e02b3c27d9f17fd7a7c65d7d4091aa63b7fc7e
--- /dev/null
+++ b/roms/ipxe/src/crypto/sha256.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * SHA-256 algorithm
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <byteswap.h>
+#include <assert.h>
+#include <ipxe/rotate.h>
+#include <ipxe/crypto.h>
+#include <ipxe/asn1.h>
+#include <ipxe/sha256.h>
+
+/** SHA-256 variables */
+struct sha256_variables {
+	/* This layout matches that of struct sha256_digest_data,
+	 * allowing for efficient endianness-conversion,
+	 */
+	uint32_t a;
+	uint32_t b;
+	uint32_t c;
+	uint32_t d;
+	uint32_t e;
+	uint32_t f;
+	uint32_t g;
+	uint32_t h;
+	uint32_t w[64];
+} __attribute__ (( packed ));
+
+/** SHA-256 constants */
+static const uint32_t k[64] = {
+	0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
+	0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+	0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
+	0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+	0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
+	0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+	0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
+	0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+	0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
+	0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+	0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+/**
+ * Initialise SHA-256 algorithm
+ *
+ * @v ctx		SHA-256 context
+ */
+static void sha256_init ( void *ctx ) {
+	struct sha256_context *context = ctx;
+
+	context->ddd.dd.digest.h[0] = cpu_to_be32 ( 0x6a09e667 );
+	context->ddd.dd.digest.h[1] = cpu_to_be32 ( 0xbb67ae85 );
+	context->ddd.dd.digest.h[2] = cpu_to_be32 ( 0x3c6ef372 );
+	context->ddd.dd.digest.h[3] = cpu_to_be32 ( 0xa54ff53a );
+	context->ddd.dd.digest.h[4] = cpu_to_be32 ( 0x510e527f );
+	context->ddd.dd.digest.h[5] = cpu_to_be32 ( 0x9b05688c );
+	context->ddd.dd.digest.h[6] = cpu_to_be32 ( 0x1f83d9ab );
+	context->ddd.dd.digest.h[7] = cpu_to_be32 ( 0x5be0cd19 );
+	context->len = 0;
+}
+
+/**
+ * Calculate SHA-256 digest of accumulated data
+ *
+ * @v context		SHA-256 context
+ */
+static void sha256_digest ( struct sha256_context *context ) {
+        union {
+		union sha256_digest_data_dwords ddd;
+		struct sha256_variables v;
+	} u;
+	uint32_t *a = &u.v.a;
+	uint32_t *b = &u.v.b;
+	uint32_t *c = &u.v.c;
+	uint32_t *d = &u.v.d;
+	uint32_t *e = &u.v.e;
+	uint32_t *f = &u.v.f;
+	uint32_t *g = &u.v.g;
+	uint32_t *h = &u.v.h;
+	uint32_t *w = u.v.w;
+	uint32_t s0;
+	uint32_t s1;
+	uint32_t maj;
+	uint32_t t1;
+	uint32_t t2;
+	uint32_t ch;
+	unsigned int i;
+
+	/* Sanity checks */
+	assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
+	linker_assert ( &u.ddd.dd.digest.h[0] == a, sha256_bad_layout );
+	linker_assert ( &u.ddd.dd.digest.h[1] == b, sha256_bad_layout );
+	linker_assert ( &u.ddd.dd.digest.h[2] == c, sha256_bad_layout );
+	linker_assert ( &u.ddd.dd.digest.h[3] == d, sha256_bad_layout );
+	linker_assert ( &u.ddd.dd.digest.h[4] == e, sha256_bad_layout );
+	linker_assert ( &u.ddd.dd.digest.h[5] == f, sha256_bad_layout );
+	linker_assert ( &u.ddd.dd.digest.h[6] == g, sha256_bad_layout );
+	linker_assert ( &u.ddd.dd.digest.h[7] == h, sha256_bad_layout );
+	linker_assert ( &u.ddd.dd.data.dword[0] == w, sha256_bad_layout );
+
+	DBGC ( context, "SHA256 digesting:\n" );
+	DBGC_HDA ( context, 0, &context->ddd.dd.digest,
+		   sizeof ( context->ddd.dd.digest ) );
+	DBGC_HDA ( context, context->len, &context->ddd.dd.data,
+		   sizeof ( context->ddd.dd.data ) );
+
+	/* Convert h[0..7] to host-endian, and initialise a, b, c, d,
+	 * e, f, g, h, and w[0..15]
+	 */
+	for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) /
+			    sizeof ( u.ddd.dword[0] ) ) ; i++ ) {
+		be32_to_cpus ( &context->ddd.dword[i] );
+		u.ddd.dword[i] = context->ddd.dword[i];
+	}
+
+	/* Initialise w[16..63] */
+	for ( i = 16 ; i < 64 ; i++ ) {
+		s0 = ( ror32 ( w[i-15], 7 ) ^ ror32 ( w[i-15], 18 ) ^
+		       ( w[i-15] >> 3 ) );
+		s1 = ( ror32 ( w[i-2], 17 ) ^ ror32 ( w[i-2], 19 ) ^
+		       ( w[i-2] >> 10 ) );
+		w[i] = ( w[i-16] + s0 + w[i-7] + s1 );
+	}
+
+	/* Main loop */
+	for ( i = 0 ; i < 64 ; i++ ) {
+		s0 = ( ror32 ( *a, 2 ) ^ ror32 ( *a, 13 ) ^ ror32 ( *a, 22 ) );
+		maj = ( ( *a & *b ) ^ ( *a & *c ) ^ ( *b & *c ) );
+		t2 = ( s0 + maj );
+		s1 = ( ror32 ( *e, 6 ) ^ ror32 ( *e, 11 ) ^ ror32 ( *e, 25 ) );
+		ch = ( ( *e & *f ) ^ ( (~*e) & *g ) );
+		t1 = ( *h + s1 + ch + k[i] + w[i] );
+		*h = *g;
+		*g = *f;
+		*f = *e;
+		*e = ( *d + t1 );
+		*d = *c;
+		*c = *b;
+		*b = *a;
+		*a = ( t1 + t2 );
+		DBGC2 ( context, "%2d : %08x %08x %08x %08x %08x %08x %08x "
+			"%08x\n", i, *a, *b, *c, *d, *e, *f, *g, *h );
+	}
+
+	/* Add chunk to hash and convert back to big-endian */
+	for ( i = 0 ; i < 8 ; i++ ) {
+		context->ddd.dd.digest.h[i] =
+			cpu_to_be32 ( context->ddd.dd.digest.h[i] +
+				      u.ddd.dd.digest.h[i] );
+	}
+
+	DBGC ( context, "SHA256 digested:\n" );
+	DBGC_HDA ( context, 0, &context->ddd.dd.digest,
+		   sizeof ( context->ddd.dd.digest ) );
+}
+
+/**
+ * Accumulate data with SHA-256 algorithm
+ *
+ * @v ctx		SHA-256 context
+ * @v data		Data
+ * @v len		Length of data
+ */
+static void sha256_update ( void *ctx, const void *data, size_t len ) {
+	struct sha256_context *context = ctx;
+	const uint8_t *byte = data;
+	size_t offset;
+
+	/* Accumulate data a byte at a time, performing the digest
+	 * whenever we fill the data buffer
+	 */
+	while ( len-- ) {
+		offset = ( context->len % sizeof ( context->ddd.dd.data ) );
+		context->ddd.dd.data.byte[offset] = *(byte++);
+		context->len++;
+		if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 )
+			sha256_digest ( context );
+	}
+}
+
+/**
+ * Generate SHA-256 digest
+ *
+ * @v ctx		SHA-256 context
+ * @v out		Output buffer
+ */
+static void sha256_final ( void *ctx, void *out ) {
+	struct sha256_context *context = ctx;
+	uint64_t len_bits;
+	uint8_t pad;
+
+	/* Record length before pre-processing */
+	len_bits = cpu_to_be64 ( ( ( uint64_t ) context->len ) * 8 );
+
+	/* Pad with a single "1" bit followed by as many "0" bits as required */
+	pad = 0x80;
+	do {
+		sha256_update ( ctx, &pad, sizeof ( pad ) );
+		pad = 0x00;
+	} while ( ( context->len % sizeof ( context->ddd.dd.data ) ) !=
+		  offsetof ( typeof ( context->ddd.dd.data ), final.len ) );
+
+	/* Append length (in bits) */
+	sha256_update ( ctx, &len_bits, sizeof ( len_bits ) );
+	assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
+
+	/* Copy out final digest */
+	memcpy ( out, &context->ddd.dd.digest,
+		 sizeof ( context->ddd.dd.digest ) );
+}
+
+/** SHA-256 algorithm */
+struct digest_algorithm sha256_algorithm = {
+	.name		= "sha256",
+	.ctxsize	= sizeof ( struct sha256_context ),
+	.blocksize	= sizeof ( union sha256_block ),
+	.digestsize	= sizeof ( struct sha256_digest ),
+	.init		= sha256_init,
+	.update		= sha256_update,
+	.final		= sha256_final,
+};
+
+/** "sha256" object identifier */
+static uint8_t oid_sha256[] = { ASN1_OID_SHA256 };
+
+/** "sha256" OID-identified algorithm */
+struct asn1_algorithm oid_sha256_algorithm __asn1_algorithm = {
+	.name = "sha256",
+	.digest = &sha256_algorithm,
+	.oid = ASN1_OID_CURSOR ( oid_sha256 ),
+};
diff --git a/roms/ipxe/src/crypto/x509.c b/roms/ipxe/src/crypto/x509.c
index 49bc2b8676dbd00c03ae9cc2ce57..df3c5c0de18023320a276d434eaf 100644
--- a/roms/ipxe/src/crypto/x509.c
+++ b/roms/ipxe/src/crypto/x509.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -21,163 +22,1570 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <assert.h>
+#include <ipxe/list.h>
+#include <ipxe/malloc.h>
 #include <ipxe/asn1.h>
+#include <ipxe/crypto.h>
+#include <ipxe/md5.h>
+#include <ipxe/sha1.h>
+#include <ipxe/sha256.h>
+#include <ipxe/rsa.h>
+#include <ipxe/rootcert.h>
 #include <ipxe/x509.h>
 
 /** @file
  *
  * X.509 certificates
  *
- * The structure of X.509v3 certificates is concisely documented in
- * RFC5280 section 4.1.  The structure of RSA public keys is
- * documented in RFC2313.
+ * The structure of X.509v3 certificates is documented in RFC 5280
+ * section 4.1.
  */
 
-/** Object Identifier for "rsaEncryption" (1.2.840.113549.1.1.1) */
-static const uint8_t oid_rsa_encryption[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7,
-					      0x0d, 0x01, 0x01, 0x01 };
+/* Disambiguate the various error causes */
+#define ENOTSUP_ALGORITHM \
+	__einfo_error ( EINFO_ENOTSUP_ALGORITHM )
+#define EINFO_ENOTSUP_ALGORITHM \
+	__einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported algorithm" )
+#define ENOTSUP_EXTENSION \
+	__einfo_error ( EINFO_ENOTSUP_EXTENSION )
+#define EINFO_ENOTSUP_EXTENSION \
+	__einfo_uniqify ( EINFO_ENOTSUP, 0x02, "Unsupported extension" )
+#define EINVAL_ALGORITHM \
+	__einfo_error ( EINFO_EINVAL_ALGORITHM )
+#define EINFO_EINVAL_ALGORITHM \
+	__einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid algorithm type" )
+#define EINVAL_ALGORITHM_MISMATCH \
+	__einfo_error ( EINFO_EINVAL_ALGORITHM_MISMATCH )
+#define EINFO_EINVAL_ALGORITHM_MISMATCH \
+	__einfo_uniqify ( EINFO_EINVAL, 0x04, "Signature algorithm mismatch" )
+#define EINVAL_PATH_LEN \
+	__einfo_error ( EINFO_EINVAL_PATH_LEN )
+#define EINFO_EINVAL_PATH_LEN \
+	__einfo_uniqify ( EINFO_EINVAL, 0x05, "Invalid pathLenConstraint" )
+#define EINVAL_VERSION \
+	__einfo_error ( EINFO_EINVAL_VERSION )
+#define EINFO_EINVAL_VERSION \
+	__einfo_uniqify ( EINFO_EINVAL, 0x06, "Invalid version" )
+#define EACCES_WRONG_ISSUER \
+	__einfo_error ( EINFO_EACCES_WRONG_ISSUER )
+#define EINFO_EACCES_WRONG_ISSUER \
+	__einfo_uniqify ( EINFO_EACCES, 0x01, "Wrong issuer" )
+#define EACCES_NOT_CA \
+	__einfo_error ( EINFO_EACCES_NOT_CA )
+#define EINFO_EACCES_NOT_CA \
+	__einfo_uniqify ( EINFO_EACCES, 0x02, "Not a CA certificate" )
+#define EACCES_KEY_USAGE \
+	__einfo_error ( EINFO_EACCES_KEY_USAGE )
+#define EINFO_EACCES_KEY_USAGE \
+	__einfo_uniqify ( EINFO_EACCES, 0x03, "Incorrect key usage" )
+#define EACCES_EXPIRED \
+	__einfo_error ( EINFO_EACCES_EXPIRED )
+#define EINFO_EACCES_EXPIRED \
+	__einfo_uniqify ( EINFO_EACCES, 0x04, "Expired (or not yet valid)" )
+#define EACCES_PATH_LEN \
+	__einfo_error ( EINFO_EACCES_PATH_LEN )
+#define EINFO_EACCES_PATH_LEN \
+	__einfo_uniqify ( EINFO_EACCES, 0x05, "Maximum path length exceeded" )
+#define EACCES_UNTRUSTED \
+	__einfo_error ( EINFO_EACCES_UNTRUSTED )
+#define EINFO_EACCES_UNTRUSTED \
+	__einfo_uniqify ( EINFO_EACCES, 0x06, "Untrusted root certificate" )
+#define EACCES_OUT_OF_ORDER \
+	__einfo_error ( EINFO_EACCES_OUT_OF_ORDER )
+#define EINFO_EACCES_OUT_OF_ORDER \
+	__einfo_uniqify ( EINFO_EACCES, 0x07, "Validation out of order" )
+#define EACCES_EMPTY \
+	__einfo_error ( EINFO_EACCES_EMPTY )
+#define EINFO_EACCES_EMPTY \
+	__einfo_uniqify ( EINFO_EACCES, 0x08, "Empty certificate chain" )
+#define EACCES_OCSP_REQUIRED \
+	__einfo_error ( EINFO_EACCES_OCSP_REQUIRED )
+#define EINFO_EACCES_OCSP_REQUIRED \
+	__einfo_uniqify ( EINFO_EACCES, 0x09, "OCSP check required" )
+
+/** Certificate cache */
+static LIST_HEAD ( x509_cache );
+
+/**
+ * Free X.509 certificate
+ *
+ * @v refcnt		Reference count
+ */
+static void x509_free ( struct refcnt *refcnt ) {
+	struct x509_certificate *cert =
+		container_of ( refcnt, struct x509_certificate, refcnt );
+
+	DBGC2 ( cert, "X509 %p freed\n", cert );
+	free ( cert->subject.name );
+	free ( cert->extensions.auth_info.ocsp.uri );
+	free ( cert );
+}
+
+/**
+ * Discard a cached certificate
+ *
+ * @ret discarded	Number of cached items discarded
+ */
+static unsigned int x509_discard ( void ) {
+	struct x509_certificate *cert;
+
+	/* Discard the least recently used certificate for which the
+	 * only reference is held by the cache itself.
+	 */
+	list_for_each_entry_reverse ( cert, &x509_cache, list ) {
+		if ( cert->refcnt.count == 0 ) {
+			list_del ( &cert->list );
+			x509_put ( cert );
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/** X.509 cache discarder */
+struct cache_discarder x509_discarder __cache_discarder ( CACHE_NORMAL ) = {
+	.discard = x509_discard,
+};
+
+/** "commonName" object identifier */
+static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME };
+
+/** "commonName" object identifier cursor */
+static struct asn1_cursor oid_common_name_cursor =
+	ASN1_OID_CURSOR ( oid_common_name );
 
 /**
- * Identify X.509 certificate public key
+ * Parse X.509 certificate version
  *
- * @v certificate	Certificate
- * @v algorithm		Public key algorithm to fill in
- * @v pubkey		Public key value to fill in
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
  * @ret rc		Return status code
  */
-static int x509_public_key ( const struct asn1_cursor *certificate,
-			     struct asn1_cursor *algorithm,
-			     struct asn1_cursor *pubkey ) {
+static int x509_parse_version ( struct x509_certificate *cert,
+				const struct asn1_cursor *raw ) {
 	struct asn1_cursor cursor;
+	int version;
 	int rc;
 
-	/* Locate subjectPublicKeyInfo */
-	memcpy ( &cursor, certificate, sizeof ( cursor ) );
-	rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */
-	       asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */
-	       asn1_skip ( &cursor, ASN1_EXPLICIT_TAG ), /* version */
-	       asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */
-	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */
-	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */
-	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* validity */
-	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* name */
-	       asn1_enter ( &cursor, ASN1_SEQUENCE )/* subjectPublicKeyInfo*/);
-	if ( rc != 0 ) {
-		DBG ( "Cannot locate subjectPublicKeyInfo in:\n" );
-		DBG_HDA ( 0, certificate->data, certificate->len );
+	/* Enter version */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+
+	/* Parse integer */
+	if ( ( rc = asn1_integer ( &cursor, &version ) ) != 0 ) {
+		DBGC ( cert, "X509 %p cannot parse version: %s\n",
+		       cert, strerror ( rc ) );
+		DBGC_HDA ( cert, 0, raw->data, raw->len );
 		return rc;
 	}
 
-	/* Locate algorithm */
-	memcpy ( algorithm, &cursor, sizeof ( *algorithm ) );
-	rc = ( asn1_enter ( algorithm, ASN1_SEQUENCE ) /* algorithm */ );
-	if ( rc != 0 ) {
-		DBG ( "Cannot locate algorithm in:\n" );
-		DBG_HDA ( 0, certificate->data, certificate->len );
+	/* Sanity check */
+	if ( version < 0 ) {
+		DBGC ( cert, "X509 %p invalid version %d\n", cert, version );
+		DBGC_HDA ( cert, 0, raw->data, raw->len );
+		return -EINVAL_VERSION;
+	}
+
+	/* Record version */
+	cert->version = version;
+	DBGC2 ( cert, "X509 %p is a version %d certificate\n",
+		cert, ( cert->version + 1 ) );
+
+	return 0;
+}
+
+/**
+ * Parse X.509 certificate serial number
+ *
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int x509_parse_serial ( struct x509_certificate *cert,
+			       const struct asn1_cursor *raw ) {
+	struct x509_serial *serial = &cert->serial;
+	int rc;
+
+	/* Record raw serial number */
+	memcpy ( &serial->raw, raw, sizeof ( serial->raw ) );
+	if ( ( rc = asn1_shrink ( &serial->raw, ASN1_INTEGER ) ) != 0 ) {
+		DBGC ( cert, "X509 %p cannot shrink serialNumber: %s\n",
+		       cert, strerror ( rc ) );
 		return rc;
 	}
+	DBGC2 ( cert, "X509 %p issuer is:\n", cert );
+	DBGC2_HDA ( cert, 0, serial->raw.data, serial->raw.len );
 
-	/* Locate subjectPublicKey */
-	memcpy ( pubkey, &cursor, sizeof ( *pubkey ) );
-	rc = ( asn1_skip ( pubkey, ASN1_SEQUENCE ), /* algorithm */
-	       asn1_enter ( pubkey, ASN1_BIT_STRING ) /* subjectPublicKey*/ );
-	if ( rc != 0 ) {
-		DBG ( "Cannot locate subjectPublicKey in:\n" );
-		DBG_HDA ( 0, certificate->data, certificate->len );
+	return 0;
+}
+
+/**
+ * Parse X.509 certificate issuer
+ *
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int x509_parse_issuer ( struct x509_certificate *cert,
+			       const struct asn1_cursor *raw ) {
+	struct x509_issuer *issuer = &cert->issuer;
+	int rc;
+
+	/* Record raw issuer */
+	memcpy ( &issuer->raw, raw, sizeof ( issuer->raw ) );
+	if ( ( rc = asn1_shrink ( &issuer->raw, ASN1_SEQUENCE ) ) != 0 ) {
+		DBGC ( cert, "X509 %p cannot shrink issuer: %s\n",
+		       cert, strerror ( rc ) );
 		return rc;
 	}
+	DBGC2 ( cert, "X509 %p issuer is:\n", cert );
+	DBGC2_HDA ( cert, 0, issuer->raw.data, issuer->raw.len );
 
 	return 0;
 }
 
 /**
- * Identify X.509 certificate RSA modulus and public exponent
+ * Parse X.509 certificate validity
  *
- * @v certificate	Certificate
- * @v rsa		RSA public key to fill in
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
  * @ret rc		Return status code
+ */
+static int x509_parse_validity ( struct x509_certificate *cert,
+				 const struct asn1_cursor *raw ) {
+	struct x509_validity *validity = &cert->validity;
+	struct x509_time *not_before = &validity->not_before;
+	struct x509_time *not_after = &validity->not_after;
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Enter validity */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Parse notBefore */
+	if ( ( rc = asn1_generalized_time ( &cursor,
+					    &not_before->time ) ) != 0 ) {
+		DBGC ( cert, "X509 %p cannot parse notBefore: %s\n",
+		       cert, strerror ( rc ) );
+		return rc;
+	}
+	DBGC2 ( cert, "X509 %p valid from time %lld\n",
+		cert, not_before->time );
+	asn1_skip_any ( &cursor );
+
+	/* Parse notAfter */
+	if ( ( rc = asn1_generalized_time ( &cursor,
+					    &not_after->time ) ) != 0 ) {
+		DBGC ( cert, "X509 %p cannot parse notAfter: %s\n",
+		       cert, strerror ( rc ) );
+		return rc;
+	}
+	DBGC2 ( cert, "X509 %p valid until time %lld\n",
+		cert, not_after->time );
+
+	return 0;
+}
+
+/**
+ * Parse X.509 certificate common name
  *
- * The caller is responsible for eventually calling
- * x509_free_rsa_public_key() to free the storage allocated to hold
- * the RSA modulus and exponent.
+ * @v cert		X.509 certificate
+ * @v name		Common name to fill in
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
  */
-int x509_rsa_public_key ( const struct asn1_cursor *certificate,
-			  struct x509_rsa_public_key *rsa_pubkey ) {
-	struct asn1_cursor algorithm;
-	struct asn1_cursor pubkey;
-	struct asn1_cursor modulus;
-	struct asn1_cursor exponent;
+static int x509_parse_common_name ( struct x509_certificate *cert, char **name,
+				    const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+	struct asn1_cursor oid_cursor;
+	struct asn1_cursor name_cursor;
 	int rc;
 
-	/* First, extract the public key algorithm and key data */
-	if ( ( rc = x509_public_key ( certificate, &algorithm,
-				      &pubkey ) ) != 0 )
+	/* Enter name */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Scan through name list */
+	for ( ; cursor.len ; asn1_skip_any ( &cursor ) ) {
+
+		/* Check for "commonName" OID */
+		memcpy ( &oid_cursor, &cursor, sizeof ( oid_cursor ) );
+		asn1_enter ( &oid_cursor, ASN1_SET );
+		asn1_enter ( &oid_cursor, ASN1_SEQUENCE );
+		memcpy ( &name_cursor, &oid_cursor, sizeof ( name_cursor ) );
+		asn1_enter ( &oid_cursor, ASN1_OID );
+		if ( asn1_compare ( &oid_common_name_cursor, &oid_cursor ) != 0)
+			continue;
+		asn1_skip_any ( &name_cursor );
+		if ( ( rc = asn1_enter_any ( &name_cursor ) ) != 0 ) {
+			DBGC ( cert, "X509 %p cannot locate name:\n", cert );
+			DBGC_HDA ( cert, 0, raw->data, raw->len );
+			return rc;
+		}
+
+		/* Allocate and copy name */
+		*name = zalloc ( name_cursor.len + 1 /* NUL */ );
+		if ( ! *name )
+			return -ENOMEM;
+		memcpy ( *name, name_cursor.data, name_cursor.len );
+
+		/* Check that name contains no NULs */
+		if ( strlen ( *name ) != name_cursor.len ) {
+			DBGC ( cert, "X509 %p contains malicious commonName:\n",
+			       cert );
+			DBGC_HDA ( cert, 0, raw->data, raw->len );
+			return rc;
+		}
+
+		return 0;
+	}
+
+	/* Certificates may not have a commonName */
+	DBGC2 ( cert, "X509 %p no commonName found:\n", cert );
+	return 0;
+}
+
+/**
+ * Parse X.509 certificate subject
+ *
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int x509_parse_subject ( struct x509_certificate *cert,
+				const struct asn1_cursor *raw ) {
+	struct x509_subject *subject = &cert->subject;
+	char **name = &subject->name;
+	int rc;
+
+	/* Record raw subject */
+	memcpy ( &subject->raw, raw, sizeof ( subject->raw ) );
+	asn1_shrink_any ( &subject->raw );
+	DBGC2 ( cert, "X509 %p subject is:\n", cert );
+	DBGC2_HDA ( cert, 0, subject->raw.data, subject->raw.len );
+
+	/* Parse common name */
+	if ( ( rc = x509_parse_common_name ( cert, name, raw ) ) != 0 )
 		return rc;
+	DBGC2 ( cert, "X509 %p common name is \"%s\":\n", cert, *name );
 
-	/* Check that algorithm is RSA */
-	rc = ( asn1_enter ( &algorithm, ASN1_OID ) /* algorithm */ );
-	if ( rc != 0 ) {
-		DBG ( "Cannot locate algorithm:\n" );
-		DBG_HDA ( 0, certificate->data, certificate->len );
-	return rc;
+	return 0;
+}
+
+/**
+ * Parse X.509 certificate public key information
+ *
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int x509_parse_public_key ( struct x509_certificate *cert,
+				   const struct asn1_cursor *raw ) {
+	struct x509_public_key *public_key = &cert->subject.public_key;
+	struct asn1_algorithm **algorithm = &public_key->algorithm;
+	struct asn1_bit_string *raw_bits = &public_key->raw_bits;
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Record raw subjectPublicKeyInfo */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_shrink_any ( &cursor );
+	memcpy ( &public_key->raw, &cursor, sizeof ( public_key->raw ) );
+	DBGC2 ( cert, "X509 %p public key is:\n", cert );
+	DBGC2_HDA ( cert, 0, public_key->raw.data, public_key->raw.len );
+
+	/* Enter subjectPublicKeyInfo */
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Parse algorithm */
+	if ( ( rc = asn1_pubkey_algorithm ( &cursor, algorithm ) ) != 0 ) {
+		DBGC ( cert, "X509 %p could not parse public key algorithm: "
+		       "%s\n", cert, strerror ( rc ) );
+		return rc;
+	}
+	DBGC2 ( cert, "X509 %p public key algorithm is %s\n",
+		cert, (*algorithm)->name );
+	asn1_skip_any ( &cursor );
+
+	/* Parse bit string */
+	if ( ( rc = asn1_bit_string ( &cursor, raw_bits ) ) != 0 ) {
+		DBGC ( cert, "X509 %p could not parse public key bits: %s\n",
+		       cert, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse X.509 certificate basic constraints
+ *
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int x509_parse_basic_constraints ( struct x509_certificate *cert,
+					  const struct asn1_cursor *raw ) {
+	struct x509_basic_constraints *basic = &cert->extensions.basic;
+	struct asn1_cursor cursor;
+	int ca = 0;
+	int path_len;
+	int rc;
+
+	/* Enter basicConstraints */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Parse "cA", if present */
+	if ( asn1_type ( &cursor ) == ASN1_BOOLEAN ) {
+		ca = asn1_boolean ( &cursor );
+		if ( ca < 0 ) {
+			rc = ca;
+			DBGC ( cert, "X509 %p cannot parse cA: %s\n",
+			       cert, strerror ( rc ) );
+			DBGC_HDA ( cert, 0, raw->data, raw->len );
+			return rc;
+		}
+		asn1_skip_any ( &cursor );
+	}
+	basic->ca = ca;
+	DBGC2 ( cert, "X509 %p is %sa CA certificate\n",
+		cert, ( basic->ca ? "" : "not " ) );
+
+	/* Ignore everything else unless "cA" is true */
+	if ( ! ca )
+		return 0;
+
+	/* Parse "pathLenConstraint", if present and applicable */
+	basic->path_len = X509_PATH_LEN_UNLIMITED;
+	if ( asn1_type ( &cursor ) == ASN1_INTEGER ) {
+		if ( ( rc = asn1_integer ( &cursor, &path_len ) ) != 0 ) {
+			DBGC ( cert, "X509 %p cannot parse pathLenConstraint: "
+			       "%s\n", cert, strerror ( rc ) );
+			DBGC_HDA ( cert, 0, raw->data, raw->len );
+			return rc;
+		}
+		if ( path_len < 0 ) {
+			DBGC ( cert, "X509 %p invalid pathLenConstraint %d\n",
+			       cert, path_len );
+			DBGC_HDA ( cert, 0, raw->data, raw->len );
+			return -EINVAL;
+		}
+		basic->path_len = path_len;
+		DBGC2 ( cert, "X509 %p path length constraint is %u\n",
+			cert, basic->path_len );
+	}
+
+	return 0;
+}
+
+/**
+ * Parse X.509 certificate key usage
+ *
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int x509_parse_key_usage ( struct x509_certificate *cert,
+				  const struct asn1_cursor *raw ) {
+	struct x509_key_usage *usage = &cert->extensions.usage;
+	struct asn1_bit_string bit_string;
+	const uint8_t *bytes;
+	size_t len;
+	unsigned int i;
+	int rc;
+
+	/* Mark extension as present */
+	usage->present = 1;
+
+	/* Parse bit string */
+	if ( ( rc = asn1_bit_string ( raw, &bit_string ) ) != 0 ) {
+		DBGC ( cert, "X509 %p could not parse key usage: %s\n",
+		       cert, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Parse key usage bits */
+	bytes = bit_string.data;
+	len = bit_string.len;
+	if ( len > sizeof ( usage->bits ) )
+		len = sizeof ( usage->bits );
+	for ( i = 0 ; i < len ; i++ ) {
+		usage->bits |= ( *(bytes++) << ( 8 * i ) );
+	}
+	DBGC2 ( cert, "X509 %p key usage is %08x\n", cert, usage->bits );
+
+	return 0;
+}
+
+/** "id-kp-codeSigning" object identifier */
+static uint8_t oid_code_signing[] = { ASN1_OID_CODESIGNING };
+
+/** "id-kp-OCSPSigning" object identifier */
+static uint8_t oid_ocsp_signing[] = { ASN1_OID_OCSPSIGNING };
+
+/** Supported key purposes */
+static struct x509_key_purpose x509_key_purposes[] = {
+	{
+		.name = "codeSigning",
+		.bits = X509_CODE_SIGNING,
+		.oid = ASN1_OID_CURSOR ( oid_code_signing ),
+	},
+	{
+		.name = "ocspSigning",
+		.bits = X509_OCSP_SIGNING,
+		.oid = ASN1_OID_CURSOR ( oid_ocsp_signing ),
+	},
+};
+
+/**
+ * Parse X.509 certificate key purpose identifier
+ *
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int x509_parse_key_purpose ( struct x509_certificate *cert,
+				    const struct asn1_cursor *raw ) {
+	struct x509_extended_key_usage *ext_usage = &cert->extensions.ext_usage;
+	struct x509_key_purpose *purpose;
+	struct asn1_cursor cursor;
+	unsigned int i;
+	int rc;
+
+	/* Enter keyPurposeId */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	if ( ( rc = asn1_enter ( &cursor, ASN1_OID ) ) != 0 ) {
+		DBGC ( cert, "X509 %p invalid keyPurposeId:\n", cert );
+		DBGC_HDA ( cert, 0, raw->data, raw->len );
+		return rc;
+	}
+
+	/* Identify key purpose */
+	for ( i = 0 ; i < ( sizeof ( x509_key_purposes ) /
+			    sizeof ( x509_key_purposes[0] ) ) ; i++ ) {
+		purpose = &x509_key_purposes[i];
+		if ( asn1_compare ( &cursor, &purpose->oid ) == 0 ) {
+			DBGC2 ( cert, "X509 %p has key purpose %s\n",
+				cert, purpose->name );
+			ext_usage->bits |= purpose->bits;
+			return 0;
+		}
+	}
+
+	/* Ignore unrecognised key purposes */
+	return 0;
+}
+
+/**
+ * Parse X.509 certificate extended key usage
+ *
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int x509_parse_extended_key_usage ( struct x509_certificate *cert,
+					   const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Enter extKeyUsage */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Parse each extended key usage in turn */
+	while ( cursor.len ) {
+		if ( ( rc = x509_parse_key_purpose ( cert, &cursor ) ) != 0 )
+			return rc;
+		asn1_skip_any ( &cursor );
+	}
+
+	return 0;
+}
+
+/**
+ * Parse X.509 certificate OCSP access method
+ *
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int x509_parse_ocsp ( struct x509_certificate *cert,
+			     const struct asn1_cursor *raw ) {
+	struct x509_ocsp_responder *ocsp = &cert->extensions.auth_info.ocsp;
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Enter accessLocation */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	if ( ( rc = asn1_enter ( &cursor, ASN1_IMPLICIT_TAG ( 6 ) ) ) != 0 ) {
+		DBGC ( cert, "X509 %p OCSP does not contain "
+		       "uniformResourceIdentifier:\n", cert );
+		DBGC_HDA ( cert, 0, raw->data, raw->len );
+		return rc;
+	}
+
+	/* Record URI */
+	ocsp->uri = zalloc ( cursor.len + 1 /* NUL */ );
+	if ( ! ocsp->uri )
+		return -ENOMEM;
+	memcpy ( ocsp->uri, cursor.data, cursor.len );
+	DBGC2 ( cert, "X509 %p OCSP URI is %s:\n", cert, ocsp->uri );
+
+	return 0;
+}
+
+/** "id-ad-ocsp" object identifier */
+static uint8_t oid_ad_ocsp[] = { ASN1_OID_OCSP };
+
+/** Supported access methods */
+static struct x509_access_method x509_access_methods[] = {
+	{
+		.name = "OCSP",
+		.oid = ASN1_OID_CURSOR ( oid_ad_ocsp ),
+		.parse = x509_parse_ocsp,
+	},
+};
+
+/**
+ * Identify X.509 access method by OID
+ *
+ * @v oid		OID
+ * @ret method		Access method, or NULL
+ */
+static struct x509_access_method *
+x509_find_access_method ( const struct asn1_cursor *oid ) {
+	struct x509_access_method *method;
+	unsigned int i;
+
+	for ( i = 0 ; i < ( sizeof ( x509_access_methods ) /
+			    sizeof ( x509_access_methods[0] ) ) ; i++ ) {
+		method = &x509_access_methods[i];
+		if ( asn1_compare ( &method->oid, oid ) == 0 )
+			return method;
+	}
+
+	return NULL;
+}
+
+/**
+ * Parse X.509 certificate access description
+ *
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int x509_parse_access_description ( struct x509_certificate *cert,
+					   const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+	struct asn1_cursor subcursor;
+	struct x509_access_method *method;
+	int rc;
+
+	/* Enter keyPurposeId */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Try to identify access method */
+	memcpy ( &subcursor, &cursor, sizeof ( subcursor ) );
+	asn1_enter ( &subcursor, ASN1_OID );
+	method = x509_find_access_method ( &subcursor );
+	asn1_skip_any ( &cursor );
+	DBGC2 ( cert, "X509 %p found access method %s\n",
+		cert, ( method ? method->name : "<unknown>" ) );
+
+	/* Parse access location, if applicable */
+	if ( method && ( ( rc = method->parse ( cert, &cursor ) ) != 0 ) )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Parse X.509 certificate authority information access
+ *
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int x509_parse_authority_info_access ( struct x509_certificate *cert,
+					      const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Enter authorityInfoAccess */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Parse each access description in turn */
+	while ( cursor.len ) {
+		if ( ( rc = x509_parse_access_description ( cert,
+							    &cursor ) ) != 0 )
+			return rc;
+		asn1_skip_any ( &cursor );
+	}
+
+	return 0;
+}
+
+/** "id-ce-basicConstraints" object identifier */
+static uint8_t oid_ce_basic_constraints[] =
+	{ ASN1_OID_BASICCONSTRAINTS };
+
+/** "id-ce-keyUsage" object identifier */
+static uint8_t oid_ce_key_usage[] =
+	{ ASN1_OID_KEYUSAGE };
+
+/** "id-ce-extKeyUsage" object identifier */
+static uint8_t oid_ce_ext_key_usage[] =
+	{ ASN1_OID_EXTKEYUSAGE };
+
+/** "id-pe-authorityInfoAccess" object identifier */
+static uint8_t oid_pe_authority_info_access[] =
+	{ ASN1_OID_AUTHORITYINFOACCESS };
+
+/** Supported certificate extensions */
+static struct x509_extension x509_extensions[] = {
+	{
+		.name = "basicConstraints",
+		.oid = ASN1_OID_CURSOR ( oid_ce_basic_constraints ),
+		.parse = x509_parse_basic_constraints,
+	},
+	{
+		.name = "keyUsage",
+		.oid = ASN1_OID_CURSOR ( oid_ce_key_usage ),
+		.parse = x509_parse_key_usage,
+	},
+	{
+		.name = "extKeyUsage",
+		.oid = ASN1_OID_CURSOR ( oid_ce_ext_key_usage ),
+		.parse = x509_parse_extended_key_usage,
+	},
+	{
+		.name = "authorityInfoAccess",
+		.oid = ASN1_OID_CURSOR ( oid_pe_authority_info_access ),
+		.parse = x509_parse_authority_info_access,
+	},
+};
+
+/**
+ * Identify X.509 extension by OID
+ *
+ * @v oid		OID
+ * @ret extension	Extension, or NULL
+ */
+static struct x509_extension *
+x509_find_extension ( const struct asn1_cursor *oid ) {
+	struct x509_extension *extension;
+	unsigned int i;
+
+	for ( i = 0 ; i < ( sizeof ( x509_extensions ) /
+			    sizeof ( x509_extensions[0] ) ) ; i++ ) {
+		extension = &x509_extensions[i];
+		if ( asn1_compare ( &extension->oid, oid ) == 0 )
+			return extension;
+	}
+
+	return NULL;
+}
+
+/**
+ * Parse X.509 certificate extension
+ *
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int x509_parse_extension ( struct x509_certificate *cert,
+				  const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+	struct asn1_cursor subcursor;
+	struct x509_extension *extension;
+	int is_critical = 0;
+	int rc;
+
+	/* Enter extension */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Try to identify extension */
+	memcpy ( &subcursor, &cursor, sizeof ( subcursor ) );
+	asn1_enter ( &subcursor, ASN1_OID );
+	extension = x509_find_extension ( &subcursor );
+	asn1_skip_any ( &cursor );
+	DBGC2 ( cert, "X509 %p found extension %s\n",
+		cert, ( extension ? extension->name : "<unknown>" ) );
+
+	/* Identify criticality */
+	if ( asn1_type ( &cursor ) == ASN1_BOOLEAN ) {
+		is_critical = asn1_boolean ( &cursor );
+		if ( is_critical < 0 ) {
+			rc = is_critical;
+			DBGC ( cert, "X509 %p cannot parse extension "
+			       "criticality: %s\n", cert, strerror ( rc ) );
+			DBGC_HDA ( cert, 0, raw->data, raw->len );
+			return rc;
+		}
+		asn1_skip_any ( &cursor );
+	}
+
+	/* Handle unknown extensions */
+	if ( ! extension ) {
+		if ( is_critical ) {
+			/* Fail if we cannot handle a critical extension */
+			DBGC ( cert, "X509 %p cannot handle critical "
+			       "extension:\n", cert );
+			DBGC_HDA ( cert, 0, raw->data, raw->len );
+			return -ENOTSUP_EXTENSION;
+		} else {
+			/* Ignore unknown non-critical extensions */
+			return 0;
+		}
+	};
+
+	/* Extract extnValue */
+	if ( ( rc = asn1_enter ( &cursor, ASN1_OCTET_STRING ) ) != 0 ) {
+		DBGC ( cert, "X509 %p extension missing extnValue:\n", cert );
+		DBGC_HDA ( cert, 0, raw->data, raw->len );
+		return rc;
+	}
+
+	/* Parse extension */
+	if ( ( rc = extension->parse ( cert, &cursor ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Parse X.509 certificate extensions, if present
+ *
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int x509_parse_extensions ( struct x509_certificate *cert,
+				   const struct asn1_cursor *raw ) {
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Enter extensions, if present */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 3 ) );
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Parse each extension in turn */
+	while ( cursor.len ) {
+		if ( ( rc = x509_parse_extension ( cert, &cursor ) ) != 0 )
+			return rc;
+		asn1_skip_any ( &cursor );
+	}
+
+	return 0;
+}
+
+/**
+ * Parse X.509 certificate tbsCertificate
+ *
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int x509_parse_tbscertificate ( struct x509_certificate *cert,
+				       const struct asn1_cursor *raw ) {
+	struct asn1_algorithm **algorithm = &cert->signature_algorithm;
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Record raw tbsCertificate */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	asn1_shrink_any ( &cursor );
+	memcpy ( &cert->tbs, &cursor, sizeof ( cert->tbs ) );
+
+	/* Enter tbsCertificate */
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Parse version, if present */
+	if ( asn1_type ( &cursor ) == ASN1_EXPLICIT_TAG ( 0 ) ) {
+		if ( ( rc = x509_parse_version ( cert, &cursor ) ) != 0 )
+			return rc;
+		asn1_skip_any ( &cursor );
 	}
-	if ( ( algorithm.len != sizeof ( oid_rsa_encryption ) ) ||
-	     ( memcmp ( algorithm.data, &oid_rsa_encryption,
-			sizeof ( oid_rsa_encryption ) ) != 0 ) ) {
-		DBG ( "algorithm is not rsaEncryption in:\n" );
-		DBG_HDA ( 0, certificate->data, certificate->len );
-		return -ENOTSUP;
+
+	/* Parse serialNumber */
+	if ( ( rc = x509_parse_serial ( cert, &cursor ) ) != 0 )
+		return rc;
+	asn1_skip_any ( &cursor );
+
+	/* Parse signature */
+	if ( ( rc = asn1_signature_algorithm ( &cursor, algorithm ) ) != 0 ) {
+		DBGC ( cert, "X509 %p could not parse signature algorithm: "
+		       "%s\n", cert, strerror ( rc ) );
+		return rc;
 	}
+	DBGC2 ( cert, "X509 %p tbsCertificate signature algorithm is %s\n",
+		cert, (*algorithm)->name );
+	asn1_skip_any ( &cursor );
+
+	/* Parse issuer */
+	if ( ( rc = x509_parse_issuer ( cert, &cursor ) ) != 0 )
+		return rc;
+	asn1_skip_any ( &cursor );
+
+	/* Parse validity */
+	if ( ( rc = x509_parse_validity ( cert, &cursor ) ) != 0 )
+		return rc;
+	asn1_skip_any ( &cursor );
+
+	/* Parse subject */
+	if ( ( rc = x509_parse_subject ( cert, &cursor ) ) != 0 )
+		return rc;
+	asn1_skip_any ( &cursor );
+
+	/* Parse subjectPublicKeyInfo */
+	if ( ( rc = x509_parse_public_key ( cert, &cursor ) ) != 0 )
+		return rc;
+	asn1_skip_any ( &cursor );
+
+	/* Parse extensions, if present */
+	if ( ( rc = x509_parse_extensions ( cert, &cursor ) ) != 0 )
+		return rc;
 
-	/* Check that public key is a byte string, i.e. that the
-	 * "unused bits" byte contains zero.
+	return 0;
+}
+
+/**
+ * Parse X.509 certificate from ASN.1 data
+ *
+ * @v cert		X.509 certificate
+ * @v raw		ASN.1 cursor
+ * @ret rc		Return status code
+ */
+static int x509_parse ( struct x509_certificate *cert,
+			const struct asn1_cursor *raw ) {
+	struct x509_signature *signature = &cert->signature;
+	struct asn1_algorithm **signature_algorithm = &signature->algorithm;
+	struct asn1_bit_string *signature_value = &signature->value;
+	struct asn1_cursor cursor;
+	int rc;
+
+	/* Record raw certificate */
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
+	memcpy ( &cert->raw, &cursor, sizeof ( cert->raw ) );
+
+	/* Enter certificate */
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+	/* Parse tbsCertificate */
+	if ( ( rc = x509_parse_tbscertificate ( cert, &cursor ) ) != 0 )
+		return rc;
+	asn1_skip_any ( &cursor );
+
+	/* Parse signatureAlgorithm */
+	if ( ( rc = asn1_signature_algorithm ( &cursor,
+					       signature_algorithm ) ) != 0 ) {
+		DBGC ( cert, "X509 %p could not parse signature algorithm: "
+		       "%s\n", cert, strerror ( rc ) );
+		return rc;
+	}
+	DBGC2 ( cert, "X509 %p signatureAlgorithm is %s\n",
+		cert, (*signature_algorithm)->name );
+	asn1_skip_any ( &cursor );
+
+	/* Parse signatureValue */
+	if ( ( rc = asn1_integral_bit_string ( &cursor,
+					       signature_value ) ) != 0 ) {
+		DBGC ( cert, "X509 %p could not parse signature value: %s\n",
+		       cert, strerror ( rc ) );
+		return rc;
+	}
+	DBGC2 ( cert, "X509 %p signatureValue is:\n", cert );
+	DBGC2_HDA ( cert, 0, signature_value->data, signature_value->len );
+
+	/* Check that algorithm in tbsCertificate matches algorithm in
+	 * signature
 	 */
-	if ( ( pubkey.len < 1 ) ||
-	     ( ( *( uint8_t * ) pubkey.data ) != 0 ) ) {
-		DBG ( "subjectPublicKey is not a byte string in:\n" );
-		DBG_HDA ( 0, certificate->data, certificate->len );
-		return -ENOTSUP;
-	}
-	pubkey.data++;
-	pubkey.len--;
-
-	/* Pick out the modulus and exponent */
-	rc = ( asn1_enter ( &pubkey, ASN1_SEQUENCE ) /* RSAPublicKey */ );
-	if ( rc != 0 ) {
-		DBG ( "Cannot locate RSAPublicKey in:\n" );
-		DBG_HDA ( 0, certificate->data, certificate->len );
-		return -ENOTSUP;
-	}
-	memcpy ( &modulus, &pubkey, sizeof ( modulus ) );
-	rc = ( asn1_enter ( &modulus, ASN1_INTEGER ) /* modulus */ );
-	if ( rc != 0 ) {
-		DBG ( "Cannot locate modulus in:\n" );
-		DBG_HDA ( 0, certificate->data, certificate->len );
-		return -ENOTSUP;
-	}
-	memcpy ( &exponent, &pubkey, sizeof ( exponent ) );
-	rc = ( asn1_skip ( &exponent, ASN1_INTEGER ), /* modulus */
-	       asn1_enter ( &exponent, ASN1_INTEGER ) /* publicExponent */ );
-	if ( rc != 0 ) {
-		DBG ( "Cannot locate publicExponent in:\n" );
-		DBG_HDA ( 0, certificate->data, certificate->len );
-		return -ENOTSUP;
-	}
-
-	/* Allocate space and copy out modulus and exponent */
-	rsa_pubkey->modulus = malloc ( modulus.len + exponent.len );
-	if ( ! rsa_pubkey->modulus )
+	if ( signature->algorithm != (*signature_algorithm) ) {
+		DBGC ( cert, "X509 %p signature algorithm %s does not match "
+		       "signatureAlgorithm %s\n",
+		       cert, signature->algorithm->name,
+		       (*signature_algorithm)->name );
+		return -EINVAL_ALGORITHM_MISMATCH;
+	}
+
+	return 0;
+}
+
+/**
+ * Create X.509 certificate
+ *
+ * @v data		Raw certificate data
+ * @v len		Length of raw data
+ * @ret cert		X.509 certificate
+ * @ret rc		Return status code
+ *
+ * On success, the caller holds a reference to the X.509 certificate,
+ * and is responsible for ultimately calling x509_put().
+ */
+int x509_certificate ( const void *data, size_t len,
+		       struct x509_certificate **cert ) {
+	struct asn1_cursor cursor;
+	void *raw;
+	int rc;
+
+	/* Initialise cursor */
+	cursor.data = data;
+	cursor.len = len;
+	asn1_shrink_any ( &cursor );
+
+	/* Search for certificate within cache */
+	list_for_each_entry ( (*cert), &x509_cache, list ) {
+		if ( asn1_compare ( &cursor, &(*cert)->raw ) == 0 ) {
+
+			DBGC2 ( *cert, "X509 %p \"%s\" cache hit\n",
+				*cert, (*cert)->subject.name );
+
+			/* Mark as most recently used */
+			list_del ( &(*cert)->list );
+			list_add ( &(*cert)->list, &x509_cache );
+
+			/* Add caller's reference */
+			x509_get ( *cert );
+
+			return 0;
+		}
+	}
+
+	/* Allocate and initialise certificate */
+	*cert = zalloc ( sizeof ( **cert ) + cursor.len );
+	if ( ! *cert )
 		return -ENOMEM;
-	rsa_pubkey->exponent = ( rsa_pubkey->modulus + modulus.len );
-	memcpy ( rsa_pubkey->modulus, modulus.data, modulus.len );
-	rsa_pubkey->modulus_len = modulus.len;
-	memcpy ( rsa_pubkey->exponent, exponent.data, exponent.len );
-	rsa_pubkey->exponent_len = exponent.len;
+	ref_init ( &(*cert)->refcnt, x509_free );
+	INIT_LIST_HEAD ( &(*cert)->list );
+	raw = ( *cert + 1 );
+
+	/* Copy raw data */
+	memcpy ( raw, cursor.data, cursor.len );
+	cursor.data = raw;
+
+	/* Parse certificate */
+	if ( ( rc = x509_parse ( *cert, &cursor ) ) != 0 ) {
+		x509_put ( *cert );
+		*cert = NULL;
+		return rc;
+	}
+
+	/* Add certificate to cache */
+	x509_get ( *cert );
+	list_add ( &(*cert)->list, &x509_cache );
+
+	return 0;
+}
+
+/**
+ * Check X.509 certificate signature
+ *
+ * @v cert		X.509 certificate
+ * @v public_key	X.509 public key
+ * @ret rc		Return status code
+ */
+static int x509_check_signature ( struct x509_certificate *cert,
+				  struct x509_public_key *public_key ) {
+	struct x509_signature *signature = &cert->signature;
+	struct asn1_algorithm *algorithm = signature->algorithm;
+	struct digest_algorithm *digest = algorithm->digest;
+	struct pubkey_algorithm *pubkey = algorithm->pubkey;
+	uint8_t digest_ctx[ digest->ctxsize ];
+	uint8_t digest_out[ digest->digestsize ];
+	uint8_t pubkey_ctx[ pubkey->ctxsize ];
+	int rc;
+
+	/* Sanity check */
+	assert ( cert->signature_algorithm == cert->signature.algorithm );
+
+	/* Calculate certificate digest */
+	digest_init ( digest, digest_ctx );
+	digest_update ( digest, digest_ctx, cert->tbs.data, cert->tbs.len );
+	digest_final ( digest, digest_ctx, digest_out );
+	DBGC2 ( cert, "X509 %p \"%s\" digest:\n", cert, cert->subject.name );
+	DBGC2_HDA ( cert, 0, digest_out, sizeof ( digest_out ) );
+
+	/* Check that signature public key algorithm matches signer */
+	if ( public_key->algorithm->pubkey != pubkey ) {
+		DBGC ( cert, "X509 %p \"%s\" signature algorithm %s does not "
+		       "match signer's algorithm %s\n",
+		       cert, cert->subject.name, algorithm->name,
+		       public_key->algorithm->name );
+		rc = -EINVAL_ALGORITHM_MISMATCH;
+		goto err_mismatch;
+	}
+
+	/* Verify signature using signer's public key */
+	if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data,
+				  public_key->raw.len ) ) != 0 ) {
+		DBGC ( cert, "X509 %p \"%s\" cannot initialise public key: "
+		       "%s\n", cert, cert->subject.name, strerror ( rc ) );
+		goto err_pubkey_init;
+	}
+	if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out,
+				    signature->value.data,
+				    signature->value.len ) ) != 0 ) {
+		DBGC ( cert, "X509 %p \"%s\" signature verification failed: "
+		       "%s\n", cert, cert->subject.name, strerror ( rc ) );
+		goto err_pubkey_verify;
+	}
+
+	/* Success */
+	rc = 0;
+
+ err_pubkey_verify:
+	pubkey_final ( pubkey, pubkey_ctx );
+ err_pubkey_init:
+ err_mismatch:
+	return rc;
+}
+
+/**
+ * Check X.509 certificate against issuer certificate
+ *
+ * @v cert		X.509 certificate
+ * @v issuer		X.509 issuer certificate
+ * @ret rc		Return status code
+ */
+int x509_check_issuer ( struct x509_certificate *cert,
+			struct x509_certificate *issuer ) {
+	struct x509_public_key *public_key = &issuer->subject.public_key;
+	int rc;
 
-	DBG2 ( "RSA modulus:\n" );
-	DBG2_HDA ( 0, rsa_pubkey->modulus, rsa_pubkey->modulus_len );
-	DBG2 ( "RSA exponent:\n" );
-	DBG2_HDA ( 0, rsa_pubkey->exponent, rsa_pubkey->exponent_len );
+	/* Check issuer.  In theory, this should be a full X.500 DN
+	 * comparison, which would require support for a plethora of
+	 * abominations such as TeletexString (which allows the
+	 * character set to be changed mid-string using escape codes).
+	 * In practice, we assume that anyone who deliberately changes
+	 * the encoding of the issuer DN is probably a masochist who
+	 * will rather enjoy the process of figuring out exactly why
+	 * their certificate doesn't work.
+	 *
+	 * See http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt
+	 * for some enjoyable ranting on this subject.
+	 */
+	if ( asn1_compare ( &cert->issuer.raw, &issuer->subject.raw ) != 0 ) {
+		DBGC ( cert, "X509 %p \"%s\" issuer does not match X509 %p "
+		       "\"%s\" subject\n", cert, cert->subject.name,
+		       issuer, issuer->subject.name );
+		DBGC_HDA ( cert, 0, cert->issuer.raw.data,
+			   cert->issuer.raw.len );
+		DBGC_HDA ( issuer, 0, issuer->subject.raw.data,
+			   issuer->subject.raw.len );
+		return -EACCES_WRONG_ISSUER;
+	}
+
+	/* Check that issuer is allowed to sign certificates */
+	if ( ! issuer->extensions.basic.ca ) {
+		DBGC ( issuer, "X509 %p \"%s\" cannot sign X509 %p \"%s\": "
+		       "not a CA certificate\n", issuer, issuer->subject.name,
+		       cert, cert->subject.name );
+		return -EACCES_NOT_CA;
+	}
+	if ( issuer->extensions.usage.present &&
+	     ( ! ( issuer->extensions.usage.bits & X509_KEY_CERT_SIGN ) ) ) {
+		DBGC ( issuer, "X509 %p \"%s\" cannot sign X509 %p \"%s\": "
+		       "no keyCertSign usage\n", issuer, issuer->subject.name,
+		       cert, cert->subject.name );
+		return -EACCES_KEY_USAGE;
+	}
+
+	/* Check signature */
+	if ( ( rc = x509_check_signature ( cert, public_key ) ) != 0 )
+		return rc;
 
 	return 0;
 }
+
+/**
+ * Calculate X.509 certificate fingerprint
+ *
+ * @v cert		X.509 certificate
+ * @v digest		Digest algorithm
+ * @v fingerprint	Fingerprint buffer
+ */
+void x509_fingerprint ( struct x509_certificate *cert,
+			struct digest_algorithm *digest,
+			void *fingerprint ) {
+	uint8_t ctx[ digest->ctxsize ];
+
+	/* Calculate fingerprint */
+	digest_init ( digest, ctx );
+	digest_update ( digest, ctx, cert->raw.data, cert->raw.len );
+	digest_final ( digest, ctx, fingerprint );
+}
+
+/**
+ * Check X.509 root certificate
+ *
+ * @v cert		X.509 certificate
+ * @v root		X.509 root certificate store
+ * @ret rc		Return status code
+ */
+int x509_check_root ( struct x509_certificate *cert, struct x509_root *root ) {
+	struct digest_algorithm *digest = root->digest;
+	uint8_t fingerprint[ digest->digestsize ];
+	const uint8_t *root_fingerprint = root->fingerprints;
+	unsigned int i;
+
+	/* Calculate certificate fingerprint */
+	x509_fingerprint ( cert, digest, fingerprint );
+
+	/* Check fingerprint against all root certificates */
+	for ( i = 0 ; i < root->count ; i++ ) {
+		if ( memcmp ( fingerprint, root_fingerprint,
+			      sizeof ( fingerprint ) ) == 0 ) {
+			DBGC ( cert, "X509 %p \"%s\" is a root certificate\n",
+			       cert, cert->subject.name );
+			return 0;
+		}
+		root_fingerprint += sizeof ( fingerprint );
+	}
+
+	DBGC2 ( cert, "X509 %p \"%s\" is not a root certificate\n",
+		cert, cert->subject.name );
+	return -ENOENT;
+}
+
+/**
+ * Check X.509 certificate validity period
+ *
+ * @v cert		X.509 certificate
+ * @v time		Time at which to check certificate
+ * @ret rc		Return status code
+ */
+int x509_check_time ( struct x509_certificate *cert, time_t time ) {
+	struct x509_validity *validity = &cert->validity;
+
+	/* Check validity period */
+	if ( validity->not_before.time > ( time + X509_ERROR_MARGIN_TIME ) ) {
+		DBGC ( cert, "X509 %p \"%s\" is not yet valid (at time %lld)\n",
+		       cert, cert->subject.name, time );
+		return -EACCES_EXPIRED;
+	}
+	if ( validity->not_after.time < ( time - X509_ERROR_MARGIN_TIME ) ) {
+		DBGC ( cert, "X509 %p \"%s\" has expired (at time %lld)\n",
+		       cert, cert->subject.name, time );
+		return -EACCES_EXPIRED;
+	}
+
+	DBGC2 ( cert, "X509 %p \"%s\" is valid (at time %lld)\n",
+		cert, cert->subject.name, time );
+	return 0;
+}
+
+/**
+ * Validate X.509 certificate
+ *
+ * @v cert		X.509 certificate
+ * @v issuer		Issuing X.509 certificate (or NULL)
+ * @v time		Time at which to validate certificate
+ * @v root		Root certificate store, or NULL to use default
+ * @ret rc		Return status code
+ *
+ * The issuing certificate must have already been validated.
+ *
+ * Validation results are cached: if a certificate has already been
+ * successfully validated then @c issuer, @c time, and @c root will be
+ * ignored.
+ */
+int x509_validate ( struct x509_certificate *cert,
+		    struct x509_certificate *issuer,
+		    time_t time, struct x509_root *root ) {
+	unsigned int max_path_remaining;
+	int rc;
+
+	/* Use default root certificate store if none specified */
+	if ( ! root )
+		root = &root_certificates;
+
+	/* Return success if certificate has already been validated */
+	if ( cert->valid )
+		return 0;
+
+	/* Fail if certificate is invalid at specified time */
+	if ( ( rc = x509_check_time ( cert, time ) ) != 0 )
+		return rc;
+
+	/* Succeed if certificate is a trusted root certificate */
+	if ( x509_check_root ( cert, root ) == 0 ) {
+		cert->valid = 1;
+		cert->path_remaining = ( cert->extensions.basic.path_len + 1 );
+		return 0;
+	}
+
+	/* Fail unless we have an issuer */
+	if ( ! issuer ) {
+		DBGC2 ( cert, "X509 %p \"%s\" has no issuer\n",
+			cert, cert->subject.name );
+		return -EACCES_UNTRUSTED;
+	}
+
+	/* Fail unless issuer has already been validated */
+	if ( ! issuer->valid ) {
+		DBGC ( cert, "X509 %p \"%s\" issuer %p \"%s\" has not yet "
+		       "been validated\n", cert, cert->subject.name,
+		       issuer, issuer->subject.name );
+		return -EACCES_OUT_OF_ORDER;
+	}
+
+	/* Fail if issuing certificate cannot validate this certificate */
+	if ( ( rc = x509_check_issuer ( cert, issuer ) ) != 0 )
+		return rc;
+
+	/* Fail if path length constraint is violated */
+	if ( issuer->path_remaining == 0 ) {
+		DBGC ( cert, "X509 %p \"%s\" issuer %p \"%s\" path length "
+		       "exceeded\n", cert, cert->subject.name,
+		       issuer, issuer->subject.name );
+		return -EACCES_PATH_LEN;
+	}
+
+	/* Fail if OCSP is required */
+	if ( cert->extensions.auth_info.ocsp.uri &&
+	     ( ! cert->extensions.auth_info.ocsp.good ) ) {
+		DBGC ( cert, "X509 %p \"%s\" requires an OCSP check\n",
+		       cert, cert->subject.name );
+		return -EACCES_OCSP_REQUIRED;
+	}
+
+	/* Calculate effective path length */
+	cert->path_remaining = ( issuer->path_remaining - 1 );
+	max_path_remaining = ( cert->extensions.basic.path_len + 1 );
+	if ( cert->path_remaining > max_path_remaining )
+		cert->path_remaining = max_path_remaining;
+
+	/* Mark certificate as valid */
+	cert->valid = 1;
+
+	DBGC ( cert, "X509 %p \"%s\" successfully validated using issuer %p "
+	       "\"%s\"\n", cert, cert->subject.name,
+	       issuer, issuer->subject.name );
+	return 0;
+}
+
+/**
+ * Free X.509 certificate chain
+ *
+ * @v refcnt		Reference count
+ */
+static void x509_free_chain ( struct refcnt *refcnt ) {
+	struct x509_chain *chain =
+		container_of ( refcnt, struct x509_chain, refcnt );
+	struct x509_link *link;
+	struct x509_link *tmp;
+
+	DBGC2 ( chain, "X509 chain %p freed\n", chain );
+
+	/* Free each link in the chain */
+	list_for_each_entry_safe ( link, tmp, &chain->links, list ) {
+		x509_put ( link->cert );
+		list_del ( &link->list );
+		free ( link );
+	}
+
+	/* Free chain */
+	free ( chain );
+}
+
+/**
+ * Allocate X.509 certificate chain
+ *
+ * @ret chain		X.509 certificate chain, or NULL
+ */
+struct x509_chain * x509_alloc_chain ( void ) {
+	struct x509_chain *chain;
+
+	/* Allocate chain */
+	chain = zalloc ( sizeof ( *chain ) );
+	if ( ! chain )
+		return NULL;
+
+	/* Initialise chain */
+	ref_init ( &chain->refcnt, x509_free_chain );
+	INIT_LIST_HEAD ( &chain->links );
+
+	DBGC2 ( chain, "X509 chain %p allocated\n", chain );
+	return chain;
+}
+
+/**
+ * Append X.509 certificate to X.509 certificate chain
+ *
+ * @v chain		X.509 certificate chain
+ * @v cert		X.509 certificate
+ * @ret rc		Return status code
+ */
+int x509_append ( struct x509_chain *chain, struct x509_certificate *cert ) {
+	struct x509_link *link;
+
+	/* Allocate link */
+	link = zalloc ( sizeof ( *link ) );
+	if ( ! link )
+		return -ENOMEM;
+
+	/* Add link to chain */
+	link->cert = x509_get ( cert );
+	list_add_tail ( &link->list, &chain->links );
+	DBGC ( chain, "X509 chain %p added X509 %p \"%s\"\n",
+	       chain, cert, cert->subject.name );
+
+	return 0;
+}
+
+/**
+ * Append X.509 certificate to X.509 certificate chain
+ *
+ * @v chain		X.509 certificate chain
+ * @v data		Raw certificate data
+ * @v len		Length of raw data
+ * @ret rc		Return status code
+ */
+int x509_append_raw ( struct x509_chain *chain, const void *data,
+		      size_t len ) {
+	struct x509_certificate *cert;
+	int rc;
+
+	/* Parse certificate */
+	if ( ( rc = x509_certificate ( data, len, &cert ) ) != 0 )
+		goto err_parse;
+
+	/* Append certificate to chain */
+	if ( ( rc = x509_append ( chain, cert ) ) != 0 )
+		goto err_append;
+
+	/* Drop reference to certificate */
+	x509_put ( cert );
+
+	return 0;
+
+ err_append:
+	x509_put ( cert );
+ err_parse:
+	return rc;
+}
+
+/**
+ * Identify X.509 certificate by subject
+ *
+ * @v certs		X.509 certificate list
+ * @v subject		Subject
+ * @ret cert		X.509 certificate, or NULL if not found
+ */
+static struct x509_certificate *
+x509_find_subject ( struct x509_chain *certs,
+		    const struct asn1_cursor *subject ) {
+	struct x509_link *link;
+	struct x509_certificate *cert;
+
+	/* Scan through certificate list */
+	list_for_each_entry ( link, &certs->links, list ) {
+
+		/* Check subject */
+		cert = link->cert;
+		if ( asn1_compare ( subject, &cert->subject.raw ) == 0 )
+			return cert;
+	}
+
+	return NULL;
+}
+
+/**
+ * Append X.509 certificates to X.509 certificate chain
+ *
+ * @v chain		X.509 certificate chain
+ * @v certs		X.509 certificate list
+ * @ret rc		Return status code
+ *
+ * Certificates will be automatically appended to the chain based upon
+ * the subject and issuer names.
+ */
+int x509_auto_append ( struct x509_chain *chain, struct x509_chain *certs ) {
+	struct x509_certificate *cert;
+	struct x509_certificate *previous;
+	int rc;
+
+	/* Get current certificate */
+	cert = x509_last ( chain );
+	if ( ! cert ) {
+		DBGC ( chain, "X509 chain %p has no certificates\n", chain );
+		return -EINVAL;
+	}
+
+	/* Append certificates, in order */
+	while ( 1 ) {
+
+		/* Find issuing certificate */
+		previous = cert;
+		cert = x509_find_subject ( certs, &cert->issuer.raw );
+		if ( ! cert )
+			break;
+		if ( cert == previous )
+			break;
+
+		/* Append certificate to chain */
+		if ( ( rc = x509_append ( chain, cert ) ) != 0 )
+			return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Validate X.509 certificate chain
+ *
+ * @v chain		X.509 certificate chain
+ * @v time		Time at which to validate certificates
+ * @v root		Root certificate store, or NULL to use default
+ * @ret rc		Return status code
+ */
+int x509_validate_chain ( struct x509_chain *chain, time_t time,
+			  struct x509_root *root ) {
+	struct x509_certificate *issuer = NULL;
+	struct x509_link *link;
+	int rc;
+
+	/* Sanity check */
+	if ( list_empty ( &chain->links ) ) {
+		DBGC ( chain, "X509 chain %p is empty\n", chain );
+		return -EACCES_EMPTY;
+	}
+
+	/* Find first certificate that can be validated as a
+	 * standalone (i.e.  is already valid, or can be validated as
+	 * a trusted root certificate).
+	 */
+	list_for_each_entry ( link, &chain->links, list ) {
+
+		/* Try validating this certificate as a standalone */
+		if ( ( rc = x509_validate ( link->cert, NULL, time,
+					    root ) ) != 0 )
+			continue;
+
+		/* Work back up to start of chain, performing pairwise
+		 * validation.
+		 */
+		issuer = link->cert;
+		list_for_each_entry_continue_reverse ( link, &chain->links,
+						       list ) {
+
+			/* Validate this certificate against its issuer */
+			if ( ( rc = x509_validate ( link->cert, issuer, time,
+						    root ) ) != 0 )
+				return rc;
+			issuer = link->cert;
+		}
+
+		return 0;
+	}
+
+	DBGC ( chain, "X509 chain %p found no valid certificates\n", chain );
+	return -EACCES_UNTRUSTED;
+}
diff --git a/roms/ipxe/src/drivers/bitbash/bitbash.c b/roms/ipxe/src/drivers/bitbash/bitbash.c
index ac914075c8fa0f31d40f088320a4..23ca30356509fc21568a2673f4eb 100644
--- a/roms/ipxe/src/drivers/bitbash/bitbash.c
+++ b/roms/ipxe/src/drivers/bitbash/bitbash.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/bitbash/i2c_bit.c b/roms/ipxe/src/drivers/bitbash/i2c_bit.c
index ccf82db8a242a55cb18ac3b859c9..decc8d80e7f4ffed3a40c6427fc1 100644
--- a/roms/ipxe/src/drivers/bitbash/i2c_bit.c
+++ b/roms/ipxe/src/drivers/bitbash/i2c_bit.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -238,6 +239,7 @@ static int i2c_reset ( struct bit_basher *basher ) {
 	 * pull SDA low while SCL is high (which creates a start
 	 * condition).
 	 */
+	open_bit ( basher );
 	setscl ( basher, 0 );
 	setsda ( basher, 1 );
 	for ( i = 0 ; i < I2C_RESET_MAX_CYCLES ; i++ ) {
@@ -250,6 +252,7 @@ static int i2c_reset ( struct bit_basher *basher ) {
 			i2c_stop ( basher );
 			DBGC ( basher, "I2CBIT %p reset after %d attempts\n",
 			       basher, ( i + 1 ) );
+			close_bit ( basher );
 			return 0;
 		}
 		setscl ( basher, 0 );
@@ -257,6 +260,7 @@ static int i2c_reset ( struct bit_basher *basher ) {
 
 	DBGC ( basher, "I2CBIT %p could not reset after %d attempts\n",
 	       basher, i );
+	close_bit ( basher );
 	return -ETIMEDOUT;
 }
 
@@ -284,6 +288,8 @@ static int i2c_bit_read ( struct i2c_interface *i2c,
 	DBGC ( basher, "I2CBIT %p reading from device %x: ",
 	       basher, i2cdev->dev_addr );
 
+	open_bit ( basher );
+
 	for ( ; ; data++, offset++ ) {
 
 		/* Select device for writing */
@@ -311,6 +317,7 @@ static int i2c_bit_read ( struct i2c_interface *i2c,
 	
 	DBGC ( basher, "%s\n", ( rc ? "failed" : "" ) );
 	i2c_stop ( basher );
+	close_bit ( basher );
 	return rc;
 }
 
@@ -338,6 +345,8 @@ static int i2c_bit_write ( struct i2c_interface *i2c,
 	DBGC ( basher, "I2CBIT %p writing to device %x: ",
 	       basher, i2cdev->dev_addr );
 
+	open_bit ( basher );
+
 	for ( ; ; data++, offset++ ) {
 
 		/* Select device for writing */
@@ -358,9 +367,10 @@ static int i2c_bit_write ( struct i2c_interface *i2c,
 		if ( ( rc = i2c_send_byte ( basher, *data ) ) != 0 )
 			break;
 	}
-	
+
 	DBGC ( basher, "%s\n", ( rc ? "failed" : "" ) );
 	i2c_stop ( basher );
+	close_bit ( basher );
 	return rc;
 }
 
diff --git a/roms/ipxe/src/drivers/bitbash/spi_bit.c b/roms/ipxe/src/drivers/bitbash/spi_bit.c
index b64ffb828eddf28eb85b3c7ecd79..1b39d72fa4d3b8cad7c35ee52670 100644
--- a/roms/ipxe/src/drivers/bitbash/spi_bit.c
+++ b/roms/ipxe/src/drivers/bitbash/spi_bit.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -162,6 +163,9 @@ static int spi_bit_rw ( struct spi_bus *bus, struct spi_device *device,
 	uint32_t tmp_address;
 	uint32_t tmp_address_detect;
 
+	/* Open bit-bashing interface */
+	open_bit ( &spibit->basher );
+
 	/* Deassert chip select to reset specified slave */
 	spi_bit_set_slave_select ( spibit, device->slave, DESELECT_SLAVE );
 
@@ -213,6 +217,9 @@ static int spi_bit_rw ( struct spi_bus *bus, struct spi_device *device,
 	/* Deassert chip select on specified slave */
 	spi_bit_set_slave_select ( spibit, device->slave, DESELECT_SLAVE );
 
+	/* Close bit-bashing interface */
+	close_bit ( &spibit->basher );
+
 	return 0;
 }
 
diff --git a/roms/ipxe/src/drivers/block/ata.c b/roms/ipxe/src/drivers/block/ata.c
index 56740012bb2a40e0bb63aa6c92cd..c9b87c20c50c63b73a7f1c760b0e 100644
--- a/roms/ipxe/src/drivers/block/ata.c
+++ b/roms/ipxe/src/drivers/block/ata.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/block/ibft.c b/roms/ipxe/src/drivers/block/ibft.c
index f160963773010fdd96e1f25d288c..75ca51a9c138eedd3e68d7e91245 100644
--- a/roms/ipxe/src/drivers/block/ibft.c
+++ b/roms/ipxe/src/drivers/block/ibft.c
@@ -37,6 +37,7 @@ FILE_LICENCE ( BSD2 );
 #include <ipxe/in.h>
 #include <ipxe/netdevice.h>
 #include <ipxe/ethernet.h>
+#include <ipxe/vlan.h>
 #include <ipxe/dhcp.h>
 #include <ipxe/iscsi.h>
 #include <ipxe/ibft.h>
@@ -264,6 +265,8 @@ static int ibft_fill_nic ( struct ibft_nic *nic,
 	DBG ( "iBFT NIC subnet = /%d\n", nic->subnet_mask_prefix );
 
 	/* Extract values from net-device configuration */
+	nic->vlan = cpu_to_le16 ( vlan_tag ( netdev ) );
+	DBG ( "iBFT NIC VLAN = %02x\n", le16_to_cpu ( nic->vlan ) );
 	if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr,
 					    nic->mac_address ) ) != 0 ) {
 		DBG ( "Could not determine iBFT MAC: %s\n", strerror ( rc ) );
diff --git a/roms/ipxe/src/drivers/block/scsi.c b/roms/ipxe/src/drivers/block/scsi.c
index d14165134cdd7fa49641d1a22be6..b45ae630454c76c97cbd8ccf3e0a 100644
--- a/roms/ipxe/src/drivers/block/scsi.c
+++ b/roms/ipxe/src/drivers/block/scsi.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -218,8 +219,10 @@ struct scsi_device {
 
 /** SCSI device flags */
 enum scsi_device_flags {
-	/** Unit is ready */
-	SCSIDEV_UNIT_READY = 0x0001,
+	/** TEST UNIT READY has been issued */
+	SCSIDEV_UNIT_TESTED = 0x0001,
+	/** TEST UNIT READY has completed successfully */
+	SCSIDEV_UNIT_READY = 0x0002,
 };
 
 /** A SCSI command */
@@ -892,23 +895,25 @@ static struct interface_descriptor scsidev_ready_desc =
 /**
  * SCSI TEST UNIT READY process
  *
- * @v process		Process
+ * @v scsidev		SCSI device
  */
-static void scsidev_step ( struct process *process ) {
-	struct scsi_device *scsidev =
-		container_of ( process, struct scsi_device, process );
+static void scsidev_step ( struct scsi_device *scsidev ) {
 	int rc;
 
+	/* Do nothing if we have already issued TEST UNIT READY */
+	if ( scsidev->flags & SCSIDEV_UNIT_TESTED )
+		return;
+
 	/* Wait until underlying SCSI device is ready */
 	if ( xfer_window ( &scsidev->scsi ) == 0 )
 		return;
 
-	/* Stop process */
-	process_del ( &scsidev->process );
-
 	DBGC ( scsidev, "SCSI %p waiting for unit to become ready\n",
 	       scsidev );
 
+	/* Mark TEST UNIT READY as sent */
+	scsidev->flags |= SCSIDEV_UNIT_TESTED;
+
 	/* Issue TEST UNIT READY command */
 	if ( ( rc = scsidev_test_unit_ready ( scsidev, &scsidev->ready )) !=0){
 		scsidev_close ( scsidev, rc );
@@ -918,6 +923,7 @@ static void scsidev_step ( struct process *process ) {
 
 /** SCSI device SCSI interface operations */
 static struct interface_operation scsidev_scsi_op[] = {
+	INTF_OP ( xfer_window_changed, struct scsi_device *, scsidev_step ),
 	INTF_OP ( intf_close, struct scsi_device *, scsidev_close ),
 };
 
@@ -926,6 +932,10 @@ static struct interface_descriptor scsidev_scsi_desc =
 	INTF_DESC_PASSTHRU ( struct scsi_device, scsi,
 			     scsidev_scsi_op, block );
 
+/** SCSI device process descriptor */
+static struct process_descriptor scsidev_process_desc =
+	PROC_DESC_ONCE ( struct scsi_device, process, scsidev_step );
+
 /**
  * Open SCSI device
  *
@@ -946,7 +956,8 @@ int scsi_open ( struct interface *block, struct interface *scsi,
 	intf_init ( &scsidev->block, &scsidev_block_desc, &scsidev->refcnt );
 	intf_init ( &scsidev->scsi, &scsidev_scsi_desc, &scsidev->refcnt );
 	intf_init ( &scsidev->ready, &scsidev_ready_desc, &scsidev->refcnt );
-	process_init ( &scsidev->process, scsidev_step, &scsidev->refcnt );
+	process_init ( &scsidev->process, &scsidev_process_desc,
+		       &scsidev->refcnt );
 	INIT_LIST_HEAD ( &scsidev->cmds );
 	memcpy ( &scsidev->lun, lun, sizeof ( scsidev->lun ) );
 	DBGC ( scsidev, "SCSI %p created for LUN " SCSI_LUN_FORMAT "\n",
diff --git a/roms/ipxe/src/drivers/bus/isa.c b/roms/ipxe/src/drivers/bus/isa.c
index 9b562c6646c8457f179a82652f74..da0c43c60b48867595f2c01e8e63 100644
--- a/roms/ipxe/src/drivers/bus/isa.c
+++ b/roms/ipxe/src/drivers/bus/isa.c
@@ -46,9 +46,9 @@ static isa_probe_addr_t isa_extra_probe_addrs[] = {
 #endif
 
 #define ISA_IOADDR( driver, ioidx )					  \
-	( ( (ioidx) < 0 ) ?						  \
-	  isa_extra_probe_addrs[ (ioidx) + ISA_EXTRA_PROBE_ADDR_COUNT ] : \
-	  (driver)->probe_addrs[(ioidx)] )
+	( ( (ioidx) >= 0 ) ?						  \
+	  (driver)->probe_addrs[(ioidx)] :				  \
+	  *( isa_extra_probe_addrs + (ioidx) + ISA_EXTRA_PROBE_ADDR_COUNT ) )
 
 static void isabus_remove ( struct root_device *rootdev );
 
diff --git a/roms/ipxe/src/drivers/bus/isapnp.c b/roms/ipxe/src/drivers/bus/isapnp.c
index f7845d3fa2ea09a25010b4c285ac..6417c74a6ac1c9b243ff466b4d8d 100644
--- a/roms/ipxe/src/drivers/bus/isapnp.c
+++ b/roms/ipxe/src/drivers/bus/isapnp.c
@@ -15,7 +15,8 @@
 *
 *    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.
+*    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+*    02110-1301, USA.
 *
 *    Portions of this code:
 *	Copyright (C) 2001  P.J.H.Fox (fox@roestock.demon.co.uk)
diff --git a/roms/ipxe/src/drivers/bus/pci.c b/roms/ipxe/src/drivers/bus/pci.c
index 3ae17e5cff2e6229f66f33788b61..7bd353d8be05a30f1ffd0f1e167c 100644
--- a/roms/ipxe/src/drivers/bus/pci.c
+++ b/roms/ipxe/src/drivers/bus/pci.c
@@ -16,7 +16,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/bus/pcibackup.c b/roms/ipxe/src/drivers/bus/pcibackup.c
index 6719c53c73d58e2a3a7c7e332f01..6b592e8937f7f5b7c5de27bb95f4 100644
--- a/roms/ipxe/src/drivers/bus/pcibackup.c
+++ b/roms/ipxe/src/drivers/bus/pcibackup.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/bus/pcivpd.c b/roms/ipxe/src/drivers/bus/pcivpd.c
index 15cf905985b2d857661e50c9454c..0b7a879fe7f2c0c36a1d55b7b833 100644
--- a/roms/ipxe/src/drivers/bus/pcivpd.c
+++ b/roms/ipxe/src/drivers/bus/pcivpd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/infiniband/arbel.c b/roms/ipxe/src/drivers/infiniband/arbel.c
index c121bfd91bb85ded80e7ecb810f0..1a56ff9af686f262695681815fa2 100644
--- a/roms/ipxe/src/drivers/infiniband/arbel.c
+++ b/roms/ipxe/src/drivers/infiniband/arbel.c
@@ -16,7 +16,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -31,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <byteswap.h>
 #include <ipxe/io.h>
 #include <ipxe/pci.h>
+#include <ipxe/pcibackup.h>
 #include <ipxe/malloc.h>
 #include <ipxe/umalloc.h>
 #include <ipxe/iobuf.h>
@@ -772,6 +774,7 @@ static int arbel_alloc_qpn ( struct ib_device *ibdev,
 		qp->qpn = ( arbel->special_qpn_base + 2 + port_offset );
 		return 0;
 	case IB_QPT_UD:
+	case IB_QPT_RC:
 		/* Find a free queue pair number */
 		qpn_offset = arbel_bitmask_alloc ( arbel->qp_inuse,
 						   ARBEL_MAX_QPS );
@@ -822,6 +825,7 @@ static uint8_t arbel_qp_st[] = {
 	[IB_QPT_SMI] = ARBEL_ST_MLX,
 	[IB_QPT_GSI] = ARBEL_ST_MLX,
 	[IB_QPT_UD] = ARBEL_ST_UD,
+	[IB_QPT_RC] = ARBEL_ST_RC,
 };
 
 /**
@@ -948,6 +952,18 @@ static int arbel_create_qp ( struct ib_device *ibdev,
 	physaddr_t wqe_base_adr;
 	int rc;
 
+	/* Warn about dysfunctional code
+	 *
+	 * Arbel seems to crash the system as soon as the first send
+	 * WQE completes on an RC queue pair.  (NOPs complete
+	 * successfully, so this is a problem specific to the work
+	 * queue rather than the completion queue.)  The cause of this
+	 * problem has remained unknown for over a year.  Patches to
+	 * fix this are welcome.
+	 */
+	if ( qp->type == IB_QPT_RC )
+		DBG ( "*** WARNING: Arbel RC support is non-functional ***\n" );
+
 	/* Calculate queue pair number */
 	if ( ( rc = arbel_alloc_qpn ( ibdev, qp ) ) != 0 )
 		goto err_alloc_qpn;
@@ -1021,7 +1037,11 @@ static int arbel_create_qp ( struct ib_device *ibdev,
 		     ( send_wqe_base_adr >> 6 ) );
 	MLX_FILL_1 ( &qpctx, 35, qpc_eec_data.snd_db_record_index,
 		     arbel_qp->send.doorbell_idx );
-	MLX_FILL_1 ( &qpctx, 38, qpc_eec_data.rsc, 1 );
+	MLX_FILL_4 ( &qpctx, 38,
+		     qpc_eec_data.rre, 1,
+		     qpc_eec_data.rwe, 1,
+		     qpc_eec_data.rae, 1,
+		     qpc_eec_data.rsc, 1 );
 	MLX_FILL_1 ( &qpctx, 41, qpc_eec_data.cqn_rcv, qp->recv.cq->cqn );
 	MLX_FILL_1 ( &qpctx, 42, qpc_eec_data.rcv_wqe_base_adr_l,
 		     ( recv_wqe_base_adr >> 6 ) );
@@ -1084,7 +1104,30 @@ static int arbel_modify_qp ( struct ib_device *ibdev,
 		memset ( &qpctx, 0, sizeof ( qpctx ) );
 		MLX_FILL_2 ( &qpctx, 4,
 			     qpc_eec_data.mtu, ARBEL_MTU_2048,
-			     qpc_eec_data.msg_max, 11 /* 2^11 = 2048 */ );
+			     qpc_eec_data.msg_max, 31 );
+		MLX_FILL_1 ( &qpctx, 7,
+			     qpc_eec_data.remote_qpn_een, qp->av.qpn );
+		MLX_FILL_2 ( &qpctx, 11,
+			     qpc_eec_data.primary_address_path.rnr_retry,
+			     ARBEL_RETRY_MAX,
+			     qpc_eec_data.primary_address_path.rlid,
+			     qp->av.lid );
+		MLX_FILL_2 ( &qpctx, 12,
+			     qpc_eec_data.primary_address_path.ack_timeout,
+			     14 /* 4.096us * 2^(14) = 67ms */,
+			     qpc_eec_data.primary_address_path.max_stat_rate,
+			     arbel_rate ( &qp->av ) );
+		memcpy ( &qpctx.u.dwords[14], &qp->av.gid,
+			 sizeof ( qp->av.gid ) );
+		MLX_FILL_1 ( &qpctx, 30,
+			     qpc_eec_data.retry_count, ARBEL_RETRY_MAX );
+		MLX_FILL_1 ( &qpctx, 39,
+			     qpc_eec_data.next_rcv_psn, qp->recv.psn );
+		MLX_FILL_1 ( &qpctx, 40,
+			     qpc_eec_data.ra_buff_indx,
+			     ( arbel->limits.reserved_rdbs +
+			       ( ( qp->qpn & ~ARBEL_QPN_RANDOM_MASK ) -
+				 arbel->special_qpn_base ) ) );
 		if ( ( rc = arbel_cmd_init2rtr_qpee ( arbel, qp->qpn,
 						      &qpctx ) ) != 0 ) {
 			DBGC ( arbel, "Arbel %p QPN %#lx INIT2RTR_QPEE failed:"
@@ -1097,6 +1140,15 @@ static int arbel_modify_qp ( struct ib_device *ibdev,
 	/* Transition queue to RTS state, if applicable */
 	if ( arbel_qp->state < ARBEL_QP_ST_RTS ) {
 		memset ( &qpctx, 0, sizeof ( qpctx ) );
+		MLX_FILL_1 ( &qpctx, 11,
+			     qpc_eec_data.primary_address_path.rnr_retry,
+			     ARBEL_RETRY_MAX );
+		MLX_FILL_1 ( &qpctx, 12,
+			     qpc_eec_data.primary_address_path.ack_timeout,
+			     14 /* 4.096us * 2^(14) = 67ms */ );
+		MLX_FILL_2 ( &qpctx, 30,
+			     qpc_eec_data.retry_count, ARBEL_RETRY_MAX,
+			     qpc_eec_data.sic, 1 );
 		MLX_FILL_1 ( &qpctx, 32,
 			     qpc_eec_data.next_send_psn, qp->send.psn );
 		if ( ( rc = arbel_cmd_rtr2rts_qpee ( arbel, qp->qpn,
@@ -1198,14 +1250,14 @@ static const union ib_gid arbel_no_gid = {
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector
+ * @v dest		Destination address vector
  * @v iobuf		I/O buffer
  * @v wqe		Send work queue entry
  * @ret nds		Work queue entry size
  */
 static size_t arbel_fill_ud_send_wqe ( struct ib_device *ibdev,
 				       struct ib_queue_pair *qp __unused,
-				       struct ib_address_vector *av,
+				       struct ib_address_vector *dest,
 				       struct io_buffer *iobuf,
 				       union arbel_send_wqe *wqe ) {
 	struct arbel *arbel = ib_get_drvdata ( ibdev );
@@ -1217,16 +1269,16 @@ static size_t arbel_fill_ud_send_wqe ( struct ib_device *ibdev,
 		     ud_address_vector.pd, ARBEL_GLOBAL_PD,
 		     ud_address_vector.port_number, ibdev->port );
 	MLX_FILL_2 ( &wqe->ud.ud, 1,
-		     ud_address_vector.rlid, av->lid,
-		     ud_address_vector.g, av->gid_present );
+		     ud_address_vector.rlid, dest->lid,
+		     ud_address_vector.g, dest->gid_present );
 	MLX_FILL_2 ( &wqe->ud.ud, 2,
-		     ud_address_vector.max_stat_rate, arbel_rate ( av ),
+		     ud_address_vector.max_stat_rate, arbel_rate ( dest ),
 		     ud_address_vector.msg, 3 );
-	MLX_FILL_1 ( &wqe->ud.ud, 3, ud_address_vector.sl, av->sl );
-	gid = ( av->gid_present ? &av->gid : &arbel_no_gid );
+	MLX_FILL_1 ( &wqe->ud.ud, 3, ud_address_vector.sl, dest->sl );
+	gid = ( dest->gid_present ? &dest->gid : &arbel_no_gid );
 	memcpy ( &wqe->ud.ud.u.dwords[4], gid, sizeof ( *gid ) );
-	MLX_FILL_1 ( &wqe->ud.ud, 8, destination_qp, av->qpn );
-	MLX_FILL_1 ( &wqe->ud.ud, 9, q_key, av->qkey );
+	MLX_FILL_1 ( &wqe->ud.ud, 8, destination_qp, dest->qpn );
+	MLX_FILL_1 ( &wqe->ud.ud, 9, q_key, dest->qkey );
 	MLX_FILL_1 ( &wqe->ud.data[0], 0, byte_count, iob_len ( iobuf ) );
 	MLX_FILL_1 ( &wqe->ud.data[0], 1, l_key, arbel->lkey );
 	MLX_FILL_H ( &wqe->ud.data[0], 2,
@@ -1242,15 +1294,14 @@ static size_t arbel_fill_ud_send_wqe ( struct ib_device *ibdev,
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector
+ * @v dest		Destination address vector
  * @v iobuf		I/O buffer
  * @v wqe		Send work queue entry
- * @v next		Previous work queue entry's "next" field
  * @ret nds		Work queue entry size
  */
 static size_t arbel_fill_mlx_send_wqe ( struct ib_device *ibdev,
 					struct ib_queue_pair *qp,
-					struct ib_address_vector *av,
+					struct ib_address_vector *dest,
 					struct io_buffer *iobuf,
 					union arbel_send_wqe *wqe ) {
 	struct arbel *arbel = ib_get_drvdata ( ibdev );
@@ -1260,16 +1311,16 @@ static size_t arbel_fill_mlx_send_wqe ( struct ib_device *ibdev,
 	iob_populate ( &headers, &wqe->mlx.headers, 0,
 		       sizeof ( wqe->mlx.headers ) );
 	iob_reserve ( &headers, sizeof ( wqe->mlx.headers ) );
-	ib_push ( ibdev, &headers, qp, iob_len ( iobuf ), av );
+	ib_push ( ibdev, &headers, qp, iob_len ( iobuf ), dest );
 
 	/* Construct this work queue entry */
 	MLX_FILL_5 ( &wqe->mlx.ctrl, 0,
 		     c, 1 /* generate completion */,
 		     icrc, 0 /* generate ICRC */,
-		     max_statrate, arbel_rate ( av ),
+		     max_statrate, arbel_rate ( dest ),
 		     slr, 0,
 		     v15, ( ( qp->ext_qpn == IB_QPN_SMI ) ? 1 : 0 ) );
-	MLX_FILL_1 ( &wqe->mlx.ctrl, 1, rlid, av->lid );
+	MLX_FILL_1 ( &wqe->mlx.ctrl, 1, rlid, dest->lid );
 	MLX_FILL_1 ( &wqe->mlx.data[0], 0,
 		     byte_count, iob_len ( &headers ) );
 	MLX_FILL_1 ( &wqe->mlx.data[0], 1, l_key, arbel->lkey );
@@ -1288,16 +1339,46 @@ static size_t arbel_fill_mlx_send_wqe ( struct ib_device *ibdev,
 	return ( offsetof ( typeof ( wqe->mlx ), data[2] ) >> 4 );
 }
 
+/**
+ * Construct RC send work queue entry
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v dest		Destination address vector
+ * @v iobuf		I/O buffer
+ * @v wqe		Send work queue entry
+ * @ret nds		Work queue entry size
+ */
+static size_t arbel_fill_rc_send_wqe ( struct ib_device *ibdev,
+				       struct ib_queue_pair *qp __unused,
+				       struct ib_address_vector *dest __unused,
+				       struct io_buffer *iobuf,
+				       union arbel_send_wqe *wqe ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+
+	/* Construct this work queue entry */
+	MLX_FILL_1 ( &wqe->rc.ctrl, 0, always1, 1 );
+	MLX_FILL_1 ( &wqe->rc.data[0], 0, byte_count, iob_len ( iobuf ) );
+	MLX_FILL_1 ( &wqe->rc.data[0], 1, l_key, arbel->lkey );
+	MLX_FILL_H ( &wqe->rc.data[0], 2,
+		     local_address_h, virt_to_bus ( iobuf->data ) );
+	MLX_FILL_1 ( &wqe->rc.data[0], 3,
+		     local_address_l, virt_to_bus ( iobuf->data ) );
+
+	return ( offsetof ( typeof ( wqe->rc ), data[1] ) >> 4 );
+}
+
 /** Work queue entry constructors */
 static size_t
 ( * arbel_fill_send_wqe[] ) ( struct ib_device *ibdev,
 			      struct ib_queue_pair *qp,
-			      struct ib_address_vector *av,
+			      struct ib_address_vector *dest,
 			      struct io_buffer *iobuf,
 			      union arbel_send_wqe *wqe ) = {
 	[IB_QPT_SMI] = arbel_fill_mlx_send_wqe,
 	[IB_QPT_GSI] = arbel_fill_mlx_send_wqe,
 	[IB_QPT_UD] = arbel_fill_ud_send_wqe,
+	[IB_QPT_RC] = arbel_fill_rc_send_wqe,
 };
 
 /**
@@ -1305,13 +1386,13 @@ static size_t
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector
+ * @v dest		Destination address vector
  * @v iobuf		I/O buffer
  * @ret rc		Return status code
  */
 static int arbel_post_send ( struct ib_device *ibdev,
 			     struct ib_queue_pair *qp,
-			     struct ib_address_vector *av,
+			     struct ib_address_vector *dest,
 			     struct io_buffer *iobuf ) {
 	struct arbel *arbel = ib_get_drvdata ( ibdev );
 	struct arbel_queue_pair *arbel_qp = ib_qp_get_drvdata ( qp );
@@ -1341,7 +1422,7 @@ static int arbel_post_send ( struct ib_device *ibdev,
 	assert ( qp->type < ( sizeof ( arbel_fill_send_wqe ) /
 			      sizeof ( arbel_fill_send_wqe[0] ) ) );
 	assert ( arbel_fill_send_wqe[qp->type] != NULL );
-	nds = arbel_fill_send_wqe[qp->type] ( ibdev, qp, av, iobuf, wqe );
+	nds = arbel_fill_send_wqe[qp->type] ( ibdev, qp, dest, iobuf, wqe );
 	DBGCP ( arbel, "Arbel %p QPN %#lx posting send WQE %#lx:\n",
 		arbel, qp->qpn, ( wq->next_idx & wqe_idx_mask ) );
 	DBGCP_HDA ( arbel, virt_to_phys ( wqe ), wqe, sizeof ( *wqe ) );
@@ -1444,9 +1525,10 @@ 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;
-	struct ib_address_vector recv_av;
+	struct ib_address_vector recv_dest;
+	struct ib_address_vector recv_source;
 	struct ib_global_route_header *grh;
-	struct ib_address_vector *av;
+	struct ib_address_vector *source;
 	unsigned int opcode;
 	unsigned long qpn;
 	int is_send;
@@ -1495,6 +1577,7 @@ static int arbel_complete ( struct ib_device *ibdev,
 			    sizeof ( arbel_recv_wq->wqe[0] ) );
 		assert ( wqe_idx < qp->recv.num_wqes );
 	}
+
 	DBGCP ( arbel, "Arbel %p CQN %#lx QPN %#lx %s WQE %#lx completed:\n",
 		arbel, cq->cqn, qp->qpn, ( is_send ? "send" : "recv" ),
 		wqe_idx );
@@ -1526,6 +1609,8 @@ static int arbel_complete ( struct ib_device *ibdev,
 			     l_key, ARBEL_INVALID_LKEY );
 		assert ( len <= iob_tailroom ( iobuf ) );
 		iob_put ( iobuf, len );
+		memset ( &recv_dest, 0, sizeof ( recv_dest ) );
+		recv_dest.qpn = qpn;
 		switch ( qp->type ) {
 		case IB_QPT_SMI:
 		case IB_QPT_GSI:
@@ -1534,20 +1619,27 @@ static int arbel_complete ( struct ib_device *ibdev,
 			grh = iobuf->data;
 			iob_pull ( iobuf, sizeof ( *grh ) );
 			/* Construct address vector */
-			av = &recv_av;
-			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 ) );
+			source = &recv_source;
+			memset ( source, 0, sizeof ( *source ) );
+			source->qpn = MLX_GET ( &cqe->normal, rqpn );
+			source->lid = MLX_GET ( &cqe->normal, rlid );
+			source->sl = MLX_GET ( &cqe->normal, sl );
+			recv_dest.gid_present = source->gid_present =
+				MLX_GET ( &cqe->normal, g );
+			memcpy ( &recv_dest.gid, &grh->dgid,
+				 sizeof ( recv_dest.gid ) );
+			memcpy ( &source->gid, &grh->sgid,
+				 sizeof ( source->gid ) );
+			break;
+		case IB_QPT_RC:
+			source = &qp->av;
 			break;
 		default:
 			assert ( 0 );
 			return -EINVAL;
 		}
 		/* Hand off to completion handler */
-		ib_complete_recv ( ibdev, qp, av, iobuf, rc );
+		ib_complete_recv ( ibdev, qp, &recv_dest, source, iobuf, rc );
 	}
 
 	return rc;
@@ -1807,195 +1899,6 @@ static void arbel_poll_eq ( struct ib_device *ibdev ) {
 	}
 }
 
-/***************************************************************************
- *
- * Infiniband link-layer operations
- *
- ***************************************************************************
- */
-
-/**
- * Initialise Infiniband link
- *
- * @v ibdev		Infiniband device
- * @ret rc		Return status code
- */
-static int arbel_open ( struct ib_device *ibdev ) {
-	struct arbel *arbel = ib_get_drvdata ( ibdev );
-	struct arbelprm_init_ib init_ib;
-	int rc;
-
-	memset ( &init_ib, 0, sizeof ( init_ib ) );
-	MLX_FILL_3 ( &init_ib, 0,
-		     mtu_cap, ARBEL_MTU_2048,
-		     port_width_cap, 3,
-		     vl_cap, 1 );
-	MLX_FILL_1 ( &init_ib, 1, max_gid, 1 );
-	MLX_FILL_1 ( &init_ib, 2, max_pkey, 64 );
-	if ( ( rc = arbel_cmd_init_ib ( arbel, ibdev->port,
-					&init_ib ) ) != 0 ) {
-		DBGC ( arbel, "Arbel %p port %d could not intialise IB: %s\n",
-		       arbel, ibdev->port, strerror ( rc ) );
-		return rc;
-	}
-
-	/* Update MAD parameters */
-	ib_smc_update ( ibdev, arbel_mad );
-
-	return 0;
-}
-
-/**
- * Close Infiniband link
- *
- * @v ibdev		Infiniband device
- */
-static void arbel_close ( struct ib_device *ibdev ) {
-	struct arbel *arbel = ib_get_drvdata ( ibdev );
-	int rc;
-
-	if ( ( rc = arbel_cmd_close_ib ( arbel, ibdev->port ) ) != 0 ) {
-		DBGC ( arbel, "Arbel %p port %d could not close IB: %s\n",
-		       arbel, ibdev->port, strerror ( rc ) );
-		/* Nothing we can do about this */
-	}
-}
-
-/**
- * Inform embedded subnet management agent of a received MAD
- *
- * @v ibdev		Infiniband device
- * @v mad		MAD
- * @ret rc		Return status code
- */
-static int arbel_inform_sma ( struct ib_device *ibdev, union ib_mad *mad ) {
-	int rc;
-
-	/* Send the MAD to the embedded SMA */
-	if ( ( rc = arbel_mad ( ibdev, mad ) ) != 0 )
-		return rc;
-
-	/* Update parameters held in software */
-	ib_smc_update ( ibdev, arbel_mad );
-
-	return 0;
-}
-
-/***************************************************************************
- *
- * 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 arbel_mcast_attach ( struct ib_device *ibdev,
-				struct ib_queue_pair *qp,
-				union ib_gid *gid ) {
-	struct arbel *arbel = ib_get_drvdata ( ibdev );
-	struct arbelprm_mgm_hash hash;
-	struct arbelprm_mgm_entry mgm;
-	unsigned int index;
-	int rc;
-
-	/* Generate hash table index */
-	if ( ( rc = arbel_cmd_mgid_hash ( arbel, gid, &hash ) ) != 0 ) {
-		DBGC ( arbel, "Arbel %p could not hash GID: %s\n",
-		       arbel, strerror ( rc ) );
-		return rc;
-	}
-	index = MLX_GET ( &hash, hash );
-
-	/* Check for existing hash table entry */
-	if ( ( rc = arbel_cmd_read_mgm ( arbel, index, &mgm ) ) != 0 ) {
-		DBGC ( arbel, "Arbel %p could not read MGM %#x: %s\n",
-		       arbel, index, strerror ( rc ) );
-		return rc;
-	}
-	if ( MLX_GET ( &mgm, mgmqp_0.qi ) != 0 ) {
-		/* FIXME: this implementation allows only a single QP
-		 * per multicast group, and doesn't handle hash
-		 * collisions.  Sufficient for IPoIB but may need to
-		 * be extended in future.
-		 */
-		DBGC ( arbel, "Arbel %p MGID index %#x already in use\n",
-		       arbel, index );
-		return -EBUSY;
-	}
-
-	/* Update hash table entry */
-	MLX_FILL_2 ( &mgm, 8,
-		     mgmqp_0.qpn_i, qp->qpn,
-		     mgmqp_0.qi, 1 );
-	memcpy ( &mgm.u.dwords[4], gid, sizeof ( *gid ) );
-	if ( ( rc = arbel_cmd_write_mgm ( arbel, index, &mgm ) ) != 0 ) {
-		DBGC ( arbel, "Arbel %p could not write MGM %#x: %s\n",
-		       arbel, index, strerror ( rc ) );
-		return rc;
-	}
-
-	return 0;
-}
-
-/**
- * Detach from multicast group
- *
- * @v ibdev		Infiniband device
- * @v qp		Queue pair
- * @v gid		Multicast GID
- */
-static void arbel_mcast_detach ( struct ib_device *ibdev,
-				 struct ib_queue_pair *qp __unused,
-				 union ib_gid *gid ) {
-	struct arbel *arbel = ib_get_drvdata ( ibdev );
-	struct arbelprm_mgm_hash hash;
-	struct arbelprm_mgm_entry mgm;
-	unsigned int index;
-	int rc;
-
-	/* Generate hash table index */
-	if ( ( rc = arbel_cmd_mgid_hash ( arbel, gid, &hash ) ) != 0 ) {
-		DBGC ( arbel, "Arbel %p could not hash GID: %s\n",
-		       arbel, strerror ( rc ) );
-		return;
-	}
-	index = MLX_GET ( &hash, hash );
-
-	/* Clear hash table entry */
-	memset ( &mgm, 0, sizeof ( mgm ) );
-	if ( ( rc = arbel_cmd_write_mgm ( arbel, index, &mgm ) ) != 0 ) {
-		DBGC ( arbel, "Arbel %p could not write MGM %#x: %s\n",
-		       arbel, index, strerror ( rc ) );
-		return;
-	}
-}
-
-/** Arbel Infiniband operations */
-static struct ib_device_operations arbel_ib_operations = {
-	.create_cq	= arbel_create_cq,
-	.destroy_cq	= arbel_destroy_cq,
-	.create_qp	= arbel_create_qp,
-	.modify_qp	= arbel_modify_qp,
-	.destroy_qp	= arbel_destroy_qp,
-	.post_send	= arbel_post_send,
-	.post_recv	= arbel_post_recv,
-	.poll_cq	= arbel_poll_cq,
-	.poll_eq	= arbel_poll_eq,
-	.open		= arbel_open,
-	.close		= arbel_close,
-	.mcast_attach	= arbel_mcast_attach,
-	.mcast_detach	= arbel_mcast_detach,
-	.set_port_info	= arbel_inform_sma,
-	.set_pkey_table	= arbel_inform_sma,
-};
-
 /***************************************************************************
  *
  * Firmware control
@@ -2095,7 +1998,7 @@ static int arbel_start_firmware ( struct arbel *arbel ) {
 	struct arbelprm_query_fw fw;
 	struct arbelprm_access_lam lam;
 	unsigned int fw_pages;
-	size_t fw_size;
+	size_t fw_len;
 	physaddr_t fw_base;
 	uint64_t eq_set_ci_base_addr;
 	int rc;
@@ -2123,17 +2026,22 @@ static int arbel_start_firmware ( struct arbel *arbel ) {
 	arbel_cmd_enable_lam ( arbel, &lam );
 
 	/* Allocate firmware pages and map firmware area */
-	fw_size = ( fw_pages * ARBEL_PAGE_SIZE );
-	arbel->firmware_area = umalloc ( fw_size );
+	fw_len = ( fw_pages * ARBEL_PAGE_SIZE );
 	if ( ! arbel->firmware_area ) {
-		rc = -ENOMEM;
-		goto err_alloc_fa;
+		arbel->firmware_len = fw_len;
+		arbel->firmware_area = umalloc ( arbel->firmware_len );
+		if ( ! arbel->firmware_area ) {
+			rc = -ENOMEM;
+			goto err_alloc_fa;
+		}
+	} else {
+		assert ( arbel->firmware_len == fw_len );
 	}
 	fw_base = user_to_phys ( arbel->firmware_area, 0 );
 	DBGC ( arbel, "Arbel %p firmware area at [%08lx,%08lx)\n",
-	       arbel, fw_base, ( fw_base + fw_size ) );
+	       arbel, fw_base, ( fw_base + fw_len ) );
 	if ( ( rc = arbel_map_vpm ( arbel, arbel_cmd_map_fa,
-				    0, fw_base, fw_size ) ) != 0 ) {
+				    0, fw_base, fw_len ) ) != 0 ) {
 		DBGC ( arbel, "Arbel %p could not map firmware: %s\n",
 		       arbel, strerror ( rc ) );
 		goto err_map_fa;
@@ -2152,8 +2060,6 @@ static int arbel_start_firmware ( struct arbel *arbel ) {
  err_run_fw:
 	arbel_cmd_unmap_fa ( arbel );
  err_map_fa:
-	ufree ( arbel->firmware_area );
-	arbel->firmware_area = UNULL;
  err_alloc_fa:
  err_query_fw:
 	return rc;
@@ -2171,10 +2077,9 @@ static void arbel_stop_firmware ( struct arbel *arbel ) {
 		DBGC ( arbel, "Arbel %p FATAL could not stop firmware: %s\n",
 		       arbel, strerror ( rc ) );
 		/* Leak memory and return; at least we avoid corruption */
+		arbel->firmware_area = UNULL;
 		return;
 	}
-	ufree ( arbel->firmware_area );
-	arbel->firmware_area = UNULL;
 }
 
 /***************************************************************************
@@ -2284,6 +2189,7 @@ static int arbel_alloc_icm ( struct arbel *arbel,
 	unsigned int log_num_uars, log_num_qps, log_num_srqs, log_num_ees;
 	unsigned int log_num_cqs, log_num_mtts, log_num_mpts, log_num_rdbs;
 	unsigned int log_num_eqs, log_num_mcs;
+	size_t icm_len, icm_aux_len;
 	size_t len;
 	physaddr_t icm_phys;
 	int rc;
@@ -2297,7 +2203,8 @@ static int arbel_alloc_icm ( struct arbel *arbel,
 	log_num_eqs = fls ( arbel->limits.reserved_eqs + ARBEL_MAX_EQS - 1 );
 	log_num_mtts = fls ( arbel->limits.reserved_mtts - 1 );
 	log_num_mpts = fls ( arbel->limits.reserved_mrws + 1 - 1 );
-	log_num_rdbs = fls ( arbel->limits.reserved_rdbs - 1 );
+	log_num_rdbs = fls ( arbel->limits.reserved_rdbs +
+			     ARBEL_RSVD_SPECIAL_QPS + ARBEL_MAX_QPS - 1 );
 	log_num_uars = fls ( arbel->limits.reserved_uars +
 			     1 /* single UAR used */ - 1 );
 	log_num_mcs = ARBEL_LOG_MULTICAST_HASH_SIZE;
@@ -2454,7 +2361,7 @@ static int arbel_alloc_icm ( struct arbel *arbel,
 
 	/* Record amount of ICM to be allocated */
 	icm_offset = icm_align ( icm_offset, ARBEL_PAGE_SIZE );
-	arbel->icm_len = icm_offset;
+	icm_len = icm_offset;
 
 	/* User access region contexts
 	 *
@@ -2479,24 +2386,29 @@ static int arbel_alloc_icm ( struct arbel *arbel,
 
 	/* Get ICM auxiliary area size */
 	memset ( &icm_size, 0, sizeof ( icm_size ) );
-	MLX_FILL_1 ( &icm_size, 1, value, arbel->icm_len );
+	MLX_FILL_1 ( &icm_size, 1, value, icm_len );
 	if ( ( rc = arbel_cmd_set_icm_size ( arbel, &icm_size,
 					     &icm_aux_size ) ) != 0 ) {
 		DBGC ( arbel, "Arbel %p could not set ICM size: %s\n",
 		       arbel, strerror ( rc ) );
 		goto err_set_icm_size;
 	}
-	arbel->icm_aux_len =
-		( MLX_GET ( &icm_aux_size, value ) * ARBEL_PAGE_SIZE );
+	icm_aux_len = ( MLX_GET ( &icm_aux_size, value ) * ARBEL_PAGE_SIZE );
 
 	/* Allocate ICM data and auxiliary area */
 	DBGC ( arbel, "Arbel %p requires %zd kB ICM and %zd kB AUX ICM\n",
-	       arbel, ( arbel->icm_len / 1024 ),
-	       ( arbel->icm_aux_len / 1024 ) );
-	arbel->icm = umalloc ( arbel->icm_len + arbel->icm_aux_len );
+	       arbel, ( icm_len / 1024 ), ( icm_aux_len / 1024 ) );
 	if ( ! arbel->icm ) {
-		rc = -ENOMEM;
-		goto err_alloc_icm;
+		arbel->icm_len = icm_len;
+		arbel->icm_aux_len = icm_aux_len;
+		arbel->icm = umalloc ( arbel->icm_len + arbel->icm_aux_len );
+		if ( ! arbel->icm ) {
+			rc = -ENOMEM;
+			goto err_alloc_icm;
+		}
+	} else {
+		assert ( arbel->icm_len == icm_len );
+		assert ( arbel->icm_aux_len == icm_aux_len );
 	}
 	icm_phys = user_to_phys ( arbel->icm, 0 );
 
@@ -2562,8 +2474,6 @@ static int arbel_alloc_icm ( struct arbel *arbel,
 	free_dma ( arbel->db_rec, ARBEL_PAGE_SIZE );
 	arbel->db_rec= NULL;
  err_alloc_doorbell:
-	ufree ( arbel->icm );
-	arbel->icm = UNULL;
  err_alloc_icm:
  err_set_icm_size:
 	return rc;
@@ -2586,17 +2496,41 @@ static void arbel_free_icm ( struct arbel *arbel ) {
 	arbel_cmd_unmap_icm_aux ( arbel );
 	free_dma ( arbel->db_rec, ARBEL_PAGE_SIZE );
 	arbel->db_rec = NULL;
-	ufree ( arbel->icm );
-	arbel->icm = UNULL;
 }
 
 /***************************************************************************
  *
- * PCI interface
+ * Initialisation and teardown
  *
  ***************************************************************************
  */
 
+/**
+ * Reset device
+ *
+ * @v arbel		Arbel device
+ */
+static void arbel_reset ( struct arbel *arbel ) {
+	struct pci_device *pci = arbel->pci;
+	struct pci_config_backup backup;
+	static const uint8_t backup_exclude[] =
+		PCI_CONFIG_BACKUP_EXCLUDE ( 0x58, 0x5c );
+	uint16_t vendor;
+	unsigned int i;
+
+	/* Perform device reset and preserve PCI configuration */
+	pci_backup ( pci, &backup, backup_exclude );
+	writel ( ARBEL_RESET_MAGIC,
+		 ( arbel->config + ARBEL_RESET_OFFSET ) );
+	for ( i = 0 ; i < ARBEL_RESET_WAIT_TIME_MS ; i++ ) {
+		mdelay ( 1 );
+		pci_read_config_word ( pci, PCI_VENDOR_ID, &vendor );
+		if ( vendor != 0xffff )
+			break;
+	}
+	pci_restore ( pci, &backup, backup_exclude );
+}
+
 /**
  * Set up memory protection table
  *
@@ -2614,13 +2548,18 @@ static int arbel_setup_mpt ( struct arbel *arbel ) {
 
 	/* Initialise memory protection table */
 	memset ( &mpt, 0, sizeof ( mpt ) );
-	MLX_FILL_4 ( &mpt, 0,
-		     r_w, 1,
-		     pa, 1,
+	MLX_FILL_7 ( &mpt, 0,
+		     a, 1,
+		     rw, 1,
+		     rr, 1,
+		     lw, 1,
 		     lr, 1,
-		     lw, 1 );
+		     pa, 1,
+		     r_w, 1 );
 	MLX_FILL_1 ( &mpt, 2, mem_key, key );
-	MLX_FILL_1 ( &mpt, 3, pd, ARBEL_GLOBAL_PD );
+	MLX_FILL_2 ( &mpt, 3,
+		     pd, ARBEL_GLOBAL_PD,
+		     rae, 1 );
 	MLX_FILL_1 ( &mpt, 6, reg_wnd_len_h, 0xffffffffUL );
 	MLX_FILL_1 ( &mpt, 7, reg_wnd_len_l, 0xffffffffUL );
 	if ( ( rc = arbel_cmd_sw2hw_mpt ( arbel, arbel->limits.reserved_mrws,
@@ -2671,30 +2610,395 @@ static int arbel_configure_special_qps ( struct arbel *arbel ) {
 }
 
 /**
- * Probe PCI device
+ * Start Arbel device
  *
- * @v pci		PCI device
- * @v id		PCI ID
+ * @v arbel		Arbel device
+ * @v running		Firmware is already running
  * @ret rc		Return status code
  */
-static int arbel_probe ( struct pci_device *pci ) {
-	struct arbel *arbel;
-	struct ib_device *ibdev;
+static int arbel_start ( struct arbel *arbel, int running ) {
 	struct arbelprm_init_hca init_hca;
-	int i;
+	unsigned int i;
 	int rc;
 
-	/* Allocate Arbel device */
-	arbel = zalloc ( sizeof ( *arbel ) );
-	if ( ! arbel ) {
-		rc = -ENOMEM;
-		goto err_alloc_arbel;
+	/* Start firmware if not already running */
+	if ( ! running ) {
+		if ( ( rc = arbel_start_firmware ( arbel ) ) != 0 )
+			goto err_start_firmware;
 	}
-	pci_set_drvdata ( pci, arbel );
 
-	/* Allocate Infiniband devices */
-	for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ ) {
-		ibdev = alloc_ibdev ( 0 );
+	/* Allocate ICM */
+	memset ( &init_hca, 0, sizeof ( init_hca ) );
+	if ( ( rc = arbel_alloc_icm ( arbel, &init_hca ) ) != 0 )
+		goto err_alloc_icm;
+
+	/* Initialise HCA */
+	if ( ( rc = arbel_cmd_init_hca ( arbel, &init_hca ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not initialise HCA: %s\n",
+		       arbel, strerror ( rc ) );
+		goto err_init_hca;
+	}
+
+	/* Set up memory protection */
+	if ( ( rc = arbel_setup_mpt ( arbel ) ) != 0 )
+		goto err_setup_mpt;
+	for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ )
+		arbel->ibdev[i]->rdma_key = arbel->lkey;
+
+	/* Set up event queue */
+	if ( ( rc = arbel_create_eq ( arbel ) ) != 0 )
+		goto err_create_eq;
+
+	/* Configure special QPs */
+	if ( ( rc = arbel_configure_special_qps ( arbel ) ) != 0 )
+		goto err_conf_special_qps;
+
+	return 0;
+
+ err_conf_special_qps:
+	arbel_destroy_eq ( arbel );
+ err_create_eq:
+ err_setup_mpt:
+	arbel_cmd_close_hca ( arbel );
+ err_init_hca:
+	arbel_free_icm ( arbel );
+ err_alloc_icm:
+	arbel_stop_firmware ( arbel );
+ err_start_firmware:
+	return rc;
+}
+
+/**
+ * Stop Arbel device
+ *
+ * @v arbel		Arbel device
+ */
+static void arbel_stop ( struct arbel *arbel ) {
+	arbel_destroy_eq ( arbel );
+	arbel_cmd_close_hca ( arbel );
+	arbel_free_icm ( arbel );
+	arbel_stop_firmware ( arbel );
+	arbel_reset ( arbel );
+}
+
+/**
+ * Open Arbel device
+ *
+ * @v arbel		Arbel device
+ * @ret rc		Return status code
+ */
+static int arbel_open ( struct arbel *arbel ) {
+	int rc;
+
+	/* Start device if applicable */
+	if ( arbel->open_count == 0 ) {
+		if ( ( rc = arbel_start ( arbel, 0 ) ) != 0 )
+			return rc;
+	}
+
+	/* Increment open counter */
+	arbel->open_count++;
+
+	return 0;
+}
+
+/**
+ * Close Arbel device
+ *
+ * @v arbel		Arbel device
+ */
+static void arbel_close ( struct arbel *arbel ) {
+
+	/* Decrement open counter */
+	assert ( arbel->open_count != 0 );
+	arbel->open_count--;
+
+	/* Stop device if applicable */
+	if ( arbel->open_count == 0 )
+		arbel_stop ( arbel );
+}
+
+/***************************************************************************
+ *
+ * Infiniband link-layer operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Initialise Infiniband link
+ *
+ * @v ibdev		Infiniband device
+ * @ret rc		Return status code
+ */
+static int arbel_ib_open ( struct ib_device *ibdev ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct arbelprm_init_ib init_ib;
+	int rc;
+
+	/* Open hardware */
+	if ( ( rc = arbel_open ( arbel ) ) != 0 )
+		goto err_open;
+
+	/* Initialise IB */
+	memset ( &init_ib, 0, sizeof ( init_ib ) );
+	MLX_FILL_3 ( &init_ib, 0,
+		     mtu_cap, ARBEL_MTU_2048,
+		     port_width_cap, 3,
+		     vl_cap, 1 );
+	MLX_FILL_1 ( &init_ib, 1, max_gid, 1 );
+	MLX_FILL_1 ( &init_ib, 2, max_pkey, 64 );
+	if ( ( rc = arbel_cmd_init_ib ( arbel, ibdev->port,
+					&init_ib ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p port %d could not intialise IB: %s\n",
+		       arbel, ibdev->port, strerror ( rc ) );
+		goto err_init_ib;
+	}
+
+	/* Update MAD parameters */
+	ib_smc_update ( ibdev, arbel_mad );
+
+	return 0;
+
+ err_init_ib:
+	arbel_close ( arbel );
+ err_open:
+	return rc;
+}
+
+/**
+ * Close Infiniband link
+ *
+ * @v ibdev		Infiniband device
+ */
+static void arbel_ib_close ( struct ib_device *ibdev ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	int rc;
+
+	/* Close IB */
+	if ( ( rc = arbel_cmd_close_ib ( arbel, ibdev->port ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p port %d could not close IB: %s\n",
+		       arbel, ibdev->port, strerror ( rc ) );
+		/* Nothing we can do about this */
+	}
+
+	/* Close hardware */
+	arbel_close ( arbel );
+}
+
+/**
+ * Inform embedded subnet management agent of a received MAD
+ *
+ * @v ibdev		Infiniband device
+ * @v mad		MAD
+ * @ret rc		Return status code
+ */
+static int arbel_inform_sma ( struct ib_device *ibdev, union ib_mad *mad ) {
+	int rc;
+
+	/* Send the MAD to the embedded SMA */
+	if ( ( rc = arbel_mad ( ibdev, mad ) ) != 0 )
+		return rc;
+
+	/* Update parameters held in software */
+	ib_smc_update ( ibdev, arbel_mad );
+
+	return 0;
+}
+
+/***************************************************************************
+ *
+ * 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 arbel_mcast_attach ( struct ib_device *ibdev,
+				struct ib_queue_pair *qp,
+				union ib_gid *gid ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct arbelprm_mgm_hash hash;
+	struct arbelprm_mgm_entry mgm;
+	unsigned int index;
+	int rc;
+
+	/* Generate hash table index */
+	if ( ( rc = arbel_cmd_mgid_hash ( arbel, gid, &hash ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not hash GID: %s\n",
+		       arbel, strerror ( rc ) );
+		return rc;
+	}
+	index = MLX_GET ( &hash, hash );
+
+	/* Check for existing hash table entry */
+	if ( ( rc = arbel_cmd_read_mgm ( arbel, index, &mgm ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not read MGM %#x: %s\n",
+		       arbel, index, strerror ( rc ) );
+		return rc;
+	}
+	if ( MLX_GET ( &mgm, mgmqp_0.qi ) != 0 ) {
+		/* FIXME: this implementation allows only a single QP
+		 * per multicast group, and doesn't handle hash
+		 * collisions.  Sufficient for IPoIB but may need to
+		 * be extended in future.
+		 */
+		DBGC ( arbel, "Arbel %p MGID index %#x already in use\n",
+		       arbel, index );
+		return -EBUSY;
+	}
+
+	/* Update hash table entry */
+	MLX_FILL_2 ( &mgm, 8,
+		     mgmqp_0.qpn_i, qp->qpn,
+		     mgmqp_0.qi, 1 );
+	memcpy ( &mgm.u.dwords[4], gid, sizeof ( *gid ) );
+	if ( ( rc = arbel_cmd_write_mgm ( arbel, index, &mgm ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not write MGM %#x: %s\n",
+		       arbel, index, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Detach from multicast group
+ *
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v gid		Multicast GID
+ */
+static void arbel_mcast_detach ( struct ib_device *ibdev,
+				 struct ib_queue_pair *qp __unused,
+				 union ib_gid *gid ) {
+	struct arbel *arbel = ib_get_drvdata ( ibdev );
+	struct arbelprm_mgm_hash hash;
+	struct arbelprm_mgm_entry mgm;
+	unsigned int index;
+	int rc;
+
+	/* Generate hash table index */
+	if ( ( rc = arbel_cmd_mgid_hash ( arbel, gid, &hash ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not hash GID: %s\n",
+		       arbel, strerror ( rc ) );
+		return;
+	}
+	index = MLX_GET ( &hash, hash );
+
+	/* Clear hash table entry */
+	memset ( &mgm, 0, sizeof ( mgm ) );
+	if ( ( rc = arbel_cmd_write_mgm ( arbel, index, &mgm ) ) != 0 ) {
+		DBGC ( arbel, "Arbel %p could not write MGM %#x: %s\n",
+		       arbel, index, strerror ( rc ) );
+		return;
+	}
+}
+
+/** Arbel Infiniband operations */
+static struct ib_device_operations arbel_ib_operations = {
+	.create_cq	= arbel_create_cq,
+	.destroy_cq	= arbel_destroy_cq,
+	.create_qp	= arbel_create_qp,
+	.modify_qp	= arbel_modify_qp,
+	.destroy_qp	= arbel_destroy_qp,
+	.post_send	= arbel_post_send,
+	.post_recv	= arbel_post_recv,
+	.poll_cq	= arbel_poll_cq,
+	.poll_eq	= arbel_poll_eq,
+	.open		= arbel_ib_open,
+	.close		= arbel_ib_close,
+	.mcast_attach	= arbel_mcast_attach,
+	.mcast_detach	= arbel_mcast_detach,
+	.set_port_info	= arbel_inform_sma,
+	.set_pkey_table	= arbel_inform_sma,
+};
+
+/***************************************************************************
+ *
+ * PCI interface
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Allocate Arbel device
+ *
+ * @ret arbel		Arbel device
+ */
+static struct arbel * arbel_alloc ( void ) {
+	struct arbel *arbel;
+
+	/* Allocate Arbel device */
+	arbel = zalloc ( sizeof ( *arbel ) );
+	if ( ! arbel )
+		goto err_arbel;
+
+	/* Allocate space for mailboxes */
+	arbel->mailbox_in = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN );
+	if ( ! arbel->mailbox_in )
+		goto err_mailbox_in;
+	arbel->mailbox_out = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN );
+	if ( ! arbel->mailbox_out )
+		goto err_mailbox_out;
+
+	return arbel;
+
+	free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE );
+ err_mailbox_out:
+	free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE );
+ err_mailbox_in:
+	free ( arbel );
+ err_arbel:
+	return NULL;
+}
+
+/**
+ * Free Arbel device
+ *
+ * @v arbel		Arbel device
+ */
+static void arbel_free ( struct arbel *arbel ) {
+
+	ufree ( arbel->icm );
+	ufree ( arbel->firmware_area );
+	free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE );
+	free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE );
+	free ( arbel );
+}
+
+/**
+ * Probe PCI device
+ *
+ * @v pci		PCI device
+ * @v id		PCI ID
+ * @ret rc		Return status code
+ */
+static int arbel_probe ( struct pci_device *pci ) {
+	struct arbel *arbel;
+	struct ib_device *ibdev;
+	int i;
+	int rc;
+
+	/* Allocate Arbel device */
+	arbel = arbel_alloc();
+	if ( ! arbel ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	pci_set_drvdata ( pci, arbel );
+	arbel->pci = pci;
+
+	/* Allocate Infiniband devices */
+	for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ ) {
+		ibdev = alloc_ibdev ( 0 );
 		if ( ! ibdev ) {
 			rc = -ENOMEM;
 			goto err_alloc_ibdev;
@@ -2716,17 +3020,8 @@ static int arbel_probe ( struct pci_device *pci ) {
 				 ARBEL_PCI_UAR_IDX * ARBEL_PCI_UAR_SIZE ),
 			       ARBEL_PCI_UAR_SIZE );
 
-	/* Allocate space for mailboxes */
-	arbel->mailbox_in = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN );
-	if ( ! arbel->mailbox_in ) {
-		rc = -ENOMEM;
-		goto err_mailbox_in;
-	}
-	arbel->mailbox_out = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN );
-	if ( ! arbel->mailbox_out ) {
-		rc = -ENOMEM;
-		goto err_mailbox_out;
-	}
+	/* Reset device */
+	arbel_reset ( arbel );
 
 	/* Start firmware */
 	if ( ( rc = arbel_start_firmware ( arbel ) ) != 0 )
@@ -2736,29 +3031,9 @@ static int arbel_probe ( struct pci_device *pci ) {
 	if ( ( rc = arbel_get_limits ( arbel ) ) != 0 )
 		goto err_get_limits;
 
-	/* Allocate ICM */
-	memset ( &init_hca, 0, sizeof ( init_hca ) );
-	if ( ( rc = arbel_alloc_icm ( arbel, &init_hca ) ) != 0 )
-		goto err_alloc_icm;
-
-	/* Initialise HCA */
-	if ( ( rc = arbel_cmd_init_hca ( arbel, &init_hca ) ) != 0 ) {
-		DBGC ( arbel, "Arbel %p could not initialise HCA: %s\n",
-		       arbel, strerror ( rc ) );
-		goto err_init_hca;
-	}
-
-	/* Set up memory protection */
-	if ( ( rc = arbel_setup_mpt ( arbel ) ) != 0 )
-		goto err_setup_mpt;
-
-	/* Set up event queue */
-	if ( ( rc = arbel_create_eq ( arbel ) ) != 0 )
-		goto err_create_eq;
-
-	/* Configure special QPs */
-	if ( ( rc = arbel_configure_special_qps ( arbel ) ) != 0 )
-		goto err_conf_special_qps;
+	/* Start device */
+	if ( ( rc = arbel_start ( arbel, 1 ) ) != 0 )
+		goto err_start;
 
 	/* Initialise parameters using SMC */
 	for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ )
@@ -2774,33 +3049,27 @@ static int arbel_probe ( struct pci_device *pci ) {
 		}
 	}
 
+	/* Leave device quiescent until opened */
+	if ( arbel->open_count == 0 )
+		arbel_stop ( arbel );
+
 	return 0;
 
 	i = ARBEL_NUM_PORTS;
  err_register_ibdev:
 	for ( i-- ; i >= 0 ; i-- )
 		unregister_ibdev ( arbel->ibdev[i] );
- err_conf_special_qps:
-	arbel_destroy_eq ( arbel );
- err_create_eq:
- err_setup_mpt:
-	arbel_cmd_close_hca ( arbel );
- err_init_hca:
-	arbel_free_icm ( arbel );
- err_alloc_icm:
+	arbel_stop ( arbel );
+ err_start:
  err_get_limits:
 	arbel_stop_firmware ( arbel );
  err_start_firmware:
-	free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE );
- err_mailbox_out:
-	free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE );
- err_mailbox_in:
 	i = ARBEL_NUM_PORTS;
  err_alloc_ibdev:
 	for ( i-- ; i >= 0 ; i-- )
 		ibdev_put ( arbel->ibdev[i] );
-	free ( arbel );
- err_alloc_arbel:
+	arbel_free ( arbel );
+ err_alloc:
 	return rc;
 }
 
@@ -2815,15 +3084,9 @@ static void arbel_remove ( struct pci_device *pci ) {
 
 	for ( i = ( ARBEL_NUM_PORTS - 1 ) ; i >= 0 ; i-- )
 		unregister_ibdev ( arbel->ibdev[i] );
-	arbel_destroy_eq ( arbel );
-	arbel_cmd_close_hca ( arbel );
-	arbel_free_icm ( arbel );
-	arbel_stop_firmware ( arbel );
-	free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE );
-	free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE );
 	for ( i = ( ARBEL_NUM_PORTS - 1 ) ; i >= 0 ; i-- )
 		ibdev_put ( arbel->ibdev[i] );
-	free ( arbel );
+	arbel_free ( arbel );
 }
 
 static struct pci_device_id arbel_nics[] = {
diff --git a/roms/ipxe/src/drivers/infiniband/arbel.h b/roms/ipxe/src/drivers/infiniband/arbel.h
index 534115729263c66eebe6539cd3a7..c0303f1bc2fecbe2a7ab1b8b40a5 100644
--- a/roms/ipxe/src/drivers/infiniband/arbel.h
+++ b/roms/ipxe/src/drivers/infiniband/arbel.h
@@ -31,6 +31,11 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ARBEL_PCI_UAR_IDX		1
 #define ARBEL_PCI_UAR_SIZE		0x1000
 
+/* Device reset */
+#define ARBEL_RESET_OFFSET		0x0f0010
+#define ARBEL_RESET_MAGIC		0x01000000UL
+#define ARBEL_RESET_WAIT_TIME_MS	1000
+
 /* UAR context table (UCE) resource types */
 #define ARBEL_UAR_RES_NONE		0x00
 #define ARBEL_UAR_RES_CQ_CI		0x01
@@ -81,6 +86,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ARBEL_HCR_MAP_FA		0x0fff
 
 /* Service types */
+#define ARBEL_ST_RC			0x00
 #define ARBEL_ST_UD			0x03
 #define ARBEL_ST_MLX			0x07
 
@@ -111,6 +117,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ARBEL_PM_STATE_REARM		0x01
 #define ARBEL_PM_STATE_MIGRATED		0x03
 
+#define ARBEL_RETRY_MAX			0x07
+
 /*
  * Datatypes that seem to be missing from the autogenerated documentation
  *
@@ -223,6 +231,12 @@ struct arbelprm_mlx_send_wqe {
 	uint8_t headers[IB_MAX_HEADER_SIZE];
 } __attribute__ (( packed ));
 
+struct arbelprm_rc_send_wqe {
+	struct arbelprm_wqe_segment_next next;
+	struct arbelprm_wqe_segment_ctrl_send ctrl;
+	struct arbelprm_wqe_segment_data_ptr data[ARBEL_MAX_GATHER];
+} __attribute__ (( packed ));
+
 #define ARBEL_MAX_SCATTER 1
 
 struct arbelprm_recv_wqe {
@@ -324,6 +338,7 @@ union arbel_send_wqe {
 	struct arbelprm_wqe_segment_next next;
 	struct arbelprm_ud_send_wqe ud;
 	struct arbelprm_mlx_send_wqe mlx;
+	struct arbelprm_rc_send_wqe rc;
 	uint8_t force_align[ARBEL_SEND_WQE_ALIGN];
 } __attribute__ (( packed ));
 
@@ -448,6 +463,8 @@ typedef uint32_t arbel_bitmask_t;
 
 /** An Arbel device */
 struct arbel {
+	/** PCI device */
+	struct pci_device *pci;
 	/** PCI configuration registers */
 	void *config;
 	/** PCI user Access Region */
@@ -460,13 +477,28 @@ struct arbel {
 	/** Command output mailbox */
 	void *mailbox_out;
 
-	/** Firmware area in external memory */
+	/** Device open request counter */
+	unsigned int open_count;
+
+	/** Firmware size */
+	size_t firmware_len;
+	/** Firmware area in external memory
+	 *
+	 * This is allocated when first needed, and freed only on
+	 * final teardown, in order to avoid memory map changes at
+	 * runtime.
+	 */
 	userptr_t firmware_area;
 	/** ICM size */
 	size_t icm_len;
 	/** ICM AUX size */
 	size_t icm_aux_len;
-	/** ICM area */
+	/** ICM area
+	 *
+	 * This is allocated when first needed, and freed only on
+	 * final teardown, in order to avoid memory map changes at
+	 * runtime.
+	 */
 	userptr_t icm;
 	/** Offset within ICM of doorbell records */
 	size_t db_rec_offset;
diff --git a/roms/ipxe/src/drivers/infiniband/hermon.c b/roms/ipxe/src/drivers/infiniband/hermon.c
index f44166f8b5cd06a054a3e6fd910b..a9c728706b8a54464c75e1a920da 100644
--- a/roms/ipxe/src/drivers/infiniband/hermon.c
+++ b/roms/ipxe/src/drivers/infiniband/hermon.c
@@ -14,7 +14,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -41,6 +42,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/fcoe.h>
 #include <ipxe/vlan.h>
 #include <ipxe/bofm.h>
+#include <ipxe/nvsvpd.h>
+#include <ipxe/nvo.h>
 #include "hermon.h"
 
 /**
@@ -1363,7 +1366,7 @@ static void hermon_destroy_qp ( struct ib_device *ibdev,
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector
+ * @v dest		Destination address vector
  * @v iobuf		I/O buffer
  * @v wqe		Send work queue entry
  * @ret opcode		Control opcode
@@ -1371,7 +1374,7 @@ static void hermon_destroy_qp ( struct ib_device *ibdev,
 static __attribute__ (( unused )) unsigned int
 hermon_fill_nop_send_wqe ( struct ib_device *ibdev __unused,
 			   struct ib_queue_pair *qp __unused,
-			   struct ib_address_vector *av __unused,
+			   struct ib_address_vector *dest __unused,
 			   struct io_buffer *iobuf __unused,
 			   union hermon_send_wqe *wqe ) {
 
@@ -1385,7 +1388,7 @@ hermon_fill_nop_send_wqe ( struct ib_device *ibdev __unused,
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector
+ * @v dest		Destination address vector
  * @v iobuf		I/O buffer
  * @v wqe		Send work queue entry
  * @ret opcode		Control opcode
@@ -1393,7 +1396,7 @@ hermon_fill_nop_send_wqe ( struct ib_device *ibdev __unused,
 static unsigned int
 hermon_fill_ud_send_wqe ( struct ib_device *ibdev,
 			  struct ib_queue_pair *qp __unused,
-			  struct ib_address_vector *av,
+			  struct ib_address_vector *dest,
 			  struct io_buffer *iobuf,
 			  union hermon_send_wqe *wqe ) {
 	struct hermon *hermon = ib_get_drvdata ( ibdev );
@@ -1405,14 +1408,14 @@ hermon_fill_ud_send_wqe ( struct ib_device *ibdev,
 		     ud_address_vector.pd, HERMON_GLOBAL_PD,
 		     ud_address_vector.port_number, ibdev->port );
 	MLX_FILL_2 ( &wqe->ud.ud, 1,
-		     ud_address_vector.rlid, av->lid,
-		     ud_address_vector.g, av->gid_present );
+		     ud_address_vector.rlid, dest->lid,
+		     ud_address_vector.g, dest->gid_present );
 	MLX_FILL_1 ( &wqe->ud.ud, 2,
-		     ud_address_vector.max_stat_rate, hermon_rate ( av ) );
-	MLX_FILL_1 ( &wqe->ud.ud, 3, ud_address_vector.sl, av->sl );
-	memcpy ( &wqe->ud.ud.u.dwords[4], &av->gid, sizeof ( av->gid ) );
-	MLX_FILL_1 ( &wqe->ud.ud, 8, destination_qp, av->qpn );
-	MLX_FILL_1 ( &wqe->ud.ud, 9, q_key, av->qkey );
+		     ud_address_vector.max_stat_rate, hermon_rate ( dest ) );
+	MLX_FILL_1 ( &wqe->ud.ud, 3, ud_address_vector.sl, dest->sl );
+	memcpy ( &wqe->ud.ud.u.dwords[4], &dest->gid, sizeof ( dest->gid ) );
+	MLX_FILL_1 ( &wqe->ud.ud, 8, destination_qp, dest->qpn );
+	MLX_FILL_1 ( &wqe->ud.ud, 9, q_key, dest->qkey );
 	MLX_FILL_1 ( &wqe->ud.data[0], 0, byte_count, iob_len ( iobuf ) );
 	MLX_FILL_1 ( &wqe->ud.data[0], 1, l_key, hermon->lkey );
 	MLX_FILL_H ( &wqe->ud.data[0], 2,
@@ -1427,7 +1430,7 @@ hermon_fill_ud_send_wqe ( struct ib_device *ibdev,
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector
+ * @v dest		Destination address vector
  * @v iobuf		I/O buffer
  * @v wqe		Send work queue entry
  * @ret opcode		Control opcode
@@ -1435,7 +1438,7 @@ hermon_fill_ud_send_wqe ( struct ib_device *ibdev,
 static unsigned int
 hermon_fill_mlx_send_wqe ( struct ib_device *ibdev,
 			   struct ib_queue_pair *qp,
-			   struct ib_address_vector *av,
+			   struct ib_address_vector *dest,
 			   struct io_buffer *iobuf,
 			   union hermon_send_wqe *wqe ) {
 	struct hermon *hermon = ib_get_drvdata ( ibdev );
@@ -1445,7 +1448,7 @@ hermon_fill_mlx_send_wqe ( struct ib_device *ibdev,
 	iob_populate ( &headers, &wqe->mlx.headers, 0,
 		       sizeof ( wqe->mlx.headers ) );
 	iob_reserve ( &headers, sizeof ( wqe->mlx.headers ) );
-	ib_push ( ibdev, &headers, qp, iob_len ( iobuf ), av );
+	ib_push ( ibdev, &headers, qp, iob_len ( iobuf ), dest );
 
 	/* Fill work queue entry */
 	MLX_FILL_1 ( &wqe->mlx.ctrl, 1, ds,
@@ -1453,10 +1456,10 @@ hermon_fill_mlx_send_wqe ( struct ib_device *ibdev,
 	MLX_FILL_5 ( &wqe->mlx.ctrl, 2,
 		     c, 0x03 /* generate completion */,
 		     icrc, 0 /* generate ICRC */,
-		     max_statrate, hermon_rate ( av ),
+		     max_statrate, hermon_rate ( dest ),
 		     slr, 0,
 		     v15, ( ( qp->ext_qpn == IB_QPN_SMI ) ? 1 : 0 ) );
-	MLX_FILL_1 ( &wqe->mlx.ctrl, 3, rlid, av->lid );
+	MLX_FILL_1 ( &wqe->mlx.ctrl, 3, rlid, dest->lid );
 	MLX_FILL_1 ( &wqe->mlx.data[0], 0,
 		     byte_count, iob_len ( &headers ) );
 	MLX_FILL_1 ( &wqe->mlx.data[0], 1, l_key, hermon->lkey );
@@ -1479,7 +1482,7 @@ hermon_fill_mlx_send_wqe ( struct ib_device *ibdev,
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector
+ * @v dest		Destination address vector
  * @v iobuf		I/O buffer
  * @v wqe		Send work queue entry
  * @ret opcode		Control opcode
@@ -1487,7 +1490,7 @@ hermon_fill_mlx_send_wqe ( struct ib_device *ibdev,
 static unsigned int
 hermon_fill_rc_send_wqe ( struct ib_device *ibdev,
 			  struct ib_queue_pair *qp __unused,
-			  struct ib_address_vector *av __unused,
+			  struct ib_address_vector *dest __unused,
 			  struct io_buffer *iobuf,
 			  union hermon_send_wqe *wqe ) {
 	struct hermon *hermon = ib_get_drvdata ( ibdev );
@@ -1509,7 +1512,7 @@ hermon_fill_rc_send_wqe ( struct ib_device *ibdev,
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector
+ * @v dest		Destination address vector
  * @v iobuf		I/O buffer
  * @v wqe		Send work queue entry
  * @ret opcode		Control opcode
@@ -1517,7 +1520,7 @@ hermon_fill_rc_send_wqe ( struct ib_device *ibdev,
 static unsigned int
 hermon_fill_eth_send_wqe ( struct ib_device *ibdev,
 			   struct ib_queue_pair *qp __unused,
-			   struct ib_address_vector *av __unused,
+			   struct ib_address_vector *dest __unused,
 			   struct io_buffer *iobuf,
 			   union hermon_send_wqe *wqe ) {
 	struct hermon *hermon = ib_get_drvdata ( ibdev );
@@ -1542,7 +1545,7 @@ hermon_fill_eth_send_wqe ( struct ib_device *ibdev,
 static unsigned int
 ( * hermon_fill_send_wqe[] ) ( struct ib_device *ibdev,
 			       struct ib_queue_pair *qp,
-			       struct ib_address_vector *av,
+			       struct ib_address_vector *dest,
 			       struct io_buffer *iobuf,
 			       union hermon_send_wqe *wqe ) = {
 	[IB_QPT_SMI] = hermon_fill_mlx_send_wqe,
@@ -1557,13 +1560,13 @@ static unsigned int
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector
+ * @v dest		Destination address vector
  * @v iobuf		I/O buffer
  * @ret rc		Return status code
  */
 static int hermon_post_send ( struct ib_device *ibdev,
 			      struct ib_queue_pair *qp,
-			      struct ib_address_vector *av,
+			      struct ib_address_vector *dest,
 			      struct io_buffer *iobuf ) {
 	struct hermon *hermon = ib_get_drvdata ( ibdev );
 	struct hermon_queue_pair *hermon_qp = ib_qp_get_drvdata ( qp );
@@ -1594,7 +1597,7 @@ static int hermon_post_send ( struct ib_device *ibdev,
 	assert ( qp->type < ( sizeof ( hermon_fill_send_wqe ) /
 			      sizeof ( hermon_fill_send_wqe[0] ) ) );
 	assert ( hermon_fill_send_wqe[qp->type] != NULL );
-	opcode = hermon_fill_send_wqe[qp->type] ( ibdev, qp, av, iobuf, wqe );
+	opcode = hermon_fill_send_wqe[qp->type] ( ibdev, qp, dest, iobuf, wqe );
 	barrier();
 	MLX_FILL_2 ( &wqe->ctrl, 0,
 		     opcode, opcode,
@@ -1676,9 +1679,10 @@ static int hermon_complete ( struct ib_device *ibdev,
 	struct ib_work_queue *wq;
 	struct ib_queue_pair *qp;
 	struct io_buffer *iobuf;
-	struct ib_address_vector recv_av;
+	struct ib_address_vector recv_dest;
+	struct ib_address_vector recv_source;
 	struct ib_global_route_header *grh;
-	struct ib_address_vector *av;
+	struct ib_address_vector *source;
 	unsigned int opcode;
 	unsigned long qpn;
 	int is_send;
@@ -1736,7 +1740,9 @@ static int hermon_complete ( struct ib_device *ibdev,
 		len = MLX_GET ( &cqe->normal, byte_cnt );
 		assert ( len <= iob_tailroom ( iobuf ) );
 		iob_put ( iobuf, len );
-		memset ( &recv_av, 0, sizeof ( recv_av ) );
+		memset ( &recv_dest, 0, sizeof ( recv_dest ) );
+		recv_dest.qpn = qpn;
+		memset ( &recv_source, 0, sizeof ( recv_source ) );
 		switch ( qp->type ) {
 		case IB_QPT_SMI:
 		case IB_QPT_GSI:
@@ -1745,28 +1751,32 @@ static int hermon_complete ( struct ib_device *ibdev,
 			grh = iobuf->data;
 			iob_pull ( iobuf, sizeof ( *grh ) );
 			/* Construct address vector */
-			av = &recv_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 ) );
+			source = &recv_source;
+			source->qpn = MLX_GET ( &cqe->normal, srq_rqpn );
+			source->lid = MLX_GET ( &cqe->normal, slid_smac47_32 );
+			source->sl = MLX_GET ( &cqe->normal, sl );
+			recv_dest.gid_present = source->gid_present =
+				MLX_GET ( &cqe->normal, g );
+			memcpy ( &recv_dest.gid, &grh->dgid,
+				 sizeof ( recv_dest.gid ) );
+			memcpy ( &source->gid, &grh->sgid,
+				 sizeof ( source->gid ) );
 			break;
 		case IB_QPT_RC:
-			av = &qp->av;
+			source = &qp->av;
 			break;
 		case IB_QPT_ETH:
 			/* Construct address vector */
-			av = &recv_av;
-			av->vlan_present = MLX_GET ( &cqe->normal, vlan );
-			av->vlan = MLX_GET ( &cqe->normal, vid );
+			source = &recv_source;
+			source->vlan_present = MLX_GET ( &cqe->normal, vlan );
+			source->vlan = MLX_GET ( &cqe->normal, vid );
 			break;
 		default:
 			assert ( 0 );
 			return -EINVAL;
 		}
 		/* Hand off to completion handler */
-		ib_complete_recv ( ibdev, qp, av, iobuf, rc );
+		ib_complete_recv ( ibdev, qp, &recv_dest, source, iobuf, rc );
 	}
 
 	return rc;
@@ -2040,1284 +2050,1547 @@ static void hermon_poll_eq ( struct ib_device *ibdev ) {
 
 /***************************************************************************
  *
- * Infiniband link-layer operations
+ * Firmware control
  *
  ***************************************************************************
  */
 
 /**
- * Initialise Infiniband link
+ * Map virtual to physical address for firmware usage
  *
- * @v ibdev		Infiniband device
+ * @v hermon		Hermon device
+ * @v map		Mapping function
+ * @v va		Virtual address
+ * @v pa		Physical address
+ * @v len		Length of region
  * @ret rc		Return status code
  */
-static int hermon_open ( struct ib_device *ibdev ) {
-	struct hermon *hermon = ib_get_drvdata ( ibdev );
-	union hermonprm_set_port set_port;
+static int hermon_map_vpm ( struct hermon *hermon,
+			    int ( *map ) ( struct hermon *hermon,
+			    const struct hermonprm_virtual_physical_mapping* ),
+			    uint64_t va, physaddr_t pa, size_t len ) {
+	struct hermonprm_virtual_physical_mapping mapping;
+	physaddr_t start;
+	physaddr_t low;
+	physaddr_t high;
+	physaddr_t end;
+	size_t size;
 	int rc;
 
-	/* Set port parameters */
-	memset ( &set_port, 0, sizeof ( set_port ) );
-	MLX_FILL_8 ( &set_port.ib, 0,
-		     mmc, 1,
-		     mvc, 1,
-		     mp, 1,
-		     mg, 1,
-		     mtu_cap, IB_MTU_2048,
-		     vl_cap, IB_VL_0,
-		     rcm, 1,
-		     lss, 1 );
-	MLX_FILL_2 ( &set_port.ib, 10,
-		     max_pkey, 1,
-		     max_gid, 1 );
-	MLX_FILL_1 ( &set_port.ib, 28,
-		     link_speed_supported, 1 );
-	if ( ( rc = hermon_cmd_set_port ( hermon, 0, ibdev->port,
-					  &set_port ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p port %d could not set port: %s\n",
-		       hermon, ibdev->port, strerror ( rc ) );
-		return rc;
-	}
+	/* Sanity checks */
+	assert ( ( va & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
+	assert ( ( pa & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
+	assert ( ( len & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
 
-	/* Initialise port */
-	if ( ( rc = hermon_cmd_init_port ( hermon, ibdev->port ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p port %d could not initialise port: "
-		       "%s\n", hermon, ibdev->port, strerror ( rc ) );
-		return rc;
-	}
+	/* Calculate starting points */
+	start = pa;
+	end = ( start + len );
+	size = ( 1UL << ( fls ( start ^ end ) - 1 ) );
+	low = high = ( end & ~( size - 1 ) );
+	assert ( start < low );
+	assert ( high <= end );
 
-	/* Update MAD parameters */
-	ib_smc_update ( ibdev, hermon_mad );
+	/* These mappings tend to generate huge volumes of
+	 * uninteresting debug data, which basically makes it
+	 * impossible to use debugging otherwise.
+	 */
+	DBG_DISABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
+
+	/* Map blocks in descending order of size */
+	while ( size >= HERMON_PAGE_SIZE ) {
+
+		/* Find the next candidate block */
+		if ( ( low - size ) >= start ) {
+			low -= size;
+			pa = low;
+		} else if ( ( high + size ) <= end ) {
+			pa = high;
+			high += size;
+		} else {
+			size >>= 1;
+			continue;
+		}
+		assert ( ( va & ( size - 1 ) ) == 0 );
+		assert ( ( pa & ( size - 1 ) ) == 0 );
+
+		/* Map this block */
+		memset ( &mapping, 0, sizeof ( mapping ) );
+		MLX_FILL_1 ( &mapping, 0, va_h, ( va >> 32 ) );
+		MLX_FILL_1 ( &mapping, 1, va_l, ( va >> 12 ) );
+		MLX_FILL_H ( &mapping, 2, pa_h, pa );
+		MLX_FILL_2 ( &mapping, 3,
+			     log2size, ( ( fls ( size ) - 1 ) - 12 ),
+			     pa_l, ( pa >> 12 ) );
+		if ( ( rc = map ( hermon, &mapping ) ) != 0 ) {
+			DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
+			DBGC ( hermon, "Hermon %p could not map %08llx+%zx to "
+			       "%08lx: %s\n",
+			       hermon, va, size, pa, strerror ( rc ) );
+			return rc;
+		}
+		va += size;
+	}
+	assert ( low == start );
+	assert ( high == end );
 
+	DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
 	return 0;
 }
 
 /**
- * Close Infiniband link
+ * Start firmware running
  *
- * @v ibdev		Infiniband device
+ * @v hermon		Hermon device
+ * @ret rc		Return status code
  */
-static void hermon_close ( struct ib_device *ibdev ) {
-	struct hermon *hermon = ib_get_drvdata ( ibdev );
+static int hermon_start_firmware ( struct hermon *hermon ) {
+	struct hermonprm_query_fw fw;
+	unsigned int fw_pages;
+	size_t fw_len;
+	physaddr_t fw_base;
 	int rc;
 
-	if ( ( rc = hermon_cmd_close_port ( hermon, ibdev->port ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p port %d could not close port: %s\n",
-		       hermon, ibdev->port, strerror ( rc ) );
-		/* Nothing we can do about this */
+	/* Get firmware parameters */
+	if ( ( rc = hermon_cmd_query_fw ( hermon, &fw ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not query firmware: %s\n",
+		       hermon, strerror ( rc ) );
+		goto err_query_fw;
+	}
+	DBGC ( hermon, "Hermon %p firmware version %d.%d.%d\n", hermon,
+	       MLX_GET ( &fw, fw_rev_major ), MLX_GET ( &fw, fw_rev_minor ),
+	       MLX_GET ( &fw, fw_rev_subminor ) );
+	fw_pages = MLX_GET ( &fw, fw_pages );
+	DBGC ( hermon, "Hermon %p requires %d pages (%d kB) for firmware\n",
+	       hermon, fw_pages, ( fw_pages * 4 ) );
+
+	/* Allocate firmware pages and map firmware area */
+	fw_len = ( fw_pages * HERMON_PAGE_SIZE );
+	if ( ! hermon->firmware_area ) {
+		hermon->firmware_len = fw_len;
+		hermon->firmware_area = umalloc ( hermon->firmware_len );
+		if ( ! hermon->firmware_area ) {
+			rc = -ENOMEM;
+			goto err_alloc_fa;
+		}
+	} else {
+		assert ( hermon->firmware_len == fw_len );
 	}
+	fw_base = user_to_phys ( hermon->firmware_area, 0 );
+	DBGC ( hermon, "Hermon %p firmware area at physical [%08lx,%08lx)\n",
+	       hermon, fw_base, ( fw_base + fw_len ) );
+	if ( ( rc = hermon_map_vpm ( hermon, hermon_cmd_map_fa,
+				     0, fw_base, fw_len ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not map firmware: %s\n",
+		       hermon, strerror ( rc ) );
+		goto err_map_fa;
+	}
+
+	/* Start firmware */
+	if ( ( rc = hermon_cmd_run_fw ( hermon ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not run firmware: %s\n",
+		       hermon, strerror ( rc ) );
+		goto err_run_fw;
+	}
+
+	DBGC ( hermon, "Hermon %p firmware started\n", hermon );
+	return 0;
+
+ err_run_fw:
+ err_map_fa:
+	hermon_cmd_unmap_fa ( hermon );
+ err_alloc_fa:
+ err_query_fw:
+	return rc;
 }
 
 /**
- * Inform embedded subnet management agent of a received MAD
+ * Stop firmware running
  *
- * @v ibdev		Infiniband device
- * @v mad		MAD
- * @ret rc		Return status code
+ * @v hermon		Hermon device
  */
-static int hermon_inform_sma ( struct ib_device *ibdev,
-			       union ib_mad *mad ) {
+static void hermon_stop_firmware ( struct hermon *hermon ) {
 	int rc;
 
-	/* Send the MAD to the embedded SMA */
-	if ( ( rc = hermon_mad ( ibdev, mad ) ) != 0 )
-		return rc;
-
-	/* Update parameters held in software */
-	ib_smc_update ( ibdev, hermon_mad );
-
-	return 0;
+	if ( ( rc = hermon_cmd_unmap_fa ( hermon ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p FATAL could not stop firmware: %s\n",
+		       hermon, strerror ( rc ) );
+		/* Leak memory and return; at least we avoid corruption */
+		hermon->firmware_area = UNULL;
+		return;
+	}
 }
 
 /***************************************************************************
  *
- * Multicast group operations
+ * Infinihost Context Memory management
  *
  ***************************************************************************
  */
 
 /**
- * Attach to multicast group
+ * Get device limits
  *
- * @v ibdev		Infiniband device
- * @v qp		Queue pair
- * @v gid		Multicast GID
+ * @v hermon		Hermon device
  * @ret rc		Return status code
  */
-static int hermon_mcast_attach ( struct ib_device *ibdev,
-				 struct ib_queue_pair *qp,
-				 union ib_gid *gid ) {
-	struct hermon *hermon = ib_get_drvdata ( ibdev );
-	struct hermonprm_mgm_hash hash;
-	struct hermonprm_mcg_entry mcg;
-	unsigned int index;
+static int hermon_get_cap ( struct hermon *hermon ) {
+	struct hermonprm_query_dev_cap dev_cap;
 	int rc;
 
-	/* Generate hash table index */
-	if ( ( rc = hermon_cmd_mgid_hash ( hermon, gid, &hash ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p could not hash GID: %s\n",
+	if ( ( rc = hermon_cmd_query_dev_cap ( hermon, &dev_cap ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not get device limits: %s\n",
 		       hermon, strerror ( rc ) );
 		return rc;
 	}
-	index = MLX_GET ( &hash, hash );
 
-	/* Check for existing hash table entry */
-	if ( ( rc = hermon_cmd_read_mcg ( hermon, index, &mcg ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p could not read MCG %#x: %s\n",
-		       hermon, index, strerror ( rc ) );
-		return rc;
-	}
-	if ( MLX_GET ( &mcg, hdr.members_count ) != 0 ) {
-		/* FIXME: this implementation allows only a single QP
-		 * per multicast group, and doesn't handle hash
-		 * collisions.  Sufficient for IPoIB but may need to
-		 * be extended in future.
-		 */
-		DBGC ( hermon, "Hermon %p MGID index %#x already in use\n",
-		       hermon, index );
-		return -EBUSY;
+	hermon->cap.cmpt_entry_size = MLX_GET ( &dev_cap, c_mpt_entry_sz );
+	hermon->cap.reserved_qps =
+		( 1 << MLX_GET ( &dev_cap, log2_rsvd_qps ) );
+	hermon->cap.qpc_entry_size = MLX_GET ( &dev_cap, qpc_entry_sz );
+	hermon->cap.altc_entry_size = MLX_GET ( &dev_cap, altc_entry_sz );
+	hermon->cap.auxc_entry_size = MLX_GET ( &dev_cap, aux_entry_sz );
+	hermon->cap.reserved_srqs =
+		( 1 << MLX_GET ( &dev_cap, log2_rsvd_srqs ) );
+	hermon->cap.srqc_entry_size = MLX_GET ( &dev_cap, srq_entry_sz );
+	hermon->cap.reserved_cqs =
+		( 1 << MLX_GET ( &dev_cap, log2_rsvd_cqs ) );
+	hermon->cap.cqc_entry_size = MLX_GET ( &dev_cap, cqc_entry_sz );
+	hermon->cap.reserved_eqs = MLX_GET ( &dev_cap, num_rsvd_eqs );
+	if ( hermon->cap.reserved_eqs == 0 ) {
+		/* Backward compatibility */
+		hermon->cap.reserved_eqs =
+			( 1 << MLX_GET ( &dev_cap, log2_rsvd_eqs ) );
 	}
+	hermon->cap.eqc_entry_size = MLX_GET ( &dev_cap, eqc_entry_sz );
+	hermon->cap.reserved_mtts =
+		( 1 << MLX_GET ( &dev_cap, log2_rsvd_mtts ) );
+	hermon->cap.mtt_entry_size = MLX_GET ( &dev_cap, mtt_entry_sz );
+	hermon->cap.reserved_mrws =
+		( 1 << MLX_GET ( &dev_cap, log2_rsvd_mrws ) );
+	hermon->cap.dmpt_entry_size = MLX_GET ( &dev_cap, d_mpt_entry_sz );
+	hermon->cap.reserved_uars = MLX_GET ( &dev_cap, num_rsvd_uars );
+	hermon->cap.num_ports = MLX_GET ( &dev_cap, num_ports );
+	hermon->cap.dpdp = MLX_GET ( &dev_cap, dpdp );
 
-	/* Update hash table entry */
-	MLX_FILL_1 ( &mcg, 1, hdr.members_count, 1 );
-	MLX_FILL_1 ( &mcg, 8, qp[0].qpn, qp->qpn );
-	memcpy ( &mcg.u.dwords[4], gid, sizeof ( *gid ) );
-	if ( ( rc = hermon_cmd_write_mcg ( hermon, index, &mcg ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p could not write MCG %#x: %s\n",
-		       hermon, index, strerror ( rc ) );
-		return rc;
+	/* Sanity check */
+	if ( hermon->cap.num_ports > HERMON_MAX_PORTS ) {
+		DBGC ( hermon, "Hermon %p has %d ports (only %d supported)\n",
+		       hermon, hermon->cap.num_ports, HERMON_MAX_PORTS );
+		hermon->cap.num_ports = HERMON_MAX_PORTS;
 	}
 
 	return 0;
 }
 
 /**
- * Detach from multicast group
+ * Align ICM table
  *
- * @v ibdev		Infiniband device
- * @v qp		Queue pair
- * @v gid		Multicast GID
+ * @v icm_offset	Current ICM offset
+ * @v len		ICM table length
+ * @ret icm_offset	ICM offset
  */
-static void hermon_mcast_detach ( struct ib_device *ibdev,
-				  struct ib_queue_pair *qp __unused,
-				  union ib_gid *gid ) {
-	struct hermon *hermon = ib_get_drvdata ( ibdev );
-	struct hermonprm_mgm_hash hash;
-	struct hermonprm_mcg_entry mcg;
-	unsigned int index;
-	int rc;
-
-	/* Generate hash table index */
-	if ( ( rc = hermon_cmd_mgid_hash ( hermon, gid, &hash ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p could not hash GID: %s\n",
-		       hermon, strerror ( rc ) );
-		return;
-	}
-	index = MLX_GET ( &hash, hash );
+static uint64_t icm_align ( uint64_t icm_offset, size_t len ) {
 
-	/* Clear hash table entry */
-	memset ( &mcg, 0, sizeof ( mcg ) );
-	if ( ( rc = hermon_cmd_write_mcg ( hermon, index, &mcg ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p could not write MCG %#x: %s\n",
-		       hermon, index, strerror ( rc ) );
-		return;
-	}
+	/* Round up to a multiple of the table size */
+	assert ( len == ( 1UL << ( fls ( len ) - 1 ) ) );
+	return ( ( icm_offset + len - 1 ) & ~( ( ( uint64_t ) len ) - 1 ) );
 }
 
-/** Hermon Infiniband operations */
-static struct ib_device_operations hermon_ib_operations = {
-	.create_cq	= hermon_create_cq,
-	.destroy_cq	= hermon_destroy_cq,
-	.create_qp	= hermon_create_qp,
-	.modify_qp	= hermon_modify_qp,
-	.destroy_qp	= hermon_destroy_qp,
-	.post_send	= hermon_post_send,
-	.post_recv	= hermon_post_recv,
-	.poll_cq	= hermon_poll_cq,
-	.poll_eq	= hermon_poll_eq,
-	.open		= hermon_open,
-	.close		= hermon_close,
-	.mcast_attach	= hermon_mcast_attach,
-	.mcast_detach	= hermon_mcast_detach,
-	.set_port_info	= hermon_inform_sma,
-	.set_pkey_table	= hermon_inform_sma,
-};
-
 /**
- * Register Hermon Infiniband device
+ * Map ICM (allocating if necessary)
  *
  * @v hermon		Hermon device
- * @v port		Hermon port
+ * @v init_hca		INIT_HCA structure to fill in
  * @ret rc		Return status code
  */
-static int hermon_register_ibdev ( struct hermon *hermon,
-				   struct hermon_port *port ) {
-	struct ib_device *ibdev = port->ibdev;
+static int hermon_map_icm ( struct hermon *hermon,
+			    struct hermonprm_init_hca *init_hca ) {
+	struct hermonprm_scalar_parameter icm_size;
+	struct hermonprm_scalar_parameter icm_aux_size;
+	uint64_t icm_offset = 0;
+	unsigned int log_num_qps, log_num_srqs, log_num_cqs, log_num_eqs;
+	unsigned int log_num_mtts, log_num_mpts, log_num_mcs;
+	size_t cmpt_max_len;
+	size_t icm_len, icm_aux_len;
+	size_t len;
+	physaddr_t icm_phys;
+	int i;
 	int rc;
 
-	/* Initialise parameters using SMC */
-	ib_smc_init ( ibdev, hermon_mad );
-
-	/* Register Infiniband device */
-	if ( ( rc = register_ibdev ( ibdev ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p port %d could not register IB "
-		       "device: %s\n", hermon, ibdev->port, strerror ( rc ) );
-		return rc;
-	}
+	/*
+	 * Start by carving up the ICM virtual address space
+	 *
+	 */
 
-	return 0;
-}
+	/* Calculate number of each object type within ICM */
+	log_num_qps = fls ( hermon->cap.reserved_qps +
+			    HERMON_RSVD_SPECIAL_QPS + HERMON_MAX_QPS - 1 );
+	log_num_srqs = fls ( hermon->cap.reserved_srqs - 1 );
+	log_num_cqs = fls ( hermon->cap.reserved_cqs + HERMON_MAX_CQS - 1 );
+	log_num_eqs = fls ( hermon->cap.reserved_eqs + HERMON_MAX_EQS - 1 );
+	log_num_mtts = fls ( hermon->cap.reserved_mtts + HERMON_MAX_MTTS - 1 );
+	log_num_mpts = fls ( hermon->cap.reserved_mrws + 1 - 1 );
+	log_num_mcs = HERMON_LOG_MULTICAST_HASH_SIZE;
 
-/**
- * Handle Hermon Infiniband device port state change
- *
- * @v hermon		Hermon device
- * @v port		Hermon port
- * @v link_up		Link is up
- */
-static void hermon_state_change_ibdev ( struct hermon *hermon __unused,
-					struct hermon_port *port,
-					int link_up __unused ) {
-	struct ib_device *ibdev = port->ibdev;
+	/* ICM starts with the cMPT tables, which are sparse */
+	cmpt_max_len = ( HERMON_CMPT_MAX_ENTRIES *
+			 ( ( uint64_t ) hermon->cap.cmpt_entry_size ) );
+	len = ( ( ( ( 1 << log_num_qps ) * hermon->cap.cmpt_entry_size ) +
+		  HERMON_PAGE_SIZE - 1 ) & ~( HERMON_PAGE_SIZE - 1 ) );
+	hermon->icm_map[HERMON_ICM_QP_CMPT].offset = icm_offset;
+	hermon->icm_map[HERMON_ICM_QP_CMPT].len = len;
+	icm_offset += cmpt_max_len;
+	len = ( ( ( ( 1 << log_num_srqs ) * hermon->cap.cmpt_entry_size ) +
+		  HERMON_PAGE_SIZE - 1 ) & ~( HERMON_PAGE_SIZE - 1 ) );
+	hermon->icm_map[HERMON_ICM_SRQ_CMPT].offset = icm_offset;
+	hermon->icm_map[HERMON_ICM_SRQ_CMPT].len = len;
+	icm_offset += cmpt_max_len;
+	len = ( ( ( ( 1 << log_num_cqs ) * hermon->cap.cmpt_entry_size ) +
+		  HERMON_PAGE_SIZE - 1 ) & ~( HERMON_PAGE_SIZE - 1 ) );
+	hermon->icm_map[HERMON_ICM_CQ_CMPT].offset = icm_offset;
+	hermon->icm_map[HERMON_ICM_CQ_CMPT].len = len;
+	icm_offset += cmpt_max_len;
+	len = ( ( ( ( 1 << log_num_eqs ) * hermon->cap.cmpt_entry_size ) +
+		  HERMON_PAGE_SIZE - 1 ) & ~( HERMON_PAGE_SIZE - 1 ) );
+	hermon->icm_map[HERMON_ICM_EQ_CMPT].offset = icm_offset;
+	hermon->icm_map[HERMON_ICM_EQ_CMPT].len = len;
+	icm_offset += cmpt_max_len;
 
-	/* Update MAD parameters */
-	ib_smc_update ( ibdev, hermon_mad );
-}
+	hermon->icm_map[HERMON_ICM_OTHER].offset = icm_offset;
 
-/**
- * Unregister Hermon Infiniband device
- *
- * @v hermon		Hermon device
- * @v port		Hermon port
- */
-static void hermon_unregister_ibdev ( struct hermon *hermon __unused,
-				      struct hermon_port *port ) {
-	struct ib_device *ibdev = port->ibdev;
+	/* Queue pair contexts */
+	len = ( ( 1 << log_num_qps ) * hermon->cap.qpc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 12,
+		     qpc_eec_cqc_eqc_rdb_parameters.qpc_base_addr_h,
+		     ( icm_offset >> 32 ) );
+	MLX_FILL_2 ( init_hca, 13,
+		     qpc_eec_cqc_eqc_rdb_parameters.qpc_base_addr_l,
+		     ( icm_offset >> 5 ),
+		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_qp,
+		     log_num_qps );
+	DBGC ( hermon, "Hermon %p ICM QPC is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_qps ), hermon->cap.qpc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
 
-	unregister_ibdev ( ibdev );
-}
+	/* Extended alternate path contexts */
+	len = ( ( 1 << log_num_qps ) * hermon->cap.altc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 24,
+		     qpc_eec_cqc_eqc_rdb_parameters.altc_base_addr_h,
+		     ( icm_offset >> 32 ) );
+	MLX_FILL_1 ( init_hca, 25,
+		     qpc_eec_cqc_eqc_rdb_parameters.altc_base_addr_l,
+		     icm_offset );
+	DBGC ( hermon, "Hermon %p ICM ALTC is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_qps ), hermon->cap.altc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
 
-/** Hermon Infiniband port type */
-static struct hermon_port_type hermon_port_type_ib = {
-	.register_dev = hermon_register_ibdev,
-	.state_change = hermon_state_change_ibdev,
-	.unregister_dev = hermon_unregister_ibdev,
-};
+	/* Extended auxiliary contexts */
+	len = ( ( 1 << log_num_qps ) * hermon->cap.auxc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 28,
+		     qpc_eec_cqc_eqc_rdb_parameters.auxc_base_addr_h,
+		     ( icm_offset >> 32 ) );
+	MLX_FILL_1 ( init_hca, 29,
+		     qpc_eec_cqc_eqc_rdb_parameters.auxc_base_addr_l,
+		     icm_offset );
+	DBGC ( hermon, "Hermon %p ICM AUXC is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_qps ), hermon->cap.auxc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
 
-/***************************************************************************
- *
- * Ethernet operation
- *
- ***************************************************************************
- */
+	/* Shared receive queue contexts */
+	len = ( ( 1 << log_num_srqs ) * hermon->cap.srqc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 18,
+		     qpc_eec_cqc_eqc_rdb_parameters.srqc_base_addr_h,
+		     ( icm_offset >> 32 ) );
+	MLX_FILL_2 ( init_hca, 19,
+		     qpc_eec_cqc_eqc_rdb_parameters.srqc_base_addr_l,
+		     ( icm_offset >> 5 ),
+		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_srq,
+		     log_num_srqs );
+	DBGC ( hermon, "Hermon %p ICM SRQC is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_srqs ), hermon->cap.srqc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
 
-/** Number of Hermon Ethernet send work queue entries */
-#define HERMON_ETH_NUM_SEND_WQES 2
+	/* Completion queue contexts */
+	len = ( ( 1 << log_num_cqs ) * hermon->cap.cqc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 20,
+		     qpc_eec_cqc_eqc_rdb_parameters.cqc_base_addr_h,
+		     ( icm_offset >> 32 ) );
+	MLX_FILL_2 ( init_hca, 21,
+		     qpc_eec_cqc_eqc_rdb_parameters.cqc_base_addr_l,
+		     ( icm_offset >> 5 ),
+		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_cq,
+		     log_num_cqs );
+	DBGC ( hermon, "Hermon %p ICM CQC is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_cqs ), hermon->cap.cqc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
 
-/** Number of Hermon Ethernet receive work queue entries */
-#define HERMON_ETH_NUM_RECV_WQES 4
+	/* Event queue contexts */
+	len = ( ( 1 << log_num_eqs ) * hermon->cap.eqc_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 32,
+		     qpc_eec_cqc_eqc_rdb_parameters.eqc_base_addr_h,
+		     ( icm_offset >> 32 ) );
+	MLX_FILL_2 ( init_hca, 33,
+		     qpc_eec_cqc_eqc_rdb_parameters.eqc_base_addr_l,
+		     ( icm_offset >> 5 ),
+		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_eq,
+		     log_num_eqs );
+	DBGC ( hermon, "Hermon %p ICM EQC is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_eqs ), hermon->cap.eqc_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
 
-/** Number of Hermon Ethernet completion entries */
-#define HERMON_ETH_NUM_CQES 8
+	/* Memory translation table */
+	len = ( ( 1 << log_num_mtts ) * hermon->cap.mtt_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 64,
+		     tpt_parameters.mtt_base_addr_h, ( icm_offset >> 32 ) );
+	MLX_FILL_1 ( init_hca, 65,
+		     tpt_parameters.mtt_base_addr_l, icm_offset );
+	DBGC ( hermon, "Hermon %p ICM MTT is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_mtts ), hermon->cap.mtt_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
 
-/**
- * Transmit packet via Hermon Ethernet device
- *
- * @v netdev		Network device
- * @v iobuf		I/O buffer
- * @ret rc		Return status code
- */
-static int hermon_eth_transmit ( struct net_device *netdev,
-				 struct io_buffer *iobuf ) {
-	struct hermon_port *port = netdev->priv;
-	struct ib_device *ibdev = port->ibdev;
-	struct hermon *hermon = ib_get_drvdata ( ibdev );
-	int rc;
+	/* Memory protection table */
+	len = ( ( 1 << log_num_mpts ) * hermon->cap.dmpt_entry_size );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 60,
+		     tpt_parameters.dmpt_base_adr_h, ( icm_offset >> 32 ) );
+	MLX_FILL_1 ( init_hca, 61,
+		     tpt_parameters.dmpt_base_adr_l, icm_offset );
+	MLX_FILL_1 ( init_hca, 62,
+		     tpt_parameters.log_dmpt_sz, log_num_mpts );
+	DBGC ( hermon, "Hermon %p ICM DMPT is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_mpts ), hermon->cap.dmpt_entry_size,
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
 
-	/* Transmit packet */
-	if ( ( rc = ib_post_send ( ibdev, port->eth_qp, NULL,
-				   iobuf ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p port %d could not transmit: %s\n",
-		       hermon, ibdev->port, strerror ( rc ) );
-		return rc;
+	/* Multicast table */
+	len = ( ( 1 << log_num_mcs ) * sizeof ( struct hermonprm_mcg_entry ) );
+	icm_offset = icm_align ( icm_offset, len );
+	MLX_FILL_1 ( init_hca, 48,
+		     multicast_parameters.mc_base_addr_h,
+		     ( icm_offset >> 32 ) );
+	MLX_FILL_1 ( init_hca, 49,
+		     multicast_parameters.mc_base_addr_l, icm_offset );
+	MLX_FILL_1 ( init_hca, 52,
+		     multicast_parameters.log_mc_table_entry_sz,
+		     fls ( sizeof ( struct hermonprm_mcg_entry ) - 1 ) );
+	MLX_FILL_1 ( init_hca, 53,
+		     multicast_parameters.log_mc_table_hash_sz, log_num_mcs );
+	MLX_FILL_1 ( init_hca, 54,
+		     multicast_parameters.log_mc_table_sz, log_num_mcs );
+	DBGC ( hermon, "Hermon %p ICM MC is %d x %#zx at [%08llx,%08llx)\n",
+	       hermon, ( 1 << log_num_mcs ),
+	       sizeof ( struct hermonprm_mcg_entry ),
+	       icm_offset, ( icm_offset + len ) );
+	icm_offset += len;
+
+
+	hermon->icm_map[HERMON_ICM_OTHER].len =
+		( icm_offset - hermon->icm_map[HERMON_ICM_OTHER].offset );
+
+	/*
+	 * Allocate and map physical memory for (portions of) ICM
+	 *
+	 * Map is:
+	 *   ICM AUX area (aligned to its own size)
+	 *   cMPT areas
+	 *   Other areas
+	 */
+
+	/* Calculate physical memory required for ICM */
+	icm_len = 0;
+	for ( i = 0 ; i < HERMON_ICM_NUM_REGIONS ; i++ ) {
+		icm_len += hermon->icm_map[i].len;
+	}
+
+	/* Get ICM auxiliary area size */
+	memset ( &icm_size, 0, sizeof ( icm_size ) );
+	MLX_FILL_1 ( &icm_size, 0, value_hi, ( icm_offset >> 32 ) );
+	MLX_FILL_1 ( &icm_size, 1, value, icm_offset );
+	if ( ( rc = hermon_cmd_set_icm_size ( hermon, &icm_size,
+					      &icm_aux_size ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not set ICM size: %s\n",
+		       hermon, strerror ( rc ) );
+		goto err_set_icm_size;
+	}
+	icm_aux_len = ( MLX_GET ( &icm_aux_size, value ) * HERMON_PAGE_SIZE );
+
+	/* Allocate ICM data and auxiliary area */
+	DBGC ( hermon, "Hermon %p requires %zd kB ICM and %zd kB AUX ICM\n",
+	       hermon, ( icm_len / 1024 ), ( icm_aux_len / 1024 ) );
+	if ( ! hermon->icm ) {
+		hermon->icm_len = icm_len;
+		hermon->icm_aux_len = icm_aux_len;
+		hermon->icm = umalloc ( hermon->icm_aux_len + hermon->icm_len );
+		if ( ! hermon->icm ) {
+			rc = -ENOMEM;
+			goto err_alloc;
+		}
+	} else {
+		assert ( hermon->icm_len == icm_len );
+		assert ( hermon->icm_aux_len == icm_aux_len );
+	}
+	icm_phys = user_to_phys ( hermon->icm, 0 );
+
+	/* Map ICM auxiliary area */
+	DBGC ( hermon, "Hermon %p mapping ICM AUX => %08lx\n",
+	       hermon, icm_phys );
+	if ( ( rc = hermon_map_vpm ( hermon, hermon_cmd_map_icm_aux,
+				     0, icm_phys, icm_aux_len ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not map AUX ICM: %s\n",
+		       hermon, strerror ( rc ) );
+		goto err_map_icm_aux;
+	}
+	icm_phys += icm_aux_len;
+
+	/* MAP ICM area */
+	for ( i = 0 ; i < HERMON_ICM_NUM_REGIONS ; i++ ) {
+		DBGC ( hermon, "Hermon %p mapping ICM %llx+%zx => %08lx\n",
+		       hermon, hermon->icm_map[i].offset,
+		       hermon->icm_map[i].len, icm_phys );
+		if ( ( rc = hermon_map_vpm ( hermon, hermon_cmd_map_icm,
+					     hermon->icm_map[i].offset,
+					     icm_phys,
+					     hermon->icm_map[i].len ) ) != 0 ){
+			DBGC ( hermon, "Hermon %p could not map ICM: %s\n",
+			       hermon, strerror ( rc ) );
+			goto err_map_icm;
+		}
+		icm_phys += hermon->icm_map[i].len;
 	}
 
 	return 0;
+
+ err_map_icm:
+	assert ( i == 0 ); /* We don't handle partial failure at present */
+ err_map_icm_aux:
+	hermon_cmd_unmap_icm_aux ( hermon );
+ err_alloc:
+ err_set_icm_size:
+	return rc;
 }
 
 /**
- * Handle Hermon Ethernet device send completion
+ * Unmap ICM
  *
- * @v ibdev		Infiniband device
- * @v qp		Queue pair
- * @v iobuf		I/O buffer
- * @v rc		Completion status code
+ * @v hermon		Hermon device
  */
-static void hermon_eth_complete_send ( struct ib_device *ibdev __unused,
-				       struct ib_queue_pair *qp,
-				       struct io_buffer *iobuf, int rc ) {
-	struct net_device *netdev = ib_qp_get_ownerdata ( qp );
+static void hermon_unmap_icm ( struct hermon *hermon ) {
+	struct hermonprm_scalar_parameter unmap_icm;
+	int i;
 
-	netdev_tx_complete_err ( netdev, iobuf, rc );
+	for ( i = ( HERMON_ICM_NUM_REGIONS - 1 ) ; i >= 0 ; i-- ) {
+		memset ( &unmap_icm, 0, sizeof ( unmap_icm ) );
+		MLX_FILL_1 ( &unmap_icm, 0, value_hi,
+			     ( hermon->icm_map[i].offset >> 32 ) );
+		MLX_FILL_1 ( &unmap_icm, 1, value,
+			     hermon->icm_map[i].offset );
+		hermon_cmd_unmap_icm ( hermon,
+				       ( 1 << fls ( ( hermon->icm_map[i].len /
+						      HERMON_PAGE_SIZE ) - 1)),
+				       &unmap_icm );
+	}
+	hermon_cmd_unmap_icm_aux ( hermon );
 }
 
+/***************************************************************************
+ *
+ * Initialisation and teardown
+ *
+ ***************************************************************************
+ */
+
 /**
- * Handle Hermon Ethernet device receive completion
+ * Reset device
  *
- * @v ibdev		Infiniband device
- * @v qp		Queue pair
- * @v av		Address vector, or NULL
- * @v iobuf		I/O buffer
- * @v rc		Completion status code
+ * @v hermon		Hermon device
  */
-static void hermon_eth_complete_recv ( struct ib_device *ibdev __unused,
-				       struct ib_queue_pair *qp,
-				       struct ib_address_vector *av,
-				       struct io_buffer *iobuf, int rc ) {
-	struct net_device *netdev = ib_qp_get_ownerdata ( qp );
-	struct net_device *vlan;
+static void hermon_reset ( struct hermon *hermon ) {
+	struct pci_device *pci = hermon->pci;
+	struct pci_config_backup backup;
+	static const uint8_t backup_exclude[] =
+		PCI_CONFIG_BACKUP_EXCLUDE ( 0x58, 0x5c );
 
-	/* Find VLAN device, if applicable */
-	if ( av->vlan_present ) {
-		if ( ( vlan = vlan_find ( netdev, av->vlan ) ) != NULL ) {
-			netdev = vlan;
-		} else if ( rc == 0 ) {
-			rc = -ENODEV;
-		}
-	}
+	/* Perform device reset and preserve PCI configuration */
+	pci_backup ( pci, &backup, backup_exclude );
+	writel ( HERMON_RESET_MAGIC,
+		 ( hermon->config + HERMON_RESET_OFFSET ) );
+	mdelay ( HERMON_RESET_WAIT_TIME_MS );
+	pci_restore ( pci, &backup, backup_exclude );
 
-	/* Hand off to network layer */
-	if ( rc == 0 ) {
-		netdev_rx ( netdev, iobuf );
-	} else {
-		netdev_rx_err ( netdev, iobuf, rc );
-	}
+	/* Reset command interface toggle */
+	hermon->toggle = 0;
 }
 
-/** Hermon Ethernet device completion operations */
-static struct ib_completion_queue_operations hermon_eth_cq_op = {
-	.complete_send = hermon_eth_complete_send,
-	.complete_recv = hermon_eth_complete_recv,
-};
-
 /**
- * Poll Hermon Ethernet device
+ * Set up memory protection table
  *
- * @v netdev		Network device
+ * @v hermon		Hermon device
+ * @ret rc		Return status code
  */
-static void hermon_eth_poll ( struct net_device *netdev ) {
-	struct hermon_port *port = netdev->priv;
-	struct ib_device *ibdev = port->ibdev;
+static int hermon_setup_mpt ( struct hermon *hermon ) {
+	struct hermonprm_mpt mpt;
+	uint32_t key;
+	int rc;
 
-	ib_poll_eq ( ibdev );
+	/* Derive key */
+	key = ( hermon->cap.reserved_mrws | HERMON_MKEY_PREFIX );
+	hermon->lkey = ( ( key << 8 ) | ( key >> 24 ) );
+
+	/* Initialise memory protection table */
+	memset ( &mpt, 0, sizeof ( mpt ) );
+	MLX_FILL_7 ( &mpt, 0,
+		     atomic, 1,
+		     rw, 1,
+		     rr, 1,
+		     lw, 1,
+		     lr, 1,
+		     pa, 1,
+		     r_w, 1 );
+	MLX_FILL_1 ( &mpt, 2, mem_key, key );
+	MLX_FILL_1 ( &mpt, 3,
+		     pd, HERMON_GLOBAL_PD );
+	MLX_FILL_1 ( &mpt, 10, len64, 1 );
+	if ( ( rc = hermon_cmd_sw2hw_mpt ( hermon,
+					   hermon->cap.reserved_mrws,
+					   &mpt ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not set up MPT: %s\n",
+		       hermon, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
 }
 
 /**
- * Open Hermon Ethernet device
+ * Configure special queue pairs
  *
- * @v netdev		Network device
+ * @v hermon		Hermon device
  * @ret rc		Return status code
  */
-static int hermon_eth_open ( struct net_device *netdev ) {
-	struct hermon_port *port = netdev->priv;
-	struct ib_device *ibdev = port->ibdev;
-	struct hermon *hermon = ib_get_drvdata ( ibdev );
-	union hermonprm_set_port set_port;
+static int hermon_configure_special_qps ( struct hermon *hermon ) {
 	int rc;
 
-	/* Allocate completion queue */
-	port->eth_cq = ib_create_cq ( ibdev, HERMON_ETH_NUM_CQES,
-				      &hermon_eth_cq_op );
-	if ( ! port->eth_cq ) {
-		DBGC ( hermon, "Hermon %p port %d could not create completion "
-		       "queue\n", hermon, ibdev->port );
-		rc = -ENOMEM;
-		goto err_create_cq;
-	}
+	/* Special QP block must be aligned on its own size */
+	hermon->special_qpn_base = ( ( hermon->cap.reserved_qps +
+				       HERMON_NUM_SPECIAL_QPS - 1 )
+				     & ~( HERMON_NUM_SPECIAL_QPS - 1 ) );
+	hermon->qpn_base = ( hermon->special_qpn_base +
+			     HERMON_NUM_SPECIAL_QPS );
+	DBGC ( hermon, "Hermon %p special QPs at [%lx,%lx]\n", hermon,
+	       hermon->special_qpn_base, ( hermon->qpn_base - 1 ) );
 
-	/* Allocate queue pair */
-	port->eth_qp = ib_create_qp ( ibdev, IB_QPT_ETH,
-				      HERMON_ETH_NUM_SEND_WQES, port->eth_cq,
-				      HERMON_ETH_NUM_RECV_WQES, port->eth_cq );
-	if ( ! port->eth_qp ) {
-		DBGC ( hermon, "Hermon %p port %d could not create queue "
-		       "pair\n", hermon, ibdev->port );
-		rc = -ENOMEM;
-		goto err_create_qp;
+	/* Issue command to configure special QPs */
+	if ( ( rc = hermon_cmd_conf_special_qp ( hermon, 0x00,
+					  hermon->special_qpn_base ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not configure special QPs: "
+		       "%s\n", hermon, strerror ( rc ) );
+		return rc;
 	}
-	ib_qp_set_ownerdata ( port->eth_qp, netdev );
 
-	/* Activate queue pair */
-	if ( ( rc = ib_modify_qp ( ibdev, port->eth_qp ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p port %d could not modify queue "
-		       "pair: %s\n", hermon, ibdev->port, strerror ( rc ) );
-		goto err_modify_qp;
-	}
+	return 0;
+}
 
-	/* Fill receive rings */
-	ib_refill_recv ( ibdev, port->eth_qp );
+/**
+ * Start Hermon device
+ *
+ * @v hermon		Hermon device
+ * @v running		Firmware is already running
+ * @ret rc		Return status code
+ */
+static int hermon_start ( struct hermon *hermon, int running ) {
+	struct hermonprm_init_hca init_hca;
+	unsigned int i;
+	int rc;
 
-	/* Set port general parameters */
-	memset ( &set_port, 0, sizeof ( set_port ) );
-	MLX_FILL_3 ( &set_port.general, 0,
-		     v_mtu, 1,
-		     v_pprx, 1,
-		     v_pptx, 1 );
-	MLX_FILL_1 ( &set_port.general, 1,
-		     mtu, ( ETH_FRAME_LEN + 40 /* Used by card */ ) );
-	MLX_FILL_1 ( &set_port.general, 2,
-		     pfctx, ( 1 << FCOE_VLAN_PRIORITY ) );
-	MLX_FILL_1 ( &set_port.general, 3,
-		     pfcrx, ( 1 << FCOE_VLAN_PRIORITY ) );
-	if ( ( rc = hermon_cmd_set_port ( hermon, 1,
-					  ( HERMON_SET_PORT_GENERAL_PARAM |
-					    ibdev->port ),
-					  &set_port ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p port %d could not set port general "
-		       "parameters: %s\n",
-		       hermon, ibdev->port, strerror ( rc ) );
-		goto err_set_port_general_params;
+	/* Start firmware if not already running */
+	if ( ! running ) {
+		if ( ( rc = hermon_start_firmware ( hermon ) ) != 0 )
+			goto err_start_firmware;
 	}
 
-	/* Set port receive QP */
-	memset ( &set_port, 0, sizeof ( set_port ) );
-	MLX_FILL_1 ( &set_port.rqp_calc, 0, base_qpn, port->eth_qp->qpn );
-	MLX_FILL_1 ( &set_port.rqp_calc, 2,
-		     mac_miss_index, 128 /* MAC misses go to promisc QP */ );
-	MLX_FILL_2 ( &set_port.rqp_calc, 3,
-		     vlan_miss_index, 127 /* VLAN misses go to promisc QP */,
-		     no_vlan_index, 126 /* VLAN-free go to promisc QP */ );
-	MLX_FILL_2 ( &set_port.rqp_calc, 5,
-		     promisc_qpn, port->eth_qp->qpn,
-		     en_uc_promisc, 1 );
-	MLX_FILL_2 ( &set_port.rqp_calc, 6,
-		     def_mcast_qpn, port->eth_qp->qpn,
-		     mc_promisc_mode, 2 /* Receive all multicasts */ );
-	if ( ( rc = hermon_cmd_set_port ( hermon, 1,
-					  ( HERMON_SET_PORT_RECEIVE_QP |
-					    ibdev->port ),
-					  &set_port ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p port %d could not set port receive "
-		       "QP: %s\n", hermon, ibdev->port, strerror ( rc ) );
-		goto err_set_port_receive_qp;
-	}
+	/* Allocate and map ICM */
+	memset ( &init_hca, 0, sizeof ( init_hca ) );
+	if ( ( rc = hermon_map_icm ( hermon, &init_hca ) ) != 0 )
+		goto err_map_icm;
 
-	/* Initialise port */
-	if ( ( rc = hermon_cmd_init_port ( hermon, ibdev->port ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p port %d could not initialise port: "
-		       "%s\n", hermon, ibdev->port, strerror ( rc ) );
-		goto err_init_port;
+	/* Initialise HCA */
+	MLX_FILL_1 ( &init_hca, 0, version, 0x02 /* "Must be 0x02" */ );
+	MLX_FILL_1 ( &init_hca, 5, udp, 1 );
+	MLX_FILL_1 ( &init_hca, 74, uar_parameters.log_max_uars, 8 );
+	if ( ( rc = hermon_cmd_init_hca ( hermon, &init_hca ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not initialise HCA: %s\n",
+		       hermon, strerror ( rc ) );
+		goto err_init_hca;
 	}
 
+	/* Set up memory protection */
+	if ( ( rc = hermon_setup_mpt ( hermon ) ) != 0 )
+		goto err_setup_mpt;
+	for ( i = 0 ; i < hermon->cap.num_ports ; i++ )
+		hermon->port[i].ibdev->rdma_key = hermon->lkey;
+
+	/* Set up event queue */
+	if ( ( rc = hermon_create_eq ( hermon ) ) != 0 )
+		goto err_create_eq;
+
+	/* Configure special QPs */
+	if ( ( rc = hermon_configure_special_qps ( hermon ) ) != 0 )
+		goto err_conf_special_qps;
+
 	return 0;
 
- err_init_port:
- err_set_port_receive_qp:
- err_set_port_general_params:
- err_modify_qp:
-	ib_destroy_qp ( ibdev, port->eth_qp );
- err_create_qp:
-	ib_destroy_cq ( ibdev, port->eth_cq );
- err_create_cq:
+ err_conf_special_qps:
+	hermon_destroy_eq ( hermon );
+ err_create_eq:
+ err_setup_mpt:
+	hermon_cmd_close_hca ( hermon );
+ err_init_hca:
+	hermon_unmap_icm ( hermon );
+ err_map_icm:
+	hermon_stop_firmware ( hermon );
+ err_start_firmware:
 	return rc;
 }
 
 /**
- * Close Hermon Ethernet device
+ * Stop Hermon device
  *
- * @v netdev		Network device
+ * @v hermon		Hermon device
  */
-static void hermon_eth_close ( struct net_device *netdev ) {
-	struct hermon_port *port = netdev->priv;
-	struct ib_device *ibdev = port->ibdev;
-	struct hermon *hermon = ib_get_drvdata ( ibdev );
-	int rc;
-
-	/* Close port */
-	if ( ( rc = hermon_cmd_close_port ( hermon, ibdev->port ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p port %d could not close port: %s\n",
-		       hermon, ibdev->port, strerror ( rc ) );
-		/* Nothing we can do about this */
-	}
-
-	/* Tear down the queues */
-	ib_destroy_qp ( ibdev, port->eth_qp );
-	ib_destroy_cq ( ibdev, port->eth_cq );
+static void hermon_stop ( struct hermon *hermon ) {
+	hermon_destroy_eq ( hermon );
+	hermon_cmd_close_hca ( hermon );
+	hermon_unmap_icm ( hermon );
+	hermon_stop_firmware ( hermon );
+	hermon_reset ( hermon );
 }
 
-/** Hermon Ethernet network device operations */
-static struct net_device_operations hermon_eth_operations = {
-	.open		= hermon_eth_open,
-	.close		= hermon_eth_close,
-	.transmit	= hermon_eth_transmit,
-	.poll		= hermon_eth_poll,
-};
-
 /**
- * Register Hermon Ethernet device
+ * Open Hermon device
  *
  * @v hermon		Hermon device
- * @v port		Hermon port
  * @ret rc		Return status code
  */
-static int hermon_register_netdev ( struct hermon *hermon,
-				    struct hermon_port *port ) {
-	struct net_device *netdev = port->netdev;
-	struct ib_device *ibdev = port->ibdev;
-	struct hermonprm_query_port_cap query_port;
-	union {
-		uint8_t bytes[8];
-		uint32_t dwords[2];
-	} mac;
+static int hermon_open ( struct hermon *hermon ) {
 	int rc;
 
-	/* Retrieve MAC address */
-	if ( ( rc = hermon_cmd_query_port ( hermon, ibdev->port,
-					    &query_port ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p port %d could not query port: %s\n",
-		       hermon, ibdev->port, strerror ( rc ) );
-		return rc;
+	/* Start device if applicable */
+	if ( hermon->open_count == 0 ) {
+		if ( ( rc = hermon_start ( hermon, 0 ) ) != 0 )
+			return rc;
 	}
-	mac.dwords[0] = htonl ( MLX_GET ( &query_port, mac_47_32 ) );
-	mac.dwords[1] = htonl ( MLX_GET ( &query_port, mac_31_0 ) );
-	memcpy ( netdev->hw_addr,
-		 &mac.bytes[ sizeof ( mac.bytes ) - ETH_ALEN ], ETH_ALEN );
 
-	/* Register network device */
-	if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p port %d could not register network "
-		       "device: %s\n", hermon, ibdev->port, strerror ( rc ) );
-		return rc;
-	}
+	/* Increment open counter */
+	hermon->open_count++;
 
 	return 0;
 }
 
 /**
- * Handle Hermon Ethernet device port state change
+ * Close Hermon device
  *
  * @v hermon		Hermon device
- * @v port		Hermon port
- * @v link_up		Link is up
  */
-static void hermon_state_change_netdev ( struct hermon *hermon __unused,
-					 struct hermon_port *port,
-					 int link_up ) {
-	struct net_device *netdev = port->netdev;
-
-	if ( link_up ) {
-		netdev_link_up ( netdev );
-	} else {
-		netdev_link_down ( netdev );
-	}
-}
+static void hermon_close ( struct hermon *hermon ) {
 
-/**
- * Unregister Hermon Ethernet device
- *
- * @v hermon		Hermon device
- * @v port		Hermon port
- */
-static void hermon_unregister_netdev ( struct hermon *hermon __unused,
-				       struct hermon_port *port ) {
-	struct net_device *netdev = port->netdev;
+	/* Decrement open counter */
+	assert ( hermon->open_count != 0 );
+	hermon->open_count--;
 
-	unregister_netdev ( netdev );
+	/* Stop device if applicable */
+	if ( hermon->open_count == 0 )
+		hermon_stop ( hermon );
 }
 
-/** Hermon Ethernet port type */
-static struct hermon_port_type hermon_port_type_eth = {
-	.register_dev = hermon_register_netdev,
-	.state_change = hermon_state_change_netdev,
-	.unregister_dev = hermon_unregister_netdev,
-};
-
 /***************************************************************************
  *
- * Port type detection
+ * Infiniband link-layer operations
  *
  ***************************************************************************
  */
 
-/** Timeout for port sensing */
-#define HERMON_SENSE_PORT_TIMEOUT ( TICKS_PER_SEC / 2 )
-
 /**
- * Name port type
+ * Initialise Infiniband link
  *
- * @v port_type		Port type
- * @v port_type_name	Port type name
+ * @v ibdev		Infiniband device
+ * @ret rc		Return status code
  */
-static inline const char * hermon_name_port_type ( unsigned int port_type ) {
-	switch ( port_type ) {
-	case HERMON_PORT_TYPE_UNKNOWN:	return "unknown";
-	case HERMON_PORT_TYPE_IB:	return "Infiniband";
-	case HERMON_PORT_TYPE_ETH:	return "Ethernet";
-	default:			return "INVALID";
-	}
-}
+static int hermon_ib_open ( struct ib_device *ibdev ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	union hermonprm_set_port set_port;
+	int rc;
 
-/**
- * Sense port type
- *
- * @v hermon		Hermon device
- * @v port		Hermon port
- * @ret port_type	Port type, or negative error
- */
-static int hermon_sense_port_type ( struct hermon *hermon,
-				    struct hermon_port *port ) {
-	struct ib_device *ibdev = port->ibdev;
-	struct hermonprm_sense_port sense_port;
-	int port_type;
-	int rc;
+	/* Open hardware */
+	if ( ( rc = hermon_open ( hermon ) ) != 0 )
+		goto err_open;
 
-	/* If DPDP is not supported, always assume Infiniband */
-	if ( ! hermon->cap.dpdp ) {
-		port_type = HERMON_PORT_TYPE_IB;
-		DBGC ( hermon, "Hermon %p port %d does not support DPDP; "
-		       "assuming an %s network\n", hermon, ibdev->port,
-		       hermon_name_port_type ( port_type ) );
-		return port_type;
+	/* Set port parameters */
+	memset ( &set_port, 0, sizeof ( set_port ) );
+	MLX_FILL_8 ( &set_port.ib, 0,
+		     mmc, 1,
+		     mvc, 1,
+		     mp, 1,
+		     mg, 1,
+		     mtu_cap, IB_MTU_2048,
+		     vl_cap, IB_VL_0,
+		     rcm, 1,
+		     lss, 1 );
+	MLX_FILL_2 ( &set_port.ib, 10,
+		     max_pkey, 1,
+		     max_gid, 1 );
+	MLX_FILL_1 ( &set_port.ib, 28,
+		     link_speed_supported, 1 );
+	if ( ( rc = hermon_cmd_set_port ( hermon, 0, ibdev->port,
+					  &set_port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not set port: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
+		goto err_set_port;
 	}
 
-	/* Sense the port type */
-	if ( ( rc = hermon_cmd_sense_port ( hermon, ibdev->port,
-					    &sense_port ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p port %d sense failed: %s\n",
-		       hermon, ibdev->port, strerror ( rc ) );
-		return rc;
+	/* Initialise port */
+	if ( ( rc = hermon_cmd_init_port ( hermon, ibdev->port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not initialise port: "
+		       "%s\n", hermon, ibdev->port, strerror ( rc ) );
+		goto err_init_port;
 	}
-	port_type = MLX_GET ( &sense_port, port_type );
 
-	DBGC ( hermon, "Hermon %p port %d sensed an %s network\n",
-	       hermon, ibdev->port, hermon_name_port_type ( port_type ) );
-	return port_type;
+	/* Update MAD parameters */
+	ib_smc_update ( ibdev, hermon_mad );
+
+	return 0;
+
+ err_init_port:
+ err_set_port:
+	hermon_close ( hermon );
+ err_open:
+	return rc;
 }
 
 /**
- * Set port type
+ * Close Infiniband link
  *
- * @v hermon		Hermon device
- * @v port		Hermon port
- * @ret rc		Return status code
+ * @v ibdev		Infiniband device
  */
-static int hermon_set_port_type ( struct hermon *hermon,
-				  struct hermon_port *port ) {
-	struct ib_device *ibdev = port->ibdev;
-	struct hermonprm_query_port_cap query_port;
-	int ib_supported;
-	int eth_supported;
-	int port_type;
-	unsigned long start;
-	unsigned long elapsed;
+static void hermon_ib_close ( struct ib_device *ibdev ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
 	int rc;
 
-	/* Check to see which types are supported */
-	if ( ( rc = hermon_cmd_query_port ( hermon, ibdev->port,
-					    &query_port ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p port %d could not query port: %s\n",
+	/* Close port */
+	if ( ( rc = hermon_cmd_close_port ( hermon, ibdev->port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not close port: %s\n",
 		       hermon, ibdev->port, strerror ( rc ) );
-		return rc;
+		/* Nothing we can do about this */
 	}
-	ib_supported = MLX_GET ( &query_port, ib );
-	eth_supported = MLX_GET ( &query_port, eth );
-	DBGC ( hermon, "Hermon %p port %d supports%s%s%s\n",
-	       hermon, ibdev->port, ( ib_supported ? " Infiniband" : "" ),
-	       ( ( ib_supported && eth_supported ) ? " and" : "" ),
-	       ( eth_supported ? " Ethernet" : "" ) );
 
-	/* Sense network, if applicable */
-	if ( ib_supported && eth_supported ) {
+	/* Close hardware */
+	hermon_close ( hermon );
+}
 
-		/* Both types are supported; try sensing network */
-		start = currticks();
-		do {
-			/* Try sensing port */
-			port_type = hermon_sense_port_type ( hermon, port );
-			if ( port_type < 0 ) {
-				rc = port_type;
-				return rc;
-			}
-		} while ( ( port_type == HERMON_PORT_TYPE_UNKNOWN ) &&
-			  ( ( elapsed = ( currticks() - start ) ) <
-			    HERMON_SENSE_PORT_TIMEOUT ) );
+/**
+ * Inform embedded subnet management agent of a received MAD
+ *
+ * @v ibdev		Infiniband device
+ * @v mad		MAD
+ * @ret rc		Return status code
+ */
+static int hermon_inform_sma ( struct ib_device *ibdev,
+			       union ib_mad *mad ) {
+	int rc;
 
-		/* Set port type based on sensed network, defaulting
-		 * to Infiniband if nothing was sensed.
-		 */
-		switch ( port_type ) {
-		case HERMON_PORT_TYPE_ETH:
-			port->type = &hermon_port_type_eth;
-			break;
-		case HERMON_PORT_TYPE_IB:
-		case HERMON_PORT_TYPE_UNKNOWN:
-			port->type = &hermon_port_type_ib;
-			break;
-		default:
-			return -EINVAL;
-		}
+	/* Send the MAD to the embedded SMA */
+	if ( ( rc = hermon_mad ( ibdev, mad ) ) != 0 )
+		return rc;
 
-	} else if ( eth_supported ) {
-		port->type = &hermon_port_type_eth;
-	} else {
-		port->type = &hermon_port_type_ib;
-	}
+	/* Update parameters held in software */
+	ib_smc_update ( ibdev, hermon_mad );
 
-	assert ( port->type != NULL );
 	return 0;
 }
 
 /***************************************************************************
  *
- * Firmware control
+ * Multicast group operations
  *
  ***************************************************************************
  */
 
 /**
- * Map virtual to physical address for firmware usage
+ * Attach to multicast group
  *
- * @v hermon		Hermon device
- * @v map		Mapping function
- * @v va		Virtual address
- * @v pa		Physical address
- * @v len		Length of region
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v gid		Multicast GID
  * @ret rc		Return status code
  */
-static int hermon_map_vpm ( struct hermon *hermon,
-			    int ( *map ) ( struct hermon *hermon,
-			    const struct hermonprm_virtual_physical_mapping* ),
-			    uint64_t va, physaddr_t pa, size_t len ) {
-	struct hermonprm_virtual_physical_mapping mapping;
-	physaddr_t start;
-	physaddr_t low;
-	physaddr_t high;
-	physaddr_t end;
-	size_t size;
+static int hermon_mcast_attach ( struct ib_device *ibdev,
+				 struct ib_queue_pair *qp,
+				 union ib_gid *gid ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	struct hermonprm_mgm_hash hash;
+	struct hermonprm_mcg_entry mcg;
+	unsigned int index;
 	int rc;
 
-	/* Sanity checks */
-	assert ( ( va & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
-	assert ( ( pa & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
-	assert ( ( len & ( HERMON_PAGE_SIZE - 1 ) ) == 0 );
-
-	/* Calculate starting points */
-	start = pa;
-	end = ( start + len );
-	size = ( 1UL << ( fls ( start ^ end ) - 1 ) );
-	low = high = ( end & ~( size - 1 ) );
-	assert ( start < low );
-	assert ( high <= end );
-
-	/* These mappings tend to generate huge volumes of
-	 * uninteresting debug data, which basically makes it
-	 * impossible to use debugging otherwise.
-	 */
-	DBG_DISABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
-
-	/* Map blocks in descending order of size */
-	while ( size >= HERMON_PAGE_SIZE ) {
+	/* Generate hash table index */
+	if ( ( rc = hermon_cmd_mgid_hash ( hermon, gid, &hash ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not hash GID: %s\n",
+		       hermon, strerror ( rc ) );
+		return rc;
+	}
+	index = MLX_GET ( &hash, hash );
 
-		/* Find the next candidate block */
-		if ( ( low - size ) >= start ) {
-			low -= size;
-			pa = low;
-		} else if ( ( high + size ) <= end ) {
-			pa = high;
-			high += size;
-		} else {
-			size >>= 1;
-			continue;
-		}
-		assert ( ( va & ( size - 1 ) ) == 0 );
-		assert ( ( pa & ( size - 1 ) ) == 0 );
+	/* Check for existing hash table entry */
+	if ( ( rc = hermon_cmd_read_mcg ( hermon, index, &mcg ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not read MCG %#x: %s\n",
+		       hermon, index, strerror ( rc ) );
+		return rc;
+	}
+	if ( MLX_GET ( &mcg, hdr.members_count ) != 0 ) {
+		/* FIXME: this implementation allows only a single QP
+		 * per multicast group, and doesn't handle hash
+		 * collisions.  Sufficient for IPoIB but may need to
+		 * be extended in future.
+		 */
+		DBGC ( hermon, "Hermon %p MGID index %#x already in use\n",
+		       hermon, index );
+		return -EBUSY;
+	}
 
-		/* Map this block */
-		memset ( &mapping, 0, sizeof ( mapping ) );
-		MLX_FILL_1 ( &mapping, 0, va_h, ( va >> 32 ) );
-		MLX_FILL_1 ( &mapping, 1, va_l, ( va >> 12 ) );
-		MLX_FILL_H ( &mapping, 2, pa_h, pa );
-		MLX_FILL_2 ( &mapping, 3,
-			     log2size, ( ( fls ( size ) - 1 ) - 12 ),
-			     pa_l, ( pa >> 12 ) );
-		if ( ( rc = map ( hermon, &mapping ) ) != 0 ) {
-			DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
-			DBGC ( hermon, "Hermon %p could not map %08llx+%zx to "
-			       "%08lx: %s\n",
-			       hermon, va, size, pa, strerror ( rc ) );
-			return rc;
-		}
-		va += size;
+	/* Update hash table entry */
+	MLX_FILL_1 ( &mcg, 1, hdr.members_count, 1 );
+	MLX_FILL_1 ( &mcg, 8, qp[0].qpn, qp->qpn );
+	memcpy ( &mcg.u.dwords[4], gid, sizeof ( *gid ) );
+	if ( ( rc = hermon_cmd_write_mcg ( hermon, index, &mcg ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not write MCG %#x: %s\n",
+		       hermon, index, strerror ( rc ) );
+		return rc;
 	}
-	assert ( low == start );
-	assert ( high == end );
 
-	DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA );
 	return 0;
 }
 
 /**
- * Start firmware running
+ * Detach from multicast group
  *
- * @v hermon		Hermon device
- * @ret rc		Return status code
- */
-static int hermon_start_firmware ( struct hermon *hermon ) {
-	struct hermonprm_query_fw fw;
-	unsigned int fw_pages;
-	size_t fw_size;
-	physaddr_t fw_base;
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v gid		Multicast GID
+ */
+static void hermon_mcast_detach ( struct ib_device *ibdev,
+				  struct ib_queue_pair *qp __unused,
+				  union ib_gid *gid ) {
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	struct hermonprm_mgm_hash hash;
+	struct hermonprm_mcg_entry mcg;
+	unsigned int index;
 	int rc;
 
-	/* Get firmware parameters */
-	if ( ( rc = hermon_cmd_query_fw ( hermon, &fw ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p could not query firmware: %s\n",
+	/* Generate hash table index */
+	if ( ( rc = hermon_cmd_mgid_hash ( hermon, gid, &hash ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not hash GID: %s\n",
 		       hermon, strerror ( rc ) );
-		goto err_query_fw;
+		return;
 	}
-	DBGC ( hermon, "Hermon %p firmware version %d.%d.%d\n", hermon,
-	       MLX_GET ( &fw, fw_rev_major ), MLX_GET ( &fw, fw_rev_minor ),
-	       MLX_GET ( &fw, fw_rev_subminor ) );
-	fw_pages = MLX_GET ( &fw, fw_pages );
-	DBGC ( hermon, "Hermon %p requires %d pages (%d kB) for firmware\n",
-	       hermon, fw_pages, ( fw_pages * 4 ) );
+	index = MLX_GET ( &hash, hash );
 
-	/* Allocate firmware pages and map firmware area */
-	fw_size = ( fw_pages * HERMON_PAGE_SIZE );
-	hermon->firmware_area = umalloc ( fw_size );
-	if ( ! hermon->firmware_area ) {
-		rc = -ENOMEM;
-		goto err_alloc_fa;
-	}
-	fw_base = user_to_phys ( hermon->firmware_area, 0 );
-	DBGC ( hermon, "Hermon %p firmware area at physical [%08lx,%08lx)\n",
-	       hermon, fw_base, ( fw_base + fw_size ) );
-	if ( ( rc = hermon_map_vpm ( hermon, hermon_cmd_map_fa,
-				     0, fw_base, fw_size ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p could not map firmware: %s\n",
-		       hermon, strerror ( rc ) );
-		goto err_map_fa;
+	/* Clear hash table entry */
+	memset ( &mcg, 0, sizeof ( mcg ) );
+	if ( ( rc = hermon_cmd_write_mcg ( hermon, index, &mcg ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p could not write MCG %#x: %s\n",
+		       hermon, index, strerror ( rc ) );
+		return;
 	}
+}
 
-	/* Start firmware */
-	if ( ( rc = hermon_cmd_run_fw ( hermon ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p could not run firmware: %s\n",
-		       hermon, strerror ( rc ) );
-		goto err_run_fw;
+/** Hermon Infiniband operations */
+static struct ib_device_operations hermon_ib_operations = {
+	.create_cq	= hermon_create_cq,
+	.destroy_cq	= hermon_destroy_cq,
+	.create_qp	= hermon_create_qp,
+	.modify_qp	= hermon_modify_qp,
+	.destroy_qp	= hermon_destroy_qp,
+	.post_send	= hermon_post_send,
+	.post_recv	= hermon_post_recv,
+	.poll_cq	= hermon_poll_cq,
+	.poll_eq	= hermon_poll_eq,
+	.open		= hermon_ib_open,
+	.close		= hermon_ib_close,
+	.mcast_attach	= hermon_mcast_attach,
+	.mcast_detach	= hermon_mcast_detach,
+	.set_port_info	= hermon_inform_sma,
+	.set_pkey_table	= hermon_inform_sma,
+};
+
+/**
+ * Register Hermon Infiniband device
+ *
+ * @v hermon		Hermon device
+ * @v port		Hermon port
+ * @ret rc		Return status code
+ */
+static int hermon_register_ibdev ( struct hermon *hermon,
+				   struct hermon_port *port ) {
+	struct ib_device *ibdev = port->ibdev;
+	int rc;
+
+	/* Initialise parameters using SMC */
+	ib_smc_init ( ibdev, hermon_mad );
+
+	/* Register Infiniband device */
+	if ( ( rc = register_ibdev ( ibdev ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not register IB "
+		       "device: %s\n", hermon, ibdev->port, strerror ( rc ) );
+		return rc;
 	}
 
-	DBGC ( hermon, "Hermon %p firmware started\n", hermon );
 	return 0;
+}
 
- err_run_fw:
- err_map_fa:
-	hermon_cmd_unmap_fa ( hermon );
-	ufree ( hermon->firmware_area );
-	hermon->firmware_area = UNULL;
- err_alloc_fa:
- err_query_fw:
-	return rc;
+/**
+ * Handle Hermon Infiniband device port state change
+ *
+ * @v hermon		Hermon device
+ * @v port		Hermon port
+ * @v link_up		Link is up
+ */
+static void hermon_state_change_ibdev ( struct hermon *hermon __unused,
+					struct hermon_port *port,
+					int link_up __unused ) {
+	struct ib_device *ibdev = port->ibdev;
+
+	/* Update MAD parameters */
+	ib_smc_update ( ibdev, hermon_mad );
 }
 
 /**
- * Stop firmware running
+ * Unregister Hermon Infiniband device
  *
  * @v hermon		Hermon device
+ * @v port		Hermon port
  */
-static void hermon_stop_firmware ( struct hermon *hermon ) {
-	int rc;
+static void hermon_unregister_ibdev ( struct hermon *hermon __unused,
+				      struct hermon_port *port ) {
+	struct ib_device *ibdev = port->ibdev;
 
-	if ( ( rc = hermon_cmd_unmap_fa ( hermon ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p FATAL could not stop firmware: %s\n",
-		       hermon, strerror ( rc ) );
-		/* Leak memory and return; at least we avoid corruption */
-		return;
-	}
-	ufree ( hermon->firmware_area );
-	hermon->firmware_area = UNULL;
+	unregister_ibdev ( ibdev );
 }
 
+/** Hermon Infiniband port type */
+static struct hermon_port_type hermon_port_type_ib = {
+	.register_dev = hermon_register_ibdev,
+	.state_change = hermon_state_change_ibdev,
+	.unregister_dev = hermon_unregister_ibdev,
+};
+
 /***************************************************************************
  *
- * Infinihost Context Memory management
+ * Ethernet operation
  *
  ***************************************************************************
  */
 
+/** Number of Hermon Ethernet send work queue entries */
+#define HERMON_ETH_NUM_SEND_WQES 2
+
+/** Number of Hermon Ethernet receive work queue entries */
+#define HERMON_ETH_NUM_RECV_WQES 4
+
+/** Number of Hermon Ethernet completion entries */
+#define HERMON_ETH_NUM_CQES 8
+
 /**
- * Get device limits
+ * Transmit packet via Hermon Ethernet device
  *
- * @v hermon		Hermon device
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
  * @ret rc		Return status code
  */
-static int hermon_get_cap ( struct hermon *hermon ) {
-	struct hermonprm_query_dev_cap dev_cap;
+static int hermon_eth_transmit ( struct net_device *netdev,
+				 struct io_buffer *iobuf ) {
+	struct hermon_port *port = netdev->priv;
+	struct ib_device *ibdev = port->ibdev;
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
 	int rc;
 
-	if ( ( rc = hermon_cmd_query_dev_cap ( hermon, &dev_cap ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p could not get device limits: %s\n",
-		       hermon, strerror ( rc ) );
+	/* Transmit packet */
+	if ( ( rc = ib_post_send ( ibdev, port->eth_qp, NULL,
+				   iobuf ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not transmit: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
 		return rc;
 	}
 
-	hermon->cap.cmpt_entry_size = MLX_GET ( &dev_cap, c_mpt_entry_sz );
-	hermon->cap.reserved_qps =
-		( 1 << MLX_GET ( &dev_cap, log2_rsvd_qps ) );
-	hermon->cap.qpc_entry_size = MLX_GET ( &dev_cap, qpc_entry_sz );
-	hermon->cap.altc_entry_size = MLX_GET ( &dev_cap, altc_entry_sz );
-	hermon->cap.auxc_entry_size = MLX_GET ( &dev_cap, aux_entry_sz );
-	hermon->cap.reserved_srqs =
-		( 1 << MLX_GET ( &dev_cap, log2_rsvd_srqs ) );
-	hermon->cap.srqc_entry_size = MLX_GET ( &dev_cap, srq_entry_sz );
-	hermon->cap.reserved_cqs =
-		( 1 << MLX_GET ( &dev_cap, log2_rsvd_cqs ) );
-	hermon->cap.cqc_entry_size = MLX_GET ( &dev_cap, cqc_entry_sz );
-	hermon->cap.reserved_eqs = MLX_GET ( &dev_cap, num_rsvd_eqs );
-	if ( hermon->cap.reserved_eqs == 0 ) {
-		/* Backward compatibility */
-		hermon->cap.reserved_eqs =
-			( 1 << MLX_GET ( &dev_cap, log2_rsvd_eqs ) );
-	}
-	hermon->cap.eqc_entry_size = MLX_GET ( &dev_cap, eqc_entry_sz );
-	hermon->cap.reserved_mtts =
-		( 1 << MLX_GET ( &dev_cap, log2_rsvd_mtts ) );
-	hermon->cap.mtt_entry_size = MLX_GET ( &dev_cap, mtt_entry_sz );
-	hermon->cap.reserved_mrws =
-		( 1 << MLX_GET ( &dev_cap, log2_rsvd_mrws ) );
-	hermon->cap.dmpt_entry_size = MLX_GET ( &dev_cap, d_mpt_entry_sz );
-	hermon->cap.reserved_uars = MLX_GET ( &dev_cap, num_rsvd_uars );
-	hermon->cap.num_ports = MLX_GET ( &dev_cap, num_ports );
-	hermon->cap.dpdp = MLX_GET ( &dev_cap, dpdp );
-
-	/* Sanity check */
-	if ( hermon->cap.num_ports > HERMON_MAX_PORTS ) {
-		DBGC ( hermon, "Hermon %p has %d ports (only %d supported)\n",
-		       hermon, hermon->cap.num_ports, HERMON_MAX_PORTS );
-		hermon->cap.num_ports = HERMON_MAX_PORTS;
-	}
-
 	return 0;
 }
 
+/** Hermon Ethernet queue pair operations */
+static struct ib_queue_pair_operations hermon_eth_qp_op = {
+	.alloc_iob = alloc_iob,
+};
+
 /**
- * Align ICM table
+ * Handle Hermon Ethernet device send completion
  *
- * @v icm_offset	Current ICM offset
- * @v len		ICM table length
- * @ret icm_offset	ICM offset
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v iobuf		I/O buffer
+ * @v rc		Completion status code
  */
-static uint64_t icm_align ( uint64_t icm_offset, size_t len ) {
+static void hermon_eth_complete_send ( struct ib_device *ibdev __unused,
+				       struct ib_queue_pair *qp,
+				       struct io_buffer *iobuf, int rc ) {
+	struct net_device *netdev = ib_qp_get_ownerdata ( qp );
 
-	/* Round up to a multiple of the table size */
-	assert ( len == ( 1UL << ( fls ( len ) - 1 ) ) );
-	return ( ( icm_offset + len - 1 ) & ~( ( ( uint64_t ) len ) - 1 ) );
+	netdev_tx_complete_err ( netdev, iobuf, rc );
 }
 
 /**
- * Allocate ICM
+ * Handle Hermon Ethernet device receive completion
  *
- * @v hermon		Hermon device
- * @v init_hca		INIT_HCA structure to fill in
- * @ret rc		Return status code
+ * @v ibdev		Infiniband device
+ * @v qp		Queue pair
+ * @v dest		Destination address vector, or NULL
+ * @v source		Source address vector, or NULL
+ * @v iobuf		I/O buffer
+ * @v rc		Completion status code
  */
-static int hermon_alloc_icm ( struct hermon *hermon,
-			      struct hermonprm_init_hca *init_hca ) {
-	struct hermonprm_scalar_parameter icm_size;
-	struct hermonprm_scalar_parameter icm_aux_size;
-	uint64_t icm_offset = 0;
-	unsigned int log_num_qps, log_num_srqs, log_num_cqs, log_num_eqs;
-	unsigned int log_num_mtts, log_num_mpts, log_num_mcs;
-	size_t cmpt_max_len;
-	size_t icm_len, icm_aux_len;
-	size_t len;
-	physaddr_t icm_phys;
-	int i;
-	int rc;
+static void hermon_eth_complete_recv ( struct ib_device *ibdev __unused,
+				       struct ib_queue_pair *qp,
+				       struct ib_address_vector *dest __unused,
+				       struct ib_address_vector *source,
+				       struct io_buffer *iobuf, int rc ) {
+	struct net_device *netdev = ib_qp_get_ownerdata ( qp );
+	struct net_device *vlan;
 
-	/*
-	 * Start by carving up the ICM virtual address space
-	 *
-	 */
+	/* Find VLAN device, if applicable */
+	if ( source->vlan_present ) {
+		if ( ( vlan = vlan_find ( netdev, source->vlan ) ) != NULL ) {
+			netdev = vlan;
+		} else if ( rc == 0 ) {
+			rc = -ENODEV;
+		}
+	}
 
-	/* Calculate number of each object type within ICM */
-	log_num_qps = fls ( hermon->cap.reserved_qps +
-			    HERMON_RSVD_SPECIAL_QPS + HERMON_MAX_QPS - 1 );
-	log_num_srqs = fls ( hermon->cap.reserved_srqs - 1 );
-	log_num_cqs = fls ( hermon->cap.reserved_cqs + HERMON_MAX_CQS - 1 );
-	log_num_eqs = fls ( hermon->cap.reserved_eqs + HERMON_MAX_EQS - 1 );
-	log_num_mtts = fls ( hermon->cap.reserved_mtts + HERMON_MAX_MTTS - 1 );
-	log_num_mpts = fls ( hermon->cap.reserved_mrws + 1 - 1 );
-	log_num_mcs = HERMON_LOG_MULTICAST_HASH_SIZE;
+	/* Hand off to network layer */
+	if ( rc == 0 ) {
+		netdev_rx ( netdev, iobuf );
+	} else {
+		netdev_rx_err ( netdev, iobuf, rc );
+	}
+}
 
-	/* ICM starts with the cMPT tables, which are sparse */
-	cmpt_max_len = ( HERMON_CMPT_MAX_ENTRIES *
-			 ( ( uint64_t ) hermon->cap.cmpt_entry_size ) );
-	len = ( ( ( ( 1 << log_num_qps ) * hermon->cap.cmpt_entry_size ) +
-		  HERMON_PAGE_SIZE - 1 ) & ~( HERMON_PAGE_SIZE - 1 ) );
-	hermon->icm_map[HERMON_ICM_QP_CMPT].offset = icm_offset;
-	hermon->icm_map[HERMON_ICM_QP_CMPT].len = len;
-	icm_offset += cmpt_max_len;
-	len = ( ( ( ( 1 << log_num_srqs ) * hermon->cap.cmpt_entry_size ) +
-		  HERMON_PAGE_SIZE - 1 ) & ~( HERMON_PAGE_SIZE - 1 ) );
-	hermon->icm_map[HERMON_ICM_SRQ_CMPT].offset = icm_offset;
-	hermon->icm_map[HERMON_ICM_SRQ_CMPT].len = len;
-	icm_offset += cmpt_max_len;
-	len = ( ( ( ( 1 << log_num_cqs ) * hermon->cap.cmpt_entry_size ) +
-		  HERMON_PAGE_SIZE - 1 ) & ~( HERMON_PAGE_SIZE - 1 ) );
-	hermon->icm_map[HERMON_ICM_CQ_CMPT].offset = icm_offset;
-	hermon->icm_map[HERMON_ICM_CQ_CMPT].len = len;
-	icm_offset += cmpt_max_len;
-	len = ( ( ( ( 1 << log_num_eqs ) * hermon->cap.cmpt_entry_size ) +
-		  HERMON_PAGE_SIZE - 1 ) & ~( HERMON_PAGE_SIZE - 1 ) );
-	hermon->icm_map[HERMON_ICM_EQ_CMPT].offset = icm_offset;
-	hermon->icm_map[HERMON_ICM_EQ_CMPT].len = len;
-	icm_offset += cmpt_max_len;
+/** Hermon Ethernet device completion operations */
+static struct ib_completion_queue_operations hermon_eth_cq_op = {
+	.complete_send = hermon_eth_complete_send,
+	.complete_recv = hermon_eth_complete_recv,
+};
 
-	hermon->icm_map[HERMON_ICM_OTHER].offset = icm_offset;
+/**
+ * Poll Hermon Ethernet device
+ *
+ * @v netdev		Network device
+ */
+static void hermon_eth_poll ( struct net_device *netdev ) {
+	struct hermon_port *port = netdev->priv;
+	struct ib_device *ibdev = port->ibdev;
 
-	/* Queue pair contexts */
-	len = ( ( 1 << log_num_qps ) * hermon->cap.qpc_entry_size );
-	icm_offset = icm_align ( icm_offset, len );
-	MLX_FILL_1 ( init_hca, 12,
-		     qpc_eec_cqc_eqc_rdb_parameters.qpc_base_addr_h,
-		     ( icm_offset >> 32 ) );
-	MLX_FILL_2 ( init_hca, 13,
-		     qpc_eec_cqc_eqc_rdb_parameters.qpc_base_addr_l,
-		     ( icm_offset >> 5 ),
-		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_qp,
-		     log_num_qps );
-	DBGC ( hermon, "Hermon %p ICM QPC is %d x %#zx at [%08llx,%08llx)\n",
-	       hermon, ( 1 << log_num_qps ), hermon->cap.qpc_entry_size,
-	       icm_offset, ( icm_offset + len ) );
-	icm_offset += len;
+	ib_poll_eq ( ibdev );
+}
 
-	/* Extended alternate path contexts */
-	len = ( ( 1 << log_num_qps ) * hermon->cap.altc_entry_size );
-	icm_offset = icm_align ( icm_offset, len );
-	MLX_FILL_1 ( init_hca, 24,
-		     qpc_eec_cqc_eqc_rdb_parameters.altc_base_addr_h,
-		     ( icm_offset >> 32 ) );
-	MLX_FILL_1 ( init_hca, 25,
-		     qpc_eec_cqc_eqc_rdb_parameters.altc_base_addr_l,
-		     icm_offset );
-	DBGC ( hermon, "Hermon %p ICM ALTC is %d x %#zx at [%08llx,%08llx)\n",
-	       hermon, ( 1 << log_num_qps ), hermon->cap.altc_entry_size,
-	       icm_offset, ( icm_offset + len ) );
-	icm_offset += len;
+/**
+ * Open Hermon Ethernet device
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int hermon_eth_open ( struct net_device *netdev ) {
+	struct hermon_port *port = netdev->priv;
+	struct ib_device *ibdev = port->ibdev;
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	union hermonprm_set_port set_port;
+	int rc;
 
-	/* Extended auxiliary contexts */
-	len = ( ( 1 << log_num_qps ) * hermon->cap.auxc_entry_size );
-	icm_offset = icm_align ( icm_offset, len );
-	MLX_FILL_1 ( init_hca, 28,
-		     qpc_eec_cqc_eqc_rdb_parameters.auxc_base_addr_h,
-		     ( icm_offset >> 32 ) );
-	MLX_FILL_1 ( init_hca, 29,
-		     qpc_eec_cqc_eqc_rdb_parameters.auxc_base_addr_l,
-		     icm_offset );
-	DBGC ( hermon, "Hermon %p ICM AUXC is %d x %#zx at [%08llx,%08llx)\n",
-	       hermon, ( 1 << log_num_qps ), hermon->cap.auxc_entry_size,
-	       icm_offset, ( icm_offset + len ) );
-	icm_offset += len;
+	/* Open hardware */
+	if ( ( rc = hermon_open ( hermon ) ) != 0 )
+		goto err_open;
 
-	/* Shared receive queue contexts */
-	len = ( ( 1 << log_num_srqs ) * hermon->cap.srqc_entry_size );
-	icm_offset = icm_align ( icm_offset, len );
-	MLX_FILL_1 ( init_hca, 18,
-		     qpc_eec_cqc_eqc_rdb_parameters.srqc_base_addr_h,
-		     ( icm_offset >> 32 ) );
-	MLX_FILL_2 ( init_hca, 19,
-		     qpc_eec_cqc_eqc_rdb_parameters.srqc_base_addr_l,
-		     ( icm_offset >> 5 ),
-		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_srq,
-		     log_num_srqs );
-	DBGC ( hermon, "Hermon %p ICM SRQC is %d x %#zx at [%08llx,%08llx)\n",
-	       hermon, ( 1 << log_num_srqs ), hermon->cap.srqc_entry_size,
-	       icm_offset, ( icm_offset + len ) );
-	icm_offset += len;
+	/* Allocate completion queue */
+	port->eth_cq = ib_create_cq ( ibdev, HERMON_ETH_NUM_CQES,
+				      &hermon_eth_cq_op );
+	if ( ! port->eth_cq ) {
+		DBGC ( hermon, "Hermon %p port %d could not create completion "
+		       "queue\n", hermon, ibdev->port );
+		rc = -ENOMEM;
+		goto err_create_cq;
+	}
 
-	/* Completion queue contexts */
-	len = ( ( 1 << log_num_cqs ) * hermon->cap.cqc_entry_size );
-	icm_offset = icm_align ( icm_offset, len );
-	MLX_FILL_1 ( init_hca, 20,
-		     qpc_eec_cqc_eqc_rdb_parameters.cqc_base_addr_h,
-		     ( icm_offset >> 32 ) );
-	MLX_FILL_2 ( init_hca, 21,
-		     qpc_eec_cqc_eqc_rdb_parameters.cqc_base_addr_l,
-		     ( icm_offset >> 5 ),
-		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_cq,
-		     log_num_cqs );
-	DBGC ( hermon, "Hermon %p ICM CQC is %d x %#zx at [%08llx,%08llx)\n",
-	       hermon, ( 1 << log_num_cqs ), hermon->cap.cqc_entry_size,
-	       icm_offset, ( icm_offset + len ) );
-	icm_offset += len;
+	/* Allocate queue pair */
+	port->eth_qp = ib_create_qp ( ibdev, IB_QPT_ETH,
+				      HERMON_ETH_NUM_SEND_WQES, port->eth_cq,
+				      HERMON_ETH_NUM_RECV_WQES, port->eth_cq,
+				      &hermon_eth_qp_op );
+	if ( ! port->eth_qp ) {
+		DBGC ( hermon, "Hermon %p port %d could not create queue "
+		       "pair\n", hermon, ibdev->port );
+		rc = -ENOMEM;
+		goto err_create_qp;
+	}
+	ib_qp_set_ownerdata ( port->eth_qp, netdev );
 
-	/* Event queue contexts */
-	len = ( ( 1 << log_num_eqs ) * hermon->cap.eqc_entry_size );
-	icm_offset = icm_align ( icm_offset, len );
-	MLX_FILL_1 ( init_hca, 32,
-		     qpc_eec_cqc_eqc_rdb_parameters.eqc_base_addr_h,
-		     ( icm_offset >> 32 ) );
-	MLX_FILL_2 ( init_hca, 33,
-		     qpc_eec_cqc_eqc_rdb_parameters.eqc_base_addr_l,
-		     ( icm_offset >> 5 ),
-		     qpc_eec_cqc_eqc_rdb_parameters.log_num_of_eq,
-		     log_num_eqs );
-	DBGC ( hermon, "Hermon %p ICM EQC is %d x %#zx at [%08llx,%08llx)\n",
-	       hermon, ( 1 << log_num_eqs ), hermon->cap.eqc_entry_size,
-	       icm_offset, ( icm_offset + len ) );
-	icm_offset += len;
+	/* Activate queue pair */
+	if ( ( rc = ib_modify_qp ( ibdev, port->eth_qp ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not modify queue "
+		       "pair: %s\n", hermon, ibdev->port, strerror ( rc ) );
+		goto err_modify_qp;
+	}
 
-	/* Memory translation table */
-	len = ( ( 1 << log_num_mtts ) * hermon->cap.mtt_entry_size );
-	icm_offset = icm_align ( icm_offset, len );
-	MLX_FILL_1 ( init_hca, 64,
-		     tpt_parameters.mtt_base_addr_h, ( icm_offset >> 32 ) );
-	MLX_FILL_1 ( init_hca, 65,
-		     tpt_parameters.mtt_base_addr_l, icm_offset );
-	DBGC ( hermon, "Hermon %p ICM MTT is %d x %#zx at [%08llx,%08llx)\n",
-	       hermon, ( 1 << log_num_mtts ), hermon->cap.mtt_entry_size,
-	       icm_offset, ( icm_offset + len ) );
-	icm_offset += len;
+	/* Fill receive rings */
+	ib_refill_recv ( ibdev, port->eth_qp );
 
-	/* Memory protection table */
-	len = ( ( 1 << log_num_mpts ) * hermon->cap.dmpt_entry_size );
-	icm_offset = icm_align ( icm_offset, len );
-	MLX_FILL_1 ( init_hca, 60,
-		     tpt_parameters.dmpt_base_adr_h, ( icm_offset >> 32 ) );
-	MLX_FILL_1 ( init_hca, 61,
-		     tpt_parameters.dmpt_base_adr_l, icm_offset );
-	MLX_FILL_1 ( init_hca, 62,
-		     tpt_parameters.log_dmpt_sz, log_num_mpts );
-	DBGC ( hermon, "Hermon %p ICM DMPT is %d x %#zx at [%08llx,%08llx)\n",
-	       hermon, ( 1 << log_num_mpts ), hermon->cap.dmpt_entry_size,
-	       icm_offset, ( icm_offset + len ) );
-	icm_offset += len;
+	/* Set port general parameters */
+	memset ( &set_port, 0, sizeof ( set_port ) );
+	MLX_FILL_3 ( &set_port.general, 0,
+		     v_mtu, 1,
+		     v_pprx, 1,
+		     v_pptx, 1 );
+	MLX_FILL_1 ( &set_port.general, 1,
+		     mtu, ( ETH_FRAME_LEN + 40 /* Used by card */ ) );
+	MLX_FILL_1 ( &set_port.general, 2,
+		     pfctx, ( 1 << FCOE_VLAN_PRIORITY ) );
+	MLX_FILL_1 ( &set_port.general, 3,
+		     pfcrx, ( 1 << FCOE_VLAN_PRIORITY ) );
+	if ( ( rc = hermon_cmd_set_port ( hermon, 1,
+					  ( HERMON_SET_PORT_GENERAL_PARAM |
+					    ibdev->port ),
+					  &set_port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not set port general "
+		       "parameters: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
+		goto err_set_port_general_params;
+	}
 
-	/* Multicast table */
-	len = ( ( 1 << log_num_mcs ) * sizeof ( struct hermonprm_mcg_entry ) );
-	icm_offset = icm_align ( icm_offset, len );
-	MLX_FILL_1 ( init_hca, 48,
-		     multicast_parameters.mc_base_addr_h,
-		     ( icm_offset >> 32 ) );
-	MLX_FILL_1 ( init_hca, 49,
-		     multicast_parameters.mc_base_addr_l, icm_offset );
-	MLX_FILL_1 ( init_hca, 52,
-		     multicast_parameters.log_mc_table_entry_sz,
-		     fls ( sizeof ( struct hermonprm_mcg_entry ) - 1 ) );
-	MLX_FILL_1 ( init_hca, 53,
-		     multicast_parameters.log_mc_table_hash_sz, log_num_mcs );
-	MLX_FILL_1 ( init_hca, 54,
-		     multicast_parameters.log_mc_table_sz, log_num_mcs );
-	DBGC ( hermon, "Hermon %p ICM MC is %d x %#zx at [%08llx,%08llx)\n",
-	       hermon, ( 1 << log_num_mcs ),
-	       sizeof ( struct hermonprm_mcg_entry ),
-	       icm_offset, ( icm_offset + len ) );
-	icm_offset += len;
+	/* Set port receive QP */
+	memset ( &set_port, 0, sizeof ( set_port ) );
+	MLX_FILL_1 ( &set_port.rqp_calc, 0, base_qpn, port->eth_qp->qpn );
+	MLX_FILL_1 ( &set_port.rqp_calc, 2,
+		     mac_miss_index, 128 /* MAC misses go to promisc QP */ );
+	MLX_FILL_2 ( &set_port.rqp_calc, 3,
+		     vlan_miss_index, 127 /* VLAN misses go to promisc QP */,
+		     no_vlan_index, 126 /* VLAN-free go to promisc QP */ );
+	MLX_FILL_2 ( &set_port.rqp_calc, 5,
+		     promisc_qpn, port->eth_qp->qpn,
+		     en_uc_promisc, 1 );
+	MLX_FILL_2 ( &set_port.rqp_calc, 6,
+		     def_mcast_qpn, port->eth_qp->qpn,
+		     mc_promisc_mode, 2 /* Receive all multicasts */ );
+	if ( ( rc = hermon_cmd_set_port ( hermon, 1,
+					  ( HERMON_SET_PORT_RECEIVE_QP |
+					    ibdev->port ),
+					  &set_port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not set port receive "
+		       "QP: %s\n", hermon, ibdev->port, strerror ( rc ) );
+		goto err_set_port_receive_qp;
+	}
 
+	/* Initialise port */
+	if ( ( rc = hermon_cmd_init_port ( hermon, ibdev->port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not initialise port: "
+		       "%s\n", hermon, ibdev->port, strerror ( rc ) );
+		goto err_init_port;
+	}
 
-	hermon->icm_map[HERMON_ICM_OTHER].len =
-		( icm_offset - hermon->icm_map[HERMON_ICM_OTHER].offset );
+	return 0;
 
-	/*
-	 * Allocate and map physical memory for (portions of) ICM
-	 *
-	 * Map is:
-	 *   ICM AUX area (aligned to its own size)
-	 *   cMPT areas
-	 *   Other areas
-	 */
+ err_init_port:
+ err_set_port_receive_qp:
+ err_set_port_general_params:
+ err_modify_qp:
+	ib_destroy_qp ( ibdev, port->eth_qp );
+ err_create_qp:
+	ib_destroy_cq ( ibdev, port->eth_cq );
+ err_create_cq:
+	hermon_close ( hermon );
+ err_open:
+	return rc;
+}
 
-	/* Calculate physical memory required for ICM */
-	icm_len = 0;
-	for ( i = 0 ; i < HERMON_ICM_NUM_REGIONS ; i++ ) {
-		icm_len += hermon->icm_map[i].len;
+/**
+ * Close Hermon Ethernet device
+ *
+ * @v netdev		Network device
+ */
+static void hermon_eth_close ( struct net_device *netdev ) {
+	struct hermon_port *port = netdev->priv;
+	struct ib_device *ibdev = port->ibdev;
+	struct hermon *hermon = ib_get_drvdata ( ibdev );
+	int rc;
+
+	/* Close port */
+	if ( ( rc = hermon_cmd_close_port ( hermon, ibdev->port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not close port: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
+		/* Nothing we can do about this */
 	}
 
-	/* Get ICM auxiliary area size */
-	memset ( &icm_size, 0, sizeof ( icm_size ) );
-	MLX_FILL_1 ( &icm_size, 0, value_hi, ( icm_offset >> 32 ) );
-	MLX_FILL_1 ( &icm_size, 1, value, icm_offset );
-	if ( ( rc = hermon_cmd_set_icm_size ( hermon, &icm_size,
-					      &icm_aux_size ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p could not set ICM size: %s\n",
-		       hermon, strerror ( rc ) );
-		goto err_set_icm_size;
+	/* Tear down the queues */
+	ib_destroy_qp ( ibdev, port->eth_qp );
+	ib_destroy_cq ( ibdev, port->eth_cq );
+
+	/* Close hardware */
+	hermon_close ( hermon );
+}
+
+/** Hermon Ethernet network device operations */
+static struct net_device_operations hermon_eth_operations = {
+	.open		= hermon_eth_open,
+	.close		= hermon_eth_close,
+	.transmit	= hermon_eth_transmit,
+	.poll		= hermon_eth_poll,
+};
+
+/**
+ * Register Hermon Ethernet device
+ *
+ * @v hermon		Hermon device
+ * @v port		Hermon port
+ * @ret rc		Return status code
+ */
+static int hermon_register_netdev ( struct hermon *hermon,
+				    struct hermon_port *port ) {
+	struct net_device *netdev = port->netdev;
+	struct ib_device *ibdev = port->ibdev;
+	struct hermonprm_query_port_cap query_port;
+	union {
+		uint8_t bytes[8];
+		uint32_t dwords[2];
+	} mac;
+	int rc;
+
+	/* Retrieve MAC address */
+	if ( ( rc = hermon_cmd_query_port ( hermon, ibdev->port,
+					    &query_port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not query port: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
+		goto err_query_port;
 	}
-	icm_aux_len = ( MLX_GET ( &icm_aux_size, value ) * HERMON_PAGE_SIZE );
+	mac.dwords[0] = htonl ( MLX_GET ( &query_port, mac_47_32 ) );
+	mac.dwords[1] = htonl ( MLX_GET ( &query_port, mac_31_0 ) );
+	memcpy ( netdev->hw_addr,
+		 &mac.bytes[ sizeof ( mac.bytes ) - ETH_ALEN ], ETH_ALEN );
 
-	/* Allocate ICM data and auxiliary area */
-	DBGC ( hermon, "Hermon %p requires %zd kB ICM and %zd kB AUX ICM\n",
-	       hermon, ( icm_len / 1024 ), ( icm_aux_len / 1024 ) );
-	hermon->icm = umalloc ( icm_aux_len + icm_len );
-	if ( ! hermon->icm ) {
-		rc = -ENOMEM;
-		goto err_alloc;
+	/* Register network device */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not register network "
+		       "device: %s\n", hermon, ibdev->port, strerror ( rc ) );
+		goto err_register_netdev;
 	}
-	icm_phys = user_to_phys ( hermon->icm, 0 );
 
-	/* Map ICM auxiliary area */
-	DBGC ( hermon, "Hermon %p mapping ICM AUX => %08lx\n",
-	       hermon, icm_phys );
-	if ( ( rc = hermon_map_vpm ( hermon, hermon_cmd_map_icm_aux,
-				     0, icm_phys, icm_aux_len ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p could not map AUX ICM: %s\n",
-		       hermon, strerror ( rc ) );		
-		goto err_map_icm_aux;
+	/* Register non-volatile options */
+	if ( ( rc = register_nvo ( &port->nvo,
+				   netdev_settings ( netdev ) ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not register non-"
+		       "volatile options: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
+		goto err_register_nvo;
 	}
-	icm_phys += icm_aux_len;
 
-	/* MAP ICM area */
-	for ( i = 0 ; i < HERMON_ICM_NUM_REGIONS ; i++ ) {
-		DBGC ( hermon, "Hermon %p mapping ICM %llx+%zx => %08lx\n",
-		       hermon, hermon->icm_map[i].offset,
-		       hermon->icm_map[i].len, icm_phys );
-		if ( ( rc = hermon_map_vpm ( hermon, hermon_cmd_map_icm,
-					     hermon->icm_map[i].offset,
-					     icm_phys,
-					     hermon->icm_map[i].len ) ) != 0 ){
-			DBGC ( hermon, "Hermon %p could not map ICM: %s\n",
-			       hermon, strerror ( rc ) );
-			goto err_map_icm;
-		}
-		icm_phys += hermon->icm_map[i].len;
+	return 0;
+
+	unregister_nvo ( &port->nvo );
+ err_register_nvo:
+	unregister_netdev ( netdev );
+ err_register_netdev:
+ err_query_port:
+	return rc;
+}
+
+/**
+ * Handle Hermon Ethernet device port state change
+ *
+ * @v hermon		Hermon device
+ * @v port		Hermon port
+ * @v link_up		Link is up
+ */
+static void hermon_state_change_netdev ( struct hermon *hermon __unused,
+					 struct hermon_port *port,
+					 int link_up ) {
+	struct net_device *netdev = port->netdev;
+
+	if ( link_up ) {
+		netdev_link_up ( netdev );
+	} else {
+		netdev_link_down ( netdev );
+	}
+}
+
+/**
+ * Unregister Hermon Ethernet device
+ *
+ * @v hermon		Hermon device
+ * @v port		Hermon port
+ */
+static void hermon_unregister_netdev ( struct hermon *hermon __unused,
+				       struct hermon_port *port ) {
+	struct net_device *netdev = port->netdev;
+
+	unregister_nvo ( &port->nvo );
+	unregister_netdev ( netdev );
+}
+
+/** Hermon Ethernet port type */
+static struct hermon_port_type hermon_port_type_eth = {
+	.register_dev = hermon_register_netdev,
+	.state_change = hermon_state_change_netdev,
+	.unregister_dev = hermon_unregister_netdev,
+};
+
+/***************************************************************************
+ *
+ * Port type detection
+ *
+ ***************************************************************************
+ */
+
+/** Timeout for port sensing */
+#define HERMON_SENSE_PORT_TIMEOUT ( TICKS_PER_SEC / 2 )
+
+/**
+ * Name port type
+ *
+ * @v port_type		Port type
+ * @v port_type_name	Port type name
+ */
+static inline const char * hermon_name_port_type ( unsigned int port_type ) {
+	switch ( port_type ) {
+	case HERMON_PORT_TYPE_UNKNOWN:	return "unknown";
+	case HERMON_PORT_TYPE_IB:	return "Infiniband";
+	case HERMON_PORT_TYPE_ETH:	return "Ethernet";
+	default:			return "INVALID";
+	}
+}
+
+/**
+ * Sense port type
+ *
+ * @v hermon		Hermon device
+ * @v port		Hermon port
+ * @ret port_type	Port type, or negative error
+ */
+static int hermon_sense_port_type ( struct hermon *hermon,
+				    struct hermon_port *port ) {
+	struct ib_device *ibdev = port->ibdev;
+	struct hermonprm_sense_port sense_port;
+	int port_type;
+	int rc;
+
+	/* If DPDP is not supported, always assume Infiniband */
+	if ( ! hermon->cap.dpdp ) {
+		port_type = HERMON_PORT_TYPE_IB;
+		DBGC ( hermon, "Hermon %p port %d does not support DPDP; "
+		       "assuming an %s network\n", hermon, ibdev->port,
+		       hermon_name_port_type ( port_type ) );
+		return port_type;
 	}
 
-	return 0;
+	/* Sense the port type */
+	if ( ( rc = hermon_cmd_sense_port ( hermon, ibdev->port,
+					    &sense_port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d sense failed: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
+		return rc;
+	}
+	port_type = MLX_GET ( &sense_port, port_type );
 
- err_map_icm:
-	assert ( i == 0 ); /* We don't handle partial failure at present */
- err_map_icm_aux:
-	hermon_cmd_unmap_icm_aux ( hermon );
-	ufree ( hermon->icm );
-	hermon->icm = UNULL;
- err_alloc:
- err_set_icm_size:
-	return rc;
+	DBGC ( hermon, "Hermon %p port %d sensed an %s network\n",
+	       hermon, ibdev->port, hermon_name_port_type ( port_type ) );
+	return port_type;
 }
 
 /**
- * Free ICM
+ * Set port type
  *
  * @v hermon		Hermon device
+ * @v port		Hermon port
+ * @ret rc		Return status code
  */
-static void hermon_free_icm ( struct hermon *hermon ) {
-	struct hermonprm_scalar_parameter unmap_icm;
-	int i;
+static int hermon_set_port_type ( struct hermon *hermon,
+				  struct hermon_port *port ) {
+	struct ib_device *ibdev = port->ibdev;
+	struct hermonprm_query_port_cap query_port;
+	int ib_supported;
+	int eth_supported;
+	int port_type;
+	unsigned long start;
+	unsigned long elapsed;
+	int rc;
 
-	for ( i = ( HERMON_ICM_NUM_REGIONS - 1 ) ; i >= 0 ; i-- ) {
-		memset ( &unmap_icm, 0, sizeof ( unmap_icm ) );
-		MLX_FILL_1 ( &unmap_icm, 0, value_hi,
-			     ( hermon->icm_map[i].offset >> 32 ) );
-		MLX_FILL_1 ( &unmap_icm, 1, value,
-			     hermon->icm_map[i].offset );
-		hermon_cmd_unmap_icm ( hermon,
-				       ( 1 << fls ( ( hermon->icm_map[i].len /
-						      HERMON_PAGE_SIZE ) - 1)),
-				       &unmap_icm );
+	/* Check to see which types are supported */
+	if ( ( rc = hermon_cmd_query_port ( hermon, ibdev->port,
+					    &query_port ) ) != 0 ) {
+		DBGC ( hermon, "Hermon %p port %d could not query port: %s\n",
+		       hermon, ibdev->port, strerror ( rc ) );
+		return rc;
 	}
-	hermon_cmd_unmap_icm_aux ( hermon );
-	ufree ( hermon->icm );
-	hermon->icm = UNULL;
+	ib_supported = MLX_GET ( &query_port, ib );
+	eth_supported = MLX_GET ( &query_port, eth );
+	DBGC ( hermon, "Hermon %p port %d supports%s%s%s\n",
+	       hermon, ibdev->port, ( ib_supported ? " Infiniband" : "" ),
+	       ( ( ib_supported && eth_supported ) ? " and" : "" ),
+	       ( eth_supported ? " Ethernet" : "" ) );
+
+	/* Sense network, if applicable */
+	if ( ib_supported && eth_supported ) {
+
+		/* Both types are supported; try sensing network */
+		start = currticks();
+		do {
+			/* Try sensing port */
+			port_type = hermon_sense_port_type ( hermon, port );
+			if ( port_type < 0 ) {
+				rc = port_type;
+				return rc;
+			}
+		} while ( ( port_type == HERMON_PORT_TYPE_UNKNOWN ) &&
+			  ( ( elapsed = ( currticks() - start ) ) <
+			    HERMON_SENSE_PORT_TIMEOUT ) );
+
+		/* Set port type based on sensed network, defaulting
+		 * to Infiniband if nothing was sensed.
+		 */
+		switch ( port_type ) {
+		case HERMON_PORT_TYPE_ETH:
+			port->type = &hermon_port_type_eth;
+			break;
+		case HERMON_PORT_TYPE_IB:
+		case HERMON_PORT_TYPE_UNKNOWN:
+			port->type = &hermon_port_type_ib;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+	} else if ( eth_supported ) {
+		port->type = &hermon_port_type_eth;
+	} else {
+		port->type = &hermon_port_type_ib;
+	}
+
+	assert ( port->type != NULL );
+	return 0;
 }
 
 /***************************************************************************
@@ -3382,56 +3655,32 @@ static int hermon_bofm_update ( struct bofm_device *bofm, unsigned int mport,
 	union {
 		uint8_t bytes[8];
 		uint32_t dwords[2];
-		uint64_t qword;
 	} buf;
-	uint8_t *mac_copy = &buf.bytes[ sizeof ( buf.bytes ) - ETH_ALEN ];
 	int rc;
 
 	/* Prepare MAC address */
 	memset ( &buf, 0, sizeof ( buf ) );
-	memcpy ( mac_copy, mac, ETH_ALEN );
+	memcpy ( &buf.bytes[ sizeof ( buf.bytes ) - ETH_ALEN ], mac,
+		 ETH_ALEN );
 
-	/* Current BOFM versions are unable to create entries with
-	 * mport>1, which means that only the port 1 MAC address can
-	 * be explicitly specified.  Work around this by using the
-	 * provided MAC address as a base address for all subsequent
-	 * ports.  For example, if BOFM assigns the address
-	 *
-	 *    00:1A:64:76:00:09 for port 1
-	 *
-	 * then we will assign the addresses
-	 *
-	 *    00:1A:64:76:00:09 for port 1
-	 *    00:1A:64:76:00:0a for port 2
-	 *
-	 * Note that hermon->cap.num_ports is not yet defined at this
-	 * point.
-	 */
-	for ( ; mport <= HERMON_MAX_PORTS ; mport++ ) {
-
-		/* Modify static configuration */
-		memset ( &stat_cfg, 0, sizeof ( stat_cfg ) );
-		MLX_FILL_2 ( &stat_cfg, 36,
-			     mac_m, 1,
-			     mac_high, ntohl ( buf.dwords[0] ) );
-		MLX_FILL_1 ( &stat_cfg, 37, mac_low, ntohl ( buf.dwords[1] ) );
-		if ( ( rc = hermon_mod_stat_cfg ( hermon, mport,
+	/* Modify static configuration */
+	memset ( &stat_cfg, 0, sizeof ( stat_cfg ) );
+	MLX_FILL_2 ( &stat_cfg, 36,
+		     mac_m, 1,
+		     mac_high, ntohl ( buf.dwords[0] ) );
+	MLX_FILL_1 ( &stat_cfg, 37, mac_low, ntohl ( buf.dwords[1] ) );
+	if ( ( rc = hermon_mod_stat_cfg ( hermon, mport,
 					  HERMON_MOD_STAT_CFG_SET,
 					  HERMON_MOD_STAT_CFG_OFFSET ( mac_m ),
 					  &stat_cfg ) ) != 0 ) {
-			DBGC ( hermon, "Hermon %p port %d could not modify "
-			       "configuration: %s\n",
-			       hermon, mport, strerror ( rc ) );
-			return rc;
-		}
-
-		DBGC ( hermon, "Hermon %p port %d updated MAC address to %s\n",
-		       hermon, mport, eth_ntoa ( mac_copy ) );
-
-		/* Increment MAC address */
-		buf.qword = cpu_to_be64 ( be64_to_cpu ( buf.qword ) + 1 );
+		DBGC ( hermon, "Hermon %p port %d could not modify "
+		       "configuration: %s\n", hermon, mport, strerror ( rc ) );
+		return rc;
 	}
 
+	DBGC ( hermon, "Hermon %p port %d updated MAC address to %s\n",
+	       hermon, mport, eth_ntoa ( mac ) );
+
 	return 0;
 }
 
@@ -3448,94 +3697,6 @@ static struct bofm_operations hermon_bofm_operations = {
  ***************************************************************************
  */
 
-/**
- * Set up memory protection table
- *
- * @v hermon		Hermon device
- * @ret rc		Return status code
- */
-static int hermon_setup_mpt ( struct hermon *hermon ) {
-	struct hermonprm_mpt mpt;
-	uint32_t key;
-	int rc;
-
-	/* Derive key */
-	key = ( hermon->cap.reserved_mrws | HERMON_MKEY_PREFIX );
-	hermon->lkey = ( ( key << 8 ) | ( key >> 24 ) );
-
-	/* Initialise memory protection table */
-	memset ( &mpt, 0, sizeof ( mpt ) );
-	MLX_FILL_7 ( &mpt, 0,
-		     atomic, 1,
-		     rw, 1,
-		     rr, 1,
-		     lw, 1,
-		     lr, 1,
-		     pa, 1,
-		     r_w, 1 );
-	MLX_FILL_1 ( &mpt, 2, mem_key, key );
-	MLX_FILL_1 ( &mpt, 3,
-		     pd, HERMON_GLOBAL_PD );
-	MLX_FILL_1 ( &mpt, 10, len64, 1 );
-	if ( ( rc = hermon_cmd_sw2hw_mpt ( hermon,
-					   hermon->cap.reserved_mrws,
-					   &mpt ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p could not set up MPT: %s\n",
-		       hermon, strerror ( rc ) );
-		return rc;
-	}
-
-	return 0;
-}
-
-/**
- * Configure special queue pairs
- *
- * @v hermon		Hermon device
- * @ret rc		Return status code
- */
-static int hermon_configure_special_qps ( struct hermon *hermon ) {
-	int rc;
-
-	/* Special QP block must be aligned on its own size */
-	hermon->special_qpn_base = ( ( hermon->cap.reserved_qps +
-				       HERMON_NUM_SPECIAL_QPS - 1 )
-				     & ~( HERMON_NUM_SPECIAL_QPS - 1 ) );
-	hermon->qpn_base = ( hermon->special_qpn_base +
-			     HERMON_NUM_SPECIAL_QPS );
-	DBGC ( hermon, "Hermon %p special QPs at [%lx,%lx]\n", hermon,
-	       hermon->special_qpn_base, ( hermon->qpn_base - 1 ) );
-
-	/* Issue command to configure special QPs */
-	if ( ( rc = hermon_cmd_conf_special_qp ( hermon, 0x00,
-					  hermon->special_qpn_base ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p could not configure special QPs: "
-		       "%s\n", hermon, strerror ( rc ) );
-		return rc;
-	}
-
-	return 0;
-}
-
-/**
- * Reset device
- *
- * @v hermon		Hermon device
- * @v pci		PCI device
- */
-static void hermon_reset ( struct hermon *hermon,
-			   struct pci_device *pci ) {
-	struct pci_config_backup backup;
-	static const uint8_t backup_exclude[] =
-		PCI_CONFIG_BACKUP_EXCLUDE ( 0x58, 0x5c );
-
-	pci_backup ( pci, &backup, backup_exclude );
-	writel ( HERMON_RESET_MAGIC,
-		 ( hermon->config + HERMON_RESET_OFFSET ) );
-	mdelay ( HERMON_RESET_WAIT_TIME_MS );
-	pci_restore ( pci, &backup, backup_exclude );
-}
-
 /**
  * Allocate Hermon device
  *
@@ -3579,6 +3740,8 @@ static struct hermon * hermon_alloc ( void ) {
  */
 static void hermon_free ( struct hermon *hermon ) {
 
+	ufree ( hermon->icm );
+	ufree ( hermon->firmware_area );
 	free_dma ( hermon->mailbox_out, HERMON_MBOX_SIZE );
 	free_dma ( hermon->mailbox_in, HERMON_MBOX_SIZE );
 	free ( hermon );
@@ -3588,9 +3751,9 @@ static void hermon_free ( struct hermon *hermon ) {
  * Initialise Hermon PCI parameters
  *
  * @v hermon		Hermon device
- * @v pci		PCI device
  */
-static void hermon_pci_init ( struct hermon *hermon, struct pci_device *pci ) {
+static void hermon_pci_init ( struct hermon *hermon ) {
+	struct pci_device *pci = hermon->pci;
 
 	/* Fix up PCI device */
 	adjust_pci_device ( pci );
@@ -3614,7 +3777,6 @@ static int hermon_probe ( struct pci_device *pci ) {
 	struct ib_device *ibdev;
 	struct net_device *netdev;
 	struct hermon_port *port;
-	struct hermonprm_init_hca init_hca;
 	unsigned int i;
 	int rc;
 
@@ -3625,12 +3787,13 @@ static int hermon_probe ( struct pci_device *pci ) {
 		goto err_alloc;
 	}
 	pci_set_drvdata ( pci, hermon );
+	hermon->pci = pci;
 
 	/* Initialise PCI parameters */
-	hermon_pci_init ( hermon, pci );
+	hermon_pci_init ( hermon );
 
 	/* Reset device */
-	hermon_reset ( hermon, pci );
+	hermon_reset ( hermon );
 
 	/* Start firmware */
 	if ( ( rc = hermon_start_firmware ( hermon ) ) != 0 )
@@ -3667,34 +3830,9 @@ static int hermon_probe ( struct pci_device *pci ) {
 		netdev->priv = &hermon->port[i];
 	}
 
-	/* Allocate ICM */
-	memset ( &init_hca, 0, sizeof ( init_hca ) );
-	if ( ( rc = hermon_alloc_icm ( hermon, &init_hca ) ) != 0 )
-		goto err_alloc_icm;
-
-	/* Initialise HCA */
-	MLX_FILL_1 ( &init_hca, 0, version, 0x02 /* "Must be 0x02" */ );
-	MLX_FILL_1 ( &init_hca, 5, udp, 1 );
-	MLX_FILL_1 ( &init_hca, 74, uar_parameters.log_max_uars, 8 );
-	if ( ( rc = hermon_cmd_init_hca ( hermon, &init_hca ) ) != 0 ) {
-		DBGC ( hermon, "Hermon %p could not initialise HCA: %s\n",
-		       hermon, strerror ( rc ) );
-		goto err_init_hca;
-	}
-
-	/* Set up memory protection */
-	if ( ( rc = hermon_setup_mpt ( hermon ) ) != 0 )
-		goto err_setup_mpt;
-	for ( i = 0 ; i < hermon->cap.num_ports ; i++ )
-		hermon->port[i].ibdev->rdma_key = hermon->lkey;
-
-	/* Set up event queue */
-	if ( ( rc = hermon_create_eq ( hermon ) ) != 0 )
-		goto err_create_eq;
-
-	/* Configure special QPs */
-	if ( ( rc = hermon_configure_special_qps ( hermon ) ) != 0 )
-		goto err_conf_special_qps;
+	/* Start device */
+	if ( ( rc = hermon_start ( hermon, 1 ) ) != 0 )
+		goto err_start;
 
 	/* Determine port types */
 	for ( i = 0 ; i < hermon->cap.num_ports ; i++ ) {
@@ -3703,6 +3841,15 @@ static int hermon_probe ( struct pci_device *pci ) {
 			goto err_set_port_type;
 	}
 
+	/* Initialise non-volatile storage */
+	nvs_vpd_init ( &hermon->nvsvpd, pci );
+	for ( i = 0 ; i < hermon->cap.num_ports ; i++ ) {
+		port = &hermon->port[i];
+		nvs_vpd_nvo_init ( &hermon->nvsvpd,
+				   HERMON_VPD_FIELD ( port->ibdev->port ),
+				   &port->nvo, NULL );
+	}
+
 	/* Register devices */
 	for ( i = 0 ; i < hermon->cap.num_ports ; i++ ) {
 		port = &hermon->port[i];
@@ -3710,6 +3857,10 @@ static int hermon_probe ( struct pci_device *pci ) {
 			goto err_register;
 	}
 
+	/* Leave device quiescent until opened */
+	if ( hermon->open_count == 0 )
+		hermon_stop ( hermon );
+
 	return 0;
 
 	i = hermon->cap.num_ports;
@@ -3719,14 +3870,8 @@ static int hermon_probe ( struct pci_device *pci ) {
 		port->type->unregister_dev ( hermon, port );
 	}
  err_set_port_type:
- err_conf_special_qps:
-	hermon_destroy_eq ( hermon );
- err_create_eq:
- err_setup_mpt:
-	hermon_cmd_close_hca ( hermon );
- err_init_hca:
-	hermon_free_icm ( hermon );
- err_alloc_icm:
+	hermon_stop ( hermon );
+ err_start:
 	i = hermon->cap.num_ports;
  err_alloc_netdev:
 	for ( i-- ; ( signed int ) i >= 0 ; i-- ) {
@@ -3759,10 +3904,6 @@ static void hermon_remove ( struct pci_device *pci ) {
 		port = &hermon->port[i];
 		port->type->unregister_dev ( hermon, port );
 	}
-	hermon_destroy_eq ( hermon );
-	hermon_cmd_close_hca ( hermon );
-	hermon_free_icm ( hermon );
-	hermon_stop_firmware ( hermon );
 	for ( i = ( hermon->cap.num_ports - 1 ) ; i >= 0 ; i-- ) {
 		netdev_nullify ( hermon->port[i].netdev );
 		netdev_put ( hermon->port[i].netdev );
@@ -3790,9 +3931,10 @@ static int hermon_bofm_probe ( struct pci_device *pci ) {
 		goto err_alloc;
 	}
 	pci_set_drvdata ( pci, hermon );
+	hermon->pci = pci;
 
 	/* Initialise PCI parameters */
-	hermon_pci_init ( hermon, pci );
+	hermon_pci_init ( hermon );
 
 	/* Initialise BOFM device */
 	bofm_init ( &hermon->bofm, pci, &hermon_bofm_operations );
diff --git a/roms/ipxe/src/drivers/infiniband/hermon.h b/roms/ipxe/src/drivers/infiniband/hermon.h
index 1c862303529cc2f0d23c1a48764a..e0b028f263e86cca2ab040dadccd 100644
--- a/roms/ipxe/src/drivers/infiniband/hermon.h
+++ b/roms/ipxe/src/drivers/infiniband/hermon.h
@@ -13,6 +13,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/uaccess.h>
 #include <ipxe/ib_packet.h>
 #include <ipxe/bofm.h>
+#include <ipxe/nvsvpd.h>
+#include <ipxe/nvo.h>
 #include "mlx_bitops.h"
 #include "MT25408_PRM.h"
 
@@ -135,6 +137,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define HERMON_MOD_STAT_CFG_SET		0x01
 #define HERMON_MOD_STAT_CFG_QUERY	0x03
 
+#define HERMON_VPD_FIELD( port ) \
+	PCI_VPD_FIELD ( PCI_VPD_TAG_RW, 'V', ( '5' + (port) - 1 ) )
+
 /*
  * Datatypes that seem to be missing from the autogenerated documentation
  *
@@ -825,10 +830,14 @@ struct hermon_port {
 	struct ib_queue_pair *eth_qp;
 	/** Port type */
 	struct hermon_port_type *type;
+	/** Non-volatile option storage */
+	struct nvo_block nvo;
 };
 
 /** A Hermon device */
 struct hermon {
+	/** PCI device */
+	struct pci_device *pci;
 	/** PCI configuration registers */
 	void *config;
 	/** PCI user Access Region */
@@ -841,11 +850,30 @@ struct hermon {
 	/** Command output mailbox */
 	void *mailbox_out;
 
-	/** Firmware area in external memory */
+	/** Device open request counter */
+	unsigned int open_count;
+
+	/** Firmware size */
+	size_t firmware_len;
+	/** Firmware area in external memory
+	 *
+	 * This is allocated when first needed, and freed only on
+	 * final teardown, in order to avoid memory map changes at
+	 * runtime.
+	 */
 	userptr_t firmware_area;
 	/** ICM map */
 	struct hermon_icm_map icm_map[HERMON_ICM_NUM_REGIONS];
-	/** ICM area */
+	/** ICM size */
+	size_t icm_len;
+	/** ICM AUX size */
+	size_t icm_aux_len;
+	/** ICM area
+	 *
+	 * This is allocated when first needed, and freed only on
+	 * final teardown, in order to avoid memory map changes at
+	 * runtime.
+	 */
 	userptr_t icm;
 
 	/** Event queue */
@@ -870,6 +898,9 @@ struct hermon {
 	/** QPN base */
 	unsigned long qpn_base;
 
+	/** Non-volatile storage in PCI VPD */
+	struct nvs_vpd_device nvsvpd;
+
 	/** Ports */
 	struct hermon_port port[HERMON_MAX_PORTS];
 
diff --git a/roms/ipxe/src/drivers/infiniband/linda.c b/roms/ipxe/src/drivers/infiniband/linda.c
index 6a6a2ec9aebdee63a6454b7772f5..4afda1208860c4848de406c49714 100644
--- a/roms/ipxe/src/drivers/infiniband/linda.c
+++ b/roms/ipxe/src/drivers/infiniband/linda.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -935,13 +936,13 @@ static void linda_destroy_qp ( struct ib_device *ibdev,
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector
+ * @v dest		Destination 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 ib_address_vector *dest,
 			     struct io_buffer *iobuf ) {
 	struct linda *linda = ib_get_drvdata ( ibdev );
 	struct ib_work_queue *wq = &qp->send;
@@ -968,7 +969,7 @@ static int linda_post_send ( struct ib_device *ibdev,
 	/* 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 );
+	ib_push ( ibdev, &headers, qp, iob_len ( iobuf ), dest );
 
 	/* Calculate packet length */
 	len = ( ( sizeof ( sendpbc ) + iob_len ( &headers ) +
@@ -1169,7 +1170,8 @@ static void linda_complete_recv ( struct ib_device *ibdev,
 	struct io_buffer headers;
 	struct io_buffer *iobuf;
 	struct ib_queue_pair *intended_qp;
-	struct ib_address_vector av;
+	struct ib_address_vector dest;
+	struct ib_address_vector source;
 	unsigned int rcvtype;
 	unsigned int pktlen;
 	unsigned int egrindex;
@@ -1237,7 +1239,7 @@ static void linda_complete_recv ( struct ib_device *ibdev,
 	qp0 = ( qp->qpn == 0 );
 	intended_qp = NULL;
 	if ( ( rc = ib_pull ( ibdev, &headers, ( qp0 ? &intended_qp : NULL ),
-			      &payload_len, &av ) ) != 0 ) {
+			      &payload_len, &dest, &source ) ) != 0 ) {
 		DBGC ( linda, "Linda %p could not parse headers: %s\n",
 		       linda, strerror ( rc ) );
 		err = 1;
@@ -1294,10 +1296,12 @@ static void linda_complete_recv ( struct ib_device *ibdev,
 				qp->recv.fill--;
 				intended_qp->recv.fill++;
 			}
-			ib_complete_recv ( ibdev, intended_qp, &av, iobuf, rc);
+			ib_complete_recv ( ibdev, intended_qp, &dest, &source,
+					   iobuf, rc);
 		} else {
 			/* Completing on a skipped-over eager buffer */
-			ib_complete_recv ( ibdev, qp, &av, iobuf, -ECANCELED );
+			ib_complete_recv ( ibdev, qp, &dest, &source, iobuf,
+					   -ECANCELED );
 		}
 
 		/* Clear eager buffer */
diff --git a/roms/ipxe/src/drivers/infiniband/linda.h b/roms/ipxe/src/drivers/infiniband/linda.h
index 1450a6ada4aadac5e20c1789ebb6..72ce708686f9b964ea39d7dbfdff 100644
--- a/roms/ipxe/src/drivers/infiniband/linda.h
+++ b/roms/ipxe/src/drivers/infiniband/linda.h
@@ -16,7 +16,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/infiniband/mlx_bitops.h b/roms/ipxe/src/drivers/infiniband/mlx_bitops.h
index 490d5e3c5b1d007e5fad3cd23e36..b6ca9f633dc8e1034e6e374b2abe 100644
--- a/roms/ipxe/src/drivers/infiniband/mlx_bitops.h
+++ b/roms/ipxe/src/drivers/infiniband/mlx_bitops.h
@@ -16,7 +16,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/infiniband/qib7322.c b/roms/ipxe/src/drivers/infiniband/qib7322.c
index b66f8eff90ec7206a95e963b41b2..9979b346e9c97ed6b1fc5d312ead 100644
--- a/roms/ipxe/src/drivers/infiniband/qib7322.c
+++ b/roms/ipxe/src/drivers/infiniband/qib7322.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -1172,13 +1173,13 @@ static void qib7322_destroy_qp ( struct ib_device *ibdev,
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector
+ * @v dest		Destination address vector
  * @v iobuf		I/O buffer
  * @ret rc		Return status code
  */
 static int qib7322_post_send ( struct ib_device *ibdev,
 			       struct ib_queue_pair *qp,
-			       struct ib_address_vector *av,
+			       struct ib_address_vector *dest,
 			       struct io_buffer *iobuf ) {
 	struct qib7322 *qib7322 = ib_get_drvdata ( ibdev );
 	struct ib_work_queue *wq = &qp->send;
@@ -1210,7 +1211,7 @@ static int qib7322_post_send ( struct ib_device *ibdev,
 	/* 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 );
+	ib_push ( ibdev, &headers, qp, iob_len ( iobuf ), dest );
 
 	/* Calculate packet length */
 	len = ( ( sizeof ( sendpbc ) + iob_len ( &headers ) +
@@ -1412,7 +1413,8 @@ static void qib7322_complete_recv ( struct ib_device *ibdev,
 	struct io_buffer headers;
 	struct io_buffer *iobuf;
 	struct ib_queue_pair *intended_qp;
-	struct ib_address_vector av;
+	struct ib_address_vector dest;
+	struct ib_address_vector source;
 	unsigned int rcvtype;
 	unsigned int pktlen;
 	unsigned int egrindex;
@@ -1473,7 +1475,7 @@ static void qib7322_complete_recv ( struct ib_device *ibdev,
 	qp0 = ( qp->qpn == 0 );
 	intended_qp = NULL;
 	if ( ( rc = ib_pull ( ibdev, &headers, ( qp0 ? &intended_qp : NULL ),
-			      &payload_len, &av ) ) != 0 ) {
+			      &payload_len, &dest, &source ) ) != 0 ) {
 		DBGC ( qib7322, "QIB7322 %p could not parse headers: %s\n",
 		       qib7322, strerror ( rc ) );
 		err = 1;
@@ -1530,10 +1532,12 @@ static void qib7322_complete_recv ( struct ib_device *ibdev,
 				qp->recv.fill--;
 				intended_qp->recv.fill++;
 			}
-			ib_complete_recv ( ibdev, intended_qp, &av, iobuf, rc);
+			ib_complete_recv ( ibdev, intended_qp, &dest, &source,
+					   iobuf, rc);
 		} else {
 			/* Completing on a skipped-over eager buffer */
-			ib_complete_recv ( ibdev, qp, &av, iobuf, -ECANCELED );
+			ib_complete_recv ( ibdev, qp, &dest, &source, iobuf,
+					   -ECANCELED );
 		}
 
 		/* Clear eager buffer */
@@ -2062,6 +2066,9 @@ static int qib7322_ahb_read ( struct qib7322 *qib7322, unsigned int location,
 	struct QIB_7322_ahb_transaction_reg xact;
 	int rc;
 
+	/* Avoid returning uninitialised data on error */
+	*data = 0;
+
 	/* Initiate transaction */
 	memset ( &xact, 0, sizeof ( xact ) );
 	BIT_FILL_2 ( &xact,
diff --git a/roms/ipxe/src/drivers/infiniband/qib7322.h b/roms/ipxe/src/drivers/infiniband/qib7322.h
index 0dac09ef2fb8f962f73de949254f..63abe221b0bda22d4beeb1f4a6e0 100644
--- a/roms/ipxe/src/drivers/infiniband/qib7322.h
+++ b/roms/ipxe/src/drivers/infiniband/qib7322.h
@@ -16,7 +16,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/infiniband/qib_genbits.pl b/roms/ipxe/src/drivers/infiniband/qib_genbits.pl
index 1d5eeded04264c63aa809e211c5b..586f7b6b8219d964f903bb330d4c 100755
--- a/roms/ipxe/src/drivers/infiniband/qib_genbits.pl
+++ b/roms/ipxe/src/drivers/infiniband/qib_genbits.pl
@@ -14,7 +14,8 @@
 #
 # 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.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
 
 use strict;
 use warnings;
diff --git a/roms/ipxe/src/drivers/net/3c509-eisa.c b/roms/ipxe/src/drivers/net/3c509-eisa.c
index 195a844a433e7a3912c9d3b123bb..81c60ee913cfffc03f305be0d711 100644
--- a/roms/ipxe/src/drivers/net/3c509-eisa.c
+++ b/roms/ipxe/src/drivers/net/3c509-eisa.c
@@ -6,7 +6,6 @@
 
 #include <ipxe/eisa.h>
 #include <ipxe/isa.h>
-#include <ipxe/console.h>
 #include "3c509.h"
 
 /*
diff --git a/roms/ipxe/src/drivers/net/3c509.h b/roms/ipxe/src/drivers/net/3c509.h
index f030d4ba49ed8bc04aab9cc11936..25e4a88d8f13558eac558691e08c 100644
--- a/roms/ipxe/src/drivers/net/3c509.h
+++ b/roms/ipxe/src/drivers/net/3c509.h
@@ -77,7 +77,7 @@ FILE_LICENCE ( BSD3 );
 /**************************************************************************
  *
  * These define the EEPROM data structure.  They are used in the probe
- * function to verify the existance of the adapter after having sent
+ * function to verify the existence of the adapter after having sent
  * the ID_Sequence.
  *
  * There are others but only the ones we use are defined here.
diff --git a/roms/ipxe/src/drivers/net/3c515.c b/roms/ipxe/src/drivers/net/3c515.c
index 2b8606906ff8942d861aeaa9532b..0aa68b1aa79142f425b8e4cf5515 100644
--- a/roms/ipxe/src/drivers/net/3c515.c
+++ b/roms/ipxe/src/drivers/net/3c515.c
@@ -14,7 +14,8 @@
 *
 *    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.
+*    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+*    02110-1301, USA.
 *
 * Portions of this code:
 * Copyright (C) 1997-2002 Donald Becker  3c515.c: A 3Com ISA EtherLink XL "Corkscrew" ethernet driver for linux.
@@ -655,7 +656,7 @@ static int
 corkscrew_found_device(int ioaddr, int irq,
 		       int product_index, int options, struct nic *nic)
 {
-	/* Direct copy from Becker 3c515.c with unecessary parts removed */
+	/* Direct copy from Becker 3c515.c with unnecessary parts removed */
 	vp->product_name = "3c515";
 	vp->options = options;
 	if (options >= 0) {
diff --git a/roms/ipxe/src/drivers/net/3c595.c b/roms/ipxe/src/drivers/net/3c595.c
index 3178178ac48245b9888ae27b5970..1aa8ed641dc0e05f14906696b0a2 100644
--- a/roms/ipxe/src/drivers/net/3c595.c
+++ b/roms/ipxe/src/drivers/net/3c595.c
@@ -127,7 +127,7 @@ static void t595_reset(struct nic *nic)
 		S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
 
 /*
- * Attempt to get rid of any stray interrupts that occured during
+ * Attempt to get rid of any stray interrupts that occurred during
  * configuration.  On the i386 this isn't possible because one may
  * already be queued.  However, a single stray interrupt is
  * unimportant.
diff --git a/roms/ipxe/src/drivers/net/amd8111e.c b/roms/ipxe/src/drivers/net/amd8111e.c
index 476d53068bbefe96d034ea8cbdbb..693d77d1dbe3209a835e9241d9f3 100644
--- a/roms/ipxe/src/drivers/net/amd8111e.c
+++ b/roms/ipxe/src/drivers/net/amd8111e.c
@@ -24,7 +24,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  * USA
  */
 
diff --git a/roms/ipxe/src/drivers/net/amd8111e.h b/roms/ipxe/src/drivers/net/amd8111e.h
index a402a63ec1514a575ef38dddcc1c..2000df1586754b75d723d9ab194f 100644
--- a/roms/ipxe/src/drivers/net/amd8111e.h
+++ b/roms/ipxe/src/drivers/net/amd8111e.h
@@ -14,7 +14,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  * USA
 
 Module Name:
@@ -573,7 +574,7 @@ typedef enum {
 #define CSTATE  1 
 #define SSTATE  2 
 
-/* amd8111e decriptor flag definitions */
+/* amd8111e descriptor flag definitions */
 typedef enum {
 
 	OWN_BIT		=	(1 << 15),
diff --git a/roms/ipxe/src/drivers/net/ath/ath.h b/roms/ipxe/src/drivers/net/ath/ath.h
new file mode 100644
index 0000000000000000000000000000000000000000..5a19a19cd6af182eaa1f8b7cbf995a2ed345a303
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath.h
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ATH_H
+#define ATH_H
+
+#include <unistd.h>
+#include <ipxe/net80211.h>
+
+/* This block of functions are from kernel.h v3.0.1 */
+#define ARRAY_SIZE(arr)		(sizeof(arr) / sizeof((arr)[0]))
+#define DIV_ROUND_UP(n,d)	(((n) + (d) - 1) / (d))
+#define BITS_PER_BYTE		8
+#define BITS_TO_LONGS(nr)	DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
+#define BIT(nr)			(1UL << (nr))
+
+#define min(x, y) ({					\
+	typeof(x) _min1 = (x);				\
+	typeof(y) _min2 = (y);				\
+	(void) (&_min1 == &_min2);			\
+	_min1 < _min2 ? _min1 : _min2; })
+#define max(x, y) ({					\
+	typeof(x) _max1 = (x);				\
+	typeof(y) _max2 = (y);				\
+	(void) (&_max1 == &_max2);			\
+	_max1 > _max2 ? _max1 : _max2; })
+#define abs(x) ({					\
+		long ret;				\
+		if (sizeof(x) == sizeof(long)) {	\
+			long __x = (x);			\
+			ret = (__x < 0) ? -__x : __x;	\
+		} else {				\
+			int __x = (x);			\
+			ret = (__x < 0) ? -__x : __x;	\
+		}					\
+		ret;					\
+	})
+
+#define ___constant_swab16(x) ((uint16_t)(			\
+	(((uint16_t)(x) & (uint16_t)0x00ffU) << 8) |		\
+	(((uint16_t)(x) & (uint16_t)0xff00U) >> 8)))
+#define ___constant_swab32(x) ((uint32_t)(			\
+	(((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) |	\
+	(((uint32_t)(x) & (uint32_t)0x0000ff00UL) <<  8) |	\
+	(((uint32_t)(x) & (uint32_t)0x00ff0000UL) >>  8) |	\
+	(((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24)))
+#define __swab16(x) ___constant_swab16(x)
+#define __swab32(x) ___constant_swab32(x)
+#define swab16 __swab16
+#define swab32 __swab32
+
+static inline int32_t sign_extend32(uint32_t value, int index)
+{
+	uint8_t shift = 31 - index;
+	return (int32_t)(value << shift) >> shift;
+}
+
+static inline u16 __get_unaligned_le16(const u8 *p)
+{
+	return p[0] | p[1] << 8;
+}
+static inline u32 __get_unaligned_le32(const u8 *p)
+{
+	return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
+}
+static inline u16 get_unaligned_le16(const void *p)
+{
+	return __get_unaligned_le16((const u8 *)p);
+}
+static inline u32 get_unaligned_le32(const void *p)
+{
+	return __get_unaligned_le32((const u8 *)p);
+}
+/* End Kernel Block */
+
+/*
+ * The key cache is used for h/w cipher state and also for
+ * tracking station state such as the current tx antenna.
+ * We also setup a mapping table between key cache slot indices
+ * and station state to short-circuit node lookups on rx.
+ * Different parts have different size key caches.  We handle
+ * up to ATH_KEYMAX entries (could dynamically allocate state).
+ */
+#define	ATH_KEYMAX	        128     /* max key cache size we handle */
+
+static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+struct ath_ani {
+	int caldone;
+	unsigned int longcal_timer;
+	unsigned int shortcal_timer;
+	unsigned int resetcal_timer;
+	unsigned int checkani_timer;
+	int timer;
+};
+
+struct ath_cycle_counters {
+	u32 cycles;
+	u32 rx_busy;
+	u32 rx_frame;
+	u32 tx_frame;
+};
+
+enum ath_device_state {
+	ATH_HW_UNAVAILABLE,
+	ATH_HW_INITIALIZED,
+};
+
+enum ath_bus_type {
+	ATH_PCI,
+	ATH_AHB,
+	ATH_USB,
+};
+
+struct reg_dmn_pair_mapping {
+	u16 regDmnEnum;
+	u16 reg_5ghz_ctl;
+	u16 reg_2ghz_ctl;
+};
+
+struct ath_regulatory {
+	char alpha2[2];
+	u16 country_code;
+	u16 max_power_level;
+	u32 tp_scale;
+	u16 current_rd;
+	u16 current_rd_ext;
+	int16_t power_limit;
+	struct reg_dmn_pair_mapping *regpair;
+};
+
+enum ath_crypt_caps {
+	ATH_CRYPT_CAP_CIPHER_AESCCM		= BIT(0),
+	ATH_CRYPT_CAP_MIC_COMBINED		= BIT(1),
+};
+
+struct ath_keyval {
+	u8 kv_type;
+	u8 kv_pad;
+	u16 kv_len;
+	u8 kv_val[16]; /* TK */
+	u8 kv_mic[8]; /* Michael MIC key */
+	u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware
+			 * supports both MIC keys in the same key cache entry;
+			 * in that case, kv_mic is the RX key) */
+};
+
+enum ath_cipher {
+	ATH_CIPHER_WEP = 0,
+	ATH_CIPHER_AES_OCB = 1,
+	ATH_CIPHER_AES_CCM = 2,
+	ATH_CIPHER_CKIP = 3,
+	ATH_CIPHER_TKIP = 4,
+	ATH_CIPHER_CLR = 5,
+	ATH_CIPHER_MIC = 127
+};
+
+/**
+ * struct ath_ops - Register read/write operations
+ *
+ * @read: Register read
+ * @multi_read: Multiple register read
+ * @write: Register write
+ * @enable_write_buffer: Enable multiple register writes
+ * @write_flush: flush buffered register writes and disable buffering
+ */
+struct ath_ops {
+	unsigned int (*read)(void *, u32 reg_offset);
+	void (*multi_read)(void *, u32 *addr, u32 *val, u16 count);
+	void (*write)(void *, u32 val, u32 reg_offset);
+	void (*enable_write_buffer)(void *);
+	void (*write_flush) (void *);
+	u32 (*rmw)(void *, u32 reg_offset, u32 set, u32 clr);
+};
+
+struct ath_common;
+struct ath_bus_ops;
+
+struct ath_common {
+	void *ah;
+	void *priv;
+	struct net80211_device *dev;
+	int debug_mask;
+	enum ath_device_state state;
+
+	struct ath_ani ani;
+
+	u16 cachelsz;
+	u16 curaid;
+	u8 macaddr[ETH_ALEN];
+	u8 curbssid[ETH_ALEN];
+	u8 bssidmask[ETH_ALEN];
+
+	u8 tx_chainmask;
+	u8 rx_chainmask;
+
+	u32 rx_bufsize;
+
+	u32 keymax;
+	enum ath_crypt_caps crypt_caps;
+
+	unsigned int clockrate;
+
+	struct ath_cycle_counters cc_ani;
+	struct ath_cycle_counters cc_survey;
+
+	struct ath_regulatory regulatory;
+	const struct ath_ops *ops;
+	const struct ath_bus_ops *bus_ops;
+
+	int btcoex_enabled;
+};
+
+struct io_buffer *ath_rxbuf_alloc(struct ath_common *common,
+				u32 len,
+				u32 *iob_addr);
+
+void ath_hw_setbssidmask(struct ath_common *common);
+int ath_hw_keyreset(struct ath_common *common, u16 entry);
+void ath_hw_cycle_counters_update(struct ath_common *common);
+int32_t ath_hw_get_listen_time(struct ath_common *common);
+
+#endif /* ATH_H */
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/ath5k.c b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k.c
new file mode 100644
index 0000000000000000000000000000000000000000..92c4ffdf410bb49906a45d618080e44a3740fea8
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k.c
@@ -0,0 +1,1698 @@
+/*
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * Copyright (c) 2004-2005 Atheros Communications, Inc.
+ * Copyright (c) 2006 Devicescape Software, Inc.
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
+ *
+ * Modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>
+ * Original from Linux kernel 2.6.30.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+FILE_LICENCE ( BSD3 );
+
+#include <stdlib.h>
+#include <ipxe/malloc.h>
+#include <ipxe/timer.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/pci.h>
+#include <ipxe/pci_io.h>
+
+#include "base.h"
+#include "reg.h"
+
+#define ATH5K_CALIB_INTERVAL	10 /* Calibrate PHY every 10 seconds */
+#define ATH5K_RETRIES		4  /* Number of times to retry packet sends */
+#define ATH5K_DESC_ALIGN	16 /* Alignment for TX/RX descriptors */
+
+/******************\
+* Internal defines *
+\******************/
+
+/* Known PCI ids */
+static struct pci_device_id ath5k_nics[] = {
+	PCI_ROM(0x168c, 0x0207, "ath5210e", "Atheros 5210 early", AR5K_AR5210),
+	PCI_ROM(0x168c, 0x0007, "ath5210", "Atheros 5210", AR5K_AR5210),
+	PCI_ROM(0x168c, 0x0011, "ath5311", "Atheros 5311 (AHB)", AR5K_AR5211),
+	PCI_ROM(0x168c, 0x0012, "ath5211", "Atheros 5211", AR5K_AR5211),
+	PCI_ROM(0x168c, 0x0013, "ath5212", "Atheros 5212", AR5K_AR5212),
+	PCI_ROM(0xa727, 0x0013, "ath5212c","3com Ath 5212", AR5K_AR5212),
+	PCI_ROM(0x10b7, 0x0013, "rdag675", "3com 3CRDAG675", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x1014, "ath5212m", "Ath 5212 miniPCI", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x0014, "ath5212x14", "Atheros 5212 x14", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x0015, "ath5212x15", "Atheros 5212 x15", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x0016, "ath5212x16", "Atheros 5212 x16", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x0017, "ath5212x17", "Atheros 5212 x17", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x0018, "ath5212x18", "Atheros 5212 x18", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x0019, "ath5212x19", "Atheros 5212 x19", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x001a, "ath2413", "Atheros 2413 Griffin", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x001b, "ath5413", "Atheros 5413 Eagle", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x001c, "ath5212e", "Atheros 5212 PCI-E", AR5K_AR5212),
+	PCI_ROM(0x168c, 0x001d, "ath2417", "Atheros 2417 Nala", AR5K_AR5212),
+};
+
+/* Known SREVs */
+static const struct ath5k_srev_name srev_names[] = {
+	{ "5210",	AR5K_VERSION_MAC,	AR5K_SREV_AR5210 },
+	{ "5311",	AR5K_VERSION_MAC,	AR5K_SREV_AR5311 },
+	{ "5311A",	AR5K_VERSION_MAC,	AR5K_SREV_AR5311A },
+	{ "5311B",	AR5K_VERSION_MAC,	AR5K_SREV_AR5311B },
+	{ "5211",	AR5K_VERSION_MAC,	AR5K_SREV_AR5211 },
+	{ "5212",	AR5K_VERSION_MAC,	AR5K_SREV_AR5212 },
+	{ "5213",	AR5K_VERSION_MAC,	AR5K_SREV_AR5213 },
+	{ "5213A",	AR5K_VERSION_MAC,	AR5K_SREV_AR5213A },
+	{ "2413",	AR5K_VERSION_MAC,	AR5K_SREV_AR2413 },
+	{ "2414",	AR5K_VERSION_MAC,	AR5K_SREV_AR2414 },
+	{ "5424",	AR5K_VERSION_MAC,	AR5K_SREV_AR5424 },
+	{ "5413",	AR5K_VERSION_MAC,	AR5K_SREV_AR5413 },
+	{ "5414",	AR5K_VERSION_MAC,	AR5K_SREV_AR5414 },
+	{ "2415",	AR5K_VERSION_MAC,	AR5K_SREV_AR2415 },
+	{ "5416",	AR5K_VERSION_MAC,	AR5K_SREV_AR5416 },
+	{ "5418",	AR5K_VERSION_MAC,	AR5K_SREV_AR5418 },
+	{ "2425",	AR5K_VERSION_MAC,	AR5K_SREV_AR2425 },
+	{ "2417",	AR5K_VERSION_MAC,	AR5K_SREV_AR2417 },
+	{ "xxxxx",	AR5K_VERSION_MAC,	AR5K_SREV_UNKNOWN },
+	{ "5110",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5110 },
+	{ "5111",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5111 },
+	{ "5111A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5111A },
+	{ "2111",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2111 },
+	{ "5112",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112 },
+	{ "5112A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112A },
+	{ "5112B",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112B },
+	{ "2112",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112 },
+	{ "2112A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112A },
+	{ "2112B",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112B },
+	{ "2413",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2413 },
+	{ "5413",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5413 },
+	{ "2316",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2316 },
+	{ "2317",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2317 },
+	{ "5424",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5424 },
+	{ "5133",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5133 },
+	{ "xxxxx",	AR5K_VERSION_RAD,	AR5K_SREV_UNKNOWN },
+};
+
+#define ATH5K_SPMBL_NO   1
+#define ATH5K_SPMBL_YES  2
+#define ATH5K_SPMBL_BOTH 3
+
+static const struct {
+	u16 bitrate;
+	u8 short_pmbl;
+	u8 hw_code;
+} ath5k_rates[] = {
+	{ 10, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_1M },
+	{ 20, ATH5K_SPMBL_NO, ATH5K_RATE_CODE_2M },
+	{ 55, ATH5K_SPMBL_NO, ATH5K_RATE_CODE_5_5M },
+	{ 110, ATH5K_SPMBL_NO, ATH5K_RATE_CODE_11M },
+	{ 60, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_6M },
+	{ 90, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_9M },
+	{ 120, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_12M },
+	{ 180, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_18M },
+	{ 240, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_24M },
+	{ 360, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_36M },
+	{ 480, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_48M },
+	{ 540, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_54M },
+	{ 20, ATH5K_SPMBL_YES, ATH5K_RATE_CODE_2M | AR5K_SET_SHORT_PREAMBLE },
+	{ 55, ATH5K_SPMBL_YES, ATH5K_RATE_CODE_5_5M | AR5K_SET_SHORT_PREAMBLE },
+	{ 110, ATH5K_SPMBL_YES, ATH5K_RATE_CODE_11M | AR5K_SET_SHORT_PREAMBLE },
+	{ 0, 0, 0 },
+};
+
+#define ATH5K_NR_RATES 15
+
+/*
+ * Prototypes - PCI stack related functions
+ */
+static int 		ath5k_probe(struct pci_device *pdev);
+static void		ath5k_remove(struct pci_device *pdev);
+
+struct pci_driver ath5k_pci_driver __pci_driver = {
+	.ids		= ath5k_nics,
+	.id_count	= sizeof(ath5k_nics) / sizeof(ath5k_nics[0]),
+	.probe		= ath5k_probe,
+	.remove		= ath5k_remove,
+};
+
+
+
+/*
+ * Prototypes - MAC 802.11 stack related functions
+ */
+static int ath5k_tx(struct net80211_device *dev, struct io_buffer *skb);
+static int ath5k_reset(struct ath5k_softc *sc, struct net80211_channel *chan);
+static int ath5k_reset_wake(struct ath5k_softc *sc);
+static int ath5k_start(struct net80211_device *dev);
+static void ath5k_stop(struct net80211_device *dev);
+static int ath5k_config(struct net80211_device *dev, int changed);
+static void ath5k_poll(struct net80211_device *dev);
+static void ath5k_irq(struct net80211_device *dev, int enable);
+
+static struct net80211_device_operations ath5k_ops = {
+	.open		= ath5k_start,
+	.close		= ath5k_stop,
+	.transmit	= ath5k_tx,
+	.poll		= ath5k_poll,
+	.irq		= ath5k_irq,
+	.config		= ath5k_config,
+};
+
+/*
+ * Prototypes - Internal functions
+ */
+/* Attach detach */
+static int 	ath5k_attach(struct net80211_device *dev);
+static void 	ath5k_detach(struct net80211_device *dev);
+/* Channel/mode setup */
+static unsigned int ath5k_copy_channels(struct ath5k_hw *ah,
+				struct net80211_channel *channels,
+				unsigned int mode,
+				unsigned int max);
+static int 	ath5k_setup_bands(struct net80211_device *dev);
+static int 	ath5k_chan_set(struct ath5k_softc *sc,
+				struct net80211_channel *chan);
+static void	ath5k_setcurmode(struct ath5k_softc *sc,
+				unsigned int mode);
+static void	ath5k_mode_setup(struct ath5k_softc *sc);
+
+/* Descriptor setup */
+static int	ath5k_desc_alloc(struct ath5k_softc *sc);
+static void	ath5k_desc_free(struct ath5k_softc *sc);
+/* Buffers setup */
+static int 	ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf);
+static int 	ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf);
+
+static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
+				    struct ath5k_buf *bf)
+{
+	if (!bf->iob)
+		return;
+
+	net80211_tx_complete(sc->dev, bf->iob, 0, ECANCELED);
+	bf->iob = NULL;
+}
+
+static inline void ath5k_rxbuf_free(struct ath5k_softc *sc __unused,
+				    struct ath5k_buf *bf)
+{
+	free_iob(bf->iob);
+	bf->iob = NULL;
+}
+
+/* Queues setup */
+static int 	ath5k_txq_setup(struct ath5k_softc *sc,
+					   int qtype, int subtype);
+static void 	ath5k_txq_drainq(struct ath5k_softc *sc,
+				 struct ath5k_txq *txq);
+static void 	ath5k_txq_cleanup(struct ath5k_softc *sc);
+static void 	ath5k_txq_release(struct ath5k_softc *sc);
+/* Rx handling */
+static int 	ath5k_rx_start(struct ath5k_softc *sc);
+static void 	ath5k_rx_stop(struct ath5k_softc *sc);
+/* Tx handling */
+static void 	ath5k_tx_processq(struct ath5k_softc *sc,
+				  struct ath5k_txq *txq);
+
+/* Interrupt handling */
+static int 	ath5k_init(struct ath5k_softc *sc);
+static int 	ath5k_stop_hw(struct ath5k_softc *sc);
+
+static void 	ath5k_calibrate(struct ath5k_softc *sc);
+
+/* Filter */
+static void	ath5k_configure_filter(struct ath5k_softc *sc);
+
+/********************\
+* PCI Initialization *
+\********************/
+
+#if DBGLVL_MAX
+static const char *
+ath5k_chip_name(enum ath5k_srev_type type, u16 val)
+{
+	const char *name = "xxxxx";
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(srev_names); i++) {
+		if (srev_names[i].sr_type != type)
+			continue;
+
+		if ((val & 0xf0) == srev_names[i].sr_val)
+			name = srev_names[i].sr_name;
+
+		if ((val & 0xff) == srev_names[i].sr_val) {
+			name = srev_names[i].sr_name;
+			break;
+		}
+	}
+
+	return name;
+}
+#endif
+
+static int ath5k_probe(struct pci_device *pdev)
+{
+	void *mem;
+	struct ath5k_softc *sc;
+	struct net80211_device *dev;
+	int ret;
+	u8 csz;
+
+	adjust_pci_device(pdev);
+
+	/*
+	 * Cache line size is used to size and align various
+	 * structures used to communicate with the hardware.
+	 */
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
+	if (csz == 0) {
+		/*
+		 * We must have this setup properly for rx buffer
+		 * DMA to work so force a reasonable value here if it
+		 * comes up zero.
+		 */
+		csz = 16;
+		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
+	}
+	/*
+	 * The default setting of latency timer yields poor results,
+	 * set it to the value used by other systems.  It may be worth
+	 * tweaking this setting more.
+	 */
+	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
+
+	/*
+	 * Disable the RETRY_TIMEOUT register (0x41) to keep
+	 * PCI Tx retries from interfering with C3 CPU state.
+	 */
+	pci_write_config_byte(pdev, 0x41, 0);
+
+	mem = ioremap(pdev->membase, 0x10000);
+	if (!mem) {
+		DBG("ath5k: cannot remap PCI memory region\n");
+		ret = -EIO;
+		goto err;
+	}
+
+	/*
+	 * Allocate dev (net80211 main struct)
+	 * and dev->priv (driver private data)
+	 */
+	dev = net80211_alloc(sizeof(*sc));
+	if (!dev) {
+		DBG("ath5k: cannot allocate 802.11 device\n");
+		ret = -ENOMEM;
+		goto err_map;
+	}
+
+	/* Initialize driver private data */
+	sc = dev->priv;
+	sc->dev = dev;
+	sc->pdev = pdev;
+
+	sc->hwinfo = zalloc(sizeof(*sc->hwinfo));
+	if (!sc->hwinfo) {
+		DBG("ath5k: cannot allocate 802.11 hardware info structure\n");
+		ret = -ENOMEM;
+		goto err_free;
+	}
+
+	sc->hwinfo->flags = NET80211_HW_RX_HAS_FCS;
+	sc->hwinfo->signal_type = NET80211_SIGNAL_DB;
+	sc->hwinfo->signal_max = 40; /* 35dB should give perfect 54Mbps */
+	sc->hwinfo->channel_change_time = 5000;
+
+	/* Avoid working with the device until setup is complete */
+	sc->status |= ATH_STAT_INVALID;
+
+	sc->iobase = mem;
+	sc->cachelsz = csz * 4; /* convert to bytes */
+
+	DBG("ath5k: register base at %p (%08lx)\n", sc->iobase, pdev->membase);
+	DBG("ath5k: cache line size %d\n", sc->cachelsz);
+
+	/* Set private data */
+	pci_set_drvdata(pdev, dev);
+	dev->netdev->dev = (struct device *)pdev;
+
+	/* Initialize device */
+	ret = ath5k_hw_attach(sc, pdev->id->driver_data, &sc->ah);
+	if (ret)
+		goto err_free_hwinfo;
+
+	/* Finish private driver data initialization */
+	ret = ath5k_attach(dev);
+	if (ret)
+		goto err_ah;
+
+#if DBGLVL_MAX
+	DBG("Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
+	    ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev),
+	    sc->ah->ah_mac_srev, sc->ah->ah_phy_revision);
+
+	if (!sc->ah->ah_single_chip) {
+		/* Single chip radio (!RF5111) */
+		if (sc->ah->ah_radio_5ghz_revision &&
+		    !sc->ah->ah_radio_2ghz_revision) {
+			/* No 5GHz support -> report 2GHz radio */
+			if (!(sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11A)) {
+				DBG("RF%s 2GHz radio found (0x%x)\n",
+				    ath5k_chip_name(AR5K_VERSION_RAD,
+						    sc->ah->ah_radio_5ghz_revision),
+				    sc->ah->ah_radio_5ghz_revision);
+			/* No 2GHz support (5110 and some
+			 * 5Ghz only cards) -> report 5Ghz radio */
+			} else if (!(sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11B)) {
+				DBG("RF%s 5GHz radio found (0x%x)\n",
+				    ath5k_chip_name(AR5K_VERSION_RAD,
+						    sc->ah->ah_radio_5ghz_revision),
+				    sc->ah->ah_radio_5ghz_revision);
+			/* Multiband radio */
+			} else {
+				DBG("RF%s multiband radio found (0x%x)\n",
+				    ath5k_chip_name(AR5K_VERSION_RAD,
+						    sc->ah->ah_radio_5ghz_revision),
+				    sc->ah->ah_radio_5ghz_revision);
+			}
+		}
+		/* Multi chip radio (RF5111 - RF2111) ->
+		 * report both 2GHz/5GHz radios */
+		else if (sc->ah->ah_radio_5ghz_revision &&
+			 sc->ah->ah_radio_2ghz_revision) {
+			DBG("RF%s 5GHz radio found (0x%x)\n",
+			    ath5k_chip_name(AR5K_VERSION_RAD,
+					    sc->ah->ah_radio_5ghz_revision),
+			    sc->ah->ah_radio_5ghz_revision);
+			DBG("RF%s 2GHz radio found (0x%x)\n",
+			    ath5k_chip_name(AR5K_VERSION_RAD,
+					    sc->ah->ah_radio_2ghz_revision),
+			    sc->ah->ah_radio_2ghz_revision);
+		}
+	}
+#endif
+
+	/* Ready to go */
+	sc->status &= ~ATH_STAT_INVALID;
+
+	return 0;
+err_ah:
+	ath5k_hw_detach(sc->ah);
+err_free_hwinfo:
+	free(sc->hwinfo);
+err_free:
+	net80211_free(dev);
+err_map:
+	iounmap(mem);
+err:
+	return ret;
+}
+
+static void ath5k_remove(struct pci_device *pdev)
+{
+	struct net80211_device *dev = pci_get_drvdata(pdev);
+	struct ath5k_softc *sc = dev->priv;
+
+	ath5k_detach(dev);
+	ath5k_hw_detach(sc->ah);
+	iounmap(sc->iobase);
+	free(sc->hwinfo);
+	net80211_free(dev);
+}
+
+
+/***********************\
+* Driver Initialization *
+\***********************/
+
+static int
+ath5k_attach(struct net80211_device *dev)
+{
+	struct ath5k_softc *sc = dev->priv;
+	struct ath5k_hw *ah = sc->ah;
+	int ret;
+
+	/*
+	 * Collect the channel list.  The 802.11 layer
+	 * is resposible for filtering this list based
+	 * on settings like the phy mode and regulatory
+	 * domain restrictions.
+	 */
+	ret = ath5k_setup_bands(dev);
+	if (ret) {
+		DBG("ath5k: can't get channels\n");
+		goto err;
+	}
+
+	/* NB: setup here so ath5k_rate_update is happy */
+	if (ah->ah_modes & AR5K_MODE_BIT_11A)
+		ath5k_setcurmode(sc, AR5K_MODE_11A);
+	else
+		ath5k_setcurmode(sc, AR5K_MODE_11B);
+
+	/*
+	 * Allocate tx+rx descriptors and populate the lists.
+	 */
+	ret = ath5k_desc_alloc(sc);
+	if (ret) {
+		DBG("ath5k: can't allocate descriptors\n");
+		goto err;
+	}
+
+	/*
+	 * Allocate hardware transmit queues. Note that hw functions
+	 * handle reseting these queues at the needed time.
+	 */
+	ret = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BE);
+	if (ret) {
+		DBG("ath5k: can't setup xmit queue\n");
+		goto err_desc;
+	}
+
+	sc->last_calib_ticks = currticks();
+
+	ret = ath5k_eeprom_read_mac(ah, sc->hwinfo->hwaddr);
+	if (ret) {
+		DBG("ath5k: unable to read address from EEPROM: 0x%04x\n",
+		    sc->pdev->device);
+		goto err_queues;
+	}
+
+	memset(sc->bssidmask, 0xff, ETH_ALEN);
+	ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
+
+	ret = net80211_register(sc->dev, &ath5k_ops, sc->hwinfo);
+	if (ret) {
+		DBG("ath5k: can't register ieee80211 hw\n");
+		goto err_queues;
+	}
+
+	return 0;
+err_queues:
+	ath5k_txq_release(sc);
+err_desc:
+	ath5k_desc_free(sc);
+err:
+	return ret;
+}
+
+static void
+ath5k_detach(struct net80211_device *dev)
+{
+	struct ath5k_softc *sc = dev->priv;
+
+	net80211_unregister(dev);
+	ath5k_desc_free(sc);
+	ath5k_txq_release(sc);
+}
+
+
+
+
+/********************\
+* Channel/mode setup *
+\********************/
+
+/*
+ * Convert IEEE channel number to MHz frequency.
+ */
+static inline short
+ath5k_ieee2mhz(short chan)
+{
+	if (chan < 14)
+		return 2407 + 5 * chan;
+	if (chan == 14)
+		return 2484;
+	if (chan < 27)
+		return 2212 + 20 * chan;
+	return 5000 + 5 * chan;
+}
+
+static unsigned int
+ath5k_copy_channels(struct ath5k_hw *ah,
+		    struct net80211_channel *channels,
+		    unsigned int mode, unsigned int max)
+{
+	unsigned int i, count, size, chfreq, freq, ch;
+
+	if (!(ah->ah_modes & (1 << mode)))
+		return 0;
+
+	switch (mode) {
+	case AR5K_MODE_11A:
+	case AR5K_MODE_11A_TURBO:
+		/* 1..220, but 2GHz frequencies are filtered by check_channel */
+		size = 220;
+		chfreq = CHANNEL_5GHZ;
+		break;
+	case AR5K_MODE_11B:
+	case AR5K_MODE_11G:
+	case AR5K_MODE_11G_TURBO:
+		size = 26;
+		chfreq = CHANNEL_2GHZ;
+		break;
+	default:
+		return 0;
+	}
+
+	for (i = 0, count = 0; i < size && max > 0; i++) {
+		ch = i + 1 ;
+		freq = ath5k_ieee2mhz(ch);
+
+		/* Check if channel is supported by the chipset */
+		if (!ath5k_channel_ok(ah, freq, chfreq))
+			continue;
+
+		/* Write channel info and increment counter */
+		channels[count].center_freq = freq;
+		channels[count].maxpower = 0; /* use regulatory */
+		channels[count].band = (chfreq == CHANNEL_2GHZ) ?
+			NET80211_BAND_2GHZ : NET80211_BAND_5GHZ;
+		switch (mode) {
+		case AR5K_MODE_11A:
+		case AR5K_MODE_11G:
+			channels[count].hw_value = chfreq | CHANNEL_OFDM;
+			break;
+		case AR5K_MODE_11A_TURBO:
+		case AR5K_MODE_11G_TURBO:
+			channels[count].hw_value = chfreq |
+				CHANNEL_OFDM | CHANNEL_TURBO;
+			break;
+		case AR5K_MODE_11B:
+			channels[count].hw_value = CHANNEL_B;
+		}
+
+		count++;
+		max--;
+	}
+
+	return count;
+}
+
+static int
+ath5k_setup_bands(struct net80211_device *dev)
+{
+	struct ath5k_softc *sc = dev->priv;
+	struct ath5k_hw *ah = sc->ah;
+	int max_c, count_c = 0;
+	int i;
+	int band;
+
+	max_c = sizeof(sc->hwinfo->channels) / sizeof(sc->hwinfo->channels[0]);
+
+	/* 2GHz band */
+	if (sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11G) {
+		/* G mode */
+		band = NET80211_BAND_2GHZ;
+		sc->hwinfo->bands = NET80211_BAND_BIT_2GHZ;
+		sc->hwinfo->modes = (NET80211_MODE_G | NET80211_MODE_B);
+
+		for (i = 0; i < 12; i++)
+			sc->hwinfo->rates[band][i] = ath5k_rates[i].bitrate;
+		sc->hwinfo->nr_rates[band] = 12;
+
+		sc->hwinfo->nr_channels =
+			ath5k_copy_channels(ah, sc->hwinfo->channels,
+					    AR5K_MODE_11G, max_c);
+		count_c = sc->hwinfo->nr_channels;
+		max_c -= count_c;
+	} else if (sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11B) {
+		/* B mode */
+		band = NET80211_BAND_2GHZ;
+		sc->hwinfo->bands = NET80211_BAND_BIT_2GHZ;
+		sc->hwinfo->modes = NET80211_MODE_B;
+
+		for (i = 0; i < 4; i++)
+			sc->hwinfo->rates[band][i] = ath5k_rates[i].bitrate;
+		sc->hwinfo->nr_rates[band] = 4;
+
+		sc->hwinfo->nr_channels =
+			ath5k_copy_channels(ah, sc->hwinfo->channels,
+					    AR5K_MODE_11B, max_c);
+		count_c = sc->hwinfo->nr_channels;
+		max_c -= count_c;
+	}
+
+	/* 5GHz band, A mode */
+	if (sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11A) {
+		band = NET80211_BAND_5GHZ;
+		sc->hwinfo->bands |= NET80211_BAND_BIT_5GHZ;
+		sc->hwinfo->modes |= NET80211_MODE_A;
+
+		for (i = 0; i < 8; i++)
+			sc->hwinfo->rates[band][i] = ath5k_rates[i+4].bitrate;
+		sc->hwinfo->nr_rates[band] = 8;
+
+		sc->hwinfo->nr_channels =
+			ath5k_copy_channels(ah, sc->hwinfo->channels,
+					    AR5K_MODE_11B, max_c);
+		count_c = sc->hwinfo->nr_channels;
+		max_c -= count_c;
+	}
+
+	return 0;
+}
+
+/*
+ * Set/change channels.  If the channel is really being changed,
+ * it's done by reseting the chip.  To accomplish this we must
+ * first cleanup any pending DMA, then restart stuff after a la
+ * ath5k_init.
+ */
+static int
+ath5k_chan_set(struct ath5k_softc *sc, struct net80211_channel *chan)
+{
+	if (chan->center_freq != sc->curchan->center_freq ||
+	    chan->hw_value != sc->curchan->hw_value) {
+		/*
+		 * To switch channels clear any pending DMA operations;
+		 * wait long enough for the RX fifo to drain, reset the
+		 * hardware at the new frequency, and then re-enable
+		 * the relevant bits of the h/w.
+		 */
+		DBG2("ath5k: resetting for channel change (%d -> %d MHz)\n",
+		     sc->curchan->center_freq, chan->center_freq);
+		return ath5k_reset(sc, chan);
+	}
+
+	return 0;
+}
+
+static void
+ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
+{
+	sc->curmode = mode;
+
+	if (mode == AR5K_MODE_11A) {
+		sc->curband = NET80211_BAND_5GHZ;
+	} else {
+		sc->curband = NET80211_BAND_2GHZ;
+	}
+}
+
+static void
+ath5k_mode_setup(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+	u32 rfilt;
+
+	/* configure rx filter */
+	rfilt = sc->filter_flags;
+	ath5k_hw_set_rx_filter(ah, rfilt);
+
+	if (ath5k_hw_hasbssidmask(ah))
+		ath5k_hw_set_bssid_mask(ah, sc->bssidmask);
+
+	/* configure operational mode */
+	ath5k_hw_set_opmode(ah);
+
+	ath5k_hw_set_mcast_filter(ah, 0, 0);
+}
+
+static inline int
+ath5k_hw_rix_to_bitrate(int hw_rix)
+{
+	int i;
+
+	for (i = 0; i < ATH5K_NR_RATES; i++) {
+		if (ath5k_rates[i].hw_code == hw_rix)
+			return ath5k_rates[i].bitrate;
+	}
+
+	DBG("ath5k: invalid rix %02x\n", hw_rix);
+	return 10;		/* use lowest rate */
+}
+
+int ath5k_bitrate_to_hw_rix(int bitrate)
+{
+	int i;
+
+	for (i = 0; i < ATH5K_NR_RATES; i++) {
+		if (ath5k_rates[i].bitrate == bitrate)
+			return ath5k_rates[i].hw_code;
+	}
+
+	DBG("ath5k: invalid bitrate %d\n", bitrate);
+	return ATH5K_RATE_CODE_1M; /* use lowest rate */
+}
+
+/***************\
+* Buffers setup *
+\***************/
+
+static struct io_buffer *
+ath5k_rx_iob_alloc(struct ath5k_softc *sc, u32 *iob_addr)
+{
+	struct io_buffer *iob;
+	unsigned int off;
+
+	/*
+	 * Allocate buffer with headroom_needed space for the
+	 * fake physical layer header at the start.
+	 */
+	iob = alloc_iob(sc->rxbufsize + sc->cachelsz - 1);
+
+	if (!iob) {
+		DBG("ath5k: can't alloc iobuf of size %d\n",
+		    sc->rxbufsize + sc->cachelsz - 1);
+		return NULL;
+	}
+
+	*iob_addr = virt_to_bus(iob->data);
+
+	/*
+	 * Cache-line-align.  This is important (for the
+	 * 5210 at least) as not doing so causes bogus data
+	 * in rx'd frames.
+	 */
+	off = *iob_addr % sc->cachelsz;
+	if (off != 0) {
+		iob_reserve(iob, sc->cachelsz - off);
+		*iob_addr += sc->cachelsz - off;
+	}
+
+	return iob;
+}
+
+static int
+ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
+{
+	struct ath5k_hw *ah = sc->ah;
+	struct io_buffer *iob = bf->iob;
+	struct ath5k_desc *ds;
+
+	if (!iob) {
+		iob = ath5k_rx_iob_alloc(sc, &bf->iobaddr);
+		if (!iob)
+			return -ENOMEM;
+		bf->iob = iob;
+	}
+
+	/*
+	 * Setup descriptors.  For receive we always terminate
+	 * the descriptor list with a self-linked entry so we'll
+	 * not get overrun under high load (as can happen with a
+	 * 5212 when ANI processing enables PHY error frames).
+	 *
+	 * To insure the last descriptor is self-linked we create
+	 * each descriptor as self-linked and add it to the end.  As
+	 * each additional descriptor is added the previous self-linked
+	 * entry is ``fixed'' naturally.  This should be safe even
+	 * if DMA is happening.  When processing RX interrupts we
+	 * never remove/process the last, self-linked, entry on the
+	 * descriptor list.  This insures the hardware always has
+	 * someplace to write a new frame.
+	 */
+	ds = bf->desc;
+	ds->ds_link = bf->daddr;	/* link to self */
+	ds->ds_data = bf->iobaddr;
+	if (ah->ah_setup_rx_desc(ah, ds,
+				 iob_tailroom(iob),	/* buffer size */
+				 0) != 0) {
+		DBG("ath5k: error setting up RX descriptor for %zd bytes\n", iob_tailroom(iob));
+		return -EINVAL;
+	}
+
+	if (sc->rxlink != NULL)
+		*sc->rxlink = bf->daddr;
+	sc->rxlink = &ds->ds_link;
+	return 0;
+}
+
+static int
+ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
+{
+	struct ath5k_hw *ah = sc->ah;
+	struct ath5k_txq *txq = &sc->txq;
+	struct ath5k_desc *ds = bf->desc;
+	struct io_buffer *iob = bf->iob;
+	unsigned int pktlen, flags;
+	int ret;
+	u16 duration = 0;
+	u16 cts_rate = 0;
+
+	flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
+	bf->iobaddr = virt_to_bus(iob->data);
+	pktlen = iob_len(iob);
+
+	/* FIXME: If we are in g mode and rate is a CCK rate
+	 * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta
+	 * from tx power (value is in dB units already) */
+	if (sc->dev->phy_flags & NET80211_PHY_USE_PROTECTION) {
+		struct net80211_device *dev = sc->dev;
+
+		flags |= AR5K_TXDESC_CTSENA;
+		cts_rate = sc->hw_rtscts_rate;
+		duration = net80211_cts_duration(dev, pktlen);
+	}
+	ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
+				   IEEE80211_TYP_FRAME_HEADER_LEN,
+				   AR5K_PKT_TYPE_NORMAL, sc->power_level * 2,
+				   sc->hw_rate, ATH5K_RETRIES,
+				   AR5K_TXKEYIX_INVALID, 0, flags,
+				   cts_rate, duration);
+	if (ret)
+		return ret;
+
+	ds->ds_link = 0;
+	ds->ds_data = bf->iobaddr;
+
+	list_add_tail(&bf->list, &txq->q);
+	if (txq->link == NULL) /* is this first packet? */
+		ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr);
+	else /* no, so only link it */
+		*txq->link = bf->daddr;
+
+	txq->link = &ds->ds_link;
+	ath5k_hw_start_tx_dma(ah, txq->qnum);
+	mb();
+
+	return 0;
+}
+
+/*******************\
+* Descriptors setup *
+\*******************/
+
+static int
+ath5k_desc_alloc(struct ath5k_softc *sc)
+{
+	struct ath5k_desc *ds;
+	struct ath5k_buf *bf;
+	u32 da;
+	unsigned int i;
+	int ret;
+
+	/* allocate descriptors */
+	sc->desc_len = sizeof(struct ath5k_desc) * (ATH_TXBUF + ATH_RXBUF + 1);
+	sc->desc = malloc_dma(sc->desc_len, ATH5K_DESC_ALIGN);
+	if (sc->desc == NULL) {
+		DBG("ath5k: can't allocate descriptors\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	memset(sc->desc, 0, sc->desc_len);
+	sc->desc_daddr = virt_to_bus(sc->desc);
+
+	ds = sc->desc;
+	da = sc->desc_daddr;
+
+	bf = calloc(ATH_TXBUF + ATH_RXBUF + 1, sizeof(struct ath5k_buf));
+	if (bf == NULL) {
+		DBG("ath5k: can't allocate buffer pointers\n");
+		ret = -ENOMEM;
+		goto err_free;
+	}
+	sc->bufptr = bf;
+
+	INIT_LIST_HEAD(&sc->rxbuf);
+	for (i = 0; i < ATH_RXBUF; i++, bf++, ds++, da += sizeof(*ds)) {
+		bf->desc = ds;
+		bf->daddr = da;
+		list_add_tail(&bf->list, &sc->rxbuf);
+	}
+
+	INIT_LIST_HEAD(&sc->txbuf);
+	sc->txbuf_len = ATH_TXBUF;
+	for (i = 0; i < ATH_TXBUF; i++, bf++, ds++, da += sizeof(*ds)) {
+		bf->desc = ds;
+		bf->daddr = da;
+		list_add_tail(&bf->list, &sc->txbuf);
+	}
+
+	return 0;
+
+err_free:
+	free_dma(sc->desc, sc->desc_len);
+err:
+	sc->desc = NULL;
+	return ret;
+}
+
+static void
+ath5k_desc_free(struct ath5k_softc *sc)
+{
+	struct ath5k_buf *bf;
+
+	list_for_each_entry(bf, &sc->txbuf, list)
+		ath5k_txbuf_free(sc, bf);
+	list_for_each_entry(bf, &sc->rxbuf, list)
+		ath5k_rxbuf_free(sc, bf);
+
+	/* Free memory associated with all descriptors */
+	free_dma(sc->desc, sc->desc_len);
+
+	free(sc->bufptr);
+	sc->bufptr = NULL;
+}
+
+
+
+
+
+/**************\
+* Queues setup *
+\**************/
+
+static int
+ath5k_txq_setup(struct ath5k_softc *sc, int qtype, int subtype)
+{
+	struct ath5k_hw *ah = sc->ah;
+	struct ath5k_txq *txq;
+	struct ath5k_txq_info qi = {
+		.tqi_subtype = subtype,
+		.tqi_aifs = AR5K_TXQ_USEDEFAULT,
+		.tqi_cw_min = AR5K_TXQ_USEDEFAULT,
+		.tqi_cw_max = AR5K_TXQ_USEDEFAULT
+	};
+	int qnum;
+
+	/*
+	 * Enable interrupts only for EOL and DESC conditions.
+	 * We mark tx descriptors to receive a DESC interrupt
+	 * when a tx queue gets deep; otherwise waiting for the
+	 * EOL to reap descriptors.  Note that this is done to
+	 * reduce interrupt load and this only defers reaping
+	 * descriptors, never transmitting frames.  Aside from
+	 * reducing interrupts this also permits more concurrency.
+	 * The only potential downside is if the tx queue backs
+	 * up in which case the top half of the kernel may backup
+	 * due to a lack of tx descriptors.
+	 */
+	qi.tqi_flags = AR5K_TXQ_FLAG_TXEOLINT_ENABLE |
+				AR5K_TXQ_FLAG_TXDESCINT_ENABLE;
+	qnum = ath5k_hw_setup_tx_queue(ah, qtype, &qi);
+	if (qnum < 0) {
+		DBG("ath5k: can't set up a TX queue\n");
+		return -EIO;
+	}
+
+	txq = &sc->txq;
+	if (!txq->setup) {
+		txq->qnum = qnum;
+		txq->link = NULL;
+		INIT_LIST_HEAD(&txq->q);
+		txq->setup = 1;
+	}
+	return 0;
+}
+
+static void
+ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
+{
+	struct ath5k_buf *bf, *bf0;
+
+	list_for_each_entry_safe(bf, bf0, &txq->q, list) {
+		ath5k_txbuf_free(sc, bf);
+
+		list_del(&bf->list);
+		list_add_tail(&bf->list, &sc->txbuf);
+		sc->txbuf_len++;
+	}
+	txq->link = NULL;
+}
+
+/*
+ * Drain the transmit queues and reclaim resources.
+ */
+static void
+ath5k_txq_cleanup(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+
+	if (!(sc->status & ATH_STAT_INVALID)) {
+		/* don't touch the hardware if marked invalid */
+		if (sc->txq.setup) {
+			ath5k_hw_stop_tx_dma(ah, sc->txq.qnum);
+			DBG("ath5k: txq [%d] %x, link %p\n",
+			    sc->txq.qnum,
+			    ath5k_hw_get_txdp(ah, sc->txq.qnum),
+			    sc->txq.link);
+		}
+	}
+
+	if (sc->txq.setup)
+		ath5k_txq_drainq(sc, &sc->txq);
+}
+
+static void
+ath5k_txq_release(struct ath5k_softc *sc)
+{
+	if (sc->txq.setup) {
+		ath5k_hw_release_tx_queue(sc->ah);
+		sc->txq.setup = 0;
+	}
+}
+
+
+
+
+/*************\
+* RX Handling *
+\*************/
+
+/*
+ * Enable the receive h/w following a reset.
+ */
+static int
+ath5k_rx_start(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+	struct ath5k_buf *bf;
+	int ret;
+
+	sc->rxbufsize = IEEE80211_MAX_LEN;
+	if (sc->rxbufsize % sc->cachelsz != 0)
+		sc->rxbufsize += sc->cachelsz - (sc->rxbufsize % sc->cachelsz);
+
+	sc->rxlink = NULL;
+
+	list_for_each_entry(bf, &sc->rxbuf, list) {
+		ret = ath5k_rxbuf_setup(sc, bf);
+		if (ret != 0)
+			return ret;
+	}
+
+	bf = list_entry(sc->rxbuf.next, struct ath5k_buf, list);
+
+	ath5k_hw_set_rxdp(ah, bf->daddr);
+	ath5k_hw_start_rx_dma(ah);	/* enable recv descriptors */
+	ath5k_mode_setup(sc);		/* set filters, etc. */
+	ath5k_hw_start_rx_pcu(ah);	/* re-enable PCU/DMA engine */
+
+	return 0;
+}
+
+/*
+ * Disable the receive h/w in preparation for a reset.
+ */
+static void
+ath5k_rx_stop(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+
+	ath5k_hw_stop_rx_pcu(ah);	/* disable PCU */
+	ath5k_hw_set_rx_filter(ah, 0);	/* clear recv filter */
+	ath5k_hw_stop_rx_dma(ah);	/* disable DMA engine */
+
+	sc->rxlink = NULL;		/* just in case */
+}
+
+static void
+ath5k_handle_rx(struct ath5k_softc *sc)
+{
+	struct ath5k_rx_status rs;
+	struct io_buffer *iob, *next_iob;
+	u32 next_iob_addr;
+	struct ath5k_buf *bf, *bf_last;
+	struct ath5k_desc *ds;
+	int ret;
+
+	memset(&rs, 0, sizeof(rs));
+
+	if (list_empty(&sc->rxbuf)) {
+		DBG("ath5k: empty rx buf pool\n");
+		return;
+	}
+
+	bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list);
+
+	do {
+		bf = list_entry(sc->rxbuf.next, struct ath5k_buf, list);
+		assert(bf->iob != NULL);
+		iob = bf->iob;
+		ds = bf->desc;
+
+		/*
+		 * last buffer must not be freed to ensure proper hardware
+		 * function. When the hardware finishes also a packet next to
+		 * it, we are sure, it doesn't use it anymore and we can go on.
+		 */
+		if (bf_last == bf)
+			bf->flags |= 1;
+		if (bf->flags) {
+			struct ath5k_buf *bf_next = list_entry(bf->list.next,
+					struct ath5k_buf, list);
+			ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc,
+					&rs);
+			if (ret)
+				break;
+			bf->flags &= ~1;
+			/* skip the overwritten one (even status is martian) */
+			goto next;
+		}
+
+		ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs);
+		if (ret) {
+			if (ret != -EINPROGRESS) {
+				DBG("ath5k: error in processing rx desc: %s\n",
+				    strerror(ret));
+				net80211_rx_err(sc->dev, NULL, -ret);
+			} else {
+				/* normal return, reached end of
+				   available descriptors */
+			}
+			return;
+		}
+
+		if (rs.rs_more) {
+			DBG("ath5k: unsupported fragmented rx\n");
+			goto next;
+		}
+
+		if (rs.rs_status) {
+			if (rs.rs_status & AR5K_RXERR_PHY) {
+				/* These are uncommon, and may indicate a real problem. */
+				net80211_rx_err(sc->dev, NULL, EIO);
+				goto next;
+			}
+			if (rs.rs_status & AR5K_RXERR_CRC) {
+				/* These occur *all the time*. */
+				goto next;
+			}
+			if (rs.rs_status & AR5K_RXERR_DECRYPT) {
+				/*
+				 * Decrypt error.  If the error occurred
+				 * because there was no hardware key, then
+				 * let the frame through so the upper layers
+				 * can process it.  This is necessary for 5210
+				 * parts which have no way to setup a ``clear''
+				 * key cache entry.
+				 *
+				 * XXX do key cache faulting
+				 */
+				if (rs.rs_keyix == AR5K_RXKEYIX_INVALID &&
+				    !(rs.rs_status & AR5K_RXERR_CRC))
+					goto accept;
+			}
+
+			/* any other error, unhandled */
+			DBG("ath5k: packet rx status %x\n", rs.rs_status);
+			goto next;
+		}
+accept:
+		next_iob = ath5k_rx_iob_alloc(sc, &next_iob_addr);
+
+		/*
+		 * If we can't replace bf->iob with a new iob under memory
+		 * pressure, just skip this packet
+		 */
+		if (!next_iob) {
+			DBG("ath5k: dropping packet under memory pressure\n");
+			goto next;
+		}
+
+		iob_put(iob, rs.rs_datalen);
+
+		/* The MAC header is padded to have 32-bit boundary if the
+		 * packet payload is non-zero. However, iPXE only
+		 * supports standard 802.11 packets with 24-byte
+		 * header, so no padding correction should be needed.
+		 */
+
+		DBG2("ath5k: rx %d bytes, signal %d\n", rs.rs_datalen,
+		     rs.rs_rssi);
+
+		net80211_rx(sc->dev, iob, rs.rs_rssi,
+			    ath5k_hw_rix_to_bitrate(rs.rs_rate));
+
+		bf->iob = next_iob;
+		bf->iobaddr = next_iob_addr;
+next:
+		list_del(&bf->list);
+		list_add_tail(&bf->list, &sc->rxbuf);
+	} while (ath5k_rxbuf_setup(sc, bf) == 0);
+}
+
+
+
+
+/*************\
+* TX Handling *
+\*************/
+
+static void
+ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
+{
+	struct ath5k_tx_status ts;
+	struct ath5k_buf *bf, *bf0;
+	struct ath5k_desc *ds;
+	struct io_buffer *iob;
+	int ret;
+
+	memset(&ts, 0, sizeof(ts));
+
+	list_for_each_entry_safe(bf, bf0, &txq->q, list) {
+		ds = bf->desc;
+
+		ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts);
+		if (ret) {
+			if (ret != -EINPROGRESS) {
+				DBG("ath5k: error in processing tx desc: %s\n",
+				    strerror(ret));
+			} else {
+				/* normal return, reached end of tx completions */
+			}
+			break;
+		}
+
+		iob = bf->iob;
+		bf->iob = NULL;
+
+		DBG2("ath5k: tx %zd bytes complete, %d retries\n",
+		     iob_len(iob), ts.ts_retry[0]);
+
+		net80211_tx_complete(sc->dev, iob, ts.ts_retry[0],
+				     ts.ts_status ? EIO : 0);
+
+		list_del(&bf->list);
+		list_add_tail(&bf->list, &sc->txbuf);
+		sc->txbuf_len++;
+	}
+
+	if (list_empty(&txq->q))
+		txq->link = NULL;
+}
+
+static void
+ath5k_handle_tx(struct ath5k_softc *sc)
+{
+	ath5k_tx_processq(sc, &sc->txq);
+}
+
+
+/********************\
+* Interrupt handling *
+\********************/
+
+static void
+ath5k_irq(struct net80211_device *dev, int enable)
+{
+	struct ath5k_softc *sc = dev->priv;
+	struct ath5k_hw *ah = sc->ah;
+
+	sc->irq_ena = enable;
+	ah->ah_ier = enable ? AR5K_IER_ENABLE : AR5K_IER_DISABLE;
+
+	ath5k_hw_reg_write(ah, ah->ah_ier, AR5K_IER);
+	ath5k_hw_set_imr(ah, sc->imask);
+}
+
+static int
+ath5k_init(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+	int ret, i;
+
+	/*
+	 * Stop anything previously setup.  This is safe
+	 * no matter this is the first time through or not.
+	 */
+	ath5k_stop_hw(sc);
+
+	/*
+	 * The basic interface to setting the hardware in a good
+	 * state is ``reset''.  On return the hardware is known to
+	 * be powered up and with interrupts disabled.  This must
+	 * be followed by initialization of the appropriate bits
+	 * and then setup of the interrupt mask.
+	 */
+	sc->curchan = sc->dev->channels + sc->dev->channel;
+	sc->curband = sc->curchan->band;
+	sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
+		AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
+		AR5K_INT_FATAL | AR5K_INT_GLOBAL;
+	ret = ath5k_reset(sc, NULL);
+	if (ret)
+		goto done;
+
+	ath5k_rfkill_hw_start(ah);
+
+	/*
+	 * Reset the key cache since some parts do not reset the
+	 * contents on initial power up or resume from suspend.
+	 */
+	for (i = 0; i < AR5K_KEYTABLE_SIZE; i++)
+		ath5k_hw_reset_key(ah, i);
+
+	/* Set ack to be sent at low bit-rates */
+	ath5k_hw_set_ack_bitrate_high(ah, 0);
+
+	ret = 0;
+done:
+	mb();
+	return ret;
+}
+
+static int
+ath5k_stop_hw(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+
+	/*
+	 * Shutdown the hardware and driver:
+	 *    stop output from above
+	 *    disable interrupts
+	 *    turn off timers
+	 *    turn off the radio
+	 *    clear transmit machinery
+	 *    clear receive machinery
+	 *    drain and release tx queues
+	 *    reclaim beacon resources
+	 *    power down hardware
+	 *
+	 * Note that some of this work is not possible if the
+	 * hardware is gone (invalid).
+	 */
+
+	if (!(sc->status & ATH_STAT_INVALID)) {
+		ath5k_hw_set_imr(ah, 0);
+	}
+	ath5k_txq_cleanup(sc);
+	if (!(sc->status & ATH_STAT_INVALID)) {
+		ath5k_rx_stop(sc);
+		ath5k_hw_phy_disable(ah);
+	} else
+		sc->rxlink = NULL;
+
+	ath5k_rfkill_hw_stop(sc->ah);
+
+	return 0;
+}
+
+static void
+ath5k_poll(struct net80211_device *dev)
+{
+	struct ath5k_softc *sc = dev->priv;
+	struct ath5k_hw *ah = sc->ah;
+	enum ath5k_int status;
+	unsigned int counter = 1000;
+
+	if (currticks() - sc->last_calib_ticks >
+	    ATH5K_CALIB_INTERVAL * ticks_per_sec()) {
+		ath5k_calibrate(sc);
+		sc->last_calib_ticks = currticks();
+	}
+
+	if ((sc->status & ATH_STAT_INVALID) ||
+	    (sc->irq_ena && !ath5k_hw_is_intr_pending(ah)))
+		return;
+
+	do {
+		ath5k_hw_get_isr(ah, &status);		/* NB: clears IRQ too */
+		DBGP("ath5k: status %#x/%#x\n", status, sc->imask);
+		if (status & AR5K_INT_FATAL) {
+			/*
+			 * Fatal errors are unrecoverable.
+			 * Typically these are caused by DMA errors.
+			 */
+			DBG("ath5k: fatal error, resetting\n");
+			ath5k_reset_wake(sc);
+		} else if (status & AR5K_INT_RXORN) {
+			DBG("ath5k: rx overrun, resetting\n");
+			ath5k_reset_wake(sc);
+		} else {
+			if (status & AR5K_INT_RXEOL) {
+				/*
+				 * NB: the hardware should re-read the link when
+				 *     RXE bit is written, but it doesn't work at
+				 *     least on older hardware revs.
+				 */
+				DBG("ath5k: rx EOL\n");
+				sc->rxlink = NULL;
+			}
+			if (status & AR5K_INT_TXURN) {
+				/* bump tx trigger level */
+				DBG("ath5k: tx underrun\n");
+				ath5k_hw_update_tx_triglevel(ah, 1);
+			}
+			if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
+				ath5k_handle_rx(sc);
+			if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
+				      | AR5K_INT_TXERR | AR5K_INT_TXEOL))
+				ath5k_handle_tx(sc);
+		}
+	} while (ath5k_hw_is_intr_pending(ah) && counter-- > 0);
+
+	if (!counter)
+		DBG("ath5k: too many interrupts, giving up for now\n");
+}
+
+/*
+ * Periodically recalibrate the PHY to account
+ * for temperature/environment changes.
+ */
+static void
+ath5k_calibrate(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+
+	if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
+		/*
+		 * Rfgain is out of bounds, reset the chip
+		 * to load new gain values.
+		 */
+		DBG("ath5k: resetting for calibration\n");
+		ath5k_reset_wake(sc);
+	}
+	if (ath5k_hw_phy_calibrate(ah, sc->curchan))
+		DBG("ath5k: calibration of channel %d failed\n",
+		    sc->curchan->channel_nr);
+}
+
+
+/********************\
+* Net80211 functions *
+\********************/
+
+static int
+ath5k_tx(struct net80211_device *dev, struct io_buffer *iob)
+{
+	struct ath5k_softc *sc = dev->priv;
+	struct ath5k_buf *bf;
+	int rc;
+
+	/*
+	 * The hardware expects the header padded to 4 byte boundaries.
+	 * iPXE only ever sends 24-byte headers, so no action necessary.
+	 */
+
+	if (list_empty(&sc->txbuf)) {
+		DBG("ath5k: dropping packet because no tx bufs available\n");
+		return -ENOBUFS;
+	}
+
+	bf = list_entry(sc->txbuf.next, struct ath5k_buf, list);
+	list_del(&bf->list);
+	sc->txbuf_len--;
+
+	bf->iob = iob;
+
+	if ((rc = ath5k_txbuf_setup(sc, bf)) != 0) {
+		bf->iob = NULL;
+		list_add_tail(&bf->list, &sc->txbuf);
+		sc->txbuf_len++;
+		return rc;
+	}
+	return 0;
+}
+
+/*
+ * Reset the hardware.  If chan is not NULL, then also pause rx/tx
+ * and change to the given channel.
+ */
+static int
+ath5k_reset(struct ath5k_softc *sc, struct net80211_channel *chan)
+{
+	struct ath5k_hw *ah = sc->ah;
+	int ret;
+
+	if (chan) {
+		ath5k_hw_set_imr(ah, 0);
+		ath5k_txq_cleanup(sc);
+		ath5k_rx_stop(sc);
+
+		sc->curchan = chan;
+		sc->curband = chan->band;
+	}
+
+	ret = ath5k_hw_reset(ah, sc->curchan, 1);
+	if (ret) {
+		DBG("ath5k: can't reset hardware: %s\n", strerror(ret));
+		return ret;
+	}
+
+	ret = ath5k_rx_start(sc);
+	if (ret) {
+		DBG("ath5k: can't start rx logic: %s\n", strerror(ret));
+		return ret;
+	}
+
+	/*
+	 * Change channels and update the h/w rate map if we're switching;
+	 * e.g. 11a to 11b/g.
+	 *
+	 * We may be doing a reset in response to an ioctl that changes the
+	 * channel so update any state that might change as a result.
+	 *
+	 * XXX needed?
+	 */
+/*	ath5k_chan_change(sc, c); */
+
+	/* Reenable interrupts if necessary */
+	ath5k_irq(sc->dev, sc->irq_ena);
+
+	return 0;
+}
+
+static int ath5k_reset_wake(struct ath5k_softc *sc)
+{
+	return ath5k_reset(sc, sc->curchan);
+}
+
+static int ath5k_start(struct net80211_device *dev)
+{
+	struct ath5k_softc *sc = dev->priv;
+	int ret;
+
+	if ((ret = ath5k_init(sc)) != 0)
+		return ret;
+
+	sc->assoc = 0;
+	ath5k_configure_filter(sc);
+	ath5k_hw_set_lladdr(sc->ah, dev->netdev->ll_addr);
+
+	return 0;
+}
+
+static void ath5k_stop(struct net80211_device *dev)
+{
+	struct ath5k_softc *sc = dev->priv;
+	u8 mac[ETH_ALEN] = {};
+
+	ath5k_hw_set_lladdr(sc->ah, mac);
+
+	ath5k_stop_hw(sc);
+}
+
+static int
+ath5k_config(struct net80211_device *dev, int changed)
+{
+	struct ath5k_softc *sc = dev->priv;
+	struct ath5k_hw *ah = sc->ah;
+	struct net80211_channel *chan = &dev->channels[dev->channel];
+	int ret;
+
+	if (changed & NET80211_CFG_CHANNEL) {
+		sc->power_level = chan->maxpower;
+		if ((ret = ath5k_chan_set(sc, chan)) != 0)
+			return ret;
+	}
+
+	if ((changed & NET80211_CFG_RATE) ||
+	    (changed & NET80211_CFG_PHY_PARAMS)) {
+		int spmbl = ATH5K_SPMBL_NO;
+		u16 rate = dev->rates[dev->rate];
+		u16 slowrate = dev->rates[dev->rtscts_rate];
+		int i;
+
+		if (dev->phy_flags & NET80211_PHY_USE_SHORT_PREAMBLE)
+			spmbl = ATH5K_SPMBL_YES;
+
+		for (i = 0; i < ATH5K_NR_RATES; i++) {
+			if (ath5k_rates[i].bitrate == rate &&
+			    (ath5k_rates[i].short_pmbl & spmbl))
+				sc->hw_rate = ath5k_rates[i].hw_code;
+
+			if (ath5k_rates[i].bitrate == slowrate &&
+			    (ath5k_rates[i].short_pmbl & spmbl))
+				sc->hw_rtscts_rate = ath5k_rates[i].hw_code;
+		}
+	}
+
+	if (changed & NET80211_CFG_ASSOC) {
+		sc->assoc = !!(dev->state & NET80211_ASSOCIATED);
+		if (sc->assoc) {
+			memcpy(ah->ah_bssid, dev->bssid, ETH_ALEN);
+		} else {
+			memset(ah->ah_bssid, 0xff, ETH_ALEN);
+		}
+		ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+	}
+
+	return 0;
+}
+
+/*
+ * o always accept unicast, broadcast, and multicast traffic
+ * o multicast traffic for all BSSIDs will be enabled if mac80211
+ *   says it should be
+ * o maintain current state of phy ofdm or phy cck error reception.
+ *   If the hardware detects any of these type of errors then
+ *   ath5k_hw_get_rx_filter() will pass to us the respective
+ *   hardware filters to be able to receive these type of frames.
+ * o probe request frames are accepted only when operating in
+ *   hostap, adhoc, or monitor modes
+ * o enable promiscuous mode according to the interface state
+ * o accept beacons:
+ *   - when operating in adhoc mode so the 802.11 layer creates
+ *     node table entries for peers,
+ *   - when operating in station mode for collecting rssi data when
+ *     the station is otherwise quiet, or
+ *   - when scanning
+ */
+static void ath5k_configure_filter(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+	u32 mfilt[2], rfilt;
+
+	/* Enable all multicast */
+	mfilt[0] = ~0;
+	mfilt[1] = ~0;
+
+	/* Enable data frames and beacons */
+	rfilt = (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
+		 AR5K_RX_FILTER_MCAST | AR5K_RX_FILTER_BEACON);
+
+	/* Set filters */
+	ath5k_hw_set_rx_filter(ah, rfilt);
+
+	/* Set multicast bits */
+	ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
+
+	/* Set the cached hw filter flags, this will alter actually
+	 * be set in HW */
+	sc->filter_flags = rfilt;
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/ath5k.h b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k.h
new file mode 100644
index 0000000000000000000000000000000000000000..30e2024c60307b27d531563c8f7849249760e9a8
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k.h
@@ -0,0 +1,1279 @@
+/*
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>
+ * Original from Linux kernel 2.6.30.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _ATH5K_H
+#define _ATH5K_H
+
+FILE_LICENCE ( MIT );
+
+#include <stddef.h>
+#include <byteswap.h>
+#include <ipxe/io.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/net80211.h>
+#include <errno.h>
+
+/* Keep all ath5k files under one errfile ID */
+#undef ERRFILE
+#define ERRFILE ERRFILE_ath5k
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+
+/* RX/TX descriptor hw structs */
+#include "desc.h"
+
+/* EEPROM structs/offsets */
+#include "eeprom.h"
+
+/* PCI IDs */
+#define PCI_DEVICE_ID_ATHEROS_AR5210 		0x0007 /* AR5210 */
+#define PCI_DEVICE_ID_ATHEROS_AR5311 		0x0011 /* AR5311 */
+#define PCI_DEVICE_ID_ATHEROS_AR5211 		0x0012 /* AR5211 */
+#define PCI_DEVICE_ID_ATHEROS_AR5212 		0x0013 /* AR5212 */
+#define PCI_DEVICE_ID_3COM_3CRDAG675 		0x0013 /* 3CRDAG675 (Atheros AR5212) */
+#define PCI_DEVICE_ID_3COM_2_3CRPAG175 		0x0013 /* 3CRPAG175 (Atheros AR5212) */
+#define PCI_DEVICE_ID_ATHEROS_AR5210_AP 	0x0207 /* AR5210 (Early) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_IBM	0x1014 /* AR5212 (IBM MiniPCI) */
+#define PCI_DEVICE_ID_ATHEROS_AR5210_DEFAULT 	0x1107 /* AR5210 (no eeprom) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_DEFAULT 	0x1113 /* AR5212 (no eeprom) */
+#define PCI_DEVICE_ID_ATHEROS_AR5211_DEFAULT 	0x1112 /* AR5211 (no eeprom) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_FPGA 	0xf013 /* AR5212 (emulation board) */
+#define PCI_DEVICE_ID_ATHEROS_AR5211_LEGACY 	0xff12 /* AR5211 (emulation board) */
+#define PCI_DEVICE_ID_ATHEROS_AR5211_FPGA11B 	0xf11b /* AR5211 (emulation board) */
+#define PCI_DEVICE_ID_ATHEROS_AR5312_REV2 	0x0052 /* AR5312 WMAC (AP31) */
+#define PCI_DEVICE_ID_ATHEROS_AR5312_REV7 	0x0057 /* AR5312 WMAC (AP30-040) */
+#define PCI_DEVICE_ID_ATHEROS_AR5312_REV8 	0x0058 /* AR5312 WMAC (AP43-030) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0014 	0x0014 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0015 	0x0015 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0016 	0x0016 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0017 	0x0017 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0018 	0x0018 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0019 	0x0019 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR2413 		0x001a /* AR2413 (Griffin-lite) */
+#define PCI_DEVICE_ID_ATHEROS_AR5413 		0x001b /* AR5413 (Eagle) */
+#define PCI_DEVICE_ID_ATHEROS_AR5424 		0x001c /* AR5424 (Condor PCI-E) */
+#define PCI_DEVICE_ID_ATHEROS_AR5416 		0x0023 /* AR5416 */
+#define PCI_DEVICE_ID_ATHEROS_AR5418 		0x0024 /* AR5418 */
+
+/****************************\
+  GENERIC DRIVER DEFINITIONS
+\****************************/
+
+/*
+ * AR5K REGISTER ACCESS
+ */
+
+/* Some macros to read/write fields */
+
+/* First shift, then mask */
+#define AR5K_REG_SM(_val, _flags)					\
+	(((_val) << _flags##_S) & (_flags))
+
+/* First mask, then shift */
+#define AR5K_REG_MS(_val, _flags)					\
+	(((_val) & (_flags)) >> _flags##_S)
+
+/* Some registers can hold multiple values of interest. For this
+ * reason when we want to write to these registers we must first
+ * retrieve the values which we do not want to clear (lets call this
+ * old_data) and then set the register with this and our new_value:
+ * ( old_data | new_value) */
+#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val)			\
+	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \
+	    (((_val) << _flags##_S) & (_flags)), _reg)
+
+#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask)			\
+	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) &		\
+			(_mask)) | (_flags), _reg)
+
+#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags)				\
+	ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg)
+
+#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags)			\
+	ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg)
+
+/* Access to PHY registers */
+#define AR5K_PHY_READ(ah, _reg)					\
+	ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2))
+
+#define AR5K_PHY_WRITE(ah, _reg, _val)					\
+	ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2))
+
+/* Access QCU registers per queue */
+#define AR5K_REG_READ_Q(ah, _reg, _queue)				\
+	(ath5k_hw_reg_read(ah, _reg) & (1 << _queue))			\
+
+#define AR5K_REG_WRITE_Q(ah, _reg, _queue)				\
+	ath5k_hw_reg_write(ah, (1 << _queue), _reg)
+
+#define AR5K_Q_ENABLE_BITS(_reg, _queue) do {				\
+	_reg |= 1 << _queue;						\
+} while (0)
+
+#define AR5K_Q_DISABLE_BITS(_reg, _queue) do {				\
+	_reg &= ~(1 << _queue);						\
+} while (0)
+
+/* Used while writing initvals */
+#define AR5K_REG_WAIT(_i) do {						\
+	if (_i % 64)							\
+		udelay(1);						\
+} while (0)
+
+/* Register dumps are done per operation mode */
+#define AR5K_INI_RFGAIN_5GHZ		0
+#define AR5K_INI_RFGAIN_2GHZ		1
+
+/* TODO: Clean this up */
+#define AR5K_INI_VAL_11A		0
+#define AR5K_INI_VAL_11A_TURBO		1
+#define AR5K_INI_VAL_11B		2
+#define AR5K_INI_VAL_11G		3
+#define AR5K_INI_VAL_11G_TURBO		4
+#define AR5K_INI_VAL_XR			0
+#define AR5K_INI_VAL_MAX		5
+
+/* Used for BSSID etc manipulation */
+#define AR5K_LOW_ID(_a)(				\
+(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24	\
+)
+
+#define AR5K_HIGH_ID(_a)	((_a)[4] | (_a)[5] << 8)
+
+#define IEEE80211_MAX_LEN	2352
+
+/*
+ * Some tuneable values (these should be changeable by the user)
+ */
+#define AR5K_TUNE_DMA_BEACON_RESP		2
+#define AR5K_TUNE_SW_BEACON_RESP		10
+#define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF	0
+#define AR5K_TUNE_RADAR_ALERT			0
+#define AR5K_TUNE_MIN_TX_FIFO_THRES		1
+#define AR5K_TUNE_MAX_TX_FIFO_THRES		((IEEE80211_MAX_LEN / 64) + 1)
+#define AR5K_TUNE_REGISTER_TIMEOUT		20000
+/* Register for RSSI threshold has a mask of 0xff, so 255 seems to
+ * be the max value. */
+#define AR5K_TUNE_RSSI_THRES			129
+/* This must be set when setting the RSSI threshold otherwise it can
+ * prevent a reset. If AR5K_RSSI_THR is read after writing to it
+ * the BMISS_THRES will be seen as 0, seems harware doesn't keep
+ * track of it. Max value depends on harware. For AR5210 this is just 7.
+ * For AR5211+ this seems to be up to 255. */
+#define AR5K_TUNE_BMISS_THRES			7
+#define AR5K_TUNE_REGISTER_DWELL_TIME		20000
+#define AR5K_TUNE_BEACON_INTERVAL		100
+#define AR5K_TUNE_AIFS				2
+#define AR5K_TUNE_AIFS_11B			2
+#define AR5K_TUNE_AIFS_XR			0
+#define AR5K_TUNE_CWMIN				15
+#define AR5K_TUNE_CWMIN_11B			31
+#define AR5K_TUNE_CWMIN_XR			3
+#define AR5K_TUNE_CWMAX				1023
+#define AR5K_TUNE_CWMAX_11B			1023
+#define AR5K_TUNE_CWMAX_XR			7
+#define AR5K_TUNE_NOISE_FLOOR			-72
+#define AR5K_TUNE_MAX_TXPOWER			63
+#define AR5K_TUNE_DEFAULT_TXPOWER		25
+#define AR5K_TUNE_TPC_TXPOWER			0
+#define AR5K_TUNE_ANT_DIVERSITY			1
+#define AR5K_TUNE_HWTXTRIES			4
+
+#define AR5K_INIT_CARR_SENSE_EN			1
+
+/*Swap RX/TX Descriptor for big endian archs*/
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define AR5K_INIT_CFG	(		\
+	AR5K_CFG_SWTD | AR5K_CFG_SWRD	\
+)
+#else
+#define AR5K_INIT_CFG	0x00000000
+#endif
+
+/* Initial values */
+#define	AR5K_INIT_CYCRSSI_THR1			2
+#define AR5K_INIT_TX_LATENCY			502
+#define AR5K_INIT_USEC				39
+#define AR5K_INIT_USEC_TURBO			79
+#define AR5K_INIT_USEC_32			31
+#define AR5K_INIT_SLOT_TIME			396
+#define AR5K_INIT_SLOT_TIME_TURBO		480
+#define AR5K_INIT_ACK_CTS_TIMEOUT		1024
+#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO		0x08000800
+#define AR5K_INIT_PROG_IFS			920
+#define AR5K_INIT_PROG_IFS_TURBO		960
+#define AR5K_INIT_EIFS				3440
+#define AR5K_INIT_EIFS_TURBO			6880
+#define AR5K_INIT_SIFS				560
+#define AR5K_INIT_SIFS_TURBO			480
+#define AR5K_INIT_SH_RETRY			10
+#define AR5K_INIT_LG_RETRY			AR5K_INIT_SH_RETRY
+#define AR5K_INIT_SSH_RETRY			32
+#define AR5K_INIT_SLG_RETRY			AR5K_INIT_SSH_RETRY
+#define AR5K_INIT_TX_RETRY			10
+
+#define AR5K_INIT_TRANSMIT_LATENCY		(			\
+	(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |	\
+	(AR5K_INIT_USEC)						\
+)
+#define AR5K_INIT_TRANSMIT_LATENCY_TURBO	(			\
+	(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |	\
+	(AR5K_INIT_USEC_TURBO)						\
+)
+#define AR5K_INIT_PROTO_TIME_CNTRL		(			\
+	(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) |	\
+	(AR5K_INIT_PROG_IFS)						\
+)
+#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO	(			\
+	(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \
+	(AR5K_INIT_PROG_IFS_TURBO)					\
+)
+
+/* token to use for aifs, cwmin, cwmax in MadWiFi */
+#define	AR5K_TXQ_USEDEFAULT	((u32) -1)
+
+/* GENERIC CHIPSET DEFINITIONS */
+
+/* MAC Chips */
+enum ath5k_version {
+	AR5K_AR5210	= 0,
+	AR5K_AR5211	= 1,
+	AR5K_AR5212	= 2,
+};
+
+/* PHY Chips */
+enum ath5k_radio {
+	AR5K_RF5110	= 0,
+	AR5K_RF5111	= 1,
+	AR5K_RF5112	= 2,
+	AR5K_RF2413	= 3,
+	AR5K_RF5413	= 4,
+	AR5K_RF2316	= 5,
+	AR5K_RF2317	= 6,
+	AR5K_RF2425	= 7,
+};
+
+/*
+ * Common silicon revision/version values
+ */
+
+enum ath5k_srev_type {
+	AR5K_VERSION_MAC,
+	AR5K_VERSION_RAD,
+};
+
+struct ath5k_srev_name {
+	const char		*sr_name;
+	enum ath5k_srev_type	sr_type;
+	unsigned		sr_val;
+};
+
+#define AR5K_SREV_UNKNOWN	0xffff
+
+#define AR5K_SREV_AR5210	0x00 /* Crete */
+#define AR5K_SREV_AR5311	0x10 /* Maui 1 */
+#define AR5K_SREV_AR5311A	0x20 /* Maui 2 */
+#define AR5K_SREV_AR5311B	0x30 /* Spirit */
+#define AR5K_SREV_AR5211	0x40 /* Oahu */
+#define AR5K_SREV_AR5212	0x50 /* Venice */
+#define AR5K_SREV_AR5213	0x55 /* ??? */
+#define AR5K_SREV_AR5213A	0x59 /* Hainan */
+#define AR5K_SREV_AR2413	0x78 /* Griffin lite */
+#define AR5K_SREV_AR2414	0x70 /* Griffin */
+#define AR5K_SREV_AR5424	0x90 /* Condor */
+#define AR5K_SREV_AR5413	0xa4 /* Eagle lite */
+#define AR5K_SREV_AR5414	0xa0 /* Eagle */
+#define AR5K_SREV_AR2415	0xb0 /* Talon */
+#define AR5K_SREV_AR5416	0xc0 /* PCI-E */
+#define AR5K_SREV_AR5418	0xca /* PCI-E */
+#define AR5K_SREV_AR2425	0xe0 /* Swan */
+#define AR5K_SREV_AR2417	0xf0 /* Nala */
+
+#define AR5K_SREV_RAD_5110	0x00
+#define AR5K_SREV_RAD_5111	0x10
+#define AR5K_SREV_RAD_5111A	0x15
+#define AR5K_SREV_RAD_2111	0x20
+#define AR5K_SREV_RAD_5112	0x30
+#define AR5K_SREV_RAD_5112A	0x35
+#define	AR5K_SREV_RAD_5112B	0x36
+#define AR5K_SREV_RAD_2112	0x40
+#define AR5K_SREV_RAD_2112A	0x45
+#define	AR5K_SREV_RAD_2112B	0x46
+#define AR5K_SREV_RAD_2413	0x50
+#define AR5K_SREV_RAD_5413	0x60
+#define AR5K_SREV_RAD_2316	0x70 /* Cobra SoC */
+#define AR5K_SREV_RAD_2317	0x80
+#define AR5K_SREV_RAD_5424	0xa0 /* Mostly same as 5413 */
+#define AR5K_SREV_RAD_2425	0xa2
+#define AR5K_SREV_RAD_5133	0xc0
+
+#define AR5K_SREV_PHY_5211	0x30
+#define AR5K_SREV_PHY_5212	0x41
+#define	AR5K_SREV_PHY_5212A	0x42
+#define AR5K_SREV_PHY_5212B	0x43
+#define AR5K_SREV_PHY_2413	0x45
+#define AR5K_SREV_PHY_5413	0x61
+#define AR5K_SREV_PHY_2425	0x70
+
+/*
+ * Some of this information is based on Documentation from:
+ *
+ * http://madwifi.org/wiki/ChipsetFeatures/SuperAG
+ *
+ * Modulation for Atheros' eXtended Range - range enhancing extension that is
+ * supposed to double the distance an Atheros client device can keep a
+ * connection with an Atheros access point. This is achieved by increasing
+ * the receiver sensitivity up to, -105dBm, which is about 20dB above what
+ * the 802.11 specifications demand. In addition, new (proprietary) data rates
+ * are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s.
+ *
+ * Please note that can you either use XR or TURBO but you cannot use both,
+ * they are exclusive.
+ *
+ */
+#define MODULATION_XR 		0x00000200
+
+/*
+ * Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a
+ * throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s
+ * signaling rate achieved through the bonding of two 54Mbit/s 802.11g
+ * channels. To use this feature your Access Point must also suport it.
+ * There is also a distinction between "static" and "dynamic" turbo modes:
+ *
+ * - Static: is the dumb version: devices set to this mode stick to it until
+ *     the mode is turned off.
+ * - Dynamic: is the intelligent version, the network decides itself if it
+ *     is ok to use turbo. As soon as traffic is detected on adjacent channels
+ *     (which would get used in turbo mode), or when a non-turbo station joins
+ *     the network, turbo mode won't be used until the situation changes again.
+ *     Dynamic mode is achieved by Atheros' Adaptive Radio (AR) feature which
+ *     monitors the used radio band in order to decide whether turbo mode may
+ *     be used or not.
+ *
+ * This article claims Super G sticks to bonding of channels 5 and 6 for
+ * USA:
+ *
+ * http://www.pcworld.com/article/id,113428-page,1/article.html
+ *
+ * The channel bonding seems to be driver specific though. In addition to
+ * deciding what channels will be used, these "Turbo" modes are accomplished
+ * by also enabling the following features:
+ *
+ * - Bursting: allows multiple frames to be sent at once, rather than pausing
+ *     after each frame. Bursting is a standards-compliant feature that can be
+ *     used with any Access Point.
+ * - Fast frames: increases the amount of information that can be sent per
+ *     frame, also resulting in a reduction of transmission overhead. It is a
+ *     proprietary feature that needs to be supported by the Access Point.
+ * - Compression: data frames are compressed in real time using a Lempel Ziv
+ *     algorithm. This is done transparently. Once this feature is enabled,
+ *     compression and decompression takes place inside the chipset, without
+ *     putting additional load on the host CPU.
+ *
+ */
+#define MODULATION_TURBO	0x00000080
+
+enum ath5k_driver_mode {
+	AR5K_MODE_11A		= 0,
+	AR5K_MODE_11A_TURBO	= 1,
+	AR5K_MODE_11B		= 2,
+	AR5K_MODE_11G		= 3,
+	AR5K_MODE_11G_TURBO	= 4,
+	AR5K_MODE_XR		= 5,
+};
+
+enum {
+	AR5K_MODE_BIT_11A	= (1 << AR5K_MODE_11A),
+	AR5K_MODE_BIT_11A_TURBO	= (1 << AR5K_MODE_11A_TURBO),
+	AR5K_MODE_BIT_11B	= (1 << AR5K_MODE_11B),
+	AR5K_MODE_BIT_11G	= (1 << AR5K_MODE_11G),
+	AR5K_MODE_BIT_11G_TURBO	= (1 << AR5K_MODE_11G_TURBO),
+	AR5K_MODE_BIT_XR	= (1 << AR5K_MODE_XR),
+};
+
+/****************\
+  TX DEFINITIONS
+\****************/
+
+/*
+ * TX Status descriptor
+ */
+struct ath5k_tx_status {
+	u16	ts_seqnum;
+	u16	ts_tstamp;
+	u8	ts_status;
+	u8	ts_rate[4];
+	u8	ts_retry[4];
+	u8	ts_final_idx;
+	s8	ts_rssi;
+	u8	ts_shortretry;
+	u8	ts_longretry;
+	u8	ts_virtcol;
+	u8	ts_antenna;
+} __attribute__ ((packed));
+
+#define AR5K_TXSTAT_ALTRATE	0x80
+#define AR5K_TXERR_XRETRY	0x01
+#define AR5K_TXERR_FILT		0x02
+#define AR5K_TXERR_FIFO		0x04
+
+/**
+ * enum ath5k_tx_queue - Queue types used to classify tx queues.
+ * @AR5K_TX_QUEUE_INACTIVE: q is unused -- see ath5k_hw_release_tx_queue
+ * @AR5K_TX_QUEUE_DATA: A normal data queue
+ * @AR5K_TX_QUEUE_XR_DATA: An XR-data queue
+ * @AR5K_TX_QUEUE_BEACON: The beacon queue
+ * @AR5K_TX_QUEUE_CAB: The after-beacon queue
+ * @AR5K_TX_QUEUE_UAPSD: Unscheduled Automatic Power Save Delivery queue
+ */
+enum ath5k_tx_queue {
+	AR5K_TX_QUEUE_INACTIVE = 0,
+	AR5K_TX_QUEUE_DATA,
+	AR5K_TX_QUEUE_XR_DATA,
+	AR5K_TX_QUEUE_BEACON,
+	AR5K_TX_QUEUE_CAB,
+	AR5K_TX_QUEUE_UAPSD,
+};
+
+/*
+ * Queue syb-types to classify normal data queues.
+ * These are the 4 Access Categories as defined in
+ * WME spec. 0 is the lowest priority and 4 is the
+ * highest. Normal data that hasn't been classified
+ * goes to the Best Effort AC.
+ */
+enum ath5k_tx_queue_subtype {
+	AR5K_WME_AC_BK = 0,	/*Background traffic*/
+	AR5K_WME_AC_BE, 	/*Best-effort (normal) traffic)*/
+	AR5K_WME_AC_VI, 	/*Video traffic*/
+	AR5K_WME_AC_VO, 	/*Voice traffic*/
+};
+
+/*
+ * Queue ID numbers as returned by the hw functions, each number
+ * represents a hw queue. If hw does not support hw queues
+ * (eg 5210) all data goes in one queue. These match
+ * d80211 definitions (net80211/MadWiFi don't use them).
+ */
+enum ath5k_tx_queue_id {
+	AR5K_TX_QUEUE_ID_NOQCU_DATA	= 0,
+	AR5K_TX_QUEUE_ID_NOQCU_BEACON	= 1,
+	AR5K_TX_QUEUE_ID_DATA_MIN	= 0, /*IEEE80211_TX_QUEUE_DATA0*/
+	AR5K_TX_QUEUE_ID_DATA_MAX	= 4, /*IEEE80211_TX_QUEUE_DATA4*/
+	AR5K_TX_QUEUE_ID_DATA_SVP	= 5, /*IEEE80211_TX_QUEUE_SVP - Spectralink Voice Protocol*/
+	AR5K_TX_QUEUE_ID_CAB		= 6, /*IEEE80211_TX_QUEUE_AFTER_BEACON*/
+	AR5K_TX_QUEUE_ID_BEACON		= 7, /*IEEE80211_TX_QUEUE_BEACON*/
+	AR5K_TX_QUEUE_ID_UAPSD		= 8,
+	AR5K_TX_QUEUE_ID_XR_DATA	= 9,
+};
+
+/*
+ * Flags to set hw queue's parameters...
+ */
+#define AR5K_TXQ_FLAG_TXOKINT_ENABLE		0x0001	/* Enable TXOK interrupt */
+#define AR5K_TXQ_FLAG_TXERRINT_ENABLE		0x0002	/* Enable TXERR interrupt */
+#define AR5K_TXQ_FLAG_TXEOLINT_ENABLE		0x0004	/* Enable TXEOL interrupt -not used- */
+#define AR5K_TXQ_FLAG_TXDESCINT_ENABLE		0x0008	/* Enable TXDESC interrupt -not used- */
+#define AR5K_TXQ_FLAG_TXURNINT_ENABLE		0x0010	/* Enable TXURN interrupt */
+#define AR5K_TXQ_FLAG_CBRORNINT_ENABLE		0x0020	/* Enable CBRORN interrupt */
+#define AR5K_TXQ_FLAG_CBRURNINT_ENABLE		0x0040	/* Enable CBRURN interrupt */
+#define AR5K_TXQ_FLAG_QTRIGINT_ENABLE		0x0080	/* Enable QTRIG interrupt */
+#define AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE		0x0100	/* Enable TXNOFRM interrupt */
+#define AR5K_TXQ_FLAG_BACKOFF_DISABLE		0x0200	/* Disable random post-backoff */
+#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE	0x0300	/* Enable ready time expiry policy (?)*/
+#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE	0x0800	/* Enable backoff while bursting */
+#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS		0x1000	/* Disable backoff while bursting */
+#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE	0x2000	/* Enable hw compression -not implemented-*/
+
+/*
+ * A struct to hold tx queue's parameters
+ */
+struct ath5k_txq_info {
+	enum ath5k_tx_queue tqi_type;
+	enum ath5k_tx_queue_subtype tqi_subtype;
+	u16	tqi_flags;	/* Tx queue flags (see above) */
+	u32	tqi_aifs;	/* Arbitrated Interframe Space */
+	s32	tqi_cw_min;	/* Minimum Contention Window */
+	s32	tqi_cw_max;	/* Maximum Contention Window */
+	u32	tqi_cbr_period; /* Constant bit rate period */
+	u32	tqi_cbr_overflow_limit;
+	u32	tqi_burst_time;
+	u32	tqi_ready_time; /* Not used */
+};
+
+/*
+ * Transmit packet types.
+ * used on tx control descriptor
+ * TODO: Use them inside base.c corectly
+ */
+enum ath5k_pkt_type {
+	AR5K_PKT_TYPE_NORMAL		= 0,
+	AR5K_PKT_TYPE_ATIM		= 1,
+	AR5K_PKT_TYPE_PSPOLL		= 2,
+	AR5K_PKT_TYPE_BEACON		= 3,
+	AR5K_PKT_TYPE_PROBE_RESP	= 4,
+	AR5K_PKT_TYPE_PIFS		= 5,
+};
+
+/*
+ * TX power and TPC settings
+ */
+#define AR5K_TXPOWER_OFDM(_r, _v)	(			\
+	((0 & 1) << ((_v) + 6)) |				\
+	(((ah->ah_txpower.txp_rates_power_table[(_r)]) & 0x3f) << (_v))	\
+)
+
+#define AR5K_TXPOWER_CCK(_r, _v)	(			\
+	(ah->ah_txpower.txp_rates_power_table[(_r)] & 0x3f) << (_v)	\
+)
+
+/*
+ * DMA size definitions (2^n+2)
+ */
+enum ath5k_dmasize {
+	AR5K_DMASIZE_4B	= 0,
+	AR5K_DMASIZE_8B,
+	AR5K_DMASIZE_16B,
+	AR5K_DMASIZE_32B,
+	AR5K_DMASIZE_64B,
+	AR5K_DMASIZE_128B,
+	AR5K_DMASIZE_256B,
+	AR5K_DMASIZE_512B
+};
+
+
+/****************\
+  RX DEFINITIONS
+\****************/
+
+/*
+ * RX Status descriptor
+ */
+struct ath5k_rx_status {
+	u16	rs_datalen;
+	u16	rs_tstamp;
+	u8	rs_status;
+	u8	rs_phyerr;
+	s8	rs_rssi;
+	u8	rs_keyix;
+	u8	rs_rate;
+	u8	rs_antenna;
+	u8	rs_more;
+};
+
+#define AR5K_RXERR_CRC		0x01
+#define AR5K_RXERR_PHY		0x02
+#define AR5K_RXERR_FIFO		0x04
+#define AR5K_RXERR_DECRYPT	0x08
+#define AR5K_RXERR_MIC		0x10
+#define AR5K_RXKEYIX_INVALID	((u8) - 1)
+#define AR5K_TXKEYIX_INVALID	((u32) - 1)
+
+
+/*
+ * TSF to TU conversion:
+ *
+ * TSF is a 64bit value in usec (microseconds).
+ * TU is a 32bit value and defined by IEEE802.11 (page 6) as "A measurement of
+ * time equal to 1024 usec", so it's roughly milliseconds (usec / 1024).
+ */
+#define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10)
+
+
+/*******************************\
+  GAIN OPTIMIZATION DEFINITIONS
+\*******************************/
+
+enum ath5k_rfgain {
+	AR5K_RFGAIN_INACTIVE = 0,
+	AR5K_RFGAIN_ACTIVE,
+	AR5K_RFGAIN_READ_REQUESTED,
+	AR5K_RFGAIN_NEED_CHANGE,
+};
+
+struct ath5k_gain {
+	u8			g_step_idx;
+	u8			g_current;
+	u8			g_target;
+	u8			g_low;
+	u8			g_high;
+	u8			g_f_corr;
+	u8			g_state;
+};
+
+/********************\
+  COMMON DEFINITIONS
+\********************/
+
+#define AR5K_SLOT_TIME_9	396
+#define AR5K_SLOT_TIME_20	880
+#define AR5K_SLOT_TIME_MAX	0xffff
+
+/* channel_flags */
+#define	CHANNEL_CW_INT	0x0008	/* Contention Window interference detected */
+#define	CHANNEL_TURBO	0x0010	/* Turbo Channel */
+#define	CHANNEL_CCK	0x0020	/* CCK channel */
+#define	CHANNEL_OFDM	0x0040	/* OFDM channel */
+#define	CHANNEL_2GHZ	0x0080	/* 2GHz channel. */
+#define	CHANNEL_5GHZ	0x0100	/* 5GHz channel */
+#define	CHANNEL_PASSIVE	0x0200	/* Only passive scan allowed */
+#define	CHANNEL_DYN	0x0400	/* Dynamic CCK-OFDM channel (for g operation) */
+#define	CHANNEL_XR	0x0800	/* XR channel */
+
+#define	CHANNEL_A	(CHANNEL_5GHZ|CHANNEL_OFDM)
+#define	CHANNEL_B	(CHANNEL_2GHZ|CHANNEL_CCK)
+#define	CHANNEL_G	(CHANNEL_2GHZ|CHANNEL_OFDM)
+#define	CHANNEL_T	(CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
+#define	CHANNEL_TG	(CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
+#define	CHANNEL_108A	CHANNEL_T
+#define	CHANNEL_108G	CHANNEL_TG
+#define	CHANNEL_X	(CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR)
+
+#define	CHANNEL_ALL 	(CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_2GHZ|CHANNEL_5GHZ| \
+		CHANNEL_TURBO)
+
+#define	CHANNEL_ALL_NOTURBO 	(CHANNEL_ALL & ~CHANNEL_TURBO)
+#define CHANNEL_MODES		CHANNEL_ALL
+
+/*
+ * Used internaly for reset_tx_queue).
+ * Also see struct struct net80211_channel.
+ */
+#define IS_CHAN_XR(_c)	((_c->hw_value & CHANNEL_XR) != 0)
+#define IS_CHAN_B(_c)	((_c->hw_value & CHANNEL_B) != 0)
+
+/*
+ * The following structure is used to map 2GHz channels to
+ * 5GHz Atheros channels.
+ * TODO: Clean up
+ */
+struct ath5k_athchan_2ghz {
+	u32	a2_flags;
+	u16	a2_athchan;
+};
+
+
+/******************\
+  RATE DEFINITIONS
+\******************/
+
+/**
+ * Seems the ar5xxx harware supports up to 32 rates, indexed by 1-32.
+ *
+ * The rate code is used to get the RX rate or set the TX rate on the
+ * hardware descriptors. It is also used for internal modulation control
+ * and settings.
+ *
+ * This is the hardware rate map we are aware of:
+ *
+ * rate_code   0x01    0x02    0x03    0x04    0x05    0x06    0x07    0x08
+ * rate_kbps   3000    1000    ?       ?       ?       2000    500     48000
+ *
+ * rate_code   0x09    0x0A    0x0B    0x0C    0x0D    0x0E    0x0F    0x10
+ * rate_kbps   24000   12000   6000    54000   36000   18000   9000    ?
+ *
+ * rate_code   17      18      19      20      21      22      23      24
+ * rate_kbps   ?       ?       ?       ?       ?       ?       ?       11000
+ *
+ * rate_code   25      26      27      28      29      30      31      32
+ * rate_kbps   5500    2000    1000    11000S  5500S   2000S   ?       ?
+ *
+ * "S" indicates CCK rates with short preamble.
+ *
+ * AR5211 has different rate codes for CCK (802.11B) rates. It only uses the
+ * lowest 4 bits, so they are the same as below with a 0xF mask.
+ * (0xB, 0xA, 0x9 and 0x8 for 1M, 2M, 5.5M and 11M).
+ * We handle this in ath5k_setup_bands().
+ */
+#define AR5K_MAX_RATES 32
+
+/* B */
+#define ATH5K_RATE_CODE_1M	0x1B
+#define ATH5K_RATE_CODE_2M	0x1A
+#define ATH5K_RATE_CODE_5_5M	0x19
+#define ATH5K_RATE_CODE_11M	0x18
+/* A and G */
+#define ATH5K_RATE_CODE_6M	0x0B
+#define ATH5K_RATE_CODE_9M	0x0F
+#define ATH5K_RATE_CODE_12M	0x0A
+#define ATH5K_RATE_CODE_18M	0x0E
+#define ATH5K_RATE_CODE_24M	0x09
+#define ATH5K_RATE_CODE_36M	0x0D
+#define ATH5K_RATE_CODE_48M	0x08
+#define ATH5K_RATE_CODE_54M	0x0C
+/* XR */
+#define ATH5K_RATE_CODE_XR_500K	0x07
+#define ATH5K_RATE_CODE_XR_1M	0x02
+#define ATH5K_RATE_CODE_XR_2M	0x06
+#define ATH5K_RATE_CODE_XR_3M	0x01
+
+/* adding this flag to rate_code enables short preamble */
+#define AR5K_SET_SHORT_PREAMBLE 0x04
+
+/*
+ * Crypto definitions
+ */
+
+#define AR5K_KEYCACHE_SIZE	8
+
+/***********************\
+ HW RELATED DEFINITIONS
+\***********************/
+
+/*
+ * Misc definitions
+ */
+#define	AR5K_RSSI_EP_MULTIPLIER	(1<<7)
+
+#define AR5K_ASSERT_ENTRY(_e, _s) do {		\
+	if (_e >= _s)				\
+		return 0;			\
+} while (0)
+
+/*
+ * Hardware interrupt abstraction
+ */
+
+/**
+ * enum ath5k_int - Hardware interrupt masks helpers
+ *
+ * @AR5K_INT_RX: mask to identify received frame interrupts, of type
+ * 	AR5K_ISR_RXOK or AR5K_ISR_RXERR
+ * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?)
+ * @AR5K_INT_RXNOFRM: No frame received (?)
+ * @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The
+ * 	Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's
+ * 	LinkPtr is NULL. For more details, refer to:
+ * 	http://www.freepatentsonline.com/20030225739.html
+ * @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors).
+ * 	Note that Rx overrun is not always fatal, on some chips we can continue
+ * 	operation without reseting the card, that's why int_fatal is not
+ * 	common for all chips.
+ * @AR5K_INT_TX: mask to identify received frame interrupts, of type
+ * 	AR5K_ISR_TXOK or AR5K_ISR_TXERR
+ * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?)
+ * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold
+ * 	We currently do increments on interrupt by
+ * 	(AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2
+ * @AR5K_INT_MIB: Indicates the Management Information Base counters should be
+ * 	checked. We should do this with ath5k_hw_update_mib_counters() but
+ * 	it seems we should also then do some noise immunity work.
+ * @AR5K_INT_RXPHY: RX PHY Error
+ * @AR5K_INT_RXKCM: RX Key cache miss
+ * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a
+ * 	beacon that must be handled in software. The alternative is if you
+ * 	have VEOL support, in that case you let the hardware deal with things.
+ * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing
+ * 	beacons from the AP have associated with, we should probably try to
+ * 	reassociate. When in IBSS mode this might mean we have not received
+ * 	any beacons from any local stations. Note that every station in an
+ * 	IBSS schedules to send beacons at the Target Beacon Transmission Time
+ * 	(TBTT) with a random backoff.
+ * @AR5K_INT_BNR: Beacon Not Ready interrupt - ??
+ * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now
+ * 	until properly handled
+ * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA
+ * 	errors. These types of errors we can enable seem to be of type
+ * 	AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR.
+ * @AR5K_INT_GLOBAL: Used to clear and set the IER
+ * @AR5K_INT_NOCARD: signals the card has been removed
+ * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same
+ * 	bit value
+ *
+ * These are mapped to take advantage of some common bits
+ * between the MACs, to be able to set intr properties
+ * easier. Some of them are not used yet inside hw.c. Most map
+ * to the respective hw interrupt value as they are common amogst different
+ * MACs.
+ */
+enum ath5k_int {
+	AR5K_INT_RXOK	= 0x00000001,
+	AR5K_INT_RXDESC	= 0x00000002,
+	AR5K_INT_RXERR	= 0x00000004,
+	AR5K_INT_RXNOFRM = 0x00000008,
+	AR5K_INT_RXEOL	= 0x00000010,
+	AR5K_INT_RXORN	= 0x00000020,
+	AR5K_INT_TXOK	= 0x00000040,
+	AR5K_INT_TXDESC	= 0x00000080,
+	AR5K_INT_TXERR	= 0x00000100,
+	AR5K_INT_TXNOFRM = 0x00000200,
+	AR5K_INT_TXEOL	= 0x00000400,
+	AR5K_INT_TXURN	= 0x00000800,
+	AR5K_INT_MIB	= 0x00001000,
+	AR5K_INT_SWI	= 0x00002000,
+	AR5K_INT_RXPHY	= 0x00004000,
+	AR5K_INT_RXKCM	= 0x00008000,
+	AR5K_INT_SWBA	= 0x00010000,
+	AR5K_INT_BRSSI	= 0x00020000,
+	AR5K_INT_BMISS	= 0x00040000,
+	AR5K_INT_FATAL	= 0x00080000, /* Non common */
+	AR5K_INT_BNR	= 0x00100000, /* Non common */
+	AR5K_INT_TIM	= 0x00200000, /* Non common */
+	AR5K_INT_DTIM	= 0x00400000, /* Non common */
+	AR5K_INT_DTIM_SYNC =	0x00800000, /* Non common */
+	AR5K_INT_GPIO	=	0x01000000,
+	AR5K_INT_BCN_TIMEOUT =	0x02000000, /* Non common */
+	AR5K_INT_CAB_TIMEOUT =	0x04000000, /* Non common */
+	AR5K_INT_RX_DOPPLER =	0x08000000, /* Non common */
+	AR5K_INT_QCBRORN =	0x10000000, /* Non common */
+	AR5K_INT_QCBRURN =	0x20000000, /* Non common */
+	AR5K_INT_QTRIG	=	0x40000000, /* Non common */
+	AR5K_INT_GLOBAL =	0x80000000,
+
+	AR5K_INT_COMMON  = AR5K_INT_RXOK
+		| AR5K_INT_RXDESC
+		| AR5K_INT_RXERR
+		| AR5K_INT_RXNOFRM
+		| AR5K_INT_RXEOL
+		| AR5K_INT_RXORN
+		| AR5K_INT_TXOK
+		| AR5K_INT_TXDESC
+		| AR5K_INT_TXERR
+		| AR5K_INT_TXNOFRM
+		| AR5K_INT_TXEOL
+		| AR5K_INT_TXURN
+		| AR5K_INT_MIB
+		| AR5K_INT_SWI
+		| AR5K_INT_RXPHY
+		| AR5K_INT_RXKCM
+		| AR5K_INT_SWBA
+		| AR5K_INT_BRSSI
+		| AR5K_INT_BMISS
+		| AR5K_INT_GPIO
+		| AR5K_INT_GLOBAL,
+
+	AR5K_INT_NOCARD	= 0xffffffff
+};
+
+/*
+ * Power management
+ */
+enum ath5k_power_mode {
+	AR5K_PM_UNDEFINED = 0,
+	AR5K_PM_AUTO,
+	AR5K_PM_AWAKE,
+	AR5K_PM_FULL_SLEEP,
+	AR5K_PM_NETWORK_SLEEP,
+};
+
+/* GPIO-controlled software LED */
+#define AR5K_SOFTLED_PIN	0
+#define AR5K_SOFTLED_ON		0
+#define AR5K_SOFTLED_OFF	1
+
+/*
+ * Chipset capabilities -see ath5k_hw_get_capability-
+ * get_capability function is not yet fully implemented
+ * in ath5k so most of these don't work yet...
+ * TODO: Implement these & merge with _TUNE_ stuff above
+ */
+enum ath5k_capability_type {
+	AR5K_CAP_REG_DMN		= 0,	/* Used to get current reg. domain id */
+	AR5K_CAP_TKIP_MIC		= 2,	/* Can handle TKIP MIC in hardware */
+	AR5K_CAP_TKIP_SPLIT		= 3,	/* TKIP uses split keys */
+	AR5K_CAP_PHYCOUNTERS		= 4,	/* PHY error counters */
+	AR5K_CAP_DIVERSITY		= 5,	/* Supports fast diversity */
+	AR5K_CAP_NUM_TXQUEUES		= 6,	/* Used to get max number of hw txqueues */
+	AR5K_CAP_VEOL			= 7,	/* Supports virtual EOL */
+	AR5K_CAP_COMPRESSION		= 8,	/* Supports compression */
+	AR5K_CAP_BURST			= 9,	/* Supports packet bursting */
+	AR5K_CAP_FASTFRAME		= 10,	/* Supports fast frames */
+	AR5K_CAP_TXPOW			= 11,	/* Used to get global tx power limit */
+	AR5K_CAP_TPC			= 12,	/* Can do per-packet tx power control (needed for 802.11a) */
+	AR5K_CAP_BSSIDMASK		= 13,	/* Supports bssid mask */
+	AR5K_CAP_MCAST_KEYSRCH		= 14,	/* Supports multicast key search */
+	AR5K_CAP_TSF_ADJUST		= 15,	/* Supports beacon tsf adjust */
+	AR5K_CAP_XR			= 16,	/* Supports XR mode */
+	AR5K_CAP_WME_TKIPMIC 		= 17,	/* Supports TKIP MIC when using WMM */
+	AR5K_CAP_CHAN_HALFRATE 		= 18,	/* Supports half rate channels */
+	AR5K_CAP_CHAN_QUARTERRATE 	= 19,	/* Supports quarter rate channels */
+	AR5K_CAP_RFSILENT		= 20,	/* Supports RFsilent */
+};
+
+
+/* XXX: we *may* move cap_range stuff to struct wiphy */
+struct ath5k_capabilities {
+	/*
+	 * Supported PHY modes
+	 * (ie. CHANNEL_A, CHANNEL_B, ...)
+	 */
+	u16 cap_mode;
+
+	/*
+	 * Frequency range (without regulation restrictions)
+	 */
+	struct {
+		u16	range_2ghz_min;
+		u16	range_2ghz_max;
+		u16	range_5ghz_min;
+		u16	range_5ghz_max;
+	} cap_range;
+
+	/*
+	 * Values stored in the EEPROM (some of them...)
+	 */
+	struct ath5k_eeprom_info	cap_eeprom;
+
+	/*
+	 * Queue information
+	 */
+	struct {
+		u8	q_tx_num;
+	} cap_queues;
+};
+
+
+/***************************************\
+  HARDWARE ABSTRACTION LAYER STRUCTURE
+\***************************************/
+
+/*
+ * Misc defines
+ */
+
+#define AR5K_MAX_GPIO		10
+#define AR5K_MAX_RF_BANKS	8
+
+/* TODO: Clean up and merge with ath5k_softc */
+struct ath5k_hw {
+	struct ath5k_softc	*ah_sc;
+	void			*ah_iobase;
+
+	enum ath5k_int		ah_imr;
+	int			ah_ier;
+
+	struct net80211_channel	*ah_current_channel;
+	int			ah_turbo;
+	int			ah_calibration;
+	int			ah_running;
+	int			ah_single_chip;
+	int			ah_combined_mic;
+
+	u32			ah_mac_srev;
+	u16			ah_mac_version;
+	u16			ah_mac_revision;
+	u16			ah_phy_revision;
+	u16			ah_radio_5ghz_revision;
+	u16			ah_radio_2ghz_revision;
+
+	enum ath5k_version	ah_version;
+	enum ath5k_radio	ah_radio;
+	u32			ah_phy;
+
+	int			ah_5ghz;
+	int			ah_2ghz;
+
+#define ah_regdomain		ah_capabilities.cap_regdomain.reg_current
+#define ah_regdomain_hw		ah_capabilities.cap_regdomain.reg_hw
+#define ah_modes		ah_capabilities.cap_mode
+#define ah_ee_version		ah_capabilities.cap_eeprom.ee_version
+
+	u32			ah_atim_window;
+	u32			ah_aifs;
+	u32			ah_cw_min;
+	u32			ah_cw_max;
+	int			ah_software_retry;
+	u32			ah_limit_tx_retries;
+
+	u32			ah_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
+	int			ah_ant_diversity;
+
+	u8			ah_sta_id[ETH_ALEN];
+
+	/* Current BSSID we are trying to assoc to / create.
+	 * This is passed by mac80211 on config_interface() and cached here for
+	 * use in resets */
+	u8			ah_bssid[ETH_ALEN];
+	u8			ah_bssid_mask[ETH_ALEN];
+
+	u32			ah_gpio[AR5K_MAX_GPIO];
+	int			ah_gpio_npins;
+
+	struct ath5k_capabilities ah_capabilities;
+
+	struct ath5k_txq_info	ah_txq;
+	u32			ah_txq_status;
+	u32			ah_txq_imr_txok;
+	u32			ah_txq_imr_txerr;
+	u32			ah_txq_imr_txurn;
+	u32			ah_txq_imr_txdesc;
+	u32			ah_txq_imr_txeol;
+	u32			ah_txq_imr_cbrorn;
+	u32			ah_txq_imr_cbrurn;
+	u32			ah_txq_imr_qtrig;
+	u32			ah_txq_imr_nofrm;
+	u32			ah_txq_isr;
+	u32			*ah_rf_banks;
+	size_t			ah_rf_banks_size;
+	size_t			ah_rf_regs_count;
+	struct ath5k_gain	ah_gain;
+	u8			ah_offset[AR5K_MAX_RF_BANKS];
+
+
+	struct {
+		/* Temporary tables used for interpolation */
+		u8		tmpL[AR5K_EEPROM_N_PD_GAINS]
+					[AR5K_EEPROM_POWER_TABLE_SIZE];
+		u8		tmpR[AR5K_EEPROM_N_PD_GAINS]
+					[AR5K_EEPROM_POWER_TABLE_SIZE];
+		u8		txp_pd_table[AR5K_EEPROM_POWER_TABLE_SIZE * 2];
+		u16		txp_rates_power_table[AR5K_MAX_RATES];
+		u8		txp_min_idx;
+		int		txp_tpc;
+		/* Values in 0.25dB units */
+		s16		txp_min_pwr;
+		s16		txp_max_pwr;
+		s16		txp_offset;
+		s16		txp_ofdm;
+		/* Values in dB units */
+		s16		txp_cck_ofdm_pwr_delta;
+		s16		txp_cck_ofdm_gainf_delta;
+	} ah_txpower;
+
+	/* noise floor from last periodic calibration */
+	s32			ah_noise_floor;
+
+	/*
+	 * Function pointers
+	 */
+	int (*ah_setup_rx_desc)(struct ath5k_hw *ah, struct ath5k_desc *desc,
+				u32 size, unsigned int flags);
+	int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
+		unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
+		unsigned int, unsigned int, unsigned int, unsigned int,
+		unsigned int, unsigned int, unsigned int);
+	int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
+		struct ath5k_tx_status *);
+	int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *,
+		struct ath5k_rx_status *);
+};
+
+/*
+ * Prototypes
+ */
+
+extern int ath5k_bitrate_to_hw_rix(int bitrate);
+
+/* Attach/Detach Functions */
+extern int ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version, struct ath5k_hw **ah);
+extern void ath5k_hw_detach(struct ath5k_hw *ah);
+
+/* LED functions */
+extern int ath5k_init_leds(struct ath5k_softc *sc);
+extern void ath5k_led_enable(struct ath5k_softc *sc);
+extern void ath5k_led_off(struct ath5k_softc *sc);
+extern void ath5k_unregister_leds(struct ath5k_softc *sc);
+
+/* Reset Functions */
+extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, int initial);
+extern int ath5k_hw_reset(struct ath5k_hw *ah, struct net80211_channel *channel, int change_channel);
+/* Power management functions */
+extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, int set_chip, u16 sleep_duration);
+
+/* DMA Related Functions */
+extern void ath5k_hw_start_rx_dma(struct ath5k_hw *ah);
+extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah);
+extern u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah);
+extern void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr);
+extern int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue);
+extern int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue);
+extern u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue);
+extern int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue,
+				u32 phys_addr);
+extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, int increase);
+/* Interrupt handling */
+extern int ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
+extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
+extern enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask);
+
+/* EEPROM access functions */
+extern int ath5k_eeprom_init(struct ath5k_hw *ah);
+extern void ath5k_eeprom_detach(struct ath5k_hw *ah);
+extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
+extern int ath5k_eeprom_is_hb63(struct ath5k_hw *ah);
+
+/* Protocol Control Unit Functions */
+extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
+/* BSSID Functions */
+extern void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac);
+extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
+extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id);
+extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
+/* Receive start/stop functions */
+extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
+extern void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah);
+/* RX Filter functions */
+extern void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1);
+extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah);
+extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter);
+/* ACK bit rate */
+void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, int high);
+/* ACK/CTS Timeouts */
+extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout);
+extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah);
+extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout);
+extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah);
+/* Key table (WEP) functions */
+extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry);
+
+/* Queue Control Unit, DFS Control Unit Functions */
+extern int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, const struct ath5k_txq_info *queue_info);
+extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah,
+				enum ath5k_tx_queue queue_type,
+				struct ath5k_txq_info *queue_info);
+extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah);
+extern void ath5k_hw_release_tx_queue(struct ath5k_hw *ah);
+extern int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah);
+extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
+
+/* Hardware Descriptor Functions */
+extern int ath5k_hw_init_desc_functions(struct ath5k_hw *ah);
+
+/* GPIO Functions */
+extern int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio);
+extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio);
+extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio);
+extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val);
+extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level);
+
+/* rfkill Functions */
+extern void ath5k_rfkill_hw_start(struct ath5k_hw *ah);
+extern void ath5k_rfkill_hw_stop(struct ath5k_hw *ah);
+
+/* Misc functions */
+int ath5k_hw_set_capabilities(struct ath5k_hw *ah);
+extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result);
+extern int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, u16 assoc_id);
+extern int ath5k_hw_disable_pspoll(struct ath5k_hw *ah);
+
+/* Initial register settings functions */
+extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, int change_channel);
+
+/* Initialize RF */
+extern int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
+				struct net80211_channel *channel,
+				unsigned int mode);
+extern int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq);
+extern enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah);
+extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
+/* PHY/RF channel functions */
+extern int ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
+extern int ath5k_hw_channel(struct ath5k_hw *ah, struct net80211_channel *channel);
+/* PHY calibration */
+extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct net80211_channel *channel);
+extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
+/* Misc PHY functions */
+extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
+extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant);
+extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah);
+extern int ath5k_hw_phy_disable(struct ath5k_hw *ah);
+/* TX power setup */
+extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct net80211_channel *channel, u8 ee_mode, u8 txpower);
+extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 ee_mode, u8 txpower);
+
+/*
+ * Functions used internaly
+ */
+
+/*
+ * Translate usec to hw clock units
+ * TODO: Half/quarter rate
+ */
+static inline unsigned int ath5k_hw_htoclock(unsigned int usec, int turbo)
+{
+	return turbo ? (usec * 80) : (usec * 40);
+}
+
+/*
+ * Translate hw clock units to usec
+ * TODO: Half/quarter rate
+ */
+static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, int turbo)
+{
+	return turbo ? (clock / 80) : (clock / 40);
+}
+
+/*
+ * Read from a register
+ */
+static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
+{
+	return readl(ah->ah_iobase + reg);
+}
+
+/*
+ * Write to a register
+ */
+static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
+{
+	writel(val, ah->ah_iobase + reg);
+}
+
+#if defined(_ATH5K_RESET) || defined(_ATH5K_PHY)
+/*
+ * Check if a register write has been completed
+ */
+static int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag,
+		u32 val, int is_set)
+{
+	int i;
+	u32 data;
+
+	for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
+		data = ath5k_hw_reg_read(ah, reg);
+		if (is_set && (data & flag))
+			break;
+		else if ((data & flag) == val)
+			break;
+		udelay(15);
+	}
+
+	return (i <= 0) ? -EAGAIN : 0;
+}
+
+/*
+ * Convert channel frequency to channel number
+ */
+static inline int ath5k_freq_to_channel(int freq)
+{
+	if (freq == 2484)
+		return 14;
+
+	if (freq < 2484)
+		return (freq - 2407) / 5;
+
+	return freq/5 - 1000;
+}
+
+#endif
+
+static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
+{
+	u32 retval = 0, bit, i;
+
+	for (i = 0; i < bits; i++) {
+		bit = (val >> i) & 1;
+		retval = (retval << 1) | bit;
+	}
+
+	return retval;
+}
+
+#endif
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_attach.c b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_attach.c
new file mode 100644
index 0000000000000000000000000000000000000000..302536dbd093ef218e20d20ca86da33af0b4a9a5
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_attach.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>
+ * Original from Linux kernel 2.6.30.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/*************************************\
+* Attach/Detach Functions and helpers *
+\*************************************/
+
+#include <ipxe/pci.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/**
+ * ath5k_hw_post - Power On Self Test helper function
+ *
+ * @ah: The &struct ath5k_hw
+ */
+static int ath5k_hw_post(struct ath5k_hw *ah)
+{
+
+	static const u32 static_pattern[4] = {
+		0x55555555,	0xaaaaaaaa,
+		0x66666666,	0x99999999
+	};
+	static const u16 regs[2] = { AR5K_STA_ID0, AR5K_PHY(8) };
+	int i, c;
+	u16 cur_reg;
+	u32 var_pattern;
+	u32 init_val;
+	u32 cur_val;
+
+	for (c = 0; c < 2; c++) {
+
+		cur_reg = regs[c];
+
+		/* Save previous value */
+		init_val = ath5k_hw_reg_read(ah, cur_reg);
+
+		for (i = 0; i < 256; i++) {
+			var_pattern = i << 16 | i;
+			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
+			cur_val = ath5k_hw_reg_read(ah, cur_reg);
+
+			if (cur_val != var_pattern) {
+				DBG("ath5k: POST failed!\n");
+				return -EAGAIN;
+			}
+
+			/* Found on ndiswrapper dumps */
+			var_pattern = 0x0039080f;
+			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
+		}
+
+		for (i = 0; i < 4; i++) {
+			var_pattern = static_pattern[i];
+			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
+			cur_val = ath5k_hw_reg_read(ah, cur_reg);
+
+			if (cur_val != var_pattern) {
+				DBG("ath5k: POST failed!\n");
+				return -EAGAIN;
+			}
+
+			/* Found on ndiswrapper dumps */
+			var_pattern = 0x003b080f;
+			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
+		}
+
+		/* Restore previous value */
+		ath5k_hw_reg_write(ah, init_val, cur_reg);
+
+	}
+
+	return 0;
+
+}
+
+/**
+ * ath5k_hw_attach - Check if hw is supported and init the needed structs
+ *
+ * @sc: The &struct ath5k_softc we got from the driver's attach function
+ * @mac_version: The mac version id (check out ath5k.h) based on pci id
+ * @hw: Returned newly allocated hardware structure, on success
+ *
+ * Check if the device is supported, perform a POST and initialize the needed
+ * structs. Returns -ENOMEM if we don't have memory for the needed structs,
+ * -ENODEV if the device is not supported or prints an error msg if something
+ * else went wrong.
+ */
+int ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version,
+		    struct ath5k_hw **hw)
+{
+	struct ath5k_hw *ah;
+	struct pci_device *pdev = sc->pdev;
+	int ret;
+	u32 srev;
+
+	ah = zalloc(sizeof(struct ath5k_hw));
+	if (ah == NULL) {
+		ret = -ENOMEM;
+		DBG("ath5k: out of memory\n");
+		goto err;
+	}
+
+	ah->ah_sc = sc;
+	ah->ah_iobase = sc->iobase;
+
+	/*
+	 * HW information
+	 */
+	ah->ah_turbo = 0;
+	ah->ah_txpower.txp_tpc = 0;
+	ah->ah_imr = 0;
+	ah->ah_atim_window = 0;
+	ah->ah_aifs = AR5K_TUNE_AIFS;
+	ah->ah_cw_min = AR5K_TUNE_CWMIN;
+	ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
+	ah->ah_software_retry = 0;
+	ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY;
+
+	/*
+	 * Set the mac version based on the pci id
+	 */
+	ah->ah_version = mac_version;
+
+	/*Fill the ath5k_hw struct with the needed functions*/
+	ret = ath5k_hw_init_desc_functions(ah);
+	if (ret)
+		goto err_free;
+
+	/* Bring device out of sleep and reset it's units */
+	ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, 1);
+	if (ret)
+		goto err_free;
+
+	/* Get MAC, PHY and RADIO revisions */
+	srev = ath5k_hw_reg_read(ah, AR5K_SREV);
+	ah->ah_mac_srev = srev;
+	ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
+	ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
+	ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID);
+	ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, CHANNEL_5GHZ);
+	ah->ah_phy = AR5K_PHY(0);
+
+	/* Try to identify radio chip based on it's srev */
+	switch (ah->ah_radio_5ghz_revision & 0xf0) {
+	case AR5K_SREV_RAD_5111:
+		ah->ah_radio = AR5K_RF5111;
+		ah->ah_single_chip = 0;
+		ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
+							CHANNEL_2GHZ);
+		break;
+	case AR5K_SREV_RAD_5112:
+	case AR5K_SREV_RAD_2112:
+		ah->ah_radio = AR5K_RF5112;
+		ah->ah_single_chip = 0;
+		ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
+							CHANNEL_2GHZ);
+		break;
+	case AR5K_SREV_RAD_2413:
+		ah->ah_radio = AR5K_RF2413;
+		ah->ah_single_chip = 1;
+		break;
+	case AR5K_SREV_RAD_5413:
+		ah->ah_radio = AR5K_RF5413;
+		ah->ah_single_chip = 1;
+		break;
+	case AR5K_SREV_RAD_2316:
+		ah->ah_radio = AR5K_RF2316;
+		ah->ah_single_chip = 1;
+		break;
+	case AR5K_SREV_RAD_2317:
+		ah->ah_radio = AR5K_RF2317;
+		ah->ah_single_chip = 1;
+		break;
+	case AR5K_SREV_RAD_5424:
+		if (ah->ah_mac_version == AR5K_SREV_AR2425 ||
+		    ah->ah_mac_version == AR5K_SREV_AR2417) {
+			ah->ah_radio = AR5K_RF2425;
+		} else {
+			ah->ah_radio = AR5K_RF5413;
+		}
+		ah->ah_single_chip = 1;
+		break;
+	default:
+		/* Identify radio based on mac/phy srev */
+		if (ah->ah_version == AR5K_AR5210) {
+			ah->ah_radio = AR5K_RF5110;
+			ah->ah_single_chip = 0;
+		} else if (ah->ah_version == AR5K_AR5211) {
+			ah->ah_radio = AR5K_RF5111;
+			ah->ah_single_chip = 0;
+			ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
+								CHANNEL_2GHZ);
+		} else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) ||
+			   ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) ||
+			   ah->ah_phy_revision == AR5K_SREV_PHY_2425) {
+			ah->ah_radio = AR5K_RF2425;
+			ah->ah_single_chip = 1;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425;
+		} else if (srev == AR5K_SREV_AR5213A &&
+			   ah->ah_phy_revision == AR5K_SREV_PHY_5212B) {
+			ah->ah_radio = AR5K_RF5112;
+			ah->ah_single_chip = 0;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5112B;
+		} else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4)) {
+			ah->ah_radio = AR5K_RF2316;
+			ah->ah_single_chip = 1;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316;
+		} else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) ||
+			   ah->ah_phy_revision == AR5K_SREV_PHY_5413) {
+			ah->ah_radio = AR5K_RF5413;
+			ah->ah_single_chip = 1;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413;
+		} else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) ||
+			   ah->ah_phy_revision == AR5K_SREV_PHY_2413) {
+			ah->ah_radio = AR5K_RF2413;
+			ah->ah_single_chip = 1;
+			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413;
+		} else {
+			DBG("ath5k: Couldn't identify radio revision.\n");
+			ret = -ENOTSUP;
+			goto err_free;
+		}
+	}
+
+	/* Return on unsuported chips (unsupported eeprom etc) */
+	if ((srev >= AR5K_SREV_AR5416) &&
+	    (srev < AR5K_SREV_AR2425)) {
+		DBG("ath5k: Device not yet supported.\n");
+		ret = -ENOTSUP;
+		goto err_free;
+	}
+
+	/*
+	 * Write PCI-E power save settings
+	 */
+	if ((ah->ah_version == AR5K_AR5212) &&
+	    pci_find_capability(pdev, PCI_CAP_ID_EXP)) {
+		ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
+		ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
+		/* Shut off RX when elecidle is asserted */
+		ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES);
+		ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES);
+		/* TODO: EEPROM work */
+		ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES);
+		/* Shut off PLL and CLKREQ active in L1 */
+		ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES);
+		/* Preserce other settings */
+		ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES);
+		ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES);
+		ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES);
+		/* Reset SERDES to load new settings */
+		ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET);
+		mdelay(1);
+	}
+
+	/*
+	 * POST
+	 */
+	ret = ath5k_hw_post(ah);
+	if (ret)
+		goto err_free;
+
+	/* Enable pci core retry fix on Hainan (5213A) and later chips */
+	if (srev >= AR5K_SREV_AR5213A)
+		ath5k_hw_reg_write(ah, AR5K_PCICFG_RETRY_FIX, AR5K_PCICFG);
+
+	/*
+	 * Get card capabilities, calibration values etc
+	 * TODO: EEPROM work
+	 */
+	ret = ath5k_eeprom_init(ah);
+	if (ret) {
+		DBG("ath5k: unable to init EEPROM\n");
+		goto err_free;
+	}
+
+	/* Get misc capabilities */
+	ret = ath5k_hw_set_capabilities(ah);
+	if (ret) {
+		DBG("ath5k: unable to get device capabilities: 0x%04x\n",
+		    sc->pdev->device);
+		goto err_free;
+	}
+
+	if (srev >= AR5K_SREV_AR2414) {
+		ah->ah_combined_mic = 1;
+		AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE,
+				     AR5K_MISC_MODE_COMBINED_MIC);
+	}
+
+	/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
+	memset(ah->ah_bssid, 0xff, ETH_ALEN);
+	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+	ath5k_hw_set_opmode(ah);
+
+	ath5k_hw_rfgain_opt_init(ah);
+
+	*hw = ah;
+	return 0;
+err_free:
+	free(ah);
+err:
+	return ret;
+}
+
+/**
+ * ath5k_hw_detach - Free the ath5k_hw struct
+ *
+ * @ah: The &struct ath5k_hw
+ */
+void ath5k_hw_detach(struct ath5k_hw *ah)
+{
+	free(ah->ah_rf_banks);
+	ath5k_eeprom_detach(ah);
+	free(ah);
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_caps.c b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_caps.c
new file mode 100644
index 0000000000000000000000000000000000000000..9c00d15d771b166f587b365305aed2ecb6a33171
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_caps.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/**************\
+* Capabilities *
+\**************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*
+ * Fill the capabilities struct
+ * TODO: Merge this with EEPROM code when we are done with it
+ */
+int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
+{
+	u16 ee_header;
+
+	/* Capabilities stored in the EEPROM */
+	ee_header = ah->ah_capabilities.cap_eeprom.ee_header;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		/*
+		 * Set radio capabilities
+		 * (The AR5110 only supports the middle 5GHz band)
+		 */
+		ah->ah_capabilities.cap_range.range_5ghz_min = 5120;
+		ah->ah_capabilities.cap_range.range_5ghz_max = 5430;
+		ah->ah_capabilities.cap_range.range_2ghz_min = 0;
+		ah->ah_capabilities.cap_range.range_2ghz_max = 0;
+
+		/* Set supported modes */
+		ah->ah_capabilities.cap_mode |= AR5K_MODE_BIT_11A;
+		ah->ah_capabilities.cap_mode |= AR5K_MODE_BIT_11A_TURBO;
+	} else {
+		/*
+		 * XXX The tranceiver supports frequencies from 4920 to 6100GHz
+		 * XXX and from 2312 to 2732GHz. There are problems with the
+		 * XXX current ieee80211 implementation because the IEEE
+		 * XXX channel mapping does not support negative channel
+		 * XXX numbers (2312MHz is channel -19). Of course, this
+		 * XXX doesn't matter because these channels are out of range
+		 * XXX but some regulation domains like MKK (Japan) will
+		 * XXX support frequencies somewhere around 4.8GHz.
+		 */
+
+		/*
+		 * Set radio capabilities
+		 */
+
+		if (AR5K_EEPROM_HDR_11A(ee_header)) {
+			/* 4920 */
+			ah->ah_capabilities.cap_range.range_5ghz_min = 5005;
+			ah->ah_capabilities.cap_range.range_5ghz_max = 6100;
+
+			/* Set supported modes */
+			ah->ah_capabilities.cap_mode |= AR5K_MODE_BIT_11A;
+			ah->ah_capabilities.cap_mode |= AR5K_MODE_BIT_11A_TURBO;
+			if (ah->ah_version == AR5K_AR5212)
+				ah->ah_capabilities.cap_mode |=
+					AR5K_MODE_BIT_11G_TURBO;
+		}
+
+		/* Enable  802.11b if a 2GHz capable radio (2111/5112) is
+		 * connected */
+		if (AR5K_EEPROM_HDR_11B(ee_header) ||
+		    (AR5K_EEPROM_HDR_11G(ee_header) &&
+		     ah->ah_version != AR5K_AR5211)) {
+			/* 2312 */
+			ah->ah_capabilities.cap_range.range_2ghz_min = 2412;
+			ah->ah_capabilities.cap_range.range_2ghz_max = 2732;
+
+			if (AR5K_EEPROM_HDR_11B(ee_header))
+				ah->ah_capabilities.cap_mode |=
+					AR5K_MODE_BIT_11B;
+
+			if (AR5K_EEPROM_HDR_11G(ee_header) &&
+			    ah->ah_version != AR5K_AR5211)
+				ah->ah_capabilities.cap_mode |=
+					AR5K_MODE_BIT_11G;
+		}
+	}
+
+	/* GPIO */
+	ah->ah_gpio_npins = AR5K_NUM_GPIO;
+
+	/* Set number of supported TX queues */
+	ah->ah_capabilities.cap_queues.q_tx_num = 1;
+
+	return 0;
+}
+
+/* Main function used by the driver part to check caps */
+int ath5k_hw_get_capability(struct ath5k_hw *ah,
+		enum ath5k_capability_type cap_type,
+		u32 capability __unused, u32 *result)
+{
+	switch (cap_type) {
+	case AR5K_CAP_NUM_TXQUEUES:
+		if (result) {
+			*result = 1;
+			goto yes;
+		}
+	case AR5K_CAP_VEOL:
+		goto yes;
+	case AR5K_CAP_COMPRESSION:
+		if (ah->ah_version == AR5K_AR5212)
+			goto yes;
+		else
+			goto no;
+	case AR5K_CAP_BURST:
+		goto yes;
+	case AR5K_CAP_TPC:
+		goto yes;
+	case AR5K_CAP_BSSIDMASK:
+		if (ah->ah_version == AR5K_AR5212)
+			goto yes;
+		else
+			goto no;
+	case AR5K_CAP_XR:
+		if (ah->ah_version == AR5K_AR5212)
+			goto yes;
+		else
+			goto no;
+	default:
+		goto no;
+	}
+
+no:
+	return -EINVAL;
+yes:
+	return 0;
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_desc.c b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_desc.c
new file mode 100644
index 0000000000000000000000000000000000000000..30fe1c77704a7988f69190b327ea488fda349f29
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_desc.c
@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/******************************\
+ Hardware Descriptor Functions
+\******************************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*
+ * TX Descriptors
+ */
+
+#define FCS_LEN	4
+
+/*
+ * Initialize the 2-word tx control descriptor on 5210/5211
+ */
+static int
+ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+	unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type,
+	unsigned int tx_power __unused, unsigned int tx_rate0, unsigned int tx_tries0,
+	unsigned int key_index __unused, unsigned int antenna_mode, unsigned int flags,
+	unsigned int rtscts_rate __unused, unsigned int rtscts_duration)
+{
+	u32 frame_type;
+	struct ath5k_hw_2w_tx_ctl *tx_ctl;
+	unsigned int frame_len;
+
+	tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
+
+	/*
+	 * Validate input
+	 * - Zero retries don't make sense.
+	 * - A zero rate will put the HW into a mode where it continously sends
+	 *   noise on the channel, so it is important to avoid this.
+	 */
+	if (tx_tries0 == 0) {
+		DBG("ath5k: zero retries\n");
+		return -EINVAL;
+	}
+	if (tx_rate0 == 0) {
+		DBG("ath5k: zero rate\n");
+		return -EINVAL;
+	}
+
+	/* Clear descriptor */
+	memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc));
+
+	/* Setup control descriptor */
+
+	/* Verify and set frame length */
+
+	frame_len = pkt_len + FCS_LEN;
+
+	if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
+		return -EINVAL;
+
+	tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
+
+	/* Verify and set buffer length */
+
+	if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
+		return -EINVAL;
+
+	tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
+
+	/*
+	 * Verify and set header length
+	 * XXX: I only found that on 5210 code, does it work on 5211 ?
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN)
+			return -EINVAL;
+		tx_ctl->tx_control_0 |=
+			AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN);
+	}
+
+	/*Diferences between 5210-5211*/
+	if (ah->ah_version == AR5K_AR5210) {
+		switch (type) {
+		case AR5K_PKT_TYPE_BEACON:
+		case AR5K_PKT_TYPE_PROBE_RESP:
+			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY;
+		case AR5K_PKT_TYPE_PIFS:
+			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS;
+		default:
+			frame_type = type /*<< 2 ?*/;
+		}
+
+		tx_ctl->tx_control_0 |=
+		AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) |
+		AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
+
+	} else {
+		tx_ctl->tx_control_0 |=
+			AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) |
+			AR5K_REG_SM(antenna_mode,
+				AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT);
+		tx_ctl->tx_control_1 |=
+			AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE);
+	}
+#define _TX_FLAGS(_c, _flag)					\
+	if (flags & AR5K_TXDESC_##_flag) {			\
+		tx_ctl->tx_control_##_c |=			\
+			AR5K_2W_TX_DESC_CTL##_c##_##_flag;	\
+	}
+
+	_TX_FLAGS(0, CLRDMASK);
+	_TX_FLAGS(0, VEOL);
+	_TX_FLAGS(0, INTREQ);
+	_TX_FLAGS(0, RTSENA);
+	_TX_FLAGS(1, NOACK);
+
+#undef _TX_FLAGS
+
+	/*
+	 * RTS/CTS Duration [5210 ?]
+	 */
+	if ((ah->ah_version == AR5K_AR5210) &&
+			(flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)))
+		tx_ctl->tx_control_1 |= rtscts_duration &
+				AR5K_2W_TX_DESC_CTL1_RTS_DURATION;
+
+	return 0;
+}
+
+/*
+ * Initialize the 4-word tx control descriptor on 5212
+ */
+static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
+	struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len __unused,
+	enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0,
+	unsigned int tx_tries0, unsigned int key_index __unused,
+	unsigned int antenna_mode, unsigned int flags,
+	unsigned int rtscts_rate,
+	unsigned int rtscts_duration)
+{
+	struct ath5k_hw_4w_tx_ctl *tx_ctl;
+	unsigned int frame_len;
+
+	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
+
+	/*
+	 * Validate input
+	 * - Zero retries don't make sense.
+	 * - A zero rate will put the HW into a mode where it continously sends
+	 *   noise on the channel, so it is important to avoid this.
+	 */
+	if (tx_tries0 == 0) {
+		DBG("ath5k: zero retries\n");
+		return -EINVAL;
+	}
+	if (tx_rate0 == 0) {
+		DBG("ath5k: zero rate\n");
+		return -EINVAL;
+	}
+
+	tx_power += ah->ah_txpower.txp_offset;
+	if (tx_power > AR5K_TUNE_MAX_TXPOWER)
+		tx_power = AR5K_TUNE_MAX_TXPOWER;
+
+	/* Clear descriptor */
+	memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc));
+
+	/* Setup control descriptor */
+
+	/* Verify and set frame length */
+
+	frame_len = pkt_len + FCS_LEN;
+
+	if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
+		return -EINVAL;
+
+	tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
+
+	/* Verify and set buffer length */
+
+	if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
+		return -EINVAL;
+
+	tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
+
+	tx_ctl->tx_control_0 |=
+		AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
+		AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
+	tx_ctl->tx_control_1 |= AR5K_REG_SM(type,
+					AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
+	tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES,
+					AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
+	tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+
+#define _TX_FLAGS(_c, _flag)					\
+	if (flags & AR5K_TXDESC_##_flag) {			\
+		tx_ctl->tx_control_##_c |=			\
+			AR5K_4W_TX_DESC_CTL##_c##_##_flag;	\
+	}
+
+	_TX_FLAGS(0, CLRDMASK);
+	_TX_FLAGS(0, VEOL);
+	_TX_FLAGS(0, INTREQ);
+	_TX_FLAGS(0, RTSENA);
+	_TX_FLAGS(0, CTSENA);
+	_TX_FLAGS(1, NOACK);
+
+#undef _TX_FLAGS
+
+	/*
+	 * RTS/CTS
+	 */
+	if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) {
+		if ((flags & AR5K_TXDESC_RTSENA) &&
+				(flags & AR5K_TXDESC_CTSENA))
+			return -EINVAL;
+		tx_ctl->tx_control_2 |= rtscts_duration &
+				AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
+		tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
+				AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
+	}
+
+	return 0;
+}
+
+/*
+ * Proccess the tx status descriptor on 5210/5211
+ */
+static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah __unused,
+		struct ath5k_desc *desc, struct ath5k_tx_status *ts)
+{
+	struct ath5k_hw_2w_tx_ctl *tx_ctl;
+	struct ath5k_hw_tx_status *tx_status;
+
+	tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
+	tx_status = &desc->ud.ds_tx5210.tx_stat;
+
+	/* No frame has been send or error */
+	if ((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)
+		return -EINPROGRESS;
+
+	/*
+	 * Get descriptor status
+	 */
+	ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
+	ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
+	ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
+	/*TODO: ts->ts_virtcol + test*/
+	ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_SEQ_NUM);
+	ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
+	ts->ts_antenna = 1;
+	ts->ts_status = 0;
+	ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0,
+		AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
+	ts->ts_retry[0] = ts->ts_longretry;
+	ts->ts_final_idx = 0;
+
+	if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
+		if (tx_status->tx_status_0 &
+				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
+			ts->ts_status |= AR5K_TXERR_XRETRY;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
+			ts->ts_status |= AR5K_TXERR_FIFO;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
+			ts->ts_status |= AR5K_TXERR_FILT;
+	}
+
+	return 0;
+}
+
+/*
+ * Proccess a tx status descriptor on 5212
+ */
+static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah __unused,
+		struct ath5k_desc *desc, struct ath5k_tx_status *ts)
+{
+	struct ath5k_hw_4w_tx_ctl *tx_ctl;
+	struct ath5k_hw_tx_status *tx_status;
+
+	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
+	tx_status = &desc->ud.ds_tx5212.tx_stat;
+
+	/* No frame has been send or error */
+	if (!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE))
+		return -EINPROGRESS;
+
+	/*
+	 * Get descriptor status
+	 */
+	ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
+	ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
+	ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
+	ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_SEQ_NUM);
+	ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
+	ts->ts_antenna = (tx_status->tx_status_1 &
+		AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
+	ts->ts_status = 0;
+
+	ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1,
+			AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX);
+
+	ts->ts_retry[0] = ts->ts_longretry;
+	ts->ts_rate[0] = tx_ctl->tx_control_3 &
+		AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+
+	/* TX error */
+	if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
+		if (tx_status->tx_status_0 &
+				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
+			ts->ts_status |= AR5K_TXERR_XRETRY;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
+			ts->ts_status |= AR5K_TXERR_FIFO;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
+			ts->ts_status |= AR5K_TXERR_FILT;
+	}
+
+	return 0;
+}
+
+/*
+ * RX Descriptors
+ */
+
+/*
+ * Initialize an rx control descriptor
+ */
+static int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah __unused,
+				  struct ath5k_desc *desc,
+				  u32 size, unsigned int flags)
+{
+	struct ath5k_hw_rx_ctl *rx_ctl;
+
+	rx_ctl = &desc->ud.ds_rx.rx_ctl;
+
+	/*
+	 * Clear the descriptor
+	 * If we don't clean the status descriptor,
+	 * while scanning we get too many results,
+	 * most of them virtual, after some secs
+	 * of scanning system hangs. M.F.
+	*/
+	memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc));
+
+	/* Setup descriptor */
+	rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
+	if (rx_ctl->rx_control_1 != size)
+		return -EINVAL;
+
+	if (flags & AR5K_RXDESC_INTREQ)
+		rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
+
+	return 0;
+}
+
+/*
+ * Proccess the rx status descriptor on 5210/5211
+ */
+static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah __unused,
+		struct ath5k_desc *desc, struct ath5k_rx_status *rs)
+{
+	struct ath5k_hw_rx_status *rx_status;
+
+	rx_status = &desc->ud.ds_rx.u.rx_stat;
+
+	/* No frame received / not ready */
+	if (!(rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_DONE))
+		return -EINPROGRESS;
+
+	/*
+	 * Frame receive status
+	 */
+	rs->rs_datalen = rx_status->rx_status_0 &
+		AR5K_5210_RX_DESC_STATUS0_DATA_LEN;
+	rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL);
+	rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE);
+	rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA);
+	rs->rs_more = !!(rx_status->rx_status_0 &
+		AR5K_5210_RX_DESC_STATUS0_MORE);
+	/* TODO: this timestamp is 13 bit, later on we assume 15 bit */
+	rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
+		AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
+	rs->rs_status = 0;
+	rs->rs_phyerr = 0;
+	rs->rs_keyix = AR5K_RXKEYIX_INVALID;
+
+	/*
+	 * Receive/descriptor errors
+	 */
+	if (!(rx_status->rx_status_1 &
+	      AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
+		if (rx_status->rx_status_1 &
+				AR5K_5210_RX_DESC_STATUS1_CRC_ERROR)
+			rs->rs_status |= AR5K_RXERR_CRC;
+
+		if (rx_status->rx_status_1 &
+				AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN)
+			rs->rs_status |= AR5K_RXERR_FIFO;
+
+		if (rx_status->rx_status_1 &
+				AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) {
+			rs->rs_status |= AR5K_RXERR_PHY;
+			rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1,
+				AR5K_5210_RX_DESC_STATUS1_PHY_ERROR);
+		}
+
+		if (rx_status->rx_status_1 &
+				AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+			rs->rs_status |= AR5K_RXERR_DECRYPT;
+	}
+
+	return 0;
+}
+
+/*
+ * Proccess the rx status descriptor on 5212
+ */
+static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah __unused,
+		struct ath5k_desc *desc, struct ath5k_rx_status *rs)
+{
+	struct ath5k_hw_rx_status *rx_status;
+	struct ath5k_hw_rx_error *rx_err;
+
+	rx_status = &desc->ud.ds_rx.u.rx_stat;
+
+	/* Overlay on error */
+	rx_err = &desc->ud.ds_rx.u.rx_err;
+
+	/* No frame received / not ready */
+	if (!(rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_DONE))
+		return -EINPROGRESS;
+
+	/*
+	 * Frame receive status
+	 */
+	rs->rs_datalen = rx_status->rx_status_0 &
+		AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
+	rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL);
+	rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE);
+	rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA);
+	rs->rs_more = !!(rx_status->rx_status_0 &
+		AR5K_5212_RX_DESC_STATUS0_MORE);
+	rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
+		AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
+	rs->rs_status = 0;
+	rs->rs_phyerr = 0;
+	rs->rs_keyix = AR5K_RXKEYIX_INVALID;
+
+	/*
+	 * Receive/descriptor errors
+	 */
+	if (!(rx_status->rx_status_1 &
+	      AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
+		if (rx_status->rx_status_1 &
+				AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
+			rs->rs_status |= AR5K_RXERR_CRC;
+
+		if (rx_status->rx_status_1 &
+				AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
+			rs->rs_status |= AR5K_RXERR_PHY;
+			rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1,
+					   AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
+		}
+
+		if (rx_status->rx_status_1 &
+				AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+			rs->rs_status |= AR5K_RXERR_DECRYPT;
+
+		if (rx_status->rx_status_1 &
+				AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
+			rs->rs_status |= AR5K_RXERR_MIC;
+	}
+
+	return 0;
+}
+
+/*
+ * Init function pointers inside ath5k_hw struct
+ */
+int ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
+{
+
+	if (ah->ah_version != AR5K_AR5210 &&
+	    ah->ah_version != AR5K_AR5211 &&
+	    ah->ah_version != AR5K_AR5212)
+		return -ENOTSUP;
+
+	if (ah->ah_version == AR5K_AR5212) {
+		ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
+		ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;
+		ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status;
+	} else {
+		ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
+		ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
+		ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
+	}
+
+	if (ah->ah_version == AR5K_AR5212)
+		ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status;
+	else if (ah->ah_version <= AR5K_AR5211)
+		ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status;
+
+	return 0;
+}
+
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_dma.c b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_dma.c
new file mode 100644
index 0000000000000000000000000000000000000000..fa1e0d013469da663cdeed269191fe3e1689b02c
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_dma.c
@@ -0,0 +1,631 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/*************************************\
+* DMA and interrupt masking functions *
+\*************************************/
+
+/*
+ * dma.c - DMA and interrupt masking functions
+ *
+ * Here we setup descriptor pointers (rxdp/txdp) start/stop dma engine and
+ * handle queue setup for 5210 chipset (rest are handled on qcu.c).
+ * Also we setup interrupt mask register (IMR) and read the various iterrupt
+ * status registers (ISR).
+ *
+ * TODO: Handle SISR on 5211+ and introduce a function to return the queue
+ * number that resulted the interrupt.
+ */
+
+#include <unistd.h>
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*********\
+* Receive *
+\*********/
+
+/**
+ * ath5k_hw_start_rx_dma - Start DMA receive
+ *
+ * @ah:	The &struct ath5k_hw
+ */
+void ath5k_hw_start_rx_dma(struct ath5k_hw *ah)
+{
+	ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
+	ath5k_hw_reg_read(ah, AR5K_CR);
+}
+
+/**
+ * ath5k_hw_stop_rx_dma - Stop DMA receive
+ *
+ * @ah:	The &struct ath5k_hw
+ */
+int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
+{
+	unsigned int i;
+
+	ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR);
+
+	/*
+	 * It may take some time to disable the DMA receive unit
+	 */
+	for (i = 1000; i > 0 &&
+			(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0;
+			i--)
+		udelay(10);
+
+	return i ? 0 : -EBUSY;
+}
+
+/**
+ * ath5k_hw_get_rxdp - Get RX Descriptor's address
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * XXX: Is RXDP read and clear ?
+ */
+u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah)
+{
+	return ath5k_hw_reg_read(ah, AR5K_RXDP);
+}
+
+/**
+ * ath5k_hw_set_rxdp - Set RX Descriptor's address
+ *
+ * @ah: The &struct ath5k_hw
+ * @phys_addr: RX descriptor address
+ *
+ * XXX: Should we check if rx is enabled before setting rxdp ?
+ */
+void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
+{
+	ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
+}
+
+
+/**********\
+* Transmit *
+\**********/
+
+/**
+ * ath5k_hw_start_tx_dma - Start DMA transmit for a specific queue
+ *
+ * @ah: The &struct ath5k_hw
+ * @queue: The hw queue number
+ *
+ * Start DMA transmit for a specific queue and since 5210 doesn't have
+ * QCU/DCU, set up queue parameters for 5210 here based on queue type (one
+ * queue for normal data and one queue for beacons). For queue setup
+ * on newer chips check out qcu.c. Returns -EINVAL if queue number is out
+ * of range or if queue is already disabled.
+ *
+ * NOTE: Must be called after setting up tx control descriptor for that
+ * queue (see below).
+ */
+int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
+{
+	u32 tx_queue;
+
+	/* Return if queue is declared inactive */
+	if (ah->ah_txq.tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return -EIO;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
+
+		/* Assume always a data queue */
+		tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0;
+
+		/* Start queue */
+		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
+		ath5k_hw_reg_read(ah, AR5K_CR);
+	} else {
+		/* Return if queue is disabled */
+		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue))
+			return -EIO;
+
+		/* Start queue */
+		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue);
+	}
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_stop_tx_dma - Stop DMA transmit on a specific queue
+ *
+ * @ah: The &struct ath5k_hw
+ * @queue: The hw queue number
+ *
+ * Stop DMA transmit on a specific hw queue and drain queue so we don't
+ * have any pending frames. Returns -EBUSY if we still have pending frames,
+ * -EINVAL if queue number is out of range.
+ *
+ */
+int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
+{
+	unsigned int i = 40;
+	u32 tx_queue, pending;
+
+	/* Return if queue is declared inactive */
+	if (ah->ah_txq.tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return -EIO;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
+
+		/* Assume a data queue */
+		tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0;
+
+		/* Stop queue */
+		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
+		ath5k_hw_reg_read(ah, AR5K_CR);
+	} else {
+		/*
+		 * Schedule TX disable and wait until queue is empty
+		 */
+		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue);
+
+		/*Check for pending frames*/
+		do {
+			pending = ath5k_hw_reg_read(ah,
+				AR5K_QUEUE_STATUS(queue)) &
+				AR5K_QCU_STS_FRMPENDCNT;
+			udelay(100);
+		} while (--i && pending);
+
+		/* For 2413+ order PCU to drop packets using
+		 * QUIET mechanism */
+		if (ah->ah_mac_version >= (AR5K_SREV_AR2414 >> 4) && pending) {
+			/* Set periodicity and duration */
+			ath5k_hw_reg_write(ah,
+				AR5K_REG_SM(100, AR5K_QUIET_CTL2_QT_PER)|
+				AR5K_REG_SM(10, AR5K_QUIET_CTL2_QT_DUR),
+				AR5K_QUIET_CTL2);
+
+			/* Enable quiet period for current TSF */
+			ath5k_hw_reg_write(ah,
+				AR5K_QUIET_CTL1_QT_EN |
+				AR5K_REG_SM(ath5k_hw_reg_read(ah,
+						AR5K_TSF_L32_5211) >> 10,
+						AR5K_QUIET_CTL1_NEXT_QT_TSF),
+				AR5K_QUIET_CTL1);
+
+			/* Force channel idle high */
+			AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
+					AR5K_DIAG_SW_CHANEL_IDLE_HIGH);
+
+			/* Wait a while and disable mechanism */
+			udelay(200);
+			AR5K_REG_DISABLE_BITS(ah, AR5K_QUIET_CTL1,
+						AR5K_QUIET_CTL1_QT_EN);
+
+			/* Re-check for pending frames */
+			i = 40;
+			do {
+				pending = ath5k_hw_reg_read(ah,
+					AR5K_QUEUE_STATUS(queue)) &
+					AR5K_QCU_STS_FRMPENDCNT;
+				udelay(100);
+			} while (--i && pending);
+
+			AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211,
+					AR5K_DIAG_SW_CHANEL_IDLE_HIGH);
+		}
+
+		/* Clear register */
+		ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
+		if (pending)
+			return -EBUSY;
+	}
+
+	/* TODO: Check for success on 5210 else return error */
+	return 0;
+}
+
+/**
+ * ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue
+ *
+ * @ah: The &struct ath5k_hw
+ * @queue: The hw queue number
+ *
+ * Get TX descriptor's address for a specific queue. For 5210 we ignore
+ * the queue number and use tx queue type since we only have 2 queues.
+ * We use TXDP0 for normal data queue and TXDP1 for beacon queue.
+ * For newer chips with QCU/DCU we just read the corresponding TXDP register.
+ *
+ * XXX: Is TXDP read and clear ?
+ */
+u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
+{
+	u16 tx_reg;
+
+	/*
+	 * Get the transmit queue descriptor pointer from the selected queue
+	 */
+	/*5210 doesn't have QCU*/
+	if (ah->ah_version == AR5K_AR5210) {
+		/* Assume a data queue */
+		tx_reg = AR5K_NOQCU_TXDP0;
+	} else {
+		tx_reg = AR5K_QUEUE_TXDP(queue);
+	}
+
+	return ath5k_hw_reg_read(ah, tx_reg);
+}
+
+/**
+ * ath5k_hw_set_txdp - Set TX Descriptor's address for a specific queue
+ *
+ * @ah: The &struct ath5k_hw
+ * @queue: The hw queue number
+ *
+ * Set TX descriptor's address for a specific queue. For 5210 we ignore
+ * the queue number and we use tx queue type since we only have 2 queues
+ * so as above we use TXDP0 for normal data queue and TXDP1 for beacon queue.
+ * For newer chips with QCU/DCU we just set the corresponding TXDP register.
+ * Returns -EINVAL if queue type is invalid for 5210 and -EIO if queue is still
+ * active.
+ */
+int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
+{
+	u16 tx_reg;
+
+	/*
+	 * Set the transmit queue descriptor pointer register by type
+	 * on 5210
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		/* Assume a data queue */
+		tx_reg = AR5K_NOQCU_TXDP0;
+	} else {
+		/*
+		 * Set the transmit queue descriptor pointer for
+		 * the selected queue on QCU for 5211+
+		 * (this won't work if the queue is still active)
+		 */
+		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
+			return -EIO;
+
+		tx_reg = AR5K_QUEUE_TXDP(queue);
+	}
+
+	/* Set descriptor pointer */
+	ath5k_hw_reg_write(ah, phys_addr, tx_reg);
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_update_tx_triglevel - Update tx trigger level
+ *
+ * @ah: The &struct ath5k_hw
+ * @increase: Flag to force increase of trigger level
+ *
+ * This function increases/decreases the tx trigger level for the tx fifo
+ * buffer (aka FIFO threshold) that is used to indicate when PCU flushes
+ * the buffer and transmits it's data. Lowering this results sending small
+ * frames more quickly but can lead to tx underruns, raising it a lot can
+ * result other problems (i think bmiss is related). Right now we start with
+ * the lowest possible (64Bytes) and if we get tx underrun we increase it using
+ * the increase flag. Returns -EIO if we have have reached maximum/minimum.
+ *
+ * XXX: Link this with tx DMA size ?
+ * XXX: Use it to save interrupts ?
+ * TODO: Needs testing, i think it's related to bmiss...
+ */
+int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, int increase)
+{
+	u32 trigger_level, imr;
+	int ret = -EIO;
+
+	/*
+	 * Disable interrupts by setting the mask
+	 */
+	imr = ath5k_hw_set_imr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL);
+
+	trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG),
+			AR5K_TXCFG_TXFULL);
+
+	if (!increase) {
+		if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES)
+			goto done;
+	} else
+		trigger_level +=
+			((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2);
+
+	/*
+	 * Update trigger level on success
+	 */
+	if (ah->ah_version == AR5K_AR5210)
+		ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL);
+	else
+		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+				AR5K_TXCFG_TXFULL, trigger_level);
+
+	ret = 0;
+
+done:
+	/*
+	 * Restore interrupt mask
+	 */
+	ath5k_hw_set_imr(ah, imr);
+
+	return ret;
+}
+
+/*******************\
+* Interrupt masking *
+\*******************/
+
+/**
+ * ath5k_hw_is_intr_pending - Check if we have pending interrupts
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Check if we have pending interrupts to process. Returns 1 if we
+ * have pending interrupts and 0 if we haven't.
+ */
+int ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
+{
+	return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0;
+}
+
+/**
+ * ath5k_hw_get_isr - Get interrupt status
+ *
+ * @ah: The @struct ath5k_hw
+ * @interrupt_mask: Driver's interrupt mask used to filter out
+ * interrupts in sw.
+ *
+ * This function is used inside our interrupt handler to determine the reason
+ * for the interrupt by reading Primary Interrupt Status Register. Returns an
+ * abstract interrupt status mask which is mostly ISR with some uncommon bits
+ * being mapped on some standard non hw-specific positions
+ * (check out &ath5k_int).
+ *
+ * NOTE: We use read-and-clear register, so after this function is called ISR
+ * is zeroed.
+ */
+int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
+{
+	u32 data;
+
+	/*
+	 * Read interrupt status from the Interrupt Status register
+	 * on 5210
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		data = ath5k_hw_reg_read(ah, AR5K_ISR);
+		if (data == AR5K_INT_NOCARD) {
+			*interrupt_mask = data;
+			return -ENODEV;
+		}
+	} else {
+		/*
+		 * Read interrupt status from Interrupt
+		 * Status Register shadow copy (Read And Clear)
+		 *
+		 * Note: PISR/SISR Not available on 5210
+		 */
+		data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR);
+		if (data == AR5K_INT_NOCARD) {
+			*interrupt_mask = data;
+			return -ENODEV;
+		}
+	}
+
+	/*
+	 * Get abstract interrupt mask (driver-compatible)
+	 */
+	*interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr;
+
+	if (ah->ah_version != AR5K_AR5210) {
+		u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2);
+
+		/*HIU = Host Interface Unit (PCI etc)*/
+		if (data & (AR5K_ISR_HIUERR))
+			*interrupt_mask |= AR5K_INT_FATAL;
+
+		/*Beacon Not Ready*/
+		if (data & (AR5K_ISR_BNR))
+			*interrupt_mask |= AR5K_INT_BNR;
+
+		if (sisr2 & (AR5K_SISR2_SSERR | AR5K_SISR2_DPERR |
+			     AR5K_SISR2_MCABT))
+			*interrupt_mask |= AR5K_INT_FATAL;
+
+		if (data & AR5K_ISR_TIM)
+			*interrupt_mask |= AR5K_INT_TIM;
+
+		if (data & AR5K_ISR_BCNMISC) {
+			if (sisr2 & AR5K_SISR2_TIM)
+				*interrupt_mask |= AR5K_INT_TIM;
+			if (sisr2 & AR5K_SISR2_DTIM)
+				*interrupt_mask |= AR5K_INT_DTIM;
+			if (sisr2 & AR5K_SISR2_DTIM_SYNC)
+				*interrupt_mask |= AR5K_INT_DTIM_SYNC;
+			if (sisr2 & AR5K_SISR2_BCN_TIMEOUT)
+				*interrupt_mask |= AR5K_INT_BCN_TIMEOUT;
+			if (sisr2 & AR5K_SISR2_CAB_TIMEOUT)
+				*interrupt_mask |= AR5K_INT_CAB_TIMEOUT;
+		}
+
+		if (data & AR5K_ISR_RXDOPPLER)
+			*interrupt_mask |= AR5K_INT_RX_DOPPLER;
+		if (data & AR5K_ISR_QCBRORN) {
+			*interrupt_mask |= AR5K_INT_QCBRORN;
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
+					AR5K_SISR3_QCBRORN);
+		}
+		if (data & AR5K_ISR_QCBRURN) {
+			*interrupt_mask |= AR5K_INT_QCBRURN;
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
+					AR5K_SISR3_QCBRURN);
+		}
+		if (data & AR5K_ISR_QTRIG) {
+			*interrupt_mask |= AR5K_INT_QTRIG;
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR4),
+					AR5K_SISR4_QTRIG);
+		}
+
+		if (data & AR5K_ISR_TXOK)
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
+					AR5K_SISR0_QCU_TXOK);
+
+		if (data & AR5K_ISR_TXDESC)
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
+					AR5K_SISR0_QCU_TXDESC);
+
+		if (data & AR5K_ISR_TXERR)
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
+					AR5K_SISR1_QCU_TXERR);
+
+		if (data & AR5K_ISR_TXEOL)
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
+					AR5K_SISR1_QCU_TXEOL);
+
+		if (data & AR5K_ISR_TXURN)
+			ah->ah_txq_isr |= AR5K_REG_MS(
+					ath5k_hw_reg_read(ah, AR5K_RAC_SISR2),
+					AR5K_SISR2_QCU_TXURN);
+	} else {
+		if (data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT |
+			    AR5K_ISR_HIUERR | AR5K_ISR_DPERR))
+			*interrupt_mask |= AR5K_INT_FATAL;
+
+		/*
+		 * XXX: BMISS interrupts may occur after association.
+		 * I found this on 5210 code but it needs testing. If this is
+		 * true we should disable them before assoc and re-enable them
+		 * after a successful assoc + some jiffies.
+			interrupt_mask &= ~AR5K_INT_BMISS;
+		 */
+	}
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_set_imr - Set interrupt mask
+ *
+ * @ah: The &struct ath5k_hw
+ * @new_mask: The new interrupt mask to be set
+ *
+ * Set the interrupt mask in hw to save interrupts. We do that by mapping
+ * ath5k_int bits to hw-specific bits to remove abstraction and writing
+ * Interrupt Mask Register.
+ */
+enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
+{
+	enum ath5k_int old_mask, int_mask;
+
+	old_mask = ah->ah_imr;
+
+	/*
+	 * Disable card interrupts to prevent any race conditions
+	 * (they will be re-enabled afterwards if AR5K_INT GLOBAL
+	 * is set again on the new mask).
+	 */
+	if (old_mask & AR5K_INT_GLOBAL) {
+		ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
+		ath5k_hw_reg_read(ah, AR5K_IER);
+	}
+
+	/*
+	 * Add additional, chipset-dependent interrupt mask flags
+	 * and write them to the IMR (interrupt mask register).
+	 */
+	int_mask = new_mask & AR5K_INT_COMMON;
+
+	if (ah->ah_version != AR5K_AR5210) {
+		/* Preserve per queue TXURN interrupt mask */
+		u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2)
+				& AR5K_SIMR2_QCU_TXURN;
+
+		if (new_mask & AR5K_INT_FATAL) {
+			int_mask |= AR5K_IMR_HIUERR;
+			simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR
+				| AR5K_SIMR2_DPERR);
+		}
+
+		/*Beacon Not Ready*/
+		if (new_mask & AR5K_INT_BNR)
+			int_mask |= AR5K_INT_BNR;
+
+		if (new_mask & AR5K_INT_TIM)
+			int_mask |= AR5K_IMR_TIM;
+
+		if (new_mask & AR5K_INT_TIM)
+			simr2 |= AR5K_SISR2_TIM;
+		if (new_mask & AR5K_INT_DTIM)
+			simr2 |= AR5K_SISR2_DTIM;
+		if (new_mask & AR5K_INT_DTIM_SYNC)
+			simr2 |= AR5K_SISR2_DTIM_SYNC;
+		if (new_mask & AR5K_INT_BCN_TIMEOUT)
+			simr2 |= AR5K_SISR2_BCN_TIMEOUT;
+		if (new_mask & AR5K_INT_CAB_TIMEOUT)
+			simr2 |= AR5K_SISR2_CAB_TIMEOUT;
+
+		if (new_mask & AR5K_INT_RX_DOPPLER)
+			int_mask |= AR5K_IMR_RXDOPPLER;
+
+		/* Note: Per queue interrupt masks
+		 * are set via reset_tx_queue (qcu.c) */
+		ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
+		ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2);
+
+	} else {
+		if (new_mask & AR5K_INT_FATAL)
+			int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT
+				| AR5K_IMR_HIUERR | AR5K_IMR_DPERR);
+
+		ath5k_hw_reg_write(ah, int_mask, AR5K_IMR);
+	}
+
+	/* If RXNOFRM interrupt is masked disable it
+	 * by setting AR5K_RXNOFRM to zero */
+	if (!(new_mask & AR5K_INT_RXNOFRM))
+		ath5k_hw_reg_write(ah, 0, AR5K_RXNOFRM);
+
+	/* Store new interrupt mask */
+	ah->ah_imr = new_mask;
+
+	/* ..re-enable interrupts if AR5K_INT_GLOBAL is set */
+	if (new_mask & AR5K_INT_GLOBAL) {
+		ath5k_hw_reg_write(ah, ah->ah_ier, AR5K_IER);
+		ath5k_hw_reg_read(ah, AR5K_IER);
+	}
+
+	return old_mask;
+}
+
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_eeprom.c b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_eeprom.c
new file mode 100644
index 0000000000000000000000000000000000000000..983d206b7e36cc4981ecbb760a418c04c848e286
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_eeprom.c
@@ -0,0 +1,1760 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2008-2009 Felix Fietkau <nbd@openwrt.org>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/*************************************\
+* EEPROM access functions and helpers *
+\*************************************/
+
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*
+ * Read from eeprom
+ */
+static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
+{
+	u32 status, timeout;
+
+	/*
+	 * Initialize EEPROM access
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
+		(void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset));
+	} else {
+		ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
+		AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
+				AR5K_EEPROM_CMD_READ);
+	}
+
+	for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
+		status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
+		if (status & AR5K_EEPROM_STAT_RDDONE) {
+			if (status & AR5K_EEPROM_STAT_RDERR)
+				return -EIO;
+			*data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
+					0xffff);
+			return 0;
+		}
+		udelay(15);
+	}
+
+	return -ETIMEDOUT;
+}
+
+/*
+ * Translate binary channel representation in EEPROM to frequency
+ */
+static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin,
+                                 unsigned int mode)
+{
+	u16 val;
+
+	if (bin == AR5K_EEPROM_CHANNEL_DIS)
+		return bin;
+
+	if (mode == AR5K_EEPROM_MODE_11A) {
+		if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
+			val = (5 * bin) + 4800;
+		else
+			val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
+				(bin * 10) + 5100;
+	} else {
+		if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
+			val = bin + 2300;
+		else
+			val = bin + 2400;
+	}
+
+	return val;
+}
+
+/*
+ * Initialize eeprom & capabilities structs
+ */
+static int
+ath5k_eeprom_init_header(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	int ret;
+	u16 val;
+
+	/*
+	 * Read values from EEPROM and store them in the capability structure
+	 */
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
+
+	/* Return if we have an old EEPROM */
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
+		return 0;
+
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
+	    ee_ant_gain);
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
+		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
+
+		/* XXX: Don't know which versions include these two */
+		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2);
+
+		if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3)
+			AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC3, ee_misc3);
+
+		if (ee->ee_version >= AR5K_EEPROM_VERSION_5_0) {
+			AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC4, ee_misc4);
+			AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC5, ee_misc5);
+			AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC6, ee_misc6);
+		}
+	}
+
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
+		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
+		ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
+		ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
+
+		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
+		ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
+		ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
+	}
+
+	AR5K_EEPROM_READ(AR5K_EEPROM_IS_HB63, val);
+
+	if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && val)
+		ee->ee_is_hb63 = 1;
+	else
+		ee->ee_is_hb63 = 0;
+
+	AR5K_EEPROM_READ(AR5K_EEPROM_RFKILL, val);
+	ee->ee_rfkill_pin = (u8) AR5K_REG_MS(val, AR5K_EEPROM_RFKILL_GPIO_SEL);
+	ee->ee_rfkill_pol = val & AR5K_EEPROM_RFKILL_POLARITY ? 1 : 0;
+
+	return 0;
+}
+
+
+/*
+ * Read antenna infos from eeprom
+ */
+static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
+		unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 o = *offset;
+	u16 val;
+	int ret, i = 0;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_switch_settling[mode]	= (val >> 8) & 0x7f;
+	ee->ee_atn_tx_rx[mode]		= (val >> 2) & 0x3f;
+	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
+	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= val & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	= (val >> 10) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= (val >> 4) & 0x3f;
+	ee->ee_ant_control[mode][i]	= (val << 2) & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	|= (val >> 14) & 0x3;
+	ee->ee_ant_control[mode][i++]	= (val >> 8) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= (val >> 2) & 0x3f;
+	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
+	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= val & 0x3f;
+
+	/* Get antenna modes */
+	ah->ah_antenna[mode][0] =
+	    (ee->ee_ant_control[mode][0] << 4);
+	ah->ah_antenna[mode][AR5K_ANT_FIXED_A] =
+	     ee->ee_ant_control[mode][1] 	|
+	    (ee->ee_ant_control[mode][2] << 6) 	|
+	    (ee->ee_ant_control[mode][3] << 12) |
+	    (ee->ee_ant_control[mode][4] << 18) |
+	    (ee->ee_ant_control[mode][5] << 24);
+	ah->ah_antenna[mode][AR5K_ANT_FIXED_B] =
+	     ee->ee_ant_control[mode][6] 	|
+	    (ee->ee_ant_control[mode][7] << 6) 	|
+	    (ee->ee_ant_control[mode][8] << 12) |
+	    (ee->ee_ant_control[mode][9] << 18) |
+	    (ee->ee_ant_control[mode][10] << 24);
+
+	/* return new offset */
+	*offset = o;
+
+	return 0;
+}
+
+/*
+ * Read supported modes and some mode-specific calibration data
+ * from eeprom
+ */
+static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
+		unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 o = *offset;
+	u16 val;
+	int ret;
+
+	ee->ee_n_piers[mode] = 0;
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11A:
+		ee->ee_ob[mode][3]	= (val >> 5) & 0x7;
+		ee->ee_db[mode][3]	= (val >> 2) & 0x7;
+		ee->ee_ob[mode][2]	= (val << 1) & 0x7;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_ob[mode][2]	|= (val >> 15) & 0x1;
+		ee->ee_db[mode][2]	= (val >> 12) & 0x7;
+		ee->ee_ob[mode][1]	= (val >> 9) & 0x7;
+		ee->ee_db[mode][1]	= (val >> 6) & 0x7;
+		ee->ee_ob[mode][0]	= (val >> 3) & 0x7;
+		ee->ee_db[mode][0]	= val & 0x7;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+	case AR5K_EEPROM_MODE_11B:
+		ee->ee_ob[mode][1]	= (val >> 4) & 0x7;
+		ee->ee_db[mode][1]	= val & 0x7;
+		break;
+	}
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_tx_end2xlna_enable[mode]	= (val >> 8) & 0xff;
+	ee->ee_thr_62[mode]		= val & 0xff;
+
+	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
+		ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_tx_end2xpa_disable[mode]	= (val >> 8) & 0xff;
+	ee->ee_tx_frm2xpa_enable[mode]	= val & 0xff;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_pga_desired_size[mode]	= (val >> 8) & 0xff;
+
+	if ((val & 0xff) & 0x80)
+		ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);
+	else
+		ee->ee_noise_floor_thr[mode] = val & 0xff;
+
+	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
+		ee->ee_noise_floor_thr[mode] =
+		    mode == AR5K_EEPROM_MODE_11A ? -54 : -1;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_xlna_gain[mode]		= (val >> 5) & 0xff;
+	ee->ee_x_gain[mode]		= (val >> 1) & 0xf;
+	ee->ee_xpd[mode]		= val & 0x1;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0)
+		ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) {
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_false_detect[mode] = (val >> 6) & 0x7f;
+
+		if (mode == AR5K_EEPROM_MODE_11A)
+			ee->ee_xr_power[mode] = val & 0x3f;
+		else {
+			ee->ee_ob[mode][0] = val & 0x7;
+			ee->ee_db[mode][0] = (val >> 3) & 0x7;
+		}
+	}
+
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) {
+		ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;
+		ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;
+	} else {
+		ee->ee_i_gain[mode] = (val >> 13) & 0x7;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_i_gain[mode] |= (val << 3) & 0x38;
+
+		if (mode == AR5K_EEPROM_MODE_11G) {
+			ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
+			if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6)
+				ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
+		}
+	}
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
+			mode == AR5K_EEPROM_MODE_11A) {
+		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
+		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+	}
+
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0)
+		goto done;
+
+	/* Note: >= v5 have bg freq piers on another location
+	 * so these freq piers are ignored for >= v5 (should be 0xff
+	 * anyway) */
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11A:
+		if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1)
+			break;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_margin_tx_rx[mode] = val & 0x3f;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		AR5K_EEPROM_READ(o++, val);
+
+		ee->ee_pwr_cal_b[0].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		ee->ee_pwr_cal_b[1].freq =
+			ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+		if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_pwr_cal_b[2].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		AR5K_EEPROM_READ(o++, val);
+
+		ee->ee_pwr_cal_g[0].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		ee->ee_pwr_cal_g[1].freq =
+			ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+		if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_turbo_max_power[mode] = val & 0x7f;
+		ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_pwr_cal_g[2].freq =
+			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
+		if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS)
+			ee->ee_n_piers[mode]++;
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
+		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
+			AR5K_EEPROM_READ(o++, val);
+			ee->ee_cck_ofdm_gain_delta = val & 0xff;
+		}
+		break;
+	}
+
+done:
+	/* return new offset */
+	*offset = o;
+
+	return 0;
+}
+
+/*
+ * Read turbo mode information on newer EEPROM versions
+ */
+static int
+ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
+			      u32 *offset, unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 o = *offset;
+	u16 val;
+	int ret;
+
+	if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)
+		return 0;
+
+	switch (mode){
+	case AR5K_EEPROM_MODE_11A:
+		ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f;
+
+		ee->ee_atn_tx_rx_turbo[mode] = (val >> 13) & 0x7;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x7) << 3;
+		ee->ee_margin_tx_rx_turbo[mode] = (val >> 3) & 0x3f;
+
+		ee->ee_adc_desired_size_turbo[mode] = (val >> 9) & 0x7f;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7;
+		ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff;
+
+		if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2)
+			ee->ee_pd_gain_overlap = (val >> 9) & 0xf;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		ee->ee_switch_settling_turbo[mode] = (val >> 8) & 0x7f;
+
+		ee->ee_atn_tx_rx_turbo[mode] = (val >> 15) & 0x7;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x1f) << 1;
+		ee->ee_margin_tx_rx_turbo[mode] = (val >> 5) & 0x3f;
+
+		ee->ee_adc_desired_size_turbo[mode] = (val >> 11) & 0x7f;
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_adc_desired_size_turbo[mode] |= (val & 0x7) << 5;
+		ee->ee_pga_desired_size_turbo[mode] = (val >> 3) & 0xff;
+		break;
+	}
+
+	/* return new offset */
+	*offset = o;
+
+	return 0;
+}
+
+/* Read mode-specific data (except power calibration data) */
+static int
+ath5k_eeprom_init_modes(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 mode_offset[3];
+	unsigned int mode;
+	u32 offset;
+	int ret;
+
+	/*
+	 * Get values for all modes
+	 */
+	mode_offset[AR5K_EEPROM_MODE_11A] = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
+	mode_offset[AR5K_EEPROM_MODE_11B] = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
+	mode_offset[AR5K_EEPROM_MODE_11G] = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
+
+	ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A] =
+		AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
+
+	for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) {
+		offset = mode_offset[mode];
+
+		ret = ath5k_eeprom_read_ants(ah, &offset, mode);
+		if (ret)
+			return ret;
+
+		ret = ath5k_eeprom_read_modes(ah, &offset, mode);
+		if (ret)
+			return ret;
+
+		ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode);
+		if (ret)
+			return ret;
+	}
+
+	/* override for older eeprom versions for better performance */
+	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) {
+		ee->ee_thr_62[AR5K_EEPROM_MODE_11A] = 15;
+		ee->ee_thr_62[AR5K_EEPROM_MODE_11B] = 28;
+		ee->ee_thr_62[AR5K_EEPROM_MODE_11G] = 28;
+	}
+
+	return 0;
+}
+
+/* Read the frequency piers for each mode (mostly used on newer eeproms with 0xff
+ * frequency mask) */
+static inline int
+ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max,
+			struct ath5k_chan_pcal_info *pc, unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	int o = *offset;
+	int i = 0;
+	u8 freq1, freq2;
+	int ret;
+	u16 val;
+
+	ee->ee_n_piers[mode] = 0;
+	while(i < max) {
+		AR5K_EEPROM_READ(o++, val);
+
+		freq1 = val & 0xff;
+		if (!freq1)
+			break;
+
+		pc[i++].freq = ath5k_eeprom_bin2freq(ee,
+				freq1, mode);
+		ee->ee_n_piers[mode]++;
+
+		freq2 = (val >> 8) & 0xff;
+		if (!freq2)
+			break;
+
+		pc[i++].freq = ath5k_eeprom_bin2freq(ee,
+				freq2, mode);
+		ee->ee_n_piers[mode]++;
+	}
+
+	/* return new offset */
+	*offset = o;
+
+	return 0;
+}
+
+/* Read frequency piers for 802.11a */
+static int
+ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a;
+	int i, ret;
+	u16 val;
+	u8 mask;
+
+	if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
+		ath5k_eeprom_read_freq_list(ah, &offset,
+			AR5K_EEPROM_N_5GHZ_CHAN, pcal,
+			AR5K_EEPROM_MODE_11A);
+	} else {
+		mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version);
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[0].freq  = (val >> 9) & mask;
+		pcal[1].freq  = (val >> 2) & mask;
+		pcal[2].freq  = (val << 5) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[2].freq |= (val >> 11) & 0x1f;
+		pcal[3].freq  = (val >> 4) & mask;
+		pcal[4].freq  = (val << 3) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[4].freq |= (val >> 13) & 0x7;
+		pcal[5].freq  = (val >> 6) & mask;
+		pcal[6].freq  = (val << 1) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[6].freq |= (val >> 15) & 0x1;
+		pcal[7].freq  = (val >> 8) & mask;
+		pcal[8].freq  = (val >> 1) & mask;
+		pcal[9].freq  = (val << 6) & mask;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcal[9].freq |= (val >> 10) & 0x3f;
+
+		/* Fixed number of piers */
+		ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10;
+
+		for (i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i++) {
+			pcal[i].freq = ath5k_eeprom_bin2freq(ee,
+				pcal[i].freq, AR5K_EEPROM_MODE_11A);
+		}
+	}
+
+	return 0;
+}
+
+/* Read frequency piers for 802.11bg on eeprom versions >= 5 and eemap >= 2 */
+static inline int
+ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *pcal;
+
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11B:
+		pcal = ee->ee_pwr_cal_b;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		pcal = ee->ee_pwr_cal_g;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ath5k_eeprom_read_freq_list(ah, &offset,
+		AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal,
+		mode);
+
+	return 0;
+}
+
+/*
+ * Read power calibration for RF5111 chips
+ *
+ * For RF5111 we have an XPD -eXternal Power Detector- curve
+ * for each calibrated channel. Each curve has 0,5dB Power steps
+ * on x axis and PCDAC steps (offsets) on y axis and looks like an
+ * exponential function. To recreate the curve we read 11 points
+ * here and interpolate later.
+ */
+
+/* Used to match PCDAC steps with power values on RF5111 chips
+ * (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC
+ * steps that match with the power values we read from eeprom. On
+ * older eeprom versions (< 3.2) these steps are equaly spaced at
+ * 10% of the pcdac curve -until the curve reaches it's maximum-
+ * (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2)
+ * these 11 steps are spaced in a different way. This function returns
+ * the pcdac steps based on eeprom version and curve min/max so that we
+ * can have pcdac/pwr points.
+ */
+static inline void
+ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
+{
+	static const u16 intercepts3[] =
+		{ 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
+	static const u16 intercepts3_2[] =
+		{ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
+	const u16 *ip;
+	unsigned i;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2)
+		ip = intercepts3_2;
+	else
+		ip = intercepts3;
+
+	for (i = 0; i < ARRAY_SIZE(intercepts3); i++)
+		vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100;
+}
+
+/* Convert RF5111 specific data to generic raw data
+ * used by interpolation code */
+static int
+ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
+				struct ath5k_chan_pcal_info *chinfo)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info_rf5111 *pcinfo;
+	struct ath5k_pdgain_info *pd;
+	u8 pier, point, idx;
+	u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
+
+	/* Fill raw data for each calibration pier */
+	for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
+
+		pcinfo = &chinfo[pier].rf5111_info;
+
+		/* Allocate pd_curves for this cal pier */
+		chinfo[pier].pd_curves =
+			calloc(AR5K_EEPROM_N_PD_CURVES,
+			       sizeof(struct ath5k_pdgain_info));
+
+		if (!chinfo[pier].pd_curves)
+			return -ENOMEM;
+
+		/* Only one curve for RF5111
+		 * find out which one and place
+		 * in in pd_curves.
+		 * Note: ee_x_gain is reversed here */
+		for (idx = 0; idx < AR5K_EEPROM_N_PD_CURVES; idx++) {
+
+			if (!((ee->ee_x_gain[mode] >> idx) & 0x1)) {
+				pdgain_idx[0] = idx;
+				break;
+			}
+		}
+
+		ee->ee_pd_gains[mode] = 1;
+
+		pd = &chinfo[pier].pd_curves[idx];
+
+		pd->pd_points = AR5K_EEPROM_N_PWR_POINTS_5111;
+
+		/* Allocate pd points for this curve */
+		pd->pd_step = calloc(AR5K_EEPROM_N_PWR_POINTS_5111, sizeof(u8));
+		if (!pd->pd_step)
+			return -ENOMEM;
+
+		pd->pd_pwr = calloc(AR5K_EEPROM_N_PWR_POINTS_5111, sizeof(s16));
+		if (!pd->pd_pwr)
+			return -ENOMEM;
+
+		/* Fill raw dataset
+		 * (convert power to 0.25dB units
+		 * for RF5112 combatibility) */
+		for (point = 0; point < pd->pd_points; point++) {
+
+			/* Absolute values */
+			pd->pd_pwr[point] = 2 * pcinfo->pwr[point];
+
+			/* Already sorted */
+			pd->pd_step[point] = pcinfo->pcdac[point];
+		}
+
+		/* Set min/max pwr */
+		chinfo[pier].min_pwr = pd->pd_pwr[0];
+		chinfo[pier].max_pwr = pd->pd_pwr[10];
+
+	}
+
+	return 0;
+}
+
+/* Parse EEPROM data */
+static int
+ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *pcal;
+	int offset, ret;
+	int i;
+	u16 val;
+
+	offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11A:
+		if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+			return 0;
+
+		ret = ath5k_eeprom_init_11a_pcal_freq(ah,
+			offset + AR5K_EEPROM_GROUP1_OFFSET);
+		if (ret < 0)
+			return ret;
+
+		offset += AR5K_EEPROM_GROUP2_OFFSET;
+		pcal = ee->ee_pwr_cal_a;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		if (!AR5K_EEPROM_HDR_11B(ee->ee_header) &&
+		    !AR5K_EEPROM_HDR_11G(ee->ee_header))
+			return 0;
+
+		pcal = ee->ee_pwr_cal_b;
+		offset += AR5K_EEPROM_GROUP3_OFFSET;
+
+		/* fixed piers */
+		pcal[0].freq = 2412;
+		pcal[1].freq = 2447;
+		pcal[2].freq = 2484;
+		ee->ee_n_piers[mode] = 3;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+			return 0;
+
+		pcal = ee->ee_pwr_cal_g;
+		offset += AR5K_EEPROM_GROUP4_OFFSET;
+
+		/* fixed piers */
+		pcal[0].freq = 2312;
+		pcal[1].freq = 2412;
+		pcal[2].freq = 2484;
+		ee->ee_n_piers[mode] = 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+		struct ath5k_chan_pcal_info_rf5111 *cdata =
+			&pcal[i].rf5111_info;
+
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pcdac_max = ((val >> 10) & AR5K_EEPROM_PCDAC_M);
+		cdata->pcdac_min = ((val >> 4) & AR5K_EEPROM_PCDAC_M);
+		cdata->pwr[0] = ((val << 2) & AR5K_EEPROM_POWER_M);
+
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pwr[0] |= ((val >> 14) & 0x3);
+		cdata->pwr[1] = ((val >> 8) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[2] = ((val >> 2) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[3] = ((val << 4) & AR5K_EEPROM_POWER_M);
+
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pwr[3] |= ((val >> 12) & 0xf);
+		cdata->pwr[4] = ((val >> 6) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[5] = (val  & AR5K_EEPROM_POWER_M);
+
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pwr[6] = ((val >> 10) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[7] = ((val >> 4) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[8] = ((val << 2) & AR5K_EEPROM_POWER_M);
+
+		AR5K_EEPROM_READ(offset++, val);
+		cdata->pwr[8] |= ((val >> 14) & 0x3);
+		cdata->pwr[9] = ((val >> 8) & AR5K_EEPROM_POWER_M);
+		cdata->pwr[10] = ((val >> 2) & AR5K_EEPROM_POWER_M);
+
+		ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min,
+			cdata->pcdac_max, cdata->pcdac);
+	}
+
+	return ath5k_eeprom_convert_pcal_info_5111(ah, mode, pcal);
+}
+
+
+/*
+ * Read power calibration for RF5112 chips
+ *
+ * For RF5112 we have 4 XPD -eXternal Power Detector- curves
+ * for each calibrated channel on 0, -6, -12 and -18dbm but we only
+ * use the higher (3) and the lower (0) curves. Each curve has 0.5dB
+ * power steps on x axis and PCDAC steps on y axis and looks like a
+ * linear function. To recreate the curve and pass the power values
+ * on hw, we read 4 points for xpd 0 (lower gain -> max power)
+ * and 3 points for xpd 3 (higher gain -> lower power) here and
+ * interpolate later.
+ *
+ * Note: Many vendors just use xpd 0 so xpd 3 is zeroed.
+ */
+
+/* Convert RF5112 specific data to generic raw data
+ * used by interpolation code */
+static int
+ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
+				struct ath5k_chan_pcal_info *chinfo)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info_rf5112 *pcinfo;
+	u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
+	unsigned int pier, pdg, point;
+
+	/* Fill raw data for each calibration pier */
+	for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
+
+		pcinfo = &chinfo[pier].rf5112_info;
+
+		/* Allocate pd_curves for this cal pier */
+		chinfo[pier].pd_curves =
+				calloc(AR5K_EEPROM_N_PD_CURVES,
+				       sizeof(struct ath5k_pdgain_info));
+
+		if (!chinfo[pier].pd_curves)
+			return -ENOMEM;
+
+		/* Fill pd_curves */
+		for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
+
+			u8 idx = pdgain_idx[pdg];
+			struct ath5k_pdgain_info *pd =
+					&chinfo[pier].pd_curves[idx];
+
+			/* Lowest gain curve (max power) */
+			if (pdg == 0) {
+				/* One more point for better accuracy */
+				pd->pd_points = AR5K_EEPROM_N_XPD0_POINTS;
+
+				/* Allocate pd points for this curve */
+				pd->pd_step = calloc(pd->pd_points, sizeof(u8));
+
+				if (!pd->pd_step)
+					return -ENOMEM;
+
+				pd->pd_pwr = calloc(pd->pd_points, sizeof(s16));
+
+				if (!pd->pd_pwr)
+					return -ENOMEM;
+
+
+				/* Fill raw dataset
+				 * (all power levels are in 0.25dB units) */
+				pd->pd_step[0] = pcinfo->pcdac_x0[0];
+				pd->pd_pwr[0] = pcinfo->pwr_x0[0];
+
+				for (point = 1; point < pd->pd_points;
+				point++) {
+					/* Absolute values */
+					pd->pd_pwr[point] =
+						pcinfo->pwr_x0[point];
+
+					/* Deltas */
+					pd->pd_step[point] =
+						pd->pd_step[point - 1] +
+						pcinfo->pcdac_x0[point];
+				}
+
+				/* Set min power for this frequency */
+				chinfo[pier].min_pwr = pd->pd_pwr[0];
+
+			/* Highest gain curve (min power) */
+			} else if (pdg == 1) {
+
+				pd->pd_points = AR5K_EEPROM_N_XPD3_POINTS;
+
+				/* Allocate pd points for this curve */
+				pd->pd_step = calloc(pd->pd_points, sizeof(u8));
+
+				if (!pd->pd_step)
+					return -ENOMEM;
+
+				pd->pd_pwr = calloc(pd->pd_points, sizeof(s16));
+
+				if (!pd->pd_pwr)
+					return -ENOMEM;
+
+				/* Fill raw dataset
+				 * (all power levels are in 0.25dB units) */
+				for (point = 0; point < pd->pd_points;
+				point++) {
+					/* Absolute values */
+					pd->pd_pwr[point] =
+						pcinfo->pwr_x3[point];
+
+					/* Fixed points */
+					pd->pd_step[point] =
+						pcinfo->pcdac_x3[point];
+				}
+
+				/* Since we have a higher gain curve
+				 * override min power */
+				chinfo[pier].min_pwr = pd->pd_pwr[0];
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* Parse EEPROM data */
+static int
+ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info;
+	struct ath5k_chan_pcal_info *gen_chan_info;
+	u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
+	u32 offset;
+	u8 i, c;
+	u16 val;
+	int ret;
+	u8 pd_gains = 0;
+
+	/* Count how many curves we have and
+	 * identify them (which one of the 4
+	 * available curves we have on each count).
+	 * Curves are stored from lower (x0) to
+	 * higher (x3) gain */
+	for (i = 0; i < AR5K_EEPROM_N_PD_CURVES; i++) {
+		/* ee_x_gain[mode] is x gain mask */
+		if ((ee->ee_x_gain[mode] >> i) & 0x1)
+			pdgain_idx[pd_gains++] = i;
+	}
+	ee->ee_pd_gains[mode] = pd_gains;
+
+	if (pd_gains == 0 || pd_gains > 2)
+		return -EINVAL;
+
+	switch (mode) {
+	case AR5K_EEPROM_MODE_11A:
+		/*
+		 * Read 5GHz EEPROM channels
+		 */
+		offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+		ath5k_eeprom_init_11a_pcal_freq(ah, offset);
+
+		offset += AR5K_EEPROM_GROUP2_OFFSET;
+		gen_chan_info = ee->ee_pwr_cal_a;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+		if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+			offset += AR5K_EEPROM_GROUP3_OFFSET;
+
+		/* NB: frequency piers parsed during mode init */
+		gen_chan_info = ee->ee_pwr_cal_b;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
+		if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+			offset += AR5K_EEPROM_GROUP4_OFFSET;
+		else if (AR5K_EEPROM_HDR_11B(ee->ee_header))
+			offset += AR5K_EEPROM_GROUP2_OFFSET;
+
+		/* NB: frequency piers parsed during mode init */
+		gen_chan_info = ee->ee_pwr_cal_g;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+		chan_pcal_info = &gen_chan_info[i].rf5112_info;
+
+		/* Power values in quarter dB
+		 * for the lower xpd gain curve
+		 * (0 dBm -> higher output power) */
+		for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
+			AR5K_EEPROM_READ(offset++, val);
+			chan_pcal_info->pwr_x0[c] = (s8) (val & 0xff);
+			chan_pcal_info->pwr_x0[++c] = (s8) ((val >> 8) & 0xff);
+		}
+
+		/* PCDAC steps
+		 * corresponding to the above power
+		 * measurements */
+		AR5K_EEPROM_READ(offset++, val);
+		chan_pcal_info->pcdac_x0[1] = (val & 0x1f);
+		chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f);
+		chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f);
+
+		/* Power values in quarter dB
+		 * for the higher xpd gain curve
+		 * (18 dBm -> lower output power) */
+		AR5K_EEPROM_READ(offset++, val);
+		chan_pcal_info->pwr_x3[0] = (s8) (val & 0xff);
+		chan_pcal_info->pwr_x3[1] = (s8) ((val >> 8) & 0xff);
+
+		AR5K_EEPROM_READ(offset++, val);
+		chan_pcal_info->pwr_x3[2] = (val & 0xff);
+
+		/* PCDAC steps
+		 * corresponding to the above power
+		 * measurements (fixed) */
+		chan_pcal_info->pcdac_x3[0] = 20;
+		chan_pcal_info->pcdac_x3[1] = 35;
+		chan_pcal_info->pcdac_x3[2] = 63;
+
+		if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) {
+			chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0x3f);
+
+			/* Last xpd0 power level is also channel maximum */
+			gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3];
+		} else {
+			chan_pcal_info->pcdac_x0[0] = 1;
+			gen_chan_info[i].max_pwr = (s8) ((val >> 8) & 0xff);
+		}
+
+	}
+
+	return ath5k_eeprom_convert_pcal_info_5112(ah, mode, gen_chan_info);
+}
+
+
+/*
+ * Read power calibration for RF2413 chips
+ *
+ * For RF2413 we have a Power to PDDAC table (Power Detector)
+ * instead of a PCDAC and 4 pd gain curves for each calibrated channel.
+ * Each curve has power on x axis in 0.5 db steps and PDDADC steps on y
+ * axis and looks like an exponential function like the RF5111 curve.
+ *
+ * To recreate the curves we read here the points and interpolate
+ * later. Note that in most cases only 2 (higher and lower) curves are
+ * used (like RF5112) but vendors have the oportunity to include all
+ * 4 curves on eeprom. The final curve (higher power) has an extra
+ * point for better accuracy like RF5112.
+ */
+
+/* For RF2413 power calibration data doesn't start on a fixed location and
+ * if a mode is not supported, it's section is missing -not zeroed-.
+ * So we need to calculate the starting offset for each section by using
+ * these two functions */
+
+/* Return the size of each section based on the mode and the number of pd
+ * gains available (maximum 4). */
+static inline unsigned int
+ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode)
+{
+	static const unsigned int pdgains_size[] = { 4, 6, 9, 12 };
+	unsigned int sz;
+
+	sz = pdgains_size[ee->ee_pd_gains[mode] - 1];
+	sz *= ee->ee_n_piers[mode];
+
+	return sz;
+}
+
+/* Return the starting offset for a section based on the modes supported
+ * and each section's size. */
+static unsigned int
+ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode)
+{
+	u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4);
+
+	switch(mode) {
+	case AR5K_EEPROM_MODE_11G:
+		if (AR5K_EEPROM_HDR_11B(ee->ee_header))
+			offset += ath5k_pdgains_size_2413(ee,
+					AR5K_EEPROM_MODE_11B) +
+					AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
+		/* fall through */
+	case AR5K_EEPROM_MODE_11B:
+		if (AR5K_EEPROM_HDR_11A(ee->ee_header))
+			offset += ath5k_pdgains_size_2413(ee,
+					AR5K_EEPROM_MODE_11A) +
+					AR5K_EEPROM_N_5GHZ_CHAN / 2;
+		/* fall through */
+	case AR5K_EEPROM_MODE_11A:
+		break;
+	default:
+		break;
+	}
+
+	return offset;
+}
+
+/* Convert RF2413 specific data to generic raw data
+ * used by interpolation code */
+static int
+ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
+				struct ath5k_chan_pcal_info *chinfo)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info_rf2413 *pcinfo;
+	u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
+	unsigned int pier, point;
+	int pdg;
+
+	/* Fill raw data for each calibration pier */
+	for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
+
+		pcinfo = &chinfo[pier].rf2413_info;
+
+		/* Allocate pd_curves for this cal pier */
+		chinfo[pier].pd_curves =
+				calloc(AR5K_EEPROM_N_PD_CURVES,
+				       sizeof(struct ath5k_pdgain_info));
+
+		if (!chinfo[pier].pd_curves)
+			return -ENOMEM;
+
+		/* Fill pd_curves */
+		for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
+
+			u8 idx = pdgain_idx[pdg];
+			struct ath5k_pdgain_info *pd =
+					&chinfo[pier].pd_curves[idx];
+
+			/* One more point for the highest power
+			 * curve (lowest gain) */
+			if (pdg == ee->ee_pd_gains[mode] - 1)
+				pd->pd_points = AR5K_EEPROM_N_PD_POINTS;
+			else
+				pd->pd_points = AR5K_EEPROM_N_PD_POINTS - 1;
+
+			/* Allocate pd points for this curve */
+			pd->pd_step = calloc(pd->pd_points, sizeof(u8));
+
+			if (!pd->pd_step)
+				return -ENOMEM;
+
+			pd->pd_pwr = calloc(pd->pd_points, sizeof(s16));
+
+			if (!pd->pd_pwr)
+				return -ENOMEM;
+
+			/* Fill raw dataset
+			 * convert all pwr levels to
+			 * quarter dB for RF5112 combatibility */
+			pd->pd_step[0] = pcinfo->pddac_i[pdg];
+			pd->pd_pwr[0] = 4 * pcinfo->pwr_i[pdg];
+
+			for (point = 1; point < pd->pd_points; point++) {
+
+				pd->pd_pwr[point] = pd->pd_pwr[point - 1] +
+					2 * pcinfo->pwr[pdg][point - 1];
+
+				pd->pd_step[point] = pd->pd_step[point - 1] +
+						pcinfo->pddac[pdg][point - 1];
+
+			}
+
+			/* Highest gain curve -> min power */
+			if (pdg == 0)
+				chinfo[pier].min_pwr = pd->pd_pwr[0];
+
+			/* Lowest gain curve -> max power */
+			if (pdg == ee->ee_pd_gains[mode] - 1)
+				chinfo[pier].max_pwr =
+					pd->pd_pwr[pd->pd_points - 1];
+		}
+	}
+
+	return 0;
+}
+
+/* Parse EEPROM data */
+static int
+ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info_rf2413 *pcinfo;
+	struct ath5k_chan_pcal_info *chinfo;
+	u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
+	u32 offset;
+	int idx, i, ret;
+	u16 val;
+	u8 pd_gains = 0;
+
+	/* Count how many curves we have and
+	 * identify them (which one of the 4
+	 * available curves we have on each count).
+	 * Curves are stored from higher to
+	 * lower gain so we go backwards */
+	for (idx = AR5K_EEPROM_N_PD_CURVES - 1; idx >= 0; idx--) {
+		/* ee_x_gain[mode] is x gain mask */
+		if ((ee->ee_x_gain[mode] >> idx) & 0x1)
+			pdgain_idx[pd_gains++] = idx;
+
+	}
+	ee->ee_pd_gains[mode] = pd_gains;
+
+	if (pd_gains == 0)
+		return -EINVAL;
+
+	offset = ath5k_cal_data_offset_2413(ee, mode);
+	switch (mode) {
+	case AR5K_EEPROM_MODE_11A:
+		if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+			return 0;
+
+		ath5k_eeprom_init_11a_pcal_freq(ah, offset);
+		offset += AR5K_EEPROM_N_5GHZ_CHAN / 2;
+		chinfo = ee->ee_pwr_cal_a;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
+			return 0;
+
+		ath5k_eeprom_init_11bg_2413(ah, mode, offset);
+		offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
+		chinfo = ee->ee_pwr_cal_b;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+			return 0;
+
+		ath5k_eeprom_init_11bg_2413(ah, mode, offset);
+		offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
+		chinfo = ee->ee_pwr_cal_g;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ee->ee_n_piers[mode]; i++) {
+		pcinfo = &chinfo[i].rf2413_info;
+
+		/*
+		 * Read pwr_i, pddac_i and the first
+		 * 2 pd points (pwr, pddac)
+		 */
+		AR5K_EEPROM_READ(offset++, val);
+		pcinfo->pwr_i[0] = val & 0x1f;
+		pcinfo->pddac_i[0] = (val >> 5) & 0x7f;
+		pcinfo->pwr[0][0] = (val >> 12) & 0xf;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcinfo->pddac[0][0] = val & 0x3f;
+		pcinfo->pwr[0][1] = (val >> 6) & 0xf;
+		pcinfo->pddac[0][1] = (val >> 10) & 0x3f;
+
+		AR5K_EEPROM_READ(offset++, val);
+		pcinfo->pwr[0][2] = val & 0xf;
+		pcinfo->pddac[0][2] = (val >> 4) & 0x3f;
+
+		pcinfo->pwr[0][3] = 0;
+		pcinfo->pddac[0][3] = 0;
+
+		if (pd_gains > 1) {
+			/*
+			 * Pd gain 0 is not the last pd gain
+			 * so it only has 2 pd points.
+			 * Continue wih pd gain 1.
+			 */
+			pcinfo->pwr_i[1] = (val >> 10) & 0x1f;
+
+			pcinfo->pddac_i[1] = (val >> 15) & 0x1;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pddac_i[1] |= (val & 0x3F) << 1;
+
+			pcinfo->pwr[1][0] = (val >> 6) & 0xf;
+			pcinfo->pddac[1][0] = (val >> 10) & 0x3f;
+
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pwr[1][1] = val & 0xf;
+			pcinfo->pddac[1][1] = (val >> 4) & 0x3f;
+			pcinfo->pwr[1][2] = (val >> 10) & 0xf;
+
+			pcinfo->pddac[1][2] = (val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pddac[1][2] |= (val & 0xF) << 2;
+
+			pcinfo->pwr[1][3] = 0;
+			pcinfo->pddac[1][3] = 0;
+		} else if (pd_gains == 1) {
+			/*
+			 * Pd gain 0 is the last one so
+			 * read the extra point.
+			 */
+			pcinfo->pwr[0][3] = (val >> 10) & 0xf;
+
+			pcinfo->pddac[0][3] = (val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pddac[0][3] |= (val & 0xF) << 2;
+		}
+
+		/*
+		 * Proceed with the other pd_gains
+		 * as above.
+		 */
+		if (pd_gains > 2) {
+			pcinfo->pwr_i[2] = (val >> 4) & 0x1f;
+			pcinfo->pddac_i[2] = (val >> 9) & 0x7f;
+
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pwr[2][0] = (val >> 0) & 0xf;
+			pcinfo->pddac[2][0] = (val >> 4) & 0x3f;
+			pcinfo->pwr[2][1] = (val >> 10) & 0xf;
+
+			pcinfo->pddac[2][1] = (val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pddac[2][1] |= (val & 0xF) << 2;
+
+			pcinfo->pwr[2][2] = (val >> 4) & 0xf;
+			pcinfo->pddac[2][2] = (val >> 8) & 0x3f;
+
+			pcinfo->pwr[2][3] = 0;
+			pcinfo->pddac[2][3] = 0;
+		} else if (pd_gains == 2) {
+			pcinfo->pwr[1][3] = (val >> 4) & 0xf;
+			pcinfo->pddac[1][3] = (val >> 8) & 0x3f;
+		}
+
+		if (pd_gains > 3) {
+			pcinfo->pwr_i[3] = (val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pwr_i[3] |= ((val >> 0) & 0x7) << 2;
+
+			pcinfo->pddac_i[3] = (val >> 3) & 0x7f;
+			pcinfo->pwr[3][0] = (val >> 10) & 0xf;
+			pcinfo->pddac[3][0] = (val >> 14) & 0x3;
+
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pddac[3][0] |= (val & 0xF) << 2;
+			pcinfo->pwr[3][1] = (val >> 4) & 0xf;
+			pcinfo->pddac[3][1] = (val >> 8) & 0x3f;
+
+			pcinfo->pwr[3][2] = (val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pwr[3][2] |= ((val >> 0) & 0x3) << 2;
+
+			pcinfo->pddac[3][2] = (val >> 2) & 0x3f;
+			pcinfo->pwr[3][3] = (val >> 8) & 0xf;
+
+			pcinfo->pddac[3][3] = (val >> 12) & 0xF;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pddac[3][3] |= ((val >> 0) & 0x3) << 4;
+		} else if (pd_gains == 3) {
+			pcinfo->pwr[2][3] = (val >> 14) & 0x3;
+			AR5K_EEPROM_READ(offset++, val);
+			pcinfo->pwr[2][3] |= ((val >> 0) & 0x3) << 2;
+
+			pcinfo->pddac[2][3] = (val >> 2) & 0x3f;
+		}
+	}
+
+	return ath5k_eeprom_convert_pcal_info_2413(ah, mode, chinfo);
+}
+
+
+/*
+ * Read per rate target power (this is the maximum tx power
+ * supported by the card). This info is used when setting
+ * tx power, no matter the channel.
+ *
+ * This also works for v5 EEPROMs.
+ */
+static int
+ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_rate_pcal_info *rate_pcal_info;
+	u8 *rate_target_pwr_num;
+	u32 offset;
+	u16 val;
+	int ret, i;
+
+	offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1);
+	rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode];
+	switch (mode) {
+	case AR5K_EEPROM_MODE_11A:
+		offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version);
+		rate_pcal_info = ee->ee_rate_tpwr_a;
+		ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version);
+		rate_pcal_info = ee->ee_rate_tpwr_b;
+		ee->ee_rate_target_pwr_num[mode] = 2; /* 3rd is g mode's 1st */
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		offset += AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version);
+		rate_pcal_info = ee->ee_rate_tpwr_g;
+		ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_2GHZ_CHAN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Different freq mask for older eeproms (<= v3.2) */
+	if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) {
+		for (i = 0; i < (*rate_target_pwr_num); i++) {
+			AR5K_EEPROM_READ(offset++, val);
+			rate_pcal_info[i].freq =
+			    ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode);
+
+			rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f);
+			rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f;
+
+			AR5K_EEPROM_READ(offset++, val);
+
+			if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
+			    val == 0) {
+				(*rate_target_pwr_num) = i;
+				break;
+			}
+
+			rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7);
+			rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f);
+			rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f);
+		}
+	} else {
+		for (i = 0; i < (*rate_target_pwr_num); i++) {
+			AR5K_EEPROM_READ(offset++, val);
+			rate_pcal_info[i].freq =
+			    ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
+
+			rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f);
+			rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f;
+
+			AR5K_EEPROM_READ(offset++, val);
+
+			if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
+			    val == 0) {
+				(*rate_target_pwr_num) = i;
+				break;
+			}
+
+			rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf;
+			rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f);
+			rate_pcal_info[i].target_power_54 = (val & 0x3f);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Read per channel calibration info from EEPROM
+ *
+ * This info is used to calibrate the baseband power table. Imagine
+ * that for each channel there is a power curve that's hw specific
+ * (depends on amplifier etc) and we try to "correct" this curve using
+ * offests we pass on to phy chip (baseband -> before amplifier) so that
+ * it can use accurate power values when setting tx power (takes amplifier's
+ * performance on each channel into account).
+ *
+ * EEPROM provides us with the offsets for some pre-calibrated channels
+ * and we have to interpolate to create the full table for these channels and
+ * also the table for any channel.
+ */
+static int
+ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	int (*read_pcal)(struct ath5k_hw *hw, int mode);
+	int mode;
+	int err;
+
+	if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) &&
+			(AR5K_EEPROM_EEMAP(ee->ee_misc0) == 1))
+		read_pcal = ath5k_eeprom_read_pcal_info_5112;
+	else if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0) &&
+			(AR5K_EEPROM_EEMAP(ee->ee_misc0) == 2))
+		read_pcal = ath5k_eeprom_read_pcal_info_2413;
+	else
+		read_pcal = ath5k_eeprom_read_pcal_info_5111;
+
+
+	for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G;
+	mode++) {
+		err = read_pcal(ah, mode);
+		if (err)
+			return err;
+
+		err = ath5k_eeprom_read_target_rate_pwr_info(ah, mode);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int
+ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *chinfo;
+	u8 pier, pdg;
+
+	switch (mode) {
+	case AR5K_EEPROM_MODE_11A:
+		if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+			return 0;
+		chinfo = ee->ee_pwr_cal_a;
+		break;
+	case AR5K_EEPROM_MODE_11B:
+		if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
+			return 0;
+		chinfo = ee->ee_pwr_cal_b;
+		break;
+	case AR5K_EEPROM_MODE_11G:
+		if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+			return 0;
+		chinfo = ee->ee_pwr_cal_g;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
+		if (!chinfo[pier].pd_curves)
+			continue;
+
+		for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
+			struct ath5k_pdgain_info *pd =
+					&chinfo[pier].pd_curves[pdg];
+
+			if (pd != NULL) {
+				free(pd->pd_step);
+				free(pd->pd_pwr);
+			}
+		}
+
+		free(chinfo[pier].pd_curves);
+	}
+
+	return 0;
+}
+
+void
+ath5k_eeprom_detach(struct ath5k_hw *ah)
+{
+	u8 mode;
+
+	for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++)
+		ath5k_eeprom_free_pcal_info(ah, mode);
+}
+
+/* Read conformance test limits used for regulatory control */
+static int
+ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_edge_power *rep;
+	unsigned int fmask, pmask;
+	unsigned int ctl_mode;
+	int ret, i, j;
+	u32 offset;
+	u16 val;
+
+	pmask = AR5K_EEPROM_POWER_M;
+	fmask = AR5K_EEPROM_FREQ_M(ee->ee_version);
+	offset = AR5K_EEPROM_CTL(ee->ee_version);
+	ee->ee_ctls = AR5K_EEPROM_N_CTLS(ee->ee_version);
+	for (i = 0; i < ee->ee_ctls; i += 2) {
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_ctl[i] = (val >> 8) & 0xff;
+		ee->ee_ctl[i + 1] = val & 0xff;
+	}
+
+	offset = AR5K_EEPROM_GROUP8_OFFSET;
+	if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0)
+		offset += AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) -
+			AR5K_EEPROM_GROUP5_OFFSET;
+	else
+		offset += AR5K_EEPROM_GROUPS_START(ee->ee_version);
+
+	rep = ee->ee_ctl_pwr;
+	for(i = 0; i < ee->ee_ctls; i++) {
+		switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) {
+		case AR5K_CTL_11A:
+		case AR5K_CTL_TURBO:
+			ctl_mode = AR5K_EEPROM_MODE_11A;
+			break;
+		default:
+			ctl_mode = AR5K_EEPROM_MODE_11G;
+			break;
+		}
+		if (ee->ee_ctl[i] == 0) {
+			if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3)
+				offset += 8;
+			else
+				offset += 7;
+			rep += AR5K_EEPROM_N_EDGES;
+			continue;
+		}
+		if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
+			for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
+				AR5K_EEPROM_READ(offset++, val);
+				rep[j].freq = (val >> 8) & fmask;
+				rep[j + 1].freq = val & fmask;
+			}
+			for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
+				AR5K_EEPROM_READ(offset++, val);
+				rep[j].edge = (val >> 8) & pmask;
+				rep[j].flag = (val >> 14) & 1;
+				rep[j + 1].edge = val & pmask;
+				rep[j + 1].flag = (val >> 6) & 1;
+			}
+		} else {
+			AR5K_EEPROM_READ(offset++, val);
+			rep[0].freq = (val >> 9) & fmask;
+			rep[1].freq = (val >> 2) & fmask;
+			rep[2].freq = (val << 5) & fmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[2].freq |= (val >> 11) & 0x1f;
+			rep[3].freq = (val >> 4) & fmask;
+			rep[4].freq = (val << 3) & fmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[4].freq |= (val >> 13) & 0x7;
+			rep[5].freq = (val >> 6) & fmask;
+			rep[6].freq = (val << 1) & fmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[6].freq |= (val >> 15) & 0x1;
+			rep[7].freq = (val >> 8) & fmask;
+
+			rep[0].edge = (val >> 2) & pmask;
+			rep[1].edge = (val << 4) & pmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[1].edge |= (val >> 12) & 0xf;
+			rep[2].edge = (val >> 6) & pmask;
+			rep[3].edge = val & pmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[4].edge = (val >> 10) & pmask;
+			rep[5].edge = (val >> 4) & pmask;
+			rep[6].edge = (val << 2) & pmask;
+
+			AR5K_EEPROM_READ(offset++, val);
+			rep[6].edge |= (val >> 14) & 0x3;
+			rep[7].edge = (val >> 8) & pmask;
+		}
+		for (j = 0; j < AR5K_EEPROM_N_EDGES; j++) {
+			rep[j].freq = ath5k_eeprom_bin2freq(ee,
+				rep[j].freq, ctl_mode);
+		}
+		rep += AR5K_EEPROM_N_EDGES;
+	}
+
+	return 0;
+}
+
+
+/*
+ * Initialize eeprom power tables
+ */
+int
+ath5k_eeprom_init(struct ath5k_hw *ah)
+{
+	int err;
+
+	err = ath5k_eeprom_init_header(ah);
+	if (err < 0)
+		return err;
+
+	err = ath5k_eeprom_init_modes(ah);
+	if (err < 0)
+		return err;
+
+	err = ath5k_eeprom_read_pcal_info(ah);
+	if (err < 0)
+		return err;
+
+	err = ath5k_eeprom_read_ctl_info(ah);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+/*
+ * Read the MAC address from eeprom
+ */
+int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+{
+	u8 mac_d[ETH_ALEN] = {};
+	u32 total, offset;
+	u16 data;
+	int octet, ret;
+
+	ret = ath5k_hw_eeprom_read(ah, 0x20, &data);
+	if (ret)
+		return ret;
+
+	for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
+		ret = ath5k_hw_eeprom_read(ah, offset, &data);
+		if (ret)
+			return ret;
+
+		total += data;
+		mac_d[octet + 1] = data & 0xff;
+		mac_d[octet] = data >> 8;
+		octet += 2;
+	}
+
+	if (!total || total == 3 * 0xffff)
+		return -EINVAL;
+
+	memcpy(mac, mac_d, ETH_ALEN);
+
+	return 0;
+}
+
+int ath5k_eeprom_is_hb63(struct ath5k_hw *ah)
+{
+	u16 data;
+
+	ath5k_hw_eeprom_read(ah, AR5K_EEPROM_IS_HB63, &data);
+
+	if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && data)
+		return 1;
+	else
+		return 0;
+}
+
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_gpio.c b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_gpio.c
new file mode 100644
index 0000000000000000000000000000000000000000..2301ec70b40dbc75e55ee350cf28b8bcd7c48b0c
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_gpio.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/****************\
+  GPIO Functions
+\****************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*
+ * Set GPIO inputs
+ */
+int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
+{
+	if (gpio >= AR5K_NUM_GPIO)
+		return -EINVAL;
+
+	ath5k_hw_reg_write(ah,
+		(ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio))
+		| AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR);
+
+	return 0;
+}
+
+/*
+ * Set GPIO outputs
+ */
+int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
+{
+	if (gpio >= AR5K_NUM_GPIO)
+		return -EINVAL;
+
+	ath5k_hw_reg_write(ah,
+		(ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio))
+		| AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR);
+
+	return 0;
+}
+
+/*
+ * Get GPIO state
+ */
+u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
+{
+	if (gpio >= AR5K_NUM_GPIO)
+		return 0xffffffff;
+
+	/* GPIO input magic */
+	return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) &
+		0x1;
+}
+
+/*
+ * Set GPIO state
+ */
+int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
+{
+	u32 data;
+
+	if (gpio >= AR5K_NUM_GPIO)
+		return -EINVAL;
+
+	/* GPIO output magic */
+	data = ath5k_hw_reg_read(ah, AR5K_GPIODO);
+
+	data &= ~(1 << gpio);
+	data |= (val & 1) << gpio;
+
+	ath5k_hw_reg_write(ah, data, AR5K_GPIODO);
+
+	return 0;
+}
+
+/*
+ * Initialize the GPIO interrupt (RFKill switch)
+ */
+void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
+		u32 interrupt_level)
+{
+	u32 data;
+
+	if (gpio >= AR5K_NUM_GPIO)
+		return;
+
+	/*
+	 * Set the GPIO interrupt
+	 */
+	data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &
+		~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH |
+		AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) |
+		(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA);
+
+	ath5k_hw_reg_write(ah, interrupt_level ? data :
+		(data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR);
+
+	ah->ah_imr |= AR5K_IMR_GPIO;
+
+	/* Enable GPIO interrupts */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO);
+}
+
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_initvals.c b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_initvals.c
new file mode 100644
index 0000000000000000000000000000000000000000..8f3bd20345e870e2152001a5d3af2e4de2de9cf3
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_initvals.c
@@ -0,0 +1,1560 @@
+/*
+ * Initial register settings functions
+ *
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+#include <unistd.h>
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*
+ * Mode-independent initial register writes
+ */
+
+struct ath5k_ini {
+	u16	ini_register;
+	u32	ini_value;
+
+	enum {
+		AR5K_INI_WRITE = 0,	/* Default */
+		AR5K_INI_READ = 1,	/* Cleared on read */
+	} ini_mode;
+};
+
+/*
+ * Mode specific initial register values
+ */
+
+struct ath5k_ini_mode {
+	u16	mode_register;
+	u32	mode_value[5];
+};
+
+/* Initial register settings for AR5210 */
+static const struct ath5k_ini ar5210_ini[] = {
+	/* PCU and MAC registers */
+	{ AR5K_NOQCU_TXDP0,	0, AR5K_INI_WRITE },
+	{ AR5K_NOQCU_TXDP1,	0, AR5K_INI_WRITE },
+	{ AR5K_RXDP,		0, AR5K_INI_WRITE },
+	{ AR5K_CR,		0, AR5K_INI_WRITE },
+	{ AR5K_ISR,		0, AR5K_INI_READ },
+	{ AR5K_IMR,		0, AR5K_INI_WRITE },
+	{ AR5K_IER,		AR5K_IER_DISABLE, AR5K_INI_WRITE },
+	{ AR5K_BSR,		0, AR5K_INI_READ },
+	{ AR5K_TXCFG,		AR5K_DMASIZE_128B, AR5K_INI_WRITE },
+	{ AR5K_RXCFG,		AR5K_DMASIZE_128B, AR5K_INI_WRITE },
+	{ AR5K_CFG,		AR5K_INIT_CFG, AR5K_INI_WRITE },
+	{ AR5K_TOPS,		8, AR5K_INI_WRITE },
+	{ AR5K_RXNOFRM,		8, AR5K_INI_WRITE },
+	{ AR5K_RPGTO,		0, AR5K_INI_WRITE },
+	{ AR5K_TXNOFRM,		0, AR5K_INI_WRITE },
+	{ AR5K_SFR,		0, AR5K_INI_WRITE },
+	{ AR5K_MIBC,		0, AR5K_INI_WRITE },
+	{ AR5K_MISC,		0, AR5K_INI_WRITE },
+	{ AR5K_RX_FILTER_5210,	0, AR5K_INI_WRITE },
+	{ AR5K_MCAST_FILTER0_5210, 0, AR5K_INI_WRITE },
+	{ AR5K_MCAST_FILTER1_5210, 0, AR5K_INI_WRITE },
+	{ AR5K_TX_MASK0,	0, AR5K_INI_WRITE },
+	{ AR5K_TX_MASK1,	0, AR5K_INI_WRITE },
+	{ AR5K_CLR_TMASK,	0, AR5K_INI_WRITE },
+	{ AR5K_TRIG_LVL,	AR5K_TUNE_MIN_TX_FIFO_THRES, AR5K_INI_WRITE },
+	{ AR5K_DIAG_SW_5210,	0, AR5K_INI_WRITE },
+	{ AR5K_RSSI_THR,	AR5K_TUNE_RSSI_THRES, AR5K_INI_WRITE },
+	{ AR5K_TSF_L32_5210,	0, AR5K_INI_WRITE },
+	{ AR5K_TIMER0_5210,	0, AR5K_INI_WRITE },
+	{ AR5K_TIMER1_5210,	0xffffffff, AR5K_INI_WRITE },
+	{ AR5K_TIMER2_5210,	0xffffffff, AR5K_INI_WRITE },
+	{ AR5K_TIMER3_5210,	1, AR5K_INI_WRITE },
+	{ AR5K_CFP_DUR_5210,	0, AR5K_INI_WRITE },
+	{ AR5K_CFP_PERIOD_5210,	0, AR5K_INI_WRITE },
+	/* PHY registers */
+	{ AR5K_PHY(0),	0x00000047, AR5K_INI_WRITE },
+	{ AR5K_PHY_AGC,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(3),	0x09848ea6, AR5K_INI_WRITE },
+	{ AR5K_PHY(4),	0x3d32e000, AR5K_INI_WRITE },
+	{ AR5K_PHY(5),	0x0000076b, AR5K_INI_WRITE },
+	{ AR5K_PHY_ACT,	AR5K_PHY_ACT_DISABLE, AR5K_INI_WRITE },
+	{ AR5K_PHY(8),	0x02020200, AR5K_INI_WRITE },
+	{ AR5K_PHY(9),	0x00000e0e, AR5K_INI_WRITE },
+	{ AR5K_PHY(10),	0x0a020201, AR5K_INI_WRITE },
+	{ AR5K_PHY(11),	0x00036ffc, AR5K_INI_WRITE },
+	{ AR5K_PHY(12),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(13),	0x00000e0e, AR5K_INI_WRITE },
+	{ AR5K_PHY(14),	0x00000007, AR5K_INI_WRITE },
+	{ AR5K_PHY(15),	0x00020100, AR5K_INI_WRITE },
+	{ AR5K_PHY(16),	0x89630000, AR5K_INI_WRITE },
+	{ AR5K_PHY(17),	0x1372169c, AR5K_INI_WRITE },
+	{ AR5K_PHY(18),	0x0018b633, AR5K_INI_WRITE },
+	{ AR5K_PHY(19),	0x1284613c, AR5K_INI_WRITE },
+	{ AR5K_PHY(20),	0x0de8b8e0, AR5K_INI_WRITE },
+	{ AR5K_PHY(21),	0x00074859, AR5K_INI_WRITE },
+	{ AR5K_PHY(22),	0x7e80beba, AR5K_INI_WRITE },
+	{ AR5K_PHY(23),	0x313a665e, AR5K_INI_WRITE },
+	{ AR5K_PHY_AGCCTL, 0x00001d08, AR5K_INI_WRITE },
+	{ AR5K_PHY(25),	0x0001ce00, AR5K_INI_WRITE },
+	{ AR5K_PHY(26),	0x409a4190, AR5K_INI_WRITE },
+	{ AR5K_PHY(28),	0x0000000f, AR5K_INI_WRITE },
+	{ AR5K_PHY(29),	0x00000080, AR5K_INI_WRITE },
+	{ AR5K_PHY(30),	0x00000004, AR5K_INI_WRITE },
+	{ AR5K_PHY(31),	0x00000018, AR5K_INI_WRITE }, 	/* 0x987c */
+	{ AR5K_PHY(64),	0x00000000, AR5K_INI_WRITE }, 	/* 0x9900 */
+	{ AR5K_PHY(65),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(66),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(67),	0x00800000, AR5K_INI_WRITE },
+	{ AR5K_PHY(68),	0x00000003, AR5K_INI_WRITE },
+	/* BB gain table (64bytes) */
+	{ AR5K_BB_GAIN(0), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(1), 0x00000020, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(2), 0x00000010, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(3), 0x00000030, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(4), 0x00000008, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(5), 0x00000028, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(6), 0x00000028, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(7), 0x00000004, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(8), 0x00000024, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(9), 0x00000014, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(10), 0x00000034, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(11), 0x0000000c, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(12), 0x0000002c, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(13), 0x00000002, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(14), 0x00000022, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(15), 0x00000012, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(16), 0x00000032, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(17), 0x0000000a, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(18), 0x0000002a, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(19), 0x00000001, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(20), 0x00000021, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(21), 0x00000011, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(22), 0x00000031, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(23), 0x00000009, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(24), 0x00000029, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(25), 0x00000005, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(26), 0x00000025, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(27), 0x00000015, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(28), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(29), 0x0000000d, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(30), 0x0000002d, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(31), 0x00000003, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(32), 0x00000023, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(33), 0x00000013, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(34), 0x00000033, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(35), 0x0000000b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(36), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(37), 0x00000007, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(38), 0x00000027, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(39), 0x00000017, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(40), 0x00000037, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(41), 0x0000000f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(42), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(43), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(44), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(45), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(46), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(47), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(48), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(49), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(50), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(51), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(52), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(53), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(54), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(55), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(56), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(57), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(58), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(59), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(60), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(61), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(62), 0x0000002f, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(63), 0x0000002f, AR5K_INI_WRITE },
+	/* 5110 RF gain table (64btes) */
+	{ AR5K_RF_GAIN(0), 0x0000001d, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(1), 0x0000005d, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(2), 0x0000009d, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(3), 0x000000dd, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(4), 0x0000011d, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(5), 0x00000021, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(6), 0x00000061, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(7), 0x000000a1, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(8), 0x000000e1, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(9), 0x00000031, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(10), 0x00000071, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(11), 0x000000b1, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(12), 0x0000001c, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(13), 0x0000005c, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(14), 0x00000029, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(15), 0x00000069, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(16), 0x000000a9, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(17), 0x00000020, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(18), 0x00000019, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(19), 0x00000059, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(20), 0x00000099, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(21), 0x00000030, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(22), 0x00000005, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(23), 0x00000025, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(24), 0x00000065, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(25), 0x000000a5, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(26), 0x00000028, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(27), 0x00000068, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(28), 0x0000001f, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(29), 0x0000001e, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(30), 0x00000018, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(31), 0x00000058, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(32), 0x00000098, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(33), 0x00000003, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(34), 0x00000004, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(35), 0x00000044, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(36), 0x00000084, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(37), 0x00000013, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(38), 0x00000012, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(39), 0x00000052, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(40), 0x00000092, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(41), 0x000000d2, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(42), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(43), 0x0000002a, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(44), 0x0000006a, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(45), 0x000000aa, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(46), 0x0000001b, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(47), 0x0000001a, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(48), 0x0000005a, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(49), 0x0000009a, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(50), 0x000000da, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(51), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(52), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(53), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(54), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(55), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(56), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(57), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(58), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(59), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(60), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(61), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(62), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_RF_GAIN(63), 0x00000006, AR5K_INI_WRITE },
+	/* PHY activation */
+	{ AR5K_PHY(53), 0x00000020, AR5K_INI_WRITE },
+	{ AR5K_PHY(51), 0x00000004, AR5K_INI_WRITE },
+	{ AR5K_PHY(50), 0x00060106, AR5K_INI_WRITE },
+	{ AR5K_PHY(39), 0x0000006d, AR5K_INI_WRITE },
+	{ AR5K_PHY(48), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(52), 0x00000014, AR5K_INI_WRITE },
+	{ AR5K_PHY_ACT, AR5K_PHY_ACT_ENABLE, AR5K_INI_WRITE },
+};
+
+/* Initial register settings for AR5211 */
+static const struct ath5k_ini ar5211_ini[] = {
+	{ AR5K_RXDP,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RTSD0,		0x84849c9c, AR5K_INI_WRITE },
+	{ AR5K_RTSD1,		0x7c7c7c7c, AR5K_INI_WRITE },
+	{ AR5K_RXCFG,		0x00000005, AR5K_INI_WRITE },
+	{ AR5K_MIBC,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_TOPS,		0x00000008, AR5K_INI_WRITE },
+	{ AR5K_RXNOFRM,		0x00000008, AR5K_INI_WRITE },
+	{ AR5K_TXNOFRM,		0x00000010, AR5K_INI_WRITE },
+	{ AR5K_RPGTO,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RFCNT,		0x0000001f, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(0),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(1),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(2),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(3),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(4),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(5),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(6),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(7),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(8),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(9),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_FP,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_STA_ID1,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BSS_ID0,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BSS_ID1,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RSSI_THR,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_CFP_PERIOD_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_TIMER0_5211,	0x00000030, AR5K_INI_WRITE },
+	{ AR5K_TIMER1_5211,	0x0007ffff, AR5K_INI_WRITE },
+	{ AR5K_TIMER2_5211,	0x01ffffff, AR5K_INI_WRITE },
+	{ AR5K_TIMER3_5211,	0x00000031, AR5K_INI_WRITE },
+	{ AR5K_CFP_DUR_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RX_FILTER_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MCAST_FILTER0_5211, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MCAST_FILTER1_5211, 0x00000002, AR5K_INI_WRITE },
+	{ AR5K_DIAG_SW_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_ADDAC_TEST,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DEFAULT_ANTENNA,	0x00000000, AR5K_INI_WRITE },
+	/* PHY registers */
+	{ AR5K_PHY_AGC,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(3),	0x2d849093, AR5K_INI_WRITE },
+	{ AR5K_PHY(4),	0x7d32e000, AR5K_INI_WRITE },
+	{ AR5K_PHY(5),	0x00000f6b, AR5K_INI_WRITE },
+	{ AR5K_PHY_ACT,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(11),	0x00026ffe, AR5K_INI_WRITE },
+	{ AR5K_PHY(12),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(15),	0x00020100, AR5K_INI_WRITE },
+	{ AR5K_PHY(16),	0x206a017a, AR5K_INI_WRITE },
+	{ AR5K_PHY(19),	0x1284613c, AR5K_INI_WRITE },
+	{ AR5K_PHY(21),	0x00000859, AR5K_INI_WRITE },
+	{ AR5K_PHY(26),	0x409a4190, AR5K_INI_WRITE },	/* 0x9868 */
+	{ AR5K_PHY(27),	0x050cb081, AR5K_INI_WRITE },
+	{ AR5K_PHY(28),	0x0000000f, AR5K_INI_WRITE },
+	{ AR5K_PHY(29),	0x00000080, AR5K_INI_WRITE },
+	{ AR5K_PHY(30),	0x0000000c, AR5K_INI_WRITE },
+	{ AR5K_PHY(64),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(65),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(66),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(67),	0x00800000, AR5K_INI_WRITE },
+	{ AR5K_PHY(68),	0x00000001, AR5K_INI_WRITE },
+	{ AR5K_PHY(71),	0x0000092a, AR5K_INI_WRITE },
+	{ AR5K_PHY_IQ,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(73),	0x00058a05, AR5K_INI_WRITE },
+	{ AR5K_PHY(74),	0x00000001, AR5K_INI_WRITE },
+	{ AR5K_PHY(75),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_PAPD_PROBE, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(77),	0x00000000, AR5K_INI_WRITE },	/* 0x9934 */
+	{ AR5K_PHY(78),	0x00000000, AR5K_INI_WRITE },	/* 0x9938 */
+	{ AR5K_PHY(79),	0x0000003f, AR5K_INI_WRITE },	/* 0x993c */
+	{ AR5K_PHY(80),	0x00000004, AR5K_INI_WRITE },
+	{ AR5K_PHY(82),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(83),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(84),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_RADAR, 0x5d50f14c, AR5K_INI_WRITE },
+	{ AR5K_PHY(86),	0x00000018, AR5K_INI_WRITE },
+	{ AR5K_PHY(87),	0x004b6a8e, AR5K_INI_WRITE },
+	/* Initial Power table (32bytes)
+	 * common on all cards/modes.
+	 * Note: Table is rewritten during
+	 * txpower setup later using calibration
+	 * data etc. so next write is non-common */
+	{ AR5K_PHY_PCDAC_TXPOWER(1), 0x06ff05ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(2), 0x07ff07ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(3), 0x08ff08ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(4), 0x09ff09ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(5), 0x0aff0aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(6), 0x0bff0bff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(7), 0x0cff0cff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(8), 0x0dff0dff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(9), 0x0fff0eff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(10), 0x12ff12ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(11), 0x14ff13ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(12), 0x16ff15ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(13), 0x19ff17ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(14), 0x1bff1aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(15), 0x1eff1dff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(16), 0x23ff20ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(17), 0x27ff25ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(18), 0x2cff29ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(19), 0x31ff2fff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(20), 0x37ff34ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(21), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(22), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(23), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(24), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(25), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(26), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(27), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(28), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(29), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(30), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_PCDAC_TXPOWER(31), 0x3aff3aff, AR5K_INI_WRITE },
+	{ AR5K_PHY_CCKTXCTL, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(642), 0x503e4646, AR5K_INI_WRITE },
+	{ AR5K_PHY_GAIN_2GHZ, 0x6480416c, AR5K_INI_WRITE },
+	{ AR5K_PHY(644), 0x0199a003, AR5K_INI_WRITE },
+	{ AR5K_PHY(645), 0x044cd610, AR5K_INI_WRITE },
+	{ AR5K_PHY(646), 0x13800040, AR5K_INI_WRITE },
+	{ AR5K_PHY(647), 0x1be00060, AR5K_INI_WRITE },
+	{ AR5K_PHY(648), 0x0c53800a, AR5K_INI_WRITE },
+	{ AR5K_PHY(649), 0x0014df3b, AR5K_INI_WRITE },
+	{ AR5K_PHY(650), 0x000001b5, AR5K_INI_WRITE },
+	{ AR5K_PHY(651), 0x00000020, AR5K_INI_WRITE },
+};
+
+/* Initial mode-specific settings for AR5211
+ * 5211 supports OFDM-only g (draft g) but we
+ * need to test it !
+ */
+static const struct ath5k_ini_mode ar5211_ini_mode[] = {
+	{ AR5K_TXCFG,
+	/*	  a	    aTurbo	  b	  g (OFDM)    */
+	   { 0x00000015, 0x00000015, 0x0000001d, 0x00000015 } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(0),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(1),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(2),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(3),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(4),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(5),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(6),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(7),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(8),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(9),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+	{ AR5K_DCU_GBL_IFS_SLOT,
+	   { 0x00000168, 0x000001e0, 0x000001b8, 0x00000168 } },
+	{ AR5K_DCU_GBL_IFS_SIFS,
+	   { 0x00000230, 0x000001e0, 0x000000b0, 0x00000230 } },
+	{ AR5K_DCU_GBL_IFS_EIFS,
+	   { 0x00000d98, 0x00001180, 0x00001f48, 0x00000d98 } },
+	{ AR5K_DCU_GBL_IFS_MISC,
+	   { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000a0e0 } },
+	{ AR5K_TIME_OUT,
+	   { 0x04000400, 0x08000800, 0x20003000, 0x04000400 } },
+	{ AR5K_USEC_5211,
+	   { 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95, 0x0e8d8fa7 } },
+	{ AR5K_PHY_TURBO,
+	   { 0x00000000, 0x00000003, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY(8),
+	   { 0x02020200, 0x02020200, 0x02010200, 0x02020200 } },
+	{ AR5K_PHY(9),
+	   { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e } },
+	{ AR5K_PHY(10),
+	   { 0x0a020001, 0x0a020001, 0x05010000, 0x0a020001 } },
+	{ AR5K_PHY(13),
+	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY(14),
+	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY(17),
+	   { 0x1372169c, 0x137216a5, 0x137216a8, 0x1372169c } },
+	{ AR5K_PHY(18),
+	   { 0x0018ba67, 0x0018ba67, 0x0018ba69, 0x0018ba69 } },
+	{ AR5K_PHY(20),
+	   { 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } },
+	{ AR5K_PHY_SIG,
+	   { 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e, 0x7e800d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+	   { 0x31375d5e, 0x31375d5e, 0x313a5d5e, 0x31375d5e } },
+	{ AR5K_PHY_AGCCTL,
+	   { 0x0000bd10, 0x0000bd10, 0x0000bd38, 0x0000bd10 } },
+	{ AR5K_PHY_NF,
+	   { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
+	{ AR5K_PHY_RX_DELAY,
+	   { 0x00002710, 0x00002710, 0x0000157c, 0x00002710 } },
+	{ AR5K_PHY(70),
+	   { 0x00000190, 0x00000190, 0x00000084, 0x00000190 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+	   { 0x6fe01020, 0x6fe01020, 0x6fe00920, 0x6fe01020 } },
+	{ AR5K_PHY_PCDAC_TXPOWER_BASE,
+	   { 0x05ff14ff, 0x05ff14ff, 0x05ff14ff, 0x05ff19ff } },
+	{ AR5K_RF_BUFFER_CONTROL_4,
+	   { 0x00000010, 0x00000014, 0x00000010, 0x00000010 } },
+};
+
+/* Initial register settings for AR5212 */
+static const struct ath5k_ini ar5212_ini_common_start[] = {
+	{ AR5K_RXDP,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RXCFG,		0x00000005, AR5K_INI_WRITE },
+	{ AR5K_MIBC,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_TOPS,		0x00000008, AR5K_INI_WRITE },
+	{ AR5K_RXNOFRM,		0x00000008, AR5K_INI_WRITE },
+	{ AR5K_TXNOFRM,		0x00000010, AR5K_INI_WRITE },
+	{ AR5K_RPGTO,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RFCNT,		0x0000001f, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(0),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(1),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(2),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(3),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(4),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(5),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(6),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(7),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(8),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUEUE_TXDP(9),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_FP,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TXP,		0x00000000, AR5K_INI_WRITE },
+	/* Tx filter table 0 (32 entries) */
+	{ AR5K_DCU_TX_FILTER_0(0),  0x00000000, AR5K_INI_WRITE }, /* DCU 0 */
+	{ AR5K_DCU_TX_FILTER_0(1),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(2),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(3),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(4),  0x00000000, AR5K_INI_WRITE }, /* DCU 1 */
+	{ AR5K_DCU_TX_FILTER_0(5),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(6),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(7),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(8),  0x00000000, AR5K_INI_WRITE }, /* DCU 2 */
+	{ AR5K_DCU_TX_FILTER_0(9),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(10), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(11), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(12), 0x00000000, AR5K_INI_WRITE }, /* DCU 3 */
+	{ AR5K_DCU_TX_FILTER_0(13), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(14), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(15), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(16), 0x00000000, AR5K_INI_WRITE }, /* DCU 4 */
+	{ AR5K_DCU_TX_FILTER_0(17), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(18), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(19), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(20), 0x00000000, AR5K_INI_WRITE }, /* DCU 5 */
+	{ AR5K_DCU_TX_FILTER_0(21), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(22), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(23), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(24), 0x00000000, AR5K_INI_WRITE }, /* DCU 6 */
+	{ AR5K_DCU_TX_FILTER_0(25), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(26), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(27), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(28), 0x00000000, AR5K_INI_WRITE }, /* DCU 7 */
+	{ AR5K_DCU_TX_FILTER_0(29), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(30), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_0(31), 0x00000000, AR5K_INI_WRITE },
+	/* Tx filter table 1 (16 entries) */
+	{ AR5K_DCU_TX_FILTER_1(0),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(1),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(2),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(3),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(4),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(5),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(6),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(7),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(8),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(9),  0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(10), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(11), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(12), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(13), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(14), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_1(15), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_CLR, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_SET, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_CLR, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DCU_TX_FILTER_SET, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_STA_ID1,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BSS_ID0,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BSS_ID1,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BEACON_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_CFP_PERIOD_5211, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_TIMER0_5211,	0x00000030, AR5K_INI_WRITE },
+	{ AR5K_TIMER1_5211,	0x0007ffff, AR5K_INI_WRITE },
+	{ AR5K_TIMER2_5211,	0x01ffffff, AR5K_INI_WRITE },
+	{ AR5K_TIMER3_5211,	0x00000031, AR5K_INI_WRITE },
+	{ AR5K_CFP_DUR_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RX_FILTER_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DIAG_SW_5211,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_ADDAC_TEST,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_DEFAULT_ANTENNA,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_FRAME_CTL_QOSM, 	0x000fc78f, AR5K_INI_WRITE },
+	{ AR5K_XRMODE,		0x2a82301a, AR5K_INI_WRITE },
+	{ AR5K_XRDELAY,		0x05dc01e0, AR5K_INI_WRITE },
+	{ AR5K_XRTIMEOUT,	0x1f402710, AR5K_INI_WRITE },
+	{ AR5K_XRCHIRP,		0x01f40000, AR5K_INI_WRITE },
+	{ AR5K_XRSTOMP,		0x00001e1c, AR5K_INI_WRITE },
+	{ AR5K_SLEEP0,		0x0002aaaa, AR5K_INI_WRITE },
+	{ AR5K_SLEEP1,		0x02005555, AR5K_INI_WRITE },
+	{ AR5K_SLEEP2,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BSS_IDM0,	0xffffffff, AR5K_INI_WRITE },
+	{ AR5K_BSS_IDM1,	0x0000ffff, AR5K_INI_WRITE },
+	{ AR5K_TXPC,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PROFCNT_TX,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PROFCNT_RX,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PROFCNT_RXCLR,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PROFCNT_CYCLE,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUIET_CTL1,	0x00000088, AR5K_INI_WRITE },
+	/* Initial rate duration table (32 entries )*/
+	{ AR5K_RATE_DUR(0),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(1),	0x0000008c, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(2),	0x000000e4, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(3),	0x000002d5, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(4),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(5),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(6),	0x000000a0, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(7),	0x000001c9, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(8),	0x0000002c, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(9),	0x0000002c, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(10),	0x00000030, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(11),	0x0000003c, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(12),	0x0000002c, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(13),	0x0000002c, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(14),	0x00000030, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(15),	0x0000003c, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(16),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(17),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(18),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(19),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(20),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(21),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(22),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(23),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(24),	0x000000d5, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(25),	0x000000df, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(26),	0x00000102, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(27),	0x0000013a, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(28),	0x00000075, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(29),	0x0000007f, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(30),	0x000000a2, AR5K_INI_WRITE },
+	{ AR5K_RATE_DUR(31),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_QUIET_CTL2,	0x00010002, AR5K_INI_WRITE },
+	{ AR5K_TSF_PARM,	0x00000001, AR5K_INI_WRITE },
+	{ AR5K_QOS_NOACK,	0x000000c0, AR5K_INI_WRITE },
+	{ AR5K_PHY_ERR_FIL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_XRLAT_TX,	0x00000168, AR5K_INI_WRITE },
+	{ AR5K_ACKSIFS,		0x00000000, AR5K_INI_WRITE },
+	/* Rate -> db table
+	 * notice ...03<-02<-01<-00 ! */
+	{ AR5K_RATE2DB(0),	0x03020100, AR5K_INI_WRITE },
+	{ AR5K_RATE2DB(1),	0x07060504, AR5K_INI_WRITE },
+	{ AR5K_RATE2DB(2),	0x0b0a0908, AR5K_INI_WRITE },
+	{ AR5K_RATE2DB(3),	0x0f0e0d0c, AR5K_INI_WRITE },
+	{ AR5K_RATE2DB(4),	0x13121110, AR5K_INI_WRITE },
+	{ AR5K_RATE2DB(5),	0x17161514, AR5K_INI_WRITE },
+	{ AR5K_RATE2DB(6),	0x1b1a1918, AR5K_INI_WRITE },
+	{ AR5K_RATE2DB(7),	0x1f1e1d1c, AR5K_INI_WRITE },
+	/* Db -> Rate table */
+	{ AR5K_DB2RATE(0),	0x03020100, AR5K_INI_WRITE },
+	{ AR5K_DB2RATE(1),	0x07060504, AR5K_INI_WRITE },
+	{ AR5K_DB2RATE(2),	0x0b0a0908, AR5K_INI_WRITE },
+	{ AR5K_DB2RATE(3),	0x0f0e0d0c, AR5K_INI_WRITE },
+	{ AR5K_DB2RATE(4),	0x13121110, AR5K_INI_WRITE },
+	{ AR5K_DB2RATE(5),	0x17161514, AR5K_INI_WRITE },
+	{ AR5K_DB2RATE(6),	0x1b1a1918, AR5K_INI_WRITE },
+	{ AR5K_DB2RATE(7),	0x1f1e1d1c, AR5K_INI_WRITE },
+	/* PHY registers (Common settings
+	 * for all chips/modes) */
+	{ AR5K_PHY(3),		0xad848e19, AR5K_INI_WRITE },
+	{ AR5K_PHY(4),		0x7d28e000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_3,	0x9c0a9f6b, AR5K_INI_WRITE },
+	{ AR5K_PHY_ACT,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY(16),		0x206a017a, AR5K_INI_WRITE },
+	{ AR5K_PHY(21),		0x00000859, AR5K_INI_WRITE },
+	{ AR5K_PHY_BIN_MASK_1,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_BIN_MASK_2,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_BIN_MASK_3,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_BIN_MASK_CTL, 0x00800000, AR5K_INI_WRITE },
+	{ AR5K_PHY_ANT_CTL,	0x00000001, AR5K_INI_WRITE },
+	/*{ AR5K_PHY(71), 0x0000092a, AR5K_INI_WRITE },*/ /* Old value */
+	{ AR5K_PHY_MAX_RX_LEN,	0x00000c80, AR5K_INI_WRITE },
+	{ AR5K_PHY_IQ,		0x05100000, AR5K_INI_WRITE },
+	{ AR5K_PHY_WARM_RESET,	0x00000001, AR5K_INI_WRITE },
+	{ AR5K_PHY_CTL,		0x00000004, AR5K_INI_WRITE },
+	{ AR5K_PHY_TXPOWER_RATE1, 0x1e1f2022, AR5K_INI_WRITE },
+	{ AR5K_PHY_TXPOWER_RATE2, 0x0a0b0c0d, AR5K_INI_WRITE },
+	{ AR5K_PHY_TXPOWER_RATE_MAX, 0x0000003f, AR5K_INI_WRITE },
+	{ AR5K_PHY(82),		0x9280b212, AR5K_INI_WRITE },
+	{ AR5K_PHY_RADAR,	0x5d50e188, AR5K_INI_WRITE },
+	/*{ AR5K_PHY(86), 0x000000ff, AR5K_INI_WRITE },*/
+	{ AR5K_PHY(87),		0x004b6a8e, AR5K_INI_WRITE },
+	{ AR5K_PHY_NFTHRES,	0x000003ce, AR5K_INI_WRITE },
+	{ AR5K_PHY_RESTART,	0x192fb515, AR5K_INI_WRITE },
+	{ AR5K_PHY(94),		0x00000001, AR5K_INI_WRITE },
+	{ AR5K_PHY_RFBUS_REQ,	0x00000000, AR5K_INI_WRITE },
+	/*{ AR5K_PHY(644), 0x0080a333, AR5K_INI_WRITE },*/ /* Old value */
+	/*{ AR5K_PHY(645), 0x00206c10, AR5K_INI_WRITE },*/ /* Old value */
+	{ AR5K_PHY(644),	0x00806333, AR5K_INI_WRITE },
+	{ AR5K_PHY(645),	0x00106c10, AR5K_INI_WRITE },
+	{ AR5K_PHY(646),	0x009c4060, AR5K_INI_WRITE },
+	/* { AR5K_PHY(647), 0x1483800a, AR5K_INI_WRITE }, */
+	/* { AR5K_PHY(648), 0x01831061, AR5K_INI_WRITE }, */ /* Old value */
+	{ AR5K_PHY(648),	0x018830c6, AR5K_INI_WRITE },
+	{ AR5K_PHY(649),	0x00000400, AR5K_INI_WRITE },
+	/*{ AR5K_PHY(650), 0x000001b5, AR5K_INI_WRITE },*/
+	{ AR5K_PHY(651),	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TXPOWER_RATE3, 0x20202020, AR5K_INI_WRITE },
+	{ AR5K_PHY_TXPOWER_RATE2, 0x20202020, AR5K_INI_WRITE },
+	/*{ AR5K_PHY(655), 0x13c889af, AR5K_INI_WRITE },*/
+	{ AR5K_PHY(656),	0x38490a20, AR5K_INI_WRITE },
+	{ AR5K_PHY(657),	0x00007bb6, AR5K_INI_WRITE },
+	{ AR5K_PHY(658),	0x0fff3ffc, AR5K_INI_WRITE },
+};
+
+/* Initial mode-specific settings for AR5212 (Written before ar5212_ini) */
+static const struct ath5k_ini_mode ar5212_ini_mode_start[] = {
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(0),
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(1),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(2),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(3),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(4),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(5),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(6),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(7),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(8),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(9),
+	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_DCU_GBL_IFS_SIFS,
+	   { 0x00000230, 0x000001e0, 0x000000b0, 0x00000160, 0x000001e0 } },
+	{ AR5K_DCU_GBL_IFS_SLOT,
+	   { 0x00000168, 0x000001e0, 0x000001b8, 0x0000018c, 0x000001e0 } },
+	{ AR5K_DCU_GBL_IFS_EIFS,
+	   { 0x00000e60, 0x00001180, 0x00001f1c, 0x00003e38, 0x00001180 } },
+	{ AR5K_DCU_GBL_IFS_MISC,
+	   { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000b0e0, 0x00014068 } },
+	{ AR5K_TIME_OUT,
+	   { 0x03e803e8, 0x06e006e0, 0x04200420, 0x08400840, 0x06e006e0 } },
+	{ AR5K_PHY_TURBO,
+	   { 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000003 } },
+	{ AR5K_PHY(8),
+	   { 0x02020200, 0x02020200, 0x02010200, 0x02020200, 0x02020200 } },
+	{ AR5K_PHY_RF_CTL2,
+	   { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY_SETTLING,
+	   { 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } },
+	{ AR5K_PHY_AGCCTL,
+	   { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d10 } },
+	{ AR5K_PHY_NF,
+	   { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
+	{ AR5K_PHY_WEAK_OFDM_HIGH_THR,
+	   { 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 } },
+	{ AR5K_PHY(70),
+	   { 0x000001b8, 0x000001b8, 0x00000084, 0x00000108, 0x000001b8 } },
+	{ AR5K_PHY_OFDM_SELFCORR,
+	   { 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05 } },
+	{ 0xa230,
+	   { 0x00000000, 0x00000000, 0x00000000, 0x00000108, 0x00000000 } },
+};
+
+/* Initial mode-specific settings for AR5212 + RF5111 (Written after ar5212_ini) */
+static const struct ath5k_ini_mode rf5111_ini_mode_end[] = {
+	{ AR5K_TXCFG,
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
+	{ AR5K_USEC_5211,
+	   { 0x128d8fa7, 0x09880fcf, 0x04e00f95, 0x12e00fab, 0x09880fcf } },
+	{ AR5K_PHY_RF_CTL3,
+	   { 0x0a020001, 0x0a020001, 0x05010100, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY_RF_CTL4,
+	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY_PA_CTL,
+	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY_GAIN,
+	   { 0x0018da5a, 0x0018da5a, 0x0018ca69, 0x0018ca69, 0x0018ca69 } },
+	{ AR5K_PHY_DESIRED_SIZE,
+	   { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
+	{ AR5K_PHY_SIG,
+	   { 0x7e800d2e, 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e, 0x7e800d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+	   { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137615e } },
+	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
+	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb080, 0x050cb080 } },
+	{ AR5K_PHY_RX_DELAY,
+	   { 0x00002710, 0x00002710, 0x0000157c, 0x00002af8, 0x00002710 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+	   { 0xf7b81020, 0xf7b81020, 0xf7b80d20, 0xf7b81020, 0xf7b81020 } },
+	{ AR5K_PHY_GAIN_2GHZ,
+	   { 0x642c416a, 0x642c416a, 0x6440416a, 0x6440416a, 0x6440416a } },
+	{ AR5K_PHY_CCK_RX_CTL_4,
+	   { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
+};
+
+static const struct ath5k_ini rf5111_ini_common_end[] = {
+	{ AR5K_DCU_FP,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_AGC, 	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_ADC_CTL, 	0x00022ffe, AR5K_INI_WRITE },
+	{ 0x983c, 		0x00020100, AR5K_INI_WRITE },
+	{ AR5K_PHY_GAIN_OFFSET,	0x1284613c, AR5K_INI_WRITE },
+	{ AR5K_PHY_PAPD_PROBE,	0x00004883, AR5K_INI_WRITE },
+	{ 0x9940,		0x00000004, AR5K_INI_WRITE },
+	{ 0x9958,		0x000000ff, AR5K_INI_WRITE },
+	{ 0x9974,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_SPENDING,	0x00000018, AR5K_INI_WRITE },
+	{ AR5K_PHY_CCKTXCTL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_CCK_CROSSCORR, 0xd03e6788, AR5K_INI_WRITE },
+	{ AR5K_PHY_DAG_CCK_CTL,	0x000001b5, AR5K_INI_WRITE },
+	{ 0xa23c,		0x13c889af, AR5K_INI_WRITE },
+};
+
+/* Initial mode-specific settings for AR5212 + RF5112 (Written after ar5212_ini) */
+static const struct ath5k_ini_mode rf5112_ini_mode_end[] = {
+	{ AR5K_TXCFG,
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
+	{ AR5K_USEC_5211,
+	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+	{ AR5K_PHY_RF_CTL3,
+	   { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY_RF_CTL4,
+	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY_PA_CTL,
+	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY_GAIN,
+	   { 0x0018da6d, 0x0018da6d, 0x0018ca75, 0x0018ca75, 0x0018ca75 } },
+	{ AR5K_PHY_DESIRED_SIZE,
+	   { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
+	{ AR5K_PHY_SIG,
+	   { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7e800d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+	   { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } },
+	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
+	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+	{ AR5K_PHY_RX_DELAY,
+	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+	   { 0xf7b81020, 0xf7b81020, 0xf7b80d10, 0xf7b81010, 0xf7b81010 } },
+	{ AR5K_PHY_CCKTXCTL,
+	   { 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008 } },
+	{ AR5K_PHY_CCK_CROSSCORR,
+	   { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+	{ AR5K_PHY_GAIN_2GHZ,
+	   { 0x642c0140, 0x642c0140, 0x6442c160, 0x6442c160, 0x6442c160 } },
+	{ AR5K_PHY_CCK_RX_CTL_4,
+	   { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
+};
+
+static const struct ath5k_ini rf5112_ini_common_end[] = {
+	{ AR5K_DCU_FP,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_AGC,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_ADC_CTL,	0x00022ffe, AR5K_INI_WRITE },
+	{ 0x983c,		0x00020100, AR5K_INI_WRITE },
+	{ AR5K_PHY_GAIN_OFFSET,	0x1284613c, AR5K_INI_WRITE },
+	{ AR5K_PHY_PAPD_PROBE,	0x00004882, AR5K_INI_WRITE },
+	{ 0x9940,		0x00000004, AR5K_INI_WRITE },
+	{ 0x9958,		0x000000ff, AR5K_INI_WRITE },
+	{ 0x9974,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_DAG_CCK_CTL,	0x000001b5, AR5K_INI_WRITE },
+	{ 0xa23c,		0x13c889af, AR5K_INI_WRITE },
+};
+
+/* Initial mode-specific settings for RF5413/5414 (Written after ar5212_ini) */
+static const struct ath5k_ini_mode rf5413_ini_mode_end[] = {
+	{ AR5K_TXCFG,
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
+	{ AR5K_USEC_5211,
+	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+	{ AR5K_PHY_RF_CTL3,
+	   { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY_RF_CTL4,
+	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY_PA_CTL,
+	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY_GAIN,
+	   { 0x0018fa61, 0x0018fa61, 0x001a1a63, 0x001a1a63, 0x001a1a63 } },
+	{ AR5K_PHY_DESIRED_SIZE,
+	   { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } },
+	{ AR5K_PHY_SIG,
+	   { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+	   { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
+	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
+	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+	{ AR5K_PHY_RX_DELAY,
+	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+	   { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+	{ AR5K_PHY_CCKTXCTL,
+	   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY_CCK_CROSSCORR,
+	   { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+	{ AR5K_PHY_GAIN_2GHZ,
+	   { 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 } },
+	{ AR5K_PHY_CCK_RX_CTL_4,
+	   { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+	{ 0xa300,
+	   { 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 } },
+	{ 0xa304,
+	   { 0x30032602, 0x30032602, 0x30032602, 0x30032602, 0x30032602 } },
+	{ 0xa308,
+	   { 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06 } },
+	{ 0xa30c,
+	   { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } },
+	{ 0xa310,
+	   { 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f } },
+	{ 0xa314,
+	   { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } },
+	{ 0xa318,
+	   { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } },
+	{ 0xa31c,
+	   { 0x90cf865b, 0x90cf865b, 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } },
+	{ 0xa320,
+	   { 0x9d4f970f, 0x9d4f970f, 0x9b4f970f, 0x9b4f970f, 0x9b4f970f } },
+	{ 0xa324,
+	   { 0xa7cfa38f, 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f, 0xa3cf9f8f } },
+	{ 0xa328,
+	   { 0xb55faf1f, 0xb55faf1f, 0xb35faf1f, 0xb35faf1f, 0xb35faf1f } },
+	{ 0xa32c,
+	   { 0xbddfb99f, 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f, 0xbbdfb99f } },
+	{ 0xa330,
+	   { 0xcb7fc53f, 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f, 0xcb7fc73f } },
+	{ 0xa334,
+	   { 0xd5ffd1bf, 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf } },
+};
+
+static const struct ath5k_ini rf5413_ini_common_end[] = {
+	{ AR5K_DCU_FP,		0x000003e0, AR5K_INI_WRITE },
+	{ AR5K_5414_CBCFG,	0x00000010, AR5K_INI_WRITE },
+	{ AR5K_SEQ_MASK,	0x0000000f, AR5K_INI_WRITE },
+	{ 0x809c,		0x00000000, AR5K_INI_WRITE },
+	{ 0x80a0,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MIC_QOS_CTL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MIC_QOS_SEL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MISC_MODE,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_OFDM_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_CCK_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT1,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT1_MASK, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT2,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT2_MASK, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_TSF_THRES,	0x00000000, AR5K_INI_WRITE },
+	{ 0x8140,		0x800003f9, AR5K_INI_WRITE },
+	{ 0x8144,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_AGC,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_ADC_CTL,	0x0000a000, AR5K_INI_WRITE },
+	{ 0x983c,		0x00200400, AR5K_INI_WRITE },
+	{ AR5K_PHY_GAIN_OFFSET, 0x1284233c, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCR,		0x0000001f, AR5K_INI_WRITE },
+	{ AR5K_PHY_SLMT,	0x00000080, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCAL,	0x0000000e, AR5K_INI_WRITE },
+	{ 0x9958,		0x00081fff, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_7,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_8,	0x02800000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_11,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000, AR5K_INI_WRITE },
+	{ 0x99e4,		0xaaaaaaaa, AR5K_INI_WRITE },
+	{ 0x99e8,		0x3c466478, AR5K_INI_WRITE },
+	{ 0x99ec,		0x000000aa, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCLOCK,	0x0000000c, AR5K_INI_WRITE },
+	{ AR5K_PHY_SDELAY,	0x000000ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_SPENDING,	0x00000014, AR5K_INI_WRITE },
+	{ AR5K_PHY_DAG_CCK_CTL, 0x000009b5, AR5K_INI_WRITE },
+	{ 0xa23c,		0x93c889af, AR5K_INI_WRITE },
+	{ AR5K_PHY_FAST_ADC,	0x00000001, AR5K_INI_WRITE },
+	{ 0xa250,		0x0000a000, AR5K_INI_WRITE },
+	{ AR5K_PHY_BLUETOOTH,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TPC_RG1,	0x0cc75380, AR5K_INI_WRITE },
+	{ 0xa25c,		0x0f0f0f01, AR5K_INI_WRITE },
+	{ 0xa260,		0x5f690f01, AR5K_INI_WRITE },
+	{ 0xa264,		0x00418a11, AR5K_INI_WRITE },
+	{ 0xa268,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TPC_RG5,	0x0c30c16a, AR5K_INI_WRITE },
+	{ 0xa270, 0x00820820, AR5K_INI_WRITE },
+	{ 0xa274, 0x081b7caa, AR5K_INI_WRITE },
+	{ 0xa278, 0x1ce739ce, AR5K_INI_WRITE },
+	{ 0xa27c, 0x051701ce, AR5K_INI_WRITE },
+	{ 0xa338, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa33c, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa340, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa344, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa348, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa34c, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa350, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa354, 0x0003ffff, AR5K_INI_WRITE },
+	{ 0xa358, 0x79a8aa1f, AR5K_INI_WRITE },
+	{ 0xa35c, 0x066c420f, AR5K_INI_WRITE },
+	{ 0xa360, 0x0f282207, AR5K_INI_WRITE },
+	{ 0xa364, 0x17601685, AR5K_INI_WRITE },
+	{ 0xa368, 0x1f801104, AR5K_INI_WRITE },
+	{ 0xa36c, 0x37a00c03, AR5K_INI_WRITE },
+	{ 0xa370, 0x3fc40883, AR5K_INI_WRITE },
+	{ 0xa374, 0x57c00803, AR5K_INI_WRITE },
+	{ 0xa378, 0x5fd80682, AR5K_INI_WRITE },
+	{ 0xa37c, 0x7fe00482, AR5K_INI_WRITE },
+	{ 0xa380, 0x7f3c7bba, AR5K_INI_WRITE },
+	{ 0xa384, 0xf3307ff0, AR5K_INI_WRITE },
+};
+
+/* Initial mode-specific settings for RF2413/2414 (Written after ar5212_ini) */
+/* XXX: a mode ? */
+static const struct ath5k_ini_mode rf2413_ini_mode_end[] = {
+	{ AR5K_TXCFG,
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
+	{ AR5K_USEC_5211,
+	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+	{ AR5K_PHY_RF_CTL3,
+	   { 0x0a020001, 0x0a020001, 0x05020000, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY_RF_CTL4,
+	   { 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00 } },
+	{ AR5K_PHY_PA_CTL,
+	   { 0x00000002, 0x00000002, 0x0000000a, 0x0000000a, 0x0000000a } },
+	{ AR5K_PHY_GAIN,
+	   { 0x0018da6d, 0x0018da6d, 0x001a6a64, 0x001a6a64, 0x001a6a64 } },
+	{ AR5K_PHY_DESIRED_SIZE,
+	   { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b0da, 0x0c98b0da, 0x0de8b0da } },
+	{ AR5K_PHY_SIG,
+	   { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ec80d2e, 0x7e800d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+	   { 0x3137665e, 0x3137665e, 0x3137665e, 0x3139605e, 0x3137665e } },
+	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
+	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+	{ AR5K_PHY_RX_DELAY,
+	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+	   { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+	{ AR5K_PHY_CCKTXCTL,
+	   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY_CCK_CROSSCORR,
+	   { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+	{ AR5K_PHY_GAIN_2GHZ,
+	   { 0x002c0140, 0x002c0140, 0x0042c140, 0x0042c140, 0x0042c140 } },
+	{ AR5K_PHY_CCK_RX_CTL_4,
+	   { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+};
+
+static const struct ath5k_ini rf2413_ini_common_end[] = {
+	{ AR5K_DCU_FP,		0x000003e0, AR5K_INI_WRITE },
+	{ AR5K_SEQ_MASK,	0x0000000f, AR5K_INI_WRITE },
+	{ AR5K_MIC_QOS_CTL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MIC_QOS_SEL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MISC_MODE,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_OFDM_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_CCK_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT1,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT1_MASK, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT2,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT2_MASK, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_TSF_THRES,	0x00000000, AR5K_INI_WRITE },
+	{ 0x8140,		0x800000a8, AR5K_INI_WRITE },
+	{ 0x8144,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_AGC,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_ADC_CTL,	0x0000a000, AR5K_INI_WRITE },
+	{ 0x983c,		0x00200400, AR5K_INI_WRITE },
+	{ AR5K_PHY_GAIN_OFFSET,	0x1284233c, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCR,		0x0000001f, AR5K_INI_WRITE },
+	{ AR5K_PHY_SLMT,	0x00000080, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCAL,	0x0000000e, AR5K_INI_WRITE },
+	{ 0x9958,		0x000000ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_7,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_8,	0x02800000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_11,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000, AR5K_INI_WRITE },
+	{ 0x99e4,		0xaaaaaaaa, AR5K_INI_WRITE },
+	{ 0x99e8,		0x3c466478, AR5K_INI_WRITE },
+	{ 0x99ec,		0x000000aa, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCLOCK,	0x0000000c, AR5K_INI_WRITE },
+	{ AR5K_PHY_SDELAY,	0x000000ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_SPENDING,	0x00000014, AR5K_INI_WRITE },
+	{ AR5K_PHY_DAG_CCK_CTL,	0x000009b5, AR5K_INI_WRITE },
+	{ 0xa23c,		0x93c889af, AR5K_INI_WRITE },
+	{ AR5K_PHY_FAST_ADC,	0x00000001, AR5K_INI_WRITE },
+	{ 0xa250,		0x0000a000, AR5K_INI_WRITE },
+	{ AR5K_PHY_BLUETOOTH,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TPC_RG1,	0x0cc75380, AR5K_INI_WRITE },
+	{ 0xa25c,		0x0f0f0f01, AR5K_INI_WRITE },
+	{ 0xa260,		0x5f690f01, AR5K_INI_WRITE },
+	{ 0xa264,		0x00418a11, AR5K_INI_WRITE },
+	{ 0xa268,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TPC_RG5,	0x0c30c16a, AR5K_INI_WRITE },
+	{ 0xa270, 0x00820820, AR5K_INI_WRITE },
+	{ 0xa274, 0x001b7caa, AR5K_INI_WRITE },
+	{ 0xa278, 0x1ce739ce, AR5K_INI_WRITE },
+	{ 0xa27c, 0x051701ce, AR5K_INI_WRITE },
+	{ 0xa300, 0x18010000, AR5K_INI_WRITE },
+	{ 0xa304, 0x30032602, AR5K_INI_WRITE },
+	{ 0xa308, 0x48073e06, AR5K_INI_WRITE },
+	{ 0xa30c, 0x560b4c0a, AR5K_INI_WRITE },
+	{ 0xa310, 0x641a600f, AR5K_INI_WRITE },
+	{ 0xa314, 0x784f6e1b, AR5K_INI_WRITE },
+	{ 0xa318, 0x868f7c5a, AR5K_INI_WRITE },
+	{ 0xa31c, 0x8ecf865b, AR5K_INI_WRITE },
+	{ 0xa320, 0x9d4f970f, AR5K_INI_WRITE },
+	{ 0xa324, 0xa5cfa18f, AR5K_INI_WRITE },
+	{ 0xa328, 0xb55faf1f, AR5K_INI_WRITE },
+	{ 0xa32c, 0xbddfb99f, AR5K_INI_WRITE },
+	{ 0xa330, 0xcd7fc73f, AR5K_INI_WRITE },
+	{ 0xa334, 0xd5ffd1bf, AR5K_INI_WRITE },
+	{ 0xa338, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa33c, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa340, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa344, 0x00000000, AR5K_INI_WRITE },
+	{ 0xa348, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa34c, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa350, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa354, 0x0003ffff, AR5K_INI_WRITE },
+	{ 0xa358, 0x79a8aa1f, AR5K_INI_WRITE },
+	{ 0xa35c, 0x066c420f, AR5K_INI_WRITE },
+	{ 0xa360, 0x0f282207, AR5K_INI_WRITE },
+	{ 0xa364, 0x17601685, AR5K_INI_WRITE },
+	{ 0xa368, 0x1f801104, AR5K_INI_WRITE },
+	{ 0xa36c, 0x37a00c03, AR5K_INI_WRITE },
+	{ 0xa370, 0x3fc40883, AR5K_INI_WRITE },
+	{ 0xa374, 0x57c00803, AR5K_INI_WRITE },
+	{ 0xa378, 0x5fd80682, AR5K_INI_WRITE },
+	{ 0xa37c, 0x7fe00482, AR5K_INI_WRITE },
+	{ 0xa380, 0x7f3c7bba, AR5K_INI_WRITE },
+	{ 0xa384, 0xf3307ff0, AR5K_INI_WRITE },
+};
+
+/* Initial mode-specific settings for RF2425 (Written after ar5212_ini) */
+/* XXX: a mode ? */
+static const struct ath5k_ini_mode rf2425_ini_mode_end[] = {
+	{ AR5K_TXCFG,
+	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
+	   { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
+	{ AR5K_USEC_5211,
+	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+	{ AR5K_PHY_TURBO,
+	   { 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001 } },
+	{ AR5K_PHY_RF_CTL3,
+	   { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY_RF_CTL4,
+	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY_PA_CTL,
+	   { 0x00000003, 0x00000003, 0x0000000b, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY_SETTLING,
+	   { 0x1372161c, 0x13721c25, 0x13721722, 0x13721422, 0x13721c25 } },
+	{ AR5K_PHY_GAIN,
+	   { 0x0018fa61, 0x0018fa61, 0x00199a65, 0x00199a65, 0x00199a65 } },
+	{ AR5K_PHY_DESIRED_SIZE,
+	   { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } },
+	{ AR5K_PHY_SIG,
+	   { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+	   { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
+	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
+	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+	{ AR5K_PHY_RX_DELAY,
+	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+	   { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+	{ AR5K_PHY_CCKTXCTL,
+	   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY_CCK_CROSSCORR,
+	   { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+	{ AR5K_PHY_GAIN_2GHZ,
+	   { 0x00000140, 0x00000140, 0x0052c140, 0x0052c140, 0x0052c140 } },
+	{ AR5K_PHY_CCK_RX_CTL_4,
+	   { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+	{ 0xa324,
+	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+	{ 0xa328,
+	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+	{ 0xa32c,
+	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+	{ 0xa330,
+	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+	{ 0xa334,
+	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+};
+
+static const struct ath5k_ini rf2425_ini_common_end[] = {
+	{ AR5K_DCU_FP,		0x000003e0, AR5K_INI_WRITE },
+	{ AR5K_SEQ_MASK,	0x0000000f, AR5K_INI_WRITE },
+	{ 0x809c,		0x00000000, AR5K_INI_WRITE },
+	{ 0x80a0,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MIC_QOS_CTL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MIC_QOS_SEL,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_MISC_MODE,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_OFDM_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_CCK_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT1,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT1_MASK, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT2,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHYERR_CNT2_MASK, 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_TSF_THRES,	0x00000000, AR5K_INI_WRITE },
+	{ 0x8140,		0x800003f9, AR5K_INI_WRITE },
+	{ 0x8144,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_AGC,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_ADC_CTL,	0x0000a000, AR5K_INI_WRITE },
+	{ 0x983c,		0x00200400, AR5K_INI_WRITE },
+	{ AR5K_PHY_GAIN_OFFSET, 0x1284233c, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCR,		0x0000001f, AR5K_INI_WRITE },
+	{ AR5K_PHY_SLMT,	0x00000080, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCAL,	0x0000000e, AR5K_INI_WRITE },
+	{ 0x9958,		0x00081fff, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_7,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_8,	0x02800000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TIMING_11,	0x00000000, AR5K_INI_WRITE },
+	{ 0x99dc,		0xfebadbe8, AR5K_INI_WRITE },
+	{ AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000, AR5K_INI_WRITE },
+	{ 0x99e4,		0xaaaaaaaa, AR5K_INI_WRITE },
+	{ 0x99e8,		0x3c466478, AR5K_INI_WRITE },
+	{ 0x99ec,		0x000000aa, AR5K_INI_WRITE },
+	{ AR5K_PHY_SCLOCK,	0x0000000c, AR5K_INI_WRITE },
+	{ AR5K_PHY_SDELAY,	0x000000ff, AR5K_INI_WRITE },
+	{ AR5K_PHY_SPENDING,	0x00000014, AR5K_INI_WRITE },
+	{ AR5K_PHY_DAG_CCK_CTL,	0x000009b5, AR5K_INI_WRITE },
+	{ AR5K_PHY_TXPOWER_RATE3, 0x20202020, AR5K_INI_WRITE },
+	{ AR5K_PHY_TXPOWER_RATE4, 0x20202020, AR5K_INI_WRITE },
+	{ 0xa23c,		0x93c889af, AR5K_INI_WRITE },
+	{ AR5K_PHY_FAST_ADC,	0x00000001, AR5K_INI_WRITE },
+	{ 0xa250,		0x0000a000, AR5K_INI_WRITE },
+	{ AR5K_PHY_BLUETOOTH,	0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TPC_RG1,	0x0cc75380, AR5K_INI_WRITE },
+	{ 0xa25c,		0x0f0f0f01, AR5K_INI_WRITE },
+	{ 0xa260,		0x5f690f01, AR5K_INI_WRITE },
+	{ 0xa264,		0x00418a11, AR5K_INI_WRITE },
+	{ 0xa268,		0x00000000, AR5K_INI_WRITE },
+	{ AR5K_PHY_TPC_RG5,	0x0c30c166, AR5K_INI_WRITE },
+	{ 0xa270, 0x00820820, AR5K_INI_WRITE },
+	{ 0xa274, 0x081a3caa, AR5K_INI_WRITE },
+	{ 0xa278, 0x1ce739ce, AR5K_INI_WRITE },
+	{ 0xa27c, 0x051701ce, AR5K_INI_WRITE },
+	{ 0xa300, 0x16010000, AR5K_INI_WRITE },
+	{ 0xa304, 0x2c032402, AR5K_INI_WRITE },
+	{ 0xa308, 0x48433e42, AR5K_INI_WRITE },
+	{ 0xa30c, 0x5a0f500b, AR5K_INI_WRITE },
+	{ 0xa310, 0x6c4b624a, AR5K_INI_WRITE },
+	{ 0xa314, 0x7e8b748a, AR5K_INI_WRITE },
+	{ 0xa318, 0x96cf8ccb, AR5K_INI_WRITE },
+	{ 0xa31c, 0xa34f9d0f, AR5K_INI_WRITE },
+	{ 0xa320, 0xa7cfa58f, AR5K_INI_WRITE },
+	{ 0xa348, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa34c, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa350, 0x3fffffff, AR5K_INI_WRITE },
+	{ 0xa354, 0x0003ffff, AR5K_INI_WRITE },
+	{ 0xa358, 0x79a8aa1f, AR5K_INI_WRITE },
+	{ 0xa35c, 0x066c420f, AR5K_INI_WRITE },
+	{ 0xa360, 0x0f282207, AR5K_INI_WRITE },
+	{ 0xa364, 0x17601685, AR5K_INI_WRITE },
+	{ 0xa368, 0x1f801104, AR5K_INI_WRITE },
+	{ 0xa36c, 0x37a00c03, AR5K_INI_WRITE },
+	{ 0xa370, 0x3fc40883, AR5K_INI_WRITE },
+	{ 0xa374, 0x57c00803, AR5K_INI_WRITE },
+	{ 0xa378, 0x5fd80682, AR5K_INI_WRITE },
+	{ 0xa37c, 0x7fe00482, AR5K_INI_WRITE },
+	{ 0xa380, 0x7f3c7bba, AR5K_INI_WRITE },
+	{ 0xa384, 0xf3307ff0, AR5K_INI_WRITE },
+};
+
+/*
+ * Initial BaseBand Gain settings for RF5111/5112 (AR5210 comes with
+ * RF5110 only so initial BB Gain settings are included in AR5K_AR5210_INI)
+ */
+
+/* RF5111 Initial BaseBand Gain settings */
+static const struct ath5k_ini rf5111_ini_bbgain[] = {
+	{ AR5K_BB_GAIN(0), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(1), 0x00000020, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(2), 0x00000010, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(3), 0x00000030, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(4), 0x00000008, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(5), 0x00000028, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(6), 0x00000004, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(7), 0x00000024, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(8), 0x00000014, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(9), 0x00000034, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(10), 0x0000000c, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(11), 0x0000002c, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(12), 0x00000002, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(13), 0x00000022, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(14), 0x00000012, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(15), 0x00000032, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(16), 0x0000000a, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(17), 0x0000002a, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(18), 0x00000006, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(19), 0x00000026, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(20), 0x00000016, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(21), 0x00000036, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(22), 0x0000000e, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(23), 0x0000002e, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(24), 0x00000001, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(25), 0x00000021, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(26), 0x00000011, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(27), 0x00000031, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(28), 0x00000009, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(29), 0x00000029, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(30), 0x00000005, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(31), 0x00000025, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(32), 0x00000015, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(33), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(34), 0x0000000d, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(35), 0x0000002d, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(36), 0x00000003, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(37), 0x00000023, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(38), 0x00000013, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(39), 0x00000033, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(40), 0x0000000b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(41), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(42), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(43), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(44), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(45), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(46), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(47), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(48), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(49), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(50), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(51), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(52), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(53), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(54), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(55), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(56), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(57), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(58), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(59), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(60), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(61), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(62), 0x00000002, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(63), 0x00000016, AR5K_INI_WRITE },
+};
+
+/* RF5112 Initial BaseBand Gain settings (Same for RF5413/5414+) */
+static const struct ath5k_ini rf5112_ini_bbgain[] = {
+	{ AR5K_BB_GAIN(0), 0x00000000, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(1), 0x00000001, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(2), 0x00000002, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(3), 0x00000003, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(4), 0x00000004, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(5), 0x00000005, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(6), 0x00000008, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(7), 0x00000009, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(8), 0x0000000a, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(9), 0x0000000b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(10), 0x0000000c, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(11), 0x0000000d, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(12), 0x00000010, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(13), 0x00000011, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(14), 0x00000012, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(15), 0x00000013, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(16), 0x00000014, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(17), 0x00000015, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(18), 0x00000018, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(19), 0x00000019, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(20), 0x0000001a, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(21), 0x0000001b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(22), 0x0000001c, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(23), 0x0000001d, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(24), 0x00000020, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(25), 0x00000021, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(26), 0x00000022, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(27), 0x00000023, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(28), 0x00000024, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(29), 0x00000025, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(30), 0x00000028, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(31), 0x00000029, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(32), 0x0000002a, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(33), 0x0000002b, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(34), 0x0000002c, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(35), 0x0000002d, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(36), 0x00000030, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(37), 0x00000031, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(38), 0x00000032, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(39), 0x00000033, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(40), 0x00000034, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(41), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(42), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(43), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(44), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(45), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(46), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(47), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(48), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(49), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(50), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(51), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(52), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(53), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(54), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(55), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(56), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(57), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(58), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(59), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(60), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(61), 0x00000035, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(62), 0x00000010, AR5K_INI_WRITE },
+	{ AR5K_BB_GAIN(63), 0x0000001a, AR5K_INI_WRITE },
+};
+
+
+/*
+ * Write initial register dump
+ */
+static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size,
+		const struct ath5k_ini *ini_regs, int change_channel)
+{
+	unsigned int i;
+
+	/* Write initial registers */
+	for (i = 0; i < size; i++) {
+		/* On channel change there is
+		 * no need to mess with PCU */
+		if (change_channel &&
+				ini_regs[i].ini_register >= AR5K_PCU_MIN &&
+				ini_regs[i].ini_register <= AR5K_PCU_MAX)
+			continue;
+
+		switch (ini_regs[i].ini_mode) {
+		case AR5K_INI_READ:
+			/* Cleared on read */
+			ath5k_hw_reg_read(ah, ini_regs[i].ini_register);
+			break;
+		case AR5K_INI_WRITE:
+		default:
+			AR5K_REG_WAIT(i);
+			ath5k_hw_reg_write(ah, ini_regs[i].ini_value,
+					ini_regs[i].ini_register);
+		}
+	}
+}
+
+static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah,
+		unsigned int size, const struct ath5k_ini_mode *ini_mode,
+		u8 mode)
+{
+	unsigned int i;
+
+	for (i = 0; i < size; i++) {
+		AR5K_REG_WAIT(i);
+		ath5k_hw_reg_write(ah, ini_mode[i].mode_value[mode],
+			(u32)ini_mode[i].mode_register);
+	}
+}
+
+int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, int change_channel)
+{
+	/*
+	 * Write initial register settings
+	 */
+
+	/* For AR5212 and combatible */
+	if (ah->ah_version == AR5K_AR5212) {
+
+		/* First set of mode-specific settings */
+		ath5k_hw_ini_mode_registers(ah,
+			ARRAY_SIZE(ar5212_ini_mode_start),
+			ar5212_ini_mode_start, mode);
+
+		/*
+		 * Write initial settings common for all modes
+		 */
+		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5212_ini_common_start),
+				ar5212_ini_common_start, change_channel);
+
+		/* Second set of mode-specific settings */
+		switch (ah->ah_radio) {
+		case AR5K_RF5111:
+
+			ath5k_hw_ini_mode_registers(ah,
+					ARRAY_SIZE(rf5111_ini_mode_end),
+					rf5111_ini_mode_end, mode);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5111_ini_common_end),
+					rf5111_ini_common_end, change_channel);
+
+			/* Baseband gain table */
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5111_ini_bbgain),
+					rf5111_ini_bbgain, change_channel);
+
+			break;
+		case AR5K_RF5112:
+
+			ath5k_hw_ini_mode_registers(ah,
+					ARRAY_SIZE(rf5112_ini_mode_end),
+					rf5112_ini_mode_end, mode);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5112_ini_common_end),
+					rf5112_ini_common_end, change_channel);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5112_ini_bbgain),
+					rf5112_ini_bbgain, change_channel);
+
+			break;
+		case AR5K_RF5413:
+
+			ath5k_hw_ini_mode_registers(ah,
+					ARRAY_SIZE(rf5413_ini_mode_end),
+					rf5413_ini_mode_end, mode);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5413_ini_common_end),
+					rf5413_ini_common_end, change_channel);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5112_ini_bbgain),
+					rf5112_ini_bbgain, change_channel);
+
+			break;
+		case AR5K_RF2316:
+		case AR5K_RF2413:
+
+			ath5k_hw_ini_mode_registers(ah,
+					ARRAY_SIZE(rf2413_ini_mode_end),
+					rf2413_ini_mode_end, mode);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf2413_ini_common_end),
+					rf2413_ini_common_end, change_channel);
+
+			/* Override settings from rf2413_ini_common_end */
+			if (ah->ah_radio == AR5K_RF2316) {
+				ath5k_hw_reg_write(ah, 0x00004000,
+							AR5K_PHY_AGC);
+				ath5k_hw_reg_write(ah, 0x081b7caa,
+							0xa274);
+			}
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5112_ini_bbgain),
+					rf5112_ini_bbgain, change_channel);
+			break;
+		case AR5K_RF2317:
+		case AR5K_RF2425:
+
+			ath5k_hw_ini_mode_registers(ah,
+					ARRAY_SIZE(rf2425_ini_mode_end),
+					rf2425_ini_mode_end, mode);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf2425_ini_common_end),
+					rf2425_ini_common_end, change_channel);
+
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5112_ini_bbgain),
+					rf5112_ini_bbgain, change_channel);
+			break;
+		default:
+			return -EINVAL;
+
+		}
+
+	/* For AR5211 */
+	} else if (ah->ah_version == AR5K_AR5211) {
+
+		/* AR5K_MODE_11B */
+		if (mode > 2) {
+			DBG("ath5k: unsupported channel mode %d\n", mode);
+			return -EINVAL;
+		}
+
+		/* Mode-specific settings */
+		ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5211_ini_mode),
+				ar5211_ini_mode, mode);
+
+		/*
+		 * Write initial settings common for all modes
+		 */
+		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5211_ini),
+				ar5211_ini, change_channel);
+
+		/* AR5211 only comes with 5111 */
+
+		/* Baseband gain table */
+		ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_bbgain),
+				rf5111_ini_bbgain, change_channel);
+	/* For AR5210 (for mode settings check out ath5k_hw_reset_tx_queue) */
+	} else if (ah->ah_version == AR5K_AR5210) {
+		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5210_ini),
+				ar5210_ini, change_channel);
+	}
+
+	return 0;
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_pcu.c b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_pcu.c
new file mode 100644
index 0000000000000000000000000000000000000000..c8165da792e453b0dc6703fd6c054a2e33844b56
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_pcu.c
@@ -0,0 +1,534 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007-2008 Matthew W. S. Bell  <mentor@madwifi.org>
+ * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
+ * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
+ * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/*********************************\
+* Protocol Control Unit Functions *
+\*********************************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*******************\
+* Generic functions *
+\*******************/
+
+/**
+ * ath5k_hw_set_opmode - Set PCU operating mode
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Initialize PCU for the various operating modes (AP/STA etc)
+ *
+ * For iPXE we always assume STA mode.
+ */
+int ath5k_hw_set_opmode(struct ath5k_hw *ah)
+{
+	u32 pcu_reg, beacon_reg, low_id, high_id;
+
+
+	/* Preserve rest settings */
+	pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
+	pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
+			| AR5K_STA_ID1_KEYSRCH_MODE
+			| (ah->ah_version == AR5K_AR5210 ?
+			(AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
+
+	beacon_reg = 0;
+
+	pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
+		| (ah->ah_version == AR5K_AR5210 ?
+		   AR5K_STA_ID1_PWR_SV : 0);
+
+	/*
+	 * Set PCU registers
+	 */
+	low_id = AR5K_LOW_ID(ah->ah_sta_id);
+	high_id = AR5K_HIGH_ID(ah->ah_sta_id);
+	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
+	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
+
+	/*
+	 * Set Beacon Control Register on 5210
+	 */
+	if (ah->ah_version == AR5K_AR5210)
+		ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_set_ack_bitrate - set bitrate for ACKs
+ *
+ * @ah: The &struct ath5k_hw
+ * @high: Flag to determine if we want to use high transmition rate
+ * for ACKs or not
+ *
+ * If high flag is set, we tell hw to use a set of control rates based on
+ * the current transmition rate (check out control_rates array inside reset.c).
+ * If not hw just uses the lowest rate available for the current modulation
+ * scheme being used (1Mbit for CCK and 6Mbits for OFDM).
+ */
+void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, int high)
+{
+	if (ah->ah_version != AR5K_AR5212)
+		return;
+	else {
+		u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
+		if (high)
+			AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
+		else
+			AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
+	}
+}
+
+
+/******************\
+* ACK/CTS Timeouts *
+\******************/
+
+/**
+ * ath5k_hw_het_ack_timeout - Get ACK timeout from PCU in usec
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
+{
+	return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
+			AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo);
+}
+
+/**
+ * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU
+ *
+ * @ah: The &struct ath5k_hw
+ * @timeout: Timeout in usec
+ */
+int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
+{
+	if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK),
+			ah->ah_turbo) <= timeout)
+		return -EINVAL;
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
+		ath5k_hw_htoclock(timeout, ah->ah_turbo));
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_get_cts_timeout - Get CTS timeout from PCU in usec
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
+{
+	return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
+			AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo);
+}
+
+/**
+ * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU
+ *
+ * @ah: The &struct ath5k_hw
+ * @timeout: Timeout in usec
+ */
+int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
+{
+	if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS),
+			ah->ah_turbo) <= timeout)
+		return -EINVAL;
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
+			ath5k_hw_htoclock(timeout, ah->ah_turbo));
+
+	return 0;
+}
+
+
+/****************\
+* BSSID handling *
+\****************/
+
+/**
+ * ath5k_hw_get_lladdr - Get station id
+ *
+ * @ah: The &struct ath5k_hw
+ * @mac: The card's mac address
+ *
+ * Initialize ah->ah_sta_id using the mac address provided
+ * (just a memcpy).
+ *
+ * TODO: Remove it once we merge ath5k_softc and ath5k_hw
+ */
+void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
+{
+	memcpy(mac, ah->ah_sta_id, ETH_ALEN);
+}
+
+/**
+ * ath5k_hw_set_lladdr - Set station id
+ *
+ * @ah: The &struct ath5k_hw
+ * @mac: The card's mac address
+ *
+ * Set station id on hw using the provided mac address
+ */
+int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
+{
+	u32 low_id, high_id;
+	u32 pcu_reg;
+
+	/* Set new station ID */
+	memcpy(ah->ah_sta_id, mac, ETH_ALEN);
+
+	pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
+
+	low_id = AR5K_LOW_ID(mac);
+	high_id = AR5K_HIGH_ID(mac);
+
+	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
+	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_set_associd - Set BSSID for association
+ *
+ * @ah: The &struct ath5k_hw
+ * @bssid: BSSID
+ * @assoc_id: Assoc id
+ *
+ * Sets the BSSID which trigers the "SME Join" operation
+ */
+void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
+{
+	u32 low_id, high_id;
+
+	/*
+	 * Set simple BSSID mask on 5212
+	 */
+	if (ah->ah_version == AR5K_AR5212) {
+		ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask),
+							AR5K_BSS_IDM0);
+		ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask),
+							AR5K_BSS_IDM1);
+	}
+
+	/*
+	 * Set BSSID which triggers the "SME Join" operation
+	 */
+	low_id = AR5K_LOW_ID(bssid);
+	high_id = AR5K_HIGH_ID(bssid);
+	ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0);
+	ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) <<
+				AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1);
+}
+
+/**
+ * ath5k_hw_set_bssid_mask - filter out bssids we listen
+ *
+ * @ah: the &struct ath5k_hw
+ * @mask: the bssid_mask, a u8 array of size ETH_ALEN
+ *
+ * BSSID masking is a method used by AR5212 and newer hardware to inform PCU
+ * which bits of the interface's MAC address should be looked at when trying
+ * to decide which packets to ACK. In station mode and AP mode with a single
+ * BSS every bit matters since we lock to only one BSS. In AP mode with
+ * multiple BSSes (virtual interfaces) not every bit matters because hw must
+ * accept frames for all BSSes and so we tweak some bits of our mac address
+ * in order to have multiple BSSes.
+ *
+ * NOTE: This is a simple filter and does *not* filter out all
+ * relevant frames. Some frames that are not for us might get ACKed from us
+ * by PCU because they just match the mask.
+ *
+ * When handling multiple BSSes you can get the BSSID mask by computing the
+ * set of  ~ ( MAC XOR BSSID ) for all bssids we handle.
+ *
+ * When you do this you are essentially computing the common bits of all your
+ * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with
+ * the MAC address to obtain the relevant bits and compare the result with
+ * (frame's BSSID & mask) to see if they match.
+ */
+/*
+ * Simple example: on your card you have have two BSSes you have created with
+ * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address.
+ * There is another BSSID-03 but you are not part of it. For simplicity's sake,
+ * assuming only 4 bits for a mac address and for BSSIDs you can then have:
+ *
+ *                  \
+ * MAC:                0001 |
+ * BSSID-01:   0100 | --> Belongs to us
+ * BSSID-02:   1001 |
+ *                  /
+ * -------------------
+ * BSSID-03:   0110  | --> External
+ * -------------------
+ *
+ * Our bssid_mask would then be:
+ *
+ *             On loop iteration for BSSID-01:
+ *             ~(0001 ^ 0100)  -> ~(0101)
+ *                             ->   1010
+ *             bssid_mask      =    1010
+ *
+ *             On loop iteration for BSSID-02:
+ *             bssid_mask &= ~(0001   ^   1001)
+ *             bssid_mask =   (1010)  & ~(0001 ^ 1001)
+ *             bssid_mask =   (1010)  & ~(1001)
+ *             bssid_mask =   (1010)  &  (0110)
+ *             bssid_mask =   0010
+ *
+ * A bssid_mask of 0010 means "only pay attention to the second least
+ * significant bit". This is because its the only bit common
+ * amongst the MAC and all BSSIDs we support. To findout what the real
+ * common bit is we can simply "&" the bssid_mask now with any BSSID we have
+ * or our MAC address (we assume the hardware uses the MAC address).
+ *
+ * Now, suppose there's an incoming frame for BSSID-03:
+ *
+ * IFRAME-01:  0110
+ *
+ * An easy eye-inspeciton of this already should tell you that this frame
+ * will not pass our check. This is beacuse the bssid_mask tells the
+ * hardware to only look at the second least significant bit and the
+ * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB
+ * as 1, which does not match 0.
+ *
+ * So with IFRAME-01 we *assume* the hardware will do:
+ *
+ *     allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ *  --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0;
+ *  --> allow = (0010) == 0000 ? 1 : 0;
+ *  --> allow = 0
+ *
+ *  Lets now test a frame that should work:
+ *
+ * IFRAME-02:  0001 (we should allow)
+ *
+ *     allow = (0001 & 1010) == 1010
+ *
+ *     allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ *  --> allow = (0001 & 0010) ==  (0010 & 0001) ? 1 :0;
+ *  --> allow = (0010) == (0010)
+ *  --> allow = 1
+ *
+ * Other examples:
+ *
+ * IFRAME-03:  0100 --> allowed
+ * IFRAME-04:  1001 --> allowed
+ * IFRAME-05:  1101 --> allowed but its not for us!!!
+ *
+ */
+int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
+{
+	u32 low_id, high_id;
+
+	/* Cache bssid mask so that we can restore it
+	 * on reset */
+	memcpy(ah->ah_bssid_mask, mask, ETH_ALEN);
+	if (ah->ah_version == AR5K_AR5212) {
+		low_id = AR5K_LOW_ID(mask);
+		high_id = AR5K_HIGH_ID(mask);
+
+		ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0);
+		ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1);
+
+		return 0;
+	}
+
+	return -EIO;
+}
+
+
+/************\
+* RX Control *
+\************/
+
+/**
+ * ath5k_hw_start_rx_pcu - Start RX engine
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Starts RX engine on PCU so that hw can process RXed frames
+ * (ACK etc).
+ *
+ * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
+ * TODO: Init ANI here
+ */
+void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
+{
+	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+}
+
+/**
+ * at5k_hw_stop_rx_pcu - Stop RX engine
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Stops RX engine on PCU
+ *
+ * TODO: Detach ANI here
+ */
+void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
+{
+	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+}
+
+/*
+ * Set multicast filter
+ */
+void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
+{
+	/* Set the multicat filter */
+	ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
+	ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
+}
+
+/**
+ * ath5k_hw_get_rx_filter - Get current rx filter
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Returns the RX filter by reading rx filter and
+ * phy error filter registers. RX filter is used
+ * to set the allowed frame types that PCU will accept
+ * and pass to the driver. For a list of frame types
+ * check out reg.h.
+ */
+u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
+{
+	u32 data, filter = 0;
+
+	filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
+
+	/*Radar detection for 5212*/
+	if (ah->ah_version == AR5K_AR5212) {
+		data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL);
+
+		if (data & AR5K_PHY_ERR_FIL_RADAR)
+			filter |= AR5K_RX_FILTER_RADARERR;
+		if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK))
+			filter |= AR5K_RX_FILTER_PHYERR;
+	}
+
+	return filter;
+}
+
+/**
+ * ath5k_hw_set_rx_filter - Set rx filter
+ *
+ * @ah: The &struct ath5k_hw
+ * @filter: RX filter mask (see reg.h)
+ *
+ * Sets RX filter register and also handles PHY error filter
+ * register on 5212 and newer chips so that we have proper PHY
+ * error reporting.
+ */
+void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
+{
+	u32 data = 0;
+
+	/* Set PHY error filter register on 5212*/
+	if (ah->ah_version == AR5K_AR5212) {
+		if (filter & AR5K_RX_FILTER_RADARERR)
+			data |= AR5K_PHY_ERR_FIL_RADAR;
+		if (filter & AR5K_RX_FILTER_PHYERR)
+			data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK;
+	}
+
+	/*
+	 * The AR5210 uses promiscous mode to detect radar activity
+	 */
+	if (ah->ah_version == AR5K_AR5210 &&
+			(filter & AR5K_RX_FILTER_RADARERR)) {
+		filter &= ~AR5K_RX_FILTER_RADARERR;
+		filter |= AR5K_RX_FILTER_PROM;
+	}
+
+	/*Zero length DMA (phy error reporting) */
+	if (data)
+		AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
+	else
+		AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
+
+	/*Write RX Filter register*/
+	ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER);
+
+	/*Write PHY error filter register on 5212*/
+	if (ah->ah_version == AR5K_AR5212)
+		ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL);
+
+}
+
+/*********************\
+* Key table functions *
+\*********************/
+
+/*
+ * Reset a key entry on the table
+ */
+int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
+{
+	unsigned int i, type;
+	u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
+
+	type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
+
+	for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
+		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
+
+	/* Reset associated MIC entry if TKIP
+	 * is enabled located at offset (entry + 64) */
+	if (type == AR5K_KEYTABLE_TYPE_TKIP) {
+		for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++)
+			ath5k_hw_reg_write(ah, 0,
+				AR5K_KEYTABLE_OFF(micentry, i));
+	}
+
+	/*
+	 * Set NULL encryption on AR5212+
+	 *
+	 * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5)
+	 *       AR5K_KEYTABLE_TYPE_NULL -> 0x00000007
+	 *
+	 * Note2: Windows driver (ndiswrapper) sets this to
+	 *        0x00000714 instead of 0x00000007
+	 */
+	if (ah->ah_version >= AR5K_AR5211) {
+		ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+				AR5K_KEYTABLE_TYPE(entry));
+
+		if (type == AR5K_KEYTABLE_TYPE_TKIP) {
+			ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+				AR5K_KEYTABLE_TYPE(micentry));
+		}
+	}
+
+	return 0;
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_phy.c b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_phy.c
new file mode 100644
index 0000000000000000000000000000000000000000..7891d39eaad34ac858574862895f53e76ae70f9e
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_phy.c
@@ -0,0 +1,2581 @@
+/*
+ * PHY functions
+ *
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2008-2009 Felix Fietkau <nbd@openwrt.org>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+#define _ATH5K_PHY
+
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+#include "rfbuffer.h"
+#include "rfgain.h"
+
+static inline int min(int x, int y)
+{
+	return (x < y) ? x : y;
+}
+
+static inline int max(int x, int y)
+{
+	return (x > y) ? x : y;
+}
+
+/*
+ * Used to modify RF Banks before writing them to AR5K_RF_BUFFER
+ */
+static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
+					const struct ath5k_rf_reg *rf_regs,
+					u32 val, u8 reg_id, int set)
+{
+	const struct ath5k_rf_reg *rfreg = NULL;
+	u8 offset, bank, num_bits, col, position;
+	u16 entry;
+	u32 mask, data, last_bit, bits_shifted, first_bit;
+	u32 *rfb;
+	s32 bits_left;
+	unsigned i;
+
+	data = 0;
+	rfb = ah->ah_rf_banks;
+
+	for (i = 0; i < ah->ah_rf_regs_count; i++) {
+		if (rf_regs[i].index == reg_id) {
+			rfreg = &rf_regs[i];
+			break;
+		}
+	}
+
+	if (rfb == NULL || rfreg == NULL) {
+		DBG("ath5k: RF register not found!\n");
+		/* should not happen */
+		return 0;
+	}
+
+	bank = rfreg->bank;
+	num_bits = rfreg->field.len;
+	first_bit = rfreg->field.pos;
+	col = rfreg->field.col;
+
+	/* first_bit is an offset from bank's
+	 * start. Since we have all banks on
+	 * the same array, we use this offset
+	 * to mark each bank's start */
+	offset = ah->ah_offset[bank];
+
+	/* Boundary check */
+	if (!(col <= 3 && num_bits <= 32 && first_bit + num_bits <= 319)) {
+		DBG("ath5k: RF invalid values at offset %d\n", offset);
+		return 0;
+	}
+
+	entry = ((first_bit - 1) / 8) + offset;
+	position = (first_bit - 1) % 8;
+
+	if (set)
+		data = ath5k_hw_bitswap(val, num_bits);
+
+	for (bits_shifted = 0, bits_left = num_bits; bits_left > 0;
+	position = 0, entry++) {
+
+		last_bit = (position + bits_left > 8) ? 8 :
+					position + bits_left;
+
+		mask = (((1 << last_bit) - 1) ^ ((1 << position) - 1)) <<
+								(col * 8);
+
+		if (set) {
+			rfb[entry] &= ~mask;
+			rfb[entry] |= ((data << position) << (col * 8)) & mask;
+			data >>= (8 - position);
+		} else {
+			data |= (((rfb[entry] & mask) >> (col * 8)) >> position)
+				<< bits_shifted;
+			bits_shifted += last_bit - position;
+		}
+
+		bits_left -= 8 - position;
+	}
+
+	data = set ? 1 : ath5k_hw_bitswap(data, num_bits);
+
+	return data;
+}
+
+/**********************\
+* RF Gain optimization *
+\**********************/
+
+/*
+ * This code is used to optimize rf gain on different environments
+ * (temprature mostly) based on feedback from a power detector.
+ *
+ * It's only used on RF5111 and RF5112, later RF chips seem to have
+ * auto adjustment on hw -notice they have a much smaller BANK 7 and
+ * no gain optimization ladder-.
+ *
+ * For more infos check out this patent doc
+ * http://www.freepatentsonline.com/7400691.html
+ *
+ * This paper describes power drops as seen on the receiver due to
+ * probe packets
+ * http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues
+ * %20of%20Power%20Control.pdf
+ *
+ * And this is the MadWiFi bug entry related to the above
+ * http://madwifi-project.org/ticket/1659
+ * with various measurements and diagrams
+ *
+ * TODO: Deal with power drops due to probes by setting an apropriate
+ * tx power on the probe packets ! Make this part of the calibration process.
+ */
+
+/* Initialize ah_gain durring attach */
+int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah)
+{
+	/* Initialize the gain optimization values */
+	switch (ah->ah_radio) {
+	case AR5K_RF5111:
+		ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default;
+		ah->ah_gain.g_low = 20;
+		ah->ah_gain.g_high = 35;
+		ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+		break;
+	case AR5K_RF5112:
+		ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
+		ah->ah_gain.g_low = 20;
+		ah->ah_gain.g_high = 85;
+		ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Schedule a gain probe check on the next transmited packet.
+ * That means our next packet is going to be sent with lower
+ * tx power and a Peak to Average Power Detector (PAPD) will try
+ * to measure the gain.
+ *
+ * TODO: Use propper tx power setting for the probe packet so
+ * that we don't observe a serious power drop on the receiver
+ *
+ * XXX:  How about forcing a tx packet (bypassing PCU arbitrator etc)
+ * just after we enable the probe so that we don't mess with
+ * standard traffic ? Maybe it's time to use sw interrupts and
+ * a probe tasklet !!!
+ */
+static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah)
+{
+
+	/* Skip if gain calibration is inactive or
+	 * we already handle a probe request */
+	if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE)
+		return;
+
+	/* Send the packet with 2dB below max power as
+	 * patent doc suggest */
+	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max_pwr - 4,
+			AR5K_PHY_PAPD_PROBE_TXPOWER) |
+			AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE);
+
+	ah->ah_gain.g_state = AR5K_RFGAIN_READ_REQUESTED;
+
+}
+
+/* Calculate gain_F measurement correction
+ * based on the current step for RF5112 rev. 2 */
+static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah)
+{
+	u32 mix, step;
+	const struct ath5k_gain_opt *go;
+	const struct ath5k_gain_opt_step *g_step;
+	const struct ath5k_rf_reg *rf_regs;
+
+	/* Only RF5112 Rev. 2 supports it */
+	if ((ah->ah_radio != AR5K_RF5112) ||
+	(ah->ah_radio_5ghz_revision <= AR5K_SREV_RAD_5112A))
+		return 0;
+
+	go = &rfgain_opt_5112;
+	rf_regs = rf_regs_5112a;
+	ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a);
+
+	g_step = &go->go_step[ah->ah_gain.g_step_idx];
+
+	if (ah->ah_rf_banks == NULL)
+		return 0;
+
+	ah->ah_gain.g_f_corr = 0;
+
+	/* No VGA (Variable Gain Amplifier) override, skip */
+	if (ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR, 0) != 1)
+		return 0;
+
+	/* Mix gain stepping */
+	step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXGAIN_STEP, 0);
+
+	/* Mix gain override */
+	mix = g_step->gos_param[0];
+
+	switch (mix) {
+	case 3:
+		ah->ah_gain.g_f_corr = step * 2;
+		break;
+	case 2:
+		ah->ah_gain.g_f_corr = (step - 5) * 2;
+		break;
+	case 1:
+		ah->ah_gain.g_f_corr = step;
+		break;
+	default:
+		ah->ah_gain.g_f_corr = 0;
+		break;
+	}
+
+	return ah->ah_gain.g_f_corr;
+}
+
+/* Check if current gain_F measurement is in the range of our
+ * power detector windows. If we get a measurement outside range
+ * we know it's not accurate (detectors can't measure anything outside
+ * their detection window) so we must ignore it */
+static int ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
+{
+	const struct ath5k_rf_reg *rf_regs;
+	u32 step, mix_ovr, level[4];
+
+	if (ah->ah_rf_banks == NULL)
+		return 0;
+
+	if (ah->ah_radio == AR5K_RF5111) {
+
+		rf_regs = rf_regs_5111;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111);
+
+		step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_RFGAIN_STEP,
+			0);
+
+		level[0] = 0;
+		level[1] = (step == 63) ? 50 : step + 4;
+		level[2] = (step != 63) ? 64 : level[0];
+		level[3] = level[2] + 50 ;
+
+		ah->ah_gain.g_high = level[3] -
+			(step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
+		ah->ah_gain.g_low = level[0] +
+			(step == 63 ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
+	} else {
+
+		rf_regs = rf_regs_5112;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112);
+
+		mix_ovr = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR,
+			0);
+
+		level[0] = level[2] = 0;
+
+		if (mix_ovr == 1) {
+			level[1] = level[3] = 83;
+		} else {
+			level[1] = level[3] = 107;
+			ah->ah_gain.g_high = 55;
+		}
+	}
+
+	return (ah->ah_gain.g_current >= level[0] &&
+			ah->ah_gain.g_current <= level[1]) ||
+		(ah->ah_gain.g_current >= level[2] &&
+			ah->ah_gain.g_current <= level[3]);
+}
+
+/* Perform gain_F adjustment by choosing the right set
+ * of parameters from rf gain optimization ladder */
+static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah)
+{
+	const struct ath5k_gain_opt *go;
+	const struct ath5k_gain_opt_step *g_step;
+	int ret = 0;
+
+	switch (ah->ah_radio) {
+	case AR5K_RF5111:
+		go = &rfgain_opt_5111;
+		break;
+	case AR5K_RF5112:
+		go = &rfgain_opt_5112;
+		break;
+	default:
+		return 0;
+	}
+
+	g_step = &go->go_step[ah->ah_gain.g_step_idx];
+
+	if (ah->ah_gain.g_current >= ah->ah_gain.g_high) {
+
+		/* Reached maximum */
+		if (ah->ah_gain.g_step_idx == 0)
+			return -1;
+
+		for (ah->ah_gain.g_target = ah->ah_gain.g_current;
+				ah->ah_gain.g_target >=  ah->ah_gain.g_high &&
+				ah->ah_gain.g_step_idx > 0;
+				g_step = &go->go_step[ah->ah_gain.g_step_idx])
+			ah->ah_gain.g_target -= 2 *
+			    (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain -
+			    g_step->gos_gain);
+
+		ret = 1;
+		goto done;
+	}
+
+	if (ah->ah_gain.g_current <= ah->ah_gain.g_low) {
+
+		/* Reached minimum */
+		if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1))
+			return -2;
+
+		for (ah->ah_gain.g_target = ah->ah_gain.g_current;
+				ah->ah_gain.g_target <= ah->ah_gain.g_low &&
+				ah->ah_gain.g_step_idx < go->go_steps_count-1;
+				g_step = &go->go_step[ah->ah_gain.g_step_idx])
+			ah->ah_gain.g_target -= 2 *
+			    (go->go_step[++ah->ah_gain.g_step_idx].gos_gain -
+			    g_step->gos_gain);
+
+		ret = 2;
+		goto done;
+	}
+
+done:
+	DBG2("ath5k RF adjust: ret %d, gain step %d, current gain %d, "
+	     "target gain %d\n", ret, ah->ah_gain.g_step_idx,
+	     ah->ah_gain.g_current, ah->ah_gain.g_target);
+
+	return ret;
+}
+
+/* Main callback for thermal rf gain calibration engine
+ * Check for a new gain reading and schedule an adjustment
+ * if needed.
+ *
+ * TODO: Use sw interrupt to schedule reset if gain_F needs
+ * adjustment */
+enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah)
+{
+	u32 data, type;
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+
+	if (ah->ah_rf_banks == NULL ||
+	ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE)
+		return AR5K_RFGAIN_INACTIVE;
+
+	/* No check requested, either engine is inactive
+	 * or an adjustment is already requested */
+	if (ah->ah_gain.g_state != AR5K_RFGAIN_READ_REQUESTED)
+		goto done;
+
+	/* Read the PAPD (Peak to Average Power Detector)
+	 * register */
+	data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE);
+
+	/* No probe is scheduled, read gain_F measurement */
+	if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) {
+		ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S;
+		type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE);
+
+		/* If tx packet is CCK correct the gain_F measurement
+		 * by cck ofdm gain delta */
+		if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) {
+			if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A)
+				ah->ah_gain.g_current +=
+					ee->ee_cck_ofdm_gain_delta;
+			else
+				ah->ah_gain.g_current +=
+					AR5K_GAIN_CCK_PROBE_CORR;
+		}
+
+		/* Further correct gain_F measurement for
+		 * RF5112A radios */
+		if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
+			ath5k_hw_rf_gainf_corr(ah);
+			ah->ah_gain.g_current =
+				ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ?
+				(ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
+				0;
+		}
+
+		/* Check if measurement is ok and if we need
+		 * to adjust gain, schedule a gain adjustment,
+		 * else switch back to the acive state */
+		if (ath5k_hw_rf_check_gainf_readback(ah) &&
+		AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
+		ath5k_hw_rf_gainf_adjust(ah)) {
+			ah->ah_gain.g_state = AR5K_RFGAIN_NEED_CHANGE;
+		} else {
+			ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+		}
+	}
+
+done:
+	return ah->ah_gain.g_state;
+}
+
+/* Write initial rf gain table to set the RF sensitivity
+ * this one works on all RF chips and has nothing to do
+ * with gain_F calibration */
+int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
+{
+	const struct ath5k_ini_rfgain *ath5k_rfg;
+	unsigned int i, size;
+
+	switch (ah->ah_radio) {
+	case AR5K_RF5111:
+		ath5k_rfg = rfgain_5111;
+		size = ARRAY_SIZE(rfgain_5111);
+		break;
+	case AR5K_RF5112:
+		ath5k_rfg = rfgain_5112;
+		size = ARRAY_SIZE(rfgain_5112);
+		break;
+	case AR5K_RF2413:
+		ath5k_rfg = rfgain_2413;
+		size = ARRAY_SIZE(rfgain_2413);
+		break;
+	case AR5K_RF2316:
+		ath5k_rfg = rfgain_2316;
+		size = ARRAY_SIZE(rfgain_2316);
+		break;
+	case AR5K_RF5413:
+		ath5k_rfg = rfgain_5413;
+		size = ARRAY_SIZE(rfgain_5413);
+		break;
+	case AR5K_RF2317:
+	case AR5K_RF2425:
+		ath5k_rfg = rfgain_2425;
+		size = ARRAY_SIZE(rfgain_2425);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (freq) {
+	case AR5K_INI_RFGAIN_2GHZ:
+	case AR5K_INI_RFGAIN_5GHZ:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < size; i++) {
+		AR5K_REG_WAIT(i);
+		ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
+			(u32)ath5k_rfg[i].rfg_register);
+	}
+
+	return 0;
+}
+
+
+
+/********************\
+* RF Registers setup *
+\********************/
+
+
+/*
+ * Setup RF registers by writing rf buffer on hw
+ */
+int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct net80211_channel *channel,
+		unsigned int mode)
+{
+	const struct ath5k_rf_reg *rf_regs;
+	const struct ath5k_ini_rfbuffer *ini_rfb;
+	const struct ath5k_gain_opt *go = NULL;
+	const struct ath5k_gain_opt_step *g_step;
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u8 ee_mode = 0;
+	u32 *rfb;
+	int obdb = -1, bank = -1;
+	unsigned i;
+
+	switch (ah->ah_radio) {
+	case AR5K_RF5111:
+		rf_regs = rf_regs_5111;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111);
+		ini_rfb = rfb_5111;
+		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5111);
+		go = &rfgain_opt_5111;
+		break;
+	case AR5K_RF5112:
+		if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
+			rf_regs = rf_regs_5112a;
+			ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a);
+			ini_rfb = rfb_5112a;
+			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112a);
+		} else {
+			rf_regs = rf_regs_5112;
+			ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112);
+			ini_rfb = rfb_5112;
+			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112);
+		}
+		go = &rfgain_opt_5112;
+		break;
+	case AR5K_RF2413:
+		rf_regs = rf_regs_2413;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2413);
+		ini_rfb = rfb_2413;
+		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2413);
+		break;
+	case AR5K_RF2316:
+		rf_regs = rf_regs_2316;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2316);
+		ini_rfb = rfb_2316;
+		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2316);
+		break;
+	case AR5K_RF5413:
+		rf_regs = rf_regs_5413;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5413);
+		ini_rfb = rfb_5413;
+		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5413);
+		break;
+	case AR5K_RF2317:
+		rf_regs = rf_regs_2425;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425);
+		ini_rfb = rfb_2317;
+		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2317);
+		break;
+	case AR5K_RF2425:
+		rf_regs = rf_regs_2425;
+		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425);
+		if (ah->ah_mac_srev < AR5K_SREV_AR2417) {
+			ini_rfb = rfb_2425;
+			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2425);
+		} else {
+			ini_rfb = rfb_2417;
+			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2417);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* If it's the first time we set rf buffer, allocate
+	 * ah->ah_rf_banks based on ah->ah_rf_banks_size
+	 * we set above */
+	if (ah->ah_rf_banks == NULL) {
+		ah->ah_rf_banks = malloc(sizeof(u32) * ah->ah_rf_banks_size);
+		if (ah->ah_rf_banks == NULL) {
+			return -ENOMEM;
+		}
+	}
+
+	/* Copy values to modify them */
+	rfb = ah->ah_rf_banks;
+
+	for (i = 0; i < ah->ah_rf_banks_size; i++) {
+		if (ini_rfb[i].rfb_bank >= AR5K_MAX_RF_BANKS) {
+			DBG("ath5k: invalid RF register bank\n");
+			return -EINVAL;
+		}
+
+		/* Bank changed, write down the offset */
+		if (bank != ini_rfb[i].rfb_bank) {
+			bank = ini_rfb[i].rfb_bank;
+			ah->ah_offset[bank] = i;
+		}
+
+		rfb[i] = ini_rfb[i].rfb_mode_data[mode];
+	}
+
+	/* Set Output and Driver bias current (OB/DB) */
+	if (channel->hw_value & CHANNEL_2GHZ) {
+
+		if (channel->hw_value & CHANNEL_CCK)
+			ee_mode = AR5K_EEPROM_MODE_11B;
+		else
+			ee_mode = AR5K_EEPROM_MODE_11G;
+
+		/* For RF511X/RF211X combination we
+		 * use b_OB and b_DB parameters stored
+		 * in eeprom on ee->ee_ob[ee_mode][0]
+		 *
+		 * For all other chips we use OB/DB for 2Ghz
+		 * stored in the b/g modal section just like
+		 * 802.11a on ee->ee_ob[ee_mode][1] */
+		if ((ah->ah_radio == AR5K_RF5111) ||
+		(ah->ah_radio == AR5K_RF5112))
+			obdb = 0;
+		else
+			obdb = 1;
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb],
+						AR5K_RF_OB_2GHZ, 1);
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb],
+						AR5K_RF_DB_2GHZ, 1);
+
+	/* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */
+	} else if ((channel->hw_value & CHANNEL_5GHZ) ||
+			(ah->ah_radio == AR5K_RF5111)) {
+
+		/* For 11a, Turbo and XR we need to choose
+		 * OB/DB based on frequency range */
+		ee_mode = AR5K_EEPROM_MODE_11A;
+		obdb =	 channel->center_freq >= 5725 ? 3 :
+			(channel->center_freq >= 5500 ? 2 :
+			(channel->center_freq >= 5260 ? 1 :
+			 (channel->center_freq > 4000 ? 0 : -1)));
+
+		if (obdb < 0)
+			return -EINVAL;
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb],
+						AR5K_RF_OB_5GHZ, 1);
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb],
+						AR5K_RF_DB_5GHZ, 1);
+	}
+
+	g_step = &go->go_step[ah->ah_gain.g_step_idx];
+
+	/* Bank Modifications (chip-specific) */
+	if (ah->ah_radio == AR5K_RF5111) {
+
+		/* Set gain_F settings according to current step */
+		if (channel->hw_value & CHANNEL_OFDM) {
+
+			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
+					AR5K_PHY_FRAME_CTL_TX_CLIP,
+					g_step->gos_param[0]);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1],
+							AR5K_RF_PWD_90, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2],
+							AR5K_RF_PWD_84, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3],
+						AR5K_RF_RFGAIN_SEL, 1);
+
+			/* We programmed gain_F parameters, switch back
+			 * to active state */
+			ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+
+		}
+
+		/* Bank 6/7 setup */
+
+		ath5k_hw_rfb_op(ah, rf_regs, !ee->ee_xpd[ee_mode],
+						AR5K_RF_PWD_XPD, 1);
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_x_gain[ee_mode],
+						AR5K_RF_XPD_GAIN, 1);
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode],
+						AR5K_RF_GAIN_I, 1);
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode],
+						AR5K_RF_PLO_SEL, 1);
+
+		/* TODO: Half/quarter channel support */
+	}
+
+	if (ah->ah_radio == AR5K_RF5112) {
+
+		/* Set gain_F settings according to current step */
+		if (channel->hw_value & CHANNEL_OFDM) {
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0],
+						AR5K_RF_MIXGAIN_OVR, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1],
+						AR5K_RF_PWD_138, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2],
+						AR5K_RF_PWD_137, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3],
+						AR5K_RF_PWD_136, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[4],
+						AR5K_RF_PWD_132, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[5],
+						AR5K_RF_PWD_131, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[6],
+						AR5K_RF_PWD_130, 1);
+
+			/* We programmed gain_F parameters, switch back
+			 * to active state */
+			ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
+		}
+
+		/* Bank 6/7 setup */
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode],
+						AR5K_RF_XPD_SEL, 1);
+
+		if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) {
+			/* Rev. 1 supports only one xpd */
+			ath5k_hw_rfb_op(ah, rf_regs,
+						ee->ee_x_gain[ee_mode],
+						AR5K_RF_XPD_GAIN, 1);
+
+		} else {
+			/* TODO: Set high and low gain bits */
+			ath5k_hw_rfb_op(ah, rf_regs,
+						ee->ee_x_gain[ee_mode],
+						AR5K_RF_PD_GAIN_LO, 1);
+			ath5k_hw_rfb_op(ah, rf_regs,
+						ee->ee_x_gain[ee_mode],
+						AR5K_RF_PD_GAIN_HI, 1);
+
+			/* Lower synth voltage on Rev 2 */
+			ath5k_hw_rfb_op(ah, rf_regs, 2,
+					AR5K_RF_HIGH_VC_CP, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, 2,
+					AR5K_RF_MID_VC_CP, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, 2,
+					AR5K_RF_LOW_VC_CP, 1);
+
+			ath5k_hw_rfb_op(ah, rf_regs, 2,
+					AR5K_RF_PUSH_UP, 1);
+
+			/* Decrease power consumption on 5213+ BaseBand */
+			if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
+				ath5k_hw_rfb_op(ah, rf_regs, 1,
+						AR5K_RF_PAD2GND, 1);
+
+				ath5k_hw_rfb_op(ah, rf_regs, 1,
+						AR5K_RF_XB2_LVL, 1);
+
+				ath5k_hw_rfb_op(ah, rf_regs, 1,
+						AR5K_RF_XB5_LVL, 1);
+
+				ath5k_hw_rfb_op(ah, rf_regs, 1,
+						AR5K_RF_PWD_167, 1);
+
+				ath5k_hw_rfb_op(ah, rf_regs, 1,
+						AR5K_RF_PWD_166, 1);
+			}
+		}
+
+		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode],
+						AR5K_RF_GAIN_I, 1);
+
+		/* TODO: Half/quarter channel support */
+
+	}
+
+	if (ah->ah_radio == AR5K_RF5413 &&
+	channel->hw_value & CHANNEL_2GHZ) {
+
+		ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE,
+									1);
+
+		/* Set optimum value for early revisions (on pci-e chips) */
+		if (ah->ah_mac_srev >= AR5K_SREV_AR5424 &&
+		ah->ah_mac_srev < AR5K_SREV_AR5413)
+			ath5k_hw_rfb_op(ah, rf_regs, ath5k_hw_bitswap(6, 3),
+						AR5K_RF_PWD_ICLOBUF_2G, 1);
+
+	}
+
+	/* Write RF banks on hw */
+	for (i = 0; i < ah->ah_rf_banks_size; i++) {
+		AR5K_REG_WAIT(i);
+		ath5k_hw_reg_write(ah, rfb[i], ini_rfb[i].rfb_ctrl_register);
+	}
+
+	return 0;
+}
+
+
+/**************************\
+  PHY/RF channel functions
+\**************************/
+
+/*
+ * Check if a channel is supported
+ */
+int ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
+{
+	/* Check if the channel is in our supported range */
+	if (flags & CHANNEL_2GHZ) {
+		if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
+		    (freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
+			return 1;
+	} else if (flags & CHANNEL_5GHZ)
+		if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
+		    (freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
+			return 1;
+
+	return 0;
+}
+
+/*
+ * Convertion needed for RF5110
+ */
+static u32 ath5k_hw_rf5110_chan2athchan(struct net80211_channel *channel)
+{
+	u32 athchan;
+
+	/*
+	 * Convert IEEE channel/MHz to an internal channel value used
+	 * by the AR5210 chipset. This has not been verified with
+	 * newer chipsets like the AR5212A who have a completely
+	 * different RF/PHY part.
+	 */
+	athchan = (ath5k_hw_bitswap((ath5k_freq_to_channel(channel->center_freq)
+				     - 24) / 2, 5) << 1)
+		| (1 << 6) | 0x1;
+	return athchan;
+}
+
+/*
+ * Set channel on RF5110
+ */
+static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah,
+		struct net80211_channel *channel)
+{
+	u32 data;
+
+	/*
+	 * Set the channel and wait
+	 */
+	data = ath5k_hw_rf5110_chan2athchan(channel);
+	ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER);
+	ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0);
+	mdelay(1);
+
+	return 0;
+}
+
+/*
+ * Convertion needed for 5111
+ */
+static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee,
+		struct ath5k_athchan_2ghz *athchan)
+{
+	int channel;
+
+	/* Cast this value to catch negative channel numbers (>= -19) */
+	channel = (int)ieee;
+
+	/*
+	 * Map 2GHz IEEE channel to 5GHz Atheros channel
+	 */
+	if (channel <= 13) {
+		athchan->a2_athchan = 115 + channel;
+		athchan->a2_flags = 0x46;
+	} else if (channel == 14) {
+		athchan->a2_athchan = 124;
+		athchan->a2_flags = 0x44;
+	} else if (channel >= 15 && channel <= 26) {
+		athchan->a2_athchan = ((channel - 14) * 4) + 132;
+		athchan->a2_flags = 0x46;
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * Set channel on 5111
+ */
+static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah,
+		struct net80211_channel *channel)
+{
+	struct ath5k_athchan_2ghz ath5k_channel_2ghz;
+	unsigned int ath5k_channel = ath5k_freq_to_channel(channel->center_freq);
+	u32 data0, data1, clock;
+	int ret;
+
+	/*
+	 * Set the channel on the RF5111 radio
+	 */
+	data0 = data1 = 0;
+
+	if (channel->hw_value & CHANNEL_2GHZ) {
+		/* Map 2GHz channel to 5GHz Atheros channel ID */
+		ret = ath5k_hw_rf5111_chan2athchan(ath5k_channel,
+						   &ath5k_channel_2ghz);
+		if (ret)
+			return ret;
+
+		ath5k_channel = ath5k_channel_2ghz.a2_athchan;
+		data0 = ((ath5k_hw_bitswap(ath5k_channel_2ghz.a2_flags, 8) & 0xff)
+		    << 5) | (1 << 4);
+	}
+
+	if (ath5k_channel < 145 || !(ath5k_channel & 1)) {
+		clock = 1;
+		data1 = ((ath5k_hw_bitswap(ath5k_channel - 24, 8) & 0xff) << 2) |
+			(clock << 1) | (1 << 10) | 1;
+	} else {
+		clock = 0;
+		data1 = ((ath5k_hw_bitswap((ath5k_channel - 24) / 2, 8) & 0xff)
+			<< 2) | (clock << 1) | (1 << 10) | 1;
+	}
+
+	ath5k_hw_reg_write(ah, (data1 & 0xff) | ((data0 & 0xff) << 8),
+			AR5K_RF_BUFFER);
+	ath5k_hw_reg_write(ah, ((data1 >> 8) & 0xff) | (data0 & 0xff00),
+			AR5K_RF_BUFFER_CONTROL_3);
+
+	return 0;
+}
+
+/*
+ * Set channel on 5112 and newer
+ */
+static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
+		struct net80211_channel *channel)
+{
+	u32 data, data0, data1, data2;
+	u16 c;
+
+	data = data0 = data1 = data2 = 0;
+	c = channel->center_freq;
+
+	if (c < 4800) {
+		if (!((c - 2224) % 5)) {
+			data0 = ((2 * (c - 704)) - 3040) / 10;
+			data1 = 1;
+		} else if (!((c - 2192) % 5)) {
+			data0 = ((2 * (c - 672)) - 3040) / 10;
+			data1 = 0;
+		} else
+			return -EINVAL;
+
+		data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8);
+	} else if ((c - (c % 5)) != 2 || c > 5435) {
+		if (!(c % 20) && c >= 5120) {
+			data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
+			data2 = ath5k_hw_bitswap(3, 2);
+		} else if (!(c % 10)) {
+			data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8);
+			data2 = ath5k_hw_bitswap(2, 2);
+		} else if (!(c % 5)) {
+			data0 = ath5k_hw_bitswap((c - 4800) / 5, 8);
+			data2 = ath5k_hw_bitswap(1, 2);
+		} else
+			return -EINVAL;
+	} else {
+		data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
+		data2 = ath5k_hw_bitswap(0, 2);
+	}
+
+	data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001;
+
+	ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER);
+	ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5);
+
+	return 0;
+}
+
+/*
+ * Set the channel on the RF2425
+ */
+static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
+		struct net80211_channel *channel)
+{
+	u32 data, data0, data2;
+	u16 c;
+
+	data = data0 = data2 = 0;
+	c = channel->center_freq;
+
+	if (c < 4800) {
+		data0 = ath5k_hw_bitswap((c - 2272), 8);
+		data2 = 0;
+	/* ? 5GHz ? */
+	} else if ((c - (c % 5)) != 2 || c > 5435) {
+		if (!(c % 20) && c < 5120)
+			data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
+		else if (!(c % 10))
+			data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8);
+		else if (!(c % 5))
+			data0 = ath5k_hw_bitswap((c - 4800) / 5, 8);
+		else
+			return -EINVAL;
+		data2 = ath5k_hw_bitswap(1, 2);
+	} else {
+		data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
+		data2 = ath5k_hw_bitswap(0, 2);
+	}
+
+	data = (data0 << 4) | data2 << 2 | 0x1001;
+
+	ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER);
+	ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5);
+
+	return 0;
+}
+
+/*
+ * Set a channel on the radio chip
+ */
+int ath5k_hw_channel(struct ath5k_hw *ah, struct net80211_channel *channel)
+{
+	int ret;
+	/*
+	 * Check bounds supported by the PHY (we don't care about regultory
+	 * restrictions at this point). Note: hw_value already has the band
+	 * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok()
+	 * of the band by that */
+	if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) {
+		DBG("ath5k: channel frequency (%d MHz) out of supported "
+		    "range\n", channel->center_freq);
+		return -EINVAL;
+	}
+
+	/*
+	 * Set the channel and wait
+	 */
+	switch (ah->ah_radio) {
+	case AR5K_RF5110:
+		ret = ath5k_hw_rf5110_channel(ah, channel);
+		break;
+	case AR5K_RF5111:
+		ret = ath5k_hw_rf5111_channel(ah, channel);
+		break;
+	case AR5K_RF2425:
+		ret = ath5k_hw_rf2425_channel(ah, channel);
+		break;
+	default:
+		ret = ath5k_hw_rf5112_channel(ah, channel);
+		break;
+	}
+
+	if (ret) {
+		DBG("ath5k: setting channel failed: %s\n", strerror(ret));
+		return ret;
+	}
+
+	/* Set JAPAN setting for channel 14 */
+	if (channel->center_freq == 2484) {
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL,
+				AR5K_PHY_CCKTXCTL_JAPAN);
+	} else {
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL,
+				AR5K_PHY_CCKTXCTL_WORLD);
+	}
+
+	ah->ah_current_channel = channel;
+	ah->ah_turbo = (channel->hw_value == CHANNEL_T ? 1 : 0);
+
+	return 0;
+}
+
+/*****************\
+  PHY calibration
+\*****************/
+
+/**
+ * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration
+ *
+ * @ah: struct ath5k_hw pointer we are operating on
+ * @freq: the channel frequency, just used for error logging
+ *
+ * This function performs a noise floor calibration of the PHY and waits for
+ * it to complete. Then the noise floor value is compared to some maximum
+ * noise floor we consider valid.
+ *
+ * Note that this is different from what the madwifi HAL does: it reads the
+ * noise floor and afterwards initiates the calibration. Since the noise floor
+ * calibration can take some time to finish, depending on the current channel
+ * use, that avoids the occasional timeout warnings we are seeing now.
+ *
+ * See the following link for an Atheros patent on noise floor calibration:
+ * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \
+ * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7
+ *
+ * XXX: Since during noise floor calibration antennas are detached according to
+ * the patent, we should stop tx queues here.
+ */
+int
+ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
+{
+	int ret;
+	unsigned int i;
+	s32 noise_floor;
+
+	/*
+	 * Enable noise floor calibration
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+				AR5K_PHY_AGCCTL_NF);
+
+	ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+			AR5K_PHY_AGCCTL_NF, 0, 0);
+
+	if (ret) {
+		DBG("ath5k: noise floor calibration timeout (%d MHz)\n", freq);
+		return -EAGAIN;
+	}
+
+	/* Wait until the noise floor is calibrated and read the value */
+	for (i = 20; i > 0; i--) {
+		mdelay(1);
+		noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
+		noise_floor = AR5K_PHY_NF_RVAL(noise_floor);
+		if (noise_floor & AR5K_PHY_NF_ACTIVE) {
+			noise_floor = AR5K_PHY_NF_AVAL(noise_floor);
+
+			if (noise_floor <= AR5K_TUNE_NOISE_FLOOR)
+				break;
+		}
+	}
+
+	DBG2("ath5k: noise floor %d\n", noise_floor);
+
+	if (noise_floor > AR5K_TUNE_NOISE_FLOOR) {
+		DBG("ath5k: noise floor calibration failed (%d MHz)\n", freq);
+		return -EAGAIN;
+	}
+
+	ah->ah_noise_floor = noise_floor;
+
+	return 0;
+}
+
+/*
+ * Perform a PHY calibration on RF5110
+ * -Fix BPSK/QAM Constellation (I/Q correction)
+ * -Calculate Noise Floor
+ */
+static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
+		struct net80211_channel *channel)
+{
+	u32 phy_sig, phy_agc, phy_sat, beacon;
+	int ret;
+
+	/*
+	 * Disable beacons and RX/TX queues, wait
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210,
+		AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
+	beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210);
+	ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210);
+
+	mdelay(2);
+
+	/*
+	 * Set the channel (with AGC turned off)
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+	udelay(10);
+	ret = ath5k_hw_channel(ah, channel);
+
+	/*
+	 * Activate PHY and wait
+	 */
+	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
+	mdelay(1);
+
+	AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+
+	if (ret)
+		return ret;
+
+	/*
+	 * Calibrate the radio chip
+	 */
+
+	/* Remember normal state */
+	phy_sig = ath5k_hw_reg_read(ah, AR5K_PHY_SIG);
+	phy_agc = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCOARSE);
+	phy_sat = ath5k_hw_reg_read(ah, AR5K_PHY_ADCSAT);
+
+	/* Update radio registers */
+	ath5k_hw_reg_write(ah, (phy_sig & ~(AR5K_PHY_SIG_FIRPWR)) |
+		AR5K_REG_SM(-1, AR5K_PHY_SIG_FIRPWR), AR5K_PHY_SIG);
+
+	ath5k_hw_reg_write(ah, (phy_agc & ~(AR5K_PHY_AGCCOARSE_HI |
+			AR5K_PHY_AGCCOARSE_LO)) |
+		AR5K_REG_SM(-1, AR5K_PHY_AGCCOARSE_HI) |
+		AR5K_REG_SM(-127, AR5K_PHY_AGCCOARSE_LO), AR5K_PHY_AGCCOARSE);
+
+	ath5k_hw_reg_write(ah, (phy_sat & ~(AR5K_PHY_ADCSAT_ICNT |
+			AR5K_PHY_ADCSAT_THR)) |
+		AR5K_REG_SM(2, AR5K_PHY_ADCSAT_ICNT) |
+		AR5K_REG_SM(12, AR5K_PHY_ADCSAT_THR), AR5K_PHY_ADCSAT);
+
+	udelay(20);
+
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+	udelay(10);
+	ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG);
+	AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+
+	mdelay(1);
+
+	/*
+	 * Enable calibration and wait until completion
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL);
+
+	ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+			AR5K_PHY_AGCCTL_CAL, 0, 0);
+
+	/* Reset to normal state */
+	ath5k_hw_reg_write(ah, phy_sig, AR5K_PHY_SIG);
+	ath5k_hw_reg_write(ah, phy_agc, AR5K_PHY_AGCCOARSE);
+	ath5k_hw_reg_write(ah, phy_sat, AR5K_PHY_ADCSAT);
+
+	if (ret) {
+		DBG("ath5k: calibration timeout (%d MHz)\n",
+		    channel->center_freq);
+		return ret;
+	}
+
+	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
+
+	/*
+	 * Re-enable RX/TX and beacons
+	 */
+	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210,
+		AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
+	ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210);
+
+	return 0;
+}
+
+/*
+ * Perform a PHY calibration on RF5111/5112 and newer chips
+ */
+static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
+		struct net80211_channel *channel)
+{
+	u32 i_pwr, q_pwr;
+	s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
+	int i;
+
+	if (!ah->ah_calibration ||
+		ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
+		goto done;
+
+	/* Calibration has finished, get the results and re-run */
+	for (i = 0; i <= 10; i++) {
+		iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
+		i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
+		q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q);
+	}
+
+	i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
+	q_coffd = q_pwr >> 7;
+
+	/* No correction */
+	if (i_coffd == 0 || q_coffd == 0)
+		goto done;
+
+	i_coff = ((-iq_corr) / i_coffd) & 0x3f;
+
+	/* Boundary check */
+	if (i_coff > 31)
+		i_coff = 31;
+	if (i_coff < -32)
+		i_coff = -32;
+
+	q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f;
+
+	/* Boundary check */
+	if (q_coff > 15)
+		q_coff = 15;
+	if (q_coff < -16)
+		q_coff = -16;
+
+	/* Commit new I/Q value */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE |
+		((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S));
+
+	/* Re-enable calibration -if we don't we'll commit
+	 * the same values again and again */
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
+			AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_RUN);
+
+done:
+
+	/* TODO: Separate noise floor calibration from I/Q calibration
+	 * since noise floor calibration interrupts rx path while I/Q
+	 * calibration doesn't. We don't need to run noise floor calibration
+	 * as often as I/Q calibration.*/
+	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
+
+	/* Initiate a gain_F calibration */
+	ath5k_hw_request_rfgain_probe(ah);
+
+	return 0;
+}
+
+/*
+ * Perform a PHY calibration
+ */
+int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
+		struct net80211_channel *channel)
+{
+	int ret;
+
+	if (ah->ah_radio == AR5K_RF5110)
+		ret = ath5k_hw_rf5110_calibrate(ah, channel);
+	else
+		ret = ath5k_hw_rf511x_calibrate(ah, channel);
+
+	return ret;
+}
+
+int ath5k_hw_phy_disable(struct ath5k_hw *ah)
+{
+	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
+
+	return 0;
+}
+
+/********************\
+  Misc PHY functions
+\********************/
+
+/*
+ * Get the PHY Chip revision
+ */
+u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
+{
+	unsigned int i;
+	u32 srev;
+	u16 ret;
+
+	/*
+	 * Set the radio chip access register
+	 */
+	switch (chan) {
+	case CHANNEL_2GHZ:
+		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
+		break;
+	case CHANNEL_5GHZ:
+		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+		break;
+	default:
+		return 0;
+	}
+
+	mdelay(2);
+
+	/* ...wait until PHY is ready and read the selected radio revision */
+	ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34));
+
+	for (i = 0; i < 8; i++)
+		ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
+
+	if (ah->ah_version == AR5K_AR5210) {
+		srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
+		ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
+	} else {
+		srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
+		ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) |
+				((srev & 0x0f) << 4), 8);
+	}
+
+	/* Reset to the 5GHz mode */
+	ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+
+	return ret;
+}
+
+void /*TODO:Boundary check*/
+ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant)
+{
+	if (ah->ah_version != AR5K_AR5210)
+		ath5k_hw_reg_write(ah, ant, AR5K_DEFAULT_ANTENNA);
+}
+
+unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah)
+{
+	if (ah->ah_version != AR5K_AR5210)
+		return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
+
+	return 0; /*XXX: What do we return for 5210 ?*/
+}
+
+
+/****************\
+* TX power setup *
+\****************/
+
+/*
+ * Helper functions
+ */
+
+/*
+ * Do linear interpolation between two given (x, y) points
+ */
+static s16
+ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right,
+					s16 y_left, s16 y_right)
+{
+	s16 ratio, result;
+
+	/* Avoid divide by zero and skip interpolation
+	 * if we have the same point */
+	if ((x_left == x_right) || (y_left == y_right))
+		return y_left;
+
+	/*
+	 * Since we use ints and not fps, we need to scale up in
+	 * order to get a sane ratio value (or else we 'll eg. get
+	 * always 1 instead of 1.25, 1.75 etc). We scale up by 100
+	 * to have some accuracy both for 0.5 and 0.25 steps.
+	 */
+	ratio = ((100 * y_right - 100 * y_left)/(x_right - x_left));
+
+	/* Now scale down to be in range */
+	result = y_left + (ratio * (target - x_left) / 100);
+
+	return result;
+}
+
+/*
+ * Find vertical boundary (min pwr) for the linear PCDAC curve.
+ *
+ * Since we have the top of the curve and we draw the line below
+ * until we reach 1 (1 pcdac step) we need to know which point
+ * (x value) that is so that we don't go below y axis and have negative
+ * pcdac values when creating the curve, or fill the table with zeroes.
+ */
+static s16
+ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR,
+				const s16 *pwrL, const s16 *pwrR)
+{
+	s8 tmp;
+	s16 min_pwrL, min_pwrR;
+	s16 pwr_i;
+
+	if (pwrL[0] == pwrL[1])
+		min_pwrL = pwrL[0];
+	else {
+		pwr_i = pwrL[0];
+		do {
+			pwr_i--;
+			tmp = (s8) ath5k_get_interpolated_value(pwr_i,
+							pwrL[0], pwrL[1],
+							stepL[0], stepL[1]);
+		} while (tmp > 1);
+
+		min_pwrL = pwr_i;
+	}
+
+	if (pwrR[0] == pwrR[1])
+		min_pwrR = pwrR[0];
+	else {
+		pwr_i = pwrR[0];
+		do {
+			pwr_i--;
+			tmp = (s8) ath5k_get_interpolated_value(pwr_i,
+							pwrR[0], pwrR[1],
+							stepR[0], stepR[1]);
+		} while (tmp > 1);
+
+		min_pwrR = pwr_i;
+	}
+
+	/* Keep the right boundary so that it works for both curves */
+	return max(min_pwrL, min_pwrR);
+}
+
+/*
+ * Interpolate (pwr,vpd) points to create a Power to PDADC or a
+ * Power to PCDAC curve.
+ *
+ * Each curve has power on x axis (in 0.5dB units) and PCDAC/PDADC
+ * steps (offsets) on y axis. Power can go up to 31.5dB and max
+ * PCDAC/PDADC step for each curve is 64 but we can write more than
+ * one curves on hw so we can go up to 128 (which is the max step we
+ * can write on the final table).
+ *
+ * We write y values (PCDAC/PDADC steps) on hw.
+ */
+static void
+ath5k_create_power_curve(s16 pmin, s16 pmax,
+			const s16 *pwr, const u8 *vpd,
+			u8 num_points,
+			u8 *vpd_table, u8 type)
+{
+	u8 idx[2] = { 0, 1 };
+	s16 pwr_i = 2*pmin;
+	int i;
+
+	if (num_points < 2)
+		return;
+
+	/* We want the whole line, so adjust boundaries
+	 * to cover the entire power range. Note that
+	 * power values are already 0.25dB so no need
+	 * to multiply pwr_i by 2 */
+	if (type == AR5K_PWRTABLE_LINEAR_PCDAC) {
+		pwr_i = pmin;
+		pmin = 0;
+		pmax = 63;
+	}
+
+	/* Find surrounding turning points (TPs)
+	 * and interpolate between them */
+	for (i = 0; (i <= (u16) (pmax - pmin)) &&
+	(i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) {
+
+		/* We passed the right TP, move to the next set of TPs
+		 * if we pass the last TP, extrapolate above using the last
+		 * two TPs for ratio */
+		if ((pwr_i > pwr[idx[1]]) && (idx[1] < num_points - 1)) {
+			idx[0]++;
+			idx[1]++;
+		}
+
+		vpd_table[i] = (u8) ath5k_get_interpolated_value(pwr_i,
+						pwr[idx[0]], pwr[idx[1]],
+						vpd[idx[0]], vpd[idx[1]]);
+
+		/* Increase by 0.5dB
+		 * (0.25 dB units) */
+		pwr_i += 2;
+	}
+}
+
+/*
+ * Get the surrounding per-channel power calibration piers
+ * for a given frequency so that we can interpolate between
+ * them and come up with an apropriate dataset for our current
+ * channel.
+ */
+static void
+ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah,
+			struct net80211_channel *channel,
+			struct ath5k_chan_pcal_info **pcinfo_l,
+			struct ath5k_chan_pcal_info **pcinfo_r)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_chan_pcal_info *pcinfo;
+	u8 idx_l, idx_r;
+	u8 mode, max, i;
+	u32 target = channel->center_freq;
+
+	idx_l = 0;
+	idx_r = 0;
+
+	if (!(channel->hw_value & CHANNEL_OFDM)) {
+		pcinfo = ee->ee_pwr_cal_b;
+		mode = AR5K_EEPROM_MODE_11B;
+	} else if (channel->hw_value & CHANNEL_2GHZ) {
+		pcinfo = ee->ee_pwr_cal_g;
+		mode = AR5K_EEPROM_MODE_11G;
+	} else {
+		pcinfo = ee->ee_pwr_cal_a;
+		mode = AR5K_EEPROM_MODE_11A;
+	}
+	max = ee->ee_n_piers[mode] - 1;
+
+	/* Frequency is below our calibrated
+	 * range. Use the lowest power curve
+	 * we have */
+	if (target < pcinfo[0].freq) {
+		idx_l = idx_r = 0;
+		goto done;
+	}
+
+	/* Frequency is above our calibrated
+	 * range. Use the highest power curve
+	 * we have */
+	if (target > pcinfo[max].freq) {
+		idx_l = idx_r = max;
+		goto done;
+	}
+
+	/* Frequency is inside our calibrated
+	 * channel range. Pick the surrounding
+	 * calibration piers so that we can
+	 * interpolate */
+	for (i = 0; i <= max; i++) {
+
+		/* Frequency matches one of our calibration
+		 * piers, no need to interpolate, just use
+		 * that calibration pier */
+		if (pcinfo[i].freq == target) {
+			idx_l = idx_r = i;
+			goto done;
+		}
+
+		/* We found a calibration pier that's above
+		 * frequency, use this pier and the previous
+		 * one to interpolate */
+		if (target < pcinfo[i].freq) {
+			idx_r = i;
+			idx_l = idx_r - 1;
+			goto done;
+		}
+	}
+
+done:
+	*pcinfo_l = &pcinfo[idx_l];
+	*pcinfo_r = &pcinfo[idx_r];
+
+	return;
+}
+
+/*
+ * Get the surrounding per-rate power calibration data
+ * for a given frequency and interpolate between power
+ * values to set max target power supported by hw for
+ * each rate.
+ */
+static void
+ath5k_get_rate_pcal_data(struct ath5k_hw *ah,
+			struct net80211_channel *channel,
+			struct ath5k_rate_pcal_info *rates)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_rate_pcal_info *rpinfo;
+	u8 idx_l, idx_r;
+	u8 mode, max, i;
+	u32 target = channel->center_freq;
+
+	idx_l = 0;
+	idx_r = 0;
+
+	if (!(channel->hw_value & CHANNEL_OFDM)) {
+		rpinfo = ee->ee_rate_tpwr_b;
+		mode = AR5K_EEPROM_MODE_11B;
+	} else if (channel->hw_value & CHANNEL_2GHZ) {
+		rpinfo = ee->ee_rate_tpwr_g;
+		mode = AR5K_EEPROM_MODE_11G;
+	} else {
+		rpinfo = ee->ee_rate_tpwr_a;
+		mode = AR5K_EEPROM_MODE_11A;
+	}
+	max = ee->ee_rate_target_pwr_num[mode] - 1;
+
+	/* Get the surrounding calibration
+	 * piers - same as above */
+	if (target < rpinfo[0].freq) {
+		idx_l = idx_r = 0;
+		goto done;
+	}
+
+	if (target > rpinfo[max].freq) {
+		idx_l = idx_r = max;
+		goto done;
+	}
+
+	for (i = 0; i <= max; i++) {
+
+		if (rpinfo[i].freq == target) {
+			idx_l = idx_r = i;
+			goto done;
+		}
+
+		if (target < rpinfo[i].freq) {
+			idx_r = i;
+			idx_l = idx_r - 1;
+			goto done;
+		}
+	}
+
+done:
+	/* Now interpolate power value, based on the frequency */
+	rates->freq = target;
+
+	rates->target_power_6to24 =
+		ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
+					rpinfo[idx_r].freq,
+					rpinfo[idx_l].target_power_6to24,
+					rpinfo[idx_r].target_power_6to24);
+
+	rates->target_power_36 =
+		ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
+					rpinfo[idx_r].freq,
+					rpinfo[idx_l].target_power_36,
+					rpinfo[idx_r].target_power_36);
+
+	rates->target_power_48 =
+		ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
+					rpinfo[idx_r].freq,
+					rpinfo[idx_l].target_power_48,
+					rpinfo[idx_r].target_power_48);
+
+	rates->target_power_54 =
+		ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
+					rpinfo[idx_r].freq,
+					rpinfo[idx_l].target_power_54,
+					rpinfo[idx_r].target_power_54);
+}
+
+/*
+ * Get the max edge power for this channel if
+ * we have such data from EEPROM's Conformance Test
+ * Limits (CTL), and limit max power if needed.
+ *
+ * FIXME: Only works for world regulatory domains
+ */
+static void
+ath5k_get_max_ctl_power(struct ath5k_hw *ah,
+			struct net80211_channel *channel)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	struct ath5k_edge_power *rep = ee->ee_ctl_pwr;
+	u8 *ctl_val = ee->ee_ctl;
+	s16 max_chan_pwr = ah->ah_txpower.txp_max_pwr / 4;
+	s16 edge_pwr = 0;
+	u8 rep_idx;
+	u8 i, ctl_mode;
+	u8 ctl_idx = 0xFF;
+	u32 target = channel->center_freq;
+
+	/* Find out a CTL for our mode that's not mapped
+	 * on a specific reg domain.
+	 *
+	 * TODO: Map our current reg domain to one of the 3 available
+	 * reg domain ids so that we can support more CTLs. */
+	switch (channel->hw_value & CHANNEL_MODES) {
+	case CHANNEL_A:
+		ctl_mode = AR5K_CTL_11A | AR5K_CTL_NO_REGDOMAIN;
+		break;
+	case CHANNEL_G:
+		ctl_mode = AR5K_CTL_11G | AR5K_CTL_NO_REGDOMAIN;
+		break;
+	case CHANNEL_B:
+		ctl_mode = AR5K_CTL_11B | AR5K_CTL_NO_REGDOMAIN;
+		break;
+	case CHANNEL_T:
+		ctl_mode = AR5K_CTL_TURBO | AR5K_CTL_NO_REGDOMAIN;
+		break;
+	case CHANNEL_TG:
+		ctl_mode = AR5K_CTL_TURBOG | AR5K_CTL_NO_REGDOMAIN;
+		break;
+	case CHANNEL_XR:
+		/* Fall through */
+	default:
+		return;
+	}
+
+	for (i = 0; i < ee->ee_ctls; i++) {
+		if (ctl_val[i] == ctl_mode) {
+			ctl_idx = i;
+			break;
+		}
+	}
+
+	/* If we have a CTL dataset available grab it and find the
+	 * edge power for our frequency */
+	if (ctl_idx == 0xFF)
+		return;
+
+	/* Edge powers are sorted by frequency from lower
+	 * to higher. Each CTL corresponds to 8 edge power
+	 * measurements. */
+	rep_idx = ctl_idx * AR5K_EEPROM_N_EDGES;
+
+	/* Don't do boundaries check because we
+	 * might have more that one bands defined
+	 * for this mode */
+
+	/* Get the edge power that's closer to our
+	 * frequency */
+	for (i = 0; i < AR5K_EEPROM_N_EDGES; i++) {
+		rep_idx += i;
+		if (target <= rep[rep_idx].freq)
+			edge_pwr = (s16) rep[rep_idx].edge;
+	}
+
+	if (edge_pwr) {
+		ah->ah_txpower.txp_max_pwr = 4*min(edge_pwr, max_chan_pwr);
+	}
+}
+
+
+/*
+ * Power to PCDAC table functions
+ */
+
+/*
+ * Fill Power to PCDAC table on RF5111
+ *
+ * No further processing is needed for RF5111, the only thing we have to
+ * do is fill the values below and above calibration range since eeprom data
+ * may not cover the entire PCDAC table.
+ */
+static void
+ath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min,
+							s16 *table_max)
+{
+	u8 	*pcdac_out = ah->ah_txpower.txp_pd_table;
+	u8	*pcdac_tmp = ah->ah_txpower.tmpL[0];
+	u8	pcdac_0, pcdac_n, pcdac_i, pwr_idx, i;
+	s16	min_pwr, max_pwr;
+
+	/* Get table boundaries */
+	min_pwr = table_min[0];
+	pcdac_0 = pcdac_tmp[0];
+
+	max_pwr = table_max[0];
+	pcdac_n = pcdac_tmp[table_max[0] - table_min[0]];
+
+	/* Extrapolate below minimum using pcdac_0 */
+	pcdac_i = 0;
+	for (i = 0; i < min_pwr; i++)
+		pcdac_out[pcdac_i++] = pcdac_0;
+
+	/* Copy values from pcdac_tmp */
+	pwr_idx = min_pwr;
+	for (i = 0 ; pwr_idx <= max_pwr &&
+	pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE; i++) {
+		pcdac_out[pcdac_i++] = pcdac_tmp[i];
+		pwr_idx++;
+	}
+
+	/* Extrapolate above maximum */
+	while (pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE)
+		pcdac_out[pcdac_i++] = pcdac_n;
+
+}
+
+/*
+ * Combine available XPD Curves and fill Linear Power to PCDAC table
+ * on RF5112
+ *
+ * RFX112 can have up to 2 curves (one for low txpower range and one for
+ * higher txpower range). We need to put them both on pcdac_out and place
+ * them in the correct location. In case we only have one curve available
+ * just fit it on pcdac_out (it's supposed to cover the entire range of
+ * available pwr levels since it's always the higher power curve). Extrapolate
+ * below and above final table if needed.
+ */
+static void
+ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min,
+						s16 *table_max, u8 pdcurves)
+{
+	u8 	*pcdac_out = ah->ah_txpower.txp_pd_table;
+	u8	*pcdac_low_pwr;
+	u8	*pcdac_high_pwr;
+	u8	*pcdac_tmp;
+	u8	pwr;
+	s16	max_pwr_idx;
+	s16	min_pwr_idx;
+	s16	mid_pwr_idx = 0;
+	/* Edge flag turs on the 7nth bit on the PCDAC
+	 * to delcare the higher power curve (force values
+	 * to be greater than 64). If we only have one curve
+	 * we don't need to set this, if we have 2 curves and
+	 * fill the table backwards this can also be used to
+	 * switch from higher power curve to lower power curve */
+	u8	edge_flag;
+	int	i;
+
+	/* When we have only one curve available
+	 * that's the higher power curve. If we have
+	 * two curves the first is the high power curve
+	 * and the next is the low power curve. */
+	if (pdcurves > 1) {
+		pcdac_low_pwr = ah->ah_txpower.tmpL[1];
+		pcdac_high_pwr = ah->ah_txpower.tmpL[0];
+		mid_pwr_idx = table_max[1] - table_min[1] - 1;
+		max_pwr_idx = (table_max[0] - table_min[0]) / 2;
+
+		/* If table size goes beyond 31.5dB, keep the
+		 * upper 31.5dB range when setting tx power.
+		 * Note: 126 = 31.5 dB in quarter dB steps */
+		if (table_max[0] - table_min[1] > 126)
+			min_pwr_idx = table_max[0] - 126;
+		else
+			min_pwr_idx = table_min[1];
+
+		/* Since we fill table backwards
+		 * start from high power curve */
+		pcdac_tmp = pcdac_high_pwr;
+
+		edge_flag = 0x40;
+	} else {
+		pcdac_low_pwr = ah->ah_txpower.tmpL[1]; /* Zeroed */
+		pcdac_high_pwr = ah->ah_txpower.tmpL[0];
+		min_pwr_idx = table_min[0];
+		max_pwr_idx = (table_max[0] - table_min[0]) / 2;
+		pcdac_tmp = pcdac_high_pwr;
+		edge_flag = 0;
+	}
+
+	/* This is used when setting tx power*/
+	ah->ah_txpower.txp_min_idx = min_pwr_idx/2;
+
+	/* Fill Power to PCDAC table backwards */
+	pwr = max_pwr_idx;
+	for (i = 63; i >= 0; i--) {
+		/* Entering lower power range, reset
+		 * edge flag and set pcdac_tmp to lower
+		 * power curve.*/
+		if (edge_flag == 0x40 &&
+		(2*pwr <= (table_max[1] - table_min[0]) || pwr == 0)) {
+			edge_flag = 0x00;
+			pcdac_tmp = pcdac_low_pwr;
+			pwr = mid_pwr_idx/2;
+		}
+
+		/* Don't go below 1, extrapolate below if we have
+		 * already swithced to the lower power curve -or
+		 * we only have one curve and edge_flag is zero
+		 * anyway */
+		if (pcdac_tmp[pwr] < 1 && (edge_flag == 0x00)) {
+			while (i >= 0) {
+				pcdac_out[i] = pcdac_out[i + 1];
+				i--;
+			}
+			break;
+		}
+
+		pcdac_out[i] = pcdac_tmp[pwr] | edge_flag;
+
+		/* Extrapolate above if pcdac is greater than
+		 * 126 -this can happen because we OR pcdac_out
+		 * value with edge_flag on high power curve */
+		if (pcdac_out[i] > 126)
+			pcdac_out[i] = 126;
+
+		/* Decrease by a 0.5dB step */
+		pwr--;
+	}
+}
+
+/* Write PCDAC values on hw */
+static void
+ath5k_setup_pcdac_table(struct ath5k_hw *ah)
+{
+	u8 	*pcdac_out = ah->ah_txpower.txp_pd_table;
+	int	i;
+
+	/*
+	 * Write TX power values
+	 */
+	for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) {
+		ath5k_hw_reg_write(ah,
+			(((pcdac_out[2*i + 0] << 8 | 0xff) & 0xffff) << 0) |
+			(((pcdac_out[2*i + 1] << 8 | 0xff) & 0xffff) << 16),
+			AR5K_PHY_PCDAC_TXPOWER(i));
+	}
+}
+
+
+/*
+ * Power to PDADC table functions
+ */
+
+/*
+ * Set the gain boundaries and create final Power to PDADC table
+ *
+ * We can have up to 4 pd curves, we need to do a simmilar process
+ * as we do for RF5112. This time we don't have an edge_flag but we
+ * set the gain boundaries on a separate register.
+ */
+static void
+ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah,
+			s16 *pwr_min, s16 *pwr_max, u8 pdcurves)
+{
+	u8 gain_boundaries[AR5K_EEPROM_N_PD_GAINS];
+	u8 *pdadc_out = ah->ah_txpower.txp_pd_table;
+	u8 *pdadc_tmp;
+	s16 pdadc_0;
+	u8 pdadc_i, pdadc_n, pwr_step, pdg, max_idx, table_size;
+	u8 pd_gain_overlap;
+
+	/* Note: Register value is initialized on initvals
+	 * there is no feedback from hw.
+	 * XXX: What about pd_gain_overlap from EEPROM ? */
+	pd_gain_overlap = (u8) ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG5) &
+		AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP;
+
+	/* Create final PDADC table */
+	for (pdg = 0, pdadc_i = 0; pdg < pdcurves; pdg++) {
+		pdadc_tmp = ah->ah_txpower.tmpL[pdg];
+
+		if (pdg == pdcurves - 1)
+			/* 2 dB boundary stretch for last
+			 * (higher power) curve */
+			gain_boundaries[pdg] = pwr_max[pdg] + 4;
+		else
+			/* Set gain boundary in the middle
+			 * between this curve and the next one */
+			gain_boundaries[pdg] =
+				(pwr_max[pdg] + pwr_min[pdg + 1]) / 2;
+
+		/* Sanity check in case our 2 db stretch got out of
+		 * range. */
+		if (gain_boundaries[pdg] > AR5K_TUNE_MAX_TXPOWER)
+			gain_boundaries[pdg] = AR5K_TUNE_MAX_TXPOWER;
+
+		/* For the first curve (lower power)
+		 * start from 0 dB */
+		if (pdg == 0)
+			pdadc_0 = 0;
+		else
+			/* For the other curves use the gain overlap */
+			pdadc_0 = (gain_boundaries[pdg - 1] - pwr_min[pdg]) -
+							pd_gain_overlap;
+
+		/* Force each power step to be at least 0.5 dB */
+		if ((pdadc_tmp[1] - pdadc_tmp[0]) > 1)
+			pwr_step = pdadc_tmp[1] - pdadc_tmp[0];
+		else
+			pwr_step = 1;
+
+		/* If pdadc_0 is negative, we need to extrapolate
+		 * below this pdgain by a number of pwr_steps */
+		while ((pdadc_0 < 0) && (pdadc_i < 128)) {
+			s16 tmp = pdadc_tmp[0] + pdadc_0 * pwr_step;
+			pdadc_out[pdadc_i++] = (tmp < 0) ? 0 : (u8) tmp;
+			pdadc_0++;
+		}
+
+		/* Set last pwr level, using gain boundaries */
+		pdadc_n = gain_boundaries[pdg] + pd_gain_overlap - pwr_min[pdg];
+		/* Limit it to be inside pwr range */
+		table_size = pwr_max[pdg] - pwr_min[pdg];
+		max_idx = (pdadc_n < table_size) ? pdadc_n : table_size;
+
+		/* Fill pdadc_out table */
+		while (pdadc_0 < max_idx)
+			pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++];
+
+		/* Need to extrapolate above this pdgain? */
+		if (pdadc_n <= max_idx)
+			continue;
+
+		/* Force each power step to be at least 0.5 dB */
+		if ((pdadc_tmp[table_size - 1] - pdadc_tmp[table_size - 2]) > 1)
+			pwr_step = pdadc_tmp[table_size - 1] -
+						pdadc_tmp[table_size - 2];
+		else
+			pwr_step = 1;
+
+		/* Extrapolate above */
+		while ((pdadc_0 < (s16) pdadc_n) &&
+		(pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2)) {
+			s16 tmp = pdadc_tmp[table_size - 1] +
+					(pdadc_0 - max_idx) * pwr_step;
+			pdadc_out[pdadc_i++] = (tmp > 127) ? 127 : (u8) tmp;
+			pdadc_0++;
+		}
+	}
+
+	while (pdg < AR5K_EEPROM_N_PD_GAINS) {
+		gain_boundaries[pdg] = gain_boundaries[pdg - 1];
+		pdg++;
+	}
+
+	while (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2) {
+		pdadc_out[pdadc_i] = pdadc_out[pdadc_i - 1];
+		pdadc_i++;
+	}
+
+	/* Set gain boundaries */
+	ath5k_hw_reg_write(ah,
+		AR5K_REG_SM(pd_gain_overlap,
+			AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP) |
+		AR5K_REG_SM(gain_boundaries[0],
+			AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1) |
+		AR5K_REG_SM(gain_boundaries[1],
+			AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2) |
+		AR5K_REG_SM(gain_boundaries[2],
+			AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3) |
+		AR5K_REG_SM(gain_boundaries[3],
+			AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4),
+		AR5K_PHY_TPC_RG5);
+
+	/* Used for setting rate power table */
+	ah->ah_txpower.txp_min_idx = pwr_min[0];
+
+}
+
+/* Write PDADC values on hw */
+static void
+ath5k_setup_pwr_to_pdadc_table(struct ath5k_hw *ah,
+			u8 pdcurves, u8 *pdg_to_idx)
+{
+	u8 *pdadc_out = ah->ah_txpower.txp_pd_table;
+	u32 reg;
+	u8 i;
+
+	/* Select the right pdgain curves */
+
+	/* Clear current settings */
+	reg = ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG1);
+	reg &= ~(AR5K_PHY_TPC_RG1_PDGAIN_1 |
+		AR5K_PHY_TPC_RG1_PDGAIN_2 |
+		AR5K_PHY_TPC_RG1_PDGAIN_3 |
+		AR5K_PHY_TPC_RG1_NUM_PD_GAIN);
+
+	/*
+	 * Use pd_gains curve from eeprom
+	 *
+	 * This overrides the default setting from initvals
+	 * in case some vendors (e.g. Zcomax) don't use the default
+	 * curves. If we don't honor their settings we 'll get a
+	 * 5dB (1 * gain overlap ?) drop.
+	 */
+	reg |= AR5K_REG_SM(pdcurves, AR5K_PHY_TPC_RG1_NUM_PD_GAIN);
+
+	switch (pdcurves) {
+	case 3:
+		reg |= AR5K_REG_SM(pdg_to_idx[2], AR5K_PHY_TPC_RG1_PDGAIN_3);
+		/* Fall through */
+	case 2:
+		reg |= AR5K_REG_SM(pdg_to_idx[1], AR5K_PHY_TPC_RG1_PDGAIN_2);
+		/* Fall through */
+	case 1:
+		reg |= AR5K_REG_SM(pdg_to_idx[0], AR5K_PHY_TPC_RG1_PDGAIN_1);
+		break;
+	}
+	ath5k_hw_reg_write(ah, reg, AR5K_PHY_TPC_RG1);
+
+	/*
+	 * Write TX power values
+	 */
+	for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) {
+		ath5k_hw_reg_write(ah,
+			((pdadc_out[4*i + 0] & 0xff) << 0) |
+			((pdadc_out[4*i + 1] & 0xff) << 8) |
+			((pdadc_out[4*i + 2] & 0xff) << 16) |
+			((pdadc_out[4*i + 3] & 0xff) << 24),
+			AR5K_PHY_PDADC_TXPOWER(i));
+	}
+}
+
+
+/*
+ * Common code for PCDAC/PDADC tables
+ */
+
+/*
+ * This is the main function that uses all of the above
+ * to set PCDAC/PDADC table on hw for the current channel.
+ * This table is used for tx power calibration on the basband,
+ * without it we get weird tx power levels and in some cases
+ * distorted spectral mask
+ */
+static int
+ath5k_setup_channel_powertable(struct ath5k_hw *ah,
+			struct net80211_channel *channel,
+			u8 ee_mode, u8 type)
+{
+	struct ath5k_pdgain_info *pdg_L, *pdg_R;
+	struct ath5k_chan_pcal_info *pcinfo_L;
+	struct ath5k_chan_pcal_info *pcinfo_R;
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode];
+	s16 table_min[AR5K_EEPROM_N_PD_GAINS];
+	s16 table_max[AR5K_EEPROM_N_PD_GAINS];
+	u8 *tmpL;
+	u8 *tmpR;
+	u32 target = channel->center_freq;
+	int pdg, i;
+
+	/* Get surounding freq piers for this channel */
+	ath5k_get_chan_pcal_surrounding_piers(ah, channel,
+						&pcinfo_L,
+						&pcinfo_R);
+
+	/* Loop over pd gain curves on
+	 * surounding freq piers by index */
+	for (pdg = 0; pdg < ee->ee_pd_gains[ee_mode]; pdg++) {
+
+		/* Fill curves in reverse order
+		 * from lower power (max gain)
+		 * to higher power. Use curve -> idx
+		 * backmaping we did on eeprom init */
+		u8 idx = pdg_curve_to_idx[pdg];
+
+		/* Grab the needed curves by index */
+		pdg_L = &pcinfo_L->pd_curves[idx];
+		pdg_R = &pcinfo_R->pd_curves[idx];
+
+		/* Initialize the temp tables */
+		tmpL = ah->ah_txpower.tmpL[pdg];
+		tmpR = ah->ah_txpower.tmpR[pdg];
+
+		/* Set curve's x boundaries and create
+		 * curves so that they cover the same
+		 * range (if we don't do that one table
+		 * will have values on some range and the
+		 * other one won't have any so interpolation
+		 * will fail) */
+		table_min[pdg] = min(pdg_L->pd_pwr[0],
+					pdg_R->pd_pwr[0]) / 2;
+
+		table_max[pdg] = max(pdg_L->pd_pwr[pdg_L->pd_points - 1],
+				pdg_R->pd_pwr[pdg_R->pd_points - 1]) / 2;
+
+		/* Now create the curves on surrounding channels
+		 * and interpolate if needed to get the final
+		 * curve for this gain on this channel */
+		switch (type) {
+		case AR5K_PWRTABLE_LINEAR_PCDAC:
+			/* Override min/max so that we don't loose
+			 * accuracy (don't divide by 2) */
+			table_min[pdg] = min(pdg_L->pd_pwr[0],
+						pdg_R->pd_pwr[0]);
+
+			table_max[pdg] =
+				max(pdg_L->pd_pwr[pdg_L->pd_points - 1],
+					pdg_R->pd_pwr[pdg_R->pd_points - 1]);
+
+			/* Override minimum so that we don't get
+			 * out of bounds while extrapolating
+			 * below. Don't do this when we have 2
+			 * curves and we are on the high power curve
+			 * because table_min is ok in this case */
+			if (!(ee->ee_pd_gains[ee_mode] > 1 && pdg == 0)) {
+
+				table_min[pdg] =
+					ath5k_get_linear_pcdac_min(pdg_L->pd_step,
+								pdg_R->pd_step,
+								pdg_L->pd_pwr,
+								pdg_R->pd_pwr);
+
+				/* Don't go too low because we will
+				 * miss the upper part of the curve.
+				 * Note: 126 = 31.5dB (max power supported)
+				 * in 0.25dB units */
+				if (table_max[pdg] - table_min[pdg] > 126)
+					table_min[pdg] = table_max[pdg] - 126;
+			}
+
+			/* Fall through */
+		case AR5K_PWRTABLE_PWR_TO_PCDAC:
+		case AR5K_PWRTABLE_PWR_TO_PDADC:
+
+			ath5k_create_power_curve(table_min[pdg],
+						table_max[pdg],
+						pdg_L->pd_pwr,
+						pdg_L->pd_step,
+						pdg_L->pd_points, tmpL, type);
+
+			/* We are in a calibration
+			 * pier, no need to interpolate
+			 * between freq piers */
+			if (pcinfo_L == pcinfo_R)
+				continue;
+
+			ath5k_create_power_curve(table_min[pdg],
+						table_max[pdg],
+						pdg_R->pd_pwr,
+						pdg_R->pd_step,
+						pdg_R->pd_points, tmpR, type);
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		/* Interpolate between curves
+		 * of surounding freq piers to
+		 * get the final curve for this
+		 * pd gain. Re-use tmpL for interpolation
+		 * output */
+		for (i = 0; (i < (u16) (table_max[pdg] - table_min[pdg])) &&
+		(i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) {
+			tmpL[i] = (u8) ath5k_get_interpolated_value(target,
+							(s16) pcinfo_L->freq,
+							(s16) pcinfo_R->freq,
+							(s16) tmpL[i],
+							(s16) tmpR[i]);
+		}
+	}
+
+	/* Now we have a set of curves for this
+	 * channel on tmpL (x range is table_max - table_min
+	 * and y values are tmpL[pdg][]) sorted in the same
+	 * order as EEPROM (because we've used the backmaping).
+	 * So for RF5112 it's from higher power to lower power
+	 * and for RF2413 it's from lower power to higher power.
+	 * For RF5111 we only have one curve. */
+
+	/* Fill min and max power levels for this
+	 * channel by interpolating the values on
+	 * surounding channels to complete the dataset */
+	ah->ah_txpower.txp_min_pwr = ath5k_get_interpolated_value(target,
+					(s16) pcinfo_L->freq,
+					(s16) pcinfo_R->freq,
+					pcinfo_L->min_pwr, pcinfo_R->min_pwr);
+
+	ah->ah_txpower.txp_max_pwr = ath5k_get_interpolated_value(target,
+					(s16) pcinfo_L->freq,
+					(s16) pcinfo_R->freq,
+					pcinfo_L->max_pwr, pcinfo_R->max_pwr);
+
+	/* We are ready to go, fill PCDAC/PDADC
+	 * table and write settings on hardware */
+	switch (type) {
+	case AR5K_PWRTABLE_LINEAR_PCDAC:
+		/* For RF5112 we can have one or two curves
+		 * and each curve covers a certain power lvl
+		 * range so we need to do some more processing */
+		ath5k_combine_linear_pcdac_curves(ah, table_min, table_max,
+						ee->ee_pd_gains[ee_mode]);
+
+		/* Set txp.offset so that we can
+		 * match max power value with max
+		 * table index */
+		ah->ah_txpower.txp_offset = 64 - (table_max[0] / 2);
+
+		/* Write settings on hw */
+		ath5k_setup_pcdac_table(ah);
+		break;
+	case AR5K_PWRTABLE_PWR_TO_PCDAC:
+		/* We are done for RF5111 since it has only
+		 * one curve, just fit the curve on the table */
+		ath5k_fill_pwr_to_pcdac_table(ah, table_min, table_max);
+
+		/* No rate powertable adjustment for RF5111 */
+		ah->ah_txpower.txp_min_idx = 0;
+		ah->ah_txpower.txp_offset = 0;
+
+		/* Write settings on hw */
+		ath5k_setup_pcdac_table(ah);
+		break;
+	case AR5K_PWRTABLE_PWR_TO_PDADC:
+		/* Set PDADC boundaries and fill
+		 * final PDADC table */
+		ath5k_combine_pwr_to_pdadc_curves(ah, table_min, table_max,
+						ee->ee_pd_gains[ee_mode]);
+
+		/* Write settings on hw */
+		ath5k_setup_pwr_to_pdadc_table(ah, pdg, pdg_curve_to_idx);
+
+		/* Set txp.offset, note that table_min
+		 * can be negative */
+		ah->ah_txpower.txp_offset = table_min[0];
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+/*
+ * Per-rate tx power setting
+ *
+ * This is the code that sets the desired tx power (below
+ * maximum) on hw for each rate (we also have TPC that sets
+ * power per packet). We do that by providing an index on the
+ * PCDAC/PDADC table we set up.
+ */
+
+/*
+ * Set rate power table
+ *
+ * For now we only limit txpower based on maximum tx power
+ * supported by hw (what's inside rate_info). We need to limit
+ * this even more, based on regulatory domain etc.
+ *
+ * Rate power table contains indices to PCDAC/PDADC table (0.5dB steps)
+ * and is indexed as follows:
+ * rates[0] - rates[7] -> OFDM rates
+ * rates[8] - rates[14] -> CCK rates
+ * rates[15] -> XR rates (they all have the same power)
+ */
+static void
+ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
+			struct ath5k_rate_pcal_info *rate_info,
+			u8 ee_mode)
+{
+	unsigned int i;
+	u16 *rates;
+
+	/* max_pwr is power level we got from driver/user in 0.5dB
+	 * units, switch to 0.25dB units so we can compare */
+	max_pwr *= 2;
+	max_pwr = min(max_pwr, (u16) ah->ah_txpower.txp_max_pwr) / 2;
+
+	/* apply rate limits */
+	rates = ah->ah_txpower.txp_rates_power_table;
+
+	/* OFDM rates 6 to 24Mb/s */
+	for (i = 0; i < 5; i++)
+		rates[i] = min(max_pwr, rate_info->target_power_6to24);
+
+	/* Rest OFDM rates */
+	rates[5] = min(rates[0], rate_info->target_power_36);
+	rates[6] = min(rates[0], rate_info->target_power_48);
+	rates[7] = min(rates[0], rate_info->target_power_54);
+
+	/* CCK rates */
+	/* 1L */
+	rates[8] = min(rates[0], rate_info->target_power_6to24);
+	/* 2L */
+	rates[9] = min(rates[0], rate_info->target_power_36);
+	/* 2S */
+	rates[10] = min(rates[0], rate_info->target_power_36);
+	/* 5L */
+	rates[11] = min(rates[0], rate_info->target_power_48);
+	/* 5S */
+	rates[12] = min(rates[0], rate_info->target_power_48);
+	/* 11L */
+	rates[13] = min(rates[0], rate_info->target_power_54);
+	/* 11S */
+	rates[14] = min(rates[0], rate_info->target_power_54);
+
+	/* XR rates */
+	rates[15] = min(rates[0], rate_info->target_power_6to24);
+
+	/* CCK rates have different peak to average ratio
+	 * so we have to tweak their power so that gainf
+	 * correction works ok. For this we use OFDM to
+	 * CCK delta from eeprom */
+	if ((ee_mode == AR5K_EEPROM_MODE_11G) &&
+	(ah->ah_phy_revision < AR5K_SREV_PHY_5212A))
+		for (i = 8; i <= 15; i++)
+			rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta;
+
+	ah->ah_txpower.txp_min_pwr = rates[7];
+	ah->ah_txpower.txp_max_pwr = rates[0];
+	ah->ah_txpower.txp_ofdm = rates[7];
+}
+
+
+/*
+ * Set transmition power
+ */
+int
+ath5k_hw_txpower(struct ath5k_hw *ah, struct net80211_channel *channel,
+		u8 ee_mode, u8 txpower)
+{
+	struct ath5k_rate_pcal_info rate_info;
+	u8 type;
+	int ret;
+
+	if (txpower > AR5K_TUNE_MAX_TXPOWER) {
+		DBG("ath5k: invalid tx power %d\n", txpower);
+		return -EINVAL;
+	}
+	if (txpower == 0)
+		txpower = AR5K_TUNE_DEFAULT_TXPOWER;
+
+	/* Reset TX power values */
+	memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
+	ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
+	ah->ah_txpower.txp_min_pwr = 0;
+	ah->ah_txpower.txp_max_pwr = AR5K_TUNE_MAX_TXPOWER;
+
+	/* Initialize TX power table */
+	switch (ah->ah_radio) {
+	case AR5K_RF5111:
+		type = AR5K_PWRTABLE_PWR_TO_PCDAC;
+		break;
+	case AR5K_RF5112:
+		type = AR5K_PWRTABLE_LINEAR_PCDAC;
+		break;
+	case AR5K_RF2413:
+	case AR5K_RF5413:
+	case AR5K_RF2316:
+	case AR5K_RF2317:
+	case AR5K_RF2425:
+		type = AR5K_PWRTABLE_PWR_TO_PDADC;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* FIXME: Only on channel/mode change */
+	ret = ath5k_setup_channel_powertable(ah, channel, ee_mode, type);
+	if (ret)
+		return ret;
+
+	/* Limit max power if we have a CTL available */
+	ath5k_get_max_ctl_power(ah, channel);
+
+	/* FIXME: Tx power limit for this regdomain
+	 * XXX: Mac80211/CRDA will do that anyway ? */
+
+	/* FIXME: Antenna reduction stuff */
+
+	/* FIXME: Limit power on turbo modes */
+
+	/* FIXME: TPC scale reduction */
+
+	/* Get surounding channels for per-rate power table
+	 * calibration */
+	ath5k_get_rate_pcal_data(ah, channel, &rate_info);
+
+	/* Setup rate power table */
+	ath5k_setup_rate_powertable(ah, txpower, &rate_info, ee_mode);
+
+	/* Write rate power table on hw */
+	ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) |
+		AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) |
+		AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1);
+
+	ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(7, 24) |
+		AR5K_TXPOWER_OFDM(6, 16) | AR5K_TXPOWER_OFDM(5, 8) |
+		AR5K_TXPOWER_OFDM(4, 0), AR5K_PHY_TXPOWER_RATE2);
+
+	ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(10, 24) |
+		AR5K_TXPOWER_CCK(9, 16) | AR5K_TXPOWER_CCK(15, 8) |
+		AR5K_TXPOWER_CCK(8, 0), AR5K_PHY_TXPOWER_RATE3);
+
+	ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(14, 24) |
+		AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) |
+		AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4);
+
+	/* FIXME: TPC support */
+	if (ah->ah_txpower.txp_tpc) {
+		ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE |
+			AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
+
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_ACK) |
+			AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CTS) |
+			AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP),
+			AR5K_TPC);
+	} else {
+		ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX |
+			AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
+	}
+
+	return 0;
+}
+
+int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 mode, u8 txpower)
+{
+	struct net80211_channel *channel = ah->ah_current_channel;
+
+	DBG2("ath5k: changing txpower to %d\n", txpower);
+
+	return ath5k_hw_txpower(ah, channel, mode, txpower);
+}
+
+#undef _ATH5K_PHY
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_qcu.c b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_qcu.c
new file mode 100644
index 0000000000000000000000000000000000000000..e38dba9e2f3db763cc4408e1badcca736d7d3d73
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_qcu.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+/********************************************\
+Queue Control Unit, DFS Control Unit Functions
+\********************************************/
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/*
+ * Set properties for a transmit queue
+ */
+int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah,
+				const struct ath5k_txq_info *queue_info)
+{
+	if (ah->ah_txq.tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return -EIO;
+
+	memcpy(&ah->ah_txq, queue_info, sizeof(struct ath5k_txq_info));
+
+	/*XXX: Is this supported on 5210 ?*/
+	if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA &&
+			((queue_info->tqi_subtype == AR5K_WME_AC_VI) ||
+			(queue_info->tqi_subtype == AR5K_WME_AC_VO))) ||
+			queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD)
+		ah->ah_txq.tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
+
+	return 0;
+}
+
+/*
+ * Initialize a transmit queue
+ */
+int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
+		struct ath5k_txq_info *queue_info)
+{
+	int ret;
+
+	/*
+	 * Setup internal queue structure
+	 */
+	memset(&ah->ah_txq, 0, sizeof(struct ath5k_txq_info));
+	ah->ah_txq.tqi_type = queue_type;
+
+	if (queue_info != NULL) {
+		queue_info->tqi_type = queue_type;
+		ret = ath5k_hw_set_tx_queueprops(ah, queue_info);
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * We use ah_txq_status to hold a temp value for
+	 * the Secondary interrupt mask registers on 5211+
+	 * check out ath5k_hw_reset_tx_queue
+	 */
+	AR5K_Q_ENABLE_BITS(ah->ah_txq_status, 0);
+
+	return 0;
+}
+
+/*
+ * Set a transmit queue inactive
+ */
+void ath5k_hw_release_tx_queue(struct ath5k_hw *ah)
+{
+	/* This queue will be skipped in further operations */
+	ah->ah_txq.tqi_type = AR5K_TX_QUEUE_INACTIVE;
+	/*For SIMR setup*/
+	AR5K_Q_DISABLE_BITS(ah->ah_txq_status, 0);
+}
+
+/*
+ * Set DFS properties for a transmit queue on DCU
+ */
+int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah)
+{
+	u32 cw_min, cw_max, retry_lg, retry_sh;
+	struct ath5k_txq_info *tq = &ah->ah_txq;
+	const int queue = 0;
+
+	tq = &ah->ah_txq;
+
+	if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return 0;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		/* Only handle data queues, others will be ignored */
+		if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
+			return 0;
+
+		/* Set Slot time */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
+			AR5K_SLOT_TIME);
+		/* Set ACK_CTS timeout */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
+			AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
+		/* Set Transmit Latency */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			AR5K_INIT_TRANSMIT_LATENCY_TURBO :
+			AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
+
+		/* Set IFS0 */
+		if (ah->ah_turbo) {
+			 ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
+				(ah->ah_aifs + tq->tqi_aifs) *
+				AR5K_INIT_SLOT_TIME_TURBO) <<
+				AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
+				AR5K_IFS0);
+		} else {
+			ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
+				(ah->ah_aifs + tq->tqi_aifs) *
+				AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) |
+				AR5K_INIT_SIFS, AR5K_IFS0);
+		}
+
+		/* Set IFS1 */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
+			AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
+		/* Set AR5K_PHY_SETTLING */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
+			| 0x38 :
+			(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
+			| 0x1C,
+			AR5K_PHY_SETTLING);
+		/* Set Frame Control Register */
+		ath5k_hw_reg_write(ah, ah->ah_turbo ?
+			(AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
+			AR5K_PHY_TURBO_SHORT | 0x2020) :
+			(AR5K_PHY_FRAME_CTL_INI | 0x1020),
+			AR5K_PHY_FRAME_CTL_5210);
+	}
+
+	/*
+	 * Calculate cwmin/max by channel mode
+	 */
+	cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN;
+	cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX;
+	ah->ah_aifs = AR5K_TUNE_AIFS;
+	/*XR is only supported on 5212*/
+	if (IS_CHAN_XR(ah->ah_current_channel) &&
+			ah->ah_version == AR5K_AR5212) {
+		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR;
+		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR;
+		ah->ah_aifs = AR5K_TUNE_AIFS_XR;
+	/*B mode is not supported on 5210*/
+	} else if (IS_CHAN_B(ah->ah_current_channel) &&
+			ah->ah_version != AR5K_AR5210) {
+		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B;
+		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B;
+		ah->ah_aifs = AR5K_TUNE_AIFS_11B;
+	}
+
+	cw_min = 1;
+	while (cw_min < ah->ah_cw_min)
+		cw_min = (cw_min << 1) | 1;
+
+	cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) :
+		((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1);
+	cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) :
+		((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1);
+
+	/*
+	 * Calculate and set retry limits
+	 */
+	if (ah->ah_software_retry) {
+		/* XXX Need to test this */
+		retry_lg = ah->ah_limit_tx_retries;
+		retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
+			AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg;
+	} else {
+		retry_lg = AR5K_INIT_LG_RETRY;
+		retry_sh = AR5K_INIT_SH_RETRY;
+	}
+
+	/*No QCU/DCU [5210]*/
+	if (ah->ah_version == AR5K_AR5210) {
+		ath5k_hw_reg_write(ah,
+			(cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
+			| AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
+				AR5K_NODCU_RETRY_LMT_SLG_RETRY)
+			| AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
+				AR5K_NODCU_RETRY_LMT_SSH_RETRY)
+			| AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
+			| AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
+			AR5K_NODCU_RETRY_LMT);
+	} else {
+		/*QCU/DCU [5211+]*/
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
+				AR5K_DCU_RETRY_LMT_SLG_RETRY) |
+			AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
+				AR5K_DCU_RETRY_LMT_SSH_RETRY) |
+			AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
+			AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
+			AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
+
+	/*===Rest is also for QCU/DCU only [5211+]===*/
+
+		/*
+		 * Set initial content window (cw_min/cw_max)
+		 * and arbitrated interframe space (aifs)...
+		 */
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
+			AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
+			AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs,
+				AR5K_DCU_LCL_IFS_AIFS),
+			AR5K_QUEUE_DFS_LOCAL_IFS(queue));
+
+		/*
+		 * Set misc registers
+		 */
+		/* Enable DCU early termination for this queue */
+		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+					AR5K_QCU_MISC_DCU_EARLY);
+
+		/* Enable DCU to wait for next fragment from QCU */
+		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+					AR5K_DCU_MISC_FRAG_WAIT);
+
+		/* On Maui and Spirit use the global seqnum on DCU */
+		if (ah->ah_mac_version < AR5K_SREV_AR5211)
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+						AR5K_DCU_MISC_SEQNUM_CTL);
+
+		if (tq->tqi_cbr_period) {
+			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
+				AR5K_QCU_CBRCFG_INTVAL) |
+				AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
+				AR5K_QCU_CBRCFG_ORN_THRES),
+				AR5K_QUEUE_CBRCFG(queue));
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+				AR5K_QCU_MISC_FRSHED_CBR);
+			if (tq->tqi_cbr_overflow_limit)
+				AR5K_REG_ENABLE_BITS(ah,
+					AR5K_QUEUE_MISC(queue),
+					AR5K_QCU_MISC_CBR_THRES_ENABLE);
+		}
+
+		if (tq->tqi_ready_time &&
+		(tq->tqi_type != AR5K_TX_QUEUE_CAB))
+			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
+				AR5K_QCU_RDYTIMECFG_INTVAL) |
+				AR5K_QCU_RDYTIMECFG_ENABLE,
+				AR5K_QUEUE_RDYTIMECFG(queue));
+
+		if (tq->tqi_burst_time) {
+			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
+				AR5K_DCU_CHAN_TIME_DUR) |
+				AR5K_DCU_CHAN_TIME_ENABLE,
+				AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
+
+			if (tq->tqi_flags
+			& AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
+				AR5K_REG_ENABLE_BITS(ah,
+					AR5K_QUEUE_MISC(queue),
+					AR5K_QCU_MISC_RDY_VEOL_POLICY);
+		}
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
+			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
+				AR5K_QUEUE_DFS_MISC(queue));
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
+			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
+				AR5K_QUEUE_DFS_MISC(queue));
+
+		/* TODO: Handle frame compression */
+
+		/*
+		 * Enable interrupts for this tx queue
+		 * in the secondary interrupt mask registers
+		 */
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue);
+
+		/* Update secondary interrupt mask registers */
+
+		/* Filter out inactive queues */
+		ah->ah_txq_imr_txok &= ah->ah_txq_status;
+		ah->ah_txq_imr_txerr &= ah->ah_txq_status;
+		ah->ah_txq_imr_txurn &= ah->ah_txq_status;
+		ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
+		ah->ah_txq_imr_txeol &= ah->ah_txq_status;
+		ah->ah_txq_imr_cbrorn &= ah->ah_txq_status;
+		ah->ah_txq_imr_cbrurn &= ah->ah_txq_status;
+		ah->ah_txq_imr_qtrig &= ah->ah_txq_status;
+		ah->ah_txq_imr_nofrm &= ah->ah_txq_status;
+
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
+			AR5K_SIMR0_QCU_TXOK) |
+			AR5K_REG_SM(ah->ah_txq_imr_txdesc,
+			AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
+			AR5K_SIMR1_QCU_TXERR) |
+			AR5K_REG_SM(ah->ah_txq_imr_txeol,
+			AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
+		/* Update simr2 but don't overwrite rest simr2 settings */
+		AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN);
+		AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2,
+			AR5K_REG_SM(ah->ah_txq_imr_txurn,
+			AR5K_SIMR2_QCU_TXURN));
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn,
+			AR5K_SIMR3_QCBRORN) |
+			AR5K_REG_SM(ah->ah_txq_imr_cbrurn,
+			AR5K_SIMR3_QCBRURN), AR5K_SIMR3);
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig,
+			AR5K_SIMR4_QTRIG), AR5K_SIMR4);
+		/* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm,
+			AR5K_TXNOFRM_QCU), AR5K_TXNOFRM);
+		/* No queue has TXNOFRM enabled, disable the interrupt
+		 * by setting AR5K_TXNOFRM to zero */
+		if (ah->ah_txq_imr_nofrm == 0)
+			ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
+
+		/* Set QCU mask for this DCU to save power */
+		AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
+	}
+
+	return 0;
+}
+
+/*
+ * Set slot time on DCU
+ */
+int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
+{
+	if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX)
+		return -EINVAL;
+
+	if (ah->ah_version == AR5K_AR5210)
+		ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time,
+				ah->ah_turbo), AR5K_SLOT_TIME);
+	else
+		ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT);
+
+	return 0;
+}
+
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_reset.c b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_reset.c
new file mode 100644
index 0000000000000000000000000000000000000000..2f36a4e9a04871afdfd18e977c126d24191b2a77
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_reset.c
@@ -0,0 +1,1174 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
+ * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
+ * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+FILE_LICENCE ( MIT );
+
+#define _ATH5K_RESET
+
+/*****************************\
+  Reset functions and helpers
+\*****************************/
+
+#include <ipxe/pci.h> 		/* To determine if a card is pci-e */
+#include <unistd.h>
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/* Find last set bit; fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32 */
+static int fls(int x)
+{
+        int r = 32;
+
+        if (!x)
+                return 0;
+        if (!(x & 0xffff0000u)) {
+                x <<= 16;
+                r -= 16;
+        }
+        if (!(x & 0xff000000u)) {
+                x <<= 8;
+                r -= 8;
+        }
+        if (!(x & 0xf0000000u)) {
+                x <<= 4;
+                r -= 4;
+        }
+        if (!(x & 0xc0000000u)) {
+                x <<= 2;
+                r -= 2;
+        }
+        if (!(x & 0x80000000u)) {
+                x <<= 1;
+                r -= 1;
+        }
+        return r;
+}
+
+
+/**
+ * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
+ *
+ * @ah: the &struct ath5k_hw
+ * @channel: the currently set channel upon reset
+ *
+ * Write the delta slope coefficient (used on pilot tracking ?) for OFDM
+ * operation on the AR5212 upon reset. This is a helper for ath5k_hw_reset().
+ *
+ * Since delta slope is floating point we split it on its exponent and
+ * mantissa and provide these values on hw.
+ *
+ * For more infos i think this patent is related
+ * http://www.freepatentsonline.com/7184495.html
+ */
+static int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
+	struct net80211_channel *channel)
+{
+	/* Get exponent and mantissa and set it */
+	u32 coef_scaled, coef_exp, coef_man,
+		ds_coef_exp, ds_coef_man, clock;
+
+	if (!(ah->ah_version == AR5K_AR5212) ||
+	    !(channel->hw_value & CHANNEL_OFDM)) {
+		DBG("ath5k: attempt to set OFDM timings on non-OFDM channel\n");
+		return -EFAULT;
+	}
+
+	/* Get coefficient
+	 * ALGO: coef = (5 * clock * carrier_freq) / 2)
+	 * we scale coef by shifting clock value by 24 for
+	 * better precision since we use integers */
+	/* TODO: Half/quarter rate */
+	clock =  ath5k_hw_htoclock(1, channel->hw_value & CHANNEL_TURBO);
+
+	coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq;
+
+	/* Get exponent
+	 * ALGO: coef_exp = 14 - highest set bit position */
+	coef_exp = fls(coef_scaled) - 1;
+
+	/* Doesn't make sense if it's zero*/
+	if (!coef_scaled || !coef_exp)
+		return -EINVAL;
+
+	/* Note: we've shifted coef_scaled by 24 */
+	coef_exp = 14 - (coef_exp - 24);
+
+
+	/* Get mantissa (significant digits)
+	 * ALGO: coef_mant = floor(coef_scaled* 2^coef_exp+0.5) */
+	coef_man = coef_scaled +
+		(1 << (24 - coef_exp - 1));
+
+	/* Calculate delta slope coefficient exponent
+	 * and mantissa (remove scaling) and set them on hw */
+	ds_coef_man = coef_man >> (24 - coef_exp);
+	ds_coef_exp = coef_exp - 16;
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
+		AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man);
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
+		AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp);
+
+	return 0;
+}
+
+
+/*
+ * index into rates for control rates, we can set it up like this because
+ * this is only used for AR5212 and we know it supports G mode
+ */
+static const unsigned int control_rates[] =
+	{ 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 };
+
+/**
+ * ath5k_hw_write_rate_duration - fill rate code to duration table
+ *
+ * @ah: the &struct ath5k_hw
+ * @mode: one of enum ath5k_driver_mode
+ *
+ * Write the rate code to duration table upon hw reset. This is a helper for
+ * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout on
+ * the hardware, based on current mode, for each rate. The rates which are
+ * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have
+ * different rate code so we write their value twice (one for long preample
+ * and one for short).
+ *
+ * Note: Band doesn't matter here, if we set the values for OFDM it works
+ * on both a and g modes. So all we have to do is set values for all g rates
+ * that include all OFDM and CCK rates. If we operate in turbo or xr/half/
+ * quarter rate mode, we need to use another set of bitrates (that's why we
+ * need the mode parameter) but we don't handle these proprietary modes yet.
+ */
+static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
+       unsigned int mode __unused)
+{
+	struct ath5k_softc *sc = ah->ah_sc;
+	u16 rate;
+	int i;
+
+	/* Write rate duration table */
+	for (i = 0; i < sc->hwinfo->nr_rates[NET80211_BAND_2GHZ]; i++) {
+		u32 reg;
+		u16 tx_time;
+
+		rate = sc->hwinfo->rates[NET80211_BAND_2GHZ][i];
+
+		/* Set ACK timeout */
+		reg = AR5K_RATE_DUR(ath5k_bitrate_to_hw_rix(rate));
+
+		/* An ACK frame consists of 10 bytes. If you add the FCS,
+		 * it's 14 bytes. Note we use the control rate and not the
+		 * actual rate for this rate. See mac80211 tx.c
+		 * ieee80211_duration() for a brief description of
+		 * what rate we should choose to TX ACKs. */
+		tx_time = net80211_duration(sc->dev, 14, rate);
+
+		ath5k_hw_reg_write(ah, tx_time, reg);
+
+		if (rate != 20 && rate != 55 && rate != 110)
+			continue;
+
+		/*
+		 * We're not distinguishing short preamble here,
+		 * This is true, all we'll get is a longer value here
+		 * which is not necessarilly bad.
+		 */
+		ath5k_hw_reg_write(ah, tx_time,
+			reg + (AR5K_SET_SHORT_PREAMBLE << 2));
+	}
+}
+
+/*
+ * Reset chipset
+ */
+static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
+{
+	int ret;
+	u32 mask = val ? val : ~0U;
+
+	/* Read-and-clear RX Descriptor Pointer*/
+	ath5k_hw_reg_read(ah, AR5K_RXDP);
+
+	/*
+	 * Reset the device and wait until success
+	 */
+	ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL);
+
+	/* Wait at least 128 PCI clocks */
+	udelay(15);
+
+	if (ah->ah_version == AR5K_AR5210) {
+		val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
+			| AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY;
+		mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
+			| AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY;
+	} else {
+		val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
+		mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
+	}
+
+	ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, 0);
+
+	/*
+	 * Reset configuration register (for hw byte-swap). Note that this
+	 * is only set for big endian. We do the necessary magic in
+	 * AR5K_INIT_CFG.
+	 */
+	if ((val & AR5K_RESET_CTL_PCU) == 0)
+		ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG);
+
+	return ret;
+}
+
+/*
+ * Sleep control
+ */
+int ath5k_hw_wake(struct ath5k_hw *ah)
+{
+	unsigned int i;
+	u32 staid, data;
+
+	staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
+	staid &= ~AR5K_STA_ID1_PWR_SV;
+
+	/* Preserve sleep duration */
+	data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
+	if (data & 0xffc00000)
+		data = 0;
+	else
+		data = data & 0xfffcffff;
+
+	ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
+	udelay(15);
+
+	for (i = 50; i > 0; i--) {
+		/* Check if the chip did wake up */
+		if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
+		     AR5K_PCICFG_SPWR_DN) == 0)
+			break;
+
+		/* Wait a bit and retry */
+		udelay(200);
+		ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
+	}
+
+	/* Fail if the chip didn't wake up */
+	if (i <= 0)
+		return -EIO;
+
+	ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
+
+	return 0;
+}
+
+/*
+ * Bring up MAC + PHY Chips and program PLL
+ * TODO: Half/Quarter rate support
+ */
+int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, int initial __unused)
+{
+	struct pci_device *pdev = ah->ah_sc->pdev;
+	u32 turbo, mode, clock, bus_flags;
+	int ret;
+
+	turbo = 0;
+	mode = 0;
+	clock = 0;
+
+	/* Wakeup the device */
+	ret = ath5k_hw_wake(ah);
+	if (ret) {
+		DBG("ath5k: failed to wake up the MAC chip\n");
+		return ret;
+	}
+
+	if (ah->ah_version != AR5K_AR5210) {
+		/*
+		 * Get channel mode flags
+		 */
+
+		if (ah->ah_radio >= AR5K_RF5112) {
+			mode = AR5K_PHY_MODE_RAD_RF5112;
+			clock = AR5K_PHY_PLL_RF5112;
+		} else {
+			mode = AR5K_PHY_MODE_RAD_RF5111;	/*Zero*/
+			clock = AR5K_PHY_PLL_RF5111;		/*Zero*/
+		}
+
+		if (flags & CHANNEL_2GHZ) {
+			mode |= AR5K_PHY_MODE_FREQ_2GHZ;
+			clock |= AR5K_PHY_PLL_44MHZ;
+
+			if (flags & CHANNEL_CCK) {
+				mode |= AR5K_PHY_MODE_MOD_CCK;
+			} else if (flags & CHANNEL_OFDM) {
+				/* XXX Dynamic OFDM/CCK is not supported by the
+				 * AR5211 so we set MOD_OFDM for plain g (no
+				 * CCK headers) operation. We need to test
+				 * this, 5211 might support ofdm-only g after
+				 * all, there are also initial register values
+				 * in the code for g mode (see initvals.c). */
+				if (ah->ah_version == AR5K_AR5211)
+					mode |= AR5K_PHY_MODE_MOD_OFDM;
+				else
+					mode |= AR5K_PHY_MODE_MOD_DYN;
+			} else {
+				DBG("ath5k: invalid radio modulation mode\n");
+				return -EINVAL;
+			}
+		} else if (flags & CHANNEL_5GHZ) {
+			mode |= AR5K_PHY_MODE_FREQ_5GHZ;
+
+			if (ah->ah_radio == AR5K_RF5413)
+				clock = AR5K_PHY_PLL_40MHZ_5413;
+			else
+				clock |= AR5K_PHY_PLL_40MHZ;
+
+			if (flags & CHANNEL_OFDM)
+				mode |= AR5K_PHY_MODE_MOD_OFDM;
+			else {
+				DBG("ath5k: invalid radio modulation mode\n");
+				return -EINVAL;
+			}
+		} else {
+			DBG("ath5k: invalid radio frequency mode\n");
+			return -EINVAL;
+		}
+
+		if (flags & CHANNEL_TURBO)
+			turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT;
+	} else { /* Reset the device */
+
+		/* ...enable Atheros turbo mode if requested */
+		if (flags & CHANNEL_TURBO)
+			ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE,
+					AR5K_PHY_TURBO);
+	}
+
+	/* reseting PCI on PCI-E cards results card to hang
+	 * and always return 0xffff... so we ingore that flag
+	 * for PCI-E cards */
+	if (pci_find_capability(pdev, PCI_CAP_ID_EXP))
+		bus_flags = 0;
+	else
+		bus_flags = AR5K_RESET_CTL_PCI;
+
+	/* Reset chipset */
+	if (ah->ah_version == AR5K_AR5210) {
+		ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+			AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
+			AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
+		mdelay(2);
+	} else {
+		ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+			AR5K_RESET_CTL_BASEBAND | bus_flags);
+	}
+	if (ret) {
+		DBG("ath5k: failed to reset the MAC chip\n");
+		return -EIO;
+	}
+
+	/* ...wakeup again!*/
+	ret = ath5k_hw_wake(ah);
+	if (ret) {
+		DBG("ath5k: failed to resume the MAC chip\n");
+		return ret;
+	}
+
+	/* ...final warm reset */
+	if (ath5k_hw_nic_reset(ah, 0)) {
+		DBG("ath5k: failed to warm reset the MAC chip\n");
+		return -EIO;
+	}
+
+	if (ah->ah_version != AR5K_AR5210) {
+
+		/* ...update PLL if needed */
+		if (ath5k_hw_reg_read(ah, AR5K_PHY_PLL) != clock) {
+			ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
+			udelay(300);
+		}
+
+		/* ...set the PHY operating mode */
+		ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE);
+		ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO);
+	}
+
+	return 0;
+}
+
+static int ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
+				struct net80211_channel *channel)
+{
+	u8 refclk_freq;
+
+	if ((ah->ah_radio == AR5K_RF5112) ||
+	(ah->ah_radio == AR5K_RF5413) ||
+	(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
+		refclk_freq = 40;
+	else
+		refclk_freq = 32;
+
+	if ((channel->center_freq % refclk_freq != 0) &&
+	((channel->center_freq % refclk_freq < 10) ||
+	(channel->center_freq % refclk_freq > 22)))
+		return 1;
+	else
+		return 0;
+}
+
+/* TODO: Half/Quarter rate */
+static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
+				struct net80211_channel *channel)
+{
+	if (ah->ah_version == AR5K_AR5212 &&
+	    ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
+
+		/* Setup ADC control */
+		ath5k_hw_reg_write(ah,
+				(AR5K_REG_SM(2,
+				AR5K_PHY_ADC_CTL_INBUFGAIN_OFF) |
+				AR5K_REG_SM(2,
+				AR5K_PHY_ADC_CTL_INBUFGAIN_ON) |
+				AR5K_PHY_ADC_CTL_PWD_DAC_OFF |
+				AR5K_PHY_ADC_CTL_PWD_ADC_OFF),
+				AR5K_PHY_ADC_CTL);
+
+
+
+		/* Disable barker RSSI threshold */
+		AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_DAG_CCK_CTL,
+				AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR);
+
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DAG_CCK_CTL,
+			AR5K_PHY_DAG_CCK_CTL_RSSI_THR, 2);
+
+		/* Set the mute mask */
+		ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK);
+	}
+
+	/* Clear PHY_BLUETOOTH to allow RX_CLEAR line debug */
+	if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212B)
+		ath5k_hw_reg_write(ah, 0, AR5K_PHY_BLUETOOTH);
+
+	/* Enable DCU double buffering */
+	if (ah->ah_phy_revision > AR5K_SREV_PHY_5212B)
+		AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
+				AR5K_TXCFG_DCU_DBL_BUF_DIS);
+
+	/* Set DAC/ADC delays */
+	if (ah->ah_version == AR5K_AR5212) {
+		u32 scal;
+		if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
+			scal = AR5K_PHY_SCAL_32MHZ_2417;
+		else if (ath5k_eeprom_is_hb63(ah))
+			scal = AR5K_PHY_SCAL_32MHZ_HB63;
+		else
+			scal = AR5K_PHY_SCAL_32MHZ;
+		ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL);
+	}
+
+	/* Set fast ADC */
+	if ((ah->ah_radio == AR5K_RF5413) ||
+	(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
+		u32 fast_adc = 1;
+
+		if (channel->center_freq == 2462 ||
+		channel->center_freq == 2467)
+			fast_adc = 0;
+
+		/* Only update if needed */
+		if (ath5k_hw_reg_read(ah, AR5K_PHY_FAST_ADC) != fast_adc)
+				ath5k_hw_reg_write(ah, fast_adc,
+						AR5K_PHY_FAST_ADC);
+	}
+
+	/* Fix for first revision of the RF5112 RF chipset */
+	if (ah->ah_radio == AR5K_RF5112 &&
+			ah->ah_radio_5ghz_revision <
+			AR5K_SREV_RAD_5112A) {
+		u32 data;
+		ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
+				AR5K_PHY_CCKTXCTL);
+		if (channel->hw_value & CHANNEL_5GHZ)
+			data = 0xffb81020;
+		else
+			data = 0xffb80d20;
+		ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
+	}
+
+	if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+		u32 usec_reg;
+		/* 5311 has different tx/rx latency masks
+		 * from 5211, since we deal 5311 the same
+		 * as 5211 when setting initvals, shift
+		 * values here to their proper locations */
+		usec_reg = ath5k_hw_reg_read(ah, AR5K_USEC_5211);
+		ath5k_hw_reg_write(ah, usec_reg & (AR5K_USEC_1 |
+				AR5K_USEC_32 |
+				AR5K_USEC_TX_LATENCY_5211 |
+				AR5K_REG_SM(29,
+				AR5K_USEC_RX_LATENCY_5210)),
+				AR5K_USEC_5211);
+		/* Clear QCU/DCU clock gating register */
+		ath5k_hw_reg_write(ah, 0, AR5K_QCUDCU_CLKGT);
+		/* Set DAC/ADC delays */
+		ath5k_hw_reg_write(ah, 0x08, AR5K_PHY_SCAL);
+		/* Enable PCU FIFO corruption ECO */
+		AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
+					AR5K_DIAG_SW_ECO_ENABLE);
+	}
+}
+
+static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
+		struct net80211_channel *channel, u8 *ant, u8 ee_mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	s16 cck_ofdm_pwr_delta;
+
+	/* Adjust power delta for channel 14 */
+	if (channel->center_freq == 2484)
+		cck_ofdm_pwr_delta =
+			((ee->ee_cck_ofdm_power_delta -
+			ee->ee_scaled_cck_delta) * 2) / 10;
+	else
+		cck_ofdm_pwr_delta =
+			(ee->ee_cck_ofdm_power_delta * 2) / 10;
+
+	/* Set CCK to OFDM power delta on tx power
+	 * adjustment register */
+	if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
+		if (channel->hw_value == CHANNEL_G)
+			ath5k_hw_reg_write(ah,
+			AR5K_REG_SM((ee->ee_cck_ofdm_gain_delta * -1),
+				AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) |
+			AR5K_REG_SM((cck_ofdm_pwr_delta * -1),
+				AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX),
+				AR5K_PHY_TX_PWR_ADJ);
+		else
+			ath5k_hw_reg_write(ah, 0, AR5K_PHY_TX_PWR_ADJ);
+	} else {
+		/* For older revs we scale power on sw during tx power
+		 * setup */
+		ah->ah_txpower.txp_cck_ofdm_pwr_delta = cck_ofdm_pwr_delta;
+		ah->ah_txpower.txp_cck_ofdm_gainf_delta =
+						ee->ee_cck_ofdm_gain_delta;
+	}
+
+	/* Set antenna idle switch table */
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL,
+			AR5K_PHY_ANT_CTL_SWTABLE_IDLE,
+			(ah->ah_antenna[ee_mode][0] |
+			AR5K_PHY_ANT_CTL_TXRX_EN));
+
+	/* Set antenna switch table */
+	ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]],
+		AR5K_PHY_ANT_SWITCH_TABLE_0);
+	ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]],
+		AR5K_PHY_ANT_SWITCH_TABLE_1);
+
+	/* Noise floor threshold */
+	ath5k_hw_reg_write(ah,
+		AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
+		AR5K_PHY_NFTHRES);
+
+	if ((channel->hw_value & CHANNEL_TURBO) &&
+	(ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0)) {
+		/* Switch settling time (Turbo) */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
+				AR5K_PHY_SETTLING_SWITCH,
+				ee->ee_switch_settling_turbo[ee_mode]);
+
+		/* Tx/Rx attenuation (Turbo) */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN,
+				AR5K_PHY_GAIN_TXRX_ATTEN,
+				ee->ee_atn_tx_rx_turbo[ee_mode]);
+
+		/* ADC/PGA desired size (Turbo) */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+				AR5K_PHY_DESIRED_SIZE_ADC,
+				ee->ee_adc_desired_size_turbo[ee_mode]);
+
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+				AR5K_PHY_DESIRED_SIZE_PGA,
+				ee->ee_pga_desired_size_turbo[ee_mode]);
+
+		/* Tx/Rx margin (Turbo) */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
+				AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
+				ee->ee_margin_tx_rx_turbo[ee_mode]);
+
+	} else {
+		/* Switch settling time */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
+				AR5K_PHY_SETTLING_SWITCH,
+				ee->ee_switch_settling[ee_mode]);
+
+		/* Tx/Rx attenuation */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN,
+				AR5K_PHY_GAIN_TXRX_ATTEN,
+				ee->ee_atn_tx_rx[ee_mode]);
+
+		/* ADC/PGA desired size */
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+				AR5K_PHY_DESIRED_SIZE_ADC,
+				ee->ee_adc_desired_size[ee_mode]);
+
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+				AR5K_PHY_DESIRED_SIZE_PGA,
+				ee->ee_pga_desired_size[ee_mode]);
+
+		/* Tx/Rx margin */
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
+				AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
+				ee->ee_margin_tx_rx[ee_mode]);
+	}
+
+	/* XPA delays */
+	ath5k_hw_reg_write(ah,
+		(ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
+		(ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
+		(ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
+		(ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4);
+
+	/* XLNA delay */
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RF_CTL3,
+			AR5K_PHY_RF_CTL3_TXE2XLNA_ON,
+			ee->ee_tx_end2xlna_enable[ee_mode]);
+
+	/* Thresh64 (ANI) */
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_NF,
+			AR5K_PHY_NF_THRESH62,
+			ee->ee_thr_62[ee_mode]);
+
+
+	/* False detect backoff for channels
+	 * that have spur noise. Write the new
+	 * cyclic power RSSI threshold. */
+	if (ath5k_hw_chan_has_spur_noise(ah, channel))
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
+				AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
+				AR5K_INIT_CYCRSSI_THR1 +
+				ee->ee_false_detect[ee_mode]);
+	else
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
+				AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
+				AR5K_INIT_CYCRSSI_THR1);
+
+	/* I/Q correction
+	 * TODO: Per channel i/q infos ? */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
+		AR5K_PHY_IQ_CORR_ENABLE |
+		(ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) |
+		ee->ee_q_cal[ee_mode]);
+
+	/* Heavy clipping -disable for now */
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_1)
+		ath5k_hw_reg_write(ah, 0, AR5K_PHY_HEAVY_CLIP_ENABLE);
+
+	return;
+}
+
+/*
+ * Main reset function
+ */
+int ath5k_hw_reset(struct ath5k_hw *ah,
+	struct net80211_channel *channel, int change_channel)
+{
+	u32 s_seq[10], s_ant, s_led[3], staid1_flags;
+	u32 phy_tst1;
+	u8 mode, freq, ee_mode, ant[2];
+	int i, ret;
+
+	s_ant = 0;
+	ee_mode = 0;
+	staid1_flags = 0;
+	freq = 0;
+	mode = 0;
+
+	/*
+	 * Save some registers before a reset
+	 */
+	/*DCU/Antenna selection not available on 5210*/
+	if (ah->ah_version != AR5K_AR5210) {
+
+		switch (channel->hw_value & CHANNEL_MODES) {
+		case CHANNEL_A:
+			mode = AR5K_MODE_11A;
+			freq = AR5K_INI_RFGAIN_5GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11A;
+			break;
+		case CHANNEL_G:
+			mode = AR5K_MODE_11G;
+			freq = AR5K_INI_RFGAIN_2GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11G;
+			break;
+		case CHANNEL_B:
+			mode = AR5K_MODE_11B;
+			freq = AR5K_INI_RFGAIN_2GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11B;
+			break;
+		case CHANNEL_T:
+			mode = AR5K_MODE_11A_TURBO;
+			freq = AR5K_INI_RFGAIN_5GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11A;
+			break;
+		case CHANNEL_TG:
+			if (ah->ah_version == AR5K_AR5211) {
+				DBG("ath5k: TurboG not available on 5211\n");
+				return -EINVAL;
+			}
+			mode = AR5K_MODE_11G_TURBO;
+			freq = AR5K_INI_RFGAIN_2GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11G;
+			break;
+		case CHANNEL_XR:
+			if (ah->ah_version == AR5K_AR5211) {
+				DBG("ath5k: XR mode not available on 5211\n");
+				return -EINVAL;
+			}
+			mode = AR5K_MODE_XR;
+			freq = AR5K_INI_RFGAIN_5GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11A;
+			break;
+		default:
+			DBG("ath5k: invalid channel (%d MHz)\n",
+			    channel->center_freq);
+			return -EINVAL;
+		}
+
+		if (change_channel) {
+			/*
+			 * Save frame sequence count
+			 * For revs. after Oahu, only save
+			 * seq num for DCU 0 (Global seq num)
+			 */
+			if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+
+				for (i = 0; i < 10; i++)
+					s_seq[i] = ath5k_hw_reg_read(ah,
+						AR5K_QUEUE_DCU_SEQNUM(i));
+
+			} else {
+				s_seq[0] = ath5k_hw_reg_read(ah,
+						AR5K_QUEUE_DCU_SEQNUM(0));
+			}
+		}
+
+		/* Save default antenna */
+		s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
+
+		if (ah->ah_version == AR5K_AR5212) {
+			/* Since we are going to write rf buffer
+			 * check if we have any pending gain_F
+			 * optimization settings */
+			if (change_channel && ah->ah_rf_banks != NULL)
+				ath5k_hw_gainf_calibrate(ah);
+		}
+	}
+
+	/*GPIOs*/
+	s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) &
+					AR5K_PCICFG_LEDSTATE;
+	s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
+	s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
+
+	/* AR5K_STA_ID1 flags, only preserve antenna
+	 * settings and ack/cts rate mode */
+	staid1_flags = ath5k_hw_reg_read(ah, AR5K_STA_ID1) &
+			(AR5K_STA_ID1_DEFAULT_ANTENNA |
+			AR5K_STA_ID1_DESC_ANTENNA |
+			AR5K_STA_ID1_RTS_DEF_ANTENNA |
+			AR5K_STA_ID1_ACKCTS_6MB |
+			AR5K_STA_ID1_BASE_RATE_11B |
+			AR5K_STA_ID1_SELFGEN_DEF_ANT);
+
+	/* Wakeup the device */
+	ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, 0);
+	if (ret)
+		return ret;
+
+	/* PHY access enable */
+	if (ah->ah_mac_srev >= AR5K_SREV_AR5211)
+		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+	else
+		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ | 0x40,
+							AR5K_PHY(0));
+
+	/* Write initial settings */
+	ret = ath5k_hw_write_initvals(ah, mode, change_channel);
+	if (ret)
+		return ret;
+
+	/*
+	 * 5211/5212 Specific
+	 */
+	if (ah->ah_version != AR5K_AR5210) {
+
+		/*
+		 * Write initial RF gain settings
+		 * This should work for both 5111/5112
+		 */
+		ret = ath5k_hw_rfgain_init(ah, freq);
+		if (ret)
+			return ret;
+
+		mdelay(1);
+
+		/*
+		 * Tweak initval settings for revised
+		 * chipsets and add some more config
+		 * bits
+		 */
+		ath5k_hw_tweak_initval_settings(ah, channel);
+
+		/*
+		 * Set TX power (FIXME)
+		 */
+		ret = ath5k_hw_txpower(ah, channel, ee_mode,
+					AR5K_TUNE_DEFAULT_TXPOWER);
+		if (ret)
+			return ret;
+
+		/* Write rate duration table only on AR5212 */
+		if (ah->ah_version == AR5K_AR5212)
+			ath5k_hw_write_rate_duration(ah, mode);
+
+		/*
+		 * Write RF buffer
+		 */
+		ret = ath5k_hw_rfregs_init(ah, channel, mode);
+		if (ret)
+			return ret;
+
+
+		/* Write OFDM timings on 5212*/
+		if (ah->ah_version == AR5K_AR5212 &&
+			channel->hw_value & CHANNEL_OFDM) {
+			ret = ath5k_hw_write_ofdm_timings(ah, channel);
+			if (ret)
+				return ret;
+		}
+
+		/*Enable/disable 802.11b mode on 5111
+		(enable 2111 frequency converter + CCK)*/
+		if (ah->ah_radio == AR5K_RF5111) {
+			if (mode == AR5K_MODE_11B)
+				AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
+				    AR5K_TXCFG_B_MODE);
+			else
+				AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
+				    AR5K_TXCFG_B_MODE);
+		}
+
+		/*
+		 * In case a fixed antenna was set as default
+		 * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE
+		 * registers.
+		 */
+		if (s_ant != 0) {
+			if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */
+				ant[0] = ant[1] = AR5K_ANT_FIXED_A;
+			else	/* 2 - Aux */
+				ant[0] = ant[1] = AR5K_ANT_FIXED_B;
+		} else {
+			ant[0] = AR5K_ANT_FIXED_A;
+			ant[1] = AR5K_ANT_FIXED_B;
+		}
+
+		/* Commit values from EEPROM */
+		ath5k_hw_commit_eeprom_settings(ah, channel, ant, ee_mode);
+
+	} else {
+		/*
+		 * For 5210 we do all initialization using
+		 * initvals, so we don't have to modify
+		 * any settings (5210 also only supports
+		 * a/aturbo modes)
+		 */
+		mdelay(1);
+		/* Disable phy and wait */
+		ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
+		mdelay(1);
+	}
+
+	/*
+	 * Restore saved values
+	 */
+
+	/*DCU/Antenna selection not available on 5210*/
+	if (ah->ah_version != AR5K_AR5210) {
+
+		if (change_channel) {
+			if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+				for (i = 0; i < 10; i++)
+					ath5k_hw_reg_write(ah, s_seq[i],
+						AR5K_QUEUE_DCU_SEQNUM(i));
+			} else {
+				ath5k_hw_reg_write(ah, s_seq[0],
+					AR5K_QUEUE_DCU_SEQNUM(0));
+			}
+		}
+
+		ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA);
+	}
+
+	/* Ledstate */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]);
+
+	/* Gpio settings */
+	ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR);
+	ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
+
+	/* Restore sta_id flags and preserve our mac address*/
+	ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_sta_id),
+						AR5K_STA_ID0);
+	ath5k_hw_reg_write(ah, staid1_flags | AR5K_HIGH_ID(ah->ah_sta_id),
+						AR5K_STA_ID1);
+
+
+	/*
+	 * Configure PCU
+	 */
+
+	/* Restore bssid and bssid mask */
+	/* XXX: add ah->aid once mac80211 gives this to us */
+	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+
+	/* Set PCU config */
+	ath5k_hw_set_opmode(ah);
+
+	/* Clear any pending interrupts
+	 * PISR/SISR Not available on 5210 */
+	if (ah->ah_version != AR5K_AR5210)
+		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
+
+	/* Set RSSI/BRSSI thresholds
+	 *
+	 * Note: If we decide to set this value
+	 * dynamicaly, have in mind that when AR5K_RSSI_THR
+	 * register is read it might return 0x40 if we haven't
+	 * wrote anything to it plus BMISS RSSI threshold is zeroed.
+	 * So doing a save/restore procedure here isn't the right
+	 * choice. Instead store it on ath5k_hw */
+	ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES |
+				AR5K_TUNE_BMISS_THRES <<
+				AR5K_RSSI_THR_BMISS_S),
+				AR5K_RSSI_THR);
+
+	/* MIC QoS support */
+	if (ah->ah_mac_srev >= AR5K_SREV_AR2413) {
+		ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL);
+		ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL);
+	}
+
+	/* QoS NOACK Policy */
+	if (ah->ah_version == AR5K_AR5212) {
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) |
+			AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET)  |
+			AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET),
+			AR5K_QOS_NOACK);
+	}
+
+
+	/*
+	 * Configure PHY
+	 */
+
+	/* Set channel on PHY */
+	ret = ath5k_hw_channel(ah, channel);
+	if (ret)
+		return ret;
+
+	/*
+	 * Enable the PHY and wait until completion
+	 * This includes BaseBand and Synthesizer
+	 * activation.
+	 */
+	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
+
+	/*
+	 * On 5211+ read activation -> rx delay
+	 * and use it.
+	 *
+	 * TODO: Half/quarter rate support
+	 */
+	if (ah->ah_version != AR5K_AR5210) {
+		u32 delay;
+		delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
+			AR5K_PHY_RX_DELAY_M;
+		delay = (channel->hw_value & CHANNEL_CCK) ?
+			((delay << 2) / 22) : (delay / 10);
+
+		udelay(100 + (2 * delay));
+	} else {
+		mdelay(1);
+	}
+
+	/*
+	 * Perform ADC test to see if baseband is ready
+	 * Set tx hold and check adc test register
+	 */
+	phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
+	ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
+	for (i = 0; i <= 20; i++) {
+		if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
+			break;
+		udelay(200);
+	}
+	ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
+
+	/*
+	 * Start automatic gain control calibration
+	 *
+	 * During AGC calibration RX path is re-routed to
+	 * a power detector so we don't receive anything.
+	 *
+	 * This method is used to calibrate some static offsets
+	 * used together with on-the fly I/Q calibration (the
+	 * one performed via ath5k_hw_phy_calibrate), that doesn't
+	 * interrupt rx path.
+	 *
+	 * While rx path is re-routed to the power detector we also
+	 * start a noise floor calibration, to measure the
+	 * card's noise floor (the noise we measure when we are not
+	 * transmiting or receiving anything).
+	 *
+	 * If we are in a noisy environment AGC calibration may time
+	 * out and/or noise floor calibration might timeout.
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+				AR5K_PHY_AGCCTL_CAL);
+
+	/* At the same time start I/Q calibration for QAM constellation
+	 * -no need for CCK- */
+	ah->ah_calibration = 0;
+	if (!(mode == AR5K_MODE_11B)) {
+		ah->ah_calibration = 1;
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
+				AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
+				AR5K_PHY_IQ_RUN);
+	}
+
+	/* Wait for gain calibration to finish (we check for I/Q calibration
+	 * during ath5k_phy_calibrate) */
+	if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+			AR5K_PHY_AGCCTL_CAL, 0, 0)) {
+		DBG("ath5k: gain calibration timeout (%d MHz)\n",
+		    channel->center_freq);
+	}
+
+	/*
+	 * If we run NF calibration before AGC, it always times out.
+	 * Binary HAL starts NF and AGC calibration at the same time
+	 * and only waits for AGC to finish. Also if AGC or NF cal.
+	 * times out, reset doesn't fail on binary HAL. I believe
+	 * that's wrong because since rx path is routed to a detector,
+	 * if cal. doesn't finish we won't have RX. Sam's HAL for AR5210/5211
+	 * enables noise floor calibration after offset calibration and if noise
+	 * floor calibration fails, reset fails. I believe that's
+	 * a better approach, we just need to find a polling interval
+	 * that suits best, even if reset continues we need to make
+	 * sure that rx path is ready.
+	 */
+	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
+
+
+	/*
+	 * Configure QCUs/DCUs
+	 */
+
+	/* TODO: HW Compression support for data queues */
+	/* TODO: Burst prefetch for data queues */
+
+	/*
+	 * Reset queues and start beacon timers at the end of the reset routine
+	 * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping
+	 * Note: If we want we can assign multiple qcus on one dcu.
+	 */
+	ret = ath5k_hw_reset_tx_queue(ah);
+	if (ret) {
+		DBG("ath5k: failed to reset TX queue\n");
+		return ret;
+	}
+
+	/*
+	 * Configure DMA/Interrupts
+	 */
+
+	/*
+	 * Set Rx/Tx DMA Configuration
+	 *
+	 * Set standard DMA size (128). Note that
+	 * a DMA size of 512 causes rx overruns and tx errors
+	 * on pci-e cards (tested on 5424 but since rx overruns
+	 * also occur on 5416/5418 with madwifi we set 128
+	 * for all PCI-E cards to be safe).
+	 *
+	 * XXX: need to check 5210 for this
+	 * TODO: Check out tx triger level, it's always 64 on dumps but I
+	 * guess we can tweak it and see how it goes ;-)
+	 */
+	if (ah->ah_version != AR5K_AR5210) {
+		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+			AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
+		AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
+			AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B);
+	}
+
+	/* Pre-enable interrupts on 5211/5212*/
+	if (ah->ah_version != AR5K_AR5210)
+		ath5k_hw_set_imr(ah, ah->ah_imr);
+
+	/*
+	 * Setup RFKill interrupt if rfkill flag is set on eeprom.
+	 * TODO: Use gpio pin and polarity infos from eeprom
+	 * TODO: Handle this in ath5k_intr because it'll result
+	 * 	 a nasty interrupt storm.
+	 */
+#if 0
+	if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) {
+		ath5k_hw_set_gpio_input(ah, 0);
+		ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0);
+		if (ah->ah_gpio[0] == 0)
+			ath5k_hw_set_gpio_intr(ah, 0, 1);
+		else
+			ath5k_hw_set_gpio_intr(ah, 0, 0);
+	}
+#endif
+
+	/*
+	 * Disable beacons and reset the register
+	 */
+	AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE |
+			AR5K_BEACON_RESET_TSF);
+
+	return 0;
+}
+
+#undef _ATH5K_RESET
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_rfkill.c b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_rfkill.c
new file mode 100644
index 0000000000000000000000000000000000000000..752ef70b98f0488d9633ce58f6ce8814cb9059c4
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/ath5k_rfkill.c
@@ -0,0 +1,107 @@
+/*
+ * RFKILL support for ath5k
+ *
+ * Copyright (c) 2009 Tobias Doerffel <tobias.doerffel@gmail.com>
+ * Lightly modified for iPXE, Sep 2008 by Joshua Oreman <oremanj@rwcr.net>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * NO WARRANTY
+ * 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 NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+FILE_LICENCE ( MIT );
+
+#include "base.h"
+
+
+static inline void ath5k_rfkill_disable(struct ath5k_softc *sc)
+{
+	DBG("ath5k: rfkill disable (gpio:%d polarity:%d)\n",
+	    sc->rf_kill.gpio, sc->rf_kill.polarity);
+	ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio);
+	ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, !sc->rf_kill.polarity);
+}
+
+
+static inline void ath5k_rfkill_enable(struct ath5k_softc *sc)
+{
+	DBG("ath5k: rfkill enable (gpio:%d polarity:%d)\n",
+	    sc->rf_kill.gpio, sc->rf_kill.polarity);
+	ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio);
+	ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, sc->rf_kill.polarity);
+}
+
+static inline void ath5k_rfkill_set_intr(struct ath5k_softc *sc, int enable)
+{
+	struct ath5k_hw *ah = sc->ah;
+	u32 curval;
+
+	ath5k_hw_set_gpio_input(ah, sc->rf_kill.gpio);
+	curval = ath5k_hw_get_gpio(ah, sc->rf_kill.gpio);
+	ath5k_hw_set_gpio_intr(ah, sc->rf_kill.gpio, enable ?
+			       !!curval : !curval);
+}
+
+static int __unused
+ath5k_is_rfkill_set(struct ath5k_softc *sc)
+{
+	/* configuring GPIO for input for some reason disables rfkill */
+	/*ath5k_hw_set_gpio_input(sc->ah, sc->rf_kill.gpio);*/
+	return (ath5k_hw_get_gpio(sc->ah, sc->rf_kill.gpio) ==
+		sc->rf_kill.polarity);
+}
+
+void
+ath5k_rfkill_hw_start(struct ath5k_hw *ah)
+{
+	struct ath5k_softc *sc = ah->ah_sc;
+
+	/* read rfkill GPIO configuration from EEPROM header */
+	sc->rf_kill.gpio = ah->ah_capabilities.cap_eeprom.ee_rfkill_pin;
+	sc->rf_kill.polarity = ah->ah_capabilities.cap_eeprom.ee_rfkill_pol;
+
+	ath5k_rfkill_disable(sc);
+
+	/* enable interrupt for rfkill switch */
+	if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header))
+		ath5k_rfkill_set_intr(sc, 1);
+}
+
+
+void
+ath5k_rfkill_hw_stop(struct ath5k_hw *ah)
+{
+	struct ath5k_softc *sc = ah->ah_sc;
+
+	/* disable interrupt for rfkill switch */
+	if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header))
+		ath5k_rfkill_set_intr(sc, 0);
+
+	/* enable RFKILL when stopping HW so Wifi LED is turned off */
+	ath5k_rfkill_enable(sc);
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/base.h b/roms/ipxe/src/drivers/net/ath/ath5k/base.h
new file mode 100644
index 0000000000000000000000000000000000000000..976a3f306c91d703a8e2cd94f2723cd6b0017628
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/base.h
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>
+ * Original from Linux kernel 2.6.30.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+/*
+ * Defintions for the Atheros Wireless LAN controller driver.
+ */
+#ifndef _DEV_ATH_ATHVAR_H
+#define _DEV_ATH_ATHVAR_H
+
+FILE_LICENCE ( BSD3 );
+
+#include "ath5k.h"
+#include <ipxe/iobuf.h>
+
+#define	ATH_RXBUF	16		/* number of RX buffers */
+#define	ATH_TXBUF	16		/* number of TX buffers */
+
+struct ath5k_buf {
+	struct list_head	list;
+	unsigned int		flags;	/* rx descriptor flags */
+	struct ath5k_desc	*desc;	/* virtual addr of desc */
+	u32			daddr;	/* physical addr of desc */
+	struct io_buffer	*iob;	/* I/O buffer for buf */
+	u32			iobaddr;/* physical addr of iob data */
+};
+
+/*
+ * Data transmit queue state.  One of these exists for each
+ * hardware transmit queue.  Packets sent to us from above
+ * are assigned to queues based on their priority.  Not all
+ * devices support a complete set of hardware transmit queues.
+ * For those devices the array sc_ac2q will map multiple
+ * priorities to fewer hardware queues (typically all to one
+ * hardware queue).
+ */
+struct ath5k_txq {
+	unsigned int		qnum;	/* hardware q number */
+	u32			*link;	/* link ptr in last TX desc */
+	struct list_head	q;	/* transmit queue */
+	int			setup;
+};
+
+#if CHAN_DEBUG
+#define ATH_CHAN_MAX	(26+26+26+200+200)
+#else
+#define ATH_CHAN_MAX	(14+14+14+252+20)
+#endif
+
+/* Software Carrier, keeps track of the driver state
+ * associated with an instance of a device */
+struct ath5k_softc {
+	struct pci_device	*pdev;		/* for dma mapping */
+	void			*iobase;	/* address of the device */
+	struct net80211_device	*dev;		/* IEEE 802.11 common */
+	struct ath5k_hw		*ah;		/* Atheros HW */
+	struct net80211_hw_info	*hwinfo;
+	int			curband;
+	int			irq_ena; 	/* interrupts enabled */
+
+	struct ath5k_buf	*bufptr;	/* allocated buffer ptr */
+	struct ath5k_desc	*desc;		/* TX/RX descriptors */
+	u32			desc_daddr;	/* DMA (physical) address */
+	size_t			desc_len;	/* size of TX/RX descriptors */
+	u16			cachelsz;	/* cache line size */
+
+	int			status;
+#define ATH_STAT_INVALID	0x01		/* disable hardware accesses */
+#define ATH_STAT_MRRETRY	0x02		/* multi-rate retry support */
+#define ATH_STAT_PROMISC	0x04
+#define ATH_STAT_LEDSOFT	0x08		/* enable LED gpio status */
+#define ATH_STAT_STARTED	0x10		/* opened & irqs enabled */
+
+	unsigned int		filter_flags;	/* HW flags, AR5K_RX_FILTER_* */
+	unsigned int		curmode;	/* current phy mode */
+	struct net80211_channel	*curchan;	/* current h/w channel */
+
+	enum ath5k_int		imask;		/* interrupt mask copy */
+
+	u8			bssidmask[ETH_ALEN];
+
+	unsigned int		rxbufsize;	/* rx size based on mtu */
+	struct list_head	rxbuf;		/* receive buffer */
+	u32			*rxlink;	/* link ptr in last RX desc */
+
+	struct list_head	txbuf;		/* transmit buffer */
+	unsigned int		txbuf_len;	/* buf count in txbuf list */
+	struct ath5k_txq	txq;		/* tx queue */
+
+	struct {
+		u16 gpio;
+		unsigned polarity;
+	} rf_kill;
+
+	int			last_calib_ticks;
+
+	int 			power_level;	/* Requested tx power in dbm */
+	int			assoc;		/* assocate state */
+
+	int			hw_rate;	/* Hardware tx rate code */
+	int			hw_rtscts_rate;	/* Hardware rts/cts rate code */
+};
+
+#define ath5k_hw_hasbssidmask(_ah) \
+	(ath5k_hw_get_capability(_ah, AR5K_CAP_BSSIDMASK, 0, NULL) == 0)
+#define ath5k_hw_hasveol(_ah) \
+	(ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0)
+
+#endif
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/desc.h b/roms/ipxe/src/drivers/net/ath/ath5k/desc.h
new file mode 100644
index 0000000000000000000000000000000000000000..6e11b0d43d6bb8359c98e933c07069f6706b2f9c
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/desc.h
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * Internal RX/TX descriptor structures
+ * (rX: reserved fields possibily used by future versions of the ar5k chipset)
+ */
+
+/*
+ * common hardware RX control descriptor
+ */
+struct ath5k_hw_rx_ctl {
+	u32	rx_control_0; /* RX control word 0 */
+	u32	rx_control_1; /* RX control word 1 */
+} __attribute__ ((packed));
+
+/* RX control word 0 field/sflags */
+#define AR5K_DESC_RX_CTL0			0x00000000
+
+/* RX control word 1 fields/flags */
+#define AR5K_DESC_RX_CTL1_BUF_LEN		0x00000fff
+#define AR5K_DESC_RX_CTL1_INTREQ		0x00002000
+
+/*
+ * common hardware RX status descriptor
+ * 5210/11 and 5212 differ only in the flags defined below
+ */
+struct ath5k_hw_rx_status {
+	u32	rx_status_0; /* RX status word 0 */
+	u32	rx_status_1; /* RX status word 1 */
+} __attribute__ ((packed));
+
+/* 5210/5211 */
+/* RX status word 0 fields/flags */
+#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN		0x00000fff
+#define AR5K_5210_RX_DESC_STATUS0_MORE			0x00001000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE		0x00078000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S	15
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL	0x07f80000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	19
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA	0x38000000
+#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	27
+
+/* RX status word 1 fields/flags */
+#define AR5K_5210_RX_DESC_STATUS1_DONE			0x00000001
+#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
+#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR		0x00000004
+#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN		0x00000008
+#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000010
+#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR		0x000000e0
+#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S		5
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX		0x00007e00
+#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S		9
+#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x0fff8000
+#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	15
+#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS	0x10000000
+
+/* 5212 */
+/* RX status word 0 fields/flags */
+#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN		0x00000fff
+#define AR5K_5212_RX_DESC_STATUS0_MORE			0x00001000
+#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR	0x00002000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE		0x000f8000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S	15
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL	0x0ff00000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	20
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA	0xf0000000
+#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	28
+
+/* RX status word 1 fields/flags */
+#define AR5K_5212_RX_DESC_STATUS1_DONE			0x00000001
+#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
+#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR		0x00000004
+#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000008
+#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR		0x00000010
+#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR		0x00000020
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX		0x0000fe00
+#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S		9
+#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x7fff0000
+#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	16
+#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS	0x80000000
+
+/*
+ * common hardware RX error descriptor
+ */
+struct ath5k_hw_rx_error {
+	u32	rx_error_0; /* RX status word 0 */
+	u32	rx_error_1; /* RX status word 1 */
+} __attribute__ ((packed));
+
+/* RX error word 0 fields/flags */
+#define AR5K_RX_DESC_ERROR0			0x00000000
+
+/* RX error word 1 fields/flags */
+#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE	0x0000ff00
+#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S	8
+
+/* PHY Error codes */
+#define AR5K_DESC_RX_PHY_ERROR_NONE		0x00
+#define AR5K_DESC_RX_PHY_ERROR_TIMING		0x20
+#define AR5K_DESC_RX_PHY_ERROR_PARITY		0x40
+#define AR5K_DESC_RX_PHY_ERROR_RATE		0x60
+#define AR5K_DESC_RX_PHY_ERROR_LENGTH		0x80
+#define AR5K_DESC_RX_PHY_ERROR_64QAM		0xa0
+#define AR5K_DESC_RX_PHY_ERROR_SERVICE		0xc0
+#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR	0xe0
+
+/*
+ * 5210/5211 hardware 2-word TX control descriptor
+ */
+struct ath5k_hw_2w_tx_ctl {
+	u32	tx_control_0; /* TX control word 0 */
+	u32	tx_control_1; /* TX control word 1 */
+} __attribute__ ((packed));
+
+/* TX control word 0 fields/flags */
+#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
+#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN		0x0003f000 /*[5210 ?]*/
+#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S	12
+#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE		0x003c0000
+#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S	18
+#define AR5K_2W_TX_DESC_CTL0_RTSENA		0x00400000
+#define AR5K_2W_TX_DESC_CTL0_CLRDMASK		0x01000000
+#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET	0x00800000 /*[5210]*/
+#define AR5K_2W_TX_DESC_CTL0_VEOL		0x00800000 /*[5211]*/
+#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE		0x1c000000 /*[5210]*/
+#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S	26
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210	0x02000000
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211	0x1e000000
+
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT			\
+		(ah->ah_version == AR5K_AR5210 ?		\
+		AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 :	\
+		AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211)
+
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
+#define AR5K_2W_TX_DESC_CTL0_INTREQ		0x20000000
+#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
+
+/* TX control word 1 fields/flags */
+#define AR5K_2W_TX_DESC_CTL1_BUF_LEN		0x00000fff
+#define AR5K_2W_TX_DESC_CTL1_MORE		0x00001000
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210	0x0007e000
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211	0x000fe000
+
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX				\
+			(ah->ah_version == AR5K_AR5210 ?		\
+			AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 :	\
+			AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211)
+
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
+#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE		0x00700000 /*[5211]*/
+#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S	20
+#define AR5K_2W_TX_DESC_CTL1_NOACK		0x00800000 /*[5211]*/
+#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION	0xfff80000 /*[5210 ?]*/
+
+/* Frame types */
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL   0x00
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM     0x04
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL   0x08
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS     0x10
+
+/*
+ * 5212 hardware 4-word TX control descriptor
+ */
+struct ath5k_hw_4w_tx_ctl {
+	u32	tx_control_0; /* TX control word 0 */
+
+#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
+#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER		0x003f0000
+#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S	16
+#define AR5K_4W_TX_DESC_CTL0_RTSENA		0x00400000
+#define AR5K_4W_TX_DESC_CTL0_VEOL		0x00800000
+#define AR5K_4W_TX_DESC_CTL0_CLRDMASK		0x01000000
+#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT	0x1e000000
+#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
+#define AR5K_4W_TX_DESC_CTL0_INTREQ		0x20000000
+#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
+#define AR5K_4W_TX_DESC_CTL0_CTSENA		0x80000000
+
+	u32	tx_control_1; /* TX control word 1 */
+
+#define AR5K_4W_TX_DESC_CTL1_BUF_LEN		0x00000fff
+#define AR5K_4W_TX_DESC_CTL1_MORE		0x00001000
+#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX	0x000fe000
+#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
+#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE		0x00f00000
+#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S	20
+#define AR5K_4W_TX_DESC_CTL1_NOACK		0x01000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_PROC		0x06000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S	25
+#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN	0x18000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S	27
+#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN	0x60000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S	29
+
+	u32	tx_control_2; /* TX control word 2 */
+
+#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION		0x00007fff
+#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE	0x00008000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0		0x000f0000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S		16
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1		0x00f00000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S		20
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2		0x0f000000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S		24
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3		0xf0000000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S		28
+
+	u32	tx_control_3; /* TX control word 3 */
+
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0		0x0000001f
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1		0x000003e0
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S	5
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2		0x00007c00
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S	10
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3		0x000f8000
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S	15
+#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE	0x01f00000
+#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S	20
+} __attribute__ ((packed));
+
+/*
+ * Common TX status descriptor
+ */
+struct ath5k_hw_tx_status {
+	u32	tx_status_0; /* TX status word 0 */
+	u32	tx_status_1; /* TX status word 1 */
+} __attribute__ ((packed));
+
+/* TX status word 0 fields/flags */
+#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK	0x00000001
+#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES	0x00000002
+#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN	0x00000004
+#define AR5K_DESC_TX_STATUS0_FILTERED		0x00000008
+/*???
+#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT	0x000000f0
+#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S	4
+*/
+#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT	0x000000f0
+#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S	4
+/*???
+#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT	0x00000f00
+#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S	8
+*/
+#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT	0x00000f00
+#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S	8
+#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT	0x0000f000
+#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S	12
+#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP	0xffff0000
+#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S	16
+
+/* TX status word 1 fields/flags */
+#define AR5K_DESC_TX_STATUS1_DONE		0x00000001
+#define AR5K_DESC_TX_STATUS1_SEQ_NUM		0x00001ffe
+#define AR5K_DESC_TX_STATUS1_SEQ_NUM_S		1
+#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH	0x001fe000
+#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S	13
+#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX	0x00600000
+#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S	21
+#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS	0x00800000
+#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA	0x01000000
+
+/*
+ * 5210/5211 hardware TX descriptor
+ */
+struct ath5k_hw_5210_tx_desc {
+	struct ath5k_hw_2w_tx_ctl	tx_ctl;
+	struct ath5k_hw_tx_status	tx_stat;
+} __attribute__ ((packed));
+
+/*
+ * 5212 hardware TX descriptor
+ */
+struct ath5k_hw_5212_tx_desc {
+	struct ath5k_hw_4w_tx_ctl	tx_ctl;
+	struct ath5k_hw_tx_status	tx_stat;
+} __attribute__ ((packed));
+
+/*
+ * common hardware RX descriptor
+ */
+struct ath5k_hw_all_rx_desc {
+	struct ath5k_hw_rx_ctl			rx_ctl;
+	union {
+		struct ath5k_hw_rx_status	rx_stat;
+		struct ath5k_hw_rx_error	rx_err;
+	} u;
+} __attribute__ ((packed));
+
+/*
+ * Atheros hardware descriptor
+ * This is read and written to by the hardware
+ */
+struct ath5k_desc {
+	u32	ds_link;	/* physical address of the next descriptor */
+	u32	ds_data;	/* physical address of data buffer (skb) */
+
+	union {
+		struct ath5k_hw_5210_tx_desc	ds_tx5210;
+		struct ath5k_hw_5212_tx_desc	ds_tx5212;
+		struct ath5k_hw_all_rx_desc	ds_rx;
+	} ud;
+} __attribute__ ((packed));
+
+#define AR5K_RXDESC_INTREQ	0x0020
+
+#define AR5K_TXDESC_CLRDMASK	0x0001
+#define AR5K_TXDESC_NOACK	0x0002	/*[5211+]*/
+#define AR5K_TXDESC_RTSENA	0x0004
+#define AR5K_TXDESC_CTSENA	0x0008
+#define AR5K_TXDESC_INTREQ	0x0010
+#define AR5K_TXDESC_VEOL	0x0020	/*[5211+]*/
+
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/eeprom.h b/roms/ipxe/src/drivers/net/ath/ath5k/eeprom.h
new file mode 100644
index 0000000000000000000000000000000000000000..da454339390e039c0ee31c33815d5d359793e4a5
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/eeprom.h
@@ -0,0 +1,451 @@
+/*
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
+ */
+#define AR5K_EEPROM_MAGIC		0x003d	/* EEPROM Magic number */
+#define AR5K_EEPROM_MAGIC_VALUE		0x5aa5	/* Default - found on EEPROM */
+#define AR5K_EEPROM_MAGIC_5212		0x0000145c /* 5212 */
+#define AR5K_EEPROM_MAGIC_5211		0x0000145b /* 5211 */
+#define AR5K_EEPROM_MAGIC_5210		0x0000145a /* 5210 */
+
+#define	AR5K_EEPROM_IS_HB63		0x000b	/* Talon detect */
+
+#define AR5K_EEPROM_RFKILL		0x0f
+#define AR5K_EEPROM_RFKILL_GPIO_SEL	0x0000001c
+#define AR5K_EEPROM_RFKILL_GPIO_SEL_S	2
+#define AR5K_EEPROM_RFKILL_POLARITY	0x00000002
+#define AR5K_EEPROM_RFKILL_POLARITY_S	1
+
+#define AR5K_EEPROM_REG_DOMAIN		0x00bf	/* EEPROM regdom */
+#define AR5K_EEPROM_CHECKSUM		0x00c0	/* EEPROM checksum */
+#define AR5K_EEPROM_INFO_BASE		0x00c0	/* EEPROM header */
+#define AR5K_EEPROM_INFO_MAX		(0x400 - AR5K_EEPROM_INFO_BASE)
+#define AR5K_EEPROM_INFO_CKSUM		0xffff
+#define AR5K_EEPROM_INFO(_n)		(AR5K_EEPROM_INFO_BASE + (_n))
+
+#define AR5K_EEPROM_VERSION		AR5K_EEPROM_INFO(1)	/* EEPROM Version */
+#define AR5K_EEPROM_VERSION_3_0		0x3000	/* No idea what's going on before this version */
+#define AR5K_EEPROM_VERSION_3_1		0x3001	/* ob/db values for 2Ghz (ar5211_rfregs) */
+#define AR5K_EEPROM_VERSION_3_2		0x3002	/* different frequency representation (eeprom_bin2freq) */
+#define AR5K_EEPROM_VERSION_3_3		0x3003	/* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
+#define AR5K_EEPROM_VERSION_3_4		0x3004	/* has ee_i_gain, ee_cck_ofdm_power_delta (eeprom_read_modes) */
+#define AR5K_EEPROM_VERSION_4_0		0x4000	/* has ee_misc, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_1		0x4001	/* has ee_margin_tx_rx (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_2		0x4002	/* has ee_cck_ofdm_gain_delta (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_3		0x4003	/* power calibration changes */
+#define AR5K_EEPROM_VERSION_4_4		0x4004
+#define AR5K_EEPROM_VERSION_4_5		0x4005
+#define AR5K_EEPROM_VERSION_4_6		0x4006	/* has ee_scaled_cck_delta */
+#define AR5K_EEPROM_VERSION_4_7		0x3007	/* 4007 ? */
+#define AR5K_EEPROM_VERSION_4_9		0x4009	/* EAR futureproofing */
+#define AR5K_EEPROM_VERSION_5_0		0x5000	/* Has 2413 PDADC calibration etc */
+#define AR5K_EEPROM_VERSION_5_1		0x5001	/* Has capability values */
+#define AR5K_EEPROM_VERSION_5_3		0x5003	/* Has spur mitigation tables */
+
+#define AR5K_EEPROM_MODE_11A		0
+#define AR5K_EEPROM_MODE_11B		1
+#define AR5K_EEPROM_MODE_11G		2
+
+#define AR5K_EEPROM_HDR			AR5K_EEPROM_INFO(2)	/* Header that contains the device caps */
+#define AR5K_EEPROM_HDR_11A(_v)		(((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
+#define AR5K_EEPROM_HDR_11B(_v)		(((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
+#define AR5K_EEPROM_HDR_11G(_v)		(((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
+#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v)	(((_v) >> 3) & 0x1)	/* Disable turbo for 2Ghz (?) */
+#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v)	(((_v) >> 4) & 0x7f)	/* Max turbo power for a/XR mode (eeprom_init) */
+#define AR5K_EEPROM_HDR_DEVICE(_v)	(((_v) >> 11) & 0x7)
+#define AR5K_EEPROM_HDR_RFKILL(_v)	(((_v) >> 14) & 0x1)	/* Device has RFKill support */
+#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v)	(((_v) >> 15) & 0x1)	/* Disable turbo for 5Ghz */
+
+#define AR5K_EEPROM_RFKILL_GPIO_SEL	0x0000001c
+#define AR5K_EEPROM_RFKILL_GPIO_SEL_S	2
+#define AR5K_EEPROM_RFKILL_POLARITY	0x00000002
+#define AR5K_EEPROM_RFKILL_POLARITY_S	1
+
+/* Newer EEPROMs are using a different offset */
+#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
+	(((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
+
+#define AR5K_EEPROM_ANT_GAIN(_v)	AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
+#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v)	((s8)(((_v) >> 8) & 0xff))
+#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v)	((s8)((_v) & 0xff))
+
+/* Misc values available since EEPROM 4.0 */
+#define AR5K_EEPROM_MISC0		AR5K_EEPROM_INFO(4)
+#define AR5K_EEPROM_EARSTART(_v)	((_v) & 0xfff)
+#define AR5K_EEPROM_HDR_XR2_DIS(_v)	(((_v) >> 12) & 0x1)
+#define AR5K_EEPROM_HDR_XR5_DIS(_v)	(((_v) >> 13) & 0x1)
+#define AR5K_EEPROM_EEMAP(_v)		(((_v) >> 14) & 0x3)
+
+#define AR5K_EEPROM_MISC1			AR5K_EEPROM_INFO(5)
+#define AR5K_EEPROM_TARGET_PWRSTART(_v)		((_v) & 0xfff)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)		(((_v) >> 14) & 0x1)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(_v)	(((_v) >> 15) & 0x1)
+
+#define AR5K_EEPROM_MISC2			AR5K_EEPROM_INFO(6)
+#define AR5K_EEPROM_EEP_FILE_VERSION(_v)	(((_v) >> 8) & 0xff)
+#define AR5K_EEPROM_EAR_FILE_VERSION(_v)	((_v) & 0xff)
+
+#define AR5K_EEPROM_MISC3		AR5K_EEPROM_INFO(7)
+#define AR5K_EEPROM_ART_BUILD_NUM(_v)	(((_v) >> 10) & 0x3f)
+#define AR5K_EEPROM_EAR_FILE_ID(_v)	((_v) & 0xff)
+
+#define AR5K_EEPROM_MISC4		AR5K_EEPROM_INFO(8)
+#define AR5K_EEPROM_CAL_DATA_START(_v)	(((_v) >> 4) & 0xfff)
+#define AR5K_EEPROM_MASK_R0(_v)		(((_v) >> 2) & 0x3)
+#define AR5K_EEPROM_MASK_R1(_v)		((_v) & 0x3)
+
+#define AR5K_EEPROM_MISC5		AR5K_EEPROM_INFO(9)
+#define AR5K_EEPROM_COMP_DIS(_v)	((_v) & 0x1)
+#define AR5K_EEPROM_AES_DIS(_v)		(((_v) >> 1) & 0x1)
+#define AR5K_EEPROM_FF_DIS(_v)		(((_v) >> 2) & 0x1)
+#define AR5K_EEPROM_BURST_DIS(_v)	(((_v) >> 3) & 0x1)
+#define AR5K_EEPROM_MAX_QCU(_v)		(((_v) >> 4) & 0xf)
+#define AR5K_EEPROM_HEAVY_CLIP_EN(_v)	(((_v) >> 8) & 0x1)
+#define AR5K_EEPROM_KEY_CACHE_SIZE(_v)	(((_v) >> 12) & 0xf)
+
+#define AR5K_EEPROM_MISC6		AR5K_EEPROM_INFO(10)
+#define AR5K_EEPROM_TX_CHAIN_DIS	((_v) & 0x8)
+#define AR5K_EEPROM_RX_CHAIN_DIS	(((_v) >> 3) & 0x8)
+#define AR5K_EEPROM_FCC_MID_EN		(((_v) >> 6) & 0x1)
+#define AR5K_EEPROM_JAP_U1EVEN_EN	(((_v) >> 7) & 0x1)
+#define AR5K_EEPROM_JAP_U2_EN		(((_v) >> 8) & 0x1)
+#define AR5K_EEPROM_JAP_U1ODD_EN	(((_v) >> 9) & 0x1)
+#define AR5K_EEPROM_JAP_11A_NEW_EN	(((_v) >> 10) & 0x1)
+
+/* calibration settings */
+#define AR5K_EEPROM_MODES_11A(_v)	AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
+#define AR5K_EEPROM_MODES_11B(_v)	AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
+#define AR5K_EEPROM_MODES_11G(_v)	AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
+#define AR5K_EEPROM_CTL(_v)		AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128)	/* Conformance test limits */
+#define AR5K_EEPROM_GROUPS_START(_v)	AR5K_EEPROM_OFF(_v, 0x0100, 0x0150)	/* Start of Groups */
+#define AR5K_EEPROM_GROUP1_OFFSET	0x0
+#define AR5K_EEPROM_GROUP2_OFFSET	0x5
+#define AR5K_EEPROM_GROUP3_OFFSET	0x37
+#define AR5K_EEPROM_GROUP4_OFFSET	0x46
+#define AR5K_EEPROM_GROUP5_OFFSET	0x55
+#define AR5K_EEPROM_GROUP6_OFFSET	0x65
+#define AR5K_EEPROM_GROUP7_OFFSET	0x69
+#define AR5K_EEPROM_GROUP8_OFFSET	0x6f
+
+#define AR5K_EEPROM_TARGET_PWR_OFF_11A(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+								AR5K_EEPROM_GROUP5_OFFSET, 0x0000)
+#define AR5K_EEPROM_TARGET_PWR_OFF_11B(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+								AR5K_EEPROM_GROUP6_OFFSET, 0x0010)
+#define AR5K_EEPROM_TARGET_PWR_OFF_11G(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
+								AR5K_EEPROM_GROUP7_OFFSET, 0x0014)
+
+/* [3.1 - 3.3] */
+#define AR5K_EEPROM_OBDB0_2GHZ		0x00ec
+#define AR5K_EEPROM_OBDB1_2GHZ		0x00ed
+
+#define AR5K_EEPROM_PROTECT		0x003f	/* EEPROM protect status */
+#define AR5K_EEPROM_PROTECT_RD_0_31	0x0001	/* Read protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_WR_0_31	0x0002	/* Write protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_RD_32_63	0x0004	/* 0x20 - 0x3f */
+#define AR5K_EEPROM_PROTECT_WR_32_63	0x0008
+#define AR5K_EEPROM_PROTECT_RD_64_127	0x0010	/* 0x40 - 0x7f */
+#define AR5K_EEPROM_PROTECT_WR_64_127	0x0020
+#define AR5K_EEPROM_PROTECT_RD_128_191	0x0040	/* 0x80 - 0xbf (regdom) */
+#define AR5K_EEPROM_PROTECT_WR_128_191	0x0080
+#define AR5K_EEPROM_PROTECT_RD_192_207	0x0100	/* 0xc0 - 0xcf */
+#define AR5K_EEPROM_PROTECT_WR_192_207	0x0200
+#define AR5K_EEPROM_PROTECT_RD_208_223	0x0400	/* 0xd0 - 0xdf */
+#define AR5K_EEPROM_PROTECT_WR_208_223	0x0800
+#define AR5K_EEPROM_PROTECT_RD_224_239	0x1000	/* 0xe0 - 0xef */
+#define AR5K_EEPROM_PROTECT_WR_224_239	0x2000
+#define AR5K_EEPROM_PROTECT_RD_240_255	0x4000	/* 0xf0 - 0xff */
+#define AR5K_EEPROM_PROTECT_WR_240_255	0x8000
+
+/* Some EEPROM defines */
+#define AR5K_EEPROM_EEP_SCALE		100
+#define AR5K_EEPROM_EEP_DELTA		10
+#define AR5K_EEPROM_N_MODES		3
+#define AR5K_EEPROM_N_5GHZ_CHAN		10
+#define AR5K_EEPROM_N_2GHZ_CHAN		3
+#define AR5K_EEPROM_N_2GHZ_CHAN_2413	4
+#define	AR5K_EEPROM_N_2GHZ_CHAN_MAX	4
+#define AR5K_EEPROM_MAX_CHAN		10
+#define AR5K_EEPROM_N_PWR_POINTS_5111	11
+#define AR5K_EEPROM_N_PCDAC		11
+#define AR5K_EEPROM_N_PHASE_CAL		5
+#define AR5K_EEPROM_N_TEST_FREQ		8
+#define AR5K_EEPROM_N_EDGES		8
+#define AR5K_EEPROM_N_INTERCEPTS	11
+#define AR5K_EEPROM_FREQ_M(_v)		AR5K_EEPROM_OFF(_v, 0x7f, 0xff)
+#define AR5K_EEPROM_PCDAC_M		0x3f
+#define AR5K_EEPROM_PCDAC_START		1
+#define AR5K_EEPROM_PCDAC_STOP		63
+#define AR5K_EEPROM_PCDAC_STEP		1
+#define AR5K_EEPROM_NON_EDGE_M		0x40
+#define AR5K_EEPROM_CHANNEL_POWER	8
+#define AR5K_EEPROM_N_OBDB		4
+#define AR5K_EEPROM_OBDB_DIS		0xffff
+#define AR5K_EEPROM_CHANNEL_DIS		0xff
+#define AR5K_EEPROM_SCALE_OC_DELTA(_x)	(((_x) * 2) / 10)
+#define AR5K_EEPROM_N_CTLS(_v)		AR5K_EEPROM_OFF(_v, 16, 32)
+#define AR5K_EEPROM_MAX_CTLS		32
+#define AR5K_EEPROM_N_PD_CURVES		4
+#define AR5K_EEPROM_N_XPD0_POINTS	4
+#define AR5K_EEPROM_N_XPD3_POINTS	3
+#define AR5K_EEPROM_N_PD_GAINS		4
+#define AR5K_EEPROM_N_PD_POINTS		5
+#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ	35
+#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ	55
+#define AR5K_EEPROM_POWER_M		0x3f
+#define AR5K_EEPROM_POWER_MIN		0
+#define AR5K_EEPROM_POWER_MAX		3150
+#define AR5K_EEPROM_POWER_STEP		50
+#define AR5K_EEPROM_POWER_TABLE_SIZE	64
+#define AR5K_EEPROM_N_POWER_LOC_11B	4
+#define AR5K_EEPROM_N_POWER_LOC_11G	6
+#define AR5K_EEPROM_I_GAIN		10
+#define AR5K_EEPROM_CCK_OFDM_DELTA	15
+#define AR5K_EEPROM_N_IQ_CAL		2
+
+#define AR5K_EEPROM_READ(_o, _v) do {			\
+	ret = ath5k_hw_eeprom_read(ah, (_o), &(_v));	\
+	if (ret)					\
+		return ret;				\
+} while (0)
+
+#define AR5K_EEPROM_READ_HDR(_o, _v)					\
+	AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v);	\
+
+enum ath5k_ant_setting {
+	AR5K_ANT_VARIABLE	= 0,	/* variable by programming */
+	AR5K_ANT_FIXED_A	= 1,	/* fixed to 11a frequencies */
+	AR5K_ANT_FIXED_B	= 2,	/* fixed to 11b frequencies */
+	AR5K_ANT_MAX		= 3,
+};
+
+enum ath5k_ctl_mode {
+	AR5K_CTL_11A = 0,
+	AR5K_CTL_11B = 1,
+	AR5K_CTL_11G = 2,
+	AR5K_CTL_TURBO = 3,
+	AR5K_CTL_TURBOG = 4,
+	AR5K_CTL_2GHT20 = 5,
+	AR5K_CTL_5GHT20 = 6,
+	AR5K_CTL_2GHT40 = 7,
+	AR5K_CTL_5GHT40 = 8,
+	AR5K_CTL_MODE_M = 15,
+};
+
+/* Default CTL ids for the 3 main reg domains.
+ * Atheros only uses these by default but vendors
+ * can have up to 32 different CTLs for different
+ * scenarios. Note that theese values are ORed with
+ * the mode id (above) so we can have up to 24 CTL
+ * datasets out of these 3 main regdomains. That leaves
+ * 8 ids that can be used by vendors and since 0x20 is
+ * missing from HAL sources i guess this is the set of
+ * custom CTLs vendors can use. */
+#define	AR5K_CTL_FCC	0x10
+#define	AR5K_CTL_CUSTOM	0x20
+#define	AR5K_CTL_ETSI	0x30
+#define	AR5K_CTL_MKK	0x40
+
+/* Indicates a CTL with only mode set and
+ * no reg domain mapping, such CTLs are used
+ * for world roaming domains or simply when
+ * a reg domain is not set */
+#define	AR5K_CTL_NO_REGDOMAIN	0xf0
+
+/* Indicates an empty (invalid) CTL */
+#define AR5K_CTL_NO_CTL		0xff
+
+/* Per channel calibration data, used for power table setup */
+struct ath5k_chan_pcal_info_rf5111 {
+	/* Power levels in half dbm units
+	 * for one power curve. */
+	u8 pwr[AR5K_EEPROM_N_PWR_POINTS_5111];
+	/* PCDAC table steps
+	 * for the above values */
+	u8 pcdac[AR5K_EEPROM_N_PWR_POINTS_5111];
+	/* Starting PCDAC step */
+	u8 pcdac_min;
+	/* Final PCDAC step */
+	u8 pcdac_max;
+};
+
+struct ath5k_chan_pcal_info_rf5112 {
+	/* Power levels in quarter dBm units
+	 * for lower (0) and higher (3)
+	 * level curves in 0.25dB units */
+	s8 pwr_x0[AR5K_EEPROM_N_XPD0_POINTS];
+	s8 pwr_x3[AR5K_EEPROM_N_XPD3_POINTS];
+	/* PCDAC table steps
+	 * for the above values */
+	u8 pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS];
+	u8 pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS];
+};
+
+struct ath5k_chan_pcal_info_rf2413 {
+	/* Starting pwr/pddac values */
+	s8 pwr_i[AR5K_EEPROM_N_PD_GAINS];
+	u8 pddac_i[AR5K_EEPROM_N_PD_GAINS];
+	/* (pwr,pddac) points
+	 * power levels in 0.5dB units */
+	s8 pwr[AR5K_EEPROM_N_PD_GAINS]
+		[AR5K_EEPROM_N_PD_POINTS];
+	u8 pddac[AR5K_EEPROM_N_PD_GAINS]
+		[AR5K_EEPROM_N_PD_POINTS];
+};
+
+enum ath5k_powertable_type {
+	AR5K_PWRTABLE_PWR_TO_PCDAC = 0,
+	AR5K_PWRTABLE_LINEAR_PCDAC = 1,
+	AR5K_PWRTABLE_PWR_TO_PDADC = 2,
+};
+
+struct ath5k_pdgain_info {
+	u8 pd_points;
+	u8 *pd_step;
+	/* Power values are in
+	 * 0.25dB units */
+	s16 *pd_pwr;
+};
+
+struct ath5k_chan_pcal_info {
+	/* Frequency */
+	u16	freq;
+	/* Tx power boundaries */
+	s16	max_pwr;
+	s16	min_pwr;
+	union {
+		struct ath5k_chan_pcal_info_rf5111 rf5111_info;
+		struct ath5k_chan_pcal_info_rf5112 rf5112_info;
+		struct ath5k_chan_pcal_info_rf2413 rf2413_info;
+	};
+	/* Raw values used by phy code
+	 * Curves are stored in order from lower
+	 * gain to higher gain (max txpower -> min txpower) */
+	struct ath5k_pdgain_info *pd_curves;
+};
+
+/* Per rate calibration data for each mode,
+ * used for rate power table setup.
+ * Note: Values in 0.5dB units */
+struct ath5k_rate_pcal_info {
+	u16	freq; /* Frequency */
+	/* Power level for 6-24Mbit/s rates or
+	 * 1Mb rate */
+	u16	target_power_6to24;
+	/* Power level for 36Mbit rate or
+	 * 2Mb rate */
+	u16	target_power_36;
+	/* Power level for 48Mbit rate or
+	 * 5.5Mbit rate */
+	u16	target_power_48;
+	/* Power level for 54Mbit rate or
+	 * 11Mbit rate */
+	u16	target_power_54;
+};
+
+/* Power edges for conformance test limits */
+struct ath5k_edge_power {
+	u16 freq;
+	u16 edge; /* in half dBm */
+	int flag;
+};
+
+/* EEPROM calibration data */
+struct ath5k_eeprom_info {
+
+	/* Header information */
+	u16	ee_magic;
+	u16	ee_protect;
+	u16	ee_regdomain;
+	u16	ee_version;
+	u16	ee_header;
+	u16	ee_ant_gain;
+	u8	ee_rfkill_pin;
+	int	ee_rfkill_pol;
+	int	ee_is_hb63;
+	u16	ee_misc0;
+	u16	ee_misc1;
+	u16	ee_misc2;
+	u16	ee_misc3;
+	u16	ee_misc4;
+	u16	ee_misc5;
+	u16	ee_misc6;
+	u16	ee_cck_ofdm_gain_delta;
+	u16	ee_cck_ofdm_power_delta;
+	u16	ee_scaled_cck_delta;
+
+	/* RF Calibration settings (reset, rfregs) */
+	u16	ee_i_cal[AR5K_EEPROM_N_MODES];
+	u16	ee_q_cal[AR5K_EEPROM_N_MODES];
+	u16	ee_fixed_bias[AR5K_EEPROM_N_MODES];
+	u16	ee_turbo_max_power[AR5K_EEPROM_N_MODES];
+	u16	ee_xr_power[AR5K_EEPROM_N_MODES];
+	u16	ee_switch_settling[AR5K_EEPROM_N_MODES];
+	u16	ee_atn_tx_rx[AR5K_EEPROM_N_MODES];
+	u16	ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
+	u16	ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
+	u16	ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
+	u16	ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES];
+	u16	ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES];
+	u16	ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES];
+	u16	ee_thr_62[AR5K_EEPROM_N_MODES];
+	u16	ee_xlna_gain[AR5K_EEPROM_N_MODES];
+	u16	ee_xpd[AR5K_EEPROM_N_MODES];
+	u16	ee_x_gain[AR5K_EEPROM_N_MODES];
+	u16	ee_i_gain[AR5K_EEPROM_N_MODES];
+	u16	ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
+	u16	ee_switch_settling_turbo[AR5K_EEPROM_N_MODES];
+	u16	ee_margin_tx_rx_turbo[AR5K_EEPROM_N_MODES];
+	u16	ee_atn_tx_rx_turbo[AR5K_EEPROM_N_MODES];
+
+	/* Power calibration data */
+	u16	ee_false_detect[AR5K_EEPROM_N_MODES];
+
+	/* Number of pd gain curves per mode */
+	u8	ee_pd_gains[AR5K_EEPROM_N_MODES];
+	/* Back mapping pdcurve number -> pdcurve index in pd->pd_curves */
+	u8	ee_pdc_to_idx[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PD_GAINS];
+
+	u8	ee_n_piers[AR5K_EEPROM_N_MODES];
+	struct ath5k_chan_pcal_info	ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN];
+	struct ath5k_chan_pcal_info	ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
+	struct ath5k_chan_pcal_info	ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
+
+	/* Per rate target power levels */
+	u8	ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES];
+	struct ath5k_rate_pcal_info	ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN];
+	struct ath5k_rate_pcal_info	ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
+	struct ath5k_rate_pcal_info	ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
+
+	/* Conformance test limits (Unused) */
+	u8	ee_ctls;
+	u8	ee_ctl[AR5K_EEPROM_MAX_CTLS];
+	struct ath5k_edge_power ee_ctl_pwr[AR5K_EEPROM_N_EDGES * AR5K_EEPROM_MAX_CTLS];
+
+	/* Noise Floor Calibration settings */
+	s16	ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
+	s8	ee_adc_desired_size[AR5K_EEPROM_N_MODES];
+	s8	ee_pga_desired_size[AR5K_EEPROM_N_MODES];
+	s8	ee_adc_desired_size_turbo[AR5K_EEPROM_N_MODES];
+	s8	ee_pga_desired_size_turbo[AR5K_EEPROM_N_MODES];
+	s8	ee_pd_gain_overlap;
+
+	u32	ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
+};
+
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/reg.h b/roms/ipxe/src/drivers/net/ath/ath5k/reg.h
new file mode 100644
index 0000000000000000000000000000000000000000..7070d1543cdc54359107b72ffe7032dbe16cf327
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/reg.h
@@ -0,0 +1,2589 @@
+/*
+ * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2007-2008 Michael Taylor <mike.taylor@apprion.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * Register values for Atheros 5210/5211/5212 cards from OpenBSD's ar5k
+ * maintained by Reyk Floeter
+ *
+ * I tried to document those registers by looking at ar5k code, some
+ * 802.11 (802.11e mostly) papers and by reading various public available
+ * Atheros presentations and papers like these:
+ *
+ * 5210 - http://nova.stanford.edu/~bbaas/ps/isscc2002_slides.pdf
+ *        http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf
+ *
+ * 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf
+ *
+ * This file also contains register values found on a memory dump of
+ * Atheros's ART program (Atheros Radio Test), on ath9k, on legacy-hal
+ * released by Atheros and on various debug messages found on the net.
+ */
+
+
+
+/*====MAC DMA REGISTERS====*/
+
+/*
+ * AR5210-Specific TXDP registers
+ * 5210 has only 2 transmit queues so no DCU/QCU, just
+ * 2 transmit descriptor pointers...
+ */
+#define AR5K_NOQCU_TXDP0	0x0000		/* Queue 0 - data */
+#define AR5K_NOQCU_TXDP1	0x0004		/* Queue 1 - beacons */
+
+/*
+ * Mac Control Register
+ */
+#define	AR5K_CR		0x0008			/* Register Address */
+#define AR5K_CR_TXE0	0x00000001	/* TX Enable for queue 0 on 5210 */
+#define AR5K_CR_TXE1	0x00000002	/* TX Enable for queue 1 on 5210 */
+#define	AR5K_CR_RXE	0x00000004	/* RX Enable */
+#define AR5K_CR_TXD0	0x00000008	/* TX Disable for queue 0 on 5210 */
+#define AR5K_CR_TXD1	0x00000010	/* TX Disable for queue 1 on 5210 */
+#define	AR5K_CR_RXD	0x00000020	/* RX Disable */
+#define	AR5K_CR_SWI	0x00000040	/* Software Interrupt */
+
+/*
+ * RX Descriptor Pointer register
+ */
+#define	AR5K_RXDP	0x000c
+
+/*
+ * Configuration and status register
+ */
+#define	AR5K_CFG		0x0014			/* Register Address */
+#define	AR5K_CFG_SWTD		0x00000001	/* Byte-swap TX descriptor (for big endian archs) */
+#define	AR5K_CFG_SWTB		0x00000002	/* Byte-swap TX buffer */
+#define	AR5K_CFG_SWRD		0x00000004	/* Byte-swap RX descriptor */
+#define	AR5K_CFG_SWRB		0x00000008	/* Byte-swap RX buffer */
+#define	AR5K_CFG_SWRG		0x00000010	/* Byte-swap Register access */
+#define AR5K_CFG_IBSS		0x00000020 	/* 0-BSS, 1-IBSS [5211+] */
+#define AR5K_CFG_PHY_OK		0x00000100	/* [5211+] */
+#define AR5K_CFG_EEBS		0x00000200	/* EEPROM is busy */
+#define	AR5K_CFG_CLKGD		0x00000400	/* Clock gated (Disable dynamic clock) */
+#define AR5K_CFG_TXCNT		0x00007800	/* Tx frame count (?) [5210] */
+#define AR5K_CFG_TXCNT_S	11
+#define AR5K_CFG_TXFSTAT	0x00008000	/* Tx frame status (?) [5210] */
+#define AR5K_CFG_TXFSTRT	0x00010000	/* [5210] */
+#define	AR5K_CFG_PCI_THRES	0x00060000	/* PCI Master req q threshold [5211+] */
+#define	AR5K_CFG_PCI_THRES_S	17
+
+/*
+ * Interrupt enable register
+ */
+#define AR5K_IER		0x0024		/* Register Address */
+#define AR5K_IER_DISABLE	0x00000000	/* Disable card interrupts */
+#define AR5K_IER_ENABLE		0x00000001	/* Enable card interrupts */
+
+
+/*
+ * 0x0028 is Beacon Control Register on 5210
+ * and first RTS duration register on 5211
+ */
+
+/*
+ * Beacon control register [5210]
+ */
+#define AR5K_BCR		0x0028		/* Register Address */
+#define AR5K_BCR_AP		0x00000000	/* AP mode */
+#define AR5K_BCR_ADHOC		0x00000001	/* Ad-Hoc mode */
+#define AR5K_BCR_BDMAE		0x00000002	/* DMA enable */
+#define AR5K_BCR_TQ1FV		0x00000004	/* Use Queue1 for CAB traffic */
+#define AR5K_BCR_TQ1V		0x00000008	/* Use Queue1 for Beacon traffic */
+#define AR5K_BCR_BCGET		0x00000010
+
+/*
+ * First RTS duration register [5211]
+ */
+#define AR5K_RTSD0		0x0028		/* Register Address */
+#define	AR5K_RTSD0_6		0x000000ff	/* 6Mb RTS duration mask (?) */
+#define	AR5K_RTSD0_6_S		0		/* 6Mb RTS duration shift (?) */
+#define	AR5K_RTSD0_9		0x0000ff00	/* 9Mb*/
+#define	AR5K_RTSD0_9_S		8
+#define	AR5K_RTSD0_12		0x00ff0000	/* 12Mb*/
+#define	AR5K_RTSD0_12_S		16
+#define	AR5K_RTSD0_18		0xff000000	/* 16Mb*/
+#define	AR5K_RTSD0_18_S		24
+
+
+/*
+ * 0x002c is Beacon Status Register on 5210
+ * and second RTS duration register on 5211
+ */
+
+/*
+ * Beacon status register [5210]
+ *
+ * As i can see in ar5k_ar5210_tx_start Reyk uses some of the values of BCR
+ * for this register, so i guess TQ1V,TQ1FV and BDMAE have the same meaning
+ * here and SNP/SNAP means "snapshot" (so this register gets synced with BCR).
+ * So SNAPPEDBCRVALID sould also stand for "snapped BCR -values- valid", so i
+ * renamed it to SNAPSHOTSVALID to make more sense. I realy have no idea what
+ * else can it be. I also renamed SNPBCMD to SNPADHOC to match BCR.
+ */
+#define AR5K_BSR		0x002c			/* Register Address */
+#define AR5K_BSR_BDLYSW		0x00000001	/* SW Beacon delay (?) */
+#define AR5K_BSR_BDLYDMA	0x00000002	/* DMA Beacon delay (?) */
+#define AR5K_BSR_TXQ1F		0x00000004	/* Beacon queue (1) finished */
+#define AR5K_BSR_ATIMDLY	0x00000008	/* ATIM delay (?) */
+#define AR5K_BSR_SNPADHOC	0x00000100	/* Ad-hoc mode set (?) */
+#define AR5K_BSR_SNPBDMAE	0x00000200	/* Beacon DMA enabled (?) */
+#define AR5K_BSR_SNPTQ1FV	0x00000400	/* Queue1 is used for CAB traffic (?) */
+#define AR5K_BSR_SNPTQ1V	0x00000800	/* Queue1 is used for Beacon traffic (?) */
+#define AR5K_BSR_SNAPSHOTSVALID	0x00001000	/* BCR snapshots are valid (?) */
+#define AR5K_BSR_SWBA_CNT	0x00ff0000
+
+/*
+ * Second RTS duration register [5211]
+ */
+#define AR5K_RTSD1		0x002c			/* Register Address */
+#define	AR5K_RTSD1_24		0x000000ff	/* 24Mb */
+#define	AR5K_RTSD1_24_S		0
+#define	AR5K_RTSD1_36		0x0000ff00	/* 36Mb */
+#define	AR5K_RTSD1_36_S		8
+#define	AR5K_RTSD1_48		0x00ff0000	/* 48Mb */
+#define	AR5K_RTSD1_48_S		16
+#define	AR5K_RTSD1_54		0xff000000	/* 54Mb */
+#define	AR5K_RTSD1_54_S		24
+
+
+/*
+ * Transmit configuration register
+ */
+#define AR5K_TXCFG			0x0030			/* Register Address */
+#define AR5K_TXCFG_SDMAMR		0x00000007	/* DMA size (read) */
+#define AR5K_TXCFG_SDMAMR_S		0
+#define AR5K_TXCFG_B_MODE		0x00000008	/* Set b mode for 5111 (enable 2111) */
+#define AR5K_TXCFG_TXFSTP		0x00000008	/* TX DMA full Stop [5210] */
+#define AR5K_TXCFG_TXFULL		0x000003f0	/* TX Triger level mask */
+#define AR5K_TXCFG_TXFULL_S		4
+#define AR5K_TXCFG_TXFULL_0B		0x00000000
+#define AR5K_TXCFG_TXFULL_64B		0x00000010
+#define AR5K_TXCFG_TXFULL_128B		0x00000020
+#define AR5K_TXCFG_TXFULL_192B		0x00000030
+#define AR5K_TXCFG_TXFULL_256B		0x00000040
+#define AR5K_TXCFG_TXCONT_EN		0x00000080
+#define AR5K_TXCFG_DMASIZE		0x00000100	/* Flag for passing DMA size [5210] */
+#define AR5K_TXCFG_JUMBO_DESC_EN	0x00000400	/* Enable jumbo tx descriptors [5211+] */
+#define AR5K_TXCFG_ADHOC_BCN_ATIM	0x00000800	/* Adhoc Beacon ATIM Policy */
+#define AR5K_TXCFG_ATIM_WINDOW_DEF_DIS	0x00001000	/* Disable ATIM window defer [5211+] */
+#define AR5K_TXCFG_RTSRND		0x00001000	/* [5211+] */
+#define AR5K_TXCFG_FRMPAD_DIS		0x00002000	/* [5211+] */
+#define AR5K_TXCFG_RDY_CBR_DIS		0x00004000	/* Ready time CBR disable [5211+] */
+#define AR5K_TXCFG_JUMBO_FRM_MODE	0x00008000	/* Jumbo frame mode [5211+] */
+#define	AR5K_TXCFG_DCU_DBL_BUF_DIS	0x00008000	/* Disable double buffering on DCU */
+#define AR5K_TXCFG_DCU_CACHING_DIS	0x00010000	/* Disable DCU caching */
+
+/*
+ * Receive configuration register
+ */
+#define AR5K_RXCFG		0x0034			/* Register Address */
+#define AR5K_RXCFG_SDMAMW	0x00000007	/* DMA size (write) */
+#define AR5K_RXCFG_SDMAMW_S	0
+#define AR5K_RXCFG_ZLFDMA	0x00000008	/* Enable Zero-length frame DMA */
+#define	AR5K_RXCFG_DEF_ANTENNA	0x00000010	/* Default antenna (?) */
+#define AR5K_RXCFG_JUMBO_RXE	0x00000020	/* Enable jumbo rx descriptors [5211+] */
+#define AR5K_RXCFG_JUMBO_WRAP	0x00000040	/* Wrap jumbo frames [5211+] */
+#define AR5K_RXCFG_SLE_ENTRY	0x00000080	/* Sleep entry policy */
+
+/*
+ * Receive jumbo descriptor last address register
+ * Only found in 5211 (?)
+ */
+#define AR5K_RXJLA		0x0038
+
+/*
+ * MIB control register
+ */
+#define AR5K_MIBC		0x0040			/* Register Address */
+#define AR5K_MIBC_COW		0x00000001	/* Warn test indicator */
+#define AR5K_MIBC_FMC		0x00000002	/* Freeze MIB Counters  */
+#define AR5K_MIBC_CMC		0x00000004	/* Clean MIB Counters  */
+#define AR5K_MIBC_MCS		0x00000008	/* MIB counter strobe */
+
+/*
+ * Timeout prescale register
+ */
+#define AR5K_TOPS		0x0044
+#define	AR5K_TOPS_M		0x0000ffff
+
+/*
+ * Receive timeout register (no frame received)
+ */
+#define AR5K_RXNOFRM		0x0048
+#define	AR5K_RXNOFRM_M		0x000003ff
+
+/*
+ * Transmit timeout register (no frame sent)
+ */
+#define AR5K_TXNOFRM		0x004c
+#define	AR5K_TXNOFRM_M		0x000003ff
+#define	AR5K_TXNOFRM_QCU	0x000ffc00
+#define	AR5K_TXNOFRM_QCU_S	10
+
+/*
+ * Receive frame gap timeout register
+ */
+#define AR5K_RPGTO		0x0050
+#define AR5K_RPGTO_M		0x000003ff
+
+/*
+ * Receive frame count limit register
+ */
+#define AR5K_RFCNT		0x0054
+#define AR5K_RFCNT_M		0x0000001f	/* [5211+] (?) */
+#define AR5K_RFCNT_RFCL		0x0000000f	/* [5210] */
+
+/*
+ * Misc settings register
+ * (reserved0-3)
+ */
+#define AR5K_MISC		0x0058			/* Register Address */
+#define	AR5K_MISC_DMA_OBS_M	0x000001e0
+#define	AR5K_MISC_DMA_OBS_S	5
+#define	AR5K_MISC_MISC_OBS_M	0x00000e00
+#define	AR5K_MISC_MISC_OBS_S	9
+#define	AR5K_MISC_MAC_OBS_LSB_M	0x00007000
+#define	AR5K_MISC_MAC_OBS_LSB_S	12
+#define	AR5K_MISC_MAC_OBS_MSB_M	0x00038000
+#define	AR5K_MISC_MAC_OBS_MSB_S	15
+#define AR5K_MISC_LED_DECAY	0x001c0000	/* [5210] */
+#define AR5K_MISC_LED_BLINK	0x00e00000	/* [5210] */
+
+/*
+ * QCU/DCU clock gating register (5311)
+ * (reserved4-5)
+ */
+#define	AR5K_QCUDCU_CLKGT	0x005c			/* Register Address (?) */
+#define	AR5K_QCUDCU_CLKGT_QCU	0x0000ffff	/* Mask for QCU clock */
+#define	AR5K_QCUDCU_CLKGT_DCU	0x07ff0000	/* Mask for DCU clock */
+
+/*
+ * Interrupt Status Registers
+ *
+ * For 5210 there is only one status register but for
+ * 5211/5212 we have one primary and 4 secondary registers.
+ * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212.
+ * Most of these bits are common for all chipsets.
+ */
+#define AR5K_ISR		0x001c			/* Register Address [5210] */
+#define AR5K_PISR		0x0080			/* Register Address [5211+] */
+#define AR5K_ISR_RXOK		0x00000001	/* Frame successfuly recieved */
+#define AR5K_ISR_RXDESC		0x00000002	/* RX descriptor request */
+#define AR5K_ISR_RXERR		0x00000004	/* Receive error */
+#define AR5K_ISR_RXNOFRM	0x00000008	/* No frame received (receive timeout) */
+#define AR5K_ISR_RXEOL		0x00000010	/* Empty RX descriptor */
+#define AR5K_ISR_RXORN		0x00000020	/* Receive FIFO overrun */
+#define AR5K_ISR_TXOK		0x00000040	/* Frame successfuly transmited */
+#define AR5K_ISR_TXDESC		0x00000080	/* TX descriptor request */
+#define AR5K_ISR_TXERR		0x00000100	/* Transmit error */
+#define AR5K_ISR_TXNOFRM	0x00000200	/* No frame transmited (transmit timeout) */
+#define AR5K_ISR_TXEOL		0x00000400	/* Empty TX descriptor */
+#define AR5K_ISR_TXURN		0x00000800	/* Transmit FIFO underrun */
+#define AR5K_ISR_MIB		0x00001000	/* Update MIB counters */
+#define AR5K_ISR_SWI		0x00002000	/* Software interrupt */
+#define AR5K_ISR_RXPHY		0x00004000	/* PHY error */
+#define AR5K_ISR_RXKCM		0x00008000	/* RX Key cache miss */
+#define AR5K_ISR_SWBA		0x00010000	/* Software beacon alert */
+#define AR5K_ISR_BRSSI		0x00020000	/* Beacon rssi below threshold (?) */
+#define AR5K_ISR_BMISS		0x00040000	/* Beacon missed */
+#define AR5K_ISR_HIUERR		0x00080000	/* Host Interface Unit error [5211+] */
+#define AR5K_ISR_BNR		0x00100000 	/* Beacon not ready [5211+] */
+#define AR5K_ISR_MCABT		0x00100000	/* Master Cycle Abort [5210] */
+#define AR5K_ISR_RXCHIRP	0x00200000	/* CHIRP Received [5212+] */
+#define AR5K_ISR_SSERR		0x00200000	/* Signaled System Error [5210] */
+#define AR5K_ISR_DPERR		0x00400000	/* Det par Error (?) [5210] */
+#define AR5K_ISR_RXDOPPLER	0x00400000	/* Doppler chirp received [5212+] */
+#define AR5K_ISR_TIM		0x00800000	/* [5211+] */
+#define AR5K_ISR_BCNMISC	0x00800000	/* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT,
+						CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */
+#define AR5K_ISR_GPIO		0x01000000	/* GPIO (rf kill) */
+#define AR5K_ISR_QCBRORN	0x02000000	/* QCU CBR overrun [5211+] */
+#define AR5K_ISR_QCBRURN	0x04000000	/* QCU CBR underrun [5211+] */
+#define AR5K_ISR_QTRIG		0x08000000	/* QCU scheduling trigger [5211+] */
+
+/*
+ * Secondary status registers [5211+] (0 - 4)
+ *
+ * These give the status for each QCU, only QCUs 0-9 are
+ * represented.
+ */
+#define AR5K_SISR0		0x0084			/* Register Address [5211+] */
+#define AR5K_SISR0_QCU_TXOK	0x000003ff	/* Mask for QCU_TXOK */
+#define AR5K_SISR0_QCU_TXOK_S	0
+#define AR5K_SISR0_QCU_TXDESC	0x03ff0000	/* Mask for QCU_TXDESC */
+#define AR5K_SISR0_QCU_TXDESC_S	16
+
+#define AR5K_SISR1		0x0088			/* Register Address [5211+] */
+#define AR5K_SISR1_QCU_TXERR	0x000003ff	/* Mask for QCU_TXERR */
+#define AR5K_SISR1_QCU_TXERR_S	0
+#define AR5K_SISR1_QCU_TXEOL	0x03ff0000	/* Mask for QCU_TXEOL */
+#define AR5K_SISR1_QCU_TXEOL_S	16
+
+#define AR5K_SISR2		0x008c			/* Register Address [5211+] */
+#define AR5K_SISR2_QCU_TXURN	0x000003ff	/* Mask for QCU_TXURN */
+#define	AR5K_SISR2_QCU_TXURN_S	0
+#define	AR5K_SISR2_MCABT	0x00100000	/* Master Cycle Abort */
+#define	AR5K_SISR2_SSERR	0x00200000	/* Signaled System Error */
+#define	AR5K_SISR2_DPERR	0x00400000	/* Bus parity error */
+#define	AR5K_SISR2_TIM		0x01000000	/* [5212+] */
+#define	AR5K_SISR2_CAB_END	0x02000000	/* [5212+] */
+#define	AR5K_SISR2_DTIM_SYNC	0x04000000	/* DTIM sync lost [5212+] */
+#define	AR5K_SISR2_BCN_TIMEOUT	0x08000000	/* Beacon Timeout [5212+] */
+#define	AR5K_SISR2_CAB_TIMEOUT	0x10000000	/* CAB Timeout [5212+] */
+#define	AR5K_SISR2_DTIM		0x20000000	/* [5212+] */
+#define	AR5K_SISR2_TSFOOR	0x80000000	/* TSF OOR (?) */
+
+#define AR5K_SISR3		0x0090			/* Register Address [5211+] */
+#define AR5K_SISR3_QCBRORN	0x000003ff	/* Mask for QCBRORN */
+#define AR5K_SISR3_QCBRORN_S	0
+#define AR5K_SISR3_QCBRURN	0x03ff0000	/* Mask for QCBRURN */
+#define AR5K_SISR3_QCBRURN_S	16
+
+#define AR5K_SISR4		0x0094			/* Register Address [5211+] */
+#define AR5K_SISR4_QTRIG	0x000003ff	/* Mask for QTRIG */
+#define AR5K_SISR4_QTRIG_S	0
+
+/*
+ * Shadow read-and-clear interrupt status registers [5211+]
+ */
+#define AR5K_RAC_PISR		0x00c0		/* Read and clear PISR */
+#define AR5K_RAC_SISR0		0x00c4		/* Read and clear SISR0 */
+#define AR5K_RAC_SISR1		0x00c8		/* Read and clear SISR1 */
+#define AR5K_RAC_SISR2		0x00cc		/* Read and clear SISR2 */
+#define AR5K_RAC_SISR3		0x00d0		/* Read and clear SISR3 */
+#define AR5K_RAC_SISR4		0x00d4		/* Read and clear SISR4 */
+
+/*
+ * Interrupt Mask Registers
+ *
+ * As whith ISRs 5210 has one IMR (AR5K_IMR) and 5211/5212 has one primary
+ * (AR5K_PIMR) and 4 secondary IMRs (AR5K_SIMRx). Note that ISR/IMR flags match.
+ */
+#define	AR5K_IMR		0x0020			/* Register Address [5210] */
+#define AR5K_PIMR		0x00a0			/* Register Address [5211+] */
+#define AR5K_IMR_RXOK		0x00000001	/* Frame successfuly recieved*/
+#define AR5K_IMR_RXDESC		0x00000002	/* RX descriptor request*/
+#define AR5K_IMR_RXERR		0x00000004	/* Receive error*/
+#define AR5K_IMR_RXNOFRM	0x00000008	/* No frame received (receive timeout)*/
+#define AR5K_IMR_RXEOL		0x00000010	/* Empty RX descriptor*/
+#define AR5K_IMR_RXORN		0x00000020	/* Receive FIFO overrun*/
+#define AR5K_IMR_TXOK		0x00000040	/* Frame successfuly transmited*/
+#define AR5K_IMR_TXDESC		0x00000080	/* TX descriptor request*/
+#define AR5K_IMR_TXERR		0x00000100	/* Transmit error*/
+#define AR5K_IMR_TXNOFRM	0x00000200	/* No frame transmited (transmit timeout)*/
+#define AR5K_IMR_TXEOL		0x00000400	/* Empty TX descriptor*/
+#define AR5K_IMR_TXURN		0x00000800	/* Transmit FIFO underrun*/
+#define AR5K_IMR_MIB		0x00001000	/* Update MIB counters*/
+#define AR5K_IMR_SWI		0x00002000	/* Software interrupt */
+#define AR5K_IMR_RXPHY		0x00004000	/* PHY error*/
+#define AR5K_IMR_RXKCM		0x00008000	/* RX Key cache miss */
+#define AR5K_IMR_SWBA		0x00010000	/* Software beacon alert*/
+#define AR5K_IMR_BRSSI		0x00020000	/* Beacon rssi below threshold (?) */
+#define AR5K_IMR_BMISS		0x00040000	/* Beacon missed*/
+#define AR5K_IMR_HIUERR		0x00080000	/* Host Interface Unit error [5211+] */
+#define AR5K_IMR_BNR		0x00100000 	/* Beacon not ready [5211+] */
+#define AR5K_IMR_MCABT		0x00100000	/* Master Cycle Abort [5210] */
+#define AR5K_IMR_RXCHIRP	0x00200000	/* CHIRP Received [5212+]*/
+#define AR5K_IMR_SSERR		0x00200000	/* Signaled System Error [5210] */
+#define AR5K_IMR_DPERR		0x00400000	/* Det par Error (?) [5210] */
+#define AR5K_IMR_RXDOPPLER	0x00400000	/* Doppler chirp received [5212+] */
+#define AR5K_IMR_TIM		0x00800000	/* [5211+] */
+#define AR5K_IMR_BCNMISC	0x00800000	/* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT,
+						CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */
+#define AR5K_IMR_GPIO		0x01000000	/* GPIO (rf kill)*/
+#define AR5K_IMR_QCBRORN	0x02000000	/* QCU CBR overrun (?) [5211+] */
+#define AR5K_IMR_QCBRURN	0x04000000	/* QCU CBR underrun (?) [5211+] */
+#define AR5K_IMR_QTRIG		0x08000000	/* QCU scheduling trigger [5211+] */
+
+/*
+ * Secondary interrupt mask registers [5211+] (0 - 4)
+ */
+#define AR5K_SIMR0		0x00a4			/* Register Address [5211+] */
+#define AR5K_SIMR0_QCU_TXOK	0x000003ff	/* Mask for QCU_TXOK */
+#define AR5K_SIMR0_QCU_TXOK_S	0
+#define AR5K_SIMR0_QCU_TXDESC	0x03ff0000	/* Mask for QCU_TXDESC */
+#define AR5K_SIMR0_QCU_TXDESC_S	16
+
+#define AR5K_SIMR1		0x00a8			/* Register Address [5211+] */
+#define AR5K_SIMR1_QCU_TXERR	0x000003ff	/* Mask for QCU_TXERR */
+#define AR5K_SIMR1_QCU_TXERR_S	0
+#define AR5K_SIMR1_QCU_TXEOL	0x03ff0000	/* Mask for QCU_TXEOL */
+#define AR5K_SIMR1_QCU_TXEOL_S	16
+
+#define AR5K_SIMR2		0x00ac			/* Register Address [5211+] */
+#define AR5K_SIMR2_QCU_TXURN	0x000003ff	/* Mask for QCU_TXURN */
+#define AR5K_SIMR2_QCU_TXURN_S	0
+#define	AR5K_SIMR2_MCABT	0x00100000	/* Master Cycle Abort */
+#define	AR5K_SIMR2_SSERR	0x00200000	/* Signaled System Error */
+#define	AR5K_SIMR2_DPERR	0x00400000	/* Bus parity error */
+#define	AR5K_SIMR2_TIM		0x01000000	/* [5212+] */
+#define	AR5K_SIMR2_CAB_END	0x02000000	/* [5212+] */
+#define	AR5K_SIMR2_DTIM_SYNC	0x04000000	/* DTIM Sync lost [5212+] */
+#define	AR5K_SIMR2_BCN_TIMEOUT	0x08000000	/* Beacon Timeout [5212+] */
+#define	AR5K_SIMR2_CAB_TIMEOUT	0x10000000	/* CAB Timeout [5212+] */
+#define	AR5K_SIMR2_DTIM		0x20000000	/* [5212+] */
+#define	AR5K_SIMR2_TSFOOR	0x80000000	/* TSF OOR (?) */
+
+#define AR5K_SIMR3		0x00b0			/* Register Address [5211+] */
+#define AR5K_SIMR3_QCBRORN	0x000003ff	/* Mask for QCBRORN */
+#define AR5K_SIMR3_QCBRORN_S	0
+#define AR5K_SIMR3_QCBRURN	0x03ff0000	/* Mask for QCBRURN */
+#define AR5K_SIMR3_QCBRURN_S	16
+
+#define AR5K_SIMR4		0x00b4			/* Register Address [5211+] */
+#define AR5K_SIMR4_QTRIG	0x000003ff	/* Mask for QTRIG */
+#define AR5K_SIMR4_QTRIG_S	0
+
+/*
+ * DMA Debug registers 0-7
+ * 0xe0 - 0xfc
+ */
+
+/*
+ * Decompression mask registers [5212+]
+ */
+#define AR5K_DCM_ADDR		0x0400		/*Decompression mask address (index) */
+#define AR5K_DCM_DATA		0x0404		/*Decompression mask data */
+
+/*
+ * Wake On Wireless pattern control register [5212+]
+ */
+#define	AR5K_WOW_PCFG			0x0410			/* Register Address */
+#define	AR5K_WOW_PCFG_PAT_MATCH_EN	0x00000001	/* Pattern match enable */
+#define	AR5K_WOW_PCFG_LONG_FRAME_POL	0x00000002	/* Long frame policy */
+#define	AR5K_WOW_PCFG_WOBMISS		0x00000004	/* Wake on bea(con) miss (?) */
+#define	AR5K_WOW_PCFG_PAT_0_EN		0x00000100	/* Enable pattern 0 */
+#define	AR5K_WOW_PCFG_PAT_1_EN		0x00000200	/* Enable pattern 1 */
+#define	AR5K_WOW_PCFG_PAT_2_EN		0x00000400	/* Enable pattern 2 */
+#define	AR5K_WOW_PCFG_PAT_3_EN		0x00000800	/* Enable pattern 3 */
+#define	AR5K_WOW_PCFG_PAT_4_EN		0x00001000	/* Enable pattern 4 */
+#define	AR5K_WOW_PCFG_PAT_5_EN		0x00002000	/* Enable pattern 5 */
+
+/*
+ * Wake On Wireless pattern index register (?) [5212+]
+ */
+#define	AR5K_WOW_PAT_IDX	0x0414
+
+/*
+ * Wake On Wireless pattern data register [5212+]
+ */
+#define	AR5K_WOW_PAT_DATA	0x0418			/* Register Address */
+#define	AR5K_WOW_PAT_DATA_0_3_V	0x00000001	/* Pattern 0, 3 value */
+#define	AR5K_WOW_PAT_DATA_1_4_V	0x00000100	/* Pattern 1, 4 value */
+#define	AR5K_WOW_PAT_DATA_2_5_V	0x00010000	/* Pattern 2, 5 value */
+#define	AR5K_WOW_PAT_DATA_0_3_M	0x01000000	/* Pattern 0, 3 mask */
+#define	AR5K_WOW_PAT_DATA_1_4_M	0x04000000	/* Pattern 1, 4 mask */
+#define	AR5K_WOW_PAT_DATA_2_5_M	0x10000000	/* Pattern 2, 5 mask */
+
+/*
+ * Decompression configuration registers [5212+]
+ */
+#define AR5K_DCCFG		0x0420			/* Register Address */
+#define AR5K_DCCFG_GLOBAL_EN	0x00000001	/* Enable decompression on all queues */
+#define AR5K_DCCFG_BYPASS_EN	0x00000002	/* Bypass decompression */
+#define AR5K_DCCFG_BCAST_EN	0x00000004	/* Enable decompression for bcast frames */
+#define AR5K_DCCFG_MCAST_EN	0x00000008	/* Enable decompression for mcast frames */
+
+/*
+ * Compression configuration registers [5212+]
+ */
+#define AR5K_CCFG		0x0600			/* Register Address */
+#define	AR5K_CCFG_WINDOW_SIZE	0x00000007	/* Compression window size */
+#define	AR5K_CCFG_CPC_EN	0x00000008	/* Enable performance counters */
+
+#define AR5K_CCFG_CCU		0x0604			/* Register Address */
+#define AR5K_CCFG_CCU_CUP_EN	0x00000001	/* CCU Catchup enable */
+#define AR5K_CCFG_CCU_CREDIT	0x00000002	/* CCU Credit (field) */
+#define AR5K_CCFG_CCU_CD_THRES	0x00000080	/* CCU Cyc(lic?) debt threshold (field) */
+#define AR5K_CCFG_CCU_CUP_LCNT	0x00010000	/* CCU Catchup lit(?) count */
+#define	AR5K_CCFG_CCU_INIT	0x00100200	/* Initial value during reset */
+
+/*
+ * Compression performance counter registers [5212+]
+ */
+#define AR5K_CPC0		0x0610		/* Compression performance counter 0 */
+#define AR5K_CPC1		0x0614		/* Compression performance counter 1*/
+#define AR5K_CPC2		0x0618		/* Compression performance counter 2 */
+#define AR5K_CPC3		0x061c		/* Compression performance counter 3 */
+#define AR5K_CPCOVF		0x0620		/* Compression performance overflow */
+
+
+/*
+ * Queue control unit (QCU) registers [5211+]
+ *
+ * Card has 12 TX Queues but i see that only 0-9 are used (?)
+ * both in binary HAL (see ah.h) and ar5k. Each queue has it's own
+ * TXDP at addresses 0x0800 - 0x082c, a CBR (Constant Bit Rate)
+ * configuration register (0x08c0 - 0x08ec), a ready time configuration
+ * register (0x0900 - 0x092c), a misc configuration register (0x09c0 -
+ * 0x09ec) and a status register (0x0a00 - 0x0a2c). We also have some
+ * global registers, QCU transmit enable/disable and "one shot arm (?)"
+ * set/clear, which contain status for all queues (we shift by 1 for each
+ * queue). To access these registers easily we define some macros here
+ * that are used inside HAL. For more infos check out *_tx_queue functs.
+ */
+
+/*
+ * Generic QCU Register access macros
+ */
+#define	AR5K_QUEUE_REG(_r, _q)		(((_q) << 2) + _r)
+#define AR5K_QCU_GLOBAL_READ(_r, _q)	(AR5K_REG_READ(_r) & (1 << _q))
+#define AR5K_QCU_GLOBAL_WRITE(_r, _q)	AR5K_REG_WRITE(_r, (1 << _q))
+
+/*
+ * QCU Transmit descriptor pointer registers
+ */
+#define AR5K_QCU_TXDP_BASE	0x0800		/* Register Address - Queue0 TXDP */
+#define AR5K_QUEUE_TXDP(_q)	AR5K_QUEUE_REG(AR5K_QCU_TXDP_BASE, _q)
+
+/*
+ * QCU Transmit enable register
+ */
+#define AR5K_QCU_TXE		0x0840
+#define AR5K_ENABLE_QUEUE(_q)	AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXE, _q)
+#define AR5K_QUEUE_ENABLED(_q)	AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXE, _q)
+
+/*
+ * QCU Transmit disable register
+ */
+#define AR5K_QCU_TXD		0x0880
+#define AR5K_DISABLE_QUEUE(_q)	AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXD, _q)
+#define AR5K_QUEUE_DISABLED(_q)	AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXD, _q)
+
+/*
+ * QCU Constant Bit Rate configuration registers
+ */
+#define	AR5K_QCU_CBRCFG_BASE		0x08c0	/* Register Address - Queue0 CBRCFG */
+#define	AR5K_QCU_CBRCFG_INTVAL		0x00ffffff	/* CBR Interval mask */
+#define AR5K_QCU_CBRCFG_INTVAL_S	0
+#define	AR5K_QCU_CBRCFG_ORN_THRES	0xff000000	/* CBR overrun threshold mask */
+#define AR5K_QCU_CBRCFG_ORN_THRES_S	24
+#define	AR5K_QUEUE_CBRCFG(_q)		AR5K_QUEUE_REG(AR5K_QCU_CBRCFG_BASE, _q)
+
+/*
+ * QCU Ready time configuration registers
+ */
+#define	AR5K_QCU_RDYTIMECFG_BASE	0x0900	/* Register Address - Queue0 RDYTIMECFG */
+#define	AR5K_QCU_RDYTIMECFG_INTVAL	0x00ffffff	/* Ready time interval mask */
+#define AR5K_QCU_RDYTIMECFG_INTVAL_S	0
+#define	AR5K_QCU_RDYTIMECFG_ENABLE	0x01000000	/* Ready time enable mask */
+#define AR5K_QUEUE_RDYTIMECFG(_q)	AR5K_QUEUE_REG(AR5K_QCU_RDYTIMECFG_BASE, _q)
+
+/*
+ * QCU one shot arm set registers
+ */
+#define	AR5K_QCU_ONESHOTARM_SET		0x0940	/* Register Address -QCU "one shot arm set (?)" */
+#define	AR5K_QCU_ONESHOTARM_SET_M	0x0000ffff
+
+/*
+ * QCU one shot arm clear registers
+ */
+#define	AR5K_QCU_ONESHOTARM_CLEAR	0x0980	/* Register Address -QCU "one shot arm clear (?)" */
+#define	AR5K_QCU_ONESHOTARM_CLEAR_M	0x0000ffff
+
+/*
+ * QCU misc registers
+ */
+#define AR5K_QCU_MISC_BASE		0x09c0			/* Register Address -Queue0 MISC */
+#define	AR5K_QCU_MISC_FRSHED_M		0x0000000f	/* Frame sheduling mask */
+#define	AR5K_QCU_MISC_FRSHED_ASAP		0	/* ASAP */
+#define	AR5K_QCU_MISC_FRSHED_CBR		1	/* Constant Bit Rate */
+#define	AR5K_QCU_MISC_FRSHED_DBA_GT		2	/* DMA Beacon alert gated */
+#define	AR5K_QCU_MISC_FRSHED_TIM_GT		3	/* TIMT gated */
+#define	AR5K_QCU_MISC_FRSHED_BCN_SENT_GT	4	/* Beacon sent gated */
+#define	AR5K_QCU_MISC_ONESHOT_ENABLE	0x00000010	/* Oneshot enable */
+#define	AR5K_QCU_MISC_CBREXP_DIS	0x00000020	/* Disable CBR expired counter (normal queue) */
+#define	AR5K_QCU_MISC_CBREXP_BCN_DIS	0x00000040	/* Disable CBR expired counter (beacon queue) */
+#define	AR5K_QCU_MISC_BCN_ENABLE	0x00000080	/* Enable Beacon use */
+#define	AR5K_QCU_MISC_CBR_THRES_ENABLE	0x00000100	/* CBR expired threshold enabled */
+#define	AR5K_QCU_MISC_RDY_VEOL_POLICY	0x00000200	/* TXE reset when RDYTIME expired or VEOL */
+#define	AR5K_QCU_MISC_CBR_RESET_CNT	0x00000400	/* CBR threshold (counter) reset */
+#define	AR5K_QCU_MISC_DCU_EARLY		0x00000800	/* DCU early termination */
+#define AR5K_QCU_MISC_DCU_CMP_EN	0x00001000	/* Enable frame compression */
+#define AR5K_QUEUE_MISC(_q)		AR5K_QUEUE_REG(AR5K_QCU_MISC_BASE, _q)
+
+
+/*
+ * QCU status registers
+ */
+#define AR5K_QCU_STS_BASE	0x0a00			/* Register Address - Queue0 STS */
+#define	AR5K_QCU_STS_FRMPENDCNT	0x00000003	/* Frames pending counter */
+#define	AR5K_QCU_STS_CBREXPCNT	0x0000ff00	/* CBR expired counter */
+#define	AR5K_QUEUE_STATUS(_q)	AR5K_QUEUE_REG(AR5K_QCU_STS_BASE, _q)
+
+/*
+ * QCU ready time shutdown register
+ */
+#define AR5K_QCU_RDYTIMESHDN	0x0a40
+#define AR5K_QCU_RDYTIMESHDN_M	0x000003ff
+
+/*
+ * QCU compression buffer base registers [5212+]
+ */
+#define AR5K_QCU_CBB_SELECT	0x0b00
+#define AR5K_QCU_CBB_ADDR	0x0b04
+#define AR5K_QCU_CBB_ADDR_S	9
+
+/*
+ * QCU compression buffer configuration register [5212+]
+ * (buffer size)
+ */
+#define AR5K_QCU_CBCFG		0x0b08
+
+
+
+/*
+ * Distributed Coordination Function (DCF) control unit (DCU)
+ * registers [5211+]
+ *
+ * These registers control the various characteristics of each queue
+ * for 802.11e (WME) combatibility so they go together with
+ * QCU registers in pairs. For each queue we have a QCU mask register,
+ * (0x1000 - 0x102c), a local-IFS settings register (0x1040 - 0x106c),
+ * a retry limit register (0x1080 - 0x10ac), a channel time register
+ * (0x10c0 - 0x10ec), a misc-settings register (0x1100 - 0x112c) and
+ * a sequence number register (0x1140 - 0x116c). It seems that "global"
+ * registers here afect all queues (see use of DCU_GBL_IFS_SLOT in ar5k).
+ * We use the same macros here for easier register access.
+ *
+ */
+
+/*
+ * DCU QCU mask registers
+ */
+#define AR5K_DCU_QCUMASK_BASE	0x1000		/* Register Address -Queue0 DCU_QCUMASK */
+#define AR5K_DCU_QCUMASK_M	0x000003ff
+#define AR5K_QUEUE_QCUMASK(_q)	AR5K_QUEUE_REG(AR5K_DCU_QCUMASK_BASE, _q)
+
+/*
+ * DCU local Inter Frame Space settings register
+ */
+#define AR5K_DCU_LCL_IFS_BASE		0x1040			/* Register Address -Queue0 DCU_LCL_IFS */
+#define	AR5K_DCU_LCL_IFS_CW_MIN	        0x000003ff	/* Minimum Contention Window */
+#define	AR5K_DCU_LCL_IFS_CW_MIN_S	0
+#define	AR5K_DCU_LCL_IFS_CW_MAX	        0x000ffc00	/* Maximum Contention Window */
+#define	AR5K_DCU_LCL_IFS_CW_MAX_S	10
+#define	AR5K_DCU_LCL_IFS_AIFS		0x0ff00000	/* Arbitrated Interframe Space */
+#define	AR5K_DCU_LCL_IFS_AIFS_S		20
+#define	AR5K_DCU_LCL_IFS_AIFS_MAX	0xfc		/* Anything above that can cause DCU to hang */
+#define	AR5K_QUEUE_DFS_LOCAL_IFS(_q)	AR5K_QUEUE_REG(AR5K_DCU_LCL_IFS_BASE, _q)
+
+/*
+ * DCU retry limit registers
+ */
+#define AR5K_DCU_RETRY_LMT_BASE		0x1080			/* Register Address -Queue0 DCU_RETRY_LMT */
+#define AR5K_DCU_RETRY_LMT_SH_RETRY	0x0000000f	/* Short retry limit mask */
+#define AR5K_DCU_RETRY_LMT_SH_RETRY_S	0
+#define AR5K_DCU_RETRY_LMT_LG_RETRY	0x000000f0	/* Long retry limit mask */
+#define AR5K_DCU_RETRY_LMT_LG_RETRY_S	4
+#define AR5K_DCU_RETRY_LMT_SSH_RETRY	0x00003f00	/* Station short retry limit mask (?) */
+#define AR5K_DCU_RETRY_LMT_SSH_RETRY_S	8
+#define AR5K_DCU_RETRY_LMT_SLG_RETRY	0x000fc000	/* Station long retry limit mask (?) */
+#define AR5K_DCU_RETRY_LMT_SLG_RETRY_S	14
+#define	AR5K_QUEUE_DFS_RETRY_LIMIT(_q)	AR5K_QUEUE_REG(AR5K_DCU_RETRY_LMT_BASE, _q)
+
+/*
+ * DCU channel time registers
+ */
+#define AR5K_DCU_CHAN_TIME_BASE		0x10c0			/* Register Address -Queue0 DCU_CHAN_TIME */
+#define	AR5K_DCU_CHAN_TIME_DUR		0x000fffff	/* Channel time duration */
+#define	AR5K_DCU_CHAN_TIME_DUR_S	0
+#define	AR5K_DCU_CHAN_TIME_ENABLE	0x00100000	/* Enable channel time */
+#define AR5K_QUEUE_DFS_CHANNEL_TIME(_q)	AR5K_QUEUE_REG(AR5K_DCU_CHAN_TIME_BASE, _q)
+
+/*
+ * DCU misc registers [5211+]
+ *
+ * Note: Arbiter lockout control controls the
+ * behaviour on low priority queues when we have multiple queues
+ * with pending frames. Intra-frame lockout means we wait until
+ * the queue's current frame transmits (with post frame backoff and bursting)
+ * before we transmit anything else and global lockout means we
+ * wait for the whole queue to finish before higher priority queues
+ * can transmit (this is used on beacon and CAB queues).
+ * No lockout means there is no special handling.
+ */
+#define AR5K_DCU_MISC_BASE		0x1100			/* Register Address -Queue0 DCU_MISC */
+#define	AR5K_DCU_MISC_BACKOFF		0x0000003f	/* Mask for backoff threshold */
+#define	AR5K_DCU_MISC_ETS_RTS_POL	0x00000040	/* End of transmission series
+							station RTS/data failure count
+							reset policy (?) */
+#define AR5K_DCU_MISC_ETS_CW_POL	0x00000080	/* End of transmission series
+							CW reset policy */
+#define	AR5K_DCU_MISC_FRAG_WAIT		0x00000100	/* Wait for next fragment */
+#define AR5K_DCU_MISC_BACKOFF_FRAG	0x00000200	/* Enable backoff while bursting */
+#define	AR5K_DCU_MISC_HCFPOLL_ENABLE	0x00000800	/* CF - Poll enable */
+#define	AR5K_DCU_MISC_BACKOFF_PERSIST	0x00001000	/* Persistent backoff */
+#define	AR5K_DCU_MISC_FRMPRFTCH_ENABLE	0x00002000	/* Enable frame pre-fetch */
+#define	AR5K_DCU_MISC_VIRTCOL		0x0000c000	/* Mask for Virtual Collision (?) */
+#define	AR5K_DCU_MISC_VIRTCOL_NORMAL	0
+#define	AR5K_DCU_MISC_VIRTCOL_IGNORE	1
+#define	AR5K_DCU_MISC_BCN_ENABLE	0x00010000	/* Enable Beacon use */
+#define	AR5K_DCU_MISC_ARBLOCK_CTL	0x00060000	/* Arbiter lockout control mask */
+#define	AR5K_DCU_MISC_ARBLOCK_CTL_S	17
+#define	AR5K_DCU_MISC_ARBLOCK_CTL_NONE		0	/* No arbiter lockout */
+#define	AR5K_DCU_MISC_ARBLOCK_CTL_INTFRM	1	/* Intra-frame lockout */
+#define	AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL	2	/* Global lockout */
+#define	AR5K_DCU_MISC_ARBLOCK_IGNORE	0x00080000	/* Ignore Arbiter lockout */
+#define	AR5K_DCU_MISC_SEQ_NUM_INCR_DIS	0x00100000	/* Disable sequence number increment */
+#define	AR5K_DCU_MISC_POST_FR_BKOFF_DIS	0x00200000	/* Disable post-frame backoff */
+#define	AR5K_DCU_MISC_VIRT_COLL_POLICY	0x00400000	/* Virtual Collision cw policy */
+#define	AR5K_DCU_MISC_BLOWN_IFS_POLICY	0x00800000	/* Blown IFS policy (?) */
+#define	AR5K_DCU_MISC_SEQNUM_CTL	0x01000000	/* Sequence number control (?) */
+#define AR5K_QUEUE_DFS_MISC(_q)		AR5K_QUEUE_REG(AR5K_DCU_MISC_BASE, _q)
+
+/*
+ * DCU frame sequence number registers
+ */
+#define AR5K_DCU_SEQNUM_BASE		0x1140
+#define	AR5K_DCU_SEQNUM_M		0x00000fff
+#define	AR5K_QUEUE_DCU_SEQNUM(_q)	AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q)
+
+/*
+ * DCU global IFS SIFS register
+ */
+#define AR5K_DCU_GBL_IFS_SIFS	0x1030
+#define AR5K_DCU_GBL_IFS_SIFS_M	0x0000ffff
+
+/*
+ * DCU global IFS slot interval register
+ */
+#define AR5K_DCU_GBL_IFS_SLOT	0x1070
+#define AR5K_DCU_GBL_IFS_SLOT_M	0x0000ffff
+
+/*
+ * DCU global IFS EIFS register
+ */
+#define AR5K_DCU_GBL_IFS_EIFS	0x10b0
+#define AR5K_DCU_GBL_IFS_EIFS_M	0x0000ffff
+
+/*
+ * DCU global IFS misc register
+ *
+ * LFSR stands for Linear Feedback Shift Register
+ * and it's used for generating pseudo-random
+ * number sequences.
+ *
+ * (If i understand corectly, random numbers are
+ * used for idle sensing -multiplied with cwmin/max etc-)
+ */
+#define AR5K_DCU_GBL_IFS_MISC			0x10f0			/* Register Address */
+#define	AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE	0x00000007	/* LFSR Slice Select */
+#define	AR5K_DCU_GBL_IFS_MISC_TURBO_MODE	0x00000008	/* Turbo mode */
+#define	AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC	0x000003f0	/* SIFS Duration mask */
+#define	AR5K_DCU_GBL_IFS_MISC_USEC_DUR		0x000ffc00	/* USEC Duration mask */
+#define	AR5K_DCU_GBL_IFS_MISC_USEC_DUR_S	10
+#define	AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY	0x00300000	/* DCU Arbiter delay mask */
+#define AR5K_DCU_GBL_IFS_MISC_SIFS_CNT_RST	0x00400000	/* SIFS cnt reset policy (?) */
+#define AR5K_DCU_GBL_IFS_MISC_AIFS_CNT_RST	0x00800000	/* AIFS cnt reset policy (?) */
+#define AR5K_DCU_GBL_IFS_MISC_RND_LFSR_SL_DIS	0x01000000	/* Disable random LFSR slice */
+
+/*
+ * DCU frame prefetch control register
+ */
+#define AR5K_DCU_FP			0x1230			/* Register Address */
+#define AR5K_DCU_FP_NOBURST_DCU_EN	0x00000001	/* Enable non-burst prefetch on DCU (?) */
+#define AR5K_DCU_FP_NOBURST_EN		0x00000010	/* Enable non-burst prefetch (?) */
+#define AR5K_DCU_FP_BURST_DCU_EN	0x00000020	/* Enable burst prefetch on DCU (?) */
+
+/*
+ * DCU transmit pause control/status register
+ */
+#define AR5K_DCU_TXP		0x1270			/* Register Address */
+#define	AR5K_DCU_TXP_M		0x000003ff	/* Tx pause mask */
+#define	AR5K_DCU_TXP_STATUS	0x00010000	/* Tx pause status */
+
+/*
+ * DCU transmit filter table 0 (32 entries)
+ * each entry contains a 32bit slice of the
+ * 128bit tx filter for each DCU (4 slices per DCU)
+ */
+#define AR5K_DCU_TX_FILTER_0_BASE	0x1038
+#define	AR5K_DCU_TX_FILTER_0(_n)	(AR5K_DCU_TX_FILTER_0_BASE + (_n * 64))
+
+/*
+ * DCU transmit filter table 1 (16 entries)
+ */
+#define AR5K_DCU_TX_FILTER_1_BASE	0x103c
+#define	AR5K_DCU_TX_FILTER_1(_n)	(AR5K_DCU_TX_FILTER_1_BASE + (_n * 64))
+
+/*
+ * DCU clear transmit filter register
+ */
+#define AR5K_DCU_TX_FILTER_CLR	0x143c
+
+/*
+ * DCU set transmit filter register
+ */
+#define AR5K_DCU_TX_FILTER_SET	0x147c
+
+/*
+ * Reset control register
+ */
+#define AR5K_RESET_CTL		0x4000			/* Register Address */
+#define AR5K_RESET_CTL_PCU	0x00000001	/* Protocol Control Unit reset */
+#define AR5K_RESET_CTL_DMA	0x00000002	/* DMA (Rx/Tx) reset [5210] */
+#define	AR5K_RESET_CTL_BASEBAND	0x00000002	/* Baseband reset [5211+] */
+#define AR5K_RESET_CTL_MAC	0x00000004	/* MAC reset (PCU+Baseband ?) [5210] */
+#define AR5K_RESET_CTL_PHY	0x00000008	/* PHY reset [5210] */
+#define AR5K_RESET_CTL_PCI	0x00000010	/* PCI Core reset (interrupts etc) */
+
+/*
+ * Sleep control register
+ */
+#define AR5K_SLEEP_CTL			0x4004			/* Register Address */
+#define AR5K_SLEEP_CTL_SLDUR		0x0000ffff	/* Sleep duration mask */
+#define AR5K_SLEEP_CTL_SLDUR_S		0
+#define AR5K_SLEEP_CTL_SLE		0x00030000	/* Sleep enable mask */
+#define AR5K_SLEEP_CTL_SLE_S		16
+#define AR5K_SLEEP_CTL_SLE_WAKE		0x00000000	/* Force chip awake */
+#define AR5K_SLEEP_CTL_SLE_SLP		0x00010000	/* Force chip sleep */
+#define AR5K_SLEEP_CTL_SLE_ALLOW	0x00020000	/* Normal sleep policy */
+#define AR5K_SLEEP_CTL_SLE_UNITS	0x00000008	/* [5211+] */
+#define AR5K_SLEEP_CTL_DUR_TIM_POL	0x00040000	/* Sleep duration timing policy */
+#define AR5K_SLEEP_CTL_DUR_WRITE_POL	0x00080000	/* Sleep duration write policy */
+#define AR5K_SLEEP_CTL_SLE_POL		0x00100000	/* Sleep policy mode */
+
+/*
+ * Interrupt pending register
+ */
+#define AR5K_INTPEND	0x4008
+#define AR5K_INTPEND_M	0x00000001
+
+/*
+ * Sleep force register
+ */
+#define AR5K_SFR	0x400c
+#define AR5K_SFR_EN	0x00000001
+
+/*
+ * PCI configuration register
+ * TODO: Fix LED stuff
+ */
+#define AR5K_PCICFG			0x4010			/* Register Address */
+#define AR5K_PCICFG_EEAE		0x00000001	/* Eeprom access enable [5210] */
+#define AR5K_PCICFG_SLEEP_CLOCK_EN	0x00000002	/* Enable sleep clock */
+#define AR5K_PCICFG_CLKRUNEN		0x00000004	/* CLKRUN enable [5211+] */
+#define AR5K_PCICFG_EESIZE		0x00000018	/* Mask for EEPROM size [5211+] */
+#define AR5K_PCICFG_EESIZE_S		3
+#define AR5K_PCICFG_EESIZE_4K		0		/* 4K */
+#define AR5K_PCICFG_EESIZE_8K		1		/* 8K */
+#define AR5K_PCICFG_EESIZE_16K		2		/* 16K */
+#define AR5K_PCICFG_EESIZE_FAIL		3		/* Failed to get size [5211+] */
+#define AR5K_PCICFG_LED			0x00000060	/* Led status [5211+] */
+#define AR5K_PCICFG_LED_NONE		0x00000000	/* Default [5211+] */
+#define AR5K_PCICFG_LED_PEND		0x00000020	/* Scan / Auth pending */
+#define AR5K_PCICFG_LED_ASSOC		0x00000040	/* Associated */
+#define	AR5K_PCICFG_BUS_SEL		0x00000380	/* Mask for "bus select" [5211+] (?) */
+#define AR5K_PCICFG_CBEFIX_DIS		0x00000400	/* Disable CBE fix */
+#define AR5K_PCICFG_SL_INTEN		0x00000800	/* Enable interrupts when asleep */
+#define AR5K_PCICFG_LED_BCTL		0x00001000	/* Led blink (?) [5210] */
+#define AR5K_PCICFG_RETRY_FIX		0x00001000	/* Enable pci core retry fix */
+#define AR5K_PCICFG_SL_INPEN		0x00002000	/* Sleep even whith pending interrupts*/
+#define AR5K_PCICFG_SPWR_DN		0x00010000	/* Mask for power status */
+#define AR5K_PCICFG_LEDMODE		0x000e0000	/* Ledmode [5211+] */
+#define AR5K_PCICFG_LEDMODE_PROP	0x00000000	/* Blink on standard traffic [5211+] */
+#define AR5K_PCICFG_LEDMODE_PROM	0x00020000	/* Default mode (blink on any traffic) [5211+] */
+#define AR5K_PCICFG_LEDMODE_PWR		0x00040000	/* Some other blinking mode  (?) [5211+] */
+#define AR5K_PCICFG_LEDMODE_RAND	0x00060000	/* Random blinking (?) [5211+] */
+#define AR5K_PCICFG_LEDBLINK		0x00700000	/* Led blink rate */
+#define AR5K_PCICFG_LEDBLINK_S		20
+#define AR5K_PCICFG_LEDSLOW		0x00800000	/* Slowest led blink rate [5211+] */
+#define AR5K_PCICFG_LEDSTATE				\
+	(AR5K_PCICFG_LED | AR5K_PCICFG_LEDMODE |	\
+	AR5K_PCICFG_LEDBLINK | AR5K_PCICFG_LEDSLOW)
+#define	AR5K_PCICFG_SLEEP_CLOCK_RATE	0x03000000	/* Sleep clock rate */
+#define	AR5K_PCICFG_SLEEP_CLOCK_RATE_S	24
+
+/*
+ * "General Purpose Input/Output" (GPIO) control register
+ *
+ * I'm not sure about this but after looking at the code
+ * for all chipsets here is what i got.
+ *
+ * We have 6 GPIOs (pins), each GPIO has 4 modes (2 bits)
+ * Mode 0 -> always input
+ * Mode 1 -> output when GPIODO for this GPIO is set to 0
+ * Mode 2 -> output when GPIODO for this GPIO is set to 1
+ * Mode 3 -> always output
+ *
+ * For more infos check out get_gpio/set_gpio and
+ * set_gpio_input/set_gpio_output functs.
+ * For more infos on gpio interrupt check out set_gpio_intr.
+ */
+#define AR5K_NUM_GPIO	6
+
+#define AR5K_GPIOCR		0x4014				/* Register Address */
+#define AR5K_GPIOCR_INT_ENA	0x00008000		/* Enable GPIO interrupt */
+#define AR5K_GPIOCR_INT_SELL	0x00000000		/* Generate interrupt when pin is low */
+#define AR5K_GPIOCR_INT_SELH	0x00010000		/* Generate interrupt when pin is high */
+#define AR5K_GPIOCR_IN(n)	(0 << ((n) * 2))	/* Mode 0 for pin n */
+#define AR5K_GPIOCR_OUT0(n)	(1 << ((n) * 2))	/* Mode 1 for pin n */
+#define AR5K_GPIOCR_OUT1(n)	(2 << ((n) * 2))	/* Mode 2 for pin n */
+#define AR5K_GPIOCR_OUT(n)	(3 << ((n) * 2))	/* Mode 3 for pin n */
+#define AR5K_GPIOCR_INT_SEL(n)	((n) << 12)		/* Interrupt for GPIO pin n */
+
+/*
+ * "General Purpose Input/Output" (GPIO) data output register
+ */
+#define AR5K_GPIODO	0x4018
+
+/*
+ * "General Purpose Input/Output" (GPIO) data input register
+ */
+#define AR5K_GPIODI	0x401c
+#define AR5K_GPIODI_M	0x0000002f
+
+/*
+ * Silicon revision register
+ */
+#define AR5K_SREV		0x4020			/* Register Address */
+#define AR5K_SREV_REV		0x0000000f	/* Mask for revision */
+#define AR5K_SREV_REV_S		0
+#define AR5K_SREV_VER		0x000000ff	/* Mask for version */
+#define AR5K_SREV_VER_S		4
+
+/*
+ * TXE write posting register
+ */
+#define	AR5K_TXEPOST	0x4028
+
+/*
+ * QCU sleep mask
+ */
+#define	AR5K_QCU_SLEEP_MASK	0x402c
+
+/* 0x4068 is compression buffer configuration
+ * register on 5414 and pm configuration register
+ * on 5424 and newer pci-e chips. */
+
+/*
+ * Compression buffer configuration
+ * register (enable/disable) [5414]
+ */
+#define AR5K_5414_CBCFG		0x4068
+#define AR5K_5414_CBCFG_BUF_DIS	0x10	/* Disable buffer */
+
+/*
+ * PCI-E Power managment configuration
+ * and status register [5424+]
+ */
+#define	AR5K_PCIE_PM_CTL		0x4068			/* Register address */
+/* Only 5424 */
+#define	AR5K_PCIE_PM_CTL_L1_WHEN_D2	0x00000001	/* enable PCIe core enter L1
+							when d2_sleep_en is asserted */
+#define	AR5K_PCIE_PM_CTL_L0_L0S_CLEAR	0x00000002	/* Clear L0 and L0S counters */
+#define	AR5K_PCIE_PM_CTL_L0_L0S_EN	0x00000004	/* Start L0 nd L0S counters */
+#define	AR5K_PCIE_PM_CTL_LDRESET_EN	0x00000008	/* Enable reset when link goes
+							down */
+/* Wake On Wireless */
+#define	AR5K_PCIE_PM_CTL_PME_EN		0x00000010	/* PME Enable */
+#define	AR5K_PCIE_PM_CTL_AUX_PWR_DET	0x00000020	/* Aux power detect */
+#define	AR5K_PCIE_PM_CTL_PME_CLEAR	0x00000040	/* Clear PME */
+#define	AR5K_PCIE_PM_CTL_PSM_D0		0x00000080
+#define	AR5K_PCIE_PM_CTL_PSM_D1		0x00000100
+#define	AR5K_PCIE_PM_CTL_PSM_D2		0x00000200
+#define	AR5K_PCIE_PM_CTL_PSM_D3		0x00000400
+
+/*
+ * PCI-E Workaround enable register
+ */
+#define	AR5K_PCIE_WAEN	0x407c
+
+/*
+ * PCI-E Serializer/Desirializer
+ * registers
+ */
+#define	AR5K_PCIE_SERDES	0x4080
+#define	AR5K_PCIE_SERDES_RESET	0x4084
+
+/*====EEPROM REGISTERS====*/
+
+/*
+ * EEPROM access registers
+ *
+ * Here we got a difference between 5210/5211-12
+ * read data register for 5210 is at 0x6800 and
+ * status register is at 0x6c00. There is also
+ * no eeprom command register on 5210 and the
+ * offsets are different.
+ *
+ * To read eeprom data for a specific offset:
+ * 5210 - enable eeprom access (AR5K_PCICFG_EEAE)
+ *        read AR5K_EEPROM_BASE +(4 * offset)
+ *        check the eeprom status register
+ *        and read eeprom data register.
+ *
+ * 5211 - write offset to AR5K_EEPROM_BASE
+ * 5212   write AR5K_EEPROM_CMD_READ on AR5K_EEPROM_CMD
+ *        check the eeprom status register
+ *        and read eeprom data register.
+ *
+ * To write eeprom data for a specific offset:
+ * 5210 - enable eeprom access (AR5K_PCICFG_EEAE)
+ *        write data to AR5K_EEPROM_BASE +(4 * offset)
+ *        check the eeprom status register
+ * 5211 - write AR5K_EEPROM_CMD_RESET on AR5K_EEPROM_CMD
+ * 5212   write offset to AR5K_EEPROM_BASE
+ *        write data to data register
+ *	  write AR5K_EEPROM_CMD_WRITE on AR5K_EEPROM_CMD
+ *        check the eeprom status register
+ *
+ * For more infos check eeprom_* functs and the ar5k.c
+ * file posted in madwifi-devel mailing list.
+ * http://sourceforge.net/mailarchive/message.php?msg_id=8966525
+ *
+ */
+#define AR5K_EEPROM_BASE	0x6000
+
+/*
+ * EEPROM data register
+ */
+#define AR5K_EEPROM_DATA_5211	0x6004
+#define AR5K_EEPROM_DATA_5210	0x6800
+#define	AR5K_EEPROM_DATA	(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211)
+
+/*
+ * EEPROM command register
+ */
+#define AR5K_EEPROM_CMD		0x6008			/* Register Addres */
+#define AR5K_EEPROM_CMD_READ	0x00000001	/* EEPROM read */
+#define AR5K_EEPROM_CMD_WRITE	0x00000002	/* EEPROM write */
+#define AR5K_EEPROM_CMD_RESET	0x00000004	/* EEPROM reset */
+
+/*
+ * EEPROM status register
+ */
+#define AR5K_EEPROM_STAT_5210	0x6c00			/* Register Address [5210] */
+#define AR5K_EEPROM_STAT_5211	0x600c			/* Register Address [5211+] */
+#define	AR5K_EEPROM_STATUS	(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211)
+#define AR5K_EEPROM_STAT_RDERR	0x00000001	/* EEPROM read failed */
+#define AR5K_EEPROM_STAT_RDDONE	0x00000002	/* EEPROM read successful */
+#define AR5K_EEPROM_STAT_WRERR	0x00000004	/* EEPROM write failed */
+#define AR5K_EEPROM_STAT_WRDONE	0x00000008	/* EEPROM write successful */
+
+/*
+ * EEPROM config register
+ */
+#define AR5K_EEPROM_CFG			0x6010			/* Register Addres */
+#define AR5K_EEPROM_CFG_SIZE		0x00000003		/* Size determination override */
+#define AR5K_EEPROM_CFG_SIZE_AUTO	0
+#define AR5K_EEPROM_CFG_SIZE_4KBIT	1
+#define AR5K_EEPROM_CFG_SIZE_8KBIT	2
+#define AR5K_EEPROM_CFG_SIZE_16KBIT	3
+#define AR5K_EEPROM_CFG_WR_WAIT_DIS	0x00000004	/* Disable write wait */
+#define AR5K_EEPROM_CFG_CLK_RATE	0x00000018	/* Clock rate */
+#define AR5K_EEPROM_CFG_CLK_RATE_S		3
+#define AR5K_EEPROM_CFG_CLK_RATE_156KHZ	0
+#define AR5K_EEPROM_CFG_CLK_RATE_312KHZ	1
+#define AR5K_EEPROM_CFG_CLK_RATE_625KHZ	2
+#define AR5K_EEPROM_CFG_PROT_KEY	0x00ffff00      /* Protection key */
+#define AR5K_EEPROM_CFG_PROT_KEY_S	8
+#define AR5K_EEPROM_CFG_LIND_EN		0x01000000	/* Enable length indicator (?) */
+
+
+/*
+ * TODO: Wake On Wireless registers
+ * Range 0x7000 - 0x7ce0
+ */
+
+/*
+ * Protocol Control Unit (PCU) registers
+ */
+/*
+ * Used for checking initial register writes
+ * during channel reset (see reset func)
+ */
+#define AR5K_PCU_MIN	0x8000
+#define AR5K_PCU_MAX	0x8fff
+
+/*
+ * First station id register (Lower 32 bits of MAC address)
+ */
+#define AR5K_STA_ID0		0x8000
+#define	AR5K_STA_ID0_ARRD_L32	0xffffffff
+
+/*
+ * Second station id register (Upper 16 bits of MAC address + PCU settings)
+ */
+#define AR5K_STA_ID1			0x8004			/* Register Address */
+#define	AR5K_STA_ID1_ADDR_U16		0x0000ffff	/* Upper 16 bits of MAC addres */
+#define AR5K_STA_ID1_AP			0x00010000	/* Set AP mode */
+#define AR5K_STA_ID1_ADHOC		0x00020000	/* Set Ad-Hoc mode */
+#define AR5K_STA_ID1_PWR_SV		0x00040000	/* Power save reporting */
+#define AR5K_STA_ID1_NO_KEYSRCH		0x00080000	/* No key search */
+#define AR5K_STA_ID1_NO_PSPOLL		0x00100000	/* No power save polling [5210] */
+#define AR5K_STA_ID1_PCF_5211		0x00100000	/* Enable PCF on [5211+] */
+#define AR5K_STA_ID1_PCF_5210		0x00200000	/* Enable PCF on [5210]*/
+#define	AR5K_STA_ID1_PCF		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_STA_ID1_PCF_5210 : AR5K_STA_ID1_PCF_5211)
+#define AR5K_STA_ID1_DEFAULT_ANTENNA	0x00200000	/* Use default antenna */
+#define AR5K_STA_ID1_DESC_ANTENNA	0x00400000	/* Update antenna from descriptor */
+#define AR5K_STA_ID1_RTS_DEF_ANTENNA	0x00800000	/* Use default antenna for RTS */
+#define AR5K_STA_ID1_ACKCTS_6MB		0x01000000	/* Use 6Mbit/s for ACK/CTS */
+#define AR5K_STA_ID1_BASE_RATE_11B	0x02000000	/* Use 11b base rate for ACK/CTS [5211+] */
+#define AR5K_STA_ID1_SELFGEN_DEF_ANT	0x04000000	/* Use def. antenna for self generated frames */
+#define AR5K_STA_ID1_CRYPT_MIC_EN	0x08000000	/* Enable MIC */
+#define AR5K_STA_ID1_KEYSRCH_MODE	0x10000000	/* Look up key when key id != 0 */
+#define AR5K_STA_ID1_PRESERVE_SEQ_NUM	0x20000000	/* Preserve sequence number */
+#define AR5K_STA_ID1_CBCIV_ENDIAN	0x40000000	/* ??? */
+#define AR5K_STA_ID1_KEYSRCH_MCAST	0x80000000	/* Do key cache search for mcast frames */
+
+/*
+ * First BSSID register (MAC address, lower 32bits)
+ */
+#define AR5K_BSS_ID0	0x8008
+
+/*
+ * Second BSSID register (MAC address in upper 16 bits)
+ *
+ * AID: Association ID
+ */
+#define AR5K_BSS_ID1		0x800c
+#define AR5K_BSS_ID1_AID	0xffff0000
+#define AR5K_BSS_ID1_AID_S	16
+
+/*
+ * Backoff slot time register
+ */
+#define AR5K_SLOT_TIME	0x8010
+
+/*
+ * ACK/CTS timeout register
+ */
+#define AR5K_TIME_OUT		0x8014			/* Register Address */
+#define AR5K_TIME_OUT_ACK	0x00001fff	/* ACK timeout mask */
+#define AR5K_TIME_OUT_ACK_S	0
+#define AR5K_TIME_OUT_CTS	0x1fff0000	/* CTS timeout mask */
+#define AR5K_TIME_OUT_CTS_S	16
+
+/*
+ * RSSI threshold register
+ */
+#define AR5K_RSSI_THR			0x8018		/* Register Address */
+#define AR5K_RSSI_THR_M			0x000000ff	/* Mask for RSSI threshold [5211+] */
+#define AR5K_RSSI_THR_BMISS_5210	0x00000700	/* Mask for Beacon Missed threshold [5210] */
+#define AR5K_RSSI_THR_BMISS_5210_S	8
+#define AR5K_RSSI_THR_BMISS_5211	0x0000ff00	/* Mask for Beacon Missed threshold [5211+] */
+#define AR5K_RSSI_THR_BMISS_5211_S	8
+#define	AR5K_RSSI_THR_BMISS		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_RSSI_THR_BMISS_5210 : AR5K_RSSI_THR_BMISS_5211)
+#define	AR5K_RSSI_THR_BMISS_S		8
+
+/*
+ * 5210 has more PCU registers because there is no QCU/DCU
+ * so queue parameters are set here, this way a lot common
+ * registers have different address for 5210. To make things
+ * easier we define a macro based on ah->ah_version for common
+ * registers with different addresses and common flags.
+ */
+
+/*
+ * Retry limit register
+ *
+ * Retry limit register for 5210 (no QCU/DCU so it's done in PCU)
+ */
+#define AR5K_NODCU_RETRY_LMT		0x801c			/* Register Address */
+#define AR5K_NODCU_RETRY_LMT_SH_RETRY	0x0000000f	/* Short retry limit mask */
+#define AR5K_NODCU_RETRY_LMT_SH_RETRY_S	0
+#define AR5K_NODCU_RETRY_LMT_LG_RETRY	0x000000f0	/* Long retry mask */
+#define AR5K_NODCU_RETRY_LMT_LG_RETRY_S	4
+#define AR5K_NODCU_RETRY_LMT_SSH_RETRY	0x00003f00	/* Station short retry limit mask */
+#define AR5K_NODCU_RETRY_LMT_SSH_RETRY_S	8
+#define AR5K_NODCU_RETRY_LMT_SLG_RETRY	0x000fc000	/* Station long retry limit mask */
+#define AR5K_NODCU_RETRY_LMT_SLG_RETRY_S	14
+#define AR5K_NODCU_RETRY_LMT_CW_MIN	0x3ff00000	/* Minimum contention window mask */
+#define AR5K_NODCU_RETRY_LMT_CW_MIN_S	20
+
+/*
+ * Transmit latency register
+ */
+#define AR5K_USEC_5210			0x8020			/* Register Address [5210] */
+#define AR5K_USEC_5211			0x801c			/* Register Address [5211+] */
+#define AR5K_USEC			(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_USEC_5210 : AR5K_USEC_5211)
+#define AR5K_USEC_1			0x0000007f	/* clock cycles for 1us */
+#define AR5K_USEC_1_S			0
+#define AR5K_USEC_32			0x00003f80	/* clock cycles for 1us while on 32Mhz clock */
+#define AR5K_USEC_32_S			7
+#define AR5K_USEC_TX_LATENCY_5211	0x007fc000
+#define AR5K_USEC_TX_LATENCY_5211_S	14
+#define AR5K_USEC_RX_LATENCY_5211	0x1f800000
+#define AR5K_USEC_RX_LATENCY_5211_S	23
+#define AR5K_USEC_TX_LATENCY_5210	0x000fc000	/* also for 5311 */
+#define AR5K_USEC_TX_LATENCY_5210_S	14
+#define AR5K_USEC_RX_LATENCY_5210	0x03f00000	/* also for 5311 */
+#define AR5K_USEC_RX_LATENCY_5210_S	20
+
+/*
+ * PCU beacon control register
+ */
+#define AR5K_BEACON_5210	0x8024			/*Register Address [5210] */
+#define AR5K_BEACON_5211	0x8020			/*Register Address [5211+] */
+#define AR5K_BEACON		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_BEACON_5210 : AR5K_BEACON_5211)
+#define AR5K_BEACON_PERIOD	0x0000ffff	/* Mask for beacon period */
+#define AR5K_BEACON_PERIOD_S	0
+#define AR5K_BEACON_TIM		0x007f0000	/* Mask for TIM offset */
+#define AR5K_BEACON_TIM_S	16
+#define AR5K_BEACON_ENABLE	0x00800000	/* Enable beacons */
+#define AR5K_BEACON_RESET_TSF	0x01000000	/* Force TSF reset */
+
+/*
+ * CFP period register
+ */
+#define AR5K_CFP_PERIOD_5210	0x8028
+#define AR5K_CFP_PERIOD_5211	0x8024
+#define AR5K_CFP_PERIOD		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_CFP_PERIOD_5210 : AR5K_CFP_PERIOD_5211)
+
+/*
+ * Next beacon time register
+ */
+#define AR5K_TIMER0_5210	0x802c
+#define AR5K_TIMER0_5211	0x8028
+#define AR5K_TIMER0		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TIMER0_5210 : AR5K_TIMER0_5211)
+
+/*
+ * Next DMA beacon alert register
+ */
+#define AR5K_TIMER1_5210	0x8030
+#define AR5K_TIMER1_5211	0x802c
+#define AR5K_TIMER1		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TIMER1_5210 : AR5K_TIMER1_5211)
+
+/*
+ * Next software beacon alert register
+ */
+#define AR5K_TIMER2_5210	0x8034
+#define AR5K_TIMER2_5211	0x8030
+#define AR5K_TIMER2		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TIMER2_5210 : AR5K_TIMER2_5211)
+
+/*
+ * Next ATIM window time register
+ */
+#define AR5K_TIMER3_5210	0x8038
+#define AR5K_TIMER3_5211	0x8034
+#define AR5K_TIMER3		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TIMER3_5210 : AR5K_TIMER3_5211)
+
+
+/*
+ * 5210 First inter frame spacing register (IFS)
+ */
+#define AR5K_IFS0		0x8040
+#define AR5K_IFS0_SIFS		0x000007ff
+#define AR5K_IFS0_SIFS_S	0
+#define AR5K_IFS0_DIFS		0x007ff800
+#define AR5K_IFS0_DIFS_S	11
+
+/*
+ * 5210 Second inter frame spacing register (IFS)
+ */
+#define AR5K_IFS1		0x8044
+#define AR5K_IFS1_PIFS		0x00000fff
+#define AR5K_IFS1_PIFS_S	0
+#define AR5K_IFS1_EIFS		0x03fff000
+#define AR5K_IFS1_EIFS_S	12
+#define AR5K_IFS1_CS_EN		0x04000000
+
+
+/*
+ * CFP duration register
+ */
+#define AR5K_CFP_DUR_5210	0x8048
+#define AR5K_CFP_DUR_5211	0x8038
+#define AR5K_CFP_DUR		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_CFP_DUR_5210 : AR5K_CFP_DUR_5211)
+
+/*
+ * Receive filter register
+ */
+#define AR5K_RX_FILTER_5210	0x804c			/* Register Address [5210] */
+#define AR5K_RX_FILTER_5211	0x803c			/* Register Address [5211+] */
+#define AR5K_RX_FILTER		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_RX_FILTER_5210 : AR5K_RX_FILTER_5211)
+#define	AR5K_RX_FILTER_UCAST 	0x00000001	/* Don't filter unicast frames */
+#define	AR5K_RX_FILTER_MCAST 	0x00000002	/* Don't filter multicast frames */
+#define	AR5K_RX_FILTER_BCAST 	0x00000004	/* Don't filter broadcast frames */
+#define	AR5K_RX_FILTER_CONTROL 	0x00000008	/* Don't filter control frames */
+#define	AR5K_RX_FILTER_BEACON 	0x00000010	/* Don't filter beacon frames */
+#define	AR5K_RX_FILTER_PROM 	0x00000020	/* Set promiscuous mode */
+#define	AR5K_RX_FILTER_XRPOLL 	0x00000040	/* Don't filter XR poll frame [5212+] */
+#define	AR5K_RX_FILTER_PROBEREQ 0x00000080	/* Don't filter probe requests [5212+] */
+#define	AR5K_RX_FILTER_PHYERR_5212	0x00000100	/* Don't filter phy errors [5212+] */
+#define	AR5K_RX_FILTER_RADARERR_5212 	0x00000200	/* Don't filter phy radar errors [5212+] */
+#define AR5K_RX_FILTER_PHYERR_5211	0x00000040	/* [5211] */
+#define AR5K_RX_FILTER_RADARERR_5211	0x00000080	/* [5211] */
+#define AR5K_RX_FILTER_PHYERR  \
+	((ah->ah_version == AR5K_AR5211 ? \
+	AR5K_RX_FILTER_PHYERR_5211 : AR5K_RX_FILTER_PHYERR_5212))
+#define        AR5K_RX_FILTER_RADARERR \
+	((ah->ah_version == AR5K_AR5211 ? \
+	AR5K_RX_FILTER_RADARERR_5211 : AR5K_RX_FILTER_RADARERR_5212))
+
+/*
+ * Multicast filter register (lower 32 bits)
+ */
+#define AR5K_MCAST_FILTER0_5210	0x8050
+#define AR5K_MCAST_FILTER0_5211	0x8040
+#define AR5K_MCAST_FILTER0	(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_MCAST_FILTER0_5210 : AR5K_MCAST_FILTER0_5211)
+
+/*
+ * Multicast filter register (higher 16 bits)
+ */
+#define AR5K_MCAST_FILTER1_5210	0x8054
+#define AR5K_MCAST_FILTER1_5211	0x8044
+#define AR5K_MCAST_FILTER1	(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_MCAST_FILTER1_5210 : AR5K_MCAST_FILTER1_5211)
+
+
+/*
+ * Transmit mask register (lower 32 bits) [5210]
+ */
+#define AR5K_TX_MASK0	0x8058
+
+/*
+ * Transmit mask register (higher 16 bits) [5210]
+ */
+#define AR5K_TX_MASK1	0x805c
+
+/*
+ * Clear transmit mask [5210]
+ */
+#define AR5K_CLR_TMASK	0x8060
+
+/*
+ * Trigger level register (before transmission) [5210]
+ */
+#define AR5K_TRIG_LVL	0x8064
+
+
+/*
+ * PCU control register
+ *
+ * Only DIS_RX is used in the code, the rest i guess are
+ * for tweaking/diagnostics.
+ */
+#define AR5K_DIAG_SW_5210		0x8068			/* Register Address [5210] */
+#define AR5K_DIAG_SW_5211		0x8048			/* Register Address [5211+] */
+#define AR5K_DIAG_SW			(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_5210 : AR5K_DIAG_SW_5211)
+#define AR5K_DIAG_SW_DIS_WEP_ACK	0x00000001	/* Disable ACKs if WEP key is invalid */
+#define AR5K_DIAG_SW_DIS_ACK		0x00000002	/* Disable ACKs */
+#define AR5K_DIAG_SW_DIS_CTS		0x00000004	/* Disable CTSs */
+#define AR5K_DIAG_SW_DIS_ENC		0x00000008	/* Disable encryption */
+#define AR5K_DIAG_SW_DIS_DEC		0x00000010	/* Disable decryption */
+#define AR5K_DIAG_SW_DIS_TX		0x00000020	/* Disable transmit [5210] */
+#define AR5K_DIAG_SW_DIS_RX_5210	0x00000040	/* Disable recieve */
+#define AR5K_DIAG_SW_DIS_RX_5211	0x00000020
+#define	AR5K_DIAG_SW_DIS_RX		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_DIS_RX_5210 : AR5K_DIAG_SW_DIS_RX_5211)
+#define AR5K_DIAG_SW_LOOP_BACK_5210	0x00000080	/* Loopback (i guess it goes with DIS_TX) [5210] */
+#define AR5K_DIAG_SW_LOOP_BACK_5211	0x00000040
+#define AR5K_DIAG_SW_LOOP_BACK		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211)
+#define AR5K_DIAG_SW_CORR_FCS_5210	0x00000100	/* Corrupted FCS */
+#define AR5K_DIAG_SW_CORR_FCS_5211	0x00000080
+#define AR5K_DIAG_SW_CORR_FCS		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211)
+#define AR5K_DIAG_SW_CHAN_INFO_5210	0x00000200	/* Dump channel info */
+#define AR5K_DIAG_SW_CHAN_INFO_5211	0x00000100
+#define AR5K_DIAG_SW_CHAN_INFO		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211)
+#define AR5K_DIAG_SW_EN_SCRAM_SEED_5210	0x00000400	/* Enable fixed scrambler seed */
+#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211	0x00000200
+#define AR5K_DIAG_SW_EN_SCRAM_SEED	(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_EN_SCRAM_SEED_5210 : AR5K_DIAG_SW_EN_SCRAM_SEED_5211)
+#define AR5K_DIAG_SW_ECO_ENABLE		0x00000400	/* [5211+] */
+#define AR5K_DIAG_SW_SCVRAM_SEED	0x0003f800	/* [5210] */
+#define AR5K_DIAG_SW_SCRAM_SEED_M	0x0001fc00	/* Scrambler seed mask */
+#define AR5K_DIAG_SW_SCRAM_SEED_S	10
+#define AR5K_DIAG_SW_DIS_SEQ_INC	0x00040000	/* Disable seqnum increment (?)[5210] */
+#define AR5K_DIAG_SW_FRAME_NV0_5210	0x00080000
+#define AR5K_DIAG_SW_FRAME_NV0_5211	0x00020000	/* Accept frames of non-zero protocol number */
+#define	AR5K_DIAG_SW_FRAME_NV0		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211)
+#define AR5K_DIAG_SW_OBSPT_M		0x000c0000	/* Observation point select (?) */
+#define AR5K_DIAG_SW_OBSPT_S		18
+#define AR5K_DIAG_SW_RX_CLEAR_HIGH	0x0010000	/* Force RX Clear high */
+#define AR5K_DIAG_SW_IGNORE_CARR_SENSE	0x0020000	/* Ignore virtual carrier sense */
+#define AR5K_DIAG_SW_CHANEL_IDLE_HIGH	0x0040000	/* Force channel idle high */
+#define AR5K_DIAG_SW_PHEAR_ME		0x0080000	/* ??? */
+
+/*
+ * TSF (clock) register (lower 32 bits)
+ */
+#define AR5K_TSF_L32_5210	0x806c
+#define AR5K_TSF_L32_5211	0x804c
+#define	AR5K_TSF_L32		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211)
+
+/*
+ * TSF (clock) register (higher 32 bits)
+ */
+#define AR5K_TSF_U32_5210	0x8070
+#define AR5K_TSF_U32_5211	0x8050
+#define	AR5K_TSF_U32		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211)
+
+/*
+ * Last beacon timestamp register (Read Only)
+ */
+#define AR5K_LAST_TSTP	0x8080
+
+/*
+ * ADDAC test register [5211+]
+ */
+#define AR5K_ADDAC_TEST			0x8054			/* Register Address */
+#define AR5K_ADDAC_TEST_TXCONT 		0x00000001	/* Test continuous tx */
+#define AR5K_ADDAC_TEST_TST_MODE	0x00000002	/* Test mode */
+#define AR5K_ADDAC_TEST_LOOP_EN		0x00000004	/* Enable loop */
+#define AR5K_ADDAC_TEST_LOOP_LEN	0x00000008	/* Loop length (field) */
+#define AR5K_ADDAC_TEST_USE_U8		0x00004000	/* Use upper 8 bits */
+#define AR5K_ADDAC_TEST_MSB		0x00008000	/* State of MSB */
+#define AR5K_ADDAC_TEST_TRIG_SEL	0x00010000	/* Trigger select */
+#define AR5K_ADDAC_TEST_TRIG_PTY	0x00020000	/* Trigger polarity */
+#define AR5K_ADDAC_TEST_RXCONT		0x00040000	/* Continuous capture */
+#define AR5K_ADDAC_TEST_CAPTURE		0x00080000	/* Begin capture */
+#define AR5K_ADDAC_TEST_TST_ARM		0x00100000	/* ARM rx buffer for capture */
+
+/*
+ * Default antenna register [5211+]
+ */
+#define AR5K_DEFAULT_ANTENNA	0x8058
+
+/*
+ * Frame control QoS mask register (?) [5211+]
+ * (FC_QOS_MASK)
+ */
+#define AR5K_FRAME_CTL_QOSM	0x805c
+
+/*
+ * Seq mask register (?) [5211+]
+ */
+#define AR5K_SEQ_MASK	0x8060
+
+/*
+ * Retry count register [5210]
+ */
+#define AR5K_RETRY_CNT		0x8084			/* Register Address [5210] */
+#define AR5K_RETRY_CNT_SSH	0x0000003f	/* Station short retry count (?) */
+#define AR5K_RETRY_CNT_SLG	0x00000fc0	/* Station long retry count (?) */
+
+/*
+ * Back-off status register [5210]
+ */
+#define AR5K_BACKOFF		0x8088			/* Register Address [5210] */
+#define AR5K_BACKOFF_CW		0x000003ff	/* Backoff Contention Window (?) */
+#define AR5K_BACKOFF_CNT	0x03ff0000	/* Backoff count (?) */
+
+
+
+/*
+ * NAV register (current)
+ */
+#define AR5K_NAV_5210		0x808c
+#define AR5K_NAV_5211		0x8084
+#define	AR5K_NAV		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_NAV_5210 : AR5K_NAV_5211)
+
+/*
+ * RTS success register
+ */
+#define AR5K_RTS_OK_5210	0x8090
+#define AR5K_RTS_OK_5211	0x8088
+#define	AR5K_RTS_OK		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211)
+
+/*
+ * RTS failure register
+ */
+#define AR5K_RTS_FAIL_5210	0x8094
+#define AR5K_RTS_FAIL_5211	0x808c
+#define	AR5K_RTS_FAIL		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211)
+
+/*
+ * ACK failure register
+ */
+#define AR5K_ACK_FAIL_5210	0x8098
+#define AR5K_ACK_FAIL_5211	0x8090
+#define	AR5K_ACK_FAIL		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211)
+
+/*
+ * FCS failure register
+ */
+#define AR5K_FCS_FAIL_5210	0x809c
+#define AR5K_FCS_FAIL_5211	0x8094
+#define	AR5K_FCS_FAIL		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_FCS_FAIL_5210 : AR5K_FCS_FAIL_5211)
+
+/*
+ * Beacon count register
+ */
+#define AR5K_BEACON_CNT_5210	0x80a0
+#define AR5K_BEACON_CNT_5211	0x8098
+#define	AR5K_BEACON_CNT		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_BEACON_CNT_5210 : AR5K_BEACON_CNT_5211)
+
+
+/*===5212 Specific PCU registers===*/
+
+/*
+ * Transmit power control register
+ */
+#define AR5K_TPC			0x80e8
+#define AR5K_TPC_ACK			0x0000003f	/* ack frames */
+#define AR5K_TPC_ACK_S			0
+#define AR5K_TPC_CTS			0x00003f00	/* cts frames */
+#define AR5K_TPC_CTS_S			8
+#define AR5K_TPC_CHIRP			0x003f0000	/* chirp frames */
+#define AR5K_TPC_CHIRP_S		16
+#define AR5K_TPC_DOPPLER		0x0f000000	/* doppler chirp span */
+#define AR5K_TPC_DOPPLER_S		24
+
+/*
+ * XR (eXtended Range) mode register
+ */
+#define AR5K_XRMODE			0x80c0			/* Register Address */
+#define	AR5K_XRMODE_POLL_TYPE_M		0x0000003f	/* Mask for Poll type (?) */
+#define	AR5K_XRMODE_POLL_TYPE_S		0
+#define	AR5K_XRMODE_POLL_SUBTYPE_M	0x0000003c	/* Mask for Poll subtype (?) */
+#define	AR5K_XRMODE_POLL_SUBTYPE_S	2
+#define	AR5K_XRMODE_POLL_WAIT_ALL	0x00000080	/* Wait for poll */
+#define	AR5K_XRMODE_SIFS_DELAY		0x000fff00	/* Mask for SIFS delay */
+#define	AR5K_XRMODE_FRAME_HOLD_M	0xfff00000	/* Mask for frame hold (?) */
+#define	AR5K_XRMODE_FRAME_HOLD_S	20
+
+/*
+ * XR delay register
+ */
+#define AR5K_XRDELAY			0x80c4			/* Register Address */
+#define AR5K_XRDELAY_SLOT_DELAY_M	0x0000ffff	/* Mask for slot delay */
+#define AR5K_XRDELAY_SLOT_DELAY_S	0
+#define AR5K_XRDELAY_CHIRP_DELAY_M	0xffff0000	/* Mask for CHIRP data delay */
+#define AR5K_XRDELAY_CHIRP_DELAY_S	16
+
+/*
+ * XR timeout register
+ */
+#define AR5K_XRTIMEOUT			0x80c8			/* Register Address */
+#define AR5K_XRTIMEOUT_CHIRP_M		0x0000ffff	/* Mask for CHIRP timeout */
+#define AR5K_XRTIMEOUT_CHIRP_S		0
+#define AR5K_XRTIMEOUT_POLL_M		0xffff0000	/* Mask for Poll timeout */
+#define AR5K_XRTIMEOUT_POLL_S		16
+
+/*
+ * XR chirp register
+ */
+#define AR5K_XRCHIRP			0x80cc			/* Register Address */
+#define AR5K_XRCHIRP_SEND		0x00000001	/* Send CHIRP */
+#define AR5K_XRCHIRP_GAP		0xffff0000	/* Mask for CHIRP gap (?) */
+
+/*
+ * XR stomp register
+ */
+#define AR5K_XRSTOMP			0x80d0			/* Register Address */
+#define AR5K_XRSTOMP_TX			0x00000001	/* Stomp Tx (?) */
+#define AR5K_XRSTOMP_RX			0x00000002	/* Stomp Rx (?) */
+#define AR5K_XRSTOMP_TX_RSSI		0x00000004	/* Stomp Tx RSSI (?) */
+#define AR5K_XRSTOMP_TX_BSSID		0x00000008	/* Stomp Tx BSSID (?) */
+#define AR5K_XRSTOMP_DATA		0x00000010	/* Stomp data (?)*/
+#define AR5K_XRSTOMP_RSSI_THRES		0x0000ff00	/* Mask for XR RSSI threshold */
+
+/*
+ * First enhanced sleep register
+ */
+#define AR5K_SLEEP0			0x80d4			/* Register Address */
+#define AR5K_SLEEP0_NEXT_DTIM		0x0007ffff	/* Mask for next DTIM (?) */
+#define AR5K_SLEEP0_NEXT_DTIM_S		0
+#define AR5K_SLEEP0_ASSUME_DTIM		0x00080000	/* Assume DTIM */
+#define AR5K_SLEEP0_ENH_SLEEP_EN	0x00100000	/* Enable enchanced sleep control */
+#define AR5K_SLEEP0_CABTO		0xff000000	/* Mask for CAB Time Out */
+#define AR5K_SLEEP0_CABTO_S		24
+
+/*
+ * Second enhanced sleep register
+ */
+#define AR5K_SLEEP1			0x80d8			/* Register Address */
+#define AR5K_SLEEP1_NEXT_TIM		0x0007ffff	/* Mask for next TIM (?) */
+#define AR5K_SLEEP1_NEXT_TIM_S		0
+#define AR5K_SLEEP1_BEACON_TO		0xff000000	/* Mask for Beacon Time Out */
+#define AR5K_SLEEP1_BEACON_TO_S		24
+
+/*
+ * Third enhanced sleep register
+ */
+#define AR5K_SLEEP2			0x80dc			/* Register Address */
+#define AR5K_SLEEP2_TIM_PER		0x0000ffff	/* Mask for TIM period (?) */
+#define AR5K_SLEEP2_TIM_PER_S		0
+#define AR5K_SLEEP2_DTIM_PER		0xffff0000	/* Mask for DTIM period (?) */
+#define AR5K_SLEEP2_DTIM_PER_S		16
+
+/*
+ * BSSID mask registers
+ */
+#define AR5K_BSS_IDM0			0x80e0	/* Upper bits */
+#define AR5K_BSS_IDM1			0x80e4	/* Lower bits */
+
+/*
+ * TX power control (TPC) register
+ *
+ * XXX: PCDAC steps (0.5dbm) or DBM ?
+ *
+ */
+#define AR5K_TXPC			0x80e8			/* Register Address */
+#define AR5K_TXPC_ACK_M			0x0000003f	/* ACK tx power */
+#define AR5K_TXPC_ACK_S			0
+#define AR5K_TXPC_CTS_M			0x00003f00	/* CTS tx power */
+#define AR5K_TXPC_CTS_S			8
+#define AR5K_TXPC_CHIRP_M		0x003f0000	/* CHIRP tx power */
+#define AR5K_TXPC_CHIRP_S		16
+#define AR5K_TXPC_DOPPLER		0x0f000000	/* Doppler chirp span (?) */
+#define AR5K_TXPC_DOPPLER_S		24
+
+/*
+ * Profile count registers
+ */
+#define AR5K_PROFCNT_TX			0x80ec	/* Tx count */
+#define AR5K_PROFCNT_RX			0x80f0	/* Rx count */
+#define AR5K_PROFCNT_RXCLR		0x80f4	/* Clear Rx count */
+#define AR5K_PROFCNT_CYCLE		0x80f8	/* Cycle count (?) */
+
+/*
+ * Quiet period control registers
+ */
+#define AR5K_QUIET_CTL1			0x80fc			/* Register Address */
+#define AR5K_QUIET_CTL1_NEXT_QT_TSF	0x0000ffff	/* Next quiet period TSF (TU) */
+#define AR5K_QUIET_CTL1_NEXT_QT_TSF_S	0
+#define AR5K_QUIET_CTL1_QT_EN		0x00010000	/* Enable quiet period */
+#define AR5K_QUIET_CTL1_ACK_CTS_EN	0x00020000	/* Send ACK/CTS during quiet period */
+
+#define AR5K_QUIET_CTL2			0x8100			/* Register Address */
+#define AR5K_QUIET_CTL2_QT_PER		0x0000ffff	/* Mask for quiet period periodicity */
+#define AR5K_QUIET_CTL2_QT_PER_S	0
+#define AR5K_QUIET_CTL2_QT_DUR		0xffff0000	/* Mask for quiet period duration */
+#define AR5K_QUIET_CTL2_QT_DUR_S	16
+
+/*
+ * TSF parameter register
+ */
+#define AR5K_TSF_PARM			0x8104			/* Register Address */
+#define AR5K_TSF_PARM_INC		0x000000ff	/* Mask for TSF increment */
+#define AR5K_TSF_PARM_INC_S		0
+
+/*
+ * QoS NOACK policy
+ */
+#define AR5K_QOS_NOACK			0x8108			/* Register Address */
+#define AR5K_QOS_NOACK_2BIT_VALUES	0x0000000f	/* ??? */
+#define AR5K_QOS_NOACK_2BIT_VALUES_S	0
+#define AR5K_QOS_NOACK_BIT_OFFSET	0x00000070	/* ??? */
+#define AR5K_QOS_NOACK_BIT_OFFSET_S	4
+#define AR5K_QOS_NOACK_BYTE_OFFSET	0x00000180	/* ??? */
+#define AR5K_QOS_NOACK_BYTE_OFFSET_S	7
+
+/*
+ * PHY error filter register
+ */
+#define AR5K_PHY_ERR_FIL		0x810c
+#define AR5K_PHY_ERR_FIL_RADAR		0x00000020	/* Radar signal */
+#define AR5K_PHY_ERR_FIL_OFDM		0x00020000	/* OFDM false detect (ANI) */
+#define AR5K_PHY_ERR_FIL_CCK		0x02000000	/* CCK false detect (ANI) */
+
+/*
+ * XR latency register
+ */
+#define AR5K_XRLAT_TX		0x8110
+
+/*
+ * ACK SIFS register
+ */
+#define AR5K_ACKSIFS		0x8114			/* Register Address */
+#define AR5K_ACKSIFS_INC	0x00000000	/* ACK SIFS Increment (field) */
+
+/*
+ * MIC QoS control register (?)
+ */
+#define	AR5K_MIC_QOS_CTL		0x8118			/* Register Address */
+#define	AR5K_MIC_QOS_CTL_OFF(_n)	(1 << (_n * 2))
+#define	AR5K_MIC_QOS_CTL_MQ_EN		0x00010000	/* Enable MIC QoS */
+
+/*
+ * MIC QoS select register (?)
+ */
+#define	AR5K_MIC_QOS_SEL		0x811c
+#define	AR5K_MIC_QOS_SEL_OFF(_n)	(1 << (_n * 4))
+
+/*
+ * Misc mode control register (?)
+ */
+#define	AR5K_MISC_MODE			0x8120			/* Register Address */
+#define	AR5K_MISC_MODE_FBSSID_MATCH	0x00000001	/* Force BSSID match */
+#define	AR5K_MISC_MODE_ACKSIFS_MEM	0x00000002	/* ACK SIFS memory (?) */
+#define	AR5K_MISC_MODE_COMBINED_MIC	0x00000004	/* use rx/tx MIC key */
+/* more bits */
+
+/*
+ * OFDM Filter counter
+ */
+#define	AR5K_OFDM_FIL_CNT		0x8124
+
+/*
+ * CCK Filter counter
+ */
+#define	AR5K_CCK_FIL_CNT		0x8128
+
+/*
+ * PHY Error Counters (?)
+ */
+#define	AR5K_PHYERR_CNT1		0x812c
+#define	AR5K_PHYERR_CNT1_MASK		0x8130
+
+#define	AR5K_PHYERR_CNT2		0x8134
+#define	AR5K_PHYERR_CNT2_MASK		0x8138
+
+/*
+ * TSF Threshold register (?)
+ */
+#define	AR5K_TSF_THRES			0x813c
+
+/*
+ * TODO: Wake On Wireless registers
+ * Range: 0x8147 - 0x818c
+ */
+
+/*
+ * Rate -> ACK SIFS mapping table (32 entries)
+ */
+#define	AR5K_RATE_ACKSIFS_BASE		0x8680			/* Register Address */
+#define	AR5K_RATE_ACKSIFS(_n)		(AR5K_RATE_ACKSIFS_BSE + ((_n) << 2))
+#define	AR5K_RATE_ACKSIFS_NORMAL	0x00000001	/* Normal SIFS (field) */
+#define	AR5K_RATE_ACKSIFS_TURBO		0x00000400	/* Turbo SIFS (field) */
+
+/*
+ * Rate -> duration mapping table (32 entries)
+ */
+#define AR5K_RATE_DUR_BASE		0x8700
+#define AR5K_RATE_DUR(_n)		(AR5K_RATE_DUR_BASE + ((_n) << 2))
+
+/*
+ * Rate -> db mapping table
+ * (8 entries, each one has 4 8bit fields)
+ */
+#define AR5K_RATE2DB_BASE		0x87c0
+#define AR5K_RATE2DB(_n)		(AR5K_RATE2DB_BASE + ((_n) << 2))
+
+/*
+ * db -> Rate mapping table
+ * (8 entries, each one has 4 8bit fields)
+ */
+#define AR5K_DB2RATE_BASE		0x87e0
+#define AR5K_DB2RATE(_n)		(AR5K_DB2RATE_BASE + ((_n) << 2))
+
+/*===5212 end===*/
+
+/*
+ * Key table (WEP) register
+ */
+#define AR5K_KEYTABLE_0_5210		0x9000
+#define AR5K_KEYTABLE_0_5211		0x8800
+#define AR5K_KEYTABLE_5210(_n)		(AR5K_KEYTABLE_0_5210 + ((_n) << 5))
+#define AR5K_KEYTABLE_5211(_n)		(AR5K_KEYTABLE_0_5211 + ((_n) << 5))
+#define	AR5K_KEYTABLE(_n)		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n))
+#define AR5K_KEYTABLE_OFF(_n, x)	(AR5K_KEYTABLE(_n) + (x << 2))
+#define AR5K_KEYTABLE_TYPE(_n)		AR5K_KEYTABLE_OFF(_n, 5)
+#define AR5K_KEYTABLE_TYPE_40		0x00000000
+#define AR5K_KEYTABLE_TYPE_104		0x00000001
+#define AR5K_KEYTABLE_TYPE_128		0x00000003
+#define AR5K_KEYTABLE_TYPE_TKIP		0x00000004	/* [5212+] */
+#define AR5K_KEYTABLE_TYPE_AES		0x00000005	/* [5211+] */
+#define AR5K_KEYTABLE_TYPE_CCM		0x00000006	/* [5212+] */
+#define AR5K_KEYTABLE_TYPE_NULL		0x00000007	/* [5211+] */
+#define AR5K_KEYTABLE_ANTENNA		0x00000008	/* [5212+] */
+#define AR5K_KEYTABLE_MAC0(_n)		AR5K_KEYTABLE_OFF(_n, 6)
+#define AR5K_KEYTABLE_MAC1(_n)		AR5K_KEYTABLE_OFF(_n, 7)
+#define AR5K_KEYTABLE_VALID		0x00008000
+
+/* If key type is TKIP and MIC is enabled
+ * MIC key goes in offset entry + 64 */
+#define	AR5K_KEYTABLE_MIC_OFFSET	64
+
+/* WEP 40-bit	= 40-bit  entered key + 24 bit IV = 64-bit
+ * WEP 104-bit	= 104-bit entered key + 24-bit IV = 128-bit
+ * WEP 128-bit	= 128-bit entered key + 24 bit IV = 152-bit
+ *
+ * Some vendors have introduced bigger WEP keys to address
+ * security vulnerabilities in WEP. This includes:
+ *
+ * WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit
+ *
+ * We can expand this if we find ar5k Atheros cards with a larger
+ * key table size.
+ */
+#define AR5K_KEYTABLE_SIZE_5210		64
+#define AR5K_KEYTABLE_SIZE_5211		128
+#define	AR5K_KEYTABLE_SIZE		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211)
+
+
+/*===PHY REGISTERS===*/
+
+/*
+ * PHY registers start
+ */
+#define	AR5K_PHY_BASE			0x9800
+#define	AR5K_PHY(_n)			(AR5K_PHY_BASE + ((_n) << 2))
+
+/*
+ * TST_2 (Misc config parameters)
+ */
+#define	AR5K_PHY_TST2			0x9800			/* Register Address */
+#define AR5K_PHY_TST2_TRIG_SEL		0x00000007	/* Trigger select (?)*/
+#define AR5K_PHY_TST2_TRIG		0x00000010	/* Trigger (?) */
+#define AR5K_PHY_TST2_CBUS_MODE		0x00000060	/* Cardbus mode (?) */
+#define AR5K_PHY_TST2_CLK32		0x00000400	/* CLK_OUT is CLK32 (32Khz external) */
+#define AR5K_PHY_TST2_CHANCOR_DUMP_EN	0x00000800	/* Enable Chancor dump (?) */
+#define AR5K_PHY_TST2_EVEN_CHANCOR_DUMP	0x00001000	/* Even Chancor dump (?) */
+#define AR5K_PHY_TST2_RFSILENT_EN	0x00002000	/* Enable RFSILENT */
+#define AR5K_PHY_TST2_ALT_RFDATA	0x00004000	/* Alternate RFDATA (5-2GHz switch ?) */
+#define AR5K_PHY_TST2_MINI_OBS_EN	0x00008000	/* Enable mini OBS (?) */
+#define AR5K_PHY_TST2_RX2_IS_RX5_INV	0x00010000	/* 2GHz rx path is the 5GHz path inverted (?) */
+#define AR5K_PHY_TST2_SLOW_CLK160	0x00020000	/* Slow CLK160 (?) */
+#define AR5K_PHY_TST2_AGC_OBS_SEL_3	0x00040000	/* AGC OBS Select 3 (?) */
+#define AR5K_PHY_TST2_BBB_OBS_SEL	0x00080000	/* BB OBS Select (field ?) */
+#define AR5K_PHY_TST2_ADC_OBS_SEL	0x00800000	/* ADC OBS Select (field ?) */
+#define AR5K_PHY_TST2_RX_CLR_SEL	0x08000000	/* RX Clear Select (?) */
+#define AR5K_PHY_TST2_FORCE_AGC_CLR	0x10000000	/* Force AGC clear (?) */
+#define AR5K_PHY_SHIFT_2GHZ		0x00004007	/* Used to access 2GHz radios */
+#define AR5K_PHY_SHIFT_5GHZ		0x00000007	/* Used to access 5GHz radios (default) */
+
+/*
+ * PHY frame control register [5110] /turbo mode register [5111+]
+ *
+ * There is another frame control register for [5111+]
+ * at address 0x9944 (see below) but the 2 first flags
+ * are common here between 5110 frame control register
+ * and [5111+] turbo mode register, so this also works as
+ * a "turbo mode register" for 5110. We treat this one as
+ * a frame control register for 5110 below.
+ */
+#define	AR5K_PHY_TURBO			0x9804			/* Register Address */
+#define	AR5K_PHY_TURBO_MODE		0x00000001	/* Enable turbo mode */
+#define	AR5K_PHY_TURBO_SHORT		0x00000002	/* Set short symbols to turbo mode */
+#define	AR5K_PHY_TURBO_MIMO		0x00000004	/* Set turbo for mimo mimo */
+
+/*
+ * PHY agility command register
+ * (aka TST_1)
+ */
+#define	AR5K_PHY_AGC			0x9808			/* Register Address */
+#define	AR5K_PHY_TST1			0x9808
+#define	AR5K_PHY_AGC_DISABLE		0x08000000	/* Disable AGC to A2 (?)*/
+#define	AR5K_PHY_TST1_TXHOLD		0x00003800	/* Set tx hold (?) */
+#define	AR5K_PHY_TST1_TXSRC_SRC		0x00000002	/* Used with bit 7 (?) */
+#define	AR5K_PHY_TST1_TXSRC_SRC_S	1
+#define	AR5K_PHY_TST1_TXSRC_ALT		0x00000080	/* Set input to tsdac (?) */
+#define	AR5K_PHY_TST1_TXSRC_ALT_S	7
+
+
+/*
+ * PHY timing register 3 [5112+]
+ */
+#define	AR5K_PHY_TIMING_3		0x9814
+#define	AR5K_PHY_TIMING_3_DSC_MAN	0xfffe0000
+#define	AR5K_PHY_TIMING_3_DSC_MAN_S	17
+#define	AR5K_PHY_TIMING_3_DSC_EXP	0x0001e000
+#define	AR5K_PHY_TIMING_3_DSC_EXP_S	13
+
+/*
+ * PHY chip revision register
+ */
+#define	AR5K_PHY_CHIP_ID		0x9818
+
+/*
+ * PHY activation register
+ */
+#define	AR5K_PHY_ACT			0x981c			/* Register Address */
+#define	AR5K_PHY_ACT_ENABLE		0x00000001	/* Activate PHY */
+#define	AR5K_PHY_ACT_DISABLE		0x00000002	/* Deactivate PHY */
+
+/*
+ * PHY RF control registers
+ */
+#define AR5K_PHY_RF_CTL2		0x9824			/* Register Address */
+#define	AR5K_PHY_RF_CTL2_TXF2TXD_START	0x0000000f	/* TX frame to TX data start */
+#define	AR5K_PHY_RF_CTL2_TXF2TXD_START_S	0
+
+#define AR5K_PHY_RF_CTL3		0x9828			/* Register Address */
+#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON	0x0000ff00	/* TX end to XLNA on */
+#define	AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S	8
+
+#define	AR5K_PHY_ADC_CTL			0x982c
+#define	AR5K_PHY_ADC_CTL_INBUFGAIN_OFF		0x00000003
+#define	AR5K_PHY_ADC_CTL_INBUFGAIN_OFF_S	0
+#define	AR5K_PHY_ADC_CTL_PWD_DAC_OFF		0x00002000
+#define	AR5K_PHY_ADC_CTL_PWD_BAND_GAP_OFF	0x00004000
+#define	AR5K_PHY_ADC_CTL_PWD_ADC_OFF		0x00008000
+#define	AR5K_PHY_ADC_CTL_INBUFGAIN_ON		0x00030000
+#define	AR5K_PHY_ADC_CTL_INBUFGAIN_ON_S		16
+
+#define AR5K_PHY_RF_CTL4		0x9834			/* Register Address */
+#define AR5K_PHY_RF_CTL4_TXF2XPA_A_ON	0x00000001	/* TX frame to XPA A on (field) */
+#define AR5K_PHY_RF_CTL4_TXF2XPA_B_ON	0x00000100	/* TX frame to XPA B on (field) */
+#define	AR5K_PHY_RF_CTL4_TXE2XPA_A_OFF	0x00010000	/* TX end to XPA A off (field) */
+#define AR5K_PHY_RF_CTL4_TXE2XPA_B_OFF	0x01000000	/* TX end to XPA B off (field) */
+
+/*
+ * Pre-Amplifier control register
+ * (XPA -> external pre-amplifier)
+ */
+#define	AR5K_PHY_PA_CTL			0x9838			/* Register Address */
+#define	AR5K_PHY_PA_CTL_XPA_A_HI	0x00000001	/* XPA A high (?) */
+#define	AR5K_PHY_PA_CTL_XPA_B_HI	0x00000002	/* XPA B high (?) */
+#define	AR5K_PHY_PA_CTL_XPA_A_EN	0x00000004	/* Enable XPA A */
+#define	AR5K_PHY_PA_CTL_XPA_B_EN	0x00000008	/* Enable XPA B */
+
+/*
+ * PHY settling register
+ */
+#define AR5K_PHY_SETTLING		0x9844			/* Register Address */
+#define	AR5K_PHY_SETTLING_AGC		0x0000007f	/* AGC settling time */
+#define	AR5K_PHY_SETTLING_AGC_S		0
+#define	AR5K_PHY_SETTLING_SWITCH	0x00003f80	/* Switch settlig time */
+#define	AR5K_PHY_SETTLING_SWITCH_S	7
+
+/*
+ * PHY Gain registers
+ */
+#define AR5K_PHY_GAIN			0x9848			/* Register Address */
+#define	AR5K_PHY_GAIN_TXRX_ATTEN	0x0003f000	/* TX-RX Attenuation */
+#define	AR5K_PHY_GAIN_TXRX_ATTEN_S	12
+#define	AR5K_PHY_GAIN_TXRX_RF_MAX	0x007c0000
+#define	AR5K_PHY_GAIN_TXRX_RF_MAX_S	18
+
+#define	AR5K_PHY_GAIN_OFFSET		0x984c			/* Register Address */
+#define	AR5K_PHY_GAIN_OFFSET_RXTX_FLAG	0x00020000	/* RX-TX flag (?) */
+
+/*
+ * Desired ADC/PGA size register
+ * (for more infos read ANI patent)
+ */
+#define AR5K_PHY_DESIRED_SIZE		0x9850			/* Register Address */
+#define	AR5K_PHY_DESIRED_SIZE_ADC	0x000000ff	/* ADC desired size */
+#define	AR5K_PHY_DESIRED_SIZE_ADC_S	0
+#define	AR5K_PHY_DESIRED_SIZE_PGA	0x0000ff00	/* PGA desired size */
+#define	AR5K_PHY_DESIRED_SIZE_PGA_S	8
+#define	AR5K_PHY_DESIRED_SIZE_TOT	0x0ff00000	/* Total desired size */
+#define	AR5K_PHY_DESIRED_SIZE_TOT_S	20
+
+/*
+ * PHY signal register
+ * (for more infos read ANI patent)
+ */
+#define	AR5K_PHY_SIG			0x9858			/* Register Address */
+#define	AR5K_PHY_SIG_FIRSTEP		0x0003f000	/* FIRSTEP */
+#define	AR5K_PHY_SIG_FIRSTEP_S		12
+#define	AR5K_PHY_SIG_FIRPWR		0x03fc0000	/* FIPWR */
+#define	AR5K_PHY_SIG_FIRPWR_S		18
+
+/*
+ * PHY coarse agility control register
+ * (for more infos read ANI patent)
+ */
+#define	AR5K_PHY_AGCCOARSE		0x985c			/* Register Address */
+#define	AR5K_PHY_AGCCOARSE_LO		0x00007f80	/* AGC Coarse low */
+#define	AR5K_PHY_AGCCOARSE_LO_S		7
+#define	AR5K_PHY_AGCCOARSE_HI		0x003f8000	/* AGC Coarse high */
+#define	AR5K_PHY_AGCCOARSE_HI_S		15
+
+/*
+ * PHY agility control register
+ */
+#define	AR5K_PHY_AGCCTL			0x9860			/* Register address */
+#define	AR5K_PHY_AGCCTL_CAL		0x00000001	/* Enable PHY calibration */
+#define	AR5K_PHY_AGCCTL_NF		0x00000002	/* Enable Noise Floor calibration */
+#define	AR5K_PHY_AGCCTL_NF_EN		0x00008000	/* Enable nf calibration to happen (?) */
+#define	AR5K_PHY_AGCCTL_NF_NOUPDATE	0x00020000	/* Don't update nf automaticaly */
+
+/*
+ * PHY noise floor status register
+ */
+#define AR5K_PHY_NF			0x9864			/* Register address */
+#define AR5K_PHY_NF_M			0x000001ff	/* Noise floor mask */
+#define AR5K_PHY_NF_ACTIVE		0x00000100	/* Noise floor calibration still active */
+#define AR5K_PHY_NF_RVAL(_n)		(((_n) >> 19) & AR5K_PHY_NF_M)
+#define AR5K_PHY_NF_AVAL(_n)		(-((_n) ^ AR5K_PHY_NF_M) + 1)
+#define AR5K_PHY_NF_SVAL(_n)		(((_n) & AR5K_PHY_NF_M) | (1 << 9))
+#define	AR5K_PHY_NF_THRESH62		0x0007f000	/* Thresh62 -check ANI patent- (field) */
+#define	AR5K_PHY_NF_THRESH62_S		12
+#define	AR5K_PHY_NF_MINCCA_PWR		0x0ff80000	/* ??? */
+#define	AR5K_PHY_NF_MINCCA_PWR_S	19
+
+/*
+ * PHY ADC saturation register [5110]
+ */
+#define	AR5K_PHY_ADCSAT			0x9868
+#define	AR5K_PHY_ADCSAT_ICNT		0x0001f800
+#define	AR5K_PHY_ADCSAT_ICNT_S		11
+#define	AR5K_PHY_ADCSAT_THR		0x000007e0
+#define	AR5K_PHY_ADCSAT_THR_S		5
+
+/*
+ * PHY Weak ofdm signal detection threshold registers (ANI) [5212+]
+ */
+
+/* High thresholds */
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR		0x9868
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT	0x0000001f
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT_S	0
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1		0x00fe0000
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1_S	17
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2		0x7f000000
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_S	24
+
+/* Low thresholds */
+#define AR5K_PHY_WEAK_OFDM_LOW_THR 		0x986c
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN	0x00000001
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT	0x00003f00
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT_S	8
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M1		0x001fc000
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M1_S		14
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2		0x0fe00000
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_S		21
+
+
+/*
+ * PHY sleep registers [5112+]
+ */
+#define AR5K_PHY_SCR			0x9870
+
+#define AR5K_PHY_SLMT			0x9874
+#define AR5K_PHY_SLMT_32MHZ		0x0000007f
+
+#define AR5K_PHY_SCAL			0x9878
+#define AR5K_PHY_SCAL_32MHZ		0x0000000e
+#define	AR5K_PHY_SCAL_32MHZ_2417	0x0000000a
+#define	AR5K_PHY_SCAL_32MHZ_HB63	0x00000032
+
+/*
+ * PHY PLL (Phase Locked Loop) control register
+ */
+#define	AR5K_PHY_PLL			0x987c
+#define	AR5K_PHY_PLL_20MHZ		0x00000013	/* For half rate (?) */
+/* 40MHz -> 5GHz band */
+#define	AR5K_PHY_PLL_40MHZ_5211		0x00000018
+#define	AR5K_PHY_PLL_40MHZ_5212		0x000000aa
+#define	AR5K_PHY_PLL_40MHZ_5413		0x00000004
+#define	AR5K_PHY_PLL_40MHZ		(ah->ah_version == AR5K_AR5211 ? \
+					AR5K_PHY_PLL_40MHZ_5211 : AR5K_PHY_PLL_40MHZ_5212)
+/* 44MHz -> 2.4GHz band */
+#define	AR5K_PHY_PLL_44MHZ_5211		0x00000019
+#define	AR5K_PHY_PLL_44MHZ_5212		0x000000ab
+#define	AR5K_PHY_PLL_44MHZ		(ah->ah_version == AR5K_AR5211 ? \
+					AR5K_PHY_PLL_44MHZ_5211 : AR5K_PHY_PLL_44MHZ_5212)
+
+#define AR5K_PHY_PLL_RF5111		0x00000000
+#define AR5K_PHY_PLL_RF5112		0x00000040
+#define	AR5K_PHY_PLL_HALF_RATE		0x00000100
+#define	AR5K_PHY_PLL_QUARTER_RATE	0x00000200
+
+/*
+ * RF Buffer register
+ *
+ * It's obvious from the code that 0x989c is the buffer register but
+ * for the other special registers that we write to after sending each
+ * packet, i have no idea. So i'll name them BUFFER_CONTROL_X registers
+ * for now. It's interesting that they are also used for some other operations.
+ */
+
+#define AR5K_RF_BUFFER			0x989c
+#define AR5K_RF_BUFFER_CONTROL_0	0x98c0	/* Channel on 5110 */
+#define AR5K_RF_BUFFER_CONTROL_1	0x98c4	/* Bank 7 on 5112 */
+#define AR5K_RF_BUFFER_CONTROL_2	0x98cc	/* Bank 7 on 5111 */
+
+#define AR5K_RF_BUFFER_CONTROL_3	0x98d0	/* Bank 2 on 5112 */
+						/* Channel set on 5111 */
+						/* Used to read radio revision*/
+
+#define AR5K_RF_BUFFER_CONTROL_4	0x98d4  /* RF Stage register on 5110 */
+						/* Bank 0,1,2,6 on 5111 */
+						/* Bank 1 on 5112 */
+						/* Used during activation on 5111 */
+
+#define AR5K_RF_BUFFER_CONTROL_5	0x98d8	/* Bank 3 on 5111 */
+						/* Used during activation on 5111 */
+						/* Channel on 5112 */
+						/* Bank 6 on 5112 */
+
+#define AR5K_RF_BUFFER_CONTROL_6	0x98dc	/* Bank 3 on 5112 */
+
+/*
+ * PHY RF stage register [5210]
+ */
+#define AR5K_PHY_RFSTG			0x98d4
+#define AR5K_PHY_RFSTG_DISABLE		0x00000021
+
+/*
+ * BIN masks (?)
+ */
+#define	AR5K_PHY_BIN_MASK_1	0x9900
+#define	AR5K_PHY_BIN_MASK_2	0x9904
+#define	AR5K_PHY_BIN_MASK_3	0x9908
+
+#define	AR5K_PHY_BIN_MASK_CTL		0x990c
+#define	AR5K_PHY_BIN_MASK_CTL_MASK_4	0x00003fff
+#define	AR5K_PHY_BIN_MASK_CTL_MASK_4_S	0
+#define	AR5K_PHY_BIN_MASK_CTL_RATE	0xff000000
+#define	AR5K_PHY_BIN_MASK_CTL_RATE_S	24
+
+/*
+ * PHY Antenna control register
+ */
+#define AR5K_PHY_ANT_CTL		0x9910			/* Register Address */
+#define	AR5K_PHY_ANT_CTL_TXRX_EN	0x00000001	/* Enable TX/RX (?) */
+#define	AR5K_PHY_ANT_CTL_SECTORED_ANT	0x00000004	/* Sectored Antenna */
+#define	AR5K_PHY_ANT_CTL_HITUNE5	0x00000008	/* Hitune5 (?) */
+#define	AR5K_PHY_ANT_CTL_SWTABLE_IDLE	0x000003f0	/* Switch table idle (?) */
+#define	AR5K_PHY_ANT_CTL_SWTABLE_IDLE_S	4
+
+/*
+ * PHY receiver delay register [5111+]
+ */
+#define	AR5K_PHY_RX_DELAY		0x9914			/* Register Address */
+#define	AR5K_PHY_RX_DELAY_M		0x00003fff	/* Mask for RX activate to receive delay (/100ns) */
+
+/*
+ * PHY max rx length register (?) [5111]
+ */
+#define	AR5K_PHY_MAX_RX_LEN		0x991c
+
+/*
+ * PHY timing register 4
+ * I(nphase)/Q(adrature) calibration register [5111+]
+ */
+#define	AR5K_PHY_IQ			0x9920			/* Register Address */
+#define	AR5K_PHY_IQ_CORR_Q_Q_COFF	0x0000001f	/* Mask for q correction info */
+#define	AR5K_PHY_IQ_CORR_Q_I_COFF	0x000007e0	/* Mask for i correction info */
+#define	AR5K_PHY_IQ_CORR_Q_I_COFF_S	5
+#define	AR5K_PHY_IQ_CORR_ENABLE		0x00000800	/* Enable i/q correction */
+#define	AR5K_PHY_IQ_CAL_NUM_LOG_MAX	0x0000f000	/* Mask for max number of samples in log scale */
+#define	AR5K_PHY_IQ_CAL_NUM_LOG_MAX_S	12
+#define	AR5K_PHY_IQ_RUN			0x00010000	/* Run i/q calibration */
+#define	AR5K_PHY_IQ_USE_PT_DF		0x00020000	/* Use pilot track df (?) */
+#define	AR5K_PHY_IQ_EARLY_TRIG_THR	0x00200000	/* Early trigger threshold (?) (field) */
+#define	AR5K_PHY_IQ_PILOT_MASK_EN	0x10000000	/* Enable pilot mask (?) */
+#define	AR5K_PHY_IQ_CHAN_MASK_EN	0x20000000	/* Enable channel mask (?) */
+#define	AR5K_PHY_IQ_SPUR_FILT_EN	0x40000000	/* Enable spur filter */
+#define	AR5K_PHY_IQ_SPUR_RSSI_EN	0x80000000	/* Enable spur rssi */
+
+/*
+ * PHY timing register 5
+ * OFDM Self-correlator Cyclic RSSI threshold params
+ * (Check out bb_cycpwr_thr1 on ANI patent)
+ */
+#define	AR5K_PHY_OFDM_SELFCORR			0x9924			/* Register Address */
+#define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_EN	0x00000001	/* Enable cyclic RSSI thr 1 */
+#define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1	0x000000fe	/* Mask for Cyclic RSSI threshold 1 */
+#define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_S	1
+#define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR3	0x00000100	/* Cyclic RSSI threshold 3 (field) (?) */
+#define	AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR_EN	0x00008000	/* Enable 1A RSSI threshold (?) */
+#define	AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR	0x00010000	/* 1A RSSI threshold (field) (?) */
+#define	AR5K_PHY_OFDM_SELFCORR_LSCTHR_HIRSSI	0x00800000	/* Long sc threshold hi rssi (?) */
+
+/*
+ * PHY-only warm reset register
+ */
+#define	AR5K_PHY_WARM_RESET		0x9928
+
+/*
+ * PHY-only control register
+ */
+#define AR5K_PHY_CTL			0x992c			/* Register Address */
+#define	AR5K_PHY_CTL_RX_DRAIN_RATE	0x00000001	/* RX drain rate (?) */
+#define	AR5K_PHY_CTL_LATE_TX_SIG_SYM	0x00000002	/* Late tx signal symbol (?) */
+#define	AR5K_PHY_CTL_GEN_SCRAMBLER	0x00000004	/* Generate scrambler */
+#define	AR5K_PHY_CTL_TX_ANT_SEL		0x00000008	/* TX antenna select */
+#define	AR5K_PHY_CTL_TX_ANT_STATIC	0x00000010	/* Static TX antenna */
+#define	AR5K_PHY_CTL_RX_ANT_SEL		0x00000020	/* RX antenna select */
+#define	AR5K_PHY_CTL_RX_ANT_STATIC	0x00000040	/* Static RX antenna */
+#define	AR5K_PHY_CTL_LOW_FREQ_SLE_EN	0x00000080	/* Enable low freq sleep */
+
+/*
+ * PHY PAPD probe register [5111+]
+ */
+#define	AR5K_PHY_PAPD_PROBE		0x9930
+#define	AR5K_PHY_PAPD_PROBE_SH_HI_PAR	0x00000001
+#define	AR5K_PHY_PAPD_PROBE_PCDAC_BIAS	0x00000002
+#define	AR5K_PHY_PAPD_PROBE_COMP_GAIN	0x00000040
+#define	AR5K_PHY_PAPD_PROBE_TXPOWER	0x00007e00
+#define	AR5K_PHY_PAPD_PROBE_TXPOWER_S	9
+#define	AR5K_PHY_PAPD_PROBE_TX_NEXT	0x00008000
+#define	AR5K_PHY_PAPD_PROBE_PREDIST_EN	0x00010000
+#define	AR5K_PHY_PAPD_PROBE_TYPE	0x01800000	/* [5112+] */
+#define	AR5K_PHY_PAPD_PROBE_TYPE_S	23
+#define	AR5K_PHY_PAPD_PROBE_TYPE_OFDM	0
+#define	AR5K_PHY_PAPD_PROBE_TYPE_XR	1
+#define	AR5K_PHY_PAPD_PROBE_TYPE_CCK	2
+#define	AR5K_PHY_PAPD_PROBE_GAINF	0xfe000000
+#define	AR5K_PHY_PAPD_PROBE_GAINF_S	25
+#define	AR5K_PHY_PAPD_PROBE_INI_5111	0x00004883	/* [5212+] */
+#define	AR5K_PHY_PAPD_PROBE_INI_5112	0x00004882	/* [5212+] */
+
+/*
+ * PHY TX rate power registers [5112+]
+ */
+#define	AR5K_PHY_TXPOWER_RATE1			0x9934
+#define	AR5K_PHY_TXPOWER_RATE2			0x9938
+#define	AR5K_PHY_TXPOWER_RATE_MAX		0x993c
+#define	AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE	0x00000040
+#define	AR5K_PHY_TXPOWER_RATE3			0xa234
+#define	AR5K_PHY_TXPOWER_RATE4			0xa238
+
+/*
+ * PHY frame control register [5111+]
+ */
+#define	AR5K_PHY_FRAME_CTL_5210		0x9804
+#define	AR5K_PHY_FRAME_CTL_5211		0x9944
+#define	AR5K_PHY_FRAME_CTL		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_PHY_FRAME_CTL_5210 : AR5K_PHY_FRAME_CTL_5211)
+/*---[5111+]---*/
+#define	AR5K_PHY_FRAME_CTL_TX_CLIP	0x00000038	/* Mask for tx clip (?) */
+#define	AR5K_PHY_FRAME_CTL_TX_CLIP_S	3
+#define	AR5K_PHY_FRAME_CTL_PREP_CHINFO	0x00010000	/* Prepend chan info */
+#define	AR5K_PHY_FRAME_CTL_EMU		0x80000000
+#define	AR5K_PHY_FRAME_CTL_EMU_S	31
+/*---[5110/5111]---*/
+#define	AR5K_PHY_FRAME_CTL_TIMING_ERR	0x01000000	/* PHY timing error */
+#define	AR5K_PHY_FRAME_CTL_PARITY_ERR	0x02000000	/* Parity error */
+#define	AR5K_PHY_FRAME_CTL_ILLRATE_ERR	0x04000000	/* Illegal rate */
+#define	AR5K_PHY_FRAME_CTL_ILLLEN_ERR	0x08000000	/* Illegal length */
+#define	AR5K_PHY_FRAME_CTL_SERVICE_ERR	0x20000000
+#define	AR5K_PHY_FRAME_CTL_TXURN_ERR	0x40000000	/* TX underrun */
+#define AR5K_PHY_FRAME_CTL_INI		AR5K_PHY_FRAME_CTL_SERVICE_ERR | \
+			AR5K_PHY_FRAME_CTL_TXURN_ERR | \
+			AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \
+			AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \
+			AR5K_PHY_FRAME_CTL_PARITY_ERR | \
+			AR5K_PHY_FRAME_CTL_TIMING_ERR
+
+/*
+ * PHY Tx Power adjustment register [5212A+]
+ */
+#define	AR5K_PHY_TX_PWR_ADJ			0x994c
+#define	AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA	0x00000fc0
+#define	AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA_S	6
+#define	AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX	0x00fc0000
+#define	AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX_S	18
+
+/*
+ * PHY radar detection register [5111+]
+ */
+#define	AR5K_PHY_RADAR			0x9954
+#define	AR5K_PHY_RADAR_ENABLE		0x00000001
+#define	AR5K_PHY_RADAR_DISABLE		0x00000000
+#define AR5K_PHY_RADAR_INBANDTHR    	0x0000003e	/* Inband threshold
+							5-bits, units unknown {0..31}
+							(? MHz ?) */
+#define AR5K_PHY_RADAR_INBANDTHR_S	1
+
+#define AR5K_PHY_RADAR_PRSSI_THR    	0x00000fc0	/* Pulse RSSI/SNR threshold
+							6-bits, dBm range {0..63}
+							in dBm units. */
+#define AR5K_PHY_RADAR_PRSSI_THR_S	6
+
+#define AR5K_PHY_RADAR_PHEIGHT_THR   	0x0003f000	/* Pulse height threshold
+							6-bits, dBm range {0..63}
+							in dBm units. */
+#define AR5K_PHY_RADAR_PHEIGHT_THR_S	12
+
+#define AR5K_PHY_RADAR_RSSI_THR    	0x00fc0000	/* Radar RSSI/SNR threshold.
+							6-bits, dBm range {0..63}
+							in dBm units. */
+#define AR5K_PHY_RADAR_RSSI_THR_S	18
+
+#define AR5K_PHY_RADAR_FIRPWR_THR	0x7f000000	/* Finite Impulse Response
+							filter power out threshold.
+							7-bits, standard power range
+							{0..127} in 1/2 dBm units. */
+#define AR5K_PHY_RADAR_FIRPWR_THRS	24
+
+/*
+ * PHY antenna switch table registers
+ */
+#define AR5K_PHY_ANT_SWITCH_TABLE_0	0x9960
+#define AR5K_PHY_ANT_SWITCH_TABLE_1	0x9964
+
+/*
+ * PHY Noise floor threshold
+ */
+#define AR5K_PHY_NFTHRES		0x9968
+
+/*
+ * Sigma Delta register (?) [5213]
+ */
+#define AR5K_PHY_SIGMA_DELTA		0x996C
+#define AR5K_PHY_SIGMA_DELTA_ADC_SEL	0x00000003
+#define AR5K_PHY_SIGMA_DELTA_ADC_SEL_S	0
+#define AR5K_PHY_SIGMA_DELTA_FILT2	0x000000f8
+#define AR5K_PHY_SIGMA_DELTA_FILT2_S	3
+#define AR5K_PHY_SIGMA_DELTA_FILT1	0x00001f00
+#define AR5K_PHY_SIGMA_DELTA_FILT1_S	8
+#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP	0x01ffe000
+#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP_S	13
+
+/*
+ * RF restart register [5112+] (?)
+ */
+#define AR5K_PHY_RESTART		0x9970		/* restart */
+#define AR5K_PHY_RESTART_DIV_GC		0x001c0000	/* Fast diversity gc_limit (?) */
+#define AR5K_PHY_RESTART_DIV_GC_S	18
+
+/*
+ * RF Bus access request register (for synth-oly channel switching)
+ */
+#define AR5K_PHY_RFBUS_REQ		0x997C
+#define AR5K_PHY_RFBUS_REQ_REQUEST	0x00000001
+
+/*
+ * Spur mitigation masks (?)
+ */
+#define AR5K_PHY_TIMING_7		0x9980
+#define AR5K_PHY_TIMING_8		0x9984
+#define AR5K_PHY_TIMING_8_PILOT_MASK_2		0x000fffff
+#define AR5K_PHY_TIMING_8_PILOT_MASK_2_S	0
+
+#define AR5K_PHY_BIN_MASK2_1		0x9988
+#define AR5K_PHY_BIN_MASK2_2		0x998c
+#define AR5K_PHY_BIN_MASK2_3		0x9990
+
+#define AR5K_PHY_BIN_MASK2_4		0x9994
+#define AR5K_PHY_BIN_MASK2_4_MASK_4	0x00003fff
+#define AR5K_PHY_BIN_MASK2_4_MASK_4_S	0
+
+#define AR5K_PHY_TIMING_9			0x9998
+#define AR5K_PHY_TIMING_10			0x999c
+#define AR5K_PHY_TIMING_10_PILOT_MASK_2		0x000fffff
+#define AR5K_PHY_TIMING_10_PILOT_MASK_2_S	0
+
+/*
+ * Spur mitigation control
+ */
+#define AR5K_PHY_TIMING_11			0x99a0		/* Register address */
+#define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE	0x000fffff	/* Spur delta phase */
+#define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE_S	0
+#define AR5K_PHY_TIMING_11_SPUR_FREQ_SD		0x3ff00000	/* Freq sigma delta */
+#define AR5K_PHY_TIMING_11_SPUR_FREQ_SD_S	20
+#define AR5K_PHY_TIMING_11_USE_SPUR_IN_AGC	0x40000000	/* Spur filter in AGC detector */
+#define AR5K_PHY_TIMING_11_USE_SPUR_IN_SELFCOR	0x80000000	/* Spur filter in OFDM self correlator */
+
+/*
+ * Gain tables
+ */
+#define	AR5K_BB_GAIN_BASE		0x9b00	/* BaseBand Amplifier Gain table base address */
+#define AR5K_BB_GAIN(_n)		(AR5K_BB_GAIN_BASE + ((_n) << 2))
+#define	AR5K_RF_GAIN_BASE		0x9a00	/* RF Amplrifier Gain table base address */
+#define AR5K_RF_GAIN(_n)		(AR5K_RF_GAIN_BASE + ((_n) << 2))
+
+/*
+ * PHY timing IQ calibration result register [5111+]
+ */
+#define	AR5K_PHY_IQRES_CAL_PWR_I	0x9c10	/* I (Inphase) power value */
+#define	AR5K_PHY_IQRES_CAL_PWR_Q	0x9c14	/* Q (Quadrature) power value */
+#define	AR5K_PHY_IQRES_CAL_CORR		0x9c18	/* I/Q Correlation */
+
+/*
+ * PHY current RSSI register [5111+]
+ */
+#define	AR5K_PHY_CURRENT_RSSI	0x9c1c
+
+/*
+ * PHY RF Bus grant register
+ */
+#define	AR5K_PHY_RFBUS_GRANT	0x9c20
+#define	AR5K_PHY_RFBUS_GRANT_OK	0x00000001
+
+/*
+ * PHY ADC test register
+ */
+#define	AR5K_PHY_ADC_TEST	0x9c24
+#define	AR5K_PHY_ADC_TEST_I	0x00000001
+#define	AR5K_PHY_ADC_TEST_Q	0x00000200
+
+/*
+ * PHY DAC test register
+ */
+#define	AR5K_PHY_DAC_TEST	0x9c28
+#define	AR5K_PHY_DAC_TEST_I	0x00000001
+#define	AR5K_PHY_DAC_TEST_Q	0x00000200
+
+/*
+ * PHY PTAT register (?)
+ */
+#define	AR5K_PHY_PTAT		0x9c2c
+
+/*
+ * PHY Illegal TX rate register [5112+]
+ */
+#define	AR5K_PHY_BAD_TX_RATE	0x9c30
+
+/*
+ * PHY SPUR Power register [5112+]
+ */
+#define	AR5K_PHY_SPUR_PWR	0x9c34			/* Register Address */
+#define	AR5K_PHY_SPUR_PWR_I	0x00000001	/* SPUR Power estimate for I (field) */
+#define	AR5K_PHY_SPUR_PWR_Q	0x00000100	/* SPUR Power estimate for Q (field) */
+#define	AR5K_PHY_SPUR_PWR_FILT	0x00010000	/* Power with SPUR removed (field) */
+
+/*
+ * PHY Channel status register [5112+] (?)
+ */
+#define	AR5K_PHY_CHAN_STATUS		0x9c38
+#define	AR5K_PHY_CHAN_STATUS_BT_ACT	0x00000001
+#define	AR5K_PHY_CHAN_STATUS_RX_CLR_RAW	0x00000002
+#define	AR5K_PHY_CHAN_STATUS_RX_CLR_MAC	0x00000004
+#define	AR5K_PHY_CHAN_STATUS_RX_CLR_PAP	0x00000008
+
+/*
+ * Heavy clip enable register
+ */
+#define	AR5K_PHY_HEAVY_CLIP_ENABLE	0x99e0
+
+/*
+ * PHY clock sleep registers [5112+]
+ */
+#define AR5K_PHY_SCLOCK			0x99f0
+#define AR5K_PHY_SCLOCK_32MHZ		0x0000000c
+#define AR5K_PHY_SDELAY			0x99f4
+#define AR5K_PHY_SDELAY_32MHZ		0x000000ff
+#define AR5K_PHY_SPENDING		0x99f8
+
+
+/*
+ * PHY PAPD I (power?) table (?)
+ * (92! entries)
+ */
+#define	AR5K_PHY_PAPD_I_BASE	0xa000
+#define	AR5K_PHY_PAPD_I(_n)	(AR5K_PHY_PAPD_I_BASE + ((_n) << 2))
+
+/*
+ * PHY PCDAC TX power table
+ */
+#define	AR5K_PHY_PCDAC_TXPOWER_BASE	0xa180
+#define	AR5K_PHY_PCDAC_TXPOWER(_n)	(AR5K_PHY_PCDAC_TXPOWER_BASE + ((_n) << 2))
+
+/*
+ * PHY mode register [5111+]
+ */
+#define	AR5K_PHY_MODE			0x0a200			/* Register Address */
+#define	AR5K_PHY_MODE_MOD		0x00000001	/* PHY Modulation bit */
+#define AR5K_PHY_MODE_MOD_OFDM		0
+#define AR5K_PHY_MODE_MOD_CCK		1
+#define AR5K_PHY_MODE_FREQ		0x00000002	/* Freq mode bit */
+#define	AR5K_PHY_MODE_FREQ_5GHZ		0
+#define	AR5K_PHY_MODE_FREQ_2GHZ		2
+#define AR5K_PHY_MODE_MOD_DYN		0x00000004	/* Enable Dynamic OFDM/CCK mode [5112+] */
+#define AR5K_PHY_MODE_RAD		0x00000008	/* [5212+] */
+#define AR5K_PHY_MODE_RAD_RF5111	0
+#define AR5K_PHY_MODE_RAD_RF5112	8
+#define AR5K_PHY_MODE_XR		0x00000010	/* Enable XR mode [5112+] */
+#define	AR5K_PHY_MODE_HALF_RATE		0x00000020	/* Enable Half rate (test) */
+#define	AR5K_PHY_MODE_QUARTER_RATE	0x00000040	/* Enable Quarter rat (test) */
+
+/*
+ * PHY CCK transmit control register [5111+ (?)]
+ */
+#define AR5K_PHY_CCKTXCTL		0xa204
+#define AR5K_PHY_CCKTXCTL_WORLD		0x00000000
+#define AR5K_PHY_CCKTXCTL_JAPAN		0x00000010
+#define	AR5K_PHY_CCKTXCTL_SCRAMBLER_DIS	0x00000001
+#define	AR5K_PHY_CCKTXCTK_DAC_SCALE	0x00000004
+
+/*
+ * PHY CCK Cross-correlator Barker RSSI threshold register [5212+]
+ */
+#define AR5K_PHY_CCK_CROSSCORR			0xa208
+#define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR	0x0000000f
+#define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR_S	0
+
+/* Same address is used for antenna diversity activation */
+#define	AR5K_PHY_FAST_ANT_DIV		0xa208
+#define	AR5K_PHY_FAST_ANT_DIV_EN	0x00002000
+
+/*
+ * PHY 2GHz gain register [5111+]
+ */
+#define	AR5K_PHY_GAIN_2GHZ			0xa20c
+#define	AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX		0x00fc0000
+#define	AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX_S	18
+#define	AR5K_PHY_GAIN_2GHZ_INI_5111		0x6480416c
+
+#define	AR5K_PHY_CCK_RX_CTL_4			0xa21c
+#define	AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT	0x01f80000
+#define	AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT_S	19
+
+#define	AR5K_PHY_DAG_CCK_CTL			0xa228
+#define	AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR	0x00000200
+#define	AR5K_PHY_DAG_CCK_CTL_RSSI_THR		0x0001fc00
+#define	AR5K_PHY_DAG_CCK_CTL_RSSI_THR_S		10
+
+#define	AR5K_PHY_FAST_ADC	0xa24c
+
+#define	AR5K_PHY_BLUETOOTH	0xa254
+
+/*
+ * Transmit Power Control register
+ * [2413+]
+ */
+#define	AR5K_PHY_TPC_RG1		0xa258
+#define	AR5K_PHY_TPC_RG1_NUM_PD_GAIN	0x0000c000
+#define	AR5K_PHY_TPC_RG1_NUM_PD_GAIN_S	14
+#define AR5K_PHY_TPC_RG1_PDGAIN_1	0x00030000
+#define AR5K_PHY_TPC_RG1_PDGAIN_1_S	16
+#define AR5K_PHY_TPC_RG1_PDGAIN_2	0x000c0000
+#define AR5K_PHY_TPC_RG1_PDGAIN_2_S	18
+#define AR5K_PHY_TPC_RG1_PDGAIN_3	0x00300000
+#define AR5K_PHY_TPC_RG1_PDGAIN_3_S	20
+
+#define	AR5K_PHY_TPC_RG5			0xa26C
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP	0x0000000F
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP_S	0
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1	0x000003F0
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1_S	4
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2	0x0000FC00
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2_S	10
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3	0x003F0000
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3_S	16
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4	0x0FC00000
+#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4_S	22
+
+/*
+ * PHY PDADC Tx power table
+ */
+#define AR5K_PHY_PDADC_TXPOWER_BASE	0xa280
+#define	AR5K_PHY_PDADC_TXPOWER(_n)	(AR5K_PHY_PDADC_TXPOWER_BASE + ((_n) << 2))
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/rfbuffer.h b/roms/ipxe/src/drivers/net/ath/ath5k/rfbuffer.h
new file mode 100644
index 0000000000000000000000000000000000000000..e50baff66175a969a36110b36256b31f59c7c195
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/rfbuffer.h
@@ -0,0 +1,1181 @@
+/*
+ * RF Buffer handling functions
+ *
+ * Copyright (c) 2009 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+
+/*
+ * There are some special registers on the RF chip
+ * that control various operation settings related mostly to
+ * the analog parts (channel, gain adjustment etc).
+ *
+ * We don't write on those registers directly but
+ * we send a data packet on the chip, using a special register,
+ * that holds all the settings we need. After we 've sent the
+ * data packet, we write on another special register to notify hw
+ * to apply the settings. This is done so that control registers
+ * can be dynamicaly programmed during operation and the settings
+ * are applied faster on the hw.
+ *
+ * We call each data packet an "RF Bank" and all the data we write
+ * (all RF Banks) "RF Buffer". This file holds initial RF Buffer
+ * data for the different RF chips, and various info to match RF
+ * Buffer offsets with specific RF registers so that we can access
+ * them. We tweak these settings on rfregs_init function.
+ *
+ * Also check out reg.h and U.S. Patent 6677779 B1 (about buffer
+ * registers and control registers):
+ *
+ * http://www.google.com/patents?id=qNURAAAAEBAJ
+ */
+
+
+/*
+ * Struct to hold default mode specific RF
+ * register values (RF Banks)
+ */
+struct ath5k_ini_rfbuffer {
+	u8	rfb_bank;		/* RF Bank number */
+	u16	rfb_ctrl_register;	/* RF Buffer control register */
+	u32	rfb_mode_data[5];	/* RF Buffer data for each mode */
+};
+
+/*
+ * Struct to hold RF Buffer field
+ * infos used to access certain RF
+ * analog registers
+ */
+struct ath5k_rfb_field {
+	u8	len;	/* Field length */
+	u16	pos;	/* Offset on the raw packet */
+	u8	col;	/* Column -used for shifting */
+};
+
+/*
+ * RF analog register definition
+ */
+struct ath5k_rf_reg {
+	u8			bank;	/* RF Buffer Bank number */
+	u8			index;	/* Register's index on rf_regs_idx */
+	struct ath5k_rfb_field	field;	/* RF Buffer field for this register */
+};
+
+/* Map RF registers to indexes
+ * We do this to handle common bits and make our
+ * life easier by using an index for each register
+ * instead of a full rfb_field */
+enum ath5k_rf_regs_idx {
+	/* BANK 6 */
+	AR5K_RF_OB_2GHZ = 0,
+	AR5K_RF_OB_5GHZ,
+	AR5K_RF_DB_2GHZ,
+	AR5K_RF_DB_5GHZ,
+	AR5K_RF_FIXED_BIAS_A,
+	AR5K_RF_FIXED_BIAS_B,
+	AR5K_RF_PWD_XPD,
+	AR5K_RF_XPD_SEL,
+	AR5K_RF_XPD_GAIN,
+	AR5K_RF_PD_GAIN_LO,
+	AR5K_RF_PD_GAIN_HI,
+	AR5K_RF_HIGH_VC_CP,
+	AR5K_RF_MID_VC_CP,
+	AR5K_RF_LOW_VC_CP,
+	AR5K_RF_PUSH_UP,
+	AR5K_RF_PAD2GND,
+	AR5K_RF_XB2_LVL,
+	AR5K_RF_XB5_LVL,
+	AR5K_RF_PWD_ICLOBUF_2G,
+	AR5K_RF_PWD_84,
+	AR5K_RF_PWD_90,
+	AR5K_RF_PWD_130,
+	AR5K_RF_PWD_131,
+	AR5K_RF_PWD_132,
+	AR5K_RF_PWD_136,
+	AR5K_RF_PWD_137,
+	AR5K_RF_PWD_138,
+	AR5K_RF_PWD_166,
+	AR5K_RF_PWD_167,
+	AR5K_RF_DERBY_CHAN_SEL_MODE,
+	/* BANK 7 */
+	AR5K_RF_GAIN_I,
+	AR5K_RF_PLO_SEL,
+	AR5K_RF_RFGAIN_SEL,
+	AR5K_RF_RFGAIN_STEP,
+	AR5K_RF_WAIT_S,
+	AR5K_RF_WAIT_I,
+	AR5K_RF_MAX_TIME,
+	AR5K_RF_MIXVGA_OVR,
+	AR5K_RF_MIXGAIN_OVR,
+	AR5K_RF_MIXGAIN_STEP,
+	AR5K_RF_PD_DELAY_A,
+	AR5K_RF_PD_DELAY_B,
+	AR5K_RF_PD_DELAY_XR,
+	AR5K_RF_PD_PERIOD_A,
+	AR5K_RF_PD_PERIOD_B,
+	AR5K_RF_PD_PERIOD_XR,
+};
+
+
+/*******************\
+* RF5111 (Sombrero) *
+\*******************/
+
+/* BANK 6				len  pos col */
+#define	AR5K_RF5111_OB_2GHZ		{ 3, 119, 0 }
+#define	AR5K_RF5111_DB_2GHZ		{ 3, 122, 0 }
+
+#define	AR5K_RF5111_OB_5GHZ		{ 3, 104, 0 }
+#define	AR5K_RF5111_DB_5GHZ		{ 3, 107, 0 }
+
+#define	AR5K_RF5111_PWD_XPD		{ 1, 95,  0 }
+#define	AR5K_RF5111_XPD_GAIN		{ 4, 96,  0 }
+
+/* Access to PWD registers */
+#define AR5K_RF5111_PWD(_n)		{ 1, (135 - _n), 3 }
+
+/* BANK 7				len  pos col */
+#define	AR5K_RF5111_GAIN_I		{ 6, 29,  0 }
+#define	AR5K_RF5111_PLO_SEL		{ 1, 4,   0 }
+#define	AR5K_RF5111_RFGAIN_SEL		{ 1, 36,  0 }
+#define AR5K_RF5111_RFGAIN_STEP		{ 6, 37,  0 }
+/* Only on AR5212 BaseBand and up */
+#define	AR5K_RF5111_WAIT_S		{ 5, 19,  0 }
+#define	AR5K_RF5111_WAIT_I		{ 5, 24,  0 }
+#define	AR5K_RF5111_MAX_TIME		{ 2, 49,  0 }
+
+static const struct ath5k_rf_reg rf_regs_5111[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF5111_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF5111_DB_2GHZ},
+	{6, AR5K_RF_OB_5GHZ,		AR5K_RF5111_OB_5GHZ},
+	{6, AR5K_RF_DB_5GHZ,		AR5K_RF5111_DB_5GHZ},
+	{6, AR5K_RF_PWD_XPD,		AR5K_RF5111_PWD_XPD},
+	{6, AR5K_RF_XPD_GAIN,		AR5K_RF5111_XPD_GAIN},
+	{6, AR5K_RF_PWD_84,		AR5K_RF5111_PWD(84)},
+	{6, AR5K_RF_PWD_90,		AR5K_RF5111_PWD(90)},
+	{7, AR5K_RF_GAIN_I,		AR5K_RF5111_GAIN_I},
+	{7, AR5K_RF_PLO_SEL,		AR5K_RF5111_PLO_SEL},
+	{7, AR5K_RF_RFGAIN_SEL,		AR5K_RF5111_RFGAIN_SEL},
+	{7, AR5K_RF_RFGAIN_STEP,	AR5K_RF5111_RFGAIN_STEP},
+	{7, AR5K_RF_WAIT_S,		AR5K_RF5111_WAIT_S},
+	{7, AR5K_RF_WAIT_I,		AR5K_RF5111_WAIT_I},
+	{7, AR5K_RF_MAX_TIME,		AR5K_RF5111_MAX_TIME}
+};
+
+/* Default mode specific settings */
+static const struct ath5k_ini_rfbuffer rfb_5111[] = {
+	{ 0, 0x989c,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00380000, 0x00380000, 0x00380000, 0x00380000, 0x00380000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x000000c0, 0x00000080, 0x00000080 } },
+	{ 0, 0x989c,
+	    { 0x000400f9, 0x000400f9, 0x000400ff, 0x000400fd, 0x000400fd } },
+	{ 0, 0x98d4,
+	    { 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000004 } },
+	{ 1, 0x98d4,
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d4,
+	    { 0x00000010, 0x00000014, 0x00000010, 0x00000010, 0x00000014 } },
+	{ 3, 0x98d8,
+	    { 0x00601068, 0x00601068, 0x00601068, 0x00601068, 0x00601068 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
+	{ 6, 0x989c,
+	    { 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x0a000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x003800c0, 0x00380080, 0x023800c0, 0x003800c0, 0x003800c0 } },
+	{ 6, 0x989c,
+	    { 0x00020006, 0x00020006, 0x00000006, 0x00020006, 0x00020006 } },
+	{ 6, 0x989c,
+	    { 0x00000089, 0x00000089, 0x00000089, 0x00000089, 0x00000089 } },
+	{ 6, 0x989c,
+	    { 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0 } },
+	{ 6, 0x989c,
+	    { 0x00040007, 0x00040007, 0x00040007, 0x00040007, 0x00040007 } },
+	{ 6, 0x98d4,
+	    { 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a } },
+	{ 7, 0x989c,
+	    { 0x00000040, 0x00000048, 0x00000040, 0x00000040, 0x00000040 } },
+	{ 7, 0x989c,
+	    { 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } },
+	{ 7, 0x989c,
+	    { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
+	{ 7, 0x989c,
+	    { 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f } },
+	{ 7, 0x989c,
+	    { 0x000000f1, 0x000000f1, 0x00000061, 0x000000f1, 0x000000f1 } },
+	{ 7, 0x989c,
+	    { 0x0000904f, 0x0000904f, 0x0000904c, 0x0000904f, 0x0000904f } },
+	{ 7, 0x989c,
+	    { 0x0000125a, 0x0000125a, 0x0000129a, 0x0000125a, 0x0000125a } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000f, 0x0000000e, 0x0000000e } },
+};
+
+
+
+/***********************\
+* RF5112/RF2112 (Derby) *
+\***********************/
+
+/* BANK 7 (Common)			len  pos col */
+#define	AR5K_RF5112X_GAIN_I		{ 6, 14,  0 }
+#define	AR5K_RF5112X_MIXVGA_OVR		{ 1, 36,  0 }
+#define	AR5K_RF5112X_MIXGAIN_OVR	{ 2, 37,  0 }
+#define AR5K_RF5112X_MIXGAIN_STEP	{ 4, 32,  0 }
+#define	AR5K_RF5112X_PD_DELAY_A		{ 4, 58,  0 }
+#define	AR5K_RF5112X_PD_DELAY_B		{ 4, 62,  0 }
+#define	AR5K_RF5112X_PD_DELAY_XR	{ 4, 66,  0 }
+#define	AR5K_RF5112X_PD_PERIOD_A	{ 4, 70,  0 }
+#define	AR5K_RF5112X_PD_PERIOD_B	{ 4, 74,  0 }
+#define	AR5K_RF5112X_PD_PERIOD_XR	{ 4, 78,  0 }
+
+/* RFX112 (Derby 1) */
+
+/* BANK 6 				len  pos col */
+#define	AR5K_RF5112_OB_2GHZ		{ 3, 269, 0 }
+#define	AR5K_RF5112_DB_2GHZ		{ 3, 272, 0 }
+
+#define	AR5K_RF5112_OB_5GHZ		{ 3, 261, 0 }
+#define	AR5K_RF5112_DB_5GHZ		{ 3, 264, 0 }
+
+#define	AR5K_RF5112_FIXED_BIAS_A	{ 1, 260, 0 }
+#define	AR5K_RF5112_FIXED_BIAS_B	{ 1, 259, 0 }
+
+#define	AR5K_RF5112_XPD_SEL		{ 1, 284, 0 }
+#define	AR5K_RF5112_XPD_GAIN		{ 2, 252, 0 }
+
+/* Access to PWD registers */
+#define AR5K_RF5112_PWD(_n)		{ 1, (302 - _n), 3 }
+
+static const struct ath5k_rf_reg rf_regs_5112[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF5112_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF5112_DB_2GHZ},
+	{6, AR5K_RF_OB_5GHZ,		AR5K_RF5112_OB_5GHZ},
+	{6, AR5K_RF_DB_5GHZ,		AR5K_RF5112_DB_5GHZ},
+	{6, AR5K_RF_FIXED_BIAS_A,	AR5K_RF5112_FIXED_BIAS_A},
+	{6, AR5K_RF_FIXED_BIAS_B,	AR5K_RF5112_FIXED_BIAS_B},
+	{6, AR5K_RF_XPD_SEL,		AR5K_RF5112_XPD_SEL},
+	{6, AR5K_RF_XPD_GAIN,		AR5K_RF5112_XPD_GAIN},
+	{6, AR5K_RF_PWD_130,		AR5K_RF5112_PWD(130)},
+	{6, AR5K_RF_PWD_131,		AR5K_RF5112_PWD(131)},
+	{6, AR5K_RF_PWD_132,		AR5K_RF5112_PWD(132)},
+	{6, AR5K_RF_PWD_136,		AR5K_RF5112_PWD(136)},
+	{6, AR5K_RF_PWD_137,		AR5K_RF5112_PWD(137)},
+	{6, AR5K_RF_PWD_138,		AR5K_RF5112_PWD(138)},
+	{7, AR5K_RF_GAIN_I,		AR5K_RF5112X_GAIN_I},
+	{7, AR5K_RF_MIXVGA_OVR,		AR5K_RF5112X_MIXVGA_OVR},
+	{7, AR5K_RF_MIXGAIN_OVR,	AR5K_RF5112X_MIXGAIN_OVR},
+	{7, AR5K_RF_MIXGAIN_STEP,	AR5K_RF5112X_MIXGAIN_STEP},
+	{7, AR5K_RF_PD_DELAY_A,		AR5K_RF5112X_PD_DELAY_A},
+	{7, AR5K_RF_PD_DELAY_B,		AR5K_RF5112X_PD_DELAY_B},
+	{7, AR5K_RF_PD_DELAY_XR,	AR5K_RF5112X_PD_DELAY_XR},
+	{7, AR5K_RF_PD_PERIOD_A,	AR5K_RF5112X_PD_PERIOD_A},
+	{7, AR5K_RF_PD_PERIOD_B,	AR5K_RF5112X_PD_PERIOD_B},
+	{7, AR5K_RF_PD_PERIOD_XR,	AR5K_RF5112X_PD_PERIOD_XR},
+};
+
+/* Default mode specific settings */
+static const struct ath5k_ini_rfbuffer rfb_5112[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
+	{ 3, 0x98dc,
+	    { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } },
+	{ 6, 0x989c,
+	    { 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000 } },
+	{ 6, 0x989c,
+	    { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00660000, 0x00660000, 0x00660000, 0x00660000, 0x00660000 } },
+	{ 6, 0x989c,
+	    { 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000 } },
+	{ 6, 0x989c,
+	    { 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000 } },
+	{ 6, 0x989c,
+	    { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
+	{ 6, 0x989c,
+	    { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
+	{ 6, 0x989c,
+	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000 } },
+	{ 6, 0x989c,
+	    { 0x00600000, 0x00600000, 0x00600000, 0x00600000, 0x00600000 } },
+	{ 6, 0x989c,
+	    { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
+	{ 6, 0x989c,
+	    { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
+	{ 6, 0x989c,
+	    { 0x00640000, 0x00640000, 0x00640000, 0x00640000, 0x00640000 } },
+	{ 6, 0x989c,
+	    { 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000 } },
+	{ 6, 0x989c,
+	    { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
+	{ 6, 0x989c,
+	    { 0x00250000, 0x00250000, 0x00250000, 0x00250000, 0x00250000 } },
+	{ 6, 0x989c,
+	    { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
+	{ 6, 0x989c,
+	    { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
+	{ 6, 0x989c,
+	    { 0x00510000, 0x00510000, 0x00510000, 0x00510000, 0x00510000 } },
+	{ 6, 0x989c,
+	    { 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000 } },
+	{ 6, 0x989c,
+	    { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
+	{ 6, 0x989c,
+	    { 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000 } },
+	{ 6, 0x989c,
+	    { 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000 } },
+	{ 6, 0x989c,
+	    { 0x03090000, 0x03090000, 0x03090000, 0x03090000, 0x03090000 } },
+	{ 6, 0x989c,
+	    { 0x06000000, 0x06000000, 0x06000000, 0x06000000, 0x06000000 } },
+	{ 6, 0x989c,
+	    { 0x000000b0, 0x000000b0, 0x000000a8, 0x000000a8, 0x000000a8 } },
+	{ 6, 0x989c,
+	    { 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e } },
+	{ 6, 0x989c,
+	    { 0x006c4a41, 0x006c4a41, 0x006c4af1, 0x006c4a61, 0x006c4a61 } },
+	{ 6, 0x989c,
+	    { 0x0050892a, 0x0050892a, 0x0050892b, 0x0050892b, 0x0050892b } },
+	{ 6, 0x989c,
+	    { 0x00842400, 0x00842400, 0x00842400, 0x00842400, 0x00842400 } },
+	{ 6, 0x989c,
+	    { 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200 } },
+	{ 6, 0x98d0,
+	    { 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c } },
+	{ 7, 0x989c,
+	    { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
+	{ 7, 0x989c,
+	    { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
+	{ 7, 0x989c,
+	    { 0x0000000a, 0x0000000a, 0x00000012, 0x00000012, 0x00000012 } },
+	{ 7, 0x989c,
+	    { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
+	{ 7, 0x989c,
+	    { 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1 } },
+	{ 7, 0x989c,
+	    { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
+	{ 7, 0x989c,
+	    { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
+	{ 7, 0x989c,
+	    { 0x00000022, 0x00000022, 0x00000022, 0x00000022, 0x00000022 } },
+	{ 7, 0x989c,
+	    { 0x00000092, 0x00000092, 0x00000092, 0x00000092, 0x00000092 } },
+	{ 7, 0x989c,
+	    { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
+	{ 7, 0x989c,
+	    { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
+	{ 7, 0x989c,
+	    { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
+	{ 7, 0x98c4,
+	    { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+};
+
+/* RFX112A (Derby 2) */
+
+/* BANK 6				len  pos col */
+#define	AR5K_RF5112A_OB_2GHZ		{ 3, 287, 0 }
+#define	AR5K_RF5112A_DB_2GHZ		{ 3, 290, 0 }
+
+#define	AR5K_RF5112A_OB_5GHZ		{ 3, 279, 0 }
+#define	AR5K_RF5112A_DB_5GHZ		{ 3, 282, 0 }
+
+#define	AR5K_RF5112A_FIXED_BIAS_A	{ 1, 278, 0 }
+#define	AR5K_RF5112A_FIXED_BIAS_B	{ 1, 277, 0 }
+
+#define	AR5K_RF5112A_XPD_SEL		{ 1, 302, 0 }
+#define	AR5K_RF5112A_PDGAINLO		{ 2, 270, 0 }
+#define	AR5K_RF5112A_PDGAINHI		{ 2, 257, 0 }
+
+/* Access to PWD registers */
+#define AR5K_RF5112A_PWD(_n)		{ 1, (306 - _n), 3 }
+
+/* Voltage regulators */
+#define	AR5K_RF5112A_HIGH_VC_CP		{ 2, 90,  2 }
+#define	AR5K_RF5112A_MID_VC_CP		{ 2, 92,  2 }
+#define	AR5K_RF5112A_LOW_VC_CP		{ 2, 94,  2 }
+#define	AR5K_RF5112A_PUSH_UP		{ 1, 254,  2 }
+
+/* Power consumption */
+#define	AR5K_RF5112A_PAD2GND		{ 1, 281, 1 }
+#define	AR5K_RF5112A_XB2_LVL		{ 2, 1,	  3 }
+#define	AR5K_RF5112A_XB5_LVL		{ 2, 3,	  3 }
+
+static const struct ath5k_rf_reg rf_regs_5112a[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF5112A_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF5112A_DB_2GHZ},
+	{6, AR5K_RF_OB_5GHZ,		AR5K_RF5112A_OB_5GHZ},
+	{6, AR5K_RF_DB_5GHZ,		AR5K_RF5112A_DB_5GHZ},
+	{6, AR5K_RF_FIXED_BIAS_A,	AR5K_RF5112A_FIXED_BIAS_A},
+	{6, AR5K_RF_FIXED_BIAS_B,	AR5K_RF5112A_FIXED_BIAS_B},
+	{6, AR5K_RF_XPD_SEL,		AR5K_RF5112A_XPD_SEL},
+	{6, AR5K_RF_PD_GAIN_LO,		AR5K_RF5112A_PDGAINLO},
+	{6, AR5K_RF_PD_GAIN_HI,		AR5K_RF5112A_PDGAINHI},
+	{6, AR5K_RF_PWD_130,		AR5K_RF5112A_PWD(130)},
+	{6, AR5K_RF_PWD_131,		AR5K_RF5112A_PWD(131)},
+	{6, AR5K_RF_PWD_132,		AR5K_RF5112A_PWD(132)},
+	{6, AR5K_RF_PWD_136,		AR5K_RF5112A_PWD(136)},
+	{6, AR5K_RF_PWD_137,		AR5K_RF5112A_PWD(137)},
+	{6, AR5K_RF_PWD_138,		AR5K_RF5112A_PWD(138)},
+	{6, AR5K_RF_PWD_166,		AR5K_RF5112A_PWD(166)},
+	{6, AR5K_RF_PWD_167,		AR5K_RF5112A_PWD(167)},
+	{6, AR5K_RF_HIGH_VC_CP,		AR5K_RF5112A_HIGH_VC_CP},
+	{6, AR5K_RF_MID_VC_CP,		AR5K_RF5112A_MID_VC_CP},
+	{6, AR5K_RF_LOW_VC_CP,		AR5K_RF5112A_LOW_VC_CP},
+	{6, AR5K_RF_PUSH_UP,		AR5K_RF5112A_PUSH_UP},
+	{6, AR5K_RF_PAD2GND,		AR5K_RF5112A_PAD2GND},
+	{6, AR5K_RF_XB2_LVL,		AR5K_RF5112A_XB2_LVL},
+	{6, AR5K_RF_XB5_LVL,		AR5K_RF5112A_XB5_LVL},
+	{7, AR5K_RF_GAIN_I,		AR5K_RF5112X_GAIN_I},
+	{7, AR5K_RF_MIXVGA_OVR,		AR5K_RF5112X_MIXVGA_OVR},
+	{7, AR5K_RF_MIXGAIN_OVR,	AR5K_RF5112X_MIXGAIN_OVR},
+	{7, AR5K_RF_MIXGAIN_STEP,	AR5K_RF5112X_MIXGAIN_STEP},
+	{7, AR5K_RF_PD_DELAY_A,		AR5K_RF5112X_PD_DELAY_A},
+	{7, AR5K_RF_PD_DELAY_B,		AR5K_RF5112X_PD_DELAY_B},
+	{7, AR5K_RF_PD_DELAY_XR,	AR5K_RF5112X_PD_DELAY_XR},
+	{7, AR5K_RF_PD_PERIOD_A,	AR5K_RF5112X_PD_PERIOD_A},
+	{7, AR5K_RF_PD_PERIOD_B,	AR5K_RF5112X_PD_PERIOD_B},
+	{7, AR5K_RF_PD_PERIOD_XR,	AR5K_RF5112X_PD_PERIOD_XR},
+};
+
+/* Default mode specific settings */
+static const struct ath5k_ini_rfbuffer rfb_5112a[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000 } },
+	{ 6, 0x989c,
+	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, 0x989c,
+	    { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00180000, 0x00180000, 0x00180000, 0x00180000, 0x00180000 } },
+	{ 6, 0x989c,
+	    { 0x00600000, 0x00600000, 0x006e0000, 0x006e0000, 0x006e0000 } },
+	{ 6, 0x989c,
+	    { 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000 } },
+	{ 6, 0x989c,
+	    { 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000 } },
+	{ 6, 0x989c,
+	    { 0x04480000, 0x04480000, 0x04480000, 0x04480000, 0x04480000 } },
+	{ 6, 0x989c,
+	    { 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000 } },
+	{ 6, 0x989c,
+	    { 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000 } },
+	{ 6, 0x989c,
+	    { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
+	{ 6, 0x989c,
+	    { 0x02190000, 0x02190000, 0x02190000, 0x02190000, 0x02190000 } },
+	{ 6, 0x989c,
+	    { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
+	{ 6, 0x989c,
+	    { 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000 } },
+	{ 6, 0x989c,
+	    { 0x00990000, 0x00990000, 0x00990000, 0x00990000, 0x00990000 } },
+	{ 6, 0x989c,
+	    { 0x00500000, 0x00500000, 0x00500000, 0x00500000, 0x00500000 } },
+	{ 6, 0x989c,
+	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, 0x989c,
+	    { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
+	{ 6, 0x989c,
+	    { 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000 } },
+	{ 6, 0x989c,
+	    { 0x01740000, 0x01740000, 0x01740000, 0x01740000, 0x01740000 } },
+	{ 6, 0x989c,
+	    { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
+	{ 6, 0x989c,
+	    { 0x86280000, 0x86280000, 0x86280000, 0x86280000, 0x86280000 } },
+	{ 6, 0x989c,
+	    { 0x31840000, 0x31840000, 0x31840000, 0x31840000, 0x31840000 } },
+	{ 6, 0x989c,
+	    { 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080 } },
+	{ 6, 0x989c,
+	    { 0x00270019, 0x00270019, 0x00270019, 0x00270019, 0x00270019 } },
+	{ 6, 0x989c,
+	    { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2 } },
+	{ 6, 0x989c,
+	    { 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084 } },
+	{ 6, 0x989c,
+	    { 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4 } },
+	{ 6, 0x989c,
+	    { 0x00119220, 0x00119220, 0x00119220, 0x00119220, 0x00119220 } },
+	{ 6, 0x989c,
+	    { 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800 } },
+	{ 6, 0x98d8,
+	    { 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230 } },
+	{ 7, 0x989c,
+	    { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
+	{ 7, 0x989c,
+	    { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
+	{ 7, 0x989c,
+	    { 0x00000012, 0x00000012, 0x00000012, 0x00000012, 0x00000012 } },
+	{ 7, 0x989c,
+	    { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
+	{ 7, 0x989c,
+	    { 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9 } },
+	{ 7, 0x989c,
+	    { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
+	{ 7, 0x989c,
+	    { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
+	{ 7, 0x989c,
+	    { 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2 } },
+	{ 7, 0x989c,
+	    { 0x00000052, 0x00000052, 0x00000052, 0x00000052, 0x00000052 } },
+	{ 7, 0x989c,
+	    { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
+	{ 7, 0x989c,
+	    { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
+	{ 7, 0x989c,
+	    { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
+	{ 7, 0x98c4,
+	    { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+};
+
+
+
+/******************\
+* RF2413 (Griffin) *
+\******************/
+
+/* BANK 6 				len  pos col */
+#define	AR5K_RF2413_OB_2GHZ		{ 3, 168, 0 }
+#define	AR5K_RF2413_DB_2GHZ		{ 3, 165, 0 }
+
+static const struct ath5k_rf_reg rf_regs_2413[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF2413_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF2413_DB_2GHZ},
+};
+
+/* Default mode specific settings
+ * XXX: a/aTurbo ???
+ */
+static const struct ath5k_ini_rfbuffer rfb_2413[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x40400000, 0x40400000, 0x40400000, 0x40400000, 0x40400000 } },
+	{ 6, 0x989c,
+	    { 0x65050000, 0x65050000, 0x65050000, 0x65050000, 0x65050000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00420000, 0x00420000, 0x00420000, 0x00420000, 0x00420000 } },
+	{ 6, 0x989c,
+	    { 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000 } },
+	{ 6, 0x989c,
+	    { 0x00030000, 0x00030000, 0x00030000, 0x00030000, 0x00030000 } },
+	{ 6, 0x989c,
+	    { 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000 } },
+	{ 6, 0x989c,
+	    { 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000 } },
+	{ 6, 0x989c,
+	    { 0x00220000, 0x00220000, 0x00220000, 0x00220000, 0x00220000 } },
+	{ 6, 0x989c,
+	    { 0x04220000, 0x04220000, 0x04220000, 0x04220000, 0x04220000 } },
+	{ 6, 0x989c,
+	    { 0x00230018, 0x00230018, 0x00230018, 0x00230018, 0x00230018 } },
+	{ 6, 0x989c,
+	    { 0x00280000, 0x00280000, 0x00280060, 0x00280060, 0x00280060 } },
+	{ 6, 0x989c,
+	    { 0x005000c0, 0x005000c0, 0x005000c3, 0x005000c3, 0x005000c3 } },
+	{ 6, 0x989c,
+	    { 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f } },
+	{ 6, 0x989c,
+	    { 0x00000458, 0x00000458, 0x00000458, 0x00000458, 0x00000458 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000 } },
+	{ 6, 0x98d8,
+	    { 0x00400230, 0x00400230, 0x00400230, 0x00400230, 0x00400230 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+
+
+/***************************\
+* RF2315/RF2316 (Cobra SoC) *
+\***************************/
+
+/* BANK 6				len  pos col */
+#define	AR5K_RF2316_OB_2GHZ		{ 3, 178, 0 }
+#define	AR5K_RF2316_DB_2GHZ		{ 3, 175, 0 }
+
+static const struct ath5k_rf_reg rf_regs_2316[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF2316_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF2316_DB_2GHZ},
+};
+
+/* Default mode specific settings */
+static const struct ath5k_ini_rfbuffer rfb_2316[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000 } },
+	{ 6, 0x989c,
+	    { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } },
+	{ 6, 0x989c,
+	    { 0x02000000, 0x02000000, 0x02000000, 0x02000000, 0x02000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x95150000, 0x95150000, 0x95150000, 0x95150000, 0x95150000 } },
+	{ 6, 0x989c,
+	    { 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00080000, 0x00080000, 0x00080000, 0x00080000, 0x00080000 } },
+	{ 6, 0x989c,
+	    { 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000 } },
+	{ 6, 0x989c,
+	    { 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000 } },
+	{ 6, 0x989c,
+	    { 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000 } },
+	{ 6, 0x989c,
+	    { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } },
+	{ 6, 0x989c,
+	    { 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000 } },
+	{ 6, 0x989c,
+	    { 0x10880000, 0x10880000, 0x10880000, 0x10880000, 0x10880000 } },
+	{ 6, 0x989c,
+	    { 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060 } },
+	{ 6, 0x989c,
+	    { 0x00a00000, 0x00a00000, 0x00a00080, 0x00a00080, 0x00a00080 } },
+	{ 6, 0x989c,
+	    { 0x00400000, 0x00400000, 0x0040000d, 0x0040000d, 0x0040000d } },
+	{ 6, 0x989c,
+	    { 0x00110400, 0x00110400, 0x00110400, 0x00110400, 0x00110400 } },
+	{ 6, 0x989c,
+	    { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
+	{ 6, 0x989c,
+	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
+	{ 6, 0x989c,
+	    { 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00 } },
+	{ 6, 0x989c,
+	    { 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8 } },
+	{ 6, 0x98c0,
+	    { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+
+
+/******************************\
+* RF5413/RF5424 (Eagle/Condor) *
+\******************************/
+
+/* BANK 6				len  pos col */
+#define	AR5K_RF5413_OB_2GHZ		{ 3, 241, 0 }
+#define	AR5K_RF5413_DB_2GHZ		{ 3, 238, 0 }
+
+#define	AR5K_RF5413_OB_5GHZ		{ 3, 247, 0 }
+#define	AR5K_RF5413_DB_5GHZ		{ 3, 244, 0 }
+
+#define	AR5K_RF5413_PWD_ICLOBUF2G	{ 3, 131, 3 }
+#define	AR5K_RF5413_DERBY_CHAN_SEL_MODE	{ 1, 291, 2 }
+
+static const struct ath5k_rf_reg rf_regs_5413[] = {
+	{6, AR5K_RF_OB_2GHZ,		 AR5K_RF5413_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		 AR5K_RF5413_DB_2GHZ},
+	{6, AR5K_RF_OB_5GHZ,		 AR5K_RF5413_OB_5GHZ},
+	{6, AR5K_RF_DB_5GHZ,		 AR5K_RF5413_DB_5GHZ},
+	{6, AR5K_RF_PWD_ICLOBUF_2G,	 AR5K_RF5413_PWD_ICLOBUF2G},
+	{6, AR5K_RF_DERBY_CHAN_SEL_MODE, AR5K_RF5413_DERBY_CHAN_SEL_MODE},
+};
+
+/* Default mode specific settings */
+static const struct ath5k_ini_rfbuffer rfb_5413[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
+	{ 3, 0x98dc,
+	    { 0x00a000c0, 0x00a000c0, 0x00e000c0, 0x00e000c0, 0x00e000c0 } },
+	{ 6, 0x989c,
+	    { 0x33000000, 0x33000000, 0x33000000, 0x33000000, 0x33000000 } },
+	{ 6, 0x989c,
+	    { 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000 } },
+	{ 6, 0x989c,
+	    { 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000 } },
+	{ 6, 0x989c,
+	    { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
+	{ 6, 0x989c,
+	    { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
+	{ 6, 0x989c,
+	    { 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000 } },
+	{ 6, 0x989c,
+	    { 0x00610000, 0x00610000, 0x00610000, 0x00610000, 0x00610000 } },
+	{ 6, 0x989c,
+	    { 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000 } },
+	{ 6, 0x989c,
+	    { 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000 } },
+	{ 6, 0x989c,
+	    { 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000 } },
+	{ 6, 0x989c,
+	    { 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000 } },
+	{ 6, 0x989c,
+	    { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } },
+	{ 6, 0x989c,
+	    { 0x00440000, 0x00440000, 0x00440000, 0x00440000, 0x00440000 } },
+	{ 6, 0x989c,
+	    { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
+	{ 6, 0x989c,
+	    { 0x00100080, 0x00100080, 0x00100080, 0x00100080, 0x00100080 } },
+	{ 6, 0x989c,
+	    { 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034 } },
+	{ 6, 0x989c,
+	    { 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0 } },
+	{ 6, 0x989c,
+	    { 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f } },
+	{ 6, 0x989c,
+	    { 0x00510040, 0x00510040, 0x00510040, 0x00510040, 0x00510040 } },
+	{ 6, 0x989c,
+	    { 0x005000da, 0x005000da, 0x005000da, 0x005000da, 0x005000da } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00004044, 0x00004044, 0x00004044, 0x00004044, 0x00004044 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0 } },
+	{ 6, 0x989c,
+	    { 0x00002c00, 0x00002c00, 0x00003600, 0x00003600, 0x00002c00 } },
+	{ 6, 0x98c8,
+	    { 0x00000403, 0x00000403, 0x00040403, 0x00040403, 0x00040403 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+
+
+/***************************\
+* RF2425/RF2417 (Swan/Nala) *
+* AR2317 (Spider SoC)       *
+\***************************/
+
+/* BANK 6				len  pos col */
+#define	AR5K_RF2425_OB_2GHZ		{ 3, 193, 0 }
+#define	AR5K_RF2425_DB_2GHZ		{ 3, 190, 0 }
+
+static const struct ath5k_rf_reg rf_regs_2425[] = {
+	{6, AR5K_RF_OB_2GHZ,		AR5K_RF2425_OB_2GHZ},
+	{6, AR5K_RF_DB_2GHZ,		AR5K_RF2425_DB_2GHZ},
+};
+
+/* Default mode specific settings
+ * XXX: a/aTurbo ?
+ */
+static const struct ath5k_ini_rfbuffer rfb_2425[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
+	{ 6, 0x989c,
+	    { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
+	{ 6, 0x989c,
+	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
+	{ 6, 0x989c,
+	    { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
+	{ 6, 0x989c,
+	    { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } },
+	{ 6, 0x989c,
+	    { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } },
+	{ 6, 0x989c,
+	    { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
+	{ 6, 0x989c,
+	    { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } },
+	{ 6, 0x989c,
+	    { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
+	{ 6, 0x989c,
+	    { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
+	{ 6, 0x989c,
+	    { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
+	{ 6, 0x989c,
+	    { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } },
+	{ 6, 0x98c4,
+	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+/*
+ * TODO: Handle the few differences with swan during
+ * bank modification and get rid of this
+ */
+static const struct ath5k_ini_rfbuffer rfb_2317[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
+	{ 6, 0x989c,
+	    { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
+	{ 6, 0x989c,
+	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
+	{ 6, 0x989c,
+	    { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
+	{ 6, 0x989c,
+	    { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } },
+	{ 6, 0x989c,
+	    { 0x00140100, 0x00140100, 0x00140100, 0x00140100, 0x00140100 } },
+	{ 6, 0x989c,
+	    { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
+	{ 6, 0x989c,
+	    { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } },
+	{ 6, 0x989c,
+	    { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
+	{ 6, 0x989c,
+	    { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
+	{ 6, 0x989c,
+	    { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
+	{ 6, 0x989c,
+	    { 0x00009688, 0x00009688, 0x00009688, 0x00009688, 0x00009688 } },
+	{ 6, 0x98c4,
+	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+/*
+ * TODO: Handle the few differences with swan during
+ * bank modification and get rid of this
+ * XXX: a/aTurbo ?
+ */
+static const struct ath5k_ini_rfbuffer rfb_2417[] = {
+	{ 1, 0x98d4,
+	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } },
+	{ 3, 0x98dc,
+	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, 0x989c,
+	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
+	{ 6, 0x989c,
+	    { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
+	{ 6, 0x989c,
+	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
+	{ 6, 0x989c,
+	    { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
+	{ 6, 0x989c,
+	    { 0x00e70000, 0x00e70000, 0x80e70000, 0x80e70000, 0x00e70000 } },
+	{ 6, 0x989c,
+	    { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } },
+	{ 6, 0x989c,
+	    { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
+	{ 6, 0x989c,
+	    { 0x0007001a, 0x0007001a, 0x0207001a, 0x0207001a, 0x0007001a } },
+	{ 6, 0x989c,
+	    { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
+	{ 6, 0x989c,
+	    { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
+	{ 6, 0x989c,
+	    { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
+	{ 6, 0x989c,
+	    { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } },
+	{ 6, 0x98c4,
+	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
diff --git a/roms/ipxe/src/drivers/net/ath/ath5k/rfgain.h b/roms/ipxe/src/drivers/net/ath/ath5k/rfgain.h
new file mode 100644
index 0000000000000000000000000000000000000000..1354d8c392c814f14c72d1b4e8b1f202b2d366a0
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath5k/rfgain.h
@@ -0,0 +1,516 @@
+/*
+ * RF Gain optimization
+ *
+ * Copyright (c) 2004-2009 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * Mode-specific RF Gain table (64bytes) for RF5111/5112
+ * (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial
+ * RF Gain values are included in AR5K_AR5210_INI)
+ */
+struct ath5k_ini_rfgain {
+	u16	rfg_register;	/* RF Gain register address */
+	u32	rfg_value[2];	/* [freq (see below)] */
+};
+
+/* Initial RF Gain settings for RF5111 */
+static const struct ath5k_ini_rfgain rfgain_5111[] = {
+	/*			      5Ghz	2Ghz	*/
+	{ AR5K_RF_GAIN(0),	{ 0x000001a9, 0x00000000 } },
+	{ AR5K_RF_GAIN(1),	{ 0x000001e9, 0x00000040 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000029, 0x00000080 } },
+	{ AR5K_RF_GAIN(3),	{ 0x00000069, 0x00000150 } },
+	{ AR5K_RF_GAIN(4),	{ 0x00000199, 0x00000190 } },
+	{ AR5K_RF_GAIN(5),	{ 0x000001d9, 0x000001d0 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000019, 0x00000010 } },
+	{ AR5K_RF_GAIN(7),	{ 0x00000059, 0x00000044 } },
+	{ AR5K_RF_GAIN(8),	{ 0x00000099, 0x00000084 } },
+	{ AR5K_RF_GAIN(9),	{ 0x000001a5, 0x00000148 } },
+	{ AR5K_RF_GAIN(10),	{ 0x000001e5, 0x00000188 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000025, 0x000001c8 } },
+	{ AR5K_RF_GAIN(12),	{ 0x000001c8, 0x00000014 } },
+	{ AR5K_RF_GAIN(13),	{ 0x00000008, 0x00000042 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000048, 0x00000082 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000088, 0x00000178 } },
+	{ AR5K_RF_GAIN(16),	{ 0x00000198, 0x000001b8 } },
+	{ AR5K_RF_GAIN(17),	{ 0x000001d8, 0x000001f8 } },
+	{ AR5K_RF_GAIN(18),	{ 0x00000018, 0x00000012 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000058, 0x00000052 } },
+	{ AR5K_RF_GAIN(20),	{ 0x00000098, 0x00000092 } },
+	{ AR5K_RF_GAIN(21),	{ 0x000001a4, 0x0000017c } },
+	{ AR5K_RF_GAIN(22),	{ 0x000001e4, 0x000001bc } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000024, 0x000001fc } },
+	{ AR5K_RF_GAIN(24),	{ 0x00000064, 0x0000000a } },
+	{ AR5K_RF_GAIN(25),	{ 0x000000a4, 0x0000004a } },
+	{ AR5K_RF_GAIN(26),	{ 0x000000e4, 0x0000008a } },
+	{ AR5K_RF_GAIN(27),	{ 0x0000010a, 0x0000015a } },
+	{ AR5K_RF_GAIN(28),	{ 0x0000014a, 0x0000019a } },
+	{ AR5K_RF_GAIN(29),	{ 0x0000018a, 0x000001da } },
+	{ AR5K_RF_GAIN(30),	{ 0x000001ca, 0x0000000e } },
+	{ AR5K_RF_GAIN(31),	{ 0x0000000a, 0x0000004e } },
+	{ AR5K_RF_GAIN(32),	{ 0x0000004a, 0x0000008e } },
+	{ AR5K_RF_GAIN(33),	{ 0x0000008a, 0x0000015e } },
+	{ AR5K_RF_GAIN(34),	{ 0x000001ba, 0x0000019e } },
+	{ AR5K_RF_GAIN(35),	{ 0x000001fa, 0x000001de } },
+	{ AR5K_RF_GAIN(36),	{ 0x0000003a, 0x00000009 } },
+	{ AR5K_RF_GAIN(37),	{ 0x0000007a, 0x00000049 } },
+	{ AR5K_RF_GAIN(38),	{ 0x00000186, 0x00000089 } },
+	{ AR5K_RF_GAIN(39),	{ 0x000001c6, 0x00000179 } },
+	{ AR5K_RF_GAIN(40),	{ 0x00000006, 0x000001b9 } },
+	{ AR5K_RF_GAIN(41),	{ 0x00000046, 0x000001f9 } },
+	{ AR5K_RF_GAIN(42),	{ 0x00000086, 0x00000039 } },
+	{ AR5K_RF_GAIN(43),	{ 0x000000c6, 0x00000079 } },
+	{ AR5K_RF_GAIN(44),	{ 0x000000c6, 0x000000b9 } },
+	{ AR5K_RF_GAIN(45),	{ 0x000000c6, 0x000001bd } },
+	{ AR5K_RF_GAIN(46),	{ 0x000000c6, 0x000001fd } },
+	{ AR5K_RF_GAIN(47),	{ 0x000000c6, 0x0000003d } },
+	{ AR5K_RF_GAIN(48),	{ 0x000000c6, 0x0000007d } },
+	{ AR5K_RF_GAIN(49),	{ 0x000000c6, 0x000000bd } },
+	{ AR5K_RF_GAIN(50),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(51),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(52),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(53),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(54),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(55),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(56),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(57),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(58),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(59),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(60),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(61),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(62),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(63),	{ 0x000000c6, 0x000000fd } },
+};
+
+/* Initial RF Gain settings for RF5112 */
+static const struct ath5k_ini_rfgain rfgain_5112[] = {
+	/*			      5Ghz	2Ghz	*/
+	{ AR5K_RF_GAIN(0),	{ 0x00000007, 0x00000007 } },
+	{ AR5K_RF_GAIN(1),	{ 0x00000047, 0x00000047 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000087, 0x00000087 } },
+	{ AR5K_RF_GAIN(3),	{ 0x000001a0, 0x000001a0 } },
+	{ AR5K_RF_GAIN(4),	{ 0x000001e0, 0x000001e0 } },
+	{ AR5K_RF_GAIN(5),	{ 0x00000020, 0x00000020 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000060, 0x00000060 } },
+	{ AR5K_RF_GAIN(7),	{ 0x000001a1, 0x000001a1 } },
+	{ AR5K_RF_GAIN(8),	{ 0x000001e1, 0x000001e1 } },
+	{ AR5K_RF_GAIN(9),	{ 0x00000021, 0x00000021 } },
+	{ AR5K_RF_GAIN(10),	{ 0x00000061, 0x00000061 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000162, 0x00000162 } },
+	{ AR5K_RF_GAIN(12),	{ 0x000001a2, 0x000001a2 } },
+	{ AR5K_RF_GAIN(13),	{ 0x000001e2, 0x000001e2 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000022, 0x00000022 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000062, 0x00000062 } },
+	{ AR5K_RF_GAIN(16),	{ 0x00000163, 0x00000163 } },
+	{ AR5K_RF_GAIN(17),	{ 0x000001a3, 0x000001a3 } },
+	{ AR5K_RF_GAIN(18),	{ 0x000001e3, 0x000001e3 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000023, 0x00000023 } },
+	{ AR5K_RF_GAIN(20),	{ 0x00000063, 0x00000063 } },
+	{ AR5K_RF_GAIN(21),	{ 0x00000184, 0x00000184 } },
+	{ AR5K_RF_GAIN(22),	{ 0x000001c4, 0x000001c4 } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000004, 0x00000004 } },
+	{ AR5K_RF_GAIN(24),	{ 0x000001ea, 0x0000000b } },
+	{ AR5K_RF_GAIN(25),	{ 0x0000002a, 0x0000004b } },
+	{ AR5K_RF_GAIN(26),	{ 0x0000006a, 0x0000008b } },
+	{ AR5K_RF_GAIN(27),	{ 0x000000aa, 0x000001ac } },
+	{ AR5K_RF_GAIN(28),	{ 0x000001ab, 0x000001ec } },
+	{ AR5K_RF_GAIN(29),	{ 0x000001eb, 0x0000002c } },
+	{ AR5K_RF_GAIN(30),	{ 0x0000002b, 0x00000012 } },
+	{ AR5K_RF_GAIN(31),	{ 0x0000006b, 0x00000052 } },
+	{ AR5K_RF_GAIN(32),	{ 0x000000ab, 0x00000092 } },
+	{ AR5K_RF_GAIN(33),	{ 0x000001ac, 0x00000193 } },
+	{ AR5K_RF_GAIN(34),	{ 0x000001ec, 0x000001d3 } },
+	{ AR5K_RF_GAIN(35),	{ 0x0000002c, 0x00000013 } },
+	{ AR5K_RF_GAIN(36),	{ 0x0000003a, 0x00000053 } },
+	{ AR5K_RF_GAIN(37),	{ 0x0000007a, 0x00000093 } },
+	{ AR5K_RF_GAIN(38),	{ 0x000000ba, 0x00000194 } },
+	{ AR5K_RF_GAIN(39),	{ 0x000001bb, 0x000001d4 } },
+	{ AR5K_RF_GAIN(40),	{ 0x000001fb, 0x00000014 } },
+	{ AR5K_RF_GAIN(41),	{ 0x0000003b, 0x0000003a } },
+	{ AR5K_RF_GAIN(42),	{ 0x0000007b, 0x0000007a } },
+	{ AR5K_RF_GAIN(43),	{ 0x000000bb, 0x000000ba } },
+	{ AR5K_RF_GAIN(44),	{ 0x000001bc, 0x000001bb } },
+	{ AR5K_RF_GAIN(45),	{ 0x000001fc, 0x000001fb } },
+	{ AR5K_RF_GAIN(46),	{ 0x0000003c, 0x0000003b } },
+	{ AR5K_RF_GAIN(47),	{ 0x0000007c, 0x0000007b } },
+	{ AR5K_RF_GAIN(48),	{ 0x000000bc, 0x000000bb } },
+	{ AR5K_RF_GAIN(49),	{ 0x000000fc, 0x000001bc } },
+	{ AR5K_RF_GAIN(50),	{ 0x000000fc, 0x000001fc } },
+	{ AR5K_RF_GAIN(51),	{ 0x000000fc, 0x0000003c } },
+	{ AR5K_RF_GAIN(52),	{ 0x000000fc, 0x0000007c } },
+	{ AR5K_RF_GAIN(53),	{ 0x000000fc, 0x000000bc } },
+	{ AR5K_RF_GAIN(54),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(55),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(56),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(57),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(58),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(59),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(60),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(61),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(62),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(63),	{ 0x000000fc, 0x000000fc } },
+};
+
+/* Initial RF Gain settings for RF2413 */
+static const struct ath5k_ini_rfgain rfgain_2413[] = {
+	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
+	{ AR5K_RF_GAIN(1),	{ 0x00000000, 0x00000040 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000000, 0x00000080 } },
+	{ AR5K_RF_GAIN(3),	{ 0x00000000, 0x00000181 } },
+	{ AR5K_RF_GAIN(4),	{ 0x00000000, 0x000001c1 } },
+	{ AR5K_RF_GAIN(5),	{ 0x00000000, 0x00000001 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000000, 0x00000041 } },
+	{ AR5K_RF_GAIN(7),	{ 0x00000000, 0x00000081 } },
+	{ AR5K_RF_GAIN(8),	{ 0x00000000, 0x00000168 } },
+	{ AR5K_RF_GAIN(9),	{ 0x00000000, 0x000001a8 } },
+	{ AR5K_RF_GAIN(10),	{ 0x00000000, 0x000001e8 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000000, 0x00000028 } },
+	{ AR5K_RF_GAIN(12),	{ 0x00000000, 0x00000068 } },
+	{ AR5K_RF_GAIN(13),	{ 0x00000000, 0x00000189 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000000, 0x000001c9 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000000, 0x00000009 } },
+	{ AR5K_RF_GAIN(16),	{ 0x00000000, 0x00000049 } },
+	{ AR5K_RF_GAIN(17),	{ 0x00000000, 0x00000089 } },
+	{ AR5K_RF_GAIN(18),	{ 0x00000000, 0x00000190 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000000, 0x000001d0 } },
+	{ AR5K_RF_GAIN(20),	{ 0x00000000, 0x00000010 } },
+	{ AR5K_RF_GAIN(21),	{ 0x00000000, 0x00000050 } },
+	{ AR5K_RF_GAIN(22),	{ 0x00000000, 0x00000090 } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000000, 0x00000191 } },
+	{ AR5K_RF_GAIN(24),	{ 0x00000000, 0x000001d1 } },
+	{ AR5K_RF_GAIN(25),	{ 0x00000000, 0x00000011 } },
+	{ AR5K_RF_GAIN(26),	{ 0x00000000, 0x00000051 } },
+	{ AR5K_RF_GAIN(27),	{ 0x00000000, 0x00000091 } },
+	{ AR5K_RF_GAIN(28),	{ 0x00000000, 0x00000178 } },
+	{ AR5K_RF_GAIN(29),	{ 0x00000000, 0x000001b8 } },
+	{ AR5K_RF_GAIN(30),	{ 0x00000000, 0x000001f8 } },
+	{ AR5K_RF_GAIN(31),	{ 0x00000000, 0x00000038 } },
+	{ AR5K_RF_GAIN(32),	{ 0x00000000, 0x00000078 } },
+	{ AR5K_RF_GAIN(33),	{ 0x00000000, 0x00000199 } },
+	{ AR5K_RF_GAIN(34),	{ 0x00000000, 0x000001d9 } },
+	{ AR5K_RF_GAIN(35),	{ 0x00000000, 0x00000019 } },
+	{ AR5K_RF_GAIN(36),	{ 0x00000000, 0x00000059 } },
+	{ AR5K_RF_GAIN(37),	{ 0x00000000, 0x00000099 } },
+	{ AR5K_RF_GAIN(38),	{ 0x00000000, 0x000000d9 } },
+	{ AR5K_RF_GAIN(39),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(40),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(41),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(42),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(43),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(44),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(45),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(46),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(47),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(48),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(49),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(50),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(51),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(52),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(53),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(54),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(55),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(56),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(57),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(58),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(59),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(60),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(61),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(62),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(63),	{ 0x00000000, 0x000000f9 } },
+};
+
+/* Initial RF Gain settings for AR2316 */
+static const struct ath5k_ini_rfgain rfgain_2316[] = {
+	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
+	{ AR5K_RF_GAIN(1),	{ 0x00000000, 0x00000040 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000000, 0x00000080 } },
+	{ AR5K_RF_GAIN(3),	{ 0x00000000, 0x000000c0 } },
+	{ AR5K_RF_GAIN(4),	{ 0x00000000, 0x000000e0 } },
+	{ AR5K_RF_GAIN(5),	{ 0x00000000, 0x000000e0 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000000, 0x00000128 } },
+	{ AR5K_RF_GAIN(7),	{ 0x00000000, 0x00000128 } },
+	{ AR5K_RF_GAIN(8),	{ 0x00000000, 0x00000128 } },
+	{ AR5K_RF_GAIN(9),	{ 0x00000000, 0x00000168 } },
+	{ AR5K_RF_GAIN(10),	{ 0x00000000, 0x000001a8 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000000, 0x000001e8 } },
+	{ AR5K_RF_GAIN(12),	{ 0x00000000, 0x00000028 } },
+	{ AR5K_RF_GAIN(13),	{ 0x00000000, 0x00000068 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000000, 0x000000a8 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000000, 0x000000e8 } },
+	{ AR5K_RF_GAIN(16),	{ 0x00000000, 0x000000e8 } },
+	{ AR5K_RF_GAIN(17),	{ 0x00000000, 0x00000130 } },
+	{ AR5K_RF_GAIN(18),	{ 0x00000000, 0x00000130 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000000, 0x00000170 } },
+	{ AR5K_RF_GAIN(20),	{ 0x00000000, 0x000001b0 } },
+	{ AR5K_RF_GAIN(21),	{ 0x00000000, 0x000001f0 } },
+	{ AR5K_RF_GAIN(22),	{ 0x00000000, 0x00000030 } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000000, 0x00000070 } },
+	{ AR5K_RF_GAIN(24),	{ 0x00000000, 0x000000b0 } },
+	{ AR5K_RF_GAIN(25),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(26),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(27),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(28),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(29),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(30),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(31),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(32),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(33),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(34),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(35),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(36),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(37),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(38),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(39),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(40),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(41),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(42),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(43),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(44),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(45),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(46),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(47),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(48),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(49),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(50),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(51),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(52),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(53),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(54),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(55),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(56),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(57),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(58),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(59),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(60),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(61),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(62),	{ 0x00000000, 0x000000f0 } },
+	{ AR5K_RF_GAIN(63),	{ 0x00000000, 0x000000f0 } },
+};
+
+
+/* Initial RF Gain settings for RF5413 */
+static const struct ath5k_ini_rfgain rfgain_5413[] = {
+	/*			      5Ghz	2Ghz	*/
+	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
+	{ AR5K_RF_GAIN(1),	{ 0x00000040, 0x00000040 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000080, 0x00000080 } },
+	{ AR5K_RF_GAIN(3),	{ 0x000001a1, 0x00000161 } },
+	{ AR5K_RF_GAIN(4),	{ 0x000001e1, 0x000001a1 } },
+	{ AR5K_RF_GAIN(5),	{ 0x00000021, 0x000001e1 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000061, 0x00000021 } },
+	{ AR5K_RF_GAIN(7),	{ 0x00000188, 0x00000061 } },
+	{ AR5K_RF_GAIN(8),	{ 0x000001c8, 0x00000188 } },
+	{ AR5K_RF_GAIN(9),	{ 0x00000008, 0x000001c8 } },
+	{ AR5K_RF_GAIN(10),	{ 0x00000048, 0x00000008 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000088, 0x00000048 } },
+	{ AR5K_RF_GAIN(12),	{ 0x000001a9, 0x00000088 } },
+	{ AR5K_RF_GAIN(13),	{ 0x000001e9, 0x00000169 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000029, 0x000001a9 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000069, 0x000001e9 } },
+	{ AR5K_RF_GAIN(16),	{ 0x000001d0, 0x00000029 } },
+	{ AR5K_RF_GAIN(17),	{ 0x00000010, 0x00000069 } },
+	{ AR5K_RF_GAIN(18),	{ 0x00000050, 0x00000190 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000090, 0x000001d0 } },
+	{ AR5K_RF_GAIN(20),	{ 0x000001b1, 0x00000010 } },
+	{ AR5K_RF_GAIN(21),	{ 0x000001f1, 0x00000050 } },
+	{ AR5K_RF_GAIN(22),	{ 0x00000031, 0x00000090 } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000071, 0x00000171 } },
+	{ AR5K_RF_GAIN(24),	{ 0x000001b8, 0x000001b1 } },
+	{ AR5K_RF_GAIN(25),	{ 0x000001f8, 0x000001f1 } },
+	{ AR5K_RF_GAIN(26),	{ 0x00000038, 0x00000031 } },
+	{ AR5K_RF_GAIN(27),	{ 0x00000078, 0x00000071 } },
+	{ AR5K_RF_GAIN(28),	{ 0x00000199, 0x00000198 } },
+	{ AR5K_RF_GAIN(29),	{ 0x000001d9, 0x000001d8 } },
+	{ AR5K_RF_GAIN(30),	{ 0x00000019, 0x00000018 } },
+	{ AR5K_RF_GAIN(31),	{ 0x00000059, 0x00000058 } },
+	{ AR5K_RF_GAIN(32),	{ 0x00000099, 0x00000098 } },
+	{ AR5K_RF_GAIN(33),	{ 0x000000d9, 0x00000179 } },
+	{ AR5K_RF_GAIN(34),	{ 0x000000f9, 0x000001b9 } },
+	{ AR5K_RF_GAIN(35),	{ 0x000000f9, 0x000001f9 } },
+	{ AR5K_RF_GAIN(36),	{ 0x000000f9, 0x00000039 } },
+	{ AR5K_RF_GAIN(37),	{ 0x000000f9, 0x00000079 } },
+	{ AR5K_RF_GAIN(38),	{ 0x000000f9, 0x000000b9 } },
+	{ AR5K_RF_GAIN(39),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(40),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(41),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(42),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(43),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(44),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(45),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(46),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(47),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(48),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(49),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(50),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(51),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(52),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(53),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(54),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(55),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(56),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(57),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(58),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(59),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(60),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(61),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(62),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(63),	{ 0x000000f9, 0x000000f9 } },
+};
+
+
+/* Initial RF Gain settings for RF2425 */
+static const struct ath5k_ini_rfgain rfgain_2425[] = {
+	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
+	{ AR5K_RF_GAIN(1),	{ 0x00000000, 0x00000040 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000000, 0x00000080 } },
+	{ AR5K_RF_GAIN(3),	{ 0x00000000, 0x00000181 } },
+	{ AR5K_RF_GAIN(4),	{ 0x00000000, 0x000001c1 } },
+	{ AR5K_RF_GAIN(5),	{ 0x00000000, 0x00000001 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000000, 0x00000041 } },
+	{ AR5K_RF_GAIN(7),	{ 0x00000000, 0x00000081 } },
+	{ AR5K_RF_GAIN(8),	{ 0x00000000, 0x00000188 } },
+	{ AR5K_RF_GAIN(9),	{ 0x00000000, 0x000001c8 } },
+	{ AR5K_RF_GAIN(10),	{ 0x00000000, 0x00000008 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000000, 0x00000048 } },
+	{ AR5K_RF_GAIN(12),	{ 0x00000000, 0x00000088 } },
+	{ AR5K_RF_GAIN(13),	{ 0x00000000, 0x00000189 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000000, 0x000001c9 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000000, 0x00000009 } },
+	{ AR5K_RF_GAIN(16),	{ 0x00000000, 0x00000049 } },
+	{ AR5K_RF_GAIN(17),	{ 0x00000000, 0x00000089 } },
+	{ AR5K_RF_GAIN(18),	{ 0x00000000, 0x000001b0 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000000, 0x000001f0 } },
+	{ AR5K_RF_GAIN(20),	{ 0x00000000, 0x00000030 } },
+	{ AR5K_RF_GAIN(21),	{ 0x00000000, 0x00000070 } },
+	{ AR5K_RF_GAIN(22),	{ 0x00000000, 0x00000171 } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000000, 0x000001b1 } },
+	{ AR5K_RF_GAIN(24),	{ 0x00000000, 0x000001f1 } },
+	{ AR5K_RF_GAIN(25),	{ 0x00000000, 0x00000031 } },
+	{ AR5K_RF_GAIN(26),	{ 0x00000000, 0x00000071 } },
+	{ AR5K_RF_GAIN(27),	{ 0x00000000, 0x000001b8 } },
+	{ AR5K_RF_GAIN(28),	{ 0x00000000, 0x000001f8 } },
+	{ AR5K_RF_GAIN(29),	{ 0x00000000, 0x00000038 } },
+	{ AR5K_RF_GAIN(30),	{ 0x00000000, 0x00000078 } },
+	{ AR5K_RF_GAIN(31),	{ 0x00000000, 0x000000b8 } },
+	{ AR5K_RF_GAIN(32),	{ 0x00000000, 0x000001b9 } },
+	{ AR5K_RF_GAIN(33),	{ 0x00000000, 0x000001f9 } },
+	{ AR5K_RF_GAIN(34),	{ 0x00000000, 0x00000039 } },
+	{ AR5K_RF_GAIN(35),	{ 0x00000000, 0x00000079 } },
+	{ AR5K_RF_GAIN(36),	{ 0x00000000, 0x000000b9 } },
+	{ AR5K_RF_GAIN(37),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(38),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(39),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(40),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(41),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(42),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(43),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(44),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(45),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(46),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(47),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(48),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(49),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(50),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(51),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(52),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(53),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(54),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(55),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(56),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(57),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(58),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(59),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(60),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(61),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(62),	{ 0x00000000, 0x000000f9 } },
+	{ AR5K_RF_GAIN(63),	{ 0x00000000, 0x000000f9 } },
+};
+
+#define AR5K_GAIN_CRN_FIX_BITS_5111		4
+#define AR5K_GAIN_CRN_FIX_BITS_5112		7
+#define AR5K_GAIN_CRN_MAX_FIX_BITS		AR5K_GAIN_CRN_FIX_BITS_5112
+#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN		15
+#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN		20
+#define AR5K_GAIN_CCK_PROBE_CORR		5
+#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA		15
+#define AR5K_GAIN_STEP_COUNT			10
+
+/* Check if our current measurement is inside our
+ * current variable attenuation window */
+#define AR5K_GAIN_CHECK_ADJUST(_g) 		\
+	((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
+
+struct ath5k_gain_opt_step {
+	s8				gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
+	s8				gos_gain;
+};
+
+struct ath5k_gain_opt {
+	u8				go_default;
+	u8				go_steps_count;
+	const struct ath5k_gain_opt_step	go_step[AR5K_GAIN_STEP_COUNT];
+};
+
+/*
+ * Parameters on gos_param:
+ * 1) Tx clip PHY register
+ * 2) PWD 90 RF register
+ * 3) PWD 84 RF register
+ * 4) RFGainSel RF register
+ */
+static const struct ath5k_gain_opt rfgain_opt_5111 = {
+	4,
+	9,
+	{
+		{ { 4, 1, 1, 1 }, 6 },
+		{ { 4, 0, 1, 1 }, 4 },
+		{ { 3, 1, 1, 1 }, 3 },
+		{ { 4, 0, 0, 1 }, 1 },
+		{ { 4, 1, 1, 0 }, 0 },
+		{ { 4, 0, 1, 0 }, -2 },
+		{ { 3, 1, 1, 0 }, -3 },
+		{ { 4, 0, 0, 0 }, -4 },
+		{ { 2, 1, 1, 0 }, -6 }
+	}
+};
+
+/*
+ * Parameters on gos_param:
+ * 1) Mixgain ovr RF register
+ * 2) PWD 138 RF register
+ * 3) PWD 137 RF register
+ * 4) PWD 136 RF register
+ * 5) PWD 132 RF register
+ * 6) PWD 131 RF register
+ * 7) PWD 130 RF register
+ */
+static const struct ath5k_gain_opt rfgain_opt_5112 = {
+	1,
+	8,
+	{
+		{ { 3, 0, 0, 0, 0, 0, 0 }, 6 },
+		{ { 2, 0, 0, 0, 0, 0, 0 }, 0 },
+		{ { 1, 0, 0, 0, 0, 0, 0 }, -3 },
+		{ { 0, 0, 0, 0, 0, 0, 0 }, -6 },
+		{ { 0, 1, 1, 0, 0, 0, 0 }, -8 },
+		{ { 0, 1, 1, 0, 1, 1, 0 }, -10 },
+		{ { 0, 1, 0, 1, 1, 1, 0 }, -13 },
+		{ { 0, 1, 0, 1, 1, 0, 1 }, -16 },
+	}
+};
+
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ani.h b/roms/ipxe/src/drivers/net/ath/ath9k/ani.h
new file mode 100644
index 0000000000000000000000000000000000000000..9a333b5f7eb1435a9dc49a6222c85ec774699e86
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ani.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ANI_H
+#define ANI_H
+
+#define HAL_PROCESS_ANI           0x00000001
+
+#define DO_ANI(ah) (((ah)->proc_phyerr & HAL_PROCESS_ANI) && ah->curchan)
+
+#define BEACON_RSSI(ahp) (ahp->stats.avgbrssi)
+
+/* units are errors per second */
+#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD      500
+#define ATH9K_ANI_OFDM_TRIG_HIGH_NEW      1000
+
+/* units are errors per second */
+#define ATH9K_ANI_OFDM_TRIG_LOW_OLD       200
+#define ATH9K_ANI_OFDM_TRIG_LOW_NEW       400
+
+/* units are errors per second */
+#define ATH9K_ANI_CCK_TRIG_HIGH_OLD       200
+#define ATH9K_ANI_CCK_TRIG_HIGH_NEW       600
+
+/* units are errors per second */
+#define ATH9K_ANI_CCK_TRIG_LOW_OLD        100
+#define ATH9K_ANI_CCK_TRIG_LOW_NEW        300
+
+#define ATH9K_ANI_NOISE_IMMUNE_LVL        4
+#define ATH9K_ANI_USE_OFDM_WEAK_SIG       1
+#define ATH9K_ANI_CCK_WEAK_SIG_THR        0
+
+#define ATH9K_ANI_SPUR_IMMUNE_LVL_OLD     7
+#define ATH9K_ANI_SPUR_IMMUNE_LVL_NEW     3
+
+#define ATH9K_ANI_FIRSTEP_LVL_OLD         0
+#define ATH9K_ANI_FIRSTEP_LVL_NEW         2
+
+#define ATH9K_ANI_RSSI_THR_HIGH           40
+#define ATH9K_ANI_RSSI_THR_LOW            7
+
+#define ATH9K_ANI_PERIOD_OLD              100
+#define ATH9K_ANI_PERIOD_NEW              1000
+
+/* in ms */
+#define ATH9K_ANI_POLLINTERVAL_OLD        100
+#define ATH9K_ANI_POLLINTERVAL_NEW        1000
+
+#define HAL_NOISE_IMMUNE_MAX              4
+#define HAL_SPUR_IMMUNE_MAX               7
+#define HAL_FIRST_STEP_MAX                2
+
+#define ATH9K_SIG_FIRSTEP_SETTING_MIN     0
+#define ATH9K_SIG_FIRSTEP_SETTING_MAX     20
+#define ATH9K_SIG_SPUR_IMM_SETTING_MIN    0
+#define ATH9K_SIG_SPUR_IMM_SETTING_MAX    22
+
+#define ATH9K_ANI_ENABLE_MRC_CCK          1
+
+/* values here are relative to the INI */
+
+enum ath9k_ani_cmd {
+	ATH9K_ANI_PRESENT = 0x1,
+	ATH9K_ANI_NOISE_IMMUNITY_LEVEL = 0x2,
+	ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION = 0x4,
+	ATH9K_ANI_CCK_WEAK_SIGNAL_THR = 0x8,
+	ATH9K_ANI_FIRSTEP_LEVEL = 0x10,
+	ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x20,
+	ATH9K_ANI_MODE = 0x40,
+	ATH9K_ANI_PHYERR_RESET = 0x80,
+	ATH9K_ANI_MRC_CCK = 0x100,
+	ATH9K_ANI_ALL = 0xfff
+};
+
+struct ath9k_mib_stats {
+	u32 ackrcv_bad;
+	u32 rts_bad;
+	u32 rts_good;
+	u32 fcs_bad;
+	u32 beacons;
+};
+
+/* INI default values for ANI registers */
+struct ath9k_ani_default {
+	u16 m1ThreshLow;
+	u16 m2ThreshLow;
+	u16 m1Thresh;
+	u16 m2Thresh;
+	u16 m2CountThr;
+	u16 m2CountThrLow;
+	u16 m1ThreshLowExt;
+	u16 m2ThreshLowExt;
+	u16 m1ThreshExt;
+	u16 m2ThreshExt;
+	u16 firstep;
+	u16 firstepLow;
+	u16 cycpwrThr1;
+	u16 cycpwrThr1Ext;
+};
+
+struct ar5416AniState {
+	struct ath9k_channel *c;
+	u8 noiseImmunityLevel;
+	u8 ofdmNoiseImmunityLevel;
+	u8 cckNoiseImmunityLevel;
+	int ofdmsTurn;
+	u8 mrcCCKOff;
+	u8 spurImmunityLevel;
+	u8 firstepLevel;
+	u8 ofdmWeakSigDetectOff;
+	u8 cckWeakSigThreshold;
+	u32 listenTime;
+	int32_t rssiThrLow;
+	int32_t rssiThrHigh;
+	u32 noiseFloor;
+	u32 ofdmPhyErrCount;
+	u32 cckPhyErrCount;
+	int16_t pktRssi[2];
+	int16_t ofdmErrRssi[2];
+	int16_t cckErrRssi[2];
+	struct ath9k_ani_default iniDef;
+};
+
+struct ar5416Stats {
+	u32 ast_ani_niup;
+	u32 ast_ani_nidown;
+	u32 ast_ani_spurup;
+	u32 ast_ani_spurdown;
+	u32 ast_ani_ofdmon;
+	u32 ast_ani_ofdmoff;
+	u32 ast_ani_cckhigh;
+	u32 ast_ani_ccklow;
+	u32 ast_ani_stepup;
+	u32 ast_ani_stepdown;
+	u32 ast_ani_ofdmerrs;
+	u32 ast_ani_cckerrs;
+	u32 ast_ani_reset;
+	u32 ast_ani_lzero;
+	u32 ast_ani_lneg;
+	u32 avgbrssi;
+	struct ath9k_mib_stats ast_mibstats;
+};
+#define ah_mibStats stats.ast_mibstats
+
+void ath9k_enable_mib_counters(struct ath_hw *ah);
+void ath9k_hw_disable_mib_counters(struct ath_hw *ah);
+void ath9k_hw_ani_setup(struct ath_hw *ah);
+void ath9k_hw_ani_init(struct ath_hw *ah);
+int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
+				 struct ath9k_channel *chan);
+
+#endif /* ANI_H */
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ar5008_initvals.h b/roms/ipxe/src/drivers/net/ath/ath9k/ar5008_initvals.h
new file mode 100644
index 0000000000000000000000000000000000000000..479aed547206d6a342201e5d26ca79cf9e2cac88
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ar5008_initvals.h
@@ -0,0 +1,672 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+static const u32 ar5416Modes[][6] = {
+	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
+	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
+	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
+	{0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008},
+	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
+	{0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf},
+	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
+	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
+	{0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
+	{0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+	{0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+	{0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+	{0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0},
+	{0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de, 0x6c48b0de},
+	{0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e},
+	{0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e},
+	{0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18},
+	{0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+	{0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190},
+	{0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081},
+	{0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+	{0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134},
+	{0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b},
+	{0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020},
+	{0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80},
+	{0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80},
+	{0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80},
+	{0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120},
+	{0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00},
+	{0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be},
+	{0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+	{0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c},
+	{0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+	{0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+	{0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880},
+	{0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788},
+	{0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+	{0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+	{0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa},
+	{0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000},
+	{0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402},
+	{0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06},
+	{0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b},
+	{0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b},
+	{0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a},
+	{0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf},
+	{0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f},
+	{0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f},
+	{0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f},
+	{0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+};
+
+static const u32 ar5416Common[][2] = {
+	/* Addr      allmodes  */
+	{0x0000000c, 0x00000000},
+	{0x00000030, 0x00020015},
+	{0x00000034, 0x00000005},
+	{0x00000040, 0x00000000},
+	{0x00000044, 0x00000008},
+	{0x00000048, 0x00000008},
+	{0x0000004c, 0x00000010},
+	{0x00000050, 0x00000000},
+	{0x00000054, 0x0000001f},
+	{0x00000800, 0x00000000},
+	{0x00000804, 0x00000000},
+	{0x00000808, 0x00000000},
+	{0x0000080c, 0x00000000},
+	{0x00000810, 0x00000000},
+	{0x00000814, 0x00000000},
+	{0x00000818, 0x00000000},
+	{0x0000081c, 0x00000000},
+	{0x00000820, 0x00000000},
+	{0x00000824, 0x00000000},
+	{0x00001040, 0x002ffc0f},
+	{0x00001044, 0x002ffc0f},
+	{0x00001048, 0x002ffc0f},
+	{0x0000104c, 0x002ffc0f},
+	{0x00001050, 0x002ffc0f},
+	{0x00001054, 0x002ffc0f},
+	{0x00001058, 0x002ffc0f},
+	{0x0000105c, 0x002ffc0f},
+	{0x00001060, 0x002ffc0f},
+	{0x00001064, 0x002ffc0f},
+	{0x00001230, 0x00000000},
+	{0x00001270, 0x00000000},
+	{0x00001038, 0x00000000},
+	{0x00001078, 0x00000000},
+	{0x000010b8, 0x00000000},
+	{0x000010f8, 0x00000000},
+	{0x00001138, 0x00000000},
+	{0x00001178, 0x00000000},
+	{0x000011b8, 0x00000000},
+	{0x000011f8, 0x00000000},
+	{0x00001238, 0x00000000},
+	{0x00001278, 0x00000000},
+	{0x000012b8, 0x00000000},
+	{0x000012f8, 0x00000000},
+	{0x00001338, 0x00000000},
+	{0x00001378, 0x00000000},
+	{0x000013b8, 0x00000000},
+	{0x000013f8, 0x00000000},
+	{0x00001438, 0x00000000},
+	{0x00001478, 0x00000000},
+	{0x000014b8, 0x00000000},
+	{0x000014f8, 0x00000000},
+	{0x00001538, 0x00000000},
+	{0x00001578, 0x00000000},
+	{0x000015b8, 0x00000000},
+	{0x000015f8, 0x00000000},
+	{0x00001638, 0x00000000},
+	{0x00001678, 0x00000000},
+	{0x000016b8, 0x00000000},
+	{0x000016f8, 0x00000000},
+	{0x00001738, 0x00000000},
+	{0x00001778, 0x00000000},
+	{0x000017b8, 0x00000000},
+	{0x000017f8, 0x00000000},
+	{0x0000103c, 0x00000000},
+	{0x0000107c, 0x00000000},
+	{0x000010bc, 0x00000000},
+	{0x000010fc, 0x00000000},
+	{0x0000113c, 0x00000000},
+	{0x0000117c, 0x00000000},
+	{0x000011bc, 0x00000000},
+	{0x000011fc, 0x00000000},
+	{0x0000123c, 0x00000000},
+	{0x0000127c, 0x00000000},
+	{0x000012bc, 0x00000000},
+	{0x000012fc, 0x00000000},
+	{0x0000133c, 0x00000000},
+	{0x0000137c, 0x00000000},
+	{0x000013bc, 0x00000000},
+	{0x000013fc, 0x00000000},
+	{0x0000143c, 0x00000000},
+	{0x0000147c, 0x00000000},
+	{0x00004030, 0x00000002},
+	{0x0000403c, 0x00000002},
+	{0x00007010, 0x00000000},
+	{0x00007038, 0x000004c2},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000700},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008048, 0x40000000},
+	{0x00008054, 0x00000000},
+	{0x00008058, 0x00000000},
+	{0x0000805c, 0x000fc78f},
+	{0x00008060, 0x0000000f},
+	{0x00008064, 0x00000000},
+	{0x000080c0, 0x2a82301a},
+	{0x000080c4, 0x05dc01e0},
+	{0x000080c8, 0x1f402710},
+	{0x000080cc, 0x01f40000},
+	{0x000080d0, 0x00001e00},
+	{0x000080d4, 0x00000000},
+	{0x000080d8, 0x00400000},
+	{0x000080e0, 0xffffffff},
+	{0x000080e4, 0x0000ffff},
+	{0x000080e8, 0x003f3f3f},
+	{0x000080ec, 0x00000000},
+	{0x000080f0, 0x00000000},
+	{0x000080f4, 0x00000000},
+	{0x000080f8, 0x00000000},
+	{0x000080fc, 0x00020000},
+	{0x00008100, 0x00020000},
+	{0x00008104, 0x00000001},
+	{0x00008108, 0x00000052},
+	{0x0000810c, 0x00000000},
+	{0x00008110, 0x00000168},
+	{0x00008118, 0x000100aa},
+	{0x0000811c, 0x00003210},
+	{0x00008124, 0x00000000},
+	{0x00008128, 0x00000000},
+	{0x0000812c, 0x00000000},
+	{0x00008130, 0x00000000},
+	{0x00008134, 0x00000000},
+	{0x00008138, 0x00000000},
+	{0x0000813c, 0x00000000},
+	{0x00008144, 0xffffffff},
+	{0x00008168, 0x00000000},
+	{0x0000816c, 0x00000000},
+	{0x00008170, 0x32143320},
+	{0x00008174, 0xfaa4fa50},
+	{0x00008178, 0x00000100},
+	{0x0000817c, 0x00000000},
+	{0x000081c4, 0x00000000},
+	{0x000081ec, 0x00000000},
+	{0x000081f0, 0x00000000},
+	{0x000081f4, 0x00000000},
+	{0x000081f8, 0x00000000},
+	{0x000081fc, 0x00000000},
+	{0x00008200, 0x00000000},
+	{0x00008204, 0x00000000},
+	{0x00008208, 0x00000000},
+	{0x0000820c, 0x00000000},
+	{0x00008210, 0x00000000},
+	{0x00008214, 0x00000000},
+	{0x00008218, 0x00000000},
+	{0x0000821c, 0x00000000},
+	{0x00008220, 0x00000000},
+	{0x00008224, 0x00000000},
+	{0x00008228, 0x00000000},
+	{0x0000822c, 0x00000000},
+	{0x00008230, 0x00000000},
+	{0x00008234, 0x00000000},
+	{0x00008238, 0x00000000},
+	{0x0000823c, 0x00000000},
+	{0x00008240, 0x00100000},
+	{0x00008244, 0x0010f400},
+	{0x00008248, 0x00000100},
+	{0x0000824c, 0x0001e800},
+	{0x00008250, 0x00000000},
+	{0x00008254, 0x00000000},
+	{0x00008258, 0x00000000},
+	{0x0000825c, 0x400000ff},
+	{0x00008260, 0x00080922},
+	{0x00008264, 0x88000010},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000000},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x00000000},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x00008300, 0x00000000},
+	{0x00008304, 0x00000000},
+	{0x00008308, 0x00000000},
+	{0x0000830c, 0x00000000},
+	{0x00008310, 0x00000000},
+	{0x00008314, 0x00000000},
+	{0x00008318, 0x00000000},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000007},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000e00},
+	{0x00008338, 0x00070000},
+	{0x0000833c, 0x00000000},
+	{0x00008340, 0x000107ff},
+	{0x00009808, 0x00000000},
+	{0x0000980c, 0xad848e19},
+	{0x00009810, 0x7d14e000},
+	{0x00009814, 0x9c0a9f6b},
+	{0x0000981c, 0x00000000},
+	{0x0000982c, 0x0000a000},
+	{0x00009830, 0x00000000},
+	{0x0000983c, 0x00200400},
+	{0x00009840, 0x206a002e},
+	{0x0000984c, 0x1284233c},
+	{0x00009854, 0x00000859},
+	{0x00009900, 0x00000000},
+	{0x00009904, 0x00000000},
+	{0x00009908, 0x00000000},
+	{0x0000990c, 0x00000000},
+	{0x0000991c, 0x10000fff},
+	{0x00009920, 0x05100000},
+	{0x0000a920, 0x05100000},
+	{0x0000b920, 0x05100000},
+	{0x00009928, 0x00000001},
+	{0x0000992c, 0x00000004},
+	{0x00009934, 0x1e1f2022},
+	{0x00009938, 0x0a0b0c0d},
+	{0x0000993c, 0x00000000},
+	{0x00009948, 0x9280b212},
+	{0x0000994c, 0x00020028},
+	{0x00009954, 0x5d50e188},
+	{0x00009958, 0x00081fff},
+	{0x0000c95c, 0x004b6a8e},
+	{0x0000c968, 0x000003ce},
+	{0x00009970, 0x190fb515},
+	{0x00009974, 0x00000000},
+	{0x00009978, 0x00000001},
+	{0x0000997c, 0x00000000},
+	{0x00009980, 0x00000000},
+	{0x00009984, 0x00000000},
+	{0x00009988, 0x00000000},
+	{0x0000998c, 0x00000000},
+	{0x00009990, 0x00000000},
+	{0x00009994, 0x00000000},
+	{0x00009998, 0x00000000},
+	{0x0000999c, 0x00000000},
+	{0x000099a0, 0x00000000},
+	{0x000099a4, 0x00000001},
+	{0x000099a8, 0x001fff00},
+	{0x000099ac, 0x00000000},
+	{0x000099b0, 0x03051000},
+	{0x000099dc, 0x00000000},
+	{0x000099e0, 0x00000200},
+	{0x000099e4, 0xaaaaaaaa},
+	{0x000099e8, 0x3c466478},
+	{0x000099ec, 0x000000aa},
+	{0x000099fc, 0x00001042},
+	{0x00009b00, 0x00000000},
+	{0x00009b04, 0x00000001},
+	{0x00009b08, 0x00000002},
+	{0x00009b0c, 0x00000003},
+	{0x00009b10, 0x00000004},
+	{0x00009b14, 0x00000005},
+	{0x00009b18, 0x00000008},
+	{0x00009b1c, 0x00000009},
+	{0x00009b20, 0x0000000a},
+	{0x00009b24, 0x0000000b},
+	{0x00009b28, 0x0000000c},
+	{0x00009b2c, 0x0000000d},
+	{0x00009b30, 0x00000010},
+	{0x00009b34, 0x00000011},
+	{0x00009b38, 0x00000012},
+	{0x00009b3c, 0x00000013},
+	{0x00009b40, 0x00000014},
+	{0x00009b44, 0x00000015},
+	{0x00009b48, 0x00000018},
+	{0x00009b4c, 0x00000019},
+	{0x00009b50, 0x0000001a},
+	{0x00009b54, 0x0000001b},
+	{0x00009b58, 0x0000001c},
+	{0x00009b5c, 0x0000001d},
+	{0x00009b60, 0x00000020},
+	{0x00009b64, 0x00000021},
+	{0x00009b68, 0x00000022},
+	{0x00009b6c, 0x00000023},
+	{0x00009b70, 0x00000024},
+	{0x00009b74, 0x00000025},
+	{0x00009b78, 0x00000028},
+	{0x00009b7c, 0x00000029},
+	{0x00009b80, 0x0000002a},
+	{0x00009b84, 0x0000002b},
+	{0x00009b88, 0x0000002c},
+	{0x00009b8c, 0x0000002d},
+	{0x00009b90, 0x00000030},
+	{0x00009b94, 0x00000031},
+	{0x00009b98, 0x00000032},
+	{0x00009b9c, 0x00000033},
+	{0x00009ba0, 0x00000034},
+	{0x00009ba4, 0x00000035},
+	{0x00009ba8, 0x00000035},
+	{0x00009bac, 0x00000035},
+	{0x00009bb0, 0x00000035},
+	{0x00009bb4, 0x00000035},
+	{0x00009bb8, 0x00000035},
+	{0x00009bbc, 0x00000035},
+	{0x00009bc0, 0x00000035},
+	{0x00009bc4, 0x00000035},
+	{0x00009bc8, 0x00000035},
+	{0x00009bcc, 0x00000035},
+	{0x00009bd0, 0x00000035},
+	{0x00009bd4, 0x00000035},
+	{0x00009bd8, 0x00000035},
+	{0x00009bdc, 0x00000035},
+	{0x00009be0, 0x00000035},
+	{0x00009be4, 0x00000035},
+	{0x00009be8, 0x00000035},
+	{0x00009bec, 0x00000035},
+	{0x00009bf0, 0x00000035},
+	{0x00009bf4, 0x00000035},
+	{0x00009bf8, 0x00000010},
+	{0x00009bfc, 0x0000001a},
+	{0x0000a210, 0x40806333},
+	{0x0000a214, 0x00106c10},
+	{0x0000a218, 0x009c4060},
+	{0x0000a220, 0x018830c6},
+	{0x0000a224, 0x00000400},
+	{0x0000a228, 0x00000bb5},
+	{0x0000a22c, 0x00000011},
+	{0x0000a234, 0x20202020},
+	{0x0000a238, 0x20202020},
+	{0x0000a23c, 0x13c889af},
+	{0x0000a240, 0x38490a20},
+	{0x0000a244, 0x00007bb6},
+	{0x0000a248, 0x0fff3ffc},
+	{0x0000a24c, 0x00000001},
+	{0x0000a250, 0x0000a000},
+	{0x0000a254, 0x00000000},
+	{0x0000a258, 0x0cc75380},
+	{0x0000a25c, 0x0f0f0f01},
+	{0x0000a260, 0xdfa91f01},
+	{0x0000a268, 0x00000000},
+	{0x0000a26c, 0x0e79e5c6},
+	{0x0000b26c, 0x0e79e5c6},
+	{0x0000c26c, 0x0e79e5c6},
+	{0x0000d270, 0x00820820},
+	{0x0000a278, 0x1ce739ce},
+	{0x0000a27c, 0x051701ce},
+	{0x0000a338, 0x00000000},
+	{0x0000a33c, 0x00000000},
+	{0x0000a340, 0x00000000},
+	{0x0000a344, 0x00000000},
+	{0x0000a348, 0x3fffffff},
+	{0x0000a34c, 0x3fffffff},
+	{0x0000a350, 0x3fffffff},
+	{0x0000a354, 0x0003ffff},
+	{0x0000a358, 0x79a8aa1f},
+	{0x0000d35c, 0x07ffffef},
+	{0x0000d360, 0x0fffffe7},
+	{0x0000d364, 0x17ffffe5},
+	{0x0000d368, 0x1fffffe4},
+	{0x0000d36c, 0x37ffffe3},
+	{0x0000d370, 0x3fffffe3},
+	{0x0000d374, 0x57ffffe3},
+	{0x0000d378, 0x5fffffe2},
+	{0x0000d37c, 0x7fffffe2},
+	{0x0000d380, 0x7f3c7bba},
+	{0x0000d384, 0xf3307ff0},
+	{0x0000a388, 0x08000000},
+	{0x0000a38c, 0x20202020},
+	{0x0000a390, 0x20202020},
+	{0x0000a394, 0x1ce739ce},
+	{0x0000a398, 0x000001ce},
+	{0x0000a39c, 0x00000001},
+	{0x0000a3a0, 0x00000000},
+	{0x0000a3a4, 0x00000000},
+	{0x0000a3a8, 0x00000000},
+	{0x0000a3ac, 0x00000000},
+	{0x0000a3b0, 0x00000000},
+	{0x0000a3b4, 0x00000000},
+	{0x0000a3b8, 0x00000000},
+	{0x0000a3bc, 0x00000000},
+	{0x0000a3c0, 0x00000000},
+	{0x0000a3c4, 0x00000000},
+	{0x0000a3c8, 0x00000246},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3dc, 0x1ce739ce},
+	{0x0000a3e0, 0x000001ce},
+};
+
+static const u32 ar5416Bank0[][2] = {
+	/* Addr      allmodes  */
+	{0x000098b0, 0x1e5795e5},
+	{0x000098e0, 0x02008020},
+};
+
+static const u32 ar5416BB_RfGain[][3] = {
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x00009a00, 0x00000000, 0x00000000},
+	{0x00009a04, 0x00000040, 0x00000040},
+	{0x00009a08, 0x00000080, 0x00000080},
+	{0x00009a0c, 0x000001a1, 0x00000141},
+	{0x00009a10, 0x000001e1, 0x00000181},
+	{0x00009a14, 0x00000021, 0x000001c1},
+	{0x00009a18, 0x00000061, 0x00000001},
+	{0x00009a1c, 0x00000168, 0x00000041},
+	{0x00009a20, 0x000001a8, 0x000001a8},
+	{0x00009a24, 0x000001e8, 0x000001e8},
+	{0x00009a28, 0x00000028, 0x00000028},
+	{0x00009a2c, 0x00000068, 0x00000068},
+	{0x00009a30, 0x00000189, 0x000000a8},
+	{0x00009a34, 0x000001c9, 0x00000169},
+	{0x00009a38, 0x00000009, 0x000001a9},
+	{0x00009a3c, 0x00000049, 0x000001e9},
+	{0x00009a40, 0x00000089, 0x00000029},
+	{0x00009a44, 0x00000170, 0x00000069},
+	{0x00009a48, 0x000001b0, 0x00000190},
+	{0x00009a4c, 0x000001f0, 0x000001d0},
+	{0x00009a50, 0x00000030, 0x00000010},
+	{0x00009a54, 0x00000070, 0x00000050},
+	{0x00009a58, 0x00000191, 0x00000090},
+	{0x00009a5c, 0x000001d1, 0x00000151},
+	{0x00009a60, 0x00000011, 0x00000191},
+	{0x00009a64, 0x00000051, 0x000001d1},
+	{0x00009a68, 0x00000091, 0x00000011},
+	{0x00009a6c, 0x000001b8, 0x00000051},
+	{0x00009a70, 0x000001f8, 0x00000198},
+	{0x00009a74, 0x00000038, 0x000001d8},
+	{0x00009a78, 0x00000078, 0x00000018},
+	{0x00009a7c, 0x00000199, 0x00000058},
+	{0x00009a80, 0x000001d9, 0x00000098},
+	{0x00009a84, 0x00000019, 0x00000159},
+	{0x00009a88, 0x00000059, 0x00000199},
+	{0x00009a8c, 0x00000099, 0x000001d9},
+	{0x00009a90, 0x000000d9, 0x00000019},
+	{0x00009a94, 0x000000f9, 0x00000059},
+	{0x00009a98, 0x000000f9, 0x00000099},
+	{0x00009a9c, 0x000000f9, 0x000000d9},
+	{0x00009aa0, 0x000000f9, 0x000000f9},
+	{0x00009aa4, 0x000000f9, 0x000000f9},
+	{0x00009aa8, 0x000000f9, 0x000000f9},
+	{0x00009aac, 0x000000f9, 0x000000f9},
+	{0x00009ab0, 0x000000f9, 0x000000f9},
+	{0x00009ab4, 0x000000f9, 0x000000f9},
+	{0x00009ab8, 0x000000f9, 0x000000f9},
+	{0x00009abc, 0x000000f9, 0x000000f9},
+	{0x00009ac0, 0x000000f9, 0x000000f9},
+	{0x00009ac4, 0x000000f9, 0x000000f9},
+	{0x00009ac8, 0x000000f9, 0x000000f9},
+	{0x00009acc, 0x000000f9, 0x000000f9},
+	{0x00009ad0, 0x000000f9, 0x000000f9},
+	{0x00009ad4, 0x000000f9, 0x000000f9},
+	{0x00009ad8, 0x000000f9, 0x000000f9},
+	{0x00009adc, 0x000000f9, 0x000000f9},
+	{0x00009ae0, 0x000000f9, 0x000000f9},
+	{0x00009ae4, 0x000000f9, 0x000000f9},
+	{0x00009ae8, 0x000000f9, 0x000000f9},
+	{0x00009aec, 0x000000f9, 0x000000f9},
+	{0x00009af0, 0x000000f9, 0x000000f9},
+	{0x00009af4, 0x000000f9, 0x000000f9},
+	{0x00009af8, 0x000000f9, 0x000000f9},
+	{0x00009afc, 0x000000f9, 0x000000f9},
+};
+
+static const u32 ar5416Bank1[][2] = {
+	/* Addr      allmodes  */
+	{0x000098b0, 0x02108421},
+	{0x000098ec, 0x00000008},
+};
+
+static const u32 ar5416Bank2[][2] = {
+	/* Addr      allmodes  */
+	{0x000098b0, 0x0e73ff17},
+	{0x000098e0, 0x00000420},
+};
+
+static const u32 ar5416Bank3[][3] = {
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x000098f0, 0x01400018, 0x01c00018},
+};
+
+static const u32 ar5416Bank6[][3] = {
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00e00000, 0x00e00000},
+	{0x0000989c, 0x005e0000, 0x005e0000},
+	{0x0000989c, 0x00120000, 0x00120000},
+	{0x0000989c, 0x00620000, 0x00620000},
+	{0x0000989c, 0x00020000, 0x00020000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x40ff0000, 0x40ff0000},
+	{0x0000989c, 0x005f0000, 0x005f0000},
+	{0x0000989c, 0x00870000, 0x00870000},
+	{0x0000989c, 0x00f90000, 0x00f90000},
+	{0x0000989c, 0x007b0000, 0x007b0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00f50000, 0x00f50000},
+	{0x0000989c, 0x00dc0000, 0x00dc0000},
+	{0x0000989c, 0x00110000, 0x00110000},
+	{0x0000989c, 0x006100a8, 0x006100a8},
+	{0x0000989c, 0x004210a2, 0x004210a2},
+	{0x0000989c, 0x0014008f, 0x0014008f},
+	{0x0000989c, 0x00c40003, 0x00c40003},
+	{0x0000989c, 0x003000f2, 0x003000f2},
+	{0x0000989c, 0x00440016, 0x00440016},
+	{0x0000989c, 0x00410040, 0x00410040},
+	{0x0000989c, 0x0001805e, 0x0001805e},
+	{0x0000989c, 0x0000c0ab, 0x0000c0ab},
+	{0x0000989c, 0x000000f1, 0x000000f1},
+	{0x0000989c, 0x00002081, 0x00002081},
+	{0x0000989c, 0x000000d4, 0x000000d4},
+	{0x000098d0, 0x0000000f, 0x0010000f},
+};
+
+static const u32 ar5416Bank6TPC[][3] = {
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00e00000, 0x00e00000},
+	{0x0000989c, 0x005e0000, 0x005e0000},
+	{0x0000989c, 0x00120000, 0x00120000},
+	{0x0000989c, 0x00620000, 0x00620000},
+	{0x0000989c, 0x00020000, 0x00020000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x40ff0000, 0x40ff0000},
+	{0x0000989c, 0x005f0000, 0x005f0000},
+	{0x0000989c, 0x00870000, 0x00870000},
+	{0x0000989c, 0x00f90000, 0x00f90000},
+	{0x0000989c, 0x007b0000, 0x007b0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00f50000, 0x00f50000},
+	{0x0000989c, 0x00dc0000, 0x00dc0000},
+	{0x0000989c, 0x00110000, 0x00110000},
+	{0x0000989c, 0x006100a8, 0x006100a8},
+	{0x0000989c, 0x00423022, 0x00423022},
+	{0x0000989c, 0x201400df, 0x201400df},
+	{0x0000989c, 0x00c40002, 0x00c40002},
+	{0x0000989c, 0x003000f2, 0x003000f2},
+	{0x0000989c, 0x00440016, 0x00440016},
+	{0x0000989c, 0x00410040, 0x00410040},
+	{0x0000989c, 0x0001805e, 0x0001805e},
+	{0x0000989c, 0x0000c0ab, 0x0000c0ab},
+	{0x0000989c, 0x000000e1, 0x000000e1},
+	{0x0000989c, 0x00007081, 0x00007081},
+	{0x0000989c, 0x000000d4, 0x000000d4},
+	{0x000098d0, 0x0000000f, 0x0010000f},
+};
+
+static const u32 ar5416Bank7[][2] = {
+	/* Addr      allmodes  */
+	{0x0000989c, 0x00000500},
+	{0x0000989c, 0x00000800},
+	{0x000098cc, 0x0000000e},
+};
+
+static const u32 ar5416Addac[][2] = {
+	/* Addr      allmodes  */
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000003},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x0000000c},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000030},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000060},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000058},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x000098cc, 0x00000000},
+};
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ar9001_initvals.h b/roms/ipxe/src/drivers/net/ath/ath9k/ar9001_initvals.h
new file mode 100644
index 0000000000000000000000000000000000000000..7dca47443ce8cfa3b453e1f90bf43701ad92e1bf
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ar9001_initvals.h
@@ -0,0 +1,1356 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+static const u32 ar5416Modes_9100[][6] = {
+	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
+	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
+	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
+	{0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008},
+	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
+	{0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf},
+	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
+	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
+	{0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
+	{0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+	{0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+	{0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+	{0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0},
+	{0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x00009850, 0x6c48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6c48b0e2, 0x6c48b0e2},
+	{0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e},
+	{0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e},
+	{0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18},
+	{0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+	{0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0},
+	{0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081},
+	{0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+	{0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016},
+	{0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d},
+	{0x00009940, 0x00750604, 0x00754604, 0xfff81204, 0xfff81204, 0xfff81204},
+	{0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020},
+	{0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e, 0xe250a51e},
+	{0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff, 0x3388ffff},
+	{0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0},
+	{0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0},
+	{0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0},
+	{0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120},
+	{0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00, 0x001a0c00},
+	{0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be},
+	{0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+	{0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329},
+	{0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+	{0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+	{0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880},
+	{0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788},
+	{0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+	{0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+	{0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa},
+	{0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000},
+	{0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402},
+	{0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06},
+	{0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b},
+	{0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b},
+	{0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a},
+	{0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf},
+	{0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f},
+	{0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f},
+	{0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f},
+	{0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+};
+
+static const u32 ar5416Common_9100[][2] = {
+	/* Addr      allmodes  */
+	{0x0000000c, 0x00000000},
+	{0x00000030, 0x00020015},
+	{0x00000034, 0x00000005},
+	{0x00000040, 0x00000000},
+	{0x00000044, 0x00000008},
+	{0x00000048, 0x00000008},
+	{0x0000004c, 0x00000010},
+	{0x00000050, 0x00000000},
+	{0x00000054, 0x0000001f},
+	{0x00000800, 0x00000000},
+	{0x00000804, 0x00000000},
+	{0x00000808, 0x00000000},
+	{0x0000080c, 0x00000000},
+	{0x00000810, 0x00000000},
+	{0x00000814, 0x00000000},
+	{0x00000818, 0x00000000},
+	{0x0000081c, 0x00000000},
+	{0x00000820, 0x00000000},
+	{0x00000824, 0x00000000},
+	{0x00001040, 0x002ffc0f},
+	{0x00001044, 0x002ffc0f},
+	{0x00001048, 0x002ffc0f},
+	{0x0000104c, 0x002ffc0f},
+	{0x00001050, 0x002ffc0f},
+	{0x00001054, 0x002ffc0f},
+	{0x00001058, 0x002ffc0f},
+	{0x0000105c, 0x002ffc0f},
+	{0x00001060, 0x002ffc0f},
+	{0x00001064, 0x002ffc0f},
+	{0x00001230, 0x00000000},
+	{0x00001270, 0x00000000},
+	{0x00001038, 0x00000000},
+	{0x00001078, 0x00000000},
+	{0x000010b8, 0x00000000},
+	{0x000010f8, 0x00000000},
+	{0x00001138, 0x00000000},
+	{0x00001178, 0x00000000},
+	{0x000011b8, 0x00000000},
+	{0x000011f8, 0x00000000},
+	{0x00001238, 0x00000000},
+	{0x00001278, 0x00000000},
+	{0x000012b8, 0x00000000},
+	{0x000012f8, 0x00000000},
+	{0x00001338, 0x00000000},
+	{0x00001378, 0x00000000},
+	{0x000013b8, 0x00000000},
+	{0x000013f8, 0x00000000},
+	{0x00001438, 0x00000000},
+	{0x00001478, 0x00000000},
+	{0x000014b8, 0x00000000},
+	{0x000014f8, 0x00000000},
+	{0x00001538, 0x00000000},
+	{0x00001578, 0x00000000},
+	{0x000015b8, 0x00000000},
+	{0x000015f8, 0x00000000},
+	{0x00001638, 0x00000000},
+	{0x00001678, 0x00000000},
+	{0x000016b8, 0x00000000},
+	{0x000016f8, 0x00000000},
+	{0x00001738, 0x00000000},
+	{0x00001778, 0x00000000},
+	{0x000017b8, 0x00000000},
+	{0x000017f8, 0x00000000},
+	{0x0000103c, 0x00000000},
+	{0x0000107c, 0x00000000},
+	{0x000010bc, 0x00000000},
+	{0x000010fc, 0x00000000},
+	{0x0000113c, 0x00000000},
+	{0x0000117c, 0x00000000},
+	{0x000011bc, 0x00000000},
+	{0x000011fc, 0x00000000},
+	{0x0000123c, 0x00000000},
+	{0x0000127c, 0x00000000},
+	{0x000012bc, 0x00000000},
+	{0x000012fc, 0x00000000},
+	{0x0000133c, 0x00000000},
+	{0x0000137c, 0x00000000},
+	{0x000013bc, 0x00000000},
+	{0x000013fc, 0x00000000},
+	{0x0000143c, 0x00000000},
+	{0x0000147c, 0x00000000},
+	{0x00020010, 0x00000003},
+	{0x00020038, 0x000004c2},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000700},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008048, 0x40000000},
+	{0x00008054, 0x00004000},
+	{0x00008058, 0x00000000},
+	{0x0000805c, 0x000fc78f},
+	{0x00008060, 0x0000000f},
+	{0x00008064, 0x00000000},
+	{0x000080c0, 0x2a82301a},
+	{0x000080c4, 0x05dc01e0},
+	{0x000080c8, 0x1f402710},
+	{0x000080cc, 0x01f40000},
+	{0x000080d0, 0x00001e00},
+	{0x000080d4, 0x00000000},
+	{0x000080d8, 0x00400000},
+	{0x000080e0, 0xffffffff},
+	{0x000080e4, 0x0000ffff},
+	{0x000080e8, 0x003f3f3f},
+	{0x000080ec, 0x00000000},
+	{0x000080f0, 0x00000000},
+	{0x000080f4, 0x00000000},
+	{0x000080f8, 0x00000000},
+	{0x000080fc, 0x00020000},
+	{0x00008100, 0x00020000},
+	{0x00008104, 0x00000001},
+	{0x00008108, 0x00000052},
+	{0x0000810c, 0x00000000},
+	{0x00008110, 0x00000168},
+	{0x00008118, 0x000100aa},
+	{0x0000811c, 0x00003210},
+	{0x00008120, 0x08f04800},
+	{0x00008124, 0x00000000},
+	{0x00008128, 0x00000000},
+	{0x0000812c, 0x00000000},
+	{0x00008130, 0x00000000},
+	{0x00008134, 0x00000000},
+	{0x00008138, 0x00000000},
+	{0x0000813c, 0x00000000},
+	{0x00008144, 0x00000000},
+	{0x00008168, 0x00000000},
+	{0x0000816c, 0x00000000},
+	{0x00008170, 0x32143320},
+	{0x00008174, 0xfaa4fa50},
+	{0x00008178, 0x00000100},
+	{0x0000817c, 0x00000000},
+	{0x000081c4, 0x00000000},
+	{0x000081d0, 0x00003210},
+	{0x000081ec, 0x00000000},
+	{0x000081f0, 0x00000000},
+	{0x000081f4, 0x00000000},
+	{0x000081f8, 0x00000000},
+	{0x000081fc, 0x00000000},
+	{0x00008200, 0x00000000},
+	{0x00008204, 0x00000000},
+	{0x00008208, 0x00000000},
+	{0x0000820c, 0x00000000},
+	{0x00008210, 0x00000000},
+	{0x00008214, 0x00000000},
+	{0x00008218, 0x00000000},
+	{0x0000821c, 0x00000000},
+	{0x00008220, 0x00000000},
+	{0x00008224, 0x00000000},
+	{0x00008228, 0x00000000},
+	{0x0000822c, 0x00000000},
+	{0x00008230, 0x00000000},
+	{0x00008234, 0x00000000},
+	{0x00008238, 0x00000000},
+	{0x0000823c, 0x00000000},
+	{0x00008240, 0x00100000},
+	{0x00008244, 0x0010f400},
+	{0x00008248, 0x00000100},
+	{0x0000824c, 0x0001e800},
+	{0x00008250, 0x00000000},
+	{0x00008254, 0x00000000},
+	{0x00008258, 0x00000000},
+	{0x0000825c, 0x400000ff},
+	{0x00008260, 0x00080922},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000000},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x00000000},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x00008300, 0x00000000},
+	{0x00008304, 0x00000000},
+	{0x00008308, 0x00000000},
+	{0x0000830c, 0x00000000},
+	{0x00008310, 0x00000000},
+	{0x00008314, 0x00000000},
+	{0x00008318, 0x00000000},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000007},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000e00},
+	{0x00008338, 0x00000000},
+	{0x0000833c, 0x00000000},
+	{0x00008340, 0x000107ff},
+	{0x00009808, 0x00000000},
+	{0x0000980c, 0xad848e19},
+	{0x00009810, 0x7d14e000},
+	{0x00009814, 0x9c0a9f6b},
+	{0x0000981c, 0x00000000},
+	{0x0000982c, 0x0000a000},
+	{0x00009830, 0x00000000},
+	{0x0000983c, 0x00200400},
+	{0x00009840, 0x206a01ae},
+	{0x0000984c, 0x1284233c},
+	{0x00009854, 0x00000859},
+	{0x00009900, 0x00000000},
+	{0x00009904, 0x00000000},
+	{0x00009908, 0x00000000},
+	{0x0000990c, 0x00000000},
+	{0x0000991c, 0x10000fff},
+	{0x00009920, 0x05100000},
+	{0x0000a920, 0x05100000},
+	{0x0000b920, 0x05100000},
+	{0x00009928, 0x00000001},
+	{0x0000992c, 0x00000004},
+	{0x00009934, 0x1e1f2022},
+	{0x00009938, 0x0a0b0c0d},
+	{0x0000993c, 0x00000000},
+	{0x00009948, 0x9280b212},
+	{0x0000994c, 0x00020028},
+	{0x0000c95c, 0x004b6a8e},
+	{0x0000c968, 0x000003ce},
+	{0x00009970, 0x190fb515},
+	{0x00009974, 0x00000000},
+	{0x00009978, 0x00000001},
+	{0x0000997c, 0x00000000},
+	{0x00009980, 0x00000000},
+	{0x00009984, 0x00000000},
+	{0x00009988, 0x00000000},
+	{0x0000998c, 0x00000000},
+	{0x00009990, 0x00000000},
+	{0x00009994, 0x00000000},
+	{0x00009998, 0x00000000},
+	{0x0000999c, 0x00000000},
+	{0x000099a0, 0x00000000},
+	{0x000099a4, 0x00000001},
+	{0x000099a8, 0x201fff00},
+	{0x000099ac, 0x006f0000},
+	{0x000099b0, 0x03051000},
+	{0x000099dc, 0x00000000},
+	{0x000099e0, 0x00000200},
+	{0x000099e4, 0xaaaaaaaa},
+	{0x000099e8, 0x3c466478},
+	{0x000099ec, 0x0cc80caa},
+	{0x000099fc, 0x00001042},
+	{0x00009b00, 0x00000000},
+	{0x00009b04, 0x00000001},
+	{0x00009b08, 0x00000002},
+	{0x00009b0c, 0x00000003},
+	{0x00009b10, 0x00000004},
+	{0x00009b14, 0x00000005},
+	{0x00009b18, 0x00000008},
+	{0x00009b1c, 0x00000009},
+	{0x00009b20, 0x0000000a},
+	{0x00009b24, 0x0000000b},
+	{0x00009b28, 0x0000000c},
+	{0x00009b2c, 0x0000000d},
+	{0x00009b30, 0x00000010},
+	{0x00009b34, 0x00000011},
+	{0x00009b38, 0x00000012},
+	{0x00009b3c, 0x00000013},
+	{0x00009b40, 0x00000014},
+	{0x00009b44, 0x00000015},
+	{0x00009b48, 0x00000018},
+	{0x00009b4c, 0x00000019},
+	{0x00009b50, 0x0000001a},
+	{0x00009b54, 0x0000001b},
+	{0x00009b58, 0x0000001c},
+	{0x00009b5c, 0x0000001d},
+	{0x00009b60, 0x00000020},
+	{0x00009b64, 0x00000021},
+	{0x00009b68, 0x00000022},
+	{0x00009b6c, 0x00000023},
+	{0x00009b70, 0x00000024},
+	{0x00009b74, 0x00000025},
+	{0x00009b78, 0x00000028},
+	{0x00009b7c, 0x00000029},
+	{0x00009b80, 0x0000002a},
+	{0x00009b84, 0x0000002b},
+	{0x00009b88, 0x0000002c},
+	{0x00009b8c, 0x0000002d},
+	{0x00009b90, 0x00000030},
+	{0x00009b94, 0x00000031},
+	{0x00009b98, 0x00000032},
+	{0x00009b9c, 0x00000033},
+	{0x00009ba0, 0x00000034},
+	{0x00009ba4, 0x00000035},
+	{0x00009ba8, 0x00000035},
+	{0x00009bac, 0x00000035},
+	{0x00009bb0, 0x00000035},
+	{0x00009bb4, 0x00000035},
+	{0x00009bb8, 0x00000035},
+	{0x00009bbc, 0x00000035},
+	{0x00009bc0, 0x00000035},
+	{0x00009bc4, 0x00000035},
+	{0x00009bc8, 0x00000035},
+	{0x00009bcc, 0x00000035},
+	{0x00009bd0, 0x00000035},
+	{0x00009bd4, 0x00000035},
+	{0x00009bd8, 0x00000035},
+	{0x00009bdc, 0x00000035},
+	{0x00009be0, 0x00000035},
+	{0x00009be4, 0x00000035},
+	{0x00009be8, 0x00000035},
+	{0x00009bec, 0x00000035},
+	{0x00009bf0, 0x00000035},
+	{0x00009bf4, 0x00000035},
+	{0x00009bf8, 0x00000010},
+	{0x00009bfc, 0x0000001a},
+	{0x0000a210, 0x40806333},
+	{0x0000a214, 0x00106c10},
+	{0x0000a218, 0x009c4060},
+	{0x0000a220, 0x018830c6},
+	{0x0000a224, 0x00000400},
+	{0x0000a228, 0x001a0bb5},
+	{0x0000a22c, 0x00000000},
+	{0x0000a234, 0x20202020},
+	{0x0000a238, 0x20202020},
+	{0x0000a23c, 0x13c889af},
+	{0x0000a240, 0x38490a20},
+	{0x0000a244, 0x00007bb6},
+	{0x0000a248, 0x0fff3ffc},
+	{0x0000a24c, 0x00000001},
+	{0x0000a250, 0x0000e000},
+	{0x0000a254, 0x00000000},
+	{0x0000a258, 0x0cc75380},
+	{0x0000a25c, 0x0f0f0f01},
+	{0x0000a260, 0xdfa91f01},
+	{0x0000a268, 0x00000001},
+	{0x0000a26c, 0x0ebae9c6},
+	{0x0000b26c, 0x0ebae9c6},
+	{0x0000c26c, 0x0ebae9c6},
+	{0x0000d270, 0x00820820},
+	{0x0000a278, 0x1ce739ce},
+	{0x0000a27c, 0x050701ce},
+	{0x0000a338, 0x00000000},
+	{0x0000a33c, 0x00000000},
+	{0x0000a340, 0x00000000},
+	{0x0000a344, 0x00000000},
+	{0x0000a348, 0x3fffffff},
+	{0x0000a34c, 0x3fffffff},
+	{0x0000a350, 0x3fffffff},
+	{0x0000a354, 0x0003ffff},
+	{0x0000a358, 0x79a8aa33},
+	{0x0000d35c, 0x07ffffef},
+	{0x0000d360, 0x0fffffe7},
+	{0x0000d364, 0x17ffffe5},
+	{0x0000d368, 0x1fffffe4},
+	{0x0000d36c, 0x37ffffe3},
+	{0x0000d370, 0x3fffffe3},
+	{0x0000d374, 0x57ffffe3},
+	{0x0000d378, 0x5fffffe2},
+	{0x0000d37c, 0x7fffffe2},
+	{0x0000d380, 0x7f3c7bba},
+	{0x0000d384, 0xf3307ff0},
+	{0x0000a388, 0x0c000000},
+	{0x0000a38c, 0x20202020},
+	{0x0000a390, 0x20202020},
+	{0x0000a394, 0x1ce739ce},
+	{0x0000a398, 0x000001ce},
+	{0x0000a39c, 0x00000001},
+	{0x0000a3a0, 0x00000000},
+	{0x0000a3a4, 0x00000000},
+	{0x0000a3a8, 0x00000000},
+	{0x0000a3ac, 0x00000000},
+	{0x0000a3b0, 0x00000000},
+	{0x0000a3b4, 0x00000000},
+	{0x0000a3b8, 0x00000000},
+	{0x0000a3bc, 0x00000000},
+	{0x0000a3c0, 0x00000000},
+	{0x0000a3c4, 0x00000000},
+	{0x0000a3c8, 0x00000246},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3dc, 0x1ce739ce},
+	{0x0000a3e0, 0x000001ce},
+};
+
+static const u32 ar5416Bank0_9100[][2] = {
+	/* Addr      allmodes  */
+	{0x000098b0, 0x1e5795e5},
+	{0x000098e0, 0x02008020},
+};
+
+static const u32 ar5416BB_RfGain_9100[][3] = {
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x00009a00, 0x00000000, 0x00000000},
+	{0x00009a04, 0x00000040, 0x00000040},
+	{0x00009a08, 0x00000080, 0x00000080},
+	{0x00009a0c, 0x000001a1, 0x00000141},
+	{0x00009a10, 0x000001e1, 0x00000181},
+	{0x00009a14, 0x00000021, 0x000001c1},
+	{0x00009a18, 0x00000061, 0x00000001},
+	{0x00009a1c, 0x00000168, 0x00000041},
+	{0x00009a20, 0x000001a8, 0x000001a8},
+	{0x00009a24, 0x000001e8, 0x000001e8},
+	{0x00009a28, 0x00000028, 0x00000028},
+	{0x00009a2c, 0x00000068, 0x00000068},
+	{0x00009a30, 0x00000189, 0x000000a8},
+	{0x00009a34, 0x000001c9, 0x00000169},
+	{0x00009a38, 0x00000009, 0x000001a9},
+	{0x00009a3c, 0x00000049, 0x000001e9},
+	{0x00009a40, 0x00000089, 0x00000029},
+	{0x00009a44, 0x00000170, 0x00000069},
+	{0x00009a48, 0x000001b0, 0x00000190},
+	{0x00009a4c, 0x000001f0, 0x000001d0},
+	{0x00009a50, 0x00000030, 0x00000010},
+	{0x00009a54, 0x00000070, 0x00000050},
+	{0x00009a58, 0x00000191, 0x00000090},
+	{0x00009a5c, 0x000001d1, 0x00000151},
+	{0x00009a60, 0x00000011, 0x00000191},
+	{0x00009a64, 0x00000051, 0x000001d1},
+	{0x00009a68, 0x00000091, 0x00000011},
+	{0x00009a6c, 0x000001b8, 0x00000051},
+	{0x00009a70, 0x000001f8, 0x00000198},
+	{0x00009a74, 0x00000038, 0x000001d8},
+	{0x00009a78, 0x00000078, 0x00000018},
+	{0x00009a7c, 0x00000199, 0x00000058},
+	{0x00009a80, 0x000001d9, 0x00000098},
+	{0x00009a84, 0x00000019, 0x00000159},
+	{0x00009a88, 0x00000059, 0x00000199},
+	{0x00009a8c, 0x00000099, 0x000001d9},
+	{0x00009a90, 0x000000d9, 0x00000019},
+	{0x00009a94, 0x000000f9, 0x00000059},
+	{0x00009a98, 0x000000f9, 0x00000099},
+	{0x00009a9c, 0x000000f9, 0x000000d9},
+	{0x00009aa0, 0x000000f9, 0x000000f9},
+	{0x00009aa4, 0x000000f9, 0x000000f9},
+	{0x00009aa8, 0x000000f9, 0x000000f9},
+	{0x00009aac, 0x000000f9, 0x000000f9},
+	{0x00009ab0, 0x000000f9, 0x000000f9},
+	{0x00009ab4, 0x000000f9, 0x000000f9},
+	{0x00009ab8, 0x000000f9, 0x000000f9},
+	{0x00009abc, 0x000000f9, 0x000000f9},
+	{0x00009ac0, 0x000000f9, 0x000000f9},
+	{0x00009ac4, 0x000000f9, 0x000000f9},
+	{0x00009ac8, 0x000000f9, 0x000000f9},
+	{0x00009acc, 0x000000f9, 0x000000f9},
+	{0x00009ad0, 0x000000f9, 0x000000f9},
+	{0x00009ad4, 0x000000f9, 0x000000f9},
+	{0x00009ad8, 0x000000f9, 0x000000f9},
+	{0x00009adc, 0x000000f9, 0x000000f9},
+	{0x00009ae0, 0x000000f9, 0x000000f9},
+	{0x00009ae4, 0x000000f9, 0x000000f9},
+	{0x00009ae8, 0x000000f9, 0x000000f9},
+	{0x00009aec, 0x000000f9, 0x000000f9},
+	{0x00009af0, 0x000000f9, 0x000000f9},
+	{0x00009af4, 0x000000f9, 0x000000f9},
+	{0x00009af8, 0x000000f9, 0x000000f9},
+	{0x00009afc, 0x000000f9, 0x000000f9},
+};
+
+static const u32 ar5416Bank1_9100[][2] = {
+	/* Addr      allmodes  */
+	{0x000098b0, 0x02108421},
+	{0x000098ec, 0x00000008},
+};
+
+static const u32 ar5416Bank2_9100[][2] = {
+	/* Addr      allmodes  */
+	{0x000098b0, 0x0e73ff17},
+	{0x000098e0, 0x00000420},
+};
+
+static const u32 ar5416Bank3_9100[][3] = {
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x000098f0, 0x01400018, 0x01c00018},
+};
+
+static const u32 ar5416Bank6_9100[][3] = {
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00e00000, 0x00e00000},
+	{0x0000989c, 0x005e0000, 0x005e0000},
+	{0x0000989c, 0x00120000, 0x00120000},
+	{0x0000989c, 0x00620000, 0x00620000},
+	{0x0000989c, 0x00020000, 0x00020000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x005f0000, 0x005f0000},
+	{0x0000989c, 0x00870000, 0x00870000},
+	{0x0000989c, 0x00f90000, 0x00f90000},
+	{0x0000989c, 0x007b0000, 0x007b0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00f50000, 0x00f50000},
+	{0x0000989c, 0x00dc0000, 0x00dc0000},
+	{0x0000989c, 0x00110000, 0x00110000},
+	{0x0000989c, 0x006100a8, 0x006100a8},
+	{0x0000989c, 0x004210a2, 0x004210a2},
+	{0x0000989c, 0x0014000f, 0x0014000f},
+	{0x0000989c, 0x00c40002, 0x00c40002},
+	{0x0000989c, 0x003000f2, 0x003000f2},
+	{0x0000989c, 0x00440016, 0x00440016},
+	{0x0000989c, 0x00410040, 0x00410040},
+	{0x0000989c, 0x000180d6, 0x000180d6},
+	{0x0000989c, 0x0000c0aa, 0x0000c0aa},
+	{0x0000989c, 0x000000b1, 0x000000b1},
+	{0x0000989c, 0x00002000, 0x00002000},
+	{0x0000989c, 0x000000d4, 0x000000d4},
+	{0x000098d0, 0x0000000f, 0x0010000f},
+};
+
+static const u32 ar5416Bank6TPC_9100[][3] = {
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00e00000, 0x00e00000},
+	{0x0000989c, 0x005e0000, 0x005e0000},
+	{0x0000989c, 0x00120000, 0x00120000},
+	{0x0000989c, 0x00620000, 0x00620000},
+	{0x0000989c, 0x00020000, 0x00020000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x40ff0000, 0x40ff0000},
+	{0x0000989c, 0x005f0000, 0x005f0000},
+	{0x0000989c, 0x00870000, 0x00870000},
+	{0x0000989c, 0x00f90000, 0x00f90000},
+	{0x0000989c, 0x007b0000, 0x007b0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00f50000, 0x00f50000},
+	{0x0000989c, 0x00dc0000, 0x00dc0000},
+	{0x0000989c, 0x00110000, 0x00110000},
+	{0x0000989c, 0x006100a8, 0x006100a8},
+	{0x0000989c, 0x00423022, 0x00423022},
+	{0x0000989c, 0x2014008f, 0x2014008f},
+	{0x0000989c, 0x00c40002, 0x00c40002},
+	{0x0000989c, 0x003000f2, 0x003000f2},
+	{0x0000989c, 0x00440016, 0x00440016},
+	{0x0000989c, 0x00410040, 0x00410040},
+	{0x0000989c, 0x0001805e, 0x0001805e},
+	{0x0000989c, 0x0000c0ab, 0x0000c0ab},
+	{0x0000989c, 0x000000e1, 0x000000e1},
+	{0x0000989c, 0x00007080, 0x00007080},
+	{0x0000989c, 0x000000d4, 0x000000d4},
+	{0x000098d0, 0x0000000f, 0x0010000f},
+};
+
+static const u32 ar5416Bank7_9100[][2] = {
+	/* Addr      allmodes  */
+	{0x0000989c, 0x00000500},
+	{0x0000989c, 0x00000800},
+	{0x000098cc, 0x0000000e},
+};
+
+static const u32 ar5416Addac_9100[][2] = {
+	/* Addr      allmodes  */
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000010},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x000000c0},
+	{0x0000989c, 0x00000015},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x000098cc, 0x00000000},
+};
+
+static const u32 ar5416Modes_9160[][6] = {
+	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
+	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
+	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
+	{0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008},
+	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
+	{0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf},
+	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
+	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
+	{0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
+	{0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+	{0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+	{0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+	{0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0},
+	{0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68},
+	{0x00009850, 0x6c48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6c48b0e2, 0x6c48b0e2},
+	{0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e},
+	{0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e},
+	{0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18},
+	{0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+	{0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0},
+	{0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081},
+	{0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+	{0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016},
+	{0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d},
+	{0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020},
+	{0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40},
+	{0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40},
+	{0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40},
+	{0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120},
+	{0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce},
+	{0x000099bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00},
+	{0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be},
+	{0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+	{0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329},
+	{0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+	{0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+	{0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880},
+	{0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788},
+	{0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120},
+	{0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+	{0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+	{0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa},
+	{0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000},
+	{0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402},
+	{0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06},
+	{0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b},
+	{0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b},
+	{0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a},
+	{0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf},
+	{0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f},
+	{0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f},
+	{0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f},
+	{0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+};
+
+static const u32 ar5416Common_9160[][2] = {
+	/* Addr      allmodes  */
+	{0x0000000c, 0x00000000},
+	{0x00000030, 0x00020015},
+	{0x00000034, 0x00000005},
+	{0x00000040, 0x00000000},
+	{0x00000044, 0x00000008},
+	{0x00000048, 0x00000008},
+	{0x0000004c, 0x00000010},
+	{0x00000050, 0x00000000},
+	{0x00000054, 0x0000001f},
+	{0x00000800, 0x00000000},
+	{0x00000804, 0x00000000},
+	{0x00000808, 0x00000000},
+	{0x0000080c, 0x00000000},
+	{0x00000810, 0x00000000},
+	{0x00000814, 0x00000000},
+	{0x00000818, 0x00000000},
+	{0x0000081c, 0x00000000},
+	{0x00000820, 0x00000000},
+	{0x00000824, 0x00000000},
+	{0x00001040, 0x002ffc0f},
+	{0x00001044, 0x002ffc0f},
+	{0x00001048, 0x002ffc0f},
+	{0x0000104c, 0x002ffc0f},
+	{0x00001050, 0x002ffc0f},
+	{0x00001054, 0x002ffc0f},
+	{0x00001058, 0x002ffc0f},
+	{0x0000105c, 0x002ffc0f},
+	{0x00001060, 0x002ffc0f},
+	{0x00001064, 0x002ffc0f},
+	{0x00001230, 0x00000000},
+	{0x00001270, 0x00000000},
+	{0x00001038, 0x00000000},
+	{0x00001078, 0x00000000},
+	{0x000010b8, 0x00000000},
+	{0x000010f8, 0x00000000},
+	{0x00001138, 0x00000000},
+	{0x00001178, 0x00000000},
+	{0x000011b8, 0x00000000},
+	{0x000011f8, 0x00000000},
+	{0x00001238, 0x00000000},
+	{0x00001278, 0x00000000},
+	{0x000012b8, 0x00000000},
+	{0x000012f8, 0x00000000},
+	{0x00001338, 0x00000000},
+	{0x00001378, 0x00000000},
+	{0x000013b8, 0x00000000},
+	{0x000013f8, 0x00000000},
+	{0x00001438, 0x00000000},
+	{0x00001478, 0x00000000},
+	{0x000014b8, 0x00000000},
+	{0x000014f8, 0x00000000},
+	{0x00001538, 0x00000000},
+	{0x00001578, 0x00000000},
+	{0x000015b8, 0x00000000},
+	{0x000015f8, 0x00000000},
+	{0x00001638, 0x00000000},
+	{0x00001678, 0x00000000},
+	{0x000016b8, 0x00000000},
+	{0x000016f8, 0x00000000},
+	{0x00001738, 0x00000000},
+	{0x00001778, 0x00000000},
+	{0x000017b8, 0x00000000},
+	{0x000017f8, 0x00000000},
+	{0x0000103c, 0x00000000},
+	{0x0000107c, 0x00000000},
+	{0x000010bc, 0x00000000},
+	{0x000010fc, 0x00000000},
+	{0x0000113c, 0x00000000},
+	{0x0000117c, 0x00000000},
+	{0x000011bc, 0x00000000},
+	{0x000011fc, 0x00000000},
+	{0x0000123c, 0x00000000},
+	{0x0000127c, 0x00000000},
+	{0x000012bc, 0x00000000},
+	{0x000012fc, 0x00000000},
+	{0x0000133c, 0x00000000},
+	{0x0000137c, 0x00000000},
+	{0x000013bc, 0x00000000},
+	{0x000013fc, 0x00000000},
+	{0x0000143c, 0x00000000},
+	{0x0000147c, 0x00000000},
+	{0x00004030, 0x00000002},
+	{0x0000403c, 0x00000002},
+	{0x00007010, 0x00000020},
+	{0x00007038, 0x000004c2},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000700},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008048, 0x40000000},
+	{0x00008054, 0x00000000},
+	{0x00008058, 0x00000000},
+	{0x0000805c, 0x000fc78f},
+	{0x00008060, 0x0000000f},
+	{0x00008064, 0x00000000},
+	{0x000080c0, 0x2a82301a},
+	{0x000080c4, 0x05dc01e0},
+	{0x000080c8, 0x1f402710},
+	{0x000080cc, 0x01f40000},
+	{0x000080d0, 0x00001e00},
+	{0x000080d4, 0x00000000},
+	{0x000080d8, 0x00400000},
+	{0x000080e0, 0xffffffff},
+	{0x000080e4, 0x0000ffff},
+	{0x000080e8, 0x003f3f3f},
+	{0x000080ec, 0x00000000},
+	{0x000080f0, 0x00000000},
+	{0x000080f4, 0x00000000},
+	{0x000080f8, 0x00000000},
+	{0x000080fc, 0x00020000},
+	{0x00008100, 0x00020000},
+	{0x00008104, 0x00000001},
+	{0x00008108, 0x00000052},
+	{0x0000810c, 0x00000000},
+	{0x00008110, 0x00000168},
+	{0x00008118, 0x000100aa},
+	{0x0000811c, 0x00003210},
+	{0x00008124, 0x00000000},
+	{0x00008128, 0x00000000},
+	{0x0000812c, 0x00000000},
+	{0x00008130, 0x00000000},
+	{0x00008134, 0x00000000},
+	{0x00008138, 0x00000000},
+	{0x0000813c, 0x00000000},
+	{0x00008144, 0xffffffff},
+	{0x00008168, 0x00000000},
+	{0x0000816c, 0x00000000},
+	{0x00008170, 0x32143320},
+	{0x00008174, 0xfaa4fa50},
+	{0x00008178, 0x00000100},
+	{0x0000817c, 0x00000000},
+	{0x000081c4, 0x00000000},
+	{0x000081ec, 0x00000000},
+	{0x000081f0, 0x00000000},
+	{0x000081f4, 0x00000000},
+	{0x000081f8, 0x00000000},
+	{0x000081fc, 0x00000000},
+	{0x00008200, 0x00000000},
+	{0x00008204, 0x00000000},
+	{0x00008208, 0x00000000},
+	{0x0000820c, 0x00000000},
+	{0x00008210, 0x00000000},
+	{0x00008214, 0x00000000},
+	{0x00008218, 0x00000000},
+	{0x0000821c, 0x00000000},
+	{0x00008220, 0x00000000},
+	{0x00008224, 0x00000000},
+	{0x00008228, 0x00000000},
+	{0x0000822c, 0x00000000},
+	{0x00008230, 0x00000000},
+	{0x00008234, 0x00000000},
+	{0x00008238, 0x00000000},
+	{0x0000823c, 0x00000000},
+	{0x00008240, 0x00100000},
+	{0x00008244, 0x0010f400},
+	{0x00008248, 0x00000100},
+	{0x0000824c, 0x0001e800},
+	{0x00008250, 0x00000000},
+	{0x00008254, 0x00000000},
+	{0x00008258, 0x00000000},
+	{0x0000825c, 0x400000ff},
+	{0x00008260, 0x00080922},
+	{0x00008264, 0x88a00010},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000000},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x00000000},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x00008300, 0x00000000},
+	{0x00008304, 0x00000000},
+	{0x00008308, 0x00000000},
+	{0x0000830c, 0x00000000},
+	{0x00008310, 0x00000000},
+	{0x00008314, 0x00000000},
+	{0x00008318, 0x00000000},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000007},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000e00},
+	{0x00008338, 0x00ff0000},
+	{0x0000833c, 0x00000000},
+	{0x00008340, 0x000107ff},
+	{0x00009808, 0x00000000},
+	{0x0000980c, 0xad848e19},
+	{0x00009810, 0x7d14e000},
+	{0x00009814, 0x9c0a9f6b},
+	{0x0000981c, 0x00000000},
+	{0x0000982c, 0x0000a000},
+	{0x00009830, 0x00000000},
+	{0x0000983c, 0x00200400},
+	{0x00009840, 0x206a01ae},
+	{0x0000984c, 0x1284233c},
+	{0x00009854, 0x00000859},
+	{0x00009900, 0x00000000},
+	{0x00009904, 0x00000000},
+	{0x00009908, 0x00000000},
+	{0x0000990c, 0x00000000},
+	{0x0000991c, 0x10000fff},
+	{0x00009920, 0x05100000},
+	{0x0000a920, 0x05100000},
+	{0x0000b920, 0x05100000},
+	{0x00009928, 0x00000001},
+	{0x0000992c, 0x00000004},
+	{0x00009934, 0x1e1f2022},
+	{0x00009938, 0x0a0b0c0d},
+	{0x0000993c, 0x00000000},
+	{0x00009948, 0x9280b212},
+	{0x0000994c, 0x00020028},
+	{0x00009954, 0x5f3ca3de},
+	{0x00009958, 0x2108ecff},
+	{0x00009940, 0x00750604},
+	{0x0000c95c, 0x004b6a8e},
+	{0x00009970, 0x190fb515},
+	{0x00009974, 0x00000000},
+	{0x00009978, 0x00000001},
+	{0x0000997c, 0x00000000},
+	{0x00009980, 0x00000000},
+	{0x00009984, 0x00000000},
+	{0x00009988, 0x00000000},
+	{0x0000998c, 0x00000000},
+	{0x00009990, 0x00000000},
+	{0x00009994, 0x00000000},
+	{0x00009998, 0x00000000},
+	{0x0000999c, 0x00000000},
+	{0x000099a0, 0x00000000},
+	{0x000099a4, 0x00000001},
+	{0x000099a8, 0x201fff00},
+	{0x000099ac, 0x006f0000},
+	{0x000099b0, 0x03051000},
+	{0x000099dc, 0x00000000},
+	{0x000099e0, 0x00000200},
+	{0x000099e4, 0xaaaaaaaa},
+	{0x000099e8, 0x3c466478},
+	{0x000099ec, 0x0cc80caa},
+	{0x000099fc, 0x00001042},
+	{0x00009b00, 0x00000000},
+	{0x00009b04, 0x00000001},
+	{0x00009b08, 0x00000002},
+	{0x00009b0c, 0x00000003},
+	{0x00009b10, 0x00000004},
+	{0x00009b14, 0x00000005},
+	{0x00009b18, 0x00000008},
+	{0x00009b1c, 0x00000009},
+	{0x00009b20, 0x0000000a},
+	{0x00009b24, 0x0000000b},
+	{0x00009b28, 0x0000000c},
+	{0x00009b2c, 0x0000000d},
+	{0x00009b30, 0x00000010},
+	{0x00009b34, 0x00000011},
+	{0x00009b38, 0x00000012},
+	{0x00009b3c, 0x00000013},
+	{0x00009b40, 0x00000014},
+	{0x00009b44, 0x00000015},
+	{0x00009b48, 0x00000018},
+	{0x00009b4c, 0x00000019},
+	{0x00009b50, 0x0000001a},
+	{0x00009b54, 0x0000001b},
+	{0x00009b58, 0x0000001c},
+	{0x00009b5c, 0x0000001d},
+	{0x00009b60, 0x00000020},
+	{0x00009b64, 0x00000021},
+	{0x00009b68, 0x00000022},
+	{0x00009b6c, 0x00000023},
+	{0x00009b70, 0x00000024},
+	{0x00009b74, 0x00000025},
+	{0x00009b78, 0x00000028},
+	{0x00009b7c, 0x00000029},
+	{0x00009b80, 0x0000002a},
+	{0x00009b84, 0x0000002b},
+	{0x00009b88, 0x0000002c},
+	{0x00009b8c, 0x0000002d},
+	{0x00009b90, 0x00000030},
+	{0x00009b94, 0x00000031},
+	{0x00009b98, 0x00000032},
+	{0x00009b9c, 0x00000033},
+	{0x00009ba0, 0x00000034},
+	{0x00009ba4, 0x00000035},
+	{0x00009ba8, 0x00000035},
+	{0x00009bac, 0x00000035},
+	{0x00009bb0, 0x00000035},
+	{0x00009bb4, 0x00000035},
+	{0x00009bb8, 0x00000035},
+	{0x00009bbc, 0x00000035},
+	{0x00009bc0, 0x00000035},
+	{0x00009bc4, 0x00000035},
+	{0x00009bc8, 0x00000035},
+	{0x00009bcc, 0x00000035},
+	{0x00009bd0, 0x00000035},
+	{0x00009bd4, 0x00000035},
+	{0x00009bd8, 0x00000035},
+	{0x00009bdc, 0x00000035},
+	{0x00009be0, 0x00000035},
+	{0x00009be4, 0x00000035},
+	{0x00009be8, 0x00000035},
+	{0x00009bec, 0x00000035},
+	{0x00009bf0, 0x00000035},
+	{0x00009bf4, 0x00000035},
+	{0x00009bf8, 0x00000010},
+	{0x00009bfc, 0x0000001a},
+	{0x0000a210, 0x40806333},
+	{0x0000a214, 0x00106c10},
+	{0x0000a218, 0x009c4060},
+	{0x0000a220, 0x018830c6},
+	{0x0000a224, 0x00000400},
+	{0x0000a228, 0x001a0bb5},
+	{0x0000a22c, 0x00000000},
+	{0x0000a234, 0x20202020},
+	{0x0000a238, 0x20202020},
+	{0x0000a23c, 0x13c889af},
+	{0x0000a240, 0x38490a20},
+	{0x0000a244, 0x00007bb6},
+	{0x0000a248, 0x0fff3ffc},
+	{0x0000a24c, 0x00000001},
+	{0x0000a250, 0x0000e000},
+	{0x0000a254, 0x00000000},
+	{0x0000a258, 0x0cc75380},
+	{0x0000a25c, 0x0f0f0f01},
+	{0x0000a260, 0xdfa91f01},
+	{0x0000a268, 0x00000001},
+	{0x0000a26c, 0x0e79e5c6},
+	{0x0000b26c, 0x0e79e5c6},
+	{0x0000c26c, 0x0e79e5c6},
+	{0x0000d270, 0x00820820},
+	{0x0000a278, 0x1ce739ce},
+	{0x0000a27c, 0x050701ce},
+	{0x0000a338, 0x00000000},
+	{0x0000a33c, 0x00000000},
+	{0x0000a340, 0x00000000},
+	{0x0000a344, 0x00000000},
+	{0x0000a348, 0x3fffffff},
+	{0x0000a34c, 0x3fffffff},
+	{0x0000a350, 0x3fffffff},
+	{0x0000a354, 0x0003ffff},
+	{0x0000a358, 0x79bfaa03},
+	{0x0000d35c, 0x07ffffef},
+	{0x0000d360, 0x0fffffe7},
+	{0x0000d364, 0x17ffffe5},
+	{0x0000d368, 0x1fffffe4},
+	{0x0000d36c, 0x37ffffe3},
+	{0x0000d370, 0x3fffffe3},
+	{0x0000d374, 0x57ffffe3},
+	{0x0000d378, 0x5fffffe2},
+	{0x0000d37c, 0x7fffffe2},
+	{0x0000d380, 0x7f3c7bba},
+	{0x0000d384, 0xf3307ff0},
+	{0x0000a388, 0x0c000000},
+	{0x0000a38c, 0x20202020},
+	{0x0000a390, 0x20202020},
+	{0x0000a394, 0x1ce739ce},
+	{0x0000a398, 0x000001ce},
+	{0x0000a39c, 0x00000001},
+	{0x0000a3a0, 0x00000000},
+	{0x0000a3a4, 0x00000000},
+	{0x0000a3a8, 0x00000000},
+	{0x0000a3ac, 0x00000000},
+	{0x0000a3b0, 0x00000000},
+	{0x0000a3b4, 0x00000000},
+	{0x0000a3b8, 0x00000000},
+	{0x0000a3bc, 0x00000000},
+	{0x0000a3c0, 0x00000000},
+	{0x0000a3c4, 0x00000000},
+	{0x0000a3c8, 0x00000246},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3dc, 0x1ce739ce},
+	{0x0000a3e0, 0x000001ce},
+};
+
+static const u32 ar5416Bank0_9160[][2] = {
+	/* Addr      allmodes  */
+	{0x000098b0, 0x1e5795e5},
+	{0x000098e0, 0x02008020},
+};
+
+static const u32 ar5416BB_RfGain_9160[][3] = {
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x00009a00, 0x00000000, 0x00000000},
+	{0x00009a04, 0x00000040, 0x00000040},
+	{0x00009a08, 0x00000080, 0x00000080},
+	{0x00009a0c, 0x000001a1, 0x00000141},
+	{0x00009a10, 0x000001e1, 0x00000181},
+	{0x00009a14, 0x00000021, 0x000001c1},
+	{0x00009a18, 0x00000061, 0x00000001},
+	{0x00009a1c, 0x00000168, 0x00000041},
+	{0x00009a20, 0x000001a8, 0x000001a8},
+	{0x00009a24, 0x000001e8, 0x000001e8},
+	{0x00009a28, 0x00000028, 0x00000028},
+	{0x00009a2c, 0x00000068, 0x00000068},
+	{0x00009a30, 0x00000189, 0x000000a8},
+	{0x00009a34, 0x000001c9, 0x00000169},
+	{0x00009a38, 0x00000009, 0x000001a9},
+	{0x00009a3c, 0x00000049, 0x000001e9},
+	{0x00009a40, 0x00000089, 0x00000029},
+	{0x00009a44, 0x00000170, 0x00000069},
+	{0x00009a48, 0x000001b0, 0x00000190},
+	{0x00009a4c, 0x000001f0, 0x000001d0},
+	{0x00009a50, 0x00000030, 0x00000010},
+	{0x00009a54, 0x00000070, 0x00000050},
+	{0x00009a58, 0x00000191, 0x00000090},
+	{0x00009a5c, 0x000001d1, 0x00000151},
+	{0x00009a60, 0x00000011, 0x00000191},
+	{0x00009a64, 0x00000051, 0x000001d1},
+	{0x00009a68, 0x00000091, 0x00000011},
+	{0x00009a6c, 0x000001b8, 0x00000051},
+	{0x00009a70, 0x000001f8, 0x00000198},
+	{0x00009a74, 0x00000038, 0x000001d8},
+	{0x00009a78, 0x00000078, 0x00000018},
+	{0x00009a7c, 0x00000199, 0x00000058},
+	{0x00009a80, 0x000001d9, 0x00000098},
+	{0x00009a84, 0x00000019, 0x00000159},
+	{0x00009a88, 0x00000059, 0x00000199},
+	{0x00009a8c, 0x00000099, 0x000001d9},
+	{0x00009a90, 0x000000d9, 0x00000019},
+	{0x00009a94, 0x000000f9, 0x00000059},
+	{0x00009a98, 0x000000f9, 0x00000099},
+	{0x00009a9c, 0x000000f9, 0x000000d9},
+	{0x00009aa0, 0x000000f9, 0x000000f9},
+	{0x00009aa4, 0x000000f9, 0x000000f9},
+	{0x00009aa8, 0x000000f9, 0x000000f9},
+	{0x00009aac, 0x000000f9, 0x000000f9},
+	{0x00009ab0, 0x000000f9, 0x000000f9},
+	{0x00009ab4, 0x000000f9, 0x000000f9},
+	{0x00009ab8, 0x000000f9, 0x000000f9},
+	{0x00009abc, 0x000000f9, 0x000000f9},
+	{0x00009ac0, 0x000000f9, 0x000000f9},
+	{0x00009ac4, 0x000000f9, 0x000000f9},
+	{0x00009ac8, 0x000000f9, 0x000000f9},
+	{0x00009acc, 0x000000f9, 0x000000f9},
+	{0x00009ad0, 0x000000f9, 0x000000f9},
+	{0x00009ad4, 0x000000f9, 0x000000f9},
+	{0x00009ad8, 0x000000f9, 0x000000f9},
+	{0x00009adc, 0x000000f9, 0x000000f9},
+	{0x00009ae0, 0x000000f9, 0x000000f9},
+	{0x00009ae4, 0x000000f9, 0x000000f9},
+	{0x00009ae8, 0x000000f9, 0x000000f9},
+	{0x00009aec, 0x000000f9, 0x000000f9},
+	{0x00009af0, 0x000000f9, 0x000000f9},
+	{0x00009af4, 0x000000f9, 0x000000f9},
+	{0x00009af8, 0x000000f9, 0x000000f9},
+	{0x00009afc, 0x000000f9, 0x000000f9},
+};
+
+static const u32 ar5416Bank1_9160[][2] = {
+	/* Addr      allmodes  */
+	{0x000098b0, 0x02108421},
+	{0x000098ec, 0x00000008},
+};
+
+static const u32 ar5416Bank2_9160[][2] = {
+	/* Addr      allmodes  */
+	{0x000098b0, 0x0e73ff17},
+	{0x000098e0, 0x00000420},
+};
+
+static const u32 ar5416Bank3_9160[][3] = {
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x000098f0, 0x01400018, 0x01c00018},
+};
+
+static const u32 ar5416Bank6_9160[][3] = {
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00e00000, 0x00e00000},
+	{0x0000989c, 0x005e0000, 0x005e0000},
+	{0x0000989c, 0x00120000, 0x00120000},
+	{0x0000989c, 0x00620000, 0x00620000},
+	{0x0000989c, 0x00020000, 0x00020000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x40ff0000, 0x40ff0000},
+	{0x0000989c, 0x005f0000, 0x005f0000},
+	{0x0000989c, 0x00870000, 0x00870000},
+	{0x0000989c, 0x00f90000, 0x00f90000},
+	{0x0000989c, 0x007b0000, 0x007b0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00f50000, 0x00f50000},
+	{0x0000989c, 0x00dc0000, 0x00dc0000},
+	{0x0000989c, 0x00110000, 0x00110000},
+	{0x0000989c, 0x006100a8, 0x006100a8},
+	{0x0000989c, 0x004210a2, 0x004210a2},
+	{0x0000989c, 0x0014008f, 0x0014008f},
+	{0x0000989c, 0x00c40003, 0x00c40003},
+	{0x0000989c, 0x003000f2, 0x003000f2},
+	{0x0000989c, 0x00440016, 0x00440016},
+	{0x0000989c, 0x00410040, 0x00410040},
+	{0x0000989c, 0x0001805e, 0x0001805e},
+	{0x0000989c, 0x0000c0ab, 0x0000c0ab},
+	{0x0000989c, 0x000000f1, 0x000000f1},
+	{0x0000989c, 0x00002081, 0x00002081},
+	{0x0000989c, 0x000000d4, 0x000000d4},
+	{0x000098d0, 0x0000000f, 0x0010000f},
+};
+
+static const u32 ar5416Bank6TPC_9160[][3] = {
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00000000, 0x00000000},
+	{0x0000989c, 0x00e00000, 0x00e00000},
+	{0x0000989c, 0x005e0000, 0x005e0000},
+	{0x0000989c, 0x00120000, 0x00120000},
+	{0x0000989c, 0x00620000, 0x00620000},
+	{0x0000989c, 0x00020000, 0x00020000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x40ff0000, 0x40ff0000},
+	{0x0000989c, 0x005f0000, 0x005f0000},
+	{0x0000989c, 0x00870000, 0x00870000},
+	{0x0000989c, 0x00f90000, 0x00f90000},
+	{0x0000989c, 0x007b0000, 0x007b0000},
+	{0x0000989c, 0x00ff0000, 0x00ff0000},
+	{0x0000989c, 0x00f50000, 0x00f50000},
+	{0x0000989c, 0x00dc0000, 0x00dc0000},
+	{0x0000989c, 0x00110000, 0x00110000},
+	{0x0000989c, 0x006100a8, 0x006100a8},
+	{0x0000989c, 0x00423022, 0x00423022},
+	{0x0000989c, 0x2014008f, 0x2014008f},
+	{0x0000989c, 0x00c40002, 0x00c40002},
+	{0x0000989c, 0x003000f2, 0x003000f2},
+	{0x0000989c, 0x00440016, 0x00440016},
+	{0x0000989c, 0x00410040, 0x00410040},
+	{0x0000989c, 0x0001805e, 0x0001805e},
+	{0x0000989c, 0x0000c0ab, 0x0000c0ab},
+	{0x0000989c, 0x000000e1, 0x000000e1},
+	{0x0000989c, 0x00007080, 0x00007080},
+	{0x0000989c, 0x000000d4, 0x000000d4},
+	{0x000098d0, 0x0000000f, 0x0010000f},
+};
+
+static const u32 ar5416Bank7_9160[][2] = {
+	/* Addr      allmodes  */
+	{0x0000989c, 0x00000500},
+	{0x0000989c, 0x00000800},
+	{0x000098cc, 0x0000000e},
+};
+
+static const u32 ar5416Addac_9160[][2] = {
+	/* Addr      allmodes  */
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x000000c0},
+	{0x0000989c, 0x00000018},
+	{0x0000989c, 0x00000004},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x000000c0},
+	{0x0000989c, 0x00000019},
+	{0x0000989c, 0x00000004},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000004},
+	{0x0000989c, 0x00000003},
+	{0x0000989c, 0x00000008},
+	{0x0000989c, 0x00000000},
+	{0x000098cc, 0x00000000},
+};
+
+static const u32 ar5416Addac_9160_1_1[][2] = {
+	/* Addr      allmodes  */
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x000000c0},
+	{0x0000989c, 0x00000018},
+	{0x0000989c, 0x00000004},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x000000c0},
+	{0x0000989c, 0x00000019},
+	{0x0000989c, 0x00000004},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x0000989c, 0x00000000},
+	{0x000098cc, 0x00000000},
+};
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ar9002_initvals.h b/roms/ipxe/src/drivers/net/ath/ath9k/ar9002_initvals.h
new file mode 100644
index 0000000000000000000000000000000000000000..dd121513b21298cc268fdeced4c8f2e07effc8a7
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ar9002_initvals.h
@@ -0,0 +1,3264 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+static const u32 ar9280Modes_9280_2[][6] = {
+	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
+	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
+	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
+	{0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008},
+	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
+	{0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f},
+	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
+	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a},
+	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880},
+	{0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
+	{0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+	{0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+	{0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+	{0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+	{0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e},
+	{0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0},
+	{0x00009850, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2},
+	{0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+	{0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e},
+	{0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18},
+	{0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+	{0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+	{0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881},
+	{0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+	{0x00009918, 0x0000000a, 0x00000014, 0x00000268, 0x0000000b, 0x00000016},
+	{0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d},
+	{0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010},
+	{0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010},
+	{0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010},
+	{0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210},
+	{0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce},
+	{0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c},
+	{0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00},
+	{0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+	{0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444},
+	{0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019},
+	{0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019},
+	{0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+	{0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+	{0x0000a23c, 0x13c88000, 0x13c88000, 0x13c88001, 0x13c88000, 0x13c88000},
+	{0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000},
+	{0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
+	{0x0000a388, 0x0c000000, 0x0c000000, 0x08000000, 0x0c000000, 0x0c000000},
+	{0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000},
+};
+
+static const u32 ar9280Common_9280_2[][2] = {
+	/* Addr      allmodes  */
+	{0x0000000c, 0x00000000},
+	{0x00000030, 0x00020015},
+	{0x00000034, 0x00000005},
+	{0x00000040, 0x00000000},
+	{0x00000044, 0x00000008},
+	{0x00000048, 0x00000008},
+	{0x0000004c, 0x00000010},
+	{0x00000050, 0x00000000},
+	{0x00000054, 0x0000001f},
+	{0x00000800, 0x00000000},
+	{0x00000804, 0x00000000},
+	{0x00000808, 0x00000000},
+	{0x0000080c, 0x00000000},
+	{0x00000810, 0x00000000},
+	{0x00000814, 0x00000000},
+	{0x00000818, 0x00000000},
+	{0x0000081c, 0x00000000},
+	{0x00000820, 0x00000000},
+	{0x00000824, 0x00000000},
+	{0x00001040, 0x002ffc0f},
+	{0x00001044, 0x002ffc0f},
+	{0x00001048, 0x002ffc0f},
+	{0x0000104c, 0x002ffc0f},
+	{0x00001050, 0x002ffc0f},
+	{0x00001054, 0x002ffc0f},
+	{0x00001058, 0x002ffc0f},
+	{0x0000105c, 0x002ffc0f},
+	{0x00001060, 0x002ffc0f},
+	{0x00001064, 0x002ffc0f},
+	{0x00001230, 0x00000000},
+	{0x00001270, 0x00000000},
+	{0x00001038, 0x00000000},
+	{0x00001078, 0x00000000},
+	{0x000010b8, 0x00000000},
+	{0x000010f8, 0x00000000},
+	{0x00001138, 0x00000000},
+	{0x00001178, 0x00000000},
+	{0x000011b8, 0x00000000},
+	{0x000011f8, 0x00000000},
+	{0x00001238, 0x00000000},
+	{0x00001278, 0x00000000},
+	{0x000012b8, 0x00000000},
+	{0x000012f8, 0x00000000},
+	{0x00001338, 0x00000000},
+	{0x00001378, 0x00000000},
+	{0x000013b8, 0x00000000},
+	{0x000013f8, 0x00000000},
+	{0x00001438, 0x00000000},
+	{0x00001478, 0x00000000},
+	{0x000014b8, 0x00000000},
+	{0x000014f8, 0x00000000},
+	{0x00001538, 0x00000000},
+	{0x00001578, 0x00000000},
+	{0x000015b8, 0x00000000},
+	{0x000015f8, 0x00000000},
+	{0x00001638, 0x00000000},
+	{0x00001678, 0x00000000},
+	{0x000016b8, 0x00000000},
+	{0x000016f8, 0x00000000},
+	{0x00001738, 0x00000000},
+	{0x00001778, 0x00000000},
+	{0x000017b8, 0x00000000},
+	{0x000017f8, 0x00000000},
+	{0x0000103c, 0x00000000},
+	{0x0000107c, 0x00000000},
+	{0x000010bc, 0x00000000},
+	{0x000010fc, 0x00000000},
+	{0x0000113c, 0x00000000},
+	{0x0000117c, 0x00000000},
+	{0x000011bc, 0x00000000},
+	{0x000011fc, 0x00000000},
+	{0x0000123c, 0x00000000},
+	{0x0000127c, 0x00000000},
+	{0x000012bc, 0x00000000},
+	{0x000012fc, 0x00000000},
+	{0x0000133c, 0x00000000},
+	{0x0000137c, 0x00000000},
+	{0x000013bc, 0x00000000},
+	{0x000013fc, 0x00000000},
+	{0x0000143c, 0x00000000},
+	{0x0000147c, 0x00000000},
+	{0x00004030, 0x00000002},
+	{0x0000403c, 0x00000002},
+	{0x00004024, 0x0000001f},
+	{0x00004060, 0x00000000},
+	{0x00004064, 0x00000000},
+	{0x00007010, 0x00000033},
+	{0x00007034, 0x00000002},
+	{0x00007038, 0x000004c2},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000700},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008048, 0x40000000},
+	{0x00008054, 0x00000000},
+	{0x00008058, 0x00000000},
+	{0x0000805c, 0x000fc78f},
+	{0x00008060, 0x0000000f},
+	{0x00008064, 0x00000000},
+	{0x00008070, 0x00000000},
+	{0x000080c0, 0x2a80001a},
+	{0x000080c4, 0x05dc01e0},
+	{0x000080c8, 0x1f402710},
+	{0x000080cc, 0x01f40000},
+	{0x000080d0, 0x00001e00},
+	{0x000080d4, 0x00000000},
+	{0x000080d8, 0x00400000},
+	{0x000080e0, 0xffffffff},
+	{0x000080e4, 0x0000ffff},
+	{0x000080e8, 0x003f3f3f},
+	{0x000080ec, 0x00000000},
+	{0x000080f0, 0x00000000},
+	{0x000080f4, 0x00000000},
+	{0x000080f8, 0x00000000},
+	{0x000080fc, 0x00020000},
+	{0x00008100, 0x00020000},
+	{0x00008104, 0x00000001},
+	{0x00008108, 0x00000052},
+	{0x0000810c, 0x00000000},
+	{0x00008110, 0x00000168},
+	{0x00008118, 0x000100aa},
+	{0x0000811c, 0x00003210},
+	{0x00008124, 0x00000000},
+	{0x00008128, 0x00000000},
+	{0x0000812c, 0x00000000},
+	{0x00008130, 0x00000000},
+	{0x00008134, 0x00000000},
+	{0x00008138, 0x00000000},
+	{0x0000813c, 0x00000000},
+	{0x00008144, 0xffffffff},
+	{0x00008168, 0x00000000},
+	{0x0000816c, 0x00000000},
+	{0x00008170, 0x32143320},
+	{0x00008174, 0xfaa4fa50},
+	{0x00008178, 0x00000100},
+	{0x0000817c, 0x00000000},
+	{0x000081c0, 0x00000000},
+	{0x000081ec, 0x00000000},
+	{0x000081f0, 0x00000000},
+	{0x000081f4, 0x00000000},
+	{0x000081f8, 0x00000000},
+	{0x000081fc, 0x00000000},
+	{0x00008200, 0x00000000},
+	{0x00008204, 0x00000000},
+	{0x00008208, 0x00000000},
+	{0x0000820c, 0x00000000},
+	{0x00008210, 0x00000000},
+	{0x00008214, 0x00000000},
+	{0x00008218, 0x00000000},
+	{0x0000821c, 0x00000000},
+	{0x00008220, 0x00000000},
+	{0x00008224, 0x00000000},
+	{0x00008228, 0x00000000},
+	{0x0000822c, 0x00000000},
+	{0x00008230, 0x00000000},
+	{0x00008234, 0x00000000},
+	{0x00008238, 0x00000000},
+	{0x0000823c, 0x00000000},
+	{0x00008240, 0x00100000},
+	{0x00008244, 0x0010f400},
+	{0x00008248, 0x00000100},
+	{0x0000824c, 0x0001e800},
+	{0x00008250, 0x00000000},
+	{0x00008254, 0x00000000},
+	{0x00008258, 0x00000000},
+	{0x0000825c, 0x400000ff},
+	{0x00008260, 0x00080922},
+	{0x00008264, 0x88a00010},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000000},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x00000000},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x0000829c, 0x00000000},
+	{0x00008300, 0x00000040},
+	{0x00008314, 0x00000000},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000007},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000e00},
+	{0x00008338, 0x00ff0000},
+	{0x0000833c, 0x00000000},
+	{0x00008340, 0x000107ff},
+	{0x00008344, 0x00481043},
+	{0x00009808, 0x00000000},
+	{0x0000980c, 0xafa68e30},
+	{0x00009810, 0xfd14e000},
+	{0x00009814, 0x9c0a9f6b},
+	{0x0000981c, 0x00000000},
+	{0x0000982c, 0x0000a000},
+	{0x00009830, 0x00000000},
+	{0x0000983c, 0x00200400},
+	{0x0000984c, 0x0040233c},
+	{0x0000a84c, 0x0040233c},
+	{0x00009854, 0x00000044},
+	{0x00009900, 0x00000000},
+	{0x00009904, 0x00000000},
+	{0x00009908, 0x00000000},
+	{0x0000990c, 0x00000000},
+	{0x00009910, 0x01002310},
+	{0x0000991c, 0x10000fff},
+	{0x00009920, 0x04900000},
+	{0x0000a920, 0x04900000},
+	{0x00009928, 0x00000001},
+	{0x0000992c, 0x00000004},
+	{0x00009934, 0x1e1f2022},
+	{0x00009938, 0x0a0b0c0d},
+	{0x0000993c, 0x00000000},
+	{0x00009948, 0x9280c00a},
+	{0x0000994c, 0x00020028},
+	{0x00009954, 0x5f3ca3de},
+	{0x00009958, 0x2108ecff},
+	{0x00009940, 0x14750604},
+	{0x0000c95c, 0x004b6a8e},
+	{0x00009970, 0x190fb514},
+	{0x00009974, 0x00000000},
+	{0x00009978, 0x00000001},
+	{0x0000997c, 0x00000000},
+	{0x00009980, 0x00000000},
+	{0x00009984, 0x00000000},
+	{0x00009988, 0x00000000},
+	{0x0000998c, 0x00000000},
+	{0x00009990, 0x00000000},
+	{0x00009994, 0x00000000},
+	{0x00009998, 0x00000000},
+	{0x0000999c, 0x00000000},
+	{0x000099a0, 0x00000000},
+	{0x000099a4, 0x00000001},
+	{0x000099a8, 0x201fff00},
+	{0x000099ac, 0x006f0000},
+	{0x000099b0, 0x03051000},
+	{0x000099b4, 0x00000820},
+	{0x000099c4, 0x06336f77},
+	{0x000099c8, 0x6af6532f},
+	{0x000099cc, 0x08f186c8},
+	{0x000099d0, 0x00046384},
+	{0x000099d4, 0x00000000},
+	{0x000099d8, 0x00000000},
+	{0x000099dc, 0x00000000},
+	{0x000099e0, 0x00000000},
+	{0x000099e4, 0xaaaaaaaa},
+	{0x000099e8, 0x3c466478},
+	{0x000099ec, 0x0cc80caa},
+	{0x000099f0, 0x00000000},
+	{0x000099fc, 0x00001042},
+	{0x0000a208, 0x803e4788},
+	{0x0000a210, 0x4080a333},
+	{0x0000a214, 0x40206c10},
+	{0x0000a218, 0x009c4060},
+	{0x0000a220, 0x01834061},
+	{0x0000a224, 0x00000400},
+	{0x0000a228, 0x000003b5},
+	{0x0000a22c, 0x233f7180},
+	{0x0000a234, 0x20202020},
+	{0x0000a238, 0x20202020},
+	{0x0000a240, 0x38490a20},
+	{0x0000a244, 0x00007bb6},
+	{0x0000a248, 0x0fff3ffc},
+	{0x0000a24c, 0x00000000},
+	{0x0000a254, 0x00000000},
+	{0x0000a258, 0x0cdbd380},
+	{0x0000a25c, 0x0f0f0f01},
+	{0x0000a260, 0xdfa91f01},
+	{0x0000a268, 0x00000000},
+	{0x0000a26c, 0x0e79e5c6},
+	{0x0000b26c, 0x0e79e5c6},
+	{0x0000d270, 0x00820820},
+	{0x0000a278, 0x1ce739ce},
+	{0x0000d35c, 0x07ffffef},
+	{0x0000d360, 0x0fffffe7},
+	{0x0000d364, 0x17ffffe5},
+	{0x0000d368, 0x1fffffe4},
+	{0x0000d36c, 0x37ffffe3},
+	{0x0000d370, 0x3fffffe3},
+	{0x0000d374, 0x57ffffe3},
+	{0x0000d378, 0x5fffffe2},
+	{0x0000d37c, 0x7fffffe2},
+	{0x0000d380, 0x7f3c7bba},
+	{0x0000d384, 0xf3307ff0},
+	{0x0000a38c, 0x20202020},
+	{0x0000a390, 0x20202020},
+	{0x0000a394, 0x1ce739ce},
+	{0x0000a398, 0x000001ce},
+	{0x0000a39c, 0x00000001},
+	{0x0000a3a0, 0x00000000},
+	{0x0000a3a4, 0x00000000},
+	{0x0000a3a8, 0x00000000},
+	{0x0000a3ac, 0x00000000},
+	{0x0000a3b0, 0x00000000},
+	{0x0000a3b4, 0x00000000},
+	{0x0000a3b8, 0x00000000},
+	{0x0000a3bc, 0x00000000},
+	{0x0000a3c0, 0x00000000},
+	{0x0000a3c4, 0x00000000},
+	{0x0000a3c8, 0x00000246},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3dc, 0x1ce739ce},
+	{0x0000a3e0, 0x000001ce},
+	{0x0000a3e4, 0x00000000},
+	{0x0000a3e8, 0x18c43433},
+	{0x00007800, 0x00040000},
+	{0x00007804, 0xdb005012},
+	{0x00007808, 0x04924914},
+	{0x0000780c, 0x21084210},
+	{0x00007810, 0x6d801300},
+	{0x00007818, 0x07e41000},
+	{0x00007824, 0x00040000},
+	{0x00007828, 0xdb005012},
+	{0x0000782c, 0x04924914},
+	{0x00007830, 0x21084210},
+	{0x00007834, 0x6d801300},
+	{0x0000783c, 0x07e40000},
+	{0x00007848, 0x00100000},
+	{0x0000784c, 0x773f0567},
+	{0x00007850, 0x54214514},
+	{0x00007854, 0x12035828},
+	{0x00007858, 0x9259269a},
+	{0x00007860, 0x52802000},
+	{0x00007864, 0x0a8e370e},
+	{0x00007868, 0xc0102850},
+	{0x0000786c, 0x812d4000},
+	{0x00007870, 0x807ec400},
+	{0x00007874, 0x001b6db0},
+	{0x00007878, 0x00376b63},
+	{0x0000787c, 0x06db6db6},
+	{0x00007880, 0x006d8000},
+	{0x00007884, 0xffeffffe},
+	{0x00007888, 0xffeffffe},
+	{0x0000788c, 0x00010000},
+	{0x00007890, 0x02060aeb},
+	{0x00007898, 0x2a850160},
+};
+
+static const u32 ar9280Modes_fast_clock_9280_2[][3] = {
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x00001030, 0x00000268, 0x000004d0},
+	{0x00001070, 0x0000018c, 0x00000318},
+	{0x000010b0, 0x00000fd0, 0x00001fa0},
+	{0x00008014, 0x044c044c, 0x08980898},
+	{0x0000801c, 0x148ec02b, 0x148ec057},
+	{0x00008318, 0x000044c0, 0x00008980},
+	{0x00009820, 0x02020200, 0x02020200},
+	{0x00009824, 0x01000f0f, 0x01000f0f},
+	{0x00009828, 0x0b020001, 0x0b020001},
+	{0x00009834, 0x00000f0f, 0x00000f0f},
+	{0x00009844, 0x03721821, 0x03721821},
+	{0x00009914, 0x00000898, 0x00001130},
+	{0x00009918, 0x0000000b, 0x00000016},
+};
+
+static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][6] = {
+	{0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290},
+	{0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300},
+	{0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304},
+	{0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308},
+	{0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c},
+	{0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000},
+	{0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004},
+	{0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008},
+	{0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c},
+	{0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080},
+	{0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084},
+	{0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088},
+	{0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c},
+	{0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100},
+	{0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104},
+	{0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108},
+	{0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c},
+	{0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110},
+	{0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114},
+	{0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180},
+	{0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184},
+	{0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188},
+	{0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c},
+	{0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190},
+	{0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194},
+	{0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0},
+	{0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c},
+	{0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8},
+	{0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284},
+	{0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288},
+	{0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224},
+	{0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290},
+	{0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300},
+	{0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304},
+	{0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308},
+	{0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c},
+	{0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380},
+	{0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384},
+	{0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700},
+	{0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704},
+	{0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708},
+	{0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c},
+	{0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780},
+	{0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784},
+	{0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00},
+	{0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04},
+	{0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08},
+	{0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c},
+	{0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10, 0x00008b10},
+	{0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b80, 0x00008b80, 0x00008b80},
+	{0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b84, 0x00008b84, 0x00008b84},
+	{0x00009acc, 0x0000b380, 0x0000b380, 0x00008b88, 0x00008b88, 0x00008b88},
+	{0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b8c, 0x00008b8c, 0x00008b8c},
+	{0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b90, 0x00008b90, 0x00008b90},
+	{0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b94, 0x00008b94, 0x00008b94},
+	{0x00009adc, 0x0000b390, 0x0000b390, 0x00008b98, 0x00008b98, 0x00008b98},
+	{0x00009ae0, 0x0000b394, 0x0000b394, 0x00008ba4, 0x00008ba4, 0x00008ba4},
+	{0x00009ae4, 0x0000b398, 0x0000b398, 0x00008ba8, 0x00008ba8, 0x00008ba8},
+	{0x00009ae8, 0x0000b780, 0x0000b780, 0x00008bac, 0x00008bac, 0x00008bac},
+	{0x00009aec, 0x0000b784, 0x0000b784, 0x00008bb0, 0x00008bb0, 0x00008bb0},
+	{0x00009af0, 0x0000b788, 0x0000b788, 0x00008bb4, 0x00008bb4, 0x00008bb4},
+	{0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008ba1, 0x00008ba1, 0x00008ba1},
+	{0x00009af8, 0x0000b790, 0x0000b790, 0x00008ba5, 0x00008ba5, 0x00008ba5},
+	{0x00009afc, 0x0000b794, 0x0000b794, 0x00008ba9, 0x00008ba9, 0x00008ba9},
+	{0x00009b00, 0x0000b798, 0x0000b798, 0x00008bad, 0x00008bad, 0x00008bad},
+	{0x00009b04, 0x0000d784, 0x0000d784, 0x00008bb1, 0x00008bb1, 0x00008bb1},
+	{0x00009b08, 0x0000d788, 0x0000d788, 0x00008bb5, 0x00008bb5, 0x00008bb5},
+	{0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008ba2, 0x00008ba2, 0x00008ba2},
+	{0x00009b10, 0x0000d790, 0x0000d790, 0x00008ba6, 0x00008ba6, 0x00008ba6},
+	{0x00009b14, 0x0000f780, 0x0000f780, 0x00008baa, 0x00008baa, 0x00008baa},
+	{0x00009b18, 0x0000f784, 0x0000f784, 0x00008bae, 0x00008bae, 0x00008bae},
+	{0x00009b1c, 0x0000f788, 0x0000f788, 0x00008bb2, 0x00008bb2, 0x00008bb2},
+	{0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008bb6, 0x00008bb6, 0x00008bb6},
+	{0x00009b24, 0x0000f790, 0x0000f790, 0x00008ba3, 0x00008ba3, 0x00008ba3},
+	{0x00009b28, 0x0000f794, 0x0000f794, 0x00008ba7, 0x00008ba7, 0x00008ba7},
+	{0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008bab, 0x00008bab, 0x00008bab},
+	{0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008baf, 0x00008baf, 0x00008baf},
+	{0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008bb3, 0x00008bb3, 0x00008bb3},
+	{0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008bb7, 0x00008bb7, 0x00008bb7},
+	{0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008bc3, 0x00008bc3, 0x00008bc3},
+	{0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008bc7, 0x00008bc7, 0x00008bc7},
+	{0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008bcb, 0x00008bcb, 0x00008bcb},
+	{0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008bcf, 0x00008bcf, 0x00008bcf},
+	{0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008bd3, 0x00008bd3, 0x00008bd3},
+	{0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008bd7, 0x00008bd7, 0x00008bd7},
+	{0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb},
+	{0x00009848, 0x00001066, 0x00001066, 0x00001055, 0x00001055, 0x00001055},
+	{0x0000a848, 0x00001066, 0x00001066, 0x00001055, 0x00001055, 0x00001055},
+};
+
+static const u32 ar9280Modes_original_rxgain_9280_2[][6] = {
+	{0x00009a00, 0x00008184, 0x00008184, 0x00008000, 0x00008000, 0x00008000},
+	{0x00009a04, 0x00008188, 0x00008188, 0x00008000, 0x00008000, 0x00008000},
+	{0x00009a08, 0x0000818c, 0x0000818c, 0x00008000, 0x00008000, 0x00008000},
+	{0x00009a0c, 0x00008190, 0x00008190, 0x00008000, 0x00008000, 0x00008000},
+	{0x00009a10, 0x00008194, 0x00008194, 0x00008000, 0x00008000, 0x00008000},
+	{0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000},
+	{0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004},
+	{0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008},
+	{0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c},
+	{0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080},
+	{0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084},
+	{0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088},
+	{0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c},
+	{0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100},
+	{0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104},
+	{0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108},
+	{0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c},
+	{0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110},
+	{0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114},
+	{0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180},
+	{0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184},
+	{0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188},
+	{0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c},
+	{0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190},
+	{0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194},
+	{0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0},
+	{0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c},
+	{0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8},
+	{0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284},
+	{0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288},
+	{0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224},
+	{0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290},
+	{0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300},
+	{0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304},
+	{0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308},
+	{0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c},
+	{0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380},
+	{0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384},
+	{0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700},
+	{0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704},
+	{0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708},
+	{0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c},
+	{0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780},
+	{0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784},
+	{0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00},
+	{0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04},
+	{0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08},
+	{0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c},
+	{0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80},
+	{0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84},
+	{0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88},
+	{0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c},
+	{0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90},
+	{0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80},
+	{0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84},
+	{0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88},
+	{0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c},
+	{0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90},
+	{0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c},
+	{0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310},
+	{0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384},
+	{0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388},
+	{0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324},
+	{0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704},
+	{0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4},
+	{0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8},
+	{0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710},
+	{0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714},
+	{0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720},
+	{0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724},
+	{0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728},
+	{0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c},
+	{0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0},
+	{0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4},
+	{0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8},
+	{0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0},
+	{0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4},
+	{0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8},
+	{0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5},
+	{0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9},
+	{0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad},
+	{0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1},
+	{0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5},
+	{0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9},
+	{0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5},
+	{0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9},
+	{0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1},
+	{0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5},
+	{0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9},
+	{0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6},
+	{0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca},
+	{0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce},
+	{0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2},
+	{0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6},
+	{0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3},
+	{0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7},
+	{0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb},
+	{0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf},
+	{0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7},
+	{0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db},
+	{0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063},
+	{0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063},
+};
+
+static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = {
+	{0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290},
+	{0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300},
+	{0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304},
+	{0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308},
+	{0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c},
+	{0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000},
+	{0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004},
+	{0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008},
+	{0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c},
+	{0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080},
+	{0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084},
+	{0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088},
+	{0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c},
+	{0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100},
+	{0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104},
+	{0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108},
+	{0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c},
+	{0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110},
+	{0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114},
+	{0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180},
+	{0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184},
+	{0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188},
+	{0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c},
+	{0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190},
+	{0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194},
+	{0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0},
+	{0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c},
+	{0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8},
+	{0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284},
+	{0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288},
+	{0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224},
+	{0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290},
+	{0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300},
+	{0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304},
+	{0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308},
+	{0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c},
+	{0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380},
+	{0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384},
+	{0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700},
+	{0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704},
+	{0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708},
+	{0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c},
+	{0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780},
+	{0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784},
+	{0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00},
+	{0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04},
+	{0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08},
+	{0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c},
+	{0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80},
+	{0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84},
+	{0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88},
+	{0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c},
+	{0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90},
+	{0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80},
+	{0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84},
+	{0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88},
+	{0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c},
+	{0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90},
+	{0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310, 0x00009310},
+	{0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314, 0x00009314},
+	{0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320, 0x00009320},
+	{0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324, 0x00009324},
+	{0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328, 0x00009328},
+	{0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c, 0x0000932c},
+	{0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330, 0x00009330},
+	{0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334, 0x00009334},
+	{0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321, 0x00009321},
+	{0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325, 0x00009325},
+	{0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329, 0x00009329},
+	{0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d, 0x0000932d},
+	{0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331, 0x00009331},
+	{0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335, 0x00009335},
+	{0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322, 0x00009322},
+	{0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326, 0x00009326},
+	{0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a, 0x0000932a},
+	{0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e, 0x0000932e},
+	{0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332, 0x00009332},
+	{0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336, 0x00009336},
+	{0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323, 0x00009323},
+	{0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327, 0x00009327},
+	{0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b, 0x0000932b},
+	{0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f, 0x0000932f},
+	{0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333, 0x00009333},
+	{0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337, 0x00009337},
+	{0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343, 0x00009343},
+	{0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347, 0x00009347},
+	{0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b, 0x0000934b},
+	{0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f, 0x0000934f},
+	{0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353, 0x00009353},
+	{0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357, 0x00009357},
+	{0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b},
+	{0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a},
+	{0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a},
+};
+
+static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = {
+	{0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652},
+	{0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce},
+	{0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002},
+	{0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008},
+	{0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010, 0x0000c010},
+	{0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012, 0x00010012},
+	{0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014, 0x00013014},
+	{0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a, 0x0001820a},
+	{0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211, 0x0001b211},
+	{0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213},
+	{0x0000a324, 0x00021092, 0x00021092, 0x00022411, 0x00022411, 0x00022411},
+	{0x0000a328, 0x0002510a, 0x0002510a, 0x00025413, 0x00025413, 0x00025413},
+	{0x0000a32c, 0x0002910c, 0x0002910c, 0x00029811, 0x00029811, 0x00029811},
+	{0x0000a330, 0x0002c18b, 0x0002c18b, 0x0002c813, 0x0002c813, 0x0002c813},
+	{0x0000a334, 0x0002f1cc, 0x0002f1cc, 0x00030a14, 0x00030a14, 0x00030a14},
+	{0x0000a338, 0x000321eb, 0x000321eb, 0x00035a50, 0x00035a50, 0x00035a50},
+	{0x0000a33c, 0x000341ec, 0x000341ec, 0x00039c4c, 0x00039c4c, 0x00039c4c},
+	{0x0000a340, 0x000341ec, 0x000341ec, 0x0003de8a, 0x0003de8a, 0x0003de8a},
+	{0x0000a344, 0x000341ec, 0x000341ec, 0x00042e92, 0x00042e92, 0x00042e92},
+	{0x0000a348, 0x000341ec, 0x000341ec, 0x00046ed2, 0x00046ed2, 0x00046ed2},
+	{0x0000a34c, 0x000341ec, 0x000341ec, 0x0004bed5, 0x0004bed5, 0x0004bed5},
+	{0x0000a350, 0x000341ec, 0x000341ec, 0x0004ff54, 0x0004ff54, 0x0004ff54},
+	{0x0000a354, 0x000341ec, 0x000341ec, 0x00055fd5, 0x00055fd5, 0x00055fd5},
+	{0x0000a3ec, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081},
+	{0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff},
+	{0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff},
+	{0x0000781c, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000},
+	{0x00007840, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000},
+	{0x00007820, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480},
+	{0x00007844, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480},
+};
+
+static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = {
+	{0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652},
+	{0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce},
+	{0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002},
+	{0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009},
+	{0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b},
+	{0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012},
+	{0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048},
+	{0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a},
+	{0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211},
+	{0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213},
+	{0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b},
+	{0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412},
+	{0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414},
+	{0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a},
+	{0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649},
+	{0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b},
+	{0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49},
+	{0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48},
+	{0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a},
+	{0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88},
+	{0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a},
+	{0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9},
+	{0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42},
+	{0x0000a3ec, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081},
+	{0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff},
+	{0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff},
+	{0x0000781c, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000},
+	{0x00007840, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000},
+	{0x00007820, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480},
+	{0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480},
+};
+
+static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{0x00004040, 0xc01dcffc},
+	{0x00004040, 0x1aaabe41},
+	{0x00004040, 0xbe105554},
+	{0x00004040, 0x00043007},
+	{0x00004044, 0x00000000},
+};
+
+static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{0x00004040, 0xc01dcffd},
+	{0x00004040, 0x1aaabe41},
+	{0x00004040, 0xbe105554},
+	{0x00004040, 0x00043007},
+	{0x00004044, 0x00000000},
+};
+
+static const u32 ar9285PciePhy_clkreq_always_on_L1_9285[][2] = {
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{0x00004040, 0xc01dcffd},
+	{0x00004040, 0x1aaabe41},
+	{0x00004040, 0xbe105554},
+	{0x00004040, 0x00043007},
+	{0x00004044, 0x00000000},
+};
+
+static const u32 ar9285PciePhy_clkreq_off_L1_9285[][2] = {
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{0x00004040, 0xc01dcffc},
+	{0x00004040, 0x1aaabe41},
+	{0x00004040, 0xbe105554},
+	{0x00004040, 0x00043007},
+	{0x00004044, 0x00000000},
+};
+
+static const u32 ar9285Modes_9285_1_2[][6] = {
+	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
+	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
+	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
+	{0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008},
+	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
+	{0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f},
+	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880},
+	{0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
+	{0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+	{0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+	{0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+	{0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+	{0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e},
+	{0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0},
+	{0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
+	{0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
+	{0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
+	{0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+	{0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e},
+	{0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18},
+	{0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+	{0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+	{0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881},
+	{0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+	{0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016},
+	{0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d},
+	{0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010},
+	{0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c},
+	{0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00},
+	{0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+	{0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+	{0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f},
+	{0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+	{0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+	{0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000},
+	{0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
+	{0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
+	{0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
+	{0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
+	{0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
+	{0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
+	{0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
+	{0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
+	{0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
+	{0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
+	{0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
+	{0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
+	{0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
+	{0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
+	{0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
+	{0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
+	{0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
+	{0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
+	{0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
+	{0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
+	{0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
+	{0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
+	{0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
+	{0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
+	{0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
+	{0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
+	{0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000},
+	{0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000},
+	{0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000},
+	{0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000},
+	{0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000},
+	{0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000},
+	{0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000},
+	{0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000},
+	{0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
+	{0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
+	{0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
+	{0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
+	{0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
+	{0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
+	{0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
+	{0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
+	{0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
+	{0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
+	{0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
+	{0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
+	{0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
+	{0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
+	{0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
+	{0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
+	{0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
+	{0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
+	{0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
+	{0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
+	{0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
+	{0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
+	{0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
+	{0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
+	{0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
+	{0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
+	{0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
+	{0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
+	{0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
+	{0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
+	{0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
+	{0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
+	{0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
+	{0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
+	{0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
+	{0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
+	{0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
+	{0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
+	{0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
+	{0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
+	{0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
+	{0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
+	{0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
+	{0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
+	{0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
+	{0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
+	{0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
+	{0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
+	{0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
+	{0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
+	{0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
+	{0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
+	{0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
+	{0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
+	{0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000},
+	{0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
+	{0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
+	{0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
+	{0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
+	{0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
+	{0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
+	{0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
+	{0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
+	{0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
+	{0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
+	{0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
+	{0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
+	{0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
+	{0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
+	{0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
+	{0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
+	{0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
+	{0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
+	{0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
+	{0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
+	{0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
+	{0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
+	{0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
+	{0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
+	{0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
+	{0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
+	{0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000},
+	{0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000},
+	{0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000},
+	{0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000},
+	{0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000},
+	{0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000},
+	{0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000},
+	{0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000},
+	{0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
+	{0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
+	{0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
+	{0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
+	{0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
+	{0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
+	{0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
+	{0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
+	{0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
+	{0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
+	{0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
+	{0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
+	{0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
+	{0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
+	{0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
+	{0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
+	{0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
+	{0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
+	{0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
+	{0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
+	{0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
+	{0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
+	{0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
+	{0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
+	{0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
+	{0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
+	{0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
+	{0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
+	{0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
+	{0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
+	{0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
+	{0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
+	{0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
+	{0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
+	{0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
+	{0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
+	{0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
+	{0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
+	{0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
+	{0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
+	{0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
+	{0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
+	{0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
+	{0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
+	{0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
+	{0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
+	{0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
+	{0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
+	{0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
+	{0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
+	{0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
+	{0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
+	{0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
+	{0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
+	{0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004},
+	{0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
+	{0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
+	{0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+	{0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+	{0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000},
+	{0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
+};
+
+static const u32 ar9285Common_9285_1_2[][2] = {
+	/* Addr      allmodes  */
+	{0x0000000c, 0x00000000},
+	{0x00000030, 0x00020045},
+	{0x00000034, 0x00000005},
+	{0x00000040, 0x00000000},
+	{0x00000044, 0x00000008},
+	{0x00000048, 0x00000008},
+	{0x0000004c, 0x00000010},
+	{0x00000050, 0x00000000},
+	{0x00000054, 0x0000001f},
+	{0x00000800, 0x00000000},
+	{0x00000804, 0x00000000},
+	{0x00000808, 0x00000000},
+	{0x0000080c, 0x00000000},
+	{0x00000810, 0x00000000},
+	{0x00000814, 0x00000000},
+	{0x00000818, 0x00000000},
+	{0x0000081c, 0x00000000},
+	{0x00000820, 0x00000000},
+	{0x00000824, 0x00000000},
+	{0x00001040, 0x002ffc0f},
+	{0x00001044, 0x002ffc0f},
+	{0x00001048, 0x002ffc0f},
+	{0x0000104c, 0x002ffc0f},
+	{0x00001050, 0x002ffc0f},
+	{0x00001054, 0x002ffc0f},
+	{0x00001058, 0x002ffc0f},
+	{0x0000105c, 0x002ffc0f},
+	{0x00001060, 0x002ffc0f},
+	{0x00001064, 0x002ffc0f},
+	{0x00001230, 0x00000000},
+	{0x00001270, 0x00000000},
+	{0x00001038, 0x00000000},
+	{0x00001078, 0x00000000},
+	{0x000010b8, 0x00000000},
+	{0x000010f8, 0x00000000},
+	{0x00001138, 0x00000000},
+	{0x00001178, 0x00000000},
+	{0x000011b8, 0x00000000},
+	{0x000011f8, 0x00000000},
+	{0x00001238, 0x00000000},
+	{0x00001278, 0x00000000},
+	{0x000012b8, 0x00000000},
+	{0x000012f8, 0x00000000},
+	{0x00001338, 0x00000000},
+	{0x00001378, 0x00000000},
+	{0x000013b8, 0x00000000},
+	{0x000013f8, 0x00000000},
+	{0x00001438, 0x00000000},
+	{0x00001478, 0x00000000},
+	{0x000014b8, 0x00000000},
+	{0x000014f8, 0x00000000},
+	{0x00001538, 0x00000000},
+	{0x00001578, 0x00000000},
+	{0x000015b8, 0x00000000},
+	{0x000015f8, 0x00000000},
+	{0x00001638, 0x00000000},
+	{0x00001678, 0x00000000},
+	{0x000016b8, 0x00000000},
+	{0x000016f8, 0x00000000},
+	{0x00001738, 0x00000000},
+	{0x00001778, 0x00000000},
+	{0x000017b8, 0x00000000},
+	{0x000017f8, 0x00000000},
+	{0x0000103c, 0x00000000},
+	{0x0000107c, 0x00000000},
+	{0x000010bc, 0x00000000},
+	{0x000010fc, 0x00000000},
+	{0x0000113c, 0x00000000},
+	{0x0000117c, 0x00000000},
+	{0x000011bc, 0x00000000},
+	{0x000011fc, 0x00000000},
+	{0x0000123c, 0x00000000},
+	{0x0000127c, 0x00000000},
+	{0x000012bc, 0x00000000},
+	{0x000012fc, 0x00000000},
+	{0x0000133c, 0x00000000},
+	{0x0000137c, 0x00000000},
+	{0x000013bc, 0x00000000},
+	{0x000013fc, 0x00000000},
+	{0x0000143c, 0x00000000},
+	{0x0000147c, 0x00000000},
+	{0x00004030, 0x00000002},
+	{0x0000403c, 0x00000002},
+	{0x00004024, 0x0000001f},
+	{0x00004060, 0x00000000},
+	{0x00004064, 0x00000000},
+	{0x00007010, 0x00000031},
+	{0x00007034, 0x00000002},
+	{0x00007038, 0x000004c2},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000700},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008048, 0x00000000},
+	{0x00008054, 0x00000000},
+	{0x00008058, 0x00000000},
+	{0x0000805c, 0x000fc78f},
+	{0x00008060, 0x0000000f},
+	{0x00008064, 0x00000000},
+	{0x00008070, 0x00000000},
+	{0x000080c0, 0x2a80001a},
+	{0x000080c4, 0x05dc01e0},
+	{0x000080c8, 0x1f402710},
+	{0x000080cc, 0x01f40000},
+	{0x000080d0, 0x00001e00},
+	{0x000080d4, 0x00000000},
+	{0x000080d8, 0x00400000},
+	{0x000080e0, 0xffffffff},
+	{0x000080e4, 0x0000ffff},
+	{0x000080e8, 0x003f3f3f},
+	{0x000080ec, 0x00000000},
+	{0x000080f0, 0x00000000},
+	{0x000080f4, 0x00000000},
+	{0x000080f8, 0x00000000},
+	{0x000080fc, 0x00020000},
+	{0x00008100, 0x00020000},
+	{0x00008104, 0x00000001},
+	{0x00008108, 0x00000052},
+	{0x0000810c, 0x00000000},
+	{0x00008110, 0x00000168},
+	{0x00008118, 0x000100aa},
+	{0x0000811c, 0x00003210},
+	{0x00008120, 0x08f04810},
+	{0x00008124, 0x00000000},
+	{0x00008128, 0x00000000},
+	{0x0000812c, 0x00000000},
+	{0x00008130, 0x00000000},
+	{0x00008134, 0x00000000},
+	{0x00008138, 0x00000000},
+	{0x0000813c, 0x00000000},
+	{0x00008144, 0xffffffff},
+	{0x00008168, 0x00000000},
+	{0x0000816c, 0x00000000},
+	{0x00008170, 0x32143320},
+	{0x00008174, 0xfaa4fa50},
+	{0x00008178, 0x00000100},
+	{0x0000817c, 0x00000000},
+	{0x000081c0, 0x00000000},
+	{0x000081d0, 0x0000320a},
+	{0x000081ec, 0x00000000},
+	{0x000081f0, 0x00000000},
+	{0x000081f4, 0x00000000},
+	{0x000081f8, 0x00000000},
+	{0x000081fc, 0x00000000},
+	{0x00008200, 0x00000000},
+	{0x00008204, 0x00000000},
+	{0x00008208, 0x00000000},
+	{0x0000820c, 0x00000000},
+	{0x00008210, 0x00000000},
+	{0x00008214, 0x00000000},
+	{0x00008218, 0x00000000},
+	{0x0000821c, 0x00000000},
+	{0x00008220, 0x00000000},
+	{0x00008224, 0x00000000},
+	{0x00008228, 0x00000000},
+	{0x0000822c, 0x00000000},
+	{0x00008230, 0x00000000},
+	{0x00008234, 0x00000000},
+	{0x00008238, 0x00000000},
+	{0x0000823c, 0x00000000},
+	{0x00008240, 0x00100000},
+	{0x00008244, 0x0010f400},
+	{0x00008248, 0x00000100},
+	{0x0000824c, 0x0001e800},
+	{0x00008250, 0x00000000},
+	{0x00008254, 0x00000000},
+	{0x00008258, 0x00000000},
+	{0x0000825c, 0x400000ff},
+	{0x00008260, 0x00080922},
+	{0x00008264, 0x88a00010},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000000},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x00000000},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x0000829c, 0x00000000},
+	{0x00008300, 0x00000040},
+	{0x00008314, 0x00000000},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000001},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000e00},
+	{0x00008338, 0x00ff0000},
+	{0x0000833c, 0x00000000},
+	{0x00008340, 0x00010380},
+	{0x00008344, 0x00481043},
+	{0x00009808, 0x00000000},
+	{0x0000980c, 0xafe68e30},
+	{0x00009810, 0xfd14e000},
+	{0x00009814, 0x9c0a9f6b},
+	{0x0000981c, 0x00000000},
+	{0x0000982c, 0x0000a000},
+	{0x00009830, 0x00000000},
+	{0x0000983c, 0x00200400},
+	{0x0000984c, 0x0040233c},
+	{0x00009854, 0x00000044},
+	{0x00009900, 0x00000000},
+	{0x00009904, 0x00000000},
+	{0x00009908, 0x00000000},
+	{0x0000990c, 0x00000000},
+	{0x00009910, 0x01002310},
+	{0x0000991c, 0x10000fff},
+	{0x00009920, 0x04900000},
+	{0x00009928, 0x00000001},
+	{0x0000992c, 0x00000004},
+	{0x00009934, 0x1e1f2022},
+	{0x00009938, 0x0a0b0c0d},
+	{0x0000993c, 0x00000000},
+	{0x00009940, 0x14750604},
+	{0x00009948, 0x9280c00a},
+	{0x0000994c, 0x00020028},
+	{0x00009954, 0x5f3ca3de},
+	{0x00009958, 0x2108ecff},
+	{0x00009968, 0x000003ce},
+	{0x00009970, 0x192bb514},
+	{0x00009974, 0x00000000},
+	{0x00009978, 0x00000001},
+	{0x0000997c, 0x00000000},
+	{0x00009980, 0x00000000},
+	{0x00009984, 0x00000000},
+	{0x00009988, 0x00000000},
+	{0x0000998c, 0x00000000},
+	{0x00009990, 0x00000000},
+	{0x00009994, 0x00000000},
+	{0x00009998, 0x00000000},
+	{0x0000999c, 0x00000000},
+	{0x000099a0, 0x00000000},
+	{0x000099a4, 0x00000001},
+	{0x000099a8, 0x201fff00},
+	{0x000099ac, 0x2def0400},
+	{0x000099b0, 0x03051000},
+	{0x000099b4, 0x00000820},
+	{0x000099dc, 0x00000000},
+	{0x000099e0, 0x00000000},
+	{0x000099e4, 0xaaaaaaaa},
+	{0x000099e8, 0x3c466478},
+	{0x000099ec, 0x0cc80caa},
+	{0x000099f0, 0x00000000},
+	{0x0000a208, 0x803e68c8},
+	{0x0000a210, 0x4080a333},
+	{0x0000a214, 0x00206c10},
+	{0x0000a218, 0x009c4060},
+	{0x0000a220, 0x01834061},
+	{0x0000a224, 0x00000400},
+	{0x0000a228, 0x000003b5},
+	{0x0000a22c, 0x00000000},
+	{0x0000a234, 0x20202020},
+	{0x0000a238, 0x20202020},
+	{0x0000a244, 0x00000000},
+	{0x0000a248, 0xfffffffc},
+	{0x0000a24c, 0x00000000},
+	{0x0000a254, 0x00000000},
+	{0x0000a258, 0x0ccb5380},
+	{0x0000a25c, 0x15151501},
+	{0x0000a260, 0xdfa90f01},
+	{0x0000a268, 0x00000000},
+	{0x0000a26c, 0x0ebae9e6},
+	{0x0000d270, 0x0d820820},
+	{0x0000d35c, 0x07ffffef},
+	{0x0000d360, 0x0fffffe7},
+	{0x0000d364, 0x17ffffe5},
+	{0x0000d368, 0x1fffffe4},
+	{0x0000d36c, 0x37ffffe3},
+	{0x0000d370, 0x3fffffe3},
+	{0x0000d374, 0x57ffffe3},
+	{0x0000d378, 0x5fffffe2},
+	{0x0000d37c, 0x7fffffe2},
+	{0x0000d380, 0x7f3c7bba},
+	{0x0000d384, 0xf3307ff0},
+	{0x0000a388, 0x0c000000},
+	{0x0000a38c, 0x20202020},
+	{0x0000a390, 0x20202020},
+	{0x0000a39c, 0x00000001},
+	{0x0000a3a0, 0x00000000},
+	{0x0000a3a4, 0x00000000},
+	{0x0000a3a8, 0x00000000},
+	{0x0000a3ac, 0x00000000},
+	{0x0000a3b0, 0x00000000},
+	{0x0000a3b4, 0x00000000},
+	{0x0000a3b8, 0x00000000},
+	{0x0000a3bc, 0x00000000},
+	{0x0000a3c0, 0x00000000},
+	{0x0000a3c4, 0x00000000},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3e4, 0x00000000},
+	{0x0000a3e8, 0x18c43433},
+	{0x0000a3ec, 0x00f70081},
+	{0x00007800, 0x00140000},
+	{0x00007804, 0x0e4548d8},
+	{0x00007808, 0x54214514},
+	{0x0000780c, 0x02025830},
+	{0x00007810, 0x71c0d388},
+	{0x0000781c, 0x00000000},
+	{0x00007824, 0x00d86fff},
+	{0x0000782c, 0x6e36d97b},
+	{0x00007834, 0x71400087},
+	{0x00007844, 0x000c0db6},
+	{0x00007848, 0x6db6246f},
+	{0x0000784c, 0x6d9b66db},
+	{0x00007850, 0x6d8c6dba},
+	{0x00007854, 0x00040000},
+	{0x00007858, 0xdb003012},
+	{0x0000785c, 0x04924914},
+	{0x00007860, 0x21084210},
+	{0x00007864, 0xf7d7ffde},
+	{0x00007868, 0xc2034080},
+	{0x00007870, 0x10142c00},
+};
+
+static const u32 ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
+	{0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000},
+	{0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000},
+	{0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000},
+	{0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000},
+	{0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000},
+	{0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000},
+	{0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000},
+	{0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000},
+	{0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000},
+	{0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000},
+	{0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000},
+	{0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+	{0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+	{0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8},
+	{0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b},
+	{0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e},
+	{0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803},
+	{0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe},
+	{0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20},
+	{0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe},
+	{0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00},
+	{0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652},
+	{0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+	{0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7},
+	{0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+	{0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
+	{0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+	{0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
+};
+
+static const u32 ar9285Modes_original_tx_gain_9285_1_2[][6] = {
+	{0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000},
+	{0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000},
+	{0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000},
+	{0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000},
+	{0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000},
+	{0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000},
+	{0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000},
+	{0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000},
+	{0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000},
+	{0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000},
+	{0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000},
+	{0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+	{0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+	{0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8},
+	{0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b},
+	{0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e},
+	{0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801},
+	{0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe},
+	{0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20},
+	{0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4},
+	{0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04},
+	{0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652},
+	{0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+	{0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c},
+	{0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+	{0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
+	{0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+	{0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
+};
+
+static const u32 ar9285Modes_XE2_0_normal_power[][6] = {
+	{0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000},
+	{0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000},
+	{0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000},
+	{0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000},
+	{0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000},
+	{0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000},
+	{0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000},
+	{0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000},
+	{0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000},
+	{0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000},
+	{0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000},
+	{0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+	{0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+	{0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8},
+	{0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b},
+	{0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6dbae},
+	{0x00007838, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441},
+	{0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe},
+	{0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c},
+	{0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4},
+	{0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04},
+	{0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652},
+	{0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+	{0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c},
+	{0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+	{0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
+	{0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c},
+	{0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c},
+};
+
+static const u32 ar9285Modes_XE2_0_high_power[][6] = {
+	{0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000},
+	{0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000},
+	{0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000},
+	{0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000},
+	{0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000},
+	{0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000},
+	{0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000},
+	{0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000},
+	{0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000},
+	{0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000},
+	{0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000},
+	{0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+	{0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+	{0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8},
+	{0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b},
+	{0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e},
+	{0x00007838, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443},
+	{0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe},
+	{0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c},
+	{0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe},
+	{0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00},
+	{0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652},
+	{0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+	{0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7},
+	{0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+	{0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
+	{0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+	{0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7},
+};
+
+static const u32 ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = {
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{0x00004040, 0xc01dcffd},
+	{0x00004040, 0x1aaabe41},
+	{0x00004040, 0xbe105554},
+	{0x00004040, 0x00043007},
+	{0x00004044, 0x00000000},
+};
+
+static const u32 ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = {
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{0x00004040, 0xc01dcffc},
+	{0x00004040, 0x1aaabe41},
+	{0x00004040, 0xbe105554},
+	{0x00004040, 0x00043007},
+	{0x00004044, 0x00000000},
+};
+
+static const u32 ar9287Modes_9287_1_1[][6] = {
+	{0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0},
+	{0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0},
+	{0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180},
+	{0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008},
+	{0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0},
+	{0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f},
+	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810},
+	{0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a},
+	{0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880},
+	{0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303},
+	{0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200},
+	{0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+	{0x00009828, 0x00000000, 0x00000000, 0x3a020001, 0x3a020001, 0x3a020001},
+	{0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007},
+	{0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e},
+	{0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0},
+	{0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2},
+	{0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+	{0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e},
+	{0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18},
+	{0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+	{0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+	{0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881},
+	{0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0},
+	{0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016},
+	{0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d},
+	{0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010},
+	{0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010},
+	{0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010},
+	{0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210},
+	{0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce},
+	{0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c},
+	{0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00},
+	{0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+	{0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444},
+	{0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a},
+	{0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+	{0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000},
+	{0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
+	{0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+};
+
+static const u32 ar9287Common_9287_1_1[][2] = {
+	/* Addr      allmodes  */
+	{0x0000000c, 0x00000000},
+	{0x00000030, 0x00020015},
+	{0x00000034, 0x00000005},
+	{0x00000040, 0x00000000},
+	{0x00000044, 0x00000008},
+	{0x00000048, 0x00000008},
+	{0x0000004c, 0x00000010},
+	{0x00000050, 0x00000000},
+	{0x00000054, 0x0000001f},
+	{0x00000800, 0x00000000},
+	{0x00000804, 0x00000000},
+	{0x00000808, 0x00000000},
+	{0x0000080c, 0x00000000},
+	{0x00000810, 0x00000000},
+	{0x00000814, 0x00000000},
+	{0x00000818, 0x00000000},
+	{0x0000081c, 0x00000000},
+	{0x00000820, 0x00000000},
+	{0x00000824, 0x00000000},
+	{0x00001040, 0x002ffc0f},
+	{0x00001044, 0x002ffc0f},
+	{0x00001048, 0x002ffc0f},
+	{0x0000104c, 0x002ffc0f},
+	{0x00001050, 0x002ffc0f},
+	{0x00001054, 0x002ffc0f},
+	{0x00001058, 0x002ffc0f},
+	{0x0000105c, 0x002ffc0f},
+	{0x00001060, 0x002ffc0f},
+	{0x00001064, 0x002ffc0f},
+	{0x00001230, 0x00000000},
+	{0x00001270, 0x00000000},
+	{0x00001038, 0x00000000},
+	{0x00001078, 0x00000000},
+	{0x000010b8, 0x00000000},
+	{0x000010f8, 0x00000000},
+	{0x00001138, 0x00000000},
+	{0x00001178, 0x00000000},
+	{0x000011b8, 0x00000000},
+	{0x000011f8, 0x00000000},
+	{0x00001238, 0x00000000},
+	{0x00001278, 0x00000000},
+	{0x000012b8, 0x00000000},
+	{0x000012f8, 0x00000000},
+	{0x00001338, 0x00000000},
+	{0x00001378, 0x00000000},
+	{0x000013b8, 0x00000000},
+	{0x000013f8, 0x00000000},
+	{0x00001438, 0x00000000},
+	{0x00001478, 0x00000000},
+	{0x000014b8, 0x00000000},
+	{0x000014f8, 0x00000000},
+	{0x00001538, 0x00000000},
+	{0x00001578, 0x00000000},
+	{0x000015b8, 0x00000000},
+	{0x000015f8, 0x00000000},
+	{0x00001638, 0x00000000},
+	{0x00001678, 0x00000000},
+	{0x000016b8, 0x00000000},
+	{0x000016f8, 0x00000000},
+	{0x00001738, 0x00000000},
+	{0x00001778, 0x00000000},
+	{0x000017b8, 0x00000000},
+	{0x000017f8, 0x00000000},
+	{0x0000103c, 0x00000000},
+	{0x0000107c, 0x00000000},
+	{0x000010bc, 0x00000000},
+	{0x000010fc, 0x00000000},
+	{0x0000113c, 0x00000000},
+	{0x0000117c, 0x00000000},
+	{0x000011bc, 0x00000000},
+	{0x000011fc, 0x00000000},
+	{0x0000123c, 0x00000000},
+	{0x0000127c, 0x00000000},
+	{0x000012bc, 0x00000000},
+	{0x000012fc, 0x00000000},
+	{0x0000133c, 0x00000000},
+	{0x0000137c, 0x00000000},
+	{0x000013bc, 0x00000000},
+	{0x000013fc, 0x00000000},
+	{0x0000143c, 0x00000000},
+	{0x0000147c, 0x00000000},
+	{0x00004030, 0x00000002},
+	{0x0000403c, 0x00000002},
+	{0x00004024, 0x0000001f},
+	{0x00004060, 0x00000000},
+	{0x00004064, 0x00000000},
+	{0x00007010, 0x00000033},
+	{0x00007020, 0x00000000},
+	{0x00007034, 0x00000002},
+	{0x00007038, 0x000004c2},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000700},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008048, 0x40000000},
+	{0x00008054, 0x00000000},
+	{0x00008058, 0x00000000},
+	{0x0000805c, 0x000fc78f},
+	{0x00008060, 0x0000000f},
+	{0x00008064, 0x00000000},
+	{0x00008070, 0x00000000},
+	{0x000080c0, 0x2a80001a},
+	{0x000080c4, 0x05dc01e0},
+	{0x000080c8, 0x1f402710},
+	{0x000080cc, 0x01f40000},
+	{0x000080d0, 0x00001e00},
+	{0x000080d4, 0x00000000},
+	{0x000080d8, 0x00400000},
+	{0x000080e0, 0xffffffff},
+	{0x000080e4, 0x0000ffff},
+	{0x000080e8, 0x003f3f3f},
+	{0x000080ec, 0x00000000},
+	{0x000080f0, 0x00000000},
+	{0x000080f4, 0x00000000},
+	{0x000080f8, 0x00000000},
+	{0x000080fc, 0x00020000},
+	{0x00008100, 0x00020000},
+	{0x00008104, 0x00000001},
+	{0x00008108, 0x00000052},
+	{0x0000810c, 0x00000000},
+	{0x00008110, 0x00000168},
+	{0x00008118, 0x000100aa},
+	{0x0000811c, 0x00003210},
+	{0x00008124, 0x00000000},
+	{0x00008128, 0x00000000},
+	{0x0000812c, 0x00000000},
+	{0x00008130, 0x00000000},
+	{0x00008134, 0x00000000},
+	{0x00008138, 0x00000000},
+	{0x0000813c, 0x00000000},
+	{0x00008144, 0xffffffff},
+	{0x00008168, 0x00000000},
+	{0x0000816c, 0x00000000},
+	{0x00008170, 0x18487320},
+	{0x00008174, 0xfaa4fa50},
+	{0x00008178, 0x00000100},
+	{0x0000817c, 0x00000000},
+	{0x000081c0, 0x00000000},
+	{0x000081c4, 0x00000000},
+	{0x000081d4, 0x00000000},
+	{0x000081ec, 0x00000000},
+	{0x000081f0, 0x00000000},
+	{0x000081f4, 0x00000000},
+	{0x000081f8, 0x00000000},
+	{0x000081fc, 0x00000000},
+	{0x00008200, 0x00000000},
+	{0x00008204, 0x00000000},
+	{0x00008208, 0x00000000},
+	{0x0000820c, 0x00000000},
+	{0x00008210, 0x00000000},
+	{0x00008214, 0x00000000},
+	{0x00008218, 0x00000000},
+	{0x0000821c, 0x00000000},
+	{0x00008220, 0x00000000},
+	{0x00008224, 0x00000000},
+	{0x00008228, 0x00000000},
+	{0x0000822c, 0x00000000},
+	{0x00008230, 0x00000000},
+	{0x00008234, 0x00000000},
+	{0x00008238, 0x00000000},
+	{0x0000823c, 0x00000000},
+	{0x00008240, 0x00100000},
+	{0x00008244, 0x0010f400},
+	{0x00008248, 0x00000100},
+	{0x0000824c, 0x0001e800},
+	{0x00008250, 0x00000000},
+	{0x00008254, 0x00000000},
+	{0x00008258, 0x00000000},
+	{0x0000825c, 0x400000ff},
+	{0x00008260, 0x00080922},
+	{0x00008264, 0x88a00010},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000000},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x000000ff},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x0000829c, 0x00000000},
+	{0x00008300, 0x00000040},
+	{0x00008314, 0x00000000},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000007},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000e00},
+	{0x00008338, 0x00ff0000},
+	{0x0000833c, 0x00000000},
+	{0x00008340, 0x000107ff},
+	{0x00008344, 0x01c81043},
+	{0x00008360, 0xffffffff},
+	{0x00008364, 0xffffffff},
+	{0x00008368, 0x00000000},
+	{0x00008370, 0x00000000},
+	{0x00008374, 0x000000ff},
+	{0x00008378, 0x00000000},
+	{0x0000837c, 0x00000000},
+	{0x00008380, 0xffffffff},
+	{0x00008384, 0xffffffff},
+	{0x00008390, 0x0fffffff},
+	{0x00008394, 0x0fffffff},
+	{0x00008398, 0x00000000},
+	{0x0000839c, 0x00000000},
+	{0x000083a0, 0x00000000},
+	{0x00009808, 0x00000000},
+	{0x0000980c, 0xafe68e30},
+	{0x00009810, 0xfd14e000},
+	{0x00009814, 0x9c0a9f6b},
+	{0x0000981c, 0x00000000},
+	{0x0000982c, 0x0000a000},
+	{0x00009830, 0x00000000},
+	{0x0000983c, 0x00200400},
+	{0x0000984c, 0x0040233c},
+	{0x0000a84c, 0x0040233c},
+	{0x00009854, 0x00000044},
+	{0x00009900, 0x00000000},
+	{0x00009904, 0x00000000},
+	{0x00009908, 0x00000000},
+	{0x0000990c, 0x00000000},
+	{0x00009910, 0x10002310},
+	{0x0000991c, 0x10000fff},
+	{0x00009920, 0x04900000},
+	{0x0000a920, 0x04900000},
+	{0x00009928, 0x00000001},
+	{0x0000992c, 0x00000004},
+	{0x00009930, 0x00000000},
+	{0x0000a930, 0x00000000},
+	{0x00009934, 0x1e1f2022},
+	{0x00009938, 0x0a0b0c0d},
+	{0x0000993c, 0x00000000},
+	{0x00009948, 0x9280c00a},
+	{0x0000994c, 0x00020028},
+	{0x00009954, 0x5f3ca3de},
+	{0x00009958, 0x0108ecff},
+	{0x00009940, 0x14750604},
+	{0x0000c95c, 0x004b6a8e},
+	{0x00009970, 0x990bb514},
+	{0x00009974, 0x00000000},
+	{0x00009978, 0x00000001},
+	{0x0000997c, 0x00000000},
+	{0x000099a0, 0x00000000},
+	{0x000099a4, 0x00000001},
+	{0x000099a8, 0x201fff00},
+	{0x000099ac, 0x0c6f0000},
+	{0x000099b0, 0x03051000},
+	{0x000099b4, 0x00000820},
+	{0x000099c4, 0x06336f77},
+	{0x000099c8, 0x6af6532f},
+	{0x000099cc, 0x08f186c8},
+	{0x000099d0, 0x00046384},
+	{0x000099dc, 0x00000000},
+	{0x000099e0, 0x00000000},
+	{0x000099e4, 0xaaaaaaaa},
+	{0x000099e8, 0x3c466478},
+	{0x000099ec, 0x0cc80caa},
+	{0x000099f0, 0x00000000},
+	{0x000099fc, 0x00001042},
+	{0x0000a208, 0x803e4788},
+	{0x0000a210, 0x4080a333},
+	{0x0000a214, 0x40206c10},
+	{0x0000a218, 0x009c4060},
+	{0x0000a220, 0x01834061},
+	{0x0000a224, 0x00000400},
+	{0x0000a228, 0x000003b5},
+	{0x0000a22c, 0x233f7180},
+	{0x0000a234, 0x20202020},
+	{0x0000a238, 0x20202020},
+	{0x0000a23c, 0x13c889af},
+	{0x0000a240, 0x38490a20},
+	{0x0000a244, 0x00000000},
+	{0x0000a248, 0xfffffffc},
+	{0x0000a24c, 0x00000000},
+	{0x0000a254, 0x00000000},
+	{0x0000a258, 0x0cdbd380},
+	{0x0000a25c, 0x0f0f0f01},
+	{0x0000a260, 0xdfa91f01},
+	{0x0000a264, 0x00418a11},
+	{0x0000b264, 0x00418a11},
+	{0x0000a268, 0x00000000},
+	{0x0000a26c, 0x0e79e5c6},
+	{0x0000b26c, 0x0e79e5c6},
+	{0x0000d270, 0x00820820},
+	{0x0000a278, 0x1ce739ce},
+	{0x0000a27c, 0x050701ce},
+	{0x0000d35c, 0x07ffffef},
+	{0x0000d360, 0x0fffffe7},
+	{0x0000d364, 0x17ffffe5},
+	{0x0000d368, 0x1fffffe4},
+	{0x0000d36c, 0x37ffffe3},
+	{0x0000d370, 0x3fffffe3},
+	{0x0000d374, 0x57ffffe3},
+	{0x0000d378, 0x5fffffe2},
+	{0x0000d37c, 0x7fffffe2},
+	{0x0000d380, 0x7f3c7bba},
+	{0x0000d384, 0xf3307ff0},
+	{0x0000a388, 0x0c000000},
+	{0x0000a38c, 0x20202020},
+	{0x0000a390, 0x20202020},
+	{0x0000a394, 0x1ce739ce},
+	{0x0000a398, 0x000001ce},
+	{0x0000b398, 0x000001ce},
+	{0x0000a39c, 0x00000001},
+	{0x0000a3c8, 0x00000246},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3dc, 0x1ce739ce},
+	{0x0000a3e0, 0x000001ce},
+	{0x0000a3e4, 0x00000000},
+	{0x0000a3e8, 0x18c43433},
+	{0x0000a3ec, 0x00f70081},
+	{0x0000a3f0, 0x01036a1e},
+	{0x0000a3f4, 0x00000000},
+	{0x0000b3f4, 0x00000000},
+	{0x0000a7d8, 0x000003f1},
+	{0x00007800, 0x00000800},
+	{0x00007804, 0x6c35ffd2},
+	{0x00007808, 0x6db6c000},
+	{0x0000780c, 0x6db6cb30},
+	{0x00007810, 0x6db6cb6c},
+	{0x00007814, 0x0501e200},
+	{0x00007818, 0x0094128d},
+	{0x0000781c, 0x976ee392},
+	{0x00007820, 0xf75ff6fc},
+	{0x00007824, 0x00040000},
+	{0x00007828, 0xdb003012},
+	{0x0000782c, 0x04924914},
+	{0x00007830, 0x21084210},
+	{0x00007834, 0x00140000},
+	{0x00007838, 0x0e4548d8},
+	{0x0000783c, 0x54214514},
+	{0x00007840, 0x02025830},
+	{0x00007844, 0x71c0d388},
+	{0x00007848, 0x934934a8},
+	{0x00007850, 0x00000000},
+	{0x00007854, 0x00000800},
+	{0x00007858, 0x6c35ffd2},
+	{0x0000785c, 0x6db6c000},
+	{0x00007860, 0x6db6cb30},
+	{0x00007864, 0x6db6cb6c},
+	{0x00007868, 0x0501e200},
+	{0x0000786c, 0x0094128d},
+	{0x00007870, 0x976ee392},
+	{0x00007874, 0xf75ff6fc},
+	{0x00007878, 0x00040000},
+	{0x0000787c, 0xdb003012},
+	{0x00007880, 0x04924914},
+	{0x00007884, 0x21084210},
+	{0x00007888, 0x001b6db0},
+	{0x0000788c, 0x00376b63},
+	{0x00007890, 0x06db6db6},
+	{0x00007894, 0x006d8000},
+	{0x00007898, 0x48100000},
+	{0x0000789c, 0x00000000},
+	{0x000078a0, 0x08000000},
+	{0x000078a4, 0x0007ffd8},
+	{0x000078a8, 0x0007ffd8},
+	{0x000078ac, 0x001c0020},
+	{0x000078b0, 0x00060aeb},
+	{0x000078b4, 0x40008080},
+	{0x000078b8, 0x2a850160},
+};
+
+static const u32 ar9287Common_normal_cck_fir_coeff_9287_1_1[][2] = {
+	/* Addr      allmodes  */
+	{0x0000a1f4, 0x00fffeff},
+	{0x0000a1f8, 0x00f5f9ff},
+	{0x0000a1fc, 0xb79f6427},
+};
+
+static const u32 ar9287Common_japan_2484_cck_fir_coeff_9287_1_1[][2] = {
+	/* Addr      allmodes  */
+	{0x0000a1f4, 0x00000000},
+	{0x0000a1f8, 0xefff0301},
+	{0x0000a1fc, 0xca9228ee},
+};
+
+static const u32 ar9287Modes_tx_gain_9287_1_1[][6] = {
+	{0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002},
+	{0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004},
+	{0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a},
+	{0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c},
+	{0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b},
+	{0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a},
+	{0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a},
+	{0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a},
+	{0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a},
+	{0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a},
+	{0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a},
+	{0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a},
+	{0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c},
+	{0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc},
+	{0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4},
+	{0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc},
+	{0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede},
+	{0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e},
+	{0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e},
+	{0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e},
+	{0x0000a780, 0x00000000, 0x00000000, 0x00000062, 0x00000062, 0x00000062},
+	{0x0000a784, 0x00000000, 0x00000000, 0x00004064, 0x00004064, 0x00004064},
+	{0x0000a788, 0x00000000, 0x00000000, 0x000080a4, 0x000080a4, 0x000080a4},
+	{0x0000a78c, 0x00000000, 0x00000000, 0x0000c0aa, 0x0000c0aa, 0x0000c0aa},
+	{0x0000a790, 0x00000000, 0x00000000, 0x000100ac, 0x000100ac, 0x000100ac},
+	{0x0000a794, 0x00000000, 0x00000000, 0x000140b4, 0x000140b4, 0x000140b4},
+	{0x0000a798, 0x00000000, 0x00000000, 0x000180f4, 0x000180f4, 0x000180f4},
+	{0x0000a79c, 0x00000000, 0x00000000, 0x0001c134, 0x0001c134, 0x0001c134},
+	{0x0000a7a0, 0x00000000, 0x00000000, 0x00020174, 0x00020174, 0x00020174},
+	{0x0000a7a4, 0x00000000, 0x00000000, 0x0002417c, 0x0002417c, 0x0002417c},
+	{0x0000a7a8, 0x00000000, 0x00000000, 0x0002817e, 0x0002817e, 0x0002817e},
+	{0x0000a7ac, 0x00000000, 0x00000000, 0x0002c1be, 0x0002c1be, 0x0002c1be},
+	{0x0000a7b0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7b4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7b8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7bc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7c0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7c4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7c8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7cc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7d0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a7d4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe},
+	{0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000},
+};
+
+static const u32 ar9287Modes_rx_gain_9287_1_1[][6] = {
+	{0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120},
+	{0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124},
+	{0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128},
+	{0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c},
+	{0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130},
+	{0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194},
+	{0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198},
+	{0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c},
+	{0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210},
+	{0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284},
+	{0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288},
+	{0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c},
+	{0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290},
+	{0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294},
+	{0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0},
+	{0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4},
+	{0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8},
+	{0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac},
+	{0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0},
+	{0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4},
+	{0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8},
+	{0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4},
+	{0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708},
+	{0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c},
+	{0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710},
+	{0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04},
+	{0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08},
+	{0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c},
+	{0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10},
+	{0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14},
+	{0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18},
+	{0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c},
+	{0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90},
+	{0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94},
+	{0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98},
+	{0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4},
+	{0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8},
+	{0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04},
+	{0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08},
+	{0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c},
+	{0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10},
+	{0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14},
+	{0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18},
+	{0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c},
+	{0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90},
+	{0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18},
+	{0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24},
+	{0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28},
+	{0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314},
+	{0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318},
+	{0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c},
+	{0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390},
+	{0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394},
+	{0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398},
+	{0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4},
+	{0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8},
+	{0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac},
+	{0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0},
+	{0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380},
+	{0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384},
+	{0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388},
+	{0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710},
+	{0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714},
+	{0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718},
+	{0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10},
+	{0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14},
+	{0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18},
+	{0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c},
+	{0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90},
+	{0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94},
+	{0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c},
+	{0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90},
+	{0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94},
+	{0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0},
+	{0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4},
+	{0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8},
+	{0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac},
+	{0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0},
+	{0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4},
+	{0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1},
+	{0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5},
+	{0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9},
+	{0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad},
+	{0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1},
+	{0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5},
+	{0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9},
+	{0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5},
+	{0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9},
+	{0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd},
+	{0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1},
+	{0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5},
+	{0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2},
+	{0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6},
+	{0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca},
+	{0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce},
+	{0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2},
+	{0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6},
+	{0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda},
+	{0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7},
+	{0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb},
+	{0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf},
+	{0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3},
+	{0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7},
+	{0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120},
+	{0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124},
+	{0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128},
+	{0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c},
+	{0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130},
+	{0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194},
+	{0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198},
+	{0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c},
+	{0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210},
+	{0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284},
+	{0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288},
+	{0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c},
+	{0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290},
+	{0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294},
+	{0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0},
+	{0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4},
+	{0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8},
+	{0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac},
+	{0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0},
+	{0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4},
+	{0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8},
+	{0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4},
+	{0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708},
+	{0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c},
+	{0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710},
+	{0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04},
+	{0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08},
+	{0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c},
+	{0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10},
+	{0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14},
+	{0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18},
+	{0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c},
+	{0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90},
+	{0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94},
+	{0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98},
+	{0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4},
+	{0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8},
+	{0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04},
+	{0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08},
+	{0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c},
+	{0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10},
+	{0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14},
+	{0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18},
+	{0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c},
+	{0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90},
+	{0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18},
+	{0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24},
+	{0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28},
+	{0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314},
+	{0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318},
+	{0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c},
+	{0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390},
+	{0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394},
+	{0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398},
+	{0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4},
+	{0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8},
+	{0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac},
+	{0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0},
+	{0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380},
+	{0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384},
+	{0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388},
+	{0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710},
+	{0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714},
+	{0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718},
+	{0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10},
+	{0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14},
+	{0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18},
+	{0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c},
+	{0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90},
+	{0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94},
+	{0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c},
+	{0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90},
+	{0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94},
+	{0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0},
+	{0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4},
+	{0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8},
+	{0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac},
+	{0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0},
+	{0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4},
+	{0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1},
+	{0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5},
+	{0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9},
+	{0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad},
+	{0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1},
+	{0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5},
+	{0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9},
+	{0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5},
+	{0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9},
+	{0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd},
+	{0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1},
+	{0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5},
+	{0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2},
+	{0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6},
+	{0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca},
+	{0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce},
+	{0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2},
+	{0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6},
+	{0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda},
+	{0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7},
+	{0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb},
+	{0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf},
+	{0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3},
+	{0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7},
+	{0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb},
+	{0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067},
+	{0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067},
+};
+
+static const u32 ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = {
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{0x00004040, 0xc01dcffd},
+	{0x00004040, 0x1aaabe41},
+	{0x00004040, 0xbe105554},
+	{0x00004040, 0x00043007},
+	{0x00004044, 0x00000000},
+};
+
+static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = {
+	/* Addr      allmodes  */
+	{0x00004040, 0x9248fd00},
+	{0x00004040, 0x24924924},
+	{0x00004040, 0xa8000019},
+	{0x00004040, 0x13160820},
+	{0x00004040, 0xe5980560},
+	{0x00004040, 0xc01dcffc},
+	{0x00004040, 0x1aaabe41},
+	{0x00004040, 0xbe105554},
+	{0x00004040, 0x00043007},
+	{0x00004044, 0x00000000},
+};
+
+static const u32 ar9271Modes_9271[][6] = {
+	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0},
+	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0},
+	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180},
+	{0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008},
+	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0},
+	{0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f},
+	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880},
+	{0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303},
+	{0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200},
+	{0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+	{0x00009828, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001},
+	{0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007},
+	{0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e},
+	{0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0},
+	{0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
+	{0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059},
+	{0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
+	{0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+	{0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e},
+	{0x00009860, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
+	{0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00},
+	{0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+	{0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881},
+	{0x00009910, 0x30002310, 0x30002310, 0x30002310, 0x30002310, 0x30002310},
+	{0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0},
+	{0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016},
+	{0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d},
+	{0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010},
+	{0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c},
+	{0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00},
+	{0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+	{0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77},
+	{0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f},
+	{0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8},
+	{0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384},
+	{0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000},
+	{0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
+	{0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
+	{0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
+	{0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
+	{0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
+	{0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
+	{0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
+	{0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
+	{0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
+	{0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
+	{0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
+	{0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
+	{0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
+	{0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
+	{0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
+	{0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
+	{0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
+	{0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
+	{0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
+	{0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
+	{0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
+	{0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
+	{0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
+	{0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
+	{0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
+	{0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
+	{0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000},
+	{0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000},
+	{0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000},
+	{0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000},
+	{0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000},
+	{0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000},
+	{0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000},
+	{0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000},
+	{0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
+	{0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
+	{0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
+	{0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
+	{0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
+	{0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
+	{0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
+	{0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
+	{0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
+	{0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
+	{0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
+	{0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
+	{0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
+	{0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
+	{0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
+	{0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
+	{0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
+	{0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
+	{0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
+	{0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
+	{0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
+	{0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
+	{0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
+	{0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
+	{0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
+	{0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
+	{0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
+	{0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
+	{0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
+	{0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
+	{0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
+	{0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
+	{0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
+	{0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
+	{0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
+	{0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
+	{0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
+	{0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
+	{0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
+	{0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
+	{0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
+	{0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
+	{0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
+	{0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
+	{0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
+	{0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
+	{0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
+	{0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
+	{0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
+	{0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
+	{0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
+	{0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
+	{0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
+	{0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
+	{0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000},
+	{0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000},
+	{0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000},
+	{0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000},
+	{0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000},
+	{0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000},
+	{0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000},
+	{0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000},
+	{0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000},
+	{0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000},
+	{0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000},
+	{0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000},
+	{0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000},
+	{0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000},
+	{0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000},
+	{0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000},
+	{0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000},
+	{0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000},
+	{0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000},
+	{0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000},
+	{0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000},
+	{0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000},
+	{0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000},
+	{0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000},
+	{0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000},
+	{0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000},
+	{0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000},
+	{0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000},
+	{0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000},
+	{0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000},
+	{0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000},
+	{0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000},
+	{0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000},
+	{0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000},
+	{0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000},
+	{0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000},
+	{0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000},
+	{0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000},
+	{0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000},
+	{0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000},
+	{0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000},
+	{0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000},
+	{0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000},
+	{0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000},
+	{0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000},
+	{0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000},
+	{0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000},
+	{0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000},
+	{0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000},
+	{0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000},
+	{0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000},
+	{0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000},
+	{0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000},
+	{0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000},
+	{0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000},
+	{0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000},
+	{0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000},
+	{0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000},
+	{0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000},
+	{0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000},
+	{0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000},
+	{0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000},
+	{0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000},
+	{0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000},
+	{0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000},
+	{0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000},
+	{0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000},
+	{0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000},
+	{0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000},
+	{0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000},
+	{0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000},
+	{0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000},
+	{0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000},
+	{0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000},
+	{0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000},
+	{0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000},
+	{0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000},
+	{0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000},
+	{0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000},
+	{0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000},
+	{0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000},
+	{0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000},
+	{0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000},
+	{0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000},
+	{0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000},
+	{0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000},
+	{0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000},
+	{0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000},
+	{0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000},
+	{0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000},
+	{0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004},
+	{0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
+	{0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000},
+	{0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a},
+	{0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000},
+	{0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000},
+	{0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e},
+};
+
+static const u32 ar9271Common_9271[][2] = {
+	/* Addr      allmodes  */
+	{0x0000000c, 0x00000000},
+	{0x00000030, 0x00020045},
+	{0x00000034, 0x00000005},
+	{0x00000040, 0x00000000},
+	{0x00000044, 0x00000008},
+	{0x00000048, 0x00000008},
+	{0x0000004c, 0x00000010},
+	{0x00000050, 0x00000000},
+	{0x00000054, 0x0000001f},
+	{0x00000800, 0x00000000},
+	{0x00000804, 0x00000000},
+	{0x00000808, 0x00000000},
+	{0x0000080c, 0x00000000},
+	{0x00000810, 0x00000000},
+	{0x00000814, 0x00000000},
+	{0x00000818, 0x00000000},
+	{0x0000081c, 0x00000000},
+	{0x00000820, 0x00000000},
+	{0x00000824, 0x00000000},
+	{0x00001040, 0x002ffc0f},
+	{0x00001044, 0x002ffc0f},
+	{0x00001048, 0x002ffc0f},
+	{0x0000104c, 0x002ffc0f},
+	{0x00001050, 0x002ffc0f},
+	{0x00001054, 0x002ffc0f},
+	{0x00001058, 0x002ffc0f},
+	{0x0000105c, 0x002ffc0f},
+	{0x00001060, 0x002ffc0f},
+	{0x00001064, 0x002ffc0f},
+	{0x00001230, 0x00000000},
+	{0x00001270, 0x00000000},
+	{0x00001038, 0x00000000},
+	{0x00001078, 0x00000000},
+	{0x000010b8, 0x00000000},
+	{0x000010f8, 0x00000000},
+	{0x00001138, 0x00000000},
+	{0x00001178, 0x00000000},
+	{0x000011b8, 0x00000000},
+	{0x000011f8, 0x00000000},
+	{0x00001238, 0x00000000},
+	{0x00001278, 0x00000000},
+	{0x000012b8, 0x00000000},
+	{0x000012f8, 0x00000000},
+	{0x00001338, 0x00000000},
+	{0x00001378, 0x00000000},
+	{0x000013b8, 0x00000000},
+	{0x000013f8, 0x00000000},
+	{0x00001438, 0x00000000},
+	{0x00001478, 0x00000000},
+	{0x000014b8, 0x00000000},
+	{0x000014f8, 0x00000000},
+	{0x00001538, 0x00000000},
+	{0x00001578, 0x00000000},
+	{0x000015b8, 0x00000000},
+	{0x000015f8, 0x00000000},
+	{0x00001638, 0x00000000},
+	{0x00001678, 0x00000000},
+	{0x000016b8, 0x00000000},
+	{0x000016f8, 0x00000000},
+	{0x00001738, 0x00000000},
+	{0x00001778, 0x00000000},
+	{0x000017b8, 0x00000000},
+	{0x000017f8, 0x00000000},
+	{0x0000103c, 0x00000000},
+	{0x0000107c, 0x00000000},
+	{0x000010bc, 0x00000000},
+	{0x000010fc, 0x00000000},
+	{0x0000113c, 0x00000000},
+	{0x0000117c, 0x00000000},
+	{0x000011bc, 0x00000000},
+	{0x000011fc, 0x00000000},
+	{0x0000123c, 0x00000000},
+	{0x0000127c, 0x00000000},
+	{0x000012bc, 0x00000000},
+	{0x000012fc, 0x00000000},
+	{0x0000133c, 0x00000000},
+	{0x0000137c, 0x00000000},
+	{0x000013bc, 0x00000000},
+	{0x000013fc, 0x00000000},
+	{0x0000143c, 0x00000000},
+	{0x0000147c, 0x00000000},
+	{0x00004030, 0x00000002},
+	{0x0000403c, 0x00000002},
+	{0x00004024, 0x0000001f},
+	{0x00004060, 0x00000000},
+	{0x00004064, 0x00000000},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000700},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008048, 0x00000000},
+	{0x00008054, 0x00000000},
+	{0x00008058, 0x00000000},
+	{0x0000805c, 0x000fc78f},
+	{0x00008060, 0x0000000f},
+	{0x00008064, 0x00000000},
+	{0x00008070, 0x00000000},
+	{0x000080b0, 0x00000000},
+	{0x000080b4, 0x00000000},
+	{0x000080b8, 0x00000000},
+	{0x000080bc, 0x00000000},
+	{0x000080c0, 0x2a80001a},
+	{0x000080c4, 0x05dc01e0},
+	{0x000080c8, 0x1f402710},
+	{0x000080cc, 0x01f40000},
+	{0x000080d0, 0x00001e00},
+	{0x000080d4, 0x00000000},
+	{0x000080d8, 0x00400000},
+	{0x000080e0, 0xffffffff},
+	{0x000080e4, 0x0000ffff},
+	{0x000080e8, 0x003f3f3f},
+	{0x000080ec, 0x00000000},
+	{0x000080f0, 0x00000000},
+	{0x000080f4, 0x00000000},
+	{0x000080f8, 0x00000000},
+	{0x000080fc, 0x00020000},
+	{0x00008100, 0x00020000},
+	{0x00008104, 0x00000001},
+	{0x00008108, 0x00000052},
+	{0x0000810c, 0x00000000},
+	{0x00008110, 0x00000168},
+	{0x00008118, 0x000100aa},
+	{0x0000811c, 0x00003210},
+	{0x00008120, 0x08f04810},
+	{0x00008124, 0x00000000},
+	{0x00008128, 0x00000000},
+	{0x0000812c, 0x00000000},
+	{0x00008130, 0x00000000},
+	{0x00008134, 0x00000000},
+	{0x00008138, 0x00000000},
+	{0x0000813c, 0x00000000},
+	{0x00008144, 0xffffffff},
+	{0x00008168, 0x00000000},
+	{0x0000816c, 0x00000000},
+	{0x00008170, 0x32143320},
+	{0x00008174, 0xfaa4fa50},
+	{0x00008178, 0x00000100},
+	{0x0000817c, 0x00000000},
+	{0x000081c0, 0x00000000},
+	{0x000081d0, 0x0000320a},
+	{0x000081ec, 0x00000000},
+	{0x000081f0, 0x00000000},
+	{0x000081f4, 0x00000000},
+	{0x000081f8, 0x00000000},
+	{0x000081fc, 0x00000000},
+	{0x00008200, 0x00000000},
+	{0x00008204, 0x00000000},
+	{0x00008208, 0x00000000},
+	{0x0000820c, 0x00000000},
+	{0x00008210, 0x00000000},
+	{0x00008214, 0x00000000},
+	{0x00008218, 0x00000000},
+	{0x0000821c, 0x00000000},
+	{0x00008220, 0x00000000},
+	{0x00008224, 0x00000000},
+	{0x00008228, 0x00000000},
+	{0x0000822c, 0x00000000},
+	{0x00008230, 0x00000000},
+	{0x00008234, 0x00000000},
+	{0x00008238, 0x00000000},
+	{0x0000823c, 0x00000000},
+	{0x00008240, 0x00100000},
+	{0x00008244, 0x0010f400},
+	{0x00008248, 0x00000100},
+	{0x0000824c, 0x0001e800},
+	{0x00008250, 0x00000000},
+	{0x00008254, 0x00000000},
+	{0x00008258, 0x00000000},
+	{0x0000825c, 0x400000ff},
+	{0x00008260, 0x00080922},
+	{0x00008264, 0x88a00010},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000000},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x00000000},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x0000829c, 0x00000000},
+	{0x00008300, 0x00000040},
+	{0x00008314, 0x00000000},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000001},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000e00},
+	{0x00008338, 0x00ff0000},
+	{0x0000833c, 0x00000000},
+	{0x00008340, 0x00010380},
+	{0x00008344, 0x00581043},
+	{0x00007010, 0x00000030},
+	{0x00007034, 0x00000002},
+	{0x00007038, 0x000004c2},
+	{0x00007800, 0x00140000},
+	{0x00007804, 0x0e4548d8},
+	{0x00007808, 0x54214514},
+	{0x0000780c, 0x02025820},
+	{0x00007810, 0x71c0d388},
+	{0x00007814, 0x924934a8},
+	{0x0000781c, 0x00000000},
+	{0x00007828, 0x66964300},
+	{0x0000782c, 0x8db6d961},
+	{0x00007830, 0x8db6d96c},
+	{0x00007834, 0x6140008b},
+	{0x0000783c, 0x72ee0a72},
+	{0x00007840, 0xbbfffffc},
+	{0x00007844, 0x000c0db6},
+	{0x00007848, 0x6db6246f},
+	{0x0000784c, 0x6d9b66db},
+	{0x00007850, 0x6d8c6dba},
+	{0x00007854, 0x00040000},
+	{0x00007858, 0xdb003012},
+	{0x0000785c, 0x04924914},
+	{0x00007860, 0x21084210},
+	{0x00007864, 0xf7d7ffde},
+	{0x00007868, 0xc2034080},
+	{0x00007870, 0x10142c00},
+	{0x00009808, 0x00000000},
+	{0x0000980c, 0xafe68e30},
+	{0x00009810, 0xfd14e000},
+	{0x00009814, 0x9c0a9f6b},
+	{0x0000981c, 0x00000000},
+	{0x0000982c, 0x0000a000},
+	{0x00009830, 0x00000000},
+	{0x0000983c, 0x00200400},
+	{0x0000984c, 0x0040233c},
+	{0x00009854, 0x00000044},
+	{0x00009900, 0x00000000},
+	{0x00009904, 0x00000000},
+	{0x00009908, 0x00000000},
+	{0x0000990c, 0x00000000},
+	{0x0000991c, 0x10000fff},
+	{0x00009920, 0x04900000},
+	{0x00009928, 0x00000001},
+	{0x0000992c, 0x00000004},
+	{0x00009934, 0x1e1f2022},
+	{0x00009938, 0x0a0b0c0d},
+	{0x0000993c, 0x00000000},
+	{0x00009940, 0x14750604},
+	{0x00009948, 0x9280c00a},
+	{0x0000994c, 0x00020028},
+	{0x00009954, 0x5f3ca3de},
+	{0x00009958, 0x0108ecff},
+	{0x00009968, 0x000003ce},
+	{0x00009970, 0x192bb514},
+	{0x00009974, 0x00000000},
+	{0x00009978, 0x00000001},
+	{0x0000997c, 0x00000000},
+	{0x00009980, 0x00000000},
+	{0x00009984, 0x00000000},
+	{0x00009988, 0x00000000},
+	{0x0000998c, 0x00000000},
+	{0x00009990, 0x00000000},
+	{0x00009994, 0x00000000},
+	{0x00009998, 0x00000000},
+	{0x0000999c, 0x00000000},
+	{0x000099a0, 0x00000000},
+	{0x000099a4, 0x00000001},
+	{0x000099a8, 0x201fff00},
+	{0x000099ac, 0x2def0400},
+	{0x000099b0, 0x03051000},
+	{0x000099b4, 0x00000820},
+	{0x000099dc, 0x00000000},
+	{0x000099e0, 0x00000000},
+	{0x000099e4, 0xaaaaaaaa},
+	{0x000099e8, 0x3c466478},
+	{0x000099ec, 0x0cc80caa},
+	{0x000099f0, 0x00000000},
+	{0x0000a208, 0x803e68c8},
+	{0x0000a210, 0x4080a333},
+	{0x0000a214, 0x00206c10},
+	{0x0000a218, 0x009c4060},
+	{0x0000a220, 0x01834061},
+	{0x0000a224, 0x00000400},
+	{0x0000a228, 0x000003b5},
+	{0x0000a22c, 0x00000000},
+	{0x0000a234, 0x20202020},
+	{0x0000a238, 0x20202020},
+	{0x0000a244, 0x00000000},
+	{0x0000a248, 0xfffffffc},
+	{0x0000a24c, 0x00000000},
+	{0x0000a254, 0x00000000},
+	{0x0000a258, 0x0ccb5380},
+	{0x0000a25c, 0x15151501},
+	{0x0000a260, 0xdfa90f01},
+	{0x0000a268, 0x00000000},
+	{0x0000a26c, 0x0ebae9e6},
+	{0x0000a388, 0x0c000000},
+	{0x0000a38c, 0x20202020},
+	{0x0000a390, 0x20202020},
+	{0x0000a39c, 0x00000001},
+	{0x0000a3a0, 0x00000000},
+	{0x0000a3a4, 0x00000000},
+	{0x0000a3a8, 0x00000000},
+	{0x0000a3ac, 0x00000000},
+	{0x0000a3b0, 0x00000000},
+	{0x0000a3b4, 0x00000000},
+	{0x0000a3b8, 0x00000000},
+	{0x0000a3bc, 0x00000000},
+	{0x0000a3c0, 0x00000000},
+	{0x0000a3c4, 0x00000000},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3e4, 0x00000000},
+	{0x0000a3e8, 0x18c43433},
+	{0x0000a3ec, 0x00f70081},
+	{0x0000a3f0, 0x01036a2f},
+	{0x0000a3f4, 0x00000000},
+	{0x0000d270, 0x0d820820},
+	{0x0000d35c, 0x07ffffef},
+	{0x0000d360, 0x0fffffe7},
+	{0x0000d364, 0x17ffffe5},
+	{0x0000d368, 0x1fffffe4},
+	{0x0000d36c, 0x37ffffe3},
+	{0x0000d370, 0x3fffffe3},
+	{0x0000d374, 0x57ffffe3},
+	{0x0000d378, 0x5fffffe2},
+	{0x0000d37c, 0x7fffffe2},
+	{0x0000d380, 0x7f3c7bba},
+	{0x0000d384, 0xf3307ff0},
+};
+
+static const u32 ar9271Common_normal_cck_fir_coeff_9271[][2] = {
+	/* Addr      allmodes  */
+	{0x0000a1f4, 0x00fffeff},
+	{0x0000a1f8, 0x00f5f9ff},
+	{0x0000a1fc, 0xb79f6427},
+};
+
+static const u32 ar9271Common_japan_2484_cck_fir_coeff_9271[][2] = {
+	/* Addr      allmodes  */
+	{0x0000a1f4, 0x00000000},
+	{0x0000a1f8, 0xefff0301},
+	{0x0000a1fc, 0xca9228ee},
+};
+
+static const u32 ar9271Modes_9271_1_0_only[][6] = {
+	{0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311, 0x30002311},
+	{0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001},
+};
+
+static const u32 ar9271Modes_9271_ANI_reg[][6] = {
+	{0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2},
+	{0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e},
+	{0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e},
+	{0x0000986c, 0x06903881, 0x06903881, 0x06903881, 0x06903881, 0x06903881},
+	{0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+	{0x0000a208, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8},
+	{0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d},
+	{0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+};
+
+static const u32 ar9271Modes_normal_power_tx_gain_9271[][6] = {
+	{0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000},
+	{0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000},
+	{0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000},
+	{0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000},
+	{0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000},
+	{0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000},
+	{0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000},
+	{0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000},
+	{0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000},
+	{0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000},
+	{0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000},
+	{0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+	{0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+	{0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x00007838, 0x00000029, 0x00000029, 0x00000029, 0x00000029, 0x00000029},
+	{0x00007824, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff},
+	{0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4},
+	{0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04},
+	{0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652},
+	{0x0000a278, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd},
+	{0x0000a27c, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd},
+	{0x0000a394, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd},
+	{0x0000a398, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd},
+	{0x0000a3dc, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd},
+	{0x0000a3e0, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd},
+};
+
+static const u32 ar9271Modes_high_power_tx_gain_9271[][6] = {
+	{0x0000a300, 0x00000000, 0x00000000, 0x00010000, 0x00010000, 0x00000000},
+	{0x0000a304, 0x00000000, 0x00000000, 0x00016200, 0x00016200, 0x00000000},
+	{0x0000a308, 0x00000000, 0x00000000, 0x00018201, 0x00018201, 0x00000000},
+	{0x0000a30c, 0x00000000, 0x00000000, 0x0001b240, 0x0001b240, 0x00000000},
+	{0x0000a310, 0x00000000, 0x00000000, 0x0001d241, 0x0001d241, 0x00000000},
+	{0x0000a314, 0x00000000, 0x00000000, 0x0001f600, 0x0001f600, 0x00000000},
+	{0x0000a318, 0x00000000, 0x00000000, 0x00022800, 0x00022800, 0x00000000},
+	{0x0000a31c, 0x00000000, 0x00000000, 0x00026802, 0x00026802, 0x00000000},
+	{0x0000a320, 0x00000000, 0x00000000, 0x0002b805, 0x0002b805, 0x00000000},
+	{0x0000a324, 0x00000000, 0x00000000, 0x0002ea41, 0x0002ea41, 0x00000000},
+	{0x0000a328, 0x00000000, 0x00000000, 0x00038b00, 0x00038b00, 0x00000000},
+	{0x0000a32c, 0x00000000, 0x00000000, 0x0003ab40, 0x0003ab40, 0x00000000},
+	{0x0000a330, 0x00000000, 0x00000000, 0x0003cd80, 0x0003cd80, 0x00000000},
+	{0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000},
+	{0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000},
+	{0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000},
+	{0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000},
+	{0x00007838, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b},
+	{0x00007824, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff},
+	{0x0000786c, 0x08609eb6, 0x08609eb6, 0x08609eba, 0x08609eba, 0x08609eb6},
+	{0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00},
+	{0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a214652, 0x0a214652, 0x0a22a652},
+	{0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7},
+	{0x0000a27c, 0x05018063, 0x05038063, 0x05018063, 0x05018063, 0x05018063},
+	{0x0000a394, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63},
+	{0x0000a398, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063},
+	{0x0000a3dc, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63},
+	{0x0000a3e0, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063},
+};
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ar9002_phy.h b/roms/ipxe/src/drivers/net/ath/ath9k/ar9002_phy.h
new file mode 100644
index 0000000000000000000000000000000000000000..453af6dc514b5f700a16a615d1f2ea3104191026
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ar9002_phy.h
@@ -0,0 +1,613 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef AR9002_PHY_H
+#define AR9002_PHY_H
+
+#define AR_PHY_TEST             0x9800
+#define PHY_AGC_CLR             0x10000000
+#define RFSILENT_BB             0x00002000
+
+#define AR_PHY_TURBO                0x9804
+#define AR_PHY_FC_TURBO_MODE        0x00000001
+#define AR_PHY_FC_TURBO_SHORT       0x00000002
+#define AR_PHY_FC_DYN2040_EN        0x00000004
+#define AR_PHY_FC_DYN2040_PRI_ONLY  0x00000008
+#define AR_PHY_FC_DYN2040_PRI_CH    0x00000010
+/* For 25 MHz channel spacing -- not used but supported by hw */
+#define AR_PHY_FC_DYN2040_EXT_CH    0x00000020
+#define AR_PHY_FC_HT_EN             0x00000040
+#define AR_PHY_FC_SHORT_GI_40       0x00000080
+#define AR_PHY_FC_WALSH             0x00000100
+#define AR_PHY_FC_SINGLE_HT_LTF1    0x00000200
+#define AR_PHY_FC_ENABLE_DAC_FIFO   0x00000800
+
+#define AR_PHY_TEST2			0x9808
+
+#define AR_PHY_TIMING2           0x9810
+#define AR_PHY_TIMING3           0x9814
+#define AR_PHY_TIMING3_DSC_MAN   0xFFFE0000
+#define AR_PHY_TIMING3_DSC_MAN_S 17
+#define AR_PHY_TIMING3_DSC_EXP   0x0001E000
+#define AR_PHY_TIMING3_DSC_EXP_S 13
+
+#define AR_PHY_CHIP_ID_REV_0      0x80
+#define AR_PHY_CHIP_ID_REV_1      0x81
+#define AR_PHY_CHIP_ID_9160_REV_0 0xb0
+
+#define AR_PHY_ACTIVE       0x981C
+#define AR_PHY_ACTIVE_EN    0x00000001
+#define AR_PHY_ACTIVE_DIS   0x00000000
+
+#define AR_PHY_RF_CTL2             0x9824
+#define AR_PHY_TX_END_DATA_START   0x000000FF
+#define AR_PHY_TX_END_DATA_START_S 0
+#define AR_PHY_TX_END_PA_ON        0x0000FF00
+#define AR_PHY_TX_END_PA_ON_S      8
+
+#define AR_PHY_RF_CTL3                  0x9828
+#define AR_PHY_TX_END_TO_A2_RX_ON       0x00FF0000
+#define AR_PHY_TX_END_TO_A2_RX_ON_S     16
+
+#define AR_PHY_ADC_CTL                  0x982C
+#define AR_PHY_ADC_CTL_OFF_INBUFGAIN    0x00000003
+#define AR_PHY_ADC_CTL_OFF_INBUFGAIN_S  0
+#define AR_PHY_ADC_CTL_OFF_PWDDAC       0x00002000
+#define AR_PHY_ADC_CTL_OFF_PWDBANDGAP   0x00004000
+#define AR_PHY_ADC_CTL_OFF_PWDADC       0x00008000
+#define AR_PHY_ADC_CTL_ON_INBUFGAIN     0x00030000
+#define AR_PHY_ADC_CTL_ON_INBUFGAIN_S   16
+
+#define AR_PHY_ADC_SERIAL_CTL       0x9830
+#define AR_PHY_SEL_INTERNAL_ADDAC   0x00000000
+#define AR_PHY_SEL_EXTERNAL_RADIO   0x00000001
+
+#define AR_PHY_RF_CTL4                    0x9834
+#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF    0xFF000000
+#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF_S  24
+#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF    0x00FF0000
+#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF_S  16
+#define AR_PHY_RF_CTL4_FRAME_XPAB_ON      0x0000FF00
+#define AR_PHY_RF_CTL4_FRAME_XPAB_ON_S    8
+#define AR_PHY_RF_CTL4_FRAME_XPAA_ON      0x000000FF
+#define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S    0
+
+#define AR_PHY_TSTDAC_CONST               0x983c
+
+#define AR_PHY_SETTLING          0x9844
+#define AR_PHY_SETTLING_SWITCH   0x00003F80
+#define AR_PHY_SETTLING_SWITCH_S 7
+
+#define AR_PHY_RXGAIN                   0x9848
+#define AR_PHY_RXGAIN_TXRX_ATTEN        0x0003F000
+#define AR_PHY_RXGAIN_TXRX_ATTEN_S      12
+#define AR_PHY_RXGAIN_TXRX_RF_MAX       0x007C0000
+#define AR_PHY_RXGAIN_TXRX_RF_MAX_S     18
+#define AR9280_PHY_RXGAIN_TXRX_ATTEN    0x00003F80
+#define AR9280_PHY_RXGAIN_TXRX_ATTEN_S  7
+#define AR9280_PHY_RXGAIN_TXRX_MARGIN   0x001FC000
+#define AR9280_PHY_RXGAIN_TXRX_MARGIN_S 14
+
+#define AR_PHY_DESIRED_SZ           0x9850
+#define AR_PHY_DESIRED_SZ_ADC       0x000000FF
+#define AR_PHY_DESIRED_SZ_ADC_S     0
+#define AR_PHY_DESIRED_SZ_PGA       0x0000FF00
+#define AR_PHY_DESIRED_SZ_PGA_S     8
+#define AR_PHY_DESIRED_SZ_TOT_DES   0x0FF00000
+#define AR_PHY_DESIRED_SZ_TOT_DES_S 20
+
+#define AR_PHY_FIND_SIG           0x9858
+#define AR_PHY_FIND_SIG_FIRSTEP   0x0003F000
+#define AR_PHY_FIND_SIG_FIRSTEP_S 12
+#define AR_PHY_FIND_SIG_FIRPWR    0x03FC0000
+#define AR_PHY_FIND_SIG_FIRPWR_S  18
+
+#define AR_PHY_FIND_SIG_LOW           0x9840
+#define AR_PHY_FIND_SIG_FIRSTEP_LOW   0x00000FC0L
+#define AR_PHY_FIND_SIG_FIRSTEP_LOW_S 6
+
+#define AR_PHY_AGC_CTL1                  0x985C
+#define AR_PHY_AGC_CTL1_COARSE_LOW       0x00007F80
+#define AR_PHY_AGC_CTL1_COARSE_LOW_S     7
+#define AR_PHY_AGC_CTL1_COARSE_HIGH      0x003F8000
+#define AR_PHY_AGC_CTL1_COARSE_HIGH_S    15
+
+#define AR_PHY_CCA                  0x9864
+#define AR_PHY_MINCCA_PWR           0x0FF80000
+#define AR_PHY_MINCCA_PWR_S         19
+#define AR_PHY_CCA_THRESH62         0x0007F000
+#define AR_PHY_CCA_THRESH62_S       12
+#define AR9280_PHY_MINCCA_PWR       0x1FF00000
+#define AR9280_PHY_MINCCA_PWR_S     20
+#define AR9280_PHY_CCA_THRESH62     0x000FF000
+#define AR9280_PHY_CCA_THRESH62_S   12
+
+#define AR_PHY_SFCORR_LOW                    0x986C
+#define AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW  0x00000001
+#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW    0x00003F00
+#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S  8
+#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW      0x001FC000
+#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S    14
+#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW      0x0FE00000
+#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S    21
+
+#define AR_PHY_SFCORR                0x9868
+#define AR_PHY_SFCORR_M2COUNT_THR    0x0000001F
+#define AR_PHY_SFCORR_M2COUNT_THR_S  0
+#define AR_PHY_SFCORR_M1_THRESH      0x00FE0000
+#define AR_PHY_SFCORR_M1_THRESH_S    17
+#define AR_PHY_SFCORR_M2_THRESH      0x7F000000
+#define AR_PHY_SFCORR_M2_THRESH_S    24
+
+#define AR_PHY_SLEEP_CTR_CONTROL    0x9870
+#define AR_PHY_SLEEP_CTR_LIMIT      0x9874
+#define AR_PHY_SYNTH_CONTROL        0x9874
+#define AR_PHY_SLEEP_SCAL           0x9878
+
+#define AR_PHY_PLL_CTL          0x987c
+#define AR_PHY_PLL_CTL_40       0xaa
+#define AR_PHY_PLL_CTL_40_5413  0x04
+#define AR_PHY_PLL_CTL_44       0xab
+#define AR_PHY_PLL_CTL_44_2133  0xeb
+#define AR_PHY_PLL_CTL_40_2133  0xea
+
+#define AR_PHY_SPECTRAL_SCAN			0x9910  /* AR9280 spectral scan configuration register */
+#define	AR_PHY_SPECTRAL_SCAN_ENABLE		0x1
+#define AR_PHY_SPECTRAL_SCAN_ENA		0x00000001  /* Enable spectral scan, reg 68, bit 0 */
+#define AR_PHY_SPECTRAL_SCAN_ENA_S		0  /* Enable spectral scan, reg 68, bit 0 */
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE		0x00000002  /* Activate spectral scan reg 68, bit 1*/
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S		1  /* Activate spectral scan reg 68, bit 1*/
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD		0x000000F0  /* Interval for FFT reports, reg 68, bits 4-7*/
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S	4
+#define AR_PHY_SPECTRAL_SCAN_PERIOD		0x0000FF00  /* Interval for FFT reports, reg 68, bits 8-15*/
+#define AR_PHY_SPECTRAL_SCAN_PERIOD_S		8
+#define AR_PHY_SPECTRAL_SCAN_COUNT		0x00FF0000  /* Number of reports, reg 68, bits 16-23*/
+#define AR_PHY_SPECTRAL_SCAN_COUNT_S		16
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT	0x01000000  /* Short repeat, reg 68, bit 24*/
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S	24  /* Short repeat, reg 68, bit 24*/
+
+#define AR_PHY_RX_DELAY           0x9914
+#define AR_PHY_SEARCH_START_DELAY 0x9918
+#define AR_PHY_RX_DELAY_DELAY     0x00003FFF
+
+#define AR_PHY_TIMING_CTRL4(_i)     (0x9920 + ((_i) << 12))
+#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF 0x01F
+#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_S   0
+#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF 0x7E0
+#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S   5
+#define AR_PHY_TIMING_CTRL4_IQCORR_ENABLE   0x800
+#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX 0xF000
+#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S   12
+#define AR_PHY_TIMING_CTRL4_DO_CAL    0x10000
+
+#define AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI	0x80000000
+#define	AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER	0x40000000
+#define	AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK	0x20000000
+#define	AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK	0x10000000
+
+#define AR_PHY_TIMING5               0x9924
+#define AR_PHY_TIMING5_CYCPWR_THR1   0x000000FE
+#define AR_PHY_TIMING5_CYCPWR_THR1_S 1
+
+#define AR_PHY_POWER_TX_RATE1               0x9934
+#define AR_PHY_POWER_TX_RATE2               0x9938
+#define AR_PHY_POWER_TX_RATE_MAX            0x993c
+#define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040
+
+#define AR_PHY_FRAME_CTL            0x9944
+#define AR_PHY_FRAME_CTL_TX_CLIP    0x00000038
+#define AR_PHY_FRAME_CTL_TX_CLIP_S  3
+
+#define AR_PHY_TXPWRADJ                   0x994C
+#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA    0x00000FC0
+#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA_S  6
+#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX   0x00FC0000
+#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX_S 18
+
+#define AR_PHY_RADAR_EXT      0x9940
+#define AR_PHY_RADAR_EXT_ENA  0x00004000
+
+#define AR_PHY_RADAR_0          0x9954
+#define AR_PHY_RADAR_0_ENA      0x00000001
+#define AR_PHY_RADAR_0_FFT_ENA  0x80000000
+#define AR_PHY_RADAR_0_INBAND   0x0000003e
+#define AR_PHY_RADAR_0_INBAND_S 1
+#define AR_PHY_RADAR_0_PRSSI    0x00000FC0
+#define AR_PHY_RADAR_0_PRSSI_S  6
+#define AR_PHY_RADAR_0_HEIGHT   0x0003F000
+#define AR_PHY_RADAR_0_HEIGHT_S 12
+#define AR_PHY_RADAR_0_RRSSI    0x00FC0000
+#define AR_PHY_RADAR_0_RRSSI_S  18
+#define AR_PHY_RADAR_0_FIRPWR   0x7F000000
+#define AR_PHY_RADAR_0_FIRPWR_S 24
+
+#define AR_PHY_RADAR_1                  0x9958
+#define AR_PHY_RADAR_1_RELPWR_ENA       0x00800000
+#define AR_PHY_RADAR_1_USE_FIR128       0x00400000
+#define AR_PHY_RADAR_1_RELPWR_THRESH    0x003F0000
+#define AR_PHY_RADAR_1_RELPWR_THRESH_S  16
+#define AR_PHY_RADAR_1_BLOCK_CHECK      0x00008000
+#define AR_PHY_RADAR_1_MAX_RRSSI        0x00004000
+#define AR_PHY_RADAR_1_RELSTEP_CHECK    0x00002000
+#define AR_PHY_RADAR_1_RELSTEP_THRESH   0x00001F00
+#define AR_PHY_RADAR_1_RELSTEP_THRESH_S 8
+#define AR_PHY_RADAR_1_MAXLEN           0x000000FF
+#define AR_PHY_RADAR_1_MAXLEN_S         0
+
+#define AR_PHY_SWITCH_CHAIN_0     0x9960
+#define AR_PHY_SWITCH_COM         0x9964
+
+#define AR_PHY_SIGMA_DELTA            0x996C
+#define AR_PHY_SIGMA_DELTA_ADC_SEL    0x00000003
+#define AR_PHY_SIGMA_DELTA_ADC_SEL_S  0
+#define AR_PHY_SIGMA_DELTA_FILT2      0x000000F8
+#define AR_PHY_SIGMA_DELTA_FILT2_S    3
+#define AR_PHY_SIGMA_DELTA_FILT1      0x00001F00
+#define AR_PHY_SIGMA_DELTA_FILT1_S    8
+#define AR_PHY_SIGMA_DELTA_ADC_CLIP   0x01FFE000
+#define AR_PHY_SIGMA_DELTA_ADC_CLIP_S 13
+
+#define AR_PHY_RESTART          0x9970
+#define AR_PHY_RESTART_DIV_GC   0x001C0000
+#define AR_PHY_RESTART_DIV_GC_S 18
+
+#define AR_PHY_RFBUS_REQ        0x997C
+#define AR_PHY_RFBUS_REQ_EN     0x00000001
+
+#define	AR_PHY_TIMING7		        0x9980
+#define	AR_PHY_TIMING8		        0x9984
+#define	AR_PHY_TIMING8_PILOT_MASK_2	0x000FFFFF
+#define	AR_PHY_TIMING8_PILOT_MASK_2_S	0
+
+#define	AR_PHY_BIN_MASK2_1	0x9988
+#define	AR_PHY_BIN_MASK2_2	0x998c
+#define	AR_PHY_BIN_MASK2_3	0x9990
+#define	AR_PHY_BIN_MASK2_4	0x9994
+
+#define	AR_PHY_BIN_MASK_1	0x9900
+#define	AR_PHY_BIN_MASK_2	0x9904
+#define	AR_PHY_BIN_MASK_3	0x9908
+
+#define	AR_PHY_MASK_CTL		0x990c
+
+#define	AR_PHY_BIN_MASK2_4_MASK_4	0x00003FFF
+#define	AR_PHY_BIN_MASK2_4_MASK_4_S	0
+
+#define	AR_PHY_TIMING9		        0x9998
+#define	AR_PHY_TIMING10		        0x999c
+#define	AR_PHY_TIMING10_PILOT_MASK_2	0x000FFFFF
+#define	AR_PHY_TIMING10_PILOT_MASK_2_S	0
+
+#define	AR_PHY_TIMING11			        0x99a0
+#define	AR_PHY_TIMING11_SPUR_DELTA_PHASE	0x000FFFFF
+#define	AR_PHY_TIMING11_SPUR_DELTA_PHASE_S	0
+#define AR_PHY_TIMING11_USE_SPUR_IN_AGC		0x40000000
+#define AR_PHY_TIMING11_USE_SPUR_IN_SELFCOR	0x80000000
+
+#define AR_PHY_RX_CHAINMASK     0x99a4
+#define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12))
+#define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000
+#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000
+
+#define AR_PHY_MULTICHAIN_GAIN_CTL          0x99ac
+#define AR_PHY_9285_FAST_DIV_BIAS	    0x00007E00
+#define AR_PHY_9285_FAST_DIV_BIAS_S	    9
+#define AR_PHY_9285_ANT_DIV_CTL_ALL         0x7f000000
+#define AR_PHY_9285_ANT_DIV_CTL             0x01000000
+#define AR_PHY_9285_ANT_DIV_CTL_S           24
+#define AR_PHY_9285_ANT_DIV_ALT_LNACONF     0x06000000
+#define AR_PHY_9285_ANT_DIV_ALT_LNACONF_S   25
+#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF    0x18000000
+#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S  27
+#define AR_PHY_9285_ANT_DIV_ALT_GAINTB      0x20000000
+#define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S    29
+#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB     0x40000000
+#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S   30
+#define AR_PHY_9285_ANT_DIV_LNA1            2
+#define AR_PHY_9285_ANT_DIV_LNA2            1
+#define AR_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2  3
+#define AR_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0
+#define AR_PHY_9285_ANT_DIV_GAINTB_0        0
+#define AR_PHY_9285_ANT_DIV_GAINTB_1        1
+
+#define AR_PHY_EXT_CCA0             0x99b8
+#define AR_PHY_EXT_CCA0_THRESH62    0x000000FF
+#define AR_PHY_EXT_CCA0_THRESH62_S  0
+
+#define AR_PHY_EXT_CCA                  0x99bc
+#define AR_PHY_EXT_CCA_CYCPWR_THR1      0x0000FE00
+#define AR_PHY_EXT_CCA_CYCPWR_THR1_S    9
+#define AR_PHY_EXT_CCA_THRESH62         0x007F0000
+#define AR_PHY_EXT_CCA_THRESH62_S       16
+#define AR_PHY_EXT_TIMING5_CYCPWR_THR1   0x0000FE00L
+#define AR_PHY_EXT_TIMING5_CYCPWR_THR1_S 9
+
+#define AR_PHY_EXT_MINCCA_PWR           0xFF800000
+#define AR_PHY_EXT_MINCCA_PWR_S         23
+#define AR9280_PHY_EXT_MINCCA_PWR       0x01FF0000
+#define AR9280_PHY_EXT_MINCCA_PWR_S     16
+
+#define AR_PHY_SFCORR_EXT                 0x99c0
+#define AR_PHY_SFCORR_EXT_M1_THRESH       0x0000007F
+#define AR_PHY_SFCORR_EXT_M1_THRESH_S     0
+#define AR_PHY_SFCORR_EXT_M2_THRESH       0x00003F80
+#define AR_PHY_SFCORR_EXT_M2_THRESH_S     7
+#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW   0x001FC000
+#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14
+#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW   0x0FE00000
+#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21
+#define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S   28
+
+#define AR_PHY_HALFGI           0x99D0
+#define AR_PHY_HALFGI_DSC_MAN   0x0007FFF0
+#define AR_PHY_HALFGI_DSC_MAN_S 4
+#define AR_PHY_HALFGI_DSC_EXP   0x0000000F
+#define AR_PHY_HALFGI_DSC_EXP_S 0
+
+#define AR_PHY_CHAN_INFO_MEMORY               0x99DC
+#define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK  0x0001
+
+#define AR_PHY_HEAVY_CLIP_ENABLE         0x99E0
+
+#define AR_PHY_HEAVY_CLIP_FACTOR_RIFS    0x99EC
+#define AR_PHY_RIFS_INIT_DELAY         0x03ff0000
+
+#define AR_PHY_M_SLEEP      0x99f0
+#define AR_PHY_REFCLKDLY    0x99f4
+#define AR_PHY_REFCLKPD     0x99f8
+
+#define AR_PHY_CALMODE      0x99f0
+
+#define AR_PHY_CALMODE_IQ           0x00000000
+#define AR_PHY_CALMODE_ADC_GAIN     0x00000001
+#define AR_PHY_CALMODE_ADC_DC_PER   0x00000002
+#define AR_PHY_CALMODE_ADC_DC_INIT  0x00000003
+
+#define AR_PHY_CAL_MEAS_0(_i)     (0x9c10 + ((_i) << 12))
+#define AR_PHY_CAL_MEAS_1(_i)     (0x9c14 + ((_i) << 12))
+#define AR_PHY_CAL_MEAS_2(_i)     (0x9c18 + ((_i) << 12))
+#define AR_PHY_CAL_MEAS_3(_i)     (0x9c1c + ((_i) << 12))
+
+#define AR_PHY_CURRENT_RSSI 0x9c1c
+#define AR9280_PHY_CURRENT_RSSI 0x9c3c
+
+#define AR_PHY_RFBUS_GRANT       0x9C20
+#define AR_PHY_RFBUS_GRANT_EN    0x00000001
+
+#define AR_PHY_CHAN_INFO_GAIN_DIFF             0x9CF4
+#define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320
+
+#define AR_PHY_CHAN_INFO_GAIN          0x9CFC
+
+#define AR_PHY_MODE         0xA200
+#define AR_PHY_MODE_ASYNCFIFO 0x80
+#define AR_PHY_MODE_AR2133  0x08
+#define AR_PHY_MODE_AR5111  0x00
+#define AR_PHY_MODE_AR5112  0x08
+#define AR_PHY_MODE_DYNAMIC 0x04
+#define AR_PHY_MODE_RF2GHZ  0x02
+#define AR_PHY_MODE_RF5GHZ  0x00
+#define AR_PHY_MODE_CCK     0x01
+#define AR_PHY_MODE_OFDM    0x00
+#define AR_PHY_MODE_DYN_CCK_DISABLE 0x100
+
+#define AR_PHY_CCK_TX_CTRL       0xA204
+#define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010
+#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK         0x0000000C
+#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK_S       2
+
+#define AR_PHY_CCK_DETECT                           0xA208
+#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK          0x0000003F
+#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S        0
+/* [12:6] settling time for antenna switch */
+#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME           0x00001FC0
+#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S         6
+#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV    0x2000
+#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV_S  13
+
+#define AR_PHY_GAIN_2GHZ                0xA20C
+#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN    0x00FC0000
+#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN_S  18
+#define AR_PHY_GAIN_2GHZ_BSW_MARGIN     0x00003C00
+#define AR_PHY_GAIN_2GHZ_BSW_MARGIN_S   10
+#define AR_PHY_GAIN_2GHZ_BSW_ATTEN      0x0000001F
+#define AR_PHY_GAIN_2GHZ_BSW_ATTEN_S    0
+
+#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN     0x003E0000
+#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN_S   17
+#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN     0x0001F000
+#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN_S   12
+#define AR_PHY_GAIN_2GHZ_XATTEN2_DB         0x00000FC0
+#define AR_PHY_GAIN_2GHZ_XATTEN2_DB_S       6
+#define AR_PHY_GAIN_2GHZ_XATTEN1_DB         0x0000003F
+#define AR_PHY_GAIN_2GHZ_XATTEN1_DB_S       0
+
+#define AR_PHY_CCK_RXCTRL4  0xA21C
+#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT   0x01F80000
+#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT_S 19
+
+#define AR_PHY_DAG_CTRLCCK  0xA228
+#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR  0x00000200
+#define AR_PHY_DAG_CTRLCCK_RSSI_THR     0x0001FC00
+#define AR_PHY_DAG_CTRLCCK_RSSI_THR_S   10
+
+#define AR_PHY_FORCE_CLKEN_CCK              0xA22C
+#define AR_PHY_FORCE_CLKEN_CCK_MRC_MUX      0x00000040
+
+#define AR_PHY_POWER_TX_RATE3   0xA234
+#define AR_PHY_POWER_TX_RATE4   0xA238
+
+#define AR_PHY_SCRM_SEQ_XR       0xA23C
+#define AR_PHY_HEADER_DETECT_XR  0xA240
+#define AR_PHY_CHIRP_DETECTED_XR 0xA244
+#define AR_PHY_BLUETOOTH         0xA254
+
+#define AR_PHY_TPCRG1   0xA258
+#define AR_PHY_TPCRG1_NUM_PD_GAIN   0x0000c000
+#define AR_PHY_TPCRG1_NUM_PD_GAIN_S 14
+
+#define AR_PHY_TPCRG1_PD_GAIN_1    0x00030000
+#define AR_PHY_TPCRG1_PD_GAIN_1_S  16
+#define AR_PHY_TPCRG1_PD_GAIN_2    0x000C0000
+#define AR_PHY_TPCRG1_PD_GAIN_2_S  18
+#define AR_PHY_TPCRG1_PD_GAIN_3    0x00300000
+#define AR_PHY_TPCRG1_PD_GAIN_3_S  20
+
+#define AR_PHY_TPCRG1_PD_CAL_ENABLE   0x00400000
+#define AR_PHY_TPCRG1_PD_CAL_ENABLE_S 22
+
+#define AR_PHY_TX_PWRCTRL4       0xa264
+#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID     0x00000001
+#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID_S   0
+#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT       0x000001FE
+#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT_S     1
+
+#define AR_PHY_TX_PWRCTRL6_0     0xa270
+#define AR_PHY_TX_PWRCTRL6_1     0xb270
+#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE     0x03000000
+#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE_S   24
+
+#define AR_PHY_TX_PWRCTRL7       0xa274
+#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN     0x01F80000
+#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S   19
+
+#define AR_PHY_TX_PWRCTRL8       0xa278
+
+#define AR_PHY_TX_PWRCTRL9       0xa27C
+
+#define AR_PHY_TX_PWRCTRL10       0xa394
+#define AR_PHY_TX_DESIRED_SCALE_CCK        0x00007C00
+#define AR_PHY_TX_DESIRED_SCALE_CCK_S      10
+#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL  0x80000000
+#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL_S 31
+
+#define AR_PHY_TX_GAIN_TBL1      0xa300
+#define AR_PHY_TX_GAIN                     0x0007F000
+#define AR_PHY_TX_GAIN_S                   12
+
+#define AR_PHY_CH0_TX_PWRCTRL11  0xa398
+#define AR_PHY_CH1_TX_PWRCTRL11  0xb398
+#define AR_PHY_CH0_TX_PWRCTRL12  0xa3dc
+#define AR_PHY_CH0_TX_PWRCTRL13  0xa3e0
+#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP   0x0000FC00
+#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10
+
+#define AR_PHY_VIT_MASK2_M_46_61 0xa3a0
+#define AR_PHY_MASK2_M_31_45     0xa3a4
+#define AR_PHY_MASK2_M_16_30     0xa3a8
+#define AR_PHY_MASK2_M_00_15     0xa3ac
+#define AR_PHY_MASK2_P_15_01     0xa3b8
+#define AR_PHY_MASK2_P_30_16     0xa3bc
+#define AR_PHY_MASK2_P_45_31     0xa3c0
+#define AR_PHY_MASK2_P_61_45     0xa3c4
+#define AR_PHY_SPUR_REG          0x994c
+
+#define AR_PHY_SPUR_REG_MASK_RATE_CNTL       (0xFF << 18)
+#define AR_PHY_SPUR_REG_MASK_RATE_CNTL_S     18
+
+#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM      0x20000
+#define AR_PHY_SPUR_REG_MASK_RATE_SELECT     (0xFF << 9)
+#define AR_PHY_SPUR_REG_MASK_RATE_SELECT_S   9
+#define AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI 0x100
+#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH     0x7F
+#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH_S   0
+
+#define AR_PHY_PILOT_MASK_01_30   0xa3b0
+#define AR_PHY_PILOT_MASK_31_60   0xa3b4
+
+#define AR_PHY_CHANNEL_MASK_01_30 0x99d4
+#define AR_PHY_CHANNEL_MASK_31_60 0x99d8
+
+#define AR_PHY_ANALOG_SWAP      0xa268
+#define AR_PHY_SWAP_ALT_CHAIN   0x00000040
+
+#define AR_PHY_TPCRG5   0xA26C
+#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP       0x0000000F
+#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP_S     0
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1    0x000003F0
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1_S  4
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2    0x0000FC00
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2_S  10
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3    0x003F0000
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3_S  16
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4    0x0FC00000
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S  22
+
+/* Carrier leak calibration control, do it after AGC calibration */
+#define AR_PHY_CL_CAL_CTL       0xA358
+#define AR_PHY_CL_CAL_ENABLE    0x00000002
+#define AR_PHY_PARALLEL_CAL_ENABLE    0x00000001
+
+#define AR_PHY_POWER_TX_RATE5   0xA38C
+#define AR_PHY_POWER_TX_RATE6   0xA390
+
+#define AR_PHY_CAL_CHAINMASK    0xA39C
+
+#define AR_PHY_POWER_TX_SUB     0xA3C8
+#define AR_PHY_POWER_TX_RATE7   0xA3CC
+#define AR_PHY_POWER_TX_RATE8   0xA3D0
+#define AR_PHY_POWER_TX_RATE9   0xA3D4
+
+#define AR_PHY_XPA_CFG		0xA3D8
+#define AR_PHY_FORCE_XPA_CFG	0x000000001
+#define AR_PHY_FORCE_XPA_CFG_S	0
+
+#define AR_PHY_CH1_CCA          0xa864
+#define AR_PHY_CH1_MINCCA_PWR   0x0FF80000
+#define AR_PHY_CH1_MINCCA_PWR_S 19
+#define AR9280_PHY_CH1_MINCCA_PWR   0x1FF00000
+#define AR9280_PHY_CH1_MINCCA_PWR_S 20
+
+#define AR_PHY_CH2_CCA          0xb864
+#define AR_PHY_CH2_MINCCA_PWR   0x0FF80000
+#define AR_PHY_CH2_MINCCA_PWR_S 19
+
+#define AR_PHY_CH1_EXT_CCA          0xa9bc
+#define AR_PHY_CH1_EXT_MINCCA_PWR   0xFF800000
+#define AR_PHY_CH1_EXT_MINCCA_PWR_S 23
+#define AR9280_PHY_CH1_EXT_MINCCA_PWR   0x01FF0000
+#define AR9280_PHY_CH1_EXT_MINCCA_PWR_S 16
+
+#define AR_PHY_CH2_EXT_CCA          0xb9bc
+#define AR_PHY_CH2_EXT_MINCCA_PWR   0xFF800000
+#define AR_PHY_CH2_EXT_MINCCA_PWR_S 23
+
+#define AR_PHY_CCA_NOM_VAL_5416_2GHZ            -90
+#define AR_PHY_CCA_NOM_VAL_5416_5GHZ            -100
+#define AR_PHY_CCA_MIN_GOOD_VAL_5416_2GHZ     -100
+#define AR_PHY_CCA_MIN_GOOD_VAL_5416_5GHZ     -110
+#define AR_PHY_CCA_MAX_GOOD_VAL_5416_2GHZ     -80
+#define AR_PHY_CCA_MAX_GOOD_VAL_5416_5GHZ     -90
+
+#define AR_PHY_CCA_NOM_VAL_9280_2GHZ         -112
+#define AR_PHY_CCA_NOM_VAL_9280_5GHZ         -112
+#define AR_PHY_CCA_MIN_GOOD_VAL_9280_2GHZ  -127
+#define AR_PHY_CCA_MIN_GOOD_VAL_9280_5GHZ  -122
+#define AR_PHY_CCA_MAX_GOOD_VAL_9280_2GHZ  -97
+#define AR_PHY_CCA_MAX_GOOD_VAL_9280_5GHZ  -102
+
+#define AR_PHY_CCA_NOM_VAL_9285_2GHZ           -118
+#define AR_PHY_CCA_MIN_GOOD_VAL_9285_2GHZ    -127
+#define AR_PHY_CCA_MAX_GOOD_VAL_9285_2GHZ    -108
+
+#define AR_PHY_CCA_NOM_VAL_9271_2GHZ             -118
+#define AR_PHY_CCA_MIN_GOOD_VAL_9271_2GHZ      -127
+#define AR_PHY_CCA_MAX_GOOD_VAL_9271_2GHZ      -116
+
+#define AR_PHY_CCA_NOM_VAL_9287_2GHZ           -120
+#define AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ    -127
+#define AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ    -110
+
+#endif
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_2p2_initvals.h b/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_2p2_initvals.h
new file mode 100644
index 0000000000000000000000000000000000000000..e8ac70da5ac70d2ec0fc585c556017ce51b6b90e
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_2p2_initvals.h
@@ -0,0 +1,1864 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INITVALS_9003_2P2_H
+#define INITVALS_9003_2P2_H
+
+/* AR9003 2.2 */
+
+static const u32 ar9300_2p2_radio_postamble[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x0001609c, 0x0dd08f29, 0x0dd08f29, 0x0b283f31, 0x0b283f31},
+	{0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800},
+	{0x000160b0, 0x03284f3e, 0x03284f3e, 0x05d08f20, 0x05d08f20},
+	{0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+	{0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+	{0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+};
+
+static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
+	{0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+	{0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+	{0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
+	{0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
+	{0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
+	{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
+	{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
+	{0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
+	{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
+	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
+	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
+	{0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861},
+	{0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81},
+	{0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83},
+	{0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84},
+	{0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3},
+	{0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5},
+	{0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9},
+	{0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+	{0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+	{0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+	{0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+	{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+	{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+	{0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+	{0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+	{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+	{0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861},
+	{0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81},
+	{0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83},
+	{0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84},
+	{0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3},
+	{0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5},
+	{0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9},
+	{0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb},
+	{0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000},
+	{0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501},
+	{0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501},
+	{0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03},
+	{0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04},
+	{0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04},
+	{0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016448, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016848, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9300Modes_fast_clock_2p2[][3] = {
+	/* Addr      5G_HT20     5G_HT40   */
+	{0x00001030, 0x00000268, 0x000004d0},
+	{0x00001070, 0x0000018c, 0x00000318},
+	{0x000010b0, 0x00000fd0, 0x00001fa0},
+	{0x00008014, 0x044c044c, 0x08980898},
+	{0x0000801c, 0x148ec02b, 0x148ec057},
+	{0x00008318, 0x000044c0, 0x00008980},
+	{0x00009e00, 0x0372131c, 0x0372131c},
+	{0x0000a230, 0x0000000b, 0x00000016},
+	{0x0000a254, 0x00000898, 0x00001130},
+};
+
+static const u32 ar9300_2p2_radio_core[][2] = {
+	/* Addr      allmodes  */
+	{0x00016000, 0x36db6db6},
+	{0x00016004, 0x6db6db40},
+	{0x00016008, 0x73f00000},
+	{0x0001600c, 0x00000000},
+	{0x00016040, 0x7f80fff8},
+	{0x0001604c, 0x76d005b5},
+	{0x00016050, 0x556cf031},
+	{0x00016054, 0x13449440},
+	{0x00016058, 0x0c51c92c},
+	{0x0001605c, 0x3db7fffc},
+	{0x00016060, 0xfffffffc},
+	{0x00016064, 0x000f0278},
+	{0x0001606c, 0x6db60000},
+	{0x00016080, 0x00000000},
+	{0x00016084, 0x0e48048c},
+	{0x00016088, 0x54214514},
+	{0x0001608c, 0x119f481e},
+	{0x00016090, 0x24926490},
+	{0x00016098, 0xd2888888},
+	{0x000160a0, 0x0a108ffe},
+	{0x000160a4, 0x812fc370},
+	{0x000160a8, 0x423c8000},
+	{0x000160b4, 0x92480080},
+	{0x000160c0, 0x00adb6d0},
+	{0x000160c4, 0x6db6db60},
+	{0x000160c8, 0x6db6db6c},
+	{0x000160cc, 0x01e6c000},
+	{0x00016100, 0x3fffbe01},
+	{0x00016104, 0xfff80000},
+	{0x00016108, 0x00080010},
+	{0x00016144, 0x02084080},
+	{0x00016148, 0x00000000},
+	{0x00016280, 0x058a0001},
+	{0x00016284, 0x3d840208},
+	{0x00016288, 0x05a20408},
+	{0x0001628c, 0x00038c07},
+	{0x00016290, 0x00000004},
+	{0x00016294, 0x458aa14f},
+	{0x00016380, 0x00000000},
+	{0x00016384, 0x00000000},
+	{0x00016388, 0x00800700},
+	{0x0001638c, 0x00800700},
+	{0x00016390, 0x00800700},
+	{0x00016394, 0x00000000},
+	{0x00016398, 0x00000000},
+	{0x0001639c, 0x00000000},
+	{0x000163a0, 0x00000001},
+	{0x000163a4, 0x00000001},
+	{0x000163a8, 0x00000000},
+	{0x000163ac, 0x00000000},
+	{0x000163b0, 0x00000000},
+	{0x000163b4, 0x00000000},
+	{0x000163b8, 0x00000000},
+	{0x000163bc, 0x00000000},
+	{0x000163c0, 0x000000a0},
+	{0x000163c4, 0x000c0000},
+	{0x000163c8, 0x14021402},
+	{0x000163cc, 0x00001402},
+	{0x000163d0, 0x00000000},
+	{0x000163d4, 0x00000000},
+	{0x00016400, 0x36db6db6},
+	{0x00016404, 0x6db6db40},
+	{0x00016408, 0x73f00000},
+	{0x0001640c, 0x00000000},
+	{0x00016440, 0x7f80fff8},
+	{0x0001644c, 0x76d005b5},
+	{0x00016450, 0x556cf031},
+	{0x00016454, 0x13449440},
+	{0x00016458, 0x0c51c92c},
+	{0x0001645c, 0x3db7fffc},
+	{0x00016460, 0xfffffffc},
+	{0x00016464, 0x000f0278},
+	{0x0001646c, 0x6db60000},
+	{0x00016500, 0x3fffbe01},
+	{0x00016504, 0xfff80000},
+	{0x00016508, 0x00080010},
+	{0x00016544, 0x02084080},
+	{0x00016548, 0x00000000},
+	{0x00016780, 0x00000000},
+	{0x00016784, 0x00000000},
+	{0x00016788, 0x00800700},
+	{0x0001678c, 0x00800700},
+	{0x00016790, 0x00800700},
+	{0x00016794, 0x00000000},
+	{0x00016798, 0x00000000},
+	{0x0001679c, 0x00000000},
+	{0x000167a0, 0x00000001},
+	{0x000167a4, 0x00000001},
+	{0x000167a8, 0x00000000},
+	{0x000167ac, 0x00000000},
+	{0x000167b0, 0x00000000},
+	{0x000167b4, 0x00000000},
+	{0x000167b8, 0x00000000},
+	{0x000167bc, 0x00000000},
+	{0x000167c0, 0x000000a0},
+	{0x000167c4, 0x000c0000},
+	{0x000167c8, 0x14021402},
+	{0x000167cc, 0x00001402},
+	{0x000167d0, 0x00000000},
+	{0x000167d4, 0x00000000},
+	{0x00016800, 0x36db6db6},
+	{0x00016804, 0x6db6db40},
+	{0x00016808, 0x73f00000},
+	{0x0001680c, 0x00000000},
+	{0x00016840, 0x7f80fff8},
+	{0x0001684c, 0x76d005b5},
+	{0x00016850, 0x556cf031},
+	{0x00016854, 0x13449440},
+	{0x00016858, 0x0c51c92c},
+	{0x0001685c, 0x3db7fffc},
+	{0x00016860, 0xfffffffc},
+	{0x00016864, 0x000f0278},
+	{0x0001686c, 0x6db60000},
+	{0x00016900, 0x3fffbe01},
+	{0x00016904, 0xfff80000},
+	{0x00016908, 0x00080010},
+	{0x00016944, 0x02084080},
+	{0x00016948, 0x00000000},
+	{0x00016b80, 0x00000000},
+	{0x00016b84, 0x00000000},
+	{0x00016b88, 0x00800700},
+	{0x00016b8c, 0x00800700},
+	{0x00016b90, 0x00800700},
+	{0x00016b94, 0x00000000},
+	{0x00016b98, 0x00000000},
+	{0x00016b9c, 0x00000000},
+	{0x00016ba0, 0x00000001},
+	{0x00016ba4, 0x00000001},
+	{0x00016ba8, 0x00000000},
+	{0x00016bac, 0x00000000},
+	{0x00016bb0, 0x00000000},
+	{0x00016bb4, 0x00000000},
+	{0x00016bb8, 0x00000000},
+	{0x00016bbc, 0x00000000},
+	{0x00016bc0, 0x000000a0},
+	{0x00016bc4, 0x000c0000},
+	{0x00016bc8, 0x14021402},
+	{0x00016bcc, 0x00001402},
+	{0x00016bd0, 0x00000000},
+	{0x00016bd4, 0x00000000},
+};
+
+static const u32 ar9300Common_rx_gain_table_merlin_2p2[][2] = {
+	/* Addr      allmodes  */
+	{0x0000a000, 0x02000101},
+	{0x0000a004, 0x02000102},
+	{0x0000a008, 0x02000103},
+	{0x0000a00c, 0x02000104},
+	{0x0000a010, 0x02000200},
+	{0x0000a014, 0x02000201},
+	{0x0000a018, 0x02000202},
+	{0x0000a01c, 0x02000203},
+	{0x0000a020, 0x02000204},
+	{0x0000a024, 0x02000205},
+	{0x0000a028, 0x02000208},
+	{0x0000a02c, 0x02000302},
+	{0x0000a030, 0x02000303},
+	{0x0000a034, 0x02000304},
+	{0x0000a038, 0x02000400},
+	{0x0000a03c, 0x02010300},
+	{0x0000a040, 0x02010301},
+	{0x0000a044, 0x02010302},
+	{0x0000a048, 0x02000500},
+	{0x0000a04c, 0x02010400},
+	{0x0000a050, 0x02020300},
+	{0x0000a054, 0x02020301},
+	{0x0000a058, 0x02020302},
+	{0x0000a05c, 0x02020303},
+	{0x0000a060, 0x02020400},
+	{0x0000a064, 0x02030300},
+	{0x0000a068, 0x02030301},
+	{0x0000a06c, 0x02030302},
+	{0x0000a070, 0x02030303},
+	{0x0000a074, 0x02030400},
+	{0x0000a078, 0x02040300},
+	{0x0000a07c, 0x02040301},
+	{0x0000a080, 0x02040302},
+	{0x0000a084, 0x02040303},
+	{0x0000a088, 0x02030500},
+	{0x0000a08c, 0x02040400},
+	{0x0000a090, 0x02050203},
+	{0x0000a094, 0x02050204},
+	{0x0000a098, 0x02050205},
+	{0x0000a09c, 0x02040500},
+	{0x0000a0a0, 0x02050301},
+	{0x0000a0a4, 0x02050302},
+	{0x0000a0a8, 0x02050303},
+	{0x0000a0ac, 0x02050400},
+	{0x0000a0b0, 0x02050401},
+	{0x0000a0b4, 0x02050402},
+	{0x0000a0b8, 0x02050403},
+	{0x0000a0bc, 0x02050500},
+	{0x0000a0c0, 0x02050501},
+	{0x0000a0c4, 0x02050502},
+	{0x0000a0c8, 0x02050503},
+	{0x0000a0cc, 0x02050504},
+	{0x0000a0d0, 0x02050600},
+	{0x0000a0d4, 0x02050601},
+	{0x0000a0d8, 0x02050602},
+	{0x0000a0dc, 0x02050603},
+	{0x0000a0e0, 0x02050604},
+	{0x0000a0e4, 0x02050700},
+	{0x0000a0e8, 0x02050701},
+	{0x0000a0ec, 0x02050702},
+	{0x0000a0f0, 0x02050703},
+	{0x0000a0f4, 0x02050704},
+	{0x0000a0f8, 0x02050705},
+	{0x0000a0fc, 0x02050708},
+	{0x0000a100, 0x02050709},
+	{0x0000a104, 0x0205070a},
+	{0x0000a108, 0x0205070b},
+	{0x0000a10c, 0x0205070c},
+	{0x0000a110, 0x0205070d},
+	{0x0000a114, 0x02050710},
+	{0x0000a118, 0x02050711},
+	{0x0000a11c, 0x02050712},
+	{0x0000a120, 0x02050713},
+	{0x0000a124, 0x02050714},
+	{0x0000a128, 0x02050715},
+	{0x0000a12c, 0x02050730},
+	{0x0000a130, 0x02050731},
+	{0x0000a134, 0x02050732},
+	{0x0000a138, 0x02050733},
+	{0x0000a13c, 0x02050734},
+	{0x0000a140, 0x02050735},
+	{0x0000a144, 0x02050750},
+	{0x0000a148, 0x02050751},
+	{0x0000a14c, 0x02050752},
+	{0x0000a150, 0x02050753},
+	{0x0000a154, 0x02050754},
+	{0x0000a158, 0x02050755},
+	{0x0000a15c, 0x02050770},
+	{0x0000a160, 0x02050771},
+	{0x0000a164, 0x02050772},
+	{0x0000a168, 0x02050773},
+	{0x0000a16c, 0x02050774},
+	{0x0000a170, 0x02050775},
+	{0x0000a174, 0x00000776},
+	{0x0000a178, 0x00000776},
+	{0x0000a17c, 0x00000776},
+	{0x0000a180, 0x00000776},
+	{0x0000a184, 0x00000776},
+	{0x0000a188, 0x00000776},
+	{0x0000a18c, 0x00000776},
+	{0x0000a190, 0x00000776},
+	{0x0000a194, 0x00000776},
+	{0x0000a198, 0x00000776},
+	{0x0000a19c, 0x00000776},
+	{0x0000a1a0, 0x00000776},
+	{0x0000a1a4, 0x00000776},
+	{0x0000a1a8, 0x00000776},
+	{0x0000a1ac, 0x00000776},
+	{0x0000a1b0, 0x00000776},
+	{0x0000a1b4, 0x00000776},
+	{0x0000a1b8, 0x00000776},
+	{0x0000a1bc, 0x00000776},
+	{0x0000a1c0, 0x00000776},
+	{0x0000a1c4, 0x00000776},
+	{0x0000a1c8, 0x00000776},
+	{0x0000a1cc, 0x00000776},
+	{0x0000a1d0, 0x00000776},
+	{0x0000a1d4, 0x00000776},
+	{0x0000a1d8, 0x00000776},
+	{0x0000a1dc, 0x00000776},
+	{0x0000a1e0, 0x00000776},
+	{0x0000a1e4, 0x00000776},
+	{0x0000a1e8, 0x00000776},
+	{0x0000a1ec, 0x00000776},
+	{0x0000a1f0, 0x00000776},
+	{0x0000a1f4, 0x00000776},
+	{0x0000a1f8, 0x00000776},
+	{0x0000a1fc, 0x00000776},
+	{0x0000b000, 0x02000101},
+	{0x0000b004, 0x02000102},
+	{0x0000b008, 0x02000103},
+	{0x0000b00c, 0x02000104},
+	{0x0000b010, 0x02000200},
+	{0x0000b014, 0x02000201},
+	{0x0000b018, 0x02000202},
+	{0x0000b01c, 0x02000203},
+	{0x0000b020, 0x02000204},
+	{0x0000b024, 0x02000205},
+	{0x0000b028, 0x02000208},
+	{0x0000b02c, 0x02000302},
+	{0x0000b030, 0x02000303},
+	{0x0000b034, 0x02000304},
+	{0x0000b038, 0x02000400},
+	{0x0000b03c, 0x02010300},
+	{0x0000b040, 0x02010301},
+	{0x0000b044, 0x02010302},
+	{0x0000b048, 0x02000500},
+	{0x0000b04c, 0x02010400},
+	{0x0000b050, 0x02020300},
+	{0x0000b054, 0x02020301},
+	{0x0000b058, 0x02020302},
+	{0x0000b05c, 0x02020303},
+	{0x0000b060, 0x02020400},
+	{0x0000b064, 0x02030300},
+	{0x0000b068, 0x02030301},
+	{0x0000b06c, 0x02030302},
+	{0x0000b070, 0x02030303},
+	{0x0000b074, 0x02030400},
+	{0x0000b078, 0x02040300},
+	{0x0000b07c, 0x02040301},
+	{0x0000b080, 0x02040302},
+	{0x0000b084, 0x02040303},
+	{0x0000b088, 0x02030500},
+	{0x0000b08c, 0x02040400},
+	{0x0000b090, 0x02050203},
+	{0x0000b094, 0x02050204},
+	{0x0000b098, 0x02050205},
+	{0x0000b09c, 0x02040500},
+	{0x0000b0a0, 0x02050301},
+	{0x0000b0a4, 0x02050302},
+	{0x0000b0a8, 0x02050303},
+	{0x0000b0ac, 0x02050400},
+	{0x0000b0b0, 0x02050401},
+	{0x0000b0b4, 0x02050402},
+	{0x0000b0b8, 0x02050403},
+	{0x0000b0bc, 0x02050500},
+	{0x0000b0c0, 0x02050501},
+	{0x0000b0c4, 0x02050502},
+	{0x0000b0c8, 0x02050503},
+	{0x0000b0cc, 0x02050504},
+	{0x0000b0d0, 0x02050600},
+	{0x0000b0d4, 0x02050601},
+	{0x0000b0d8, 0x02050602},
+	{0x0000b0dc, 0x02050603},
+	{0x0000b0e0, 0x02050604},
+	{0x0000b0e4, 0x02050700},
+	{0x0000b0e8, 0x02050701},
+	{0x0000b0ec, 0x02050702},
+	{0x0000b0f0, 0x02050703},
+	{0x0000b0f4, 0x02050704},
+	{0x0000b0f8, 0x02050705},
+	{0x0000b0fc, 0x02050708},
+	{0x0000b100, 0x02050709},
+	{0x0000b104, 0x0205070a},
+	{0x0000b108, 0x0205070b},
+	{0x0000b10c, 0x0205070c},
+	{0x0000b110, 0x0205070d},
+	{0x0000b114, 0x02050710},
+	{0x0000b118, 0x02050711},
+	{0x0000b11c, 0x02050712},
+	{0x0000b120, 0x02050713},
+	{0x0000b124, 0x02050714},
+	{0x0000b128, 0x02050715},
+	{0x0000b12c, 0x02050730},
+	{0x0000b130, 0x02050731},
+	{0x0000b134, 0x02050732},
+	{0x0000b138, 0x02050733},
+	{0x0000b13c, 0x02050734},
+	{0x0000b140, 0x02050735},
+	{0x0000b144, 0x02050750},
+	{0x0000b148, 0x02050751},
+	{0x0000b14c, 0x02050752},
+	{0x0000b150, 0x02050753},
+	{0x0000b154, 0x02050754},
+	{0x0000b158, 0x02050755},
+	{0x0000b15c, 0x02050770},
+	{0x0000b160, 0x02050771},
+	{0x0000b164, 0x02050772},
+	{0x0000b168, 0x02050773},
+	{0x0000b16c, 0x02050774},
+	{0x0000b170, 0x02050775},
+	{0x0000b174, 0x00000776},
+	{0x0000b178, 0x00000776},
+	{0x0000b17c, 0x00000776},
+	{0x0000b180, 0x00000776},
+	{0x0000b184, 0x00000776},
+	{0x0000b188, 0x00000776},
+	{0x0000b18c, 0x00000776},
+	{0x0000b190, 0x00000776},
+	{0x0000b194, 0x00000776},
+	{0x0000b198, 0x00000776},
+	{0x0000b19c, 0x00000776},
+	{0x0000b1a0, 0x00000776},
+	{0x0000b1a4, 0x00000776},
+	{0x0000b1a8, 0x00000776},
+	{0x0000b1ac, 0x00000776},
+	{0x0000b1b0, 0x00000776},
+	{0x0000b1b4, 0x00000776},
+	{0x0000b1b8, 0x00000776},
+	{0x0000b1bc, 0x00000776},
+	{0x0000b1c0, 0x00000776},
+	{0x0000b1c4, 0x00000776},
+	{0x0000b1c8, 0x00000776},
+	{0x0000b1cc, 0x00000776},
+	{0x0000b1d0, 0x00000776},
+	{0x0000b1d4, 0x00000776},
+	{0x0000b1d8, 0x00000776},
+	{0x0000b1dc, 0x00000776},
+	{0x0000b1e0, 0x00000776},
+	{0x0000b1e4, 0x00000776},
+	{0x0000b1e8, 0x00000776},
+	{0x0000b1ec, 0x00000776},
+	{0x0000b1f0, 0x00000776},
+	{0x0000b1f4, 0x00000776},
+	{0x0000b1f8, 0x00000776},
+	{0x0000b1fc, 0x00000776},
+};
+
+static const u32 ar9300_2p2_mac_postamble[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
+	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
+	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
+	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
+	{0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
+	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
+	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
+	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
+};
+
+static const u32 ar9300_2p2_soc_postamble[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023},
+};
+
+static const u32 ar9200_merlin_2p2_radio_core[][2] = {
+	/* Addr      allmodes  */
+	{0x00007800, 0x00040000},
+	{0x00007804, 0xdb005012},
+	{0x00007808, 0x04924914},
+	{0x0000780c, 0x21084210},
+	{0x00007810, 0x6d801300},
+	{0x00007814, 0x0019beff},
+	{0x00007818, 0x07e41000},
+	{0x0000781c, 0x00392000},
+	{0x00007820, 0x92592480},
+	{0x00007824, 0x00040000},
+	{0x00007828, 0xdb005012},
+	{0x0000782c, 0x04924914},
+	{0x00007830, 0x21084210},
+	{0x00007834, 0x6d801300},
+	{0x00007838, 0x0019beff},
+	{0x0000783c, 0x07e40000},
+	{0x00007840, 0x00392000},
+	{0x00007844, 0x92592480},
+	{0x00007848, 0x00100000},
+	{0x0000784c, 0x773f0567},
+	{0x00007850, 0x54214514},
+	{0x00007854, 0x12035828},
+	{0x00007858, 0x92592692},
+	{0x0000785c, 0x00000000},
+	{0x00007860, 0x56400000},
+	{0x00007864, 0x0a8e370e},
+	{0x00007868, 0xc0102850},
+	{0x0000786c, 0x812d4000},
+	{0x00007870, 0x807ec400},
+	{0x00007874, 0x001b6db0},
+	{0x00007878, 0x00376b63},
+	{0x0000787c, 0x06db6db6},
+	{0x00007880, 0x006d8000},
+	{0x00007884, 0xffeffffe},
+	{0x00007888, 0xffeffffe},
+	{0x0000788c, 0x00010000},
+	{0x00007890, 0x02060aeb},
+	{0x00007894, 0x5a108000},
+};
+
+static const u32 ar9300_2p2_baseband_postamble[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
+	{0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
+	{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+	{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+	{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+	{0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
+	{0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
+	{0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
+	{0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
+	{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
+	{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
+	{0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e},
+	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
+	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+	{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
+	{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
+	{0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
+	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
+	{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+	{0x0000a204, 0x000037c0, 0x000037c4, 0x000037c4, 0x000037c0},
+	{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+	{0x0000a22c, 0x01026a2f, 0x01026a2f, 0x01026a2f, 0x01026a2f},
+	{0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+	{0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
+	{0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
+	{0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+	{0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+	{0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
+	{0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+	{0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
+	{0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
+	{0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+	{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
+	{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
+	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+	{0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982},
+	{0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a},
+	{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+	{0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000},
+	{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+	{0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+	{0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+	{0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+	{0x0000be04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000},
+	{0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+	{0x0000be20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+	{0x0000c284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+};
+
+static const u32 ar9300_2p2_baseband_core[][2] = {
+	/* Addr      allmodes  */
+	{0x00009800, 0xafe68e30},
+	{0x00009804, 0xfd14e000},
+	{0x00009808, 0x9c0a9f6b},
+	{0x0000980c, 0x04900000},
+	{0x00009814, 0x9280c00a},
+	{0x00009818, 0x00000000},
+	{0x0000981c, 0x00020028},
+	{0x00009834, 0x6400a290},
+	{0x00009838, 0x0108ecff},
+	{0x0000983c, 0x0d000600},
+	{0x00009880, 0x201fff00},
+	{0x00009884, 0x00001042},
+	{0x000098a4, 0x00200400},
+	{0x000098b0, 0x32840bbe},
+	{0x000098d0, 0x004b6a8e},
+	{0x000098d4, 0x00000820},
+	{0x000098dc, 0x00000000},
+	{0x000098f0, 0x00000000},
+	{0x000098f4, 0x00000000},
+	{0x00009c04, 0xff55ff55},
+	{0x00009c08, 0x0320ff55},
+	{0x00009c0c, 0x00000000},
+	{0x00009c10, 0x00000000},
+	{0x00009c14, 0x00046384},
+	{0x00009c18, 0x05b6b440},
+	{0x00009c1c, 0x00b6b440},
+	{0x00009d00, 0xc080a333},
+	{0x00009d04, 0x40206c10},
+	{0x00009d08, 0x009c4060},
+	{0x00009d0c, 0x9883800a},
+	{0x00009d10, 0x01834061},
+	{0x00009d14, 0x00c0040b},
+	{0x00009d18, 0x00000000},
+	{0x00009e08, 0x0038230c},
+	{0x00009e24, 0x990bb515},
+	{0x00009e28, 0x0c6f0000},
+	{0x00009e30, 0x06336f77},
+	{0x00009e34, 0x6af6532f},
+	{0x00009e38, 0x0cc80c00},
+	{0x00009e40, 0x0d261820},
+	{0x00009e4c, 0x00001004},
+	{0x00009e50, 0x00ff03f1},
+	{0x00009e54, 0x00000000},
+	{0x00009fc0, 0x803e4788},
+	{0x00009fc4, 0x0001efb5},
+	{0x00009fcc, 0x40000014},
+	{0x00009fd0, 0x01193b93},
+	{0x0000a20c, 0x00000000},
+	{0x0000a220, 0x00000000},
+	{0x0000a224, 0x00000000},
+	{0x0000a228, 0x10002310},
+	{0x0000a23c, 0x00000000},
+	{0x0000a244, 0x0c000000},
+	{0x0000a2a0, 0x00000001},
+	{0x0000a2c0, 0x00000001},
+	{0x0000a2c8, 0x00000000},
+	{0x0000a2cc, 0x18c43433},
+	{0x0000a2d4, 0x00000000},
+	{0x0000a2ec, 0x00000000},
+	{0x0000a2f0, 0x00000000},
+	{0x0000a2f4, 0x00000000},
+	{0x0000a2f8, 0x00000000},
+	{0x0000a344, 0x00000000},
+	{0x0000a34c, 0x00000000},
+	{0x0000a350, 0x0000a000},
+	{0x0000a364, 0x00000000},
+	{0x0000a370, 0x00000000},
+	{0x0000a390, 0x00000001},
+	{0x0000a394, 0x00000444},
+	{0x0000a398, 0x001f0e0f},
+	{0x0000a39c, 0x0075393f},
+	{0x0000a3a0, 0xb79f6427},
+	{0x0000a3a4, 0x00000000},
+	{0x0000a3a8, 0xaaaaaaaa},
+	{0x0000a3ac, 0x3c466478},
+	{0x0000a3c0, 0x20202020},
+	{0x0000a3c4, 0x22222220},
+	{0x0000a3c8, 0x20200020},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3d8, 0x20202020},
+	{0x0000a3dc, 0x20202020},
+	{0x0000a3e0, 0x20202020},
+	{0x0000a3e4, 0x20202020},
+	{0x0000a3e8, 0x20202020},
+	{0x0000a3ec, 0x20202020},
+	{0x0000a3f0, 0x00000000},
+	{0x0000a3f4, 0x00000246},
+	{0x0000a3f8, 0x0cdbd380},
+	{0x0000a3fc, 0x000f0f01},
+	{0x0000a400, 0x8fa91f01},
+	{0x0000a404, 0x00000000},
+	{0x0000a408, 0x0e79e5c6},
+	{0x0000a40c, 0x00820820},
+	{0x0000a414, 0x1ce739ce},
+	{0x0000a418, 0x2d001dce},
+	{0x0000a41c, 0x1ce739ce},
+	{0x0000a420, 0x000001ce},
+	{0x0000a424, 0x1ce739ce},
+	{0x0000a428, 0x000001ce},
+	{0x0000a42c, 0x1ce739ce},
+	{0x0000a430, 0x1ce739ce},
+	{0x0000a434, 0x00000000},
+	{0x0000a438, 0x00001801},
+	{0x0000a43c, 0x00100000},
+	{0x0000a440, 0x00000000},
+	{0x0000a444, 0x00000000},
+	{0x0000a448, 0x06000080},
+	{0x0000a44c, 0x00000001},
+	{0x0000a450, 0x00010000},
+	{0x0000a458, 0x00000000},
+	{0x0000a640, 0x00000000},
+	{0x0000a644, 0x3fad9d74},
+	{0x0000a648, 0x0048060a},
+	{0x0000a64c, 0x00003c37},
+	{0x0000a670, 0x03020100},
+	{0x0000a674, 0x09080504},
+	{0x0000a678, 0x0d0c0b0a},
+	{0x0000a67c, 0x13121110},
+	{0x0000a680, 0x31301514},
+	{0x0000a684, 0x35343332},
+	{0x0000a688, 0x00000036},
+	{0x0000a690, 0x00000838},
+	{0x0000a7c0, 0x00000000},
+	{0x0000a7c4, 0xfffffffc},
+	{0x0000a7c8, 0x00000000},
+	{0x0000a7cc, 0x00000000},
+	{0x0000a7d0, 0x00000000},
+	{0x0000a7d4, 0x00000004},
+	{0x0000a7dc, 0x00000001},
+	{0x0000a8d0, 0x004b6a8e},
+	{0x0000a8d4, 0x00000820},
+	{0x0000a8dc, 0x00000000},
+	{0x0000a8f0, 0x00000000},
+	{0x0000a8f4, 0x00000000},
+	{0x0000b2d0, 0x00000080},
+	{0x0000b2d4, 0x00000000},
+	{0x0000b2ec, 0x00000000},
+	{0x0000b2f0, 0x00000000},
+	{0x0000b2f4, 0x00000000},
+	{0x0000b2f8, 0x00000000},
+	{0x0000b408, 0x0e79e5c0},
+	{0x0000b40c, 0x00820820},
+	{0x0000b420, 0x00000000},
+	{0x0000b8d0, 0x004b6a8e},
+	{0x0000b8d4, 0x00000820},
+	{0x0000b8dc, 0x00000000},
+	{0x0000b8f0, 0x00000000},
+	{0x0000b8f4, 0x00000000},
+	{0x0000c2d0, 0x00000080},
+	{0x0000c2d4, 0x00000000},
+	{0x0000c2ec, 0x00000000},
+	{0x0000c2f0, 0x00000000},
+	{0x0000c2f4, 0x00000000},
+	{0x0000c2f8, 0x00000000},
+	{0x0000c408, 0x0e79e5c0},
+	{0x0000c40c, 0x00820820},
+	{0x0000c420, 0x00000000},
+};
+
+static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
+	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
+	{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
+	{0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
+	{0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
+	{0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
+	{0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
+	{0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
+	{0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
+	{0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
+	{0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
+	{0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
+	{0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
+	{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
+	{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
+	{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
+	{0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
+	{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
+	{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
+	{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
+	{0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
+	{0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
+	{0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
+	{0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
+	{0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
+	{0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
+	{0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
+	{0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
+	{0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
+	{0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
+	{0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
+	{0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
+	{0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
+	{0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
+	{0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
+	{0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
+	{0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
+	{0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
+	{0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
+	{0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
+	{0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
+	{0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
+	{0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
+	{0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
+	{0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
+	{0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
+	{0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
+	{0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
+	{0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
+	{0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
+	{0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+	{0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+	{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+	{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+	{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+	{0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
+	{0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
+	{0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
+	{0x00016444, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
+	{0x00016448, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
+	{0x00016468, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
+	{0x00016844, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
+	{0x00016848, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
+	{0x00016868, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
+};
+
+static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
+	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
+	{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
+	{0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
+	{0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
+	{0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
+	{0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
+	{0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
+	{0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
+	{0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
+	{0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
+	{0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
+	{0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
+	{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
+	{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
+	{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
+	{0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
+	{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
+	{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
+	{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
+	{0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
+	{0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
+	{0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
+	{0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
+	{0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
+	{0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
+	{0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
+	{0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
+	{0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
+	{0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
+	{0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
+	{0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
+	{0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
+	{0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
+	{0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
+	{0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
+	{0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
+	{0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
+	{0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
+	{0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
+	{0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
+	{0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
+	{0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
+	{0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000},
+	{0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000},
+	{0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501},
+	{0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501},
+	{0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03},
+	{0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04},
+	{0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04},
+	{0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+	{0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+	{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+	{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+	{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
+	{0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+	{0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016444, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+	{0x00016448, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016844, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+	{0x00016848, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
+	/* Addr      allmodes  */
+	{0x0000a000, 0x00010000},
+	{0x0000a004, 0x00030002},
+	{0x0000a008, 0x00050004},
+	{0x0000a00c, 0x00810080},
+	{0x0000a010, 0x00830082},
+	{0x0000a014, 0x01810180},
+	{0x0000a018, 0x01830182},
+	{0x0000a01c, 0x01850184},
+	{0x0000a020, 0x01890188},
+	{0x0000a024, 0x018b018a},
+	{0x0000a028, 0x018d018c},
+	{0x0000a02c, 0x01910190},
+	{0x0000a030, 0x01930192},
+	{0x0000a034, 0x01950194},
+	{0x0000a038, 0x038a0196},
+	{0x0000a03c, 0x038c038b},
+	{0x0000a040, 0x0390038d},
+	{0x0000a044, 0x03920391},
+	{0x0000a048, 0x03940393},
+	{0x0000a04c, 0x03960395},
+	{0x0000a050, 0x00000000},
+	{0x0000a054, 0x00000000},
+	{0x0000a058, 0x00000000},
+	{0x0000a05c, 0x00000000},
+	{0x0000a060, 0x00000000},
+	{0x0000a064, 0x00000000},
+	{0x0000a068, 0x00000000},
+	{0x0000a06c, 0x00000000},
+	{0x0000a070, 0x00000000},
+	{0x0000a074, 0x00000000},
+	{0x0000a078, 0x00000000},
+	{0x0000a07c, 0x00000000},
+	{0x0000a080, 0x22222229},
+	{0x0000a084, 0x1d1d1d1d},
+	{0x0000a088, 0x1d1d1d1d},
+	{0x0000a08c, 0x1d1d1d1d},
+	{0x0000a090, 0x171d1d1d},
+	{0x0000a094, 0x11111717},
+	{0x0000a098, 0x00030311},
+	{0x0000a09c, 0x00000000},
+	{0x0000a0a0, 0x00000000},
+	{0x0000a0a4, 0x00000000},
+	{0x0000a0a8, 0x00000000},
+	{0x0000a0ac, 0x00000000},
+	{0x0000a0b0, 0x00000000},
+	{0x0000a0b4, 0x00000000},
+	{0x0000a0b8, 0x00000000},
+	{0x0000a0bc, 0x00000000},
+	{0x0000a0c0, 0x001f0000},
+	{0x0000a0c4, 0x01000101},
+	{0x0000a0c8, 0x011e011f},
+	{0x0000a0cc, 0x011c011d},
+	{0x0000a0d0, 0x02030204},
+	{0x0000a0d4, 0x02010202},
+	{0x0000a0d8, 0x021f0200},
+	{0x0000a0dc, 0x0302021e},
+	{0x0000a0e0, 0x03000301},
+	{0x0000a0e4, 0x031e031f},
+	{0x0000a0e8, 0x0402031d},
+	{0x0000a0ec, 0x04000401},
+	{0x0000a0f0, 0x041e041f},
+	{0x0000a0f4, 0x0502041d},
+	{0x0000a0f8, 0x05000501},
+	{0x0000a0fc, 0x051e051f},
+	{0x0000a100, 0x06010602},
+	{0x0000a104, 0x061f0600},
+	{0x0000a108, 0x061d061e},
+	{0x0000a10c, 0x07020703},
+	{0x0000a110, 0x07000701},
+	{0x0000a114, 0x00000000},
+	{0x0000a118, 0x00000000},
+	{0x0000a11c, 0x00000000},
+	{0x0000a120, 0x00000000},
+	{0x0000a124, 0x00000000},
+	{0x0000a128, 0x00000000},
+	{0x0000a12c, 0x00000000},
+	{0x0000a130, 0x00000000},
+	{0x0000a134, 0x00000000},
+	{0x0000a138, 0x00000000},
+	{0x0000a13c, 0x00000000},
+	{0x0000a140, 0x001f0000},
+	{0x0000a144, 0x01000101},
+	{0x0000a148, 0x011e011f},
+	{0x0000a14c, 0x011c011d},
+	{0x0000a150, 0x02030204},
+	{0x0000a154, 0x02010202},
+	{0x0000a158, 0x021f0200},
+	{0x0000a15c, 0x0302021e},
+	{0x0000a160, 0x03000301},
+	{0x0000a164, 0x031e031f},
+	{0x0000a168, 0x0402031d},
+	{0x0000a16c, 0x04000401},
+	{0x0000a170, 0x041e041f},
+	{0x0000a174, 0x0502041d},
+	{0x0000a178, 0x05000501},
+	{0x0000a17c, 0x051e051f},
+	{0x0000a180, 0x06010602},
+	{0x0000a184, 0x061f0600},
+	{0x0000a188, 0x061d061e},
+	{0x0000a18c, 0x07020703},
+	{0x0000a190, 0x07000701},
+	{0x0000a194, 0x00000000},
+	{0x0000a198, 0x00000000},
+	{0x0000a19c, 0x00000000},
+	{0x0000a1a0, 0x00000000},
+	{0x0000a1a4, 0x00000000},
+	{0x0000a1a8, 0x00000000},
+	{0x0000a1ac, 0x00000000},
+	{0x0000a1b0, 0x00000000},
+	{0x0000a1b4, 0x00000000},
+	{0x0000a1b8, 0x00000000},
+	{0x0000a1bc, 0x00000000},
+	{0x0000a1c0, 0x00000000},
+	{0x0000a1c4, 0x00000000},
+	{0x0000a1c8, 0x00000000},
+	{0x0000a1cc, 0x00000000},
+	{0x0000a1d0, 0x00000000},
+	{0x0000a1d4, 0x00000000},
+	{0x0000a1d8, 0x00000000},
+	{0x0000a1dc, 0x00000000},
+	{0x0000a1e0, 0x00000000},
+	{0x0000a1e4, 0x00000000},
+	{0x0000a1e8, 0x00000000},
+	{0x0000a1ec, 0x00000000},
+	{0x0000a1f0, 0x00000396},
+	{0x0000a1f4, 0x00000396},
+	{0x0000a1f8, 0x00000396},
+	{0x0000a1fc, 0x00000196},
+	{0x0000b000, 0x00010000},
+	{0x0000b004, 0x00030002},
+	{0x0000b008, 0x00050004},
+	{0x0000b00c, 0x00810080},
+	{0x0000b010, 0x00830082},
+	{0x0000b014, 0x01810180},
+	{0x0000b018, 0x01830182},
+	{0x0000b01c, 0x01850184},
+	{0x0000b020, 0x02810280},
+	{0x0000b024, 0x02830282},
+	{0x0000b028, 0x02850284},
+	{0x0000b02c, 0x02890288},
+	{0x0000b030, 0x028b028a},
+	{0x0000b034, 0x0388028c},
+	{0x0000b038, 0x038a0389},
+	{0x0000b03c, 0x038c038b},
+	{0x0000b040, 0x0390038d},
+	{0x0000b044, 0x03920391},
+	{0x0000b048, 0x03940393},
+	{0x0000b04c, 0x03960395},
+	{0x0000b050, 0x00000000},
+	{0x0000b054, 0x00000000},
+	{0x0000b058, 0x00000000},
+	{0x0000b05c, 0x00000000},
+	{0x0000b060, 0x00000000},
+	{0x0000b064, 0x00000000},
+	{0x0000b068, 0x00000000},
+	{0x0000b06c, 0x00000000},
+	{0x0000b070, 0x00000000},
+	{0x0000b074, 0x00000000},
+	{0x0000b078, 0x00000000},
+	{0x0000b07c, 0x00000000},
+	{0x0000b080, 0x2a2d2f32},
+	{0x0000b084, 0x21232328},
+	{0x0000b088, 0x19191c1e},
+	{0x0000b08c, 0x12141417},
+	{0x0000b090, 0x07070e0e},
+	{0x0000b094, 0x03030305},
+	{0x0000b098, 0x00000003},
+	{0x0000b09c, 0x00000000},
+	{0x0000b0a0, 0x00000000},
+	{0x0000b0a4, 0x00000000},
+	{0x0000b0a8, 0x00000000},
+	{0x0000b0ac, 0x00000000},
+	{0x0000b0b0, 0x00000000},
+	{0x0000b0b4, 0x00000000},
+	{0x0000b0b8, 0x00000000},
+	{0x0000b0bc, 0x00000000},
+	{0x0000b0c0, 0x003f0020},
+	{0x0000b0c4, 0x00400041},
+	{0x0000b0c8, 0x0140005f},
+	{0x0000b0cc, 0x0160015f},
+	{0x0000b0d0, 0x017e017f},
+	{0x0000b0d4, 0x02410242},
+	{0x0000b0d8, 0x025f0240},
+	{0x0000b0dc, 0x027f0260},
+	{0x0000b0e0, 0x0341027e},
+	{0x0000b0e4, 0x035f0340},
+	{0x0000b0e8, 0x037f0360},
+	{0x0000b0ec, 0x04400441},
+	{0x0000b0f0, 0x0460045f},
+	{0x0000b0f4, 0x0541047f},
+	{0x0000b0f8, 0x055f0540},
+	{0x0000b0fc, 0x057f0560},
+	{0x0000b100, 0x06400641},
+	{0x0000b104, 0x0660065f},
+	{0x0000b108, 0x067e067f},
+	{0x0000b10c, 0x07410742},
+	{0x0000b110, 0x075f0740},
+	{0x0000b114, 0x077f0760},
+	{0x0000b118, 0x07800781},
+	{0x0000b11c, 0x07a0079f},
+	{0x0000b120, 0x07c107bf},
+	{0x0000b124, 0x000007c0},
+	{0x0000b128, 0x00000000},
+	{0x0000b12c, 0x00000000},
+	{0x0000b130, 0x00000000},
+	{0x0000b134, 0x00000000},
+	{0x0000b138, 0x00000000},
+	{0x0000b13c, 0x00000000},
+	{0x0000b140, 0x003f0020},
+	{0x0000b144, 0x00400041},
+	{0x0000b148, 0x0140005f},
+	{0x0000b14c, 0x0160015f},
+	{0x0000b150, 0x017e017f},
+	{0x0000b154, 0x02410242},
+	{0x0000b158, 0x025f0240},
+	{0x0000b15c, 0x027f0260},
+	{0x0000b160, 0x0341027e},
+	{0x0000b164, 0x035f0340},
+	{0x0000b168, 0x037f0360},
+	{0x0000b16c, 0x04400441},
+	{0x0000b170, 0x0460045f},
+	{0x0000b174, 0x0541047f},
+	{0x0000b178, 0x055f0540},
+	{0x0000b17c, 0x057f0560},
+	{0x0000b180, 0x06400641},
+	{0x0000b184, 0x0660065f},
+	{0x0000b188, 0x067e067f},
+	{0x0000b18c, 0x07410742},
+	{0x0000b190, 0x075f0740},
+	{0x0000b194, 0x077f0760},
+	{0x0000b198, 0x07800781},
+	{0x0000b19c, 0x07a0079f},
+	{0x0000b1a0, 0x07c107bf},
+	{0x0000b1a4, 0x000007c0},
+	{0x0000b1a8, 0x00000000},
+	{0x0000b1ac, 0x00000000},
+	{0x0000b1b0, 0x00000000},
+	{0x0000b1b4, 0x00000000},
+	{0x0000b1b8, 0x00000000},
+	{0x0000b1bc, 0x00000000},
+	{0x0000b1c0, 0x00000000},
+	{0x0000b1c4, 0x00000000},
+	{0x0000b1c8, 0x00000000},
+	{0x0000b1cc, 0x00000000},
+	{0x0000b1d0, 0x00000000},
+	{0x0000b1d4, 0x00000000},
+	{0x0000b1d8, 0x00000000},
+	{0x0000b1dc, 0x00000000},
+	{0x0000b1e0, 0x00000000},
+	{0x0000b1e4, 0x00000000},
+	{0x0000b1e8, 0x00000000},
+	{0x0000b1ec, 0x00000000},
+	{0x0000b1f0, 0x00000396},
+	{0x0000b1f4, 0x00000396},
+	{0x0000b1f8, 0x00000396},
+	{0x0000b1fc, 0x00000196},
+};
+
+static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
+	/* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+	{0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+	{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
+	{0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+	{0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+	{0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
+	{0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
+	{0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
+	{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
+	{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
+	{0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
+	{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
+	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
+	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
+	{0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861},
+	{0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81},
+	{0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83},
+	{0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84},
+	{0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3},
+	{0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5},
+	{0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9},
+	{0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+	{0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+	{0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+	{0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+	{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+	{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+	{0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+	{0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+	{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+	{0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861},
+	{0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81},
+	{0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83},
+	{0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84},
+	{0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3},
+	{0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5},
+	{0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9},
+	{0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb},
+	{0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+	{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000},
+	{0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501},
+	{0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501},
+	{0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03},
+	{0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04},
+	{0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04},
+	{0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+	{0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+	{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+	{0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+	{0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+	{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+	{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+	{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+	{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+	{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+	{0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+	{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9300_2p2_mac_core[][2] = {
+	/* Addr      allmodes  */
+	{0x00000008, 0x00000000},
+	{0x00000030, 0x00020085},
+	{0x00000034, 0x00000005},
+	{0x00000040, 0x00000000},
+	{0x00000044, 0x00000000},
+	{0x00000048, 0x00000008},
+	{0x0000004c, 0x00000010},
+	{0x00000050, 0x00000000},
+	{0x00001040, 0x002ffc0f},
+	{0x00001044, 0x002ffc0f},
+	{0x00001048, 0x002ffc0f},
+	{0x0000104c, 0x002ffc0f},
+	{0x00001050, 0x002ffc0f},
+	{0x00001054, 0x002ffc0f},
+	{0x00001058, 0x002ffc0f},
+	{0x0000105c, 0x002ffc0f},
+	{0x00001060, 0x002ffc0f},
+	{0x00001064, 0x002ffc0f},
+	{0x000010f0, 0x00000100},
+	{0x00001270, 0x00000000},
+	{0x000012b0, 0x00000000},
+	{0x000012f0, 0x00000000},
+	{0x0000143c, 0x00000000},
+	{0x0000147c, 0x00000000},
+	{0x00008000, 0x00000000},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000000},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008040, 0x00000000},
+	{0x00008044, 0x00000000},
+	{0x00008048, 0x00000000},
+	{0x0000804c, 0xffffffff},
+	{0x00008054, 0x00000000},
+	{0x00008058, 0x00000000},
+	{0x0000805c, 0x000fc78f},
+	{0x00008060, 0x0000000f},
+	{0x00008064, 0x00000000},
+	{0x00008070, 0x00000310},
+	{0x00008074, 0x00000020},
+	{0x00008078, 0x00000000},
+	{0x0000809c, 0x0000000f},
+	{0x000080a0, 0x00000000},
+	{0x000080a4, 0x02ff0000},
+	{0x000080a8, 0x0e070605},
+	{0x000080ac, 0x0000000d},
+	{0x000080b0, 0x00000000},
+	{0x000080b4, 0x00000000},
+	{0x000080b8, 0x00000000},
+	{0x000080bc, 0x00000000},
+	{0x000080c0, 0x2a800000},
+	{0x000080c4, 0x06900168},
+	{0x000080c8, 0x13881c20},
+	{0x000080cc, 0x01f40000},
+	{0x000080d0, 0x00252500},
+	{0x000080d4, 0x00a00000},
+	{0x000080d8, 0x00400000},
+	{0x000080dc, 0x00000000},
+	{0x000080e0, 0xffffffff},
+	{0x000080e4, 0x0000ffff},
+	{0x000080e8, 0x3f3f3f3f},
+	{0x000080ec, 0x00000000},
+	{0x000080f0, 0x00000000},
+	{0x000080f4, 0x00000000},
+	{0x000080fc, 0x00020000},
+	{0x00008100, 0x00000000},
+	{0x00008108, 0x00000052},
+	{0x0000810c, 0x00000000},
+	{0x00008110, 0x00000000},
+	{0x00008114, 0x000007ff},
+	{0x00008118, 0x000000aa},
+	{0x0000811c, 0x00003210},
+	{0x00008124, 0x00000000},
+	{0x00008128, 0x00000000},
+	{0x0000812c, 0x00000000},
+	{0x00008130, 0x00000000},
+	{0x00008134, 0x00000000},
+	{0x00008138, 0x00000000},
+	{0x0000813c, 0x0000ffff},
+	{0x00008144, 0xffffffff},
+	{0x00008168, 0x00000000},
+	{0x0000816c, 0x00000000},
+	{0x000081c0, 0x00000000},
+	{0x000081c4, 0x33332210},
+	{0x000081c8, 0x00000000},
+	{0x000081cc, 0x00000000},
+	{0x000081ec, 0x00000000},
+	{0x000081f0, 0x00000000},
+	{0x000081f4, 0x00000000},
+	{0x000081f8, 0x00000000},
+	{0x000081fc, 0x00000000},
+	{0x00008240, 0x00100000},
+	{0x00008244, 0x0010f424},
+	{0x00008248, 0x00000800},
+	{0x0000824c, 0x0001e848},
+	{0x00008250, 0x00000000},
+	{0x00008254, 0x00000000},
+	{0x00008258, 0x00000000},
+	{0x0000825c, 0x40000000},
+	{0x00008260, 0x00080922},
+	{0x00008264, 0x9bc00010},
+	{0x00008268, 0xffffffff},
+	{0x0000826c, 0x0000ffff},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000004},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x000000ff},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x0000829c, 0x00000000},
+	{0x00008300, 0x00000140},
+	{0x00008314, 0x00000000},
+	{0x0000831c, 0x0000010d},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000007},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000700},
+	{0x00008338, 0x00ff0000},
+	{0x0000833c, 0x02400000},
+	{0x00008340, 0x000107ff},
+	{0x00008344, 0xaa48105b},
+	{0x00008348, 0x008f0000},
+	{0x0000835c, 0x00000000},
+	{0x00008360, 0xffffffff},
+	{0x00008364, 0xffffffff},
+	{0x00008368, 0x00000000},
+	{0x00008370, 0x00000000},
+	{0x00008374, 0x000000ff},
+	{0x00008378, 0x00000000},
+	{0x0000837c, 0x00000000},
+	{0x00008380, 0xffffffff},
+	{0x00008384, 0xffffffff},
+	{0x00008390, 0xffffffff},
+	{0x00008394, 0xffffffff},
+	{0x00008398, 0x00000000},
+	{0x0000839c, 0x00000000},
+	{0x000083a0, 0x00000000},
+	{0x000083a4, 0x0000fa14},
+	{0x000083a8, 0x000f0c00},
+	{0x000083ac, 0x33332210},
+	{0x000083b0, 0x33332210},
+	{0x000083b4, 0x33332210},
+	{0x000083b8, 0x33332210},
+	{0x000083bc, 0x00000000},
+	{0x000083c0, 0x00000000},
+	{0x000083c4, 0x00000000},
+	{0x000083c8, 0x00000000},
+	{0x000083cc, 0x00000200},
+	{0x000083d0, 0x000301ff},
+};
+
+static const u32 ar9300Common_wo_xlna_rx_gain_table_2p2[][2] = {
+	/* Addr      allmodes  */
+	{0x0000a000, 0x00010000},
+	{0x0000a004, 0x00030002},
+	{0x0000a008, 0x00050004},
+	{0x0000a00c, 0x00810080},
+	{0x0000a010, 0x00830082},
+	{0x0000a014, 0x01810180},
+	{0x0000a018, 0x01830182},
+	{0x0000a01c, 0x01850184},
+	{0x0000a020, 0x01890188},
+	{0x0000a024, 0x018b018a},
+	{0x0000a028, 0x018d018c},
+	{0x0000a02c, 0x03820190},
+	{0x0000a030, 0x03840383},
+	{0x0000a034, 0x03880385},
+	{0x0000a038, 0x038a0389},
+	{0x0000a03c, 0x038c038b},
+	{0x0000a040, 0x0390038d},
+	{0x0000a044, 0x03920391},
+	{0x0000a048, 0x03940393},
+	{0x0000a04c, 0x03960395},
+	{0x0000a050, 0x00000000},
+	{0x0000a054, 0x00000000},
+	{0x0000a058, 0x00000000},
+	{0x0000a05c, 0x00000000},
+	{0x0000a060, 0x00000000},
+	{0x0000a064, 0x00000000},
+	{0x0000a068, 0x00000000},
+	{0x0000a06c, 0x00000000},
+	{0x0000a070, 0x00000000},
+	{0x0000a074, 0x00000000},
+	{0x0000a078, 0x00000000},
+	{0x0000a07c, 0x00000000},
+	{0x0000a080, 0x29292929},
+	{0x0000a084, 0x29292929},
+	{0x0000a088, 0x29292929},
+	{0x0000a08c, 0x29292929},
+	{0x0000a090, 0x22292929},
+	{0x0000a094, 0x1d1d2222},
+	{0x0000a098, 0x0c111117},
+	{0x0000a09c, 0x00030303},
+	{0x0000a0a0, 0x00000000},
+	{0x0000a0a4, 0x00000000},
+	{0x0000a0a8, 0x00000000},
+	{0x0000a0ac, 0x00000000},
+	{0x0000a0b0, 0x00000000},
+	{0x0000a0b4, 0x00000000},
+	{0x0000a0b8, 0x00000000},
+	{0x0000a0bc, 0x00000000},
+	{0x0000a0c0, 0x001f0000},
+	{0x0000a0c4, 0x01000101},
+	{0x0000a0c8, 0x011e011f},
+	{0x0000a0cc, 0x011c011d},
+	{0x0000a0d0, 0x02030204},
+	{0x0000a0d4, 0x02010202},
+	{0x0000a0d8, 0x021f0200},
+	{0x0000a0dc, 0x0302021e},
+	{0x0000a0e0, 0x03000301},
+	{0x0000a0e4, 0x031e031f},
+	{0x0000a0e8, 0x0402031d},
+	{0x0000a0ec, 0x04000401},
+	{0x0000a0f0, 0x041e041f},
+	{0x0000a0f4, 0x0502041d},
+	{0x0000a0f8, 0x05000501},
+	{0x0000a0fc, 0x051e051f},
+	{0x0000a100, 0x06010602},
+	{0x0000a104, 0x061f0600},
+	{0x0000a108, 0x061d061e},
+	{0x0000a10c, 0x07020703},
+	{0x0000a110, 0x07000701},
+	{0x0000a114, 0x00000000},
+	{0x0000a118, 0x00000000},
+	{0x0000a11c, 0x00000000},
+	{0x0000a120, 0x00000000},
+	{0x0000a124, 0x00000000},
+	{0x0000a128, 0x00000000},
+	{0x0000a12c, 0x00000000},
+	{0x0000a130, 0x00000000},
+	{0x0000a134, 0x00000000},
+	{0x0000a138, 0x00000000},
+	{0x0000a13c, 0x00000000},
+	{0x0000a140, 0x001f0000},
+	{0x0000a144, 0x01000101},
+	{0x0000a148, 0x011e011f},
+	{0x0000a14c, 0x011c011d},
+	{0x0000a150, 0x02030204},
+	{0x0000a154, 0x02010202},
+	{0x0000a158, 0x021f0200},
+	{0x0000a15c, 0x0302021e},
+	{0x0000a160, 0x03000301},
+	{0x0000a164, 0x031e031f},
+	{0x0000a168, 0x0402031d},
+	{0x0000a16c, 0x04000401},
+	{0x0000a170, 0x041e041f},
+	{0x0000a174, 0x0502041d},
+	{0x0000a178, 0x05000501},
+	{0x0000a17c, 0x051e051f},
+	{0x0000a180, 0x06010602},
+	{0x0000a184, 0x061f0600},
+	{0x0000a188, 0x061d061e},
+	{0x0000a18c, 0x07020703},
+	{0x0000a190, 0x07000701},
+	{0x0000a194, 0x00000000},
+	{0x0000a198, 0x00000000},
+	{0x0000a19c, 0x00000000},
+	{0x0000a1a0, 0x00000000},
+	{0x0000a1a4, 0x00000000},
+	{0x0000a1a8, 0x00000000},
+	{0x0000a1ac, 0x00000000},
+	{0x0000a1b0, 0x00000000},
+	{0x0000a1b4, 0x00000000},
+	{0x0000a1b8, 0x00000000},
+	{0x0000a1bc, 0x00000000},
+	{0x0000a1c0, 0x00000000},
+	{0x0000a1c4, 0x00000000},
+	{0x0000a1c8, 0x00000000},
+	{0x0000a1cc, 0x00000000},
+	{0x0000a1d0, 0x00000000},
+	{0x0000a1d4, 0x00000000},
+	{0x0000a1d8, 0x00000000},
+	{0x0000a1dc, 0x00000000},
+	{0x0000a1e0, 0x00000000},
+	{0x0000a1e4, 0x00000000},
+	{0x0000a1e8, 0x00000000},
+	{0x0000a1ec, 0x00000000},
+	{0x0000a1f0, 0x00000396},
+	{0x0000a1f4, 0x00000396},
+	{0x0000a1f8, 0x00000396},
+	{0x0000a1fc, 0x00000196},
+	{0x0000b000, 0x00010000},
+	{0x0000b004, 0x00030002},
+	{0x0000b008, 0x00050004},
+	{0x0000b00c, 0x00810080},
+	{0x0000b010, 0x00830082},
+	{0x0000b014, 0x01810180},
+	{0x0000b018, 0x01830182},
+	{0x0000b01c, 0x01850184},
+	{0x0000b020, 0x02810280},
+	{0x0000b024, 0x02830282},
+	{0x0000b028, 0x02850284},
+	{0x0000b02c, 0x02890288},
+	{0x0000b030, 0x028b028a},
+	{0x0000b034, 0x0388028c},
+	{0x0000b038, 0x038a0389},
+	{0x0000b03c, 0x038c038b},
+	{0x0000b040, 0x0390038d},
+	{0x0000b044, 0x03920391},
+	{0x0000b048, 0x03940393},
+	{0x0000b04c, 0x03960395},
+	{0x0000b050, 0x00000000},
+	{0x0000b054, 0x00000000},
+	{0x0000b058, 0x00000000},
+	{0x0000b05c, 0x00000000},
+	{0x0000b060, 0x00000000},
+	{0x0000b064, 0x00000000},
+	{0x0000b068, 0x00000000},
+	{0x0000b06c, 0x00000000},
+	{0x0000b070, 0x00000000},
+	{0x0000b074, 0x00000000},
+	{0x0000b078, 0x00000000},
+	{0x0000b07c, 0x00000000},
+	{0x0000b080, 0x32323232},
+	{0x0000b084, 0x2f2f3232},
+	{0x0000b088, 0x23282a2d},
+	{0x0000b08c, 0x1c1e2123},
+	{0x0000b090, 0x14171919},
+	{0x0000b094, 0x0e0e1214},
+	{0x0000b098, 0x03050707},
+	{0x0000b09c, 0x00030303},
+	{0x0000b0a0, 0x00000000},
+	{0x0000b0a4, 0x00000000},
+	{0x0000b0a8, 0x00000000},
+	{0x0000b0ac, 0x00000000},
+	{0x0000b0b0, 0x00000000},
+	{0x0000b0b4, 0x00000000},
+	{0x0000b0b8, 0x00000000},
+	{0x0000b0bc, 0x00000000},
+	{0x0000b0c0, 0x003f0020},
+	{0x0000b0c4, 0x00400041},
+	{0x0000b0c8, 0x0140005f},
+	{0x0000b0cc, 0x0160015f},
+	{0x0000b0d0, 0x017e017f},
+	{0x0000b0d4, 0x02410242},
+	{0x0000b0d8, 0x025f0240},
+	{0x0000b0dc, 0x027f0260},
+	{0x0000b0e0, 0x0341027e},
+	{0x0000b0e4, 0x035f0340},
+	{0x0000b0e8, 0x037f0360},
+	{0x0000b0ec, 0x04400441},
+	{0x0000b0f0, 0x0460045f},
+	{0x0000b0f4, 0x0541047f},
+	{0x0000b0f8, 0x055f0540},
+	{0x0000b0fc, 0x057f0560},
+	{0x0000b100, 0x06400641},
+	{0x0000b104, 0x0660065f},
+	{0x0000b108, 0x067e067f},
+	{0x0000b10c, 0x07410742},
+	{0x0000b110, 0x075f0740},
+	{0x0000b114, 0x077f0760},
+	{0x0000b118, 0x07800781},
+	{0x0000b11c, 0x07a0079f},
+	{0x0000b120, 0x07c107bf},
+	{0x0000b124, 0x000007c0},
+	{0x0000b128, 0x00000000},
+	{0x0000b12c, 0x00000000},
+	{0x0000b130, 0x00000000},
+	{0x0000b134, 0x00000000},
+	{0x0000b138, 0x00000000},
+	{0x0000b13c, 0x00000000},
+	{0x0000b140, 0x003f0020},
+	{0x0000b144, 0x00400041},
+	{0x0000b148, 0x0140005f},
+	{0x0000b14c, 0x0160015f},
+	{0x0000b150, 0x017e017f},
+	{0x0000b154, 0x02410242},
+	{0x0000b158, 0x025f0240},
+	{0x0000b15c, 0x027f0260},
+	{0x0000b160, 0x0341027e},
+	{0x0000b164, 0x035f0340},
+	{0x0000b168, 0x037f0360},
+	{0x0000b16c, 0x04400441},
+	{0x0000b170, 0x0460045f},
+	{0x0000b174, 0x0541047f},
+	{0x0000b178, 0x055f0540},
+	{0x0000b17c, 0x057f0560},
+	{0x0000b180, 0x06400641},
+	{0x0000b184, 0x0660065f},
+	{0x0000b188, 0x067e067f},
+	{0x0000b18c, 0x07410742},
+	{0x0000b190, 0x075f0740},
+	{0x0000b194, 0x077f0760},
+	{0x0000b198, 0x07800781},
+	{0x0000b19c, 0x07a0079f},
+	{0x0000b1a0, 0x07c107bf},
+	{0x0000b1a4, 0x000007c0},
+	{0x0000b1a8, 0x00000000},
+	{0x0000b1ac, 0x00000000},
+	{0x0000b1b0, 0x00000000},
+	{0x0000b1b4, 0x00000000},
+	{0x0000b1b8, 0x00000000},
+	{0x0000b1bc, 0x00000000},
+	{0x0000b1c0, 0x00000000},
+	{0x0000b1c4, 0x00000000},
+	{0x0000b1c8, 0x00000000},
+	{0x0000b1cc, 0x00000000},
+	{0x0000b1d0, 0x00000000},
+	{0x0000b1d4, 0x00000000},
+	{0x0000b1d8, 0x00000000},
+	{0x0000b1dc, 0x00000000},
+	{0x0000b1e0, 0x00000000},
+	{0x0000b1e4, 0x00000000},
+	{0x0000b1e8, 0x00000000},
+	{0x0000b1ec, 0x00000000},
+	{0x0000b1f0, 0x00000396},
+	{0x0000b1f4, 0x00000396},
+	{0x0000b1f8, 0x00000396},
+	{0x0000b1fc, 0x00000196},
+};
+
+static const u32 ar9300_2p2_soc_preamble[][2] = {
+	/* Addr      allmodes  */
+	{0x000040a4, 0x00a0c1c9},
+	{0x00007008, 0x00000000},
+	{0x00007020, 0x00000000},
+	{0x00007034, 0x00000002},
+	{0x00007038, 0x000004c2},
+	{0x00007048, 0x00000008},
+};
+
+static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2[][2] = {
+	/* Addr      allmodes  */
+	{0x00004040, 0x0821265e},
+	{0x00004040, 0x0008003b},
+	{0x00004044, 0x00000000},
+};
+
+static const u32 ar9300PciePhy_clkreq_enable_L1_2p2[][2] = {
+	/* Addr      allmodes  */
+	{0x00004040, 0x08253e5e},
+	{0x00004040, 0x0008003b},
+	{0x00004044, 0x00000000},
+};
+
+static const u32 ar9300PciePhy_clkreq_disable_L1_2p2[][2] = {
+	/* Addr      allmodes  */
+	{0x00004040, 0x08213e5e},
+	{0x00004040, 0x0008003b},
+	{0x00004044, 0x00000000},
+};
+
+#endif /* INITVALS_9003_2P2_H */
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_eeprom.h b/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_eeprom.h
new file mode 100644
index 0000000000000000000000000000000000000000..393f2de52a9039e89fe394050c9730c0733e6f78
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_eeprom.h
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef AR9003_EEPROM_H
+#define AR9003_EEPROM_H
+
+#define AR9300_EEP_VER               0xD000
+#define AR9300_EEP_VER_MINOR_MASK    0xFFF
+#define AR9300_EEP_MINOR_VER_1       0x1
+#define AR9300_EEP_MINOR_VER         AR9300_EEP_MINOR_VER_1
+
+/* 16-bit offset location start of calibration struct */
+#define AR9300_EEP_START_LOC         256
+#define AR9300_NUM_5G_CAL_PIERS      8
+#define AR9300_NUM_2G_CAL_PIERS      3
+#define AR9300_NUM_5G_20_TARGET_POWERS  8
+#define AR9300_NUM_5G_40_TARGET_POWERS  8
+#define AR9300_NUM_2G_CCK_TARGET_POWERS 2
+#define AR9300_NUM_2G_20_TARGET_POWERS  3
+#define AR9300_NUM_2G_40_TARGET_POWERS  3
+/* #define AR9300_NUM_CTLS              21 */
+#define AR9300_NUM_CTLS_5G           9
+#define AR9300_NUM_CTLS_2G           12
+#define AR9300_NUM_BAND_EDGES_5G     8
+#define AR9300_NUM_BAND_EDGES_2G     4
+#define AR9300_EEPMISC_BIG_ENDIAN    0x01
+#define AR9300_EEPMISC_WOW           0x02
+#define AR9300_CUSTOMER_DATA_SIZE    20
+
+#define FBIN2FREQ(x, y) ((y) ? (2300 + x) : (4800 + 5 * x))
+#define AR9300_MAX_CHAINS            3
+#define AR9300_ANT_16S               25
+#define AR9300_FUTURE_MODAL_SZ       6
+
+#define AR9300_PAPRD_RATE_MASK		0x01ffffff
+#define AR9300_PAPRD_SCALE_1		0x0e000000
+#define AR9300_PAPRD_SCALE_1_S		25
+#define AR9300_PAPRD_SCALE_2		0x70000000
+#define AR9300_PAPRD_SCALE_2_S		28
+
+/* Delta from which to start power to pdadc table */
+/* This offset is used in both open loop and closed loop power control
+ * schemes. In open loop power control, it is not really needed, but for
+ * the "sake of consistency" it was kept. For certain AP designs, this
+ * value is overwritten by the value in the flag "pwrTableOffset" just
+ * before writing the pdadc vs pwr into the chip registers.
+ */
+#define AR9300_PWR_TABLE_OFFSET  0
+
+/* byte addressable */
+#define AR9300_EEPROM_SIZE (16*1024)
+
+#define AR9300_BASE_ADDR_4K 0xfff
+#define AR9300_BASE_ADDR 0x3ff
+#define AR9300_BASE_ADDR_512 0x1ff
+
+#define AR9300_OTP_BASE			0x14000
+#define AR9300_OTP_STATUS		0x15f18
+#define AR9300_OTP_STATUS_TYPE		0x7
+#define AR9300_OTP_STATUS_VALID		0x4
+#define AR9300_OTP_STATUS_ACCESS_BUSY	0x2
+#define AR9300_OTP_STATUS_SM_BUSY	0x1
+#define AR9300_OTP_READ_DATA		0x15f1c
+
+enum targetPowerHTRates {
+	HT_TARGET_RATE_0_8_16,
+	HT_TARGET_RATE_1_3_9_11_17_19,
+	HT_TARGET_RATE_4,
+	HT_TARGET_RATE_5,
+	HT_TARGET_RATE_6,
+	HT_TARGET_RATE_7,
+	HT_TARGET_RATE_12,
+	HT_TARGET_RATE_13,
+	HT_TARGET_RATE_14,
+	HT_TARGET_RATE_15,
+	HT_TARGET_RATE_20,
+	HT_TARGET_RATE_21,
+	HT_TARGET_RATE_22,
+	HT_TARGET_RATE_23
+};
+
+enum targetPowerLegacyRates {
+	LEGACY_TARGET_RATE_6_24,
+	LEGACY_TARGET_RATE_36,
+	LEGACY_TARGET_RATE_48,
+	LEGACY_TARGET_RATE_54
+};
+
+enum targetPowerCckRates {
+	LEGACY_TARGET_RATE_1L_5L,
+	LEGACY_TARGET_RATE_5S,
+	LEGACY_TARGET_RATE_11L,
+	LEGACY_TARGET_RATE_11S
+};
+
+enum ar9300_Rates {
+	ALL_TARGET_LEGACY_6_24,
+	ALL_TARGET_LEGACY_36,
+	ALL_TARGET_LEGACY_48,
+	ALL_TARGET_LEGACY_54,
+	ALL_TARGET_LEGACY_1L_5L,
+	ALL_TARGET_LEGACY_5S,
+	ALL_TARGET_LEGACY_11L,
+	ALL_TARGET_LEGACY_11S,
+	ALL_TARGET_HT20_0_8_16,
+	ALL_TARGET_HT20_1_3_9_11_17_19,
+	ALL_TARGET_HT20_4,
+	ALL_TARGET_HT20_5,
+	ALL_TARGET_HT20_6,
+	ALL_TARGET_HT20_7,
+	ALL_TARGET_HT20_12,
+	ALL_TARGET_HT20_13,
+	ALL_TARGET_HT20_14,
+	ALL_TARGET_HT20_15,
+	ALL_TARGET_HT20_20,
+	ALL_TARGET_HT20_21,
+	ALL_TARGET_HT20_22,
+	ALL_TARGET_HT20_23,
+	ALL_TARGET_HT40_0_8_16,
+	ALL_TARGET_HT40_1_3_9_11_17_19,
+	ALL_TARGET_HT40_4,
+	ALL_TARGET_HT40_5,
+	ALL_TARGET_HT40_6,
+	ALL_TARGET_HT40_7,
+	ALL_TARGET_HT40_12,
+	ALL_TARGET_HT40_13,
+	ALL_TARGET_HT40_14,
+	ALL_TARGET_HT40_15,
+	ALL_TARGET_HT40_20,
+	ALL_TARGET_HT40_21,
+	ALL_TARGET_HT40_22,
+	ALL_TARGET_HT40_23,
+	ar9300RateSize,
+};
+
+
+struct eepFlags {
+	u8 opFlags;
+	u8 eepMisc;
+} __attribute__((packed));
+
+enum CompressAlgorithm {
+	_CompressNone = 0,
+	_CompressLzma,
+	_CompressPairs,
+	_CompressBlock,
+	_Compress4,
+	_Compress5,
+	_Compress6,
+	_Compress7,
+};
+
+struct ar9300_base_eep_hdr {
+	uint16_t regDmn[2];
+	/* 4 bits tx and 4 bits rx */
+	u8 txrxMask;
+	struct eepFlags opCapFlags;
+	u8 rfSilent;
+	u8 blueToothOptions;
+	u8 deviceCap;
+	/* takes lower byte in eeprom location */
+	u8 deviceType;
+	/* offset in dB to be added to beginning
+	 * of pdadc table in calibration
+	 */
+	int8_t pwrTableOffset;
+	u8 params_for_tuning_caps[2];
+	/*
+	 * bit0 - enable tx temp comp
+	 * bit1 - enable tx volt comp
+	 * bit2 - enable fastClock - default to 1
+	 * bit3 - enable doubling - default to 1
+	 * bit4 - enable internal regulator - default to 1
+	 */
+	u8 featureEnable;
+	/* misc flags: bit0 - turn down drivestrength */
+	u8 miscConfiguration;
+	u8 eepromWriteEnableGpio;
+	u8 wlanDisableGpio;
+	u8 wlanLedGpio;
+	u8 rxBandSelectGpio;
+	u8 txrxgain;
+	/* SW controlled internal regulator fields */
+	uint32_t swreg;
+} __attribute__((packed));
+
+struct ar9300_modal_eep_header {
+	/* 4 idle, t1, t2, b (4 bits per setting) */
+	uint32_t antCtrlCommon;
+	/* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
+	uint32_t antCtrlCommon2;
+	/* 6 idle, t, r, rx1, rx12, b (2 bits each) */
+	uint16_t antCtrlChain[AR9300_MAX_CHAINS];
+	/* 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
+	u8 xatten1DB[AR9300_MAX_CHAINS];
+	/* 3  xatten1_margin for merlin (0xa20c/b20c 16:12 */
+	u8 xatten1Margin[AR9300_MAX_CHAINS];
+	int8_t tempSlope;
+	int8_t voltSlope;
+	/* spur channels in usual fbin coding format */
+	u8 spurChans[AR_EEPROM_MODAL_SPURS];
+	/* 3  Check if the register is per chain */
+	int8_t noiseFloorThreshCh[AR9300_MAX_CHAINS];
+	u8 ob[AR9300_MAX_CHAINS];
+	u8 db_stage2[AR9300_MAX_CHAINS];
+	u8 db_stage3[AR9300_MAX_CHAINS];
+	u8 db_stage4[AR9300_MAX_CHAINS];
+	u8 xpaBiasLvl;
+	u8 txFrameToDataStart;
+	u8 txFrameToPaOn;
+	u8 txClip;
+	int8_t antennaGain;
+	u8 switchSettling;
+	int8_t adcDesiredSize;
+	u8 txEndToXpaOff;
+	u8 txEndToRxOn;
+	u8 txFrameToXpaOn;
+	u8 thresh62;
+	uint32_t papdRateMaskHt20;
+	uint32_t papdRateMaskHt40;
+	u8 futureModal[10];
+} __attribute__((packed));
+
+struct ar9300_cal_data_per_freq_op_loop {
+	int8_t refPower;
+	/* pdadc voltage at power measurement */
+	u8 voltMeas;
+	/* pcdac used for power measurement   */
+	u8 tempMeas;
+	/* range is -60 to -127 create a mapping equation 1db resolution */
+	int8_t rxNoisefloorCal;
+	/*range is same as noisefloor */
+	int8_t rxNoisefloorPower;
+	/* temp measured when noisefloor cal was performed */
+	u8 rxTempMeas;
+} __attribute__((packed));
+
+struct cal_tgt_pow_legacy {
+	u8 tPow2x[4];
+} __attribute__((packed));
+
+struct cal_tgt_pow_ht {
+	u8 tPow2x[14];
+} __attribute__((packed));
+
+struct cal_ctl_data_2g {
+	u8 ctlEdges[AR9300_NUM_BAND_EDGES_2G];
+} __attribute__((packed));
+
+struct cal_ctl_data_5g {
+	u8 ctlEdges[AR9300_NUM_BAND_EDGES_5G];
+} __attribute__((packed));
+
+struct ar9300_BaseExtension_1 {
+	u8 ant_div_control;
+	u8 future[13];
+} __attribute__((packed));
+
+struct ar9300_BaseExtension_2 {
+	int8_t    tempSlopeLow;
+	int8_t    tempSlopeHigh;
+	u8   xatten1DBLow[AR9300_MAX_CHAINS];
+	u8   xatten1MarginLow[AR9300_MAX_CHAINS];
+	u8   xatten1DBHigh[AR9300_MAX_CHAINS];
+	u8   xatten1MarginHigh[AR9300_MAX_CHAINS];
+} __attribute__((packed));
+
+struct ar9300_eeprom {
+	u8 eepromVersion;
+	u8 templateVersion;
+	u8 macAddr[6];
+	u8 custData[AR9300_CUSTOMER_DATA_SIZE];
+
+	struct ar9300_base_eep_hdr baseEepHeader;
+
+	struct ar9300_modal_eep_header modalHeader2G;
+	struct ar9300_BaseExtension_1 base_ext1;
+	u8 calFreqPier2G[AR9300_NUM_2G_CAL_PIERS];
+	struct ar9300_cal_data_per_freq_op_loop
+	 calPierData2G[AR9300_MAX_CHAINS][AR9300_NUM_2G_CAL_PIERS];
+	u8 calTarget_freqbin_Cck[AR9300_NUM_2G_CCK_TARGET_POWERS];
+	u8 calTarget_freqbin_2G[AR9300_NUM_2G_20_TARGET_POWERS];
+	u8 calTarget_freqbin_2GHT20[AR9300_NUM_2G_20_TARGET_POWERS];
+	u8 calTarget_freqbin_2GHT40[AR9300_NUM_2G_40_TARGET_POWERS];
+	struct cal_tgt_pow_legacy
+	 calTargetPowerCck[AR9300_NUM_2G_CCK_TARGET_POWERS];
+	struct cal_tgt_pow_legacy
+	 calTargetPower2G[AR9300_NUM_2G_20_TARGET_POWERS];
+	struct cal_tgt_pow_ht
+	 calTargetPower2GHT20[AR9300_NUM_2G_20_TARGET_POWERS];
+	struct cal_tgt_pow_ht
+	 calTargetPower2GHT40[AR9300_NUM_2G_40_TARGET_POWERS];
+	u8 ctlIndex_2G[AR9300_NUM_CTLS_2G];
+	u8 ctl_freqbin_2G[AR9300_NUM_CTLS_2G][AR9300_NUM_BAND_EDGES_2G];
+	struct cal_ctl_data_2g ctlPowerData_2G[AR9300_NUM_CTLS_2G];
+	struct ar9300_modal_eep_header modalHeader5G;
+	struct ar9300_BaseExtension_2 base_ext2;
+	u8 calFreqPier5G[AR9300_NUM_5G_CAL_PIERS];
+	struct ar9300_cal_data_per_freq_op_loop
+	 calPierData5G[AR9300_MAX_CHAINS][AR9300_NUM_5G_CAL_PIERS];
+	u8 calTarget_freqbin_5G[AR9300_NUM_5G_20_TARGET_POWERS];
+	u8 calTarget_freqbin_5GHT20[AR9300_NUM_5G_20_TARGET_POWERS];
+	u8 calTarget_freqbin_5GHT40[AR9300_NUM_5G_40_TARGET_POWERS];
+	struct cal_tgt_pow_legacy
+	 calTargetPower5G[AR9300_NUM_5G_20_TARGET_POWERS];
+	struct cal_tgt_pow_ht
+	 calTargetPower5GHT20[AR9300_NUM_5G_20_TARGET_POWERS];
+	struct cal_tgt_pow_ht
+	 calTargetPower5GHT40[AR9300_NUM_5G_40_TARGET_POWERS];
+	u8 ctlIndex_5G[AR9300_NUM_CTLS_5G];
+	u8 ctl_freqbin_5G[AR9300_NUM_CTLS_5G][AR9300_NUM_BAND_EDGES_5G];
+	struct cal_ctl_data_5g ctlPowerData_5G[AR9300_NUM_CTLS_5G];
+} __attribute__((packed));
+
+s32 ar9003_hw_get_tx_gain_idx(struct ath_hw *ah);
+s32 ar9003_hw_get_rx_gain_idx(struct ath_hw *ah);
+
+u8 *ar9003_get_spur_chan_ptr(struct ath_hw *ah, int is_2ghz);
+
+unsigned int ar9003_get_paprd_scale_factor(struct ath_hw *ah,
+					   struct ath9k_channel *chan);
+#endif
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_mac.h b/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_mac.h
new file mode 100644
index 0000000000000000000000000000000000000000..6442bb77923298e2de494ac05edec9b7404a7b8b
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_mac.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef AR9003_MAC_H
+#define AR9003_MAC_H
+
+#define AR_DescId	0xffff0000
+#define AR_DescId_S	16
+#define AR_CtrlStat	0x00004000
+#define AR_CtrlStat_S	14
+#define AR_TxRxDesc	0x00008000
+#define AR_TxRxDesc_S	15
+#define AR_TxQcuNum	0x00000f00
+#define AR_TxQcuNum_S	8
+
+#define AR_BufLen	0x0fff0000
+#define AR_BufLen_S	16
+
+#define AR_TxDescId	0xffff0000
+#define AR_TxDescId_S	16
+#define AR_TxPtrChkSum	0x0000ffff
+
+#define AR_LowRxChain	0x00004000
+
+#define AR_Not_Sounding	0x20000000
+
+/* ctl 12 */
+#define AR_PAPRDChainMask	0x00000e00
+#define AR_PAPRDChainMask_S	9
+
+#define MAP_ISR_S2_CST          6
+#define MAP_ISR_S2_GTT          6
+#define MAP_ISR_S2_TIM          3
+#define MAP_ISR_S2_CABEND       0
+#define MAP_ISR_S2_DTIMSYNC     7
+#define MAP_ISR_S2_DTIM         7
+#define MAP_ISR_S2_TSFOOR       4
+#define MAP_ISR_S2_BB_WATCHDOG  6
+
+#define AR9003TXC_CONST(_ds) ((const struct ar9003_txc *) _ds)
+
+struct ar9003_rxs {
+	u32 ds_info;
+	u32 status1;
+	u32 status2;
+	u32 status3;
+	u32 status4;
+	u32 status5;
+	u32 status6;
+	u32 status7;
+	u32 status8;
+	u32 status9;
+	u32 status10;
+	u32 status11;
+} __attribute__((packed, aligned(4)));
+
+/* Transmit Control Descriptor */
+struct ar9003_txc {
+	u32 info;   /* descriptor information */
+	u32 link;   /* link pointer */
+	u32 data0;  /* data pointer to 1st buffer */
+	u32 ctl3;   /* DMA control 3  */
+	u32 data1;  /* data pointer to 2nd buffer */
+	u32 ctl5;   /* DMA control 5  */
+	u32 data2;  /* data pointer to 3rd buffer */
+	u32 ctl7;   /* DMA control 7  */
+	u32 data3;  /* data pointer to 4th buffer */
+	u32 ctl9;   /* DMA control 9  */
+	u32 ctl10;  /* DMA control 10 */
+	u32 ctl11;  /* DMA control 11 */
+	u32 ctl12;  /* DMA control 12 */
+	u32 ctl13;  /* DMA control 13 */
+	u32 ctl14;  /* DMA control 14 */
+	u32 ctl15;  /* DMA control 15 */
+	u32 ctl16;  /* DMA control 16 */
+	u32 ctl17;  /* DMA control 17 */
+	u32 ctl18;  /* DMA control 18 */
+	u32 ctl19;  /* DMA control 19 */
+	u32 ctl20;  /* DMA control 20 */
+	u32 ctl21;  /* DMA control 21 */
+	u32 ctl22;  /* DMA control 22 */
+	u32 pad[9]; /* pad to cache line (128 bytes/32 dwords) */
+} __attribute__((packed, aligned(4)));
+
+struct ar9003_txs {
+	u32 ds_info;
+	u32 status1;
+	u32 status2;
+	u32 status3;
+	u32 status4;
+	u32 status5;
+	u32 status6;
+	u32 status7;
+	u32 status8;
+} __attribute__((packed, aligned(4)));
+
+void ar9003_hw_attach_mac_ops(struct ath_hw *hw);
+void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size);
+void ath9k_hw_addrxbuf_edma(struct ath_hw *ah, u32 rxdp,
+			    enum ath9k_rx_qtype qtype);
+
+int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah,
+				 struct ath_rx_status *rxs,
+				 void *buf_addr);
+void ath9k_hw_reset_txstatus_ring(struct ath_hw *ah);
+void ath9k_hw_setup_statusring(struct ath_hw *ah, void *ts_start,
+			       u32 ts_paddr_start,
+			       u8 size);
+#endif
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_phy.h b/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_phy.h
new file mode 100644
index 0000000000000000000000000000000000000000..443090d278e33234e432085fdb97657ce974afd9
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ar9003_phy.h
@@ -0,0 +1,1124 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef AR9003_PHY_H
+#define AR9003_PHY_H
+
+/*
+ * Channel Register Map
+ */
+#define AR_CHAN_BASE	0x9800
+
+#define AR_PHY_TIMING1      (AR_CHAN_BASE + 0x0)
+#define AR_PHY_TIMING2      (AR_CHAN_BASE + 0x4)
+#define AR_PHY_TIMING3      (AR_CHAN_BASE + 0x8)
+#define AR_PHY_TIMING4      (AR_CHAN_BASE + 0xc)
+#define AR_PHY_TIMING5      (AR_CHAN_BASE + 0x10)
+#define AR_PHY_TIMING6      (AR_CHAN_BASE + 0x14)
+#define AR_PHY_TIMING11     (AR_CHAN_BASE + 0x18)
+#define AR_PHY_SPUR_REG     (AR_CHAN_BASE + 0x1c)
+#define AR_PHY_RX_IQCAL_CORR_B0    (AR_CHAN_BASE + 0xdc)
+#define AR_PHY_TX_IQCAL_CONTROL_3  (AR_CHAN_BASE + 0xb0)
+
+#define AR_PHY_TIMING11_SPUR_FREQ_SD    0x3FF00000
+#define AR_PHY_TIMING11_SPUR_FREQ_SD_S  20
+
+#define AR_PHY_TIMING11_SPUR_DELTA_PHASE 0x000FFFFF
+#define AR_PHY_TIMING11_SPUR_DELTA_PHASE_S 0
+
+#define AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC 0x40000000
+#define AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC_S 30
+
+#define AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR 0x80000000
+#define AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR_S 31
+
+#define AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT         0x4000000
+#define AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT_S       26
+
+#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM                         0x20000     /* bins move with freq offset */
+#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM_S                       17
+#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH            0x000000FF
+#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH_S          0
+#define AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI                        0x00000100
+#define AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI_S                      8
+#define AR_PHY_SPUR_REG_MASK_RATE_CNTL                          0x03FC0000
+#define AR_PHY_SPUR_REG_MASK_RATE_CNTL_S			18
+
+#define AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN   0x20000000
+#define AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN_S         29
+
+#define AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN   0x80000000
+#define AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN_S         31
+
+#define AR_PHY_FIND_SIG_LOW  (AR_CHAN_BASE + 0x20)
+
+#define AR_PHY_SFCORR           (AR_CHAN_BASE + 0x24)
+#define AR_PHY_SFCORR_LOW       (AR_CHAN_BASE + 0x28)
+#define AR_PHY_SFCORR_EXT       (AR_CHAN_BASE + 0x2c)
+
+#define AR_PHY_EXT_CCA              (AR_CHAN_BASE + 0x30)
+#define AR_PHY_RADAR_0              (AR_CHAN_BASE + 0x34)
+#define AR_PHY_RADAR_1              (AR_CHAN_BASE + 0x38)
+#define AR_PHY_RADAR_EXT            (AR_CHAN_BASE + 0x3c)
+#define AR_PHY_MULTICHAIN_CTRL      (AR_CHAN_BASE + 0x80)
+#define AR_PHY_PERCHAIN_CSD         (AR_CHAN_BASE + 0x84)
+
+#define AR_PHY_TX_PHASE_RAMP_0      (AR_CHAN_BASE + 0xd0)
+#define AR_PHY_ADC_GAIN_DC_CORR_0   (AR_CHAN_BASE + 0xd4)
+#define AR_PHY_IQ_ADC_MEAS_0_B0     (AR_CHAN_BASE + 0xc0)
+#define AR_PHY_IQ_ADC_MEAS_1_B0     (AR_CHAN_BASE + 0xc4)
+#define AR_PHY_IQ_ADC_MEAS_2_B0     (AR_CHAN_BASE + 0xc8)
+#define AR_PHY_IQ_ADC_MEAS_3_B0     (AR_CHAN_BASE + 0xcc)
+
+/* The following registers changed position from AR9300 1.0 to AR9300 2.0 */
+#define AR_PHY_TX_PHASE_RAMP_0_9300_10      (AR_CHAN_BASE + 0xd0 - 0x10)
+#define AR_PHY_ADC_GAIN_DC_CORR_0_9300_10   (AR_CHAN_BASE + 0xd4 - 0x10)
+#define AR_PHY_IQ_ADC_MEAS_0_B0_9300_10     (AR_CHAN_BASE + 0xc0 + 0x8)
+#define AR_PHY_IQ_ADC_MEAS_1_B0_9300_10     (AR_CHAN_BASE + 0xc4 + 0x8)
+#define AR_PHY_IQ_ADC_MEAS_2_B0_9300_10     (AR_CHAN_BASE + 0xc8 + 0x8)
+#define AR_PHY_IQ_ADC_MEAS_3_B0_9300_10     (AR_CHAN_BASE + 0xcc + 0x8)
+
+#define AR_PHY_TX_CRC               (AR_CHAN_BASE + 0xa0)
+#define AR_PHY_TST_DAC_CONST        (AR_CHAN_BASE + 0xa4)
+#define AR_PHY_SPUR_REPORT_0        (AR_CHAN_BASE + 0xa8)
+#define AR_PHY_CHAN_INFO_TAB_0      (AR_CHAN_BASE + 0x300)
+
+/*
+ * Channel Field Definitions
+ */
+#define AR_PHY_TIMING2_USE_FORCE_PPM    0x00001000
+#define AR_PHY_TIMING2_FORCE_PPM_VAL    0x00000fff
+#define AR_PHY_TIMING3_DSC_MAN      0xFFFE0000
+#define AR_PHY_TIMING3_DSC_MAN_S    17
+#define AR_PHY_TIMING3_DSC_EXP      0x0001E000
+#define AR_PHY_TIMING3_DSC_EXP_S    13
+#define AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX 0xF000
+#define AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX_S   12
+#define AR_PHY_TIMING4_DO_CAL    0x10000
+
+#define AR_PHY_TIMING4_ENABLE_PILOT_MASK        0x10000000
+#define AR_PHY_TIMING4_ENABLE_PILOT_MASK_S      28
+#define AR_PHY_TIMING4_ENABLE_CHAN_MASK         0x20000000
+#define AR_PHY_TIMING4_ENABLE_CHAN_MASK_S       29
+
+#define AR_PHY_TIMING4_ENABLE_SPUR_FILTER 0x40000000
+#define AR_PHY_TIMING4_ENABLE_SPUR_FILTER_S 30
+#define AR_PHY_TIMING4_ENABLE_SPUR_RSSI 0x80000000
+#define AR_PHY_TIMING4_ENABLE_SPUR_RSSI_S 31
+
+#define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000
+#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000
+#define AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW  0x00000001
+#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW    0x00003F00
+#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S  8
+#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW      0x001FC000
+#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S    14
+#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW      0x0FE00000
+#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S    21
+#define AR_PHY_SFCORR_M2COUNT_THR    0x0000001F
+#define AR_PHY_SFCORR_M2COUNT_THR_S  0
+#define AR_PHY_SFCORR_M1_THRESH      0x00FE0000
+#define AR_PHY_SFCORR_M1_THRESH_S    17
+#define AR_PHY_SFCORR_M2_THRESH      0x7F000000
+#define AR_PHY_SFCORR_M2_THRESH_S    24
+#define AR_PHY_SFCORR_EXT_M1_THRESH       0x0000007F
+#define AR_PHY_SFCORR_EXT_M1_THRESH_S     0
+#define AR_PHY_SFCORR_EXT_M2_THRESH       0x00003F80
+#define AR_PHY_SFCORR_EXT_M2_THRESH_S     7
+#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW   0x001FC000
+#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14
+#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW   0x0FE00000
+#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21
+#define AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD 0x10000000
+#define AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD_S 28
+#define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S   28
+#define AR_PHY_EXT_CCA_THRESH62 0x007F0000
+#define AR_PHY_EXT_CCA_THRESH62_S       16
+#define AR_PHY_EXT_MINCCA_PWR   0x01FF0000
+#define AR_PHY_EXT_MINCCA_PWR_S 16
+#define AR_PHY_EXT_CYCPWR_THR1 0x0000FE00L
+#define AR_PHY_EXT_CYCPWR_THR1_S 9
+#define AR_PHY_TIMING5_CYCPWR_THR1  0x000000FE
+#define AR_PHY_TIMING5_CYCPWR_THR1_S    1
+#define AR_PHY_TIMING5_CYCPWR_THR1_ENABLE  0x00000001
+#define AR_PHY_TIMING5_CYCPWR_THR1_ENABLE_S    0
+#define AR_PHY_TIMING5_CYCPWR_THR1A  0x007F0000
+#define AR_PHY_TIMING5_CYCPWR_THR1A_S    16
+#define AR_PHY_TIMING5_RSSI_THR1A     (0x7F << 16)
+#define AR_PHY_TIMING5_RSSI_THR1A_S   16
+#define AR_PHY_TIMING5_RSSI_THR1A_ENA (0x1 << 15)
+#define AR_PHY_RADAR_0_ENA  0x00000001
+#define AR_PHY_RADAR_0_FFT_ENA  0x80000000
+#define AR_PHY_RADAR_0_INBAND   0x0000003e
+#define AR_PHY_RADAR_0_INBAND_S 1
+#define AR_PHY_RADAR_0_PRSSI    0x00000FC0
+#define AR_PHY_RADAR_0_PRSSI_S  6
+#define AR_PHY_RADAR_0_HEIGHT   0x0003F000
+#define AR_PHY_RADAR_0_HEIGHT_S 12
+#define AR_PHY_RADAR_0_RRSSI    0x00FC0000
+#define AR_PHY_RADAR_0_RRSSI_S  18
+#define AR_PHY_RADAR_0_FIRPWR   0x7F000000
+#define AR_PHY_RADAR_0_FIRPWR_S 24
+#define AR_PHY_RADAR_1_RELPWR_ENA       0x00800000
+#define AR_PHY_RADAR_1_USE_FIR128       0x00400000
+#define AR_PHY_RADAR_1_RELPWR_THRESH    0x003F0000
+#define AR_PHY_RADAR_1_RELPWR_THRESH_S  16
+#define AR_PHY_RADAR_1_BLOCK_CHECK      0x00008000
+#define AR_PHY_RADAR_1_MAX_RRSSI        0x00004000
+#define AR_PHY_RADAR_1_RELSTEP_CHECK    0x00002000
+#define AR_PHY_RADAR_1_RELSTEP_THRESH   0x00001F00
+#define AR_PHY_RADAR_1_RELSTEP_THRESH_S 8
+#define AR_PHY_RADAR_1_MAXLEN           0x000000FF
+#define AR_PHY_RADAR_1_MAXLEN_S         0
+#define AR_PHY_RADAR_EXT_ENA            0x00004000
+#define AR_PHY_RADAR_DC_PWR_THRESH      0x007f8000
+#define AR_PHY_RADAR_DC_PWR_THRESH_S    15
+#define AR_PHY_RADAR_LB_DC_CAP          0x7f800000
+#define AR_PHY_RADAR_LB_DC_CAP_S        23
+#define AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW (0x3f << 6)
+#define AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW_S   6
+#define AR_PHY_FIND_SIG_LOW_FIRPWR      (0x7f << 12)
+#define AR_PHY_FIND_SIG_LOW_FIRPWR_S    12
+#define AR_PHY_FIND_SIG_LOW_FIRPWR_SIGN_BIT 19
+#define AR_PHY_FIND_SIG_LOW_RELSTEP     0x1f
+#define AR_PHY_FIND_SIG_LOW_RELSTEP_S   0
+#define AR_PHY_FIND_SIG_LOW_RELSTEP_SIGN_BIT 5
+#define AR_PHY_CHAN_INFO_TAB_S2_READ    0x00000008
+#define AR_PHY_CHAN_INFO_TAB_S2_READ_S           3
+#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF 0x0000007F
+#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF_S   0
+#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF 0x00003F80
+#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF_S   7
+#define AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE   0x00004000
+#define AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_Q_COFF   0x003f8000
+#define AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_Q_COFF_S 15
+#define AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_I_COFF   0x1fc00000
+#define AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_I_COFF_S 22
+
+/*
+ * MRC Register Map
+ */
+#define AR_MRC_BASE	0x9c00
+
+#define AR_PHY_TIMING_3A       (AR_MRC_BASE + 0x0)
+#define AR_PHY_LDPC_CNTL1      (AR_MRC_BASE + 0x4)
+#define AR_PHY_LDPC_CNTL2      (AR_MRC_BASE + 0x8)
+#define AR_PHY_PILOT_SPUR_MASK (AR_MRC_BASE + 0xc)
+#define AR_PHY_CHAN_SPUR_MASK  (AR_MRC_BASE + 0x10)
+#define AR_PHY_SGI_DELTA       (AR_MRC_BASE + 0x14)
+#define AR_PHY_ML_CNTL_1       (AR_MRC_BASE + 0x18)
+#define AR_PHY_ML_CNTL_2       (AR_MRC_BASE + 0x1c)
+#define AR_PHY_TST_ADC         (AR_MRC_BASE + 0x20)
+
+#define AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A              0x00000FE0
+#define AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A_S    5
+#define AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A                  0x1F
+#define AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A_S                0
+
+#define AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A        0x00000FE0
+#define AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A_S      5
+#define AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A            0x1F
+#define AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A_S		0
+
+/*
+ * MRC Feild Definitions
+ */
+#define AR_PHY_SGI_DSC_MAN   0x0007FFF0
+#define AR_PHY_SGI_DSC_MAN_S 4
+#define AR_PHY_SGI_DSC_EXP   0x0000000F
+#define AR_PHY_SGI_DSC_EXP_S 0
+/*
+ * BBB Register Map
+ */
+#define AR_BBB_BASE	0x9d00
+
+/*
+ * AGC Register Map
+ */
+#define AR_AGC_BASE	0x9e00
+
+#define AR_PHY_SETTLING         (AR_AGC_BASE + 0x0)
+#define AR_PHY_FORCEMAX_GAINS_0 (AR_AGC_BASE + 0x4)
+#define AR_PHY_GAINS_MINOFF0    (AR_AGC_BASE + 0x8)
+#define AR_PHY_DESIRED_SZ       (AR_AGC_BASE + 0xc)
+#define AR_PHY_FIND_SIG         (AR_AGC_BASE + 0x10)
+#define AR_PHY_AGC              (AR_AGC_BASE + 0x14)
+#define AR_PHY_EXT_ATTEN_CTL_0  (AR_AGC_BASE + 0x18)
+#define AR_PHY_CCA_0            (AR_AGC_BASE + 0x1c)
+#define AR_PHY_EXT_CCA0         (AR_AGC_BASE + 0x20)
+#define AR_PHY_RESTART          (AR_AGC_BASE + 0x24)
+
+/*
+ * Antenna Diversity  settings
+ */
+#define AR_PHY_MC_GAIN_CTRL     (AR_AGC_BASE + 0x28)
+#define AR_ANT_DIV_CTRL_ALL	0x7e000000
+#define AR_ANT_DIV_CTRL_ALL_S	25
+#define AR_ANT_DIV_ENABLE	0x1000000
+#define AR_ANT_DIV_ENABLE_S	24
+
+
+#define AR_PHY_9485_ANT_FAST_DIV_BIAS			0x00007e00
+#define AR_PHY_9485_ANT_FAST_DIV_BIAS_S                  9
+#define AR_PHY_9485_ANT_DIV_LNADIV			0x01000000
+#define AR_PHY_9485_ANT_DIV_LNADIV_S			24
+#define AR_PHY_9485_ANT_DIV_ALT_LNACONF			0x06000000
+#define AR_PHY_9485_ANT_DIV_ALT_LNACONF_S		25
+#define AR_PHY_9485_ANT_DIV_MAIN_LNACONF		0x18000000
+#define AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S		27
+#define AR_PHY_9485_ANT_DIV_ALT_GAINTB			0x20000000
+#define AR_PHY_9485_ANT_DIV_ALT_GAINTB_S		29
+#define AR_PHY_9485_ANT_DIV_MAIN_GAINTB			0x40000000
+#define AR_PHY_9485_ANT_DIV_MAIN_GAINTB_S		30
+
+#define AR_PHY_9485_ANT_DIV_LNA1_MINUS_LNA2		0x0
+#define AR_PHY_9485_ANT_DIV_LNA2			0x1
+#define AR_PHY_9485_ANT_DIV_LNA1			0x2
+#define AR_PHY_9485_ANT_DIV_LNA1_PLUS_LNA2		0x3
+
+#define AR_PHY_EXTCHN_PWRTHR1   (AR_AGC_BASE + 0x2c)
+#define AR_PHY_EXT_CHN_WIN      (AR_AGC_BASE + 0x30)
+#define AR_PHY_20_40_DET_THR    (AR_AGC_BASE + 0x34)
+#define AR_PHY_RIFS_SRCH        (AR_AGC_BASE + 0x38)
+#define AR_PHY_PEAK_DET_CTRL_1  (AR_AGC_BASE + 0x3c)
+#define AR_PHY_PEAK_DET_CTRL_2  (AR_AGC_BASE + 0x40)
+#define AR_PHY_RX_GAIN_BOUNDS_1 (AR_AGC_BASE + 0x44)
+#define AR_PHY_RX_GAIN_BOUNDS_2 (AR_AGC_BASE + 0x48)
+#define AR_PHY_RSSI_0           (AR_AGC_BASE + 0x180)
+#define AR_PHY_SPUR_CCK_REP0    (AR_AGC_BASE + 0x184)
+
+#define AR_PHY_CCK_DETECT       (AR_AGC_BASE + 0x1c0)
+#define AR_FAST_DIV_ENABLE	0x2000
+#define AR_FAST_DIV_ENABLE_S	13
+
+#define AR_PHY_DAG_CTRLCCK      (AR_AGC_BASE + 0x1c4)
+#define AR_PHY_IQCORR_CTRL_CCK  (AR_AGC_BASE + 0x1c8)
+
+#define AR_PHY_CCK_SPUR_MIT     (AR_AGC_BASE + 0x1cc)
+#define AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR                           0x000001fe
+#define AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR_S                                  1
+#define AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE                        0x60000000
+#define AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE_S                              29
+#define AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT                        0x00000001
+#define AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT_S                               0
+#define AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ                           0x1ffffe00
+#define AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ_S                                  9
+
+#define AR_PHY_MRC_CCK_CTRL         (AR_AGC_BASE + 0x1d0)
+#define AR_PHY_MRC_CCK_ENABLE       0x00000001
+#define AR_PHY_MRC_CCK_ENABLE_S              0
+#define AR_PHY_MRC_CCK_MUX_REG      0x00000002
+#define AR_PHY_MRC_CCK_MUX_REG_S             1
+
+#define AR_PHY_RX_OCGAIN        (AR_AGC_BASE + 0x200)
+
+#define AR_PHY_CCA_NOM_VAL_9300_2GHZ          -110
+#define AR_PHY_CCA_NOM_VAL_9300_5GHZ          -115
+#define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ     -125
+#define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ     -125
+#define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ     -95
+#define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ     -100
+
+/*
+ * AGC Field Definitions
+ */
+#define AR_PHY_EXT_ATTEN_CTL_RXTX_MARGIN    0x00FC0000
+#define AR_PHY_EXT_ATTEN_CTL_RXTX_MARGIN_S  18
+#define AR_PHY_EXT_ATTEN_CTL_BSW_MARGIN     0x00003C00
+#define AR_PHY_EXT_ATTEN_CTL_BSW_MARGIN_S   10
+#define AR_PHY_EXT_ATTEN_CTL_BSW_ATTEN      0x0000001F
+#define AR_PHY_EXT_ATTEN_CTL_BSW_ATTEN_S    0
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN2_MARGIN     0x003E0000
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN2_MARGIN_S   17
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN     0x0001F000
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN_S   12
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN2_DB         0x00000FC0
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN2_DB_S       6
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB         0x0000003F
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB_S       0
+#define AR_PHY_RXGAIN_TXRX_ATTEN    0x0003F000
+#define AR_PHY_RXGAIN_TXRX_ATTEN_S  12
+#define AR_PHY_RXGAIN_TXRX_RF_MAX   0x007C0000
+#define AR_PHY_RXGAIN_TXRX_RF_MAX_S 18
+#define AR9280_PHY_RXGAIN_TXRX_ATTEN    0x00003F80
+#define AR9280_PHY_RXGAIN_TXRX_ATTEN_S  7
+#define AR9280_PHY_RXGAIN_TXRX_MARGIN   0x001FC000
+#define AR9280_PHY_RXGAIN_TXRX_MARGIN_S 14
+#define AR_PHY_SETTLING_SWITCH  0x00003F80
+#define AR_PHY_SETTLING_SWITCH_S    7
+#define AR_PHY_DESIRED_SZ_ADC       0x000000FF
+#define AR_PHY_DESIRED_SZ_ADC_S     0
+#define AR_PHY_DESIRED_SZ_PGA       0x0000FF00
+#define AR_PHY_DESIRED_SZ_PGA_S     8
+#define AR_PHY_DESIRED_SZ_TOT_DES   0x0FF00000
+#define AR_PHY_DESIRED_SZ_TOT_DES_S 20
+#define AR_PHY_MINCCA_PWR       0x1FF00000
+#define AR_PHY_MINCCA_PWR_S     20
+#define AR_PHY_CCA_THRESH62     0x0007F000
+#define AR_PHY_CCA_THRESH62_S   12
+#define AR9280_PHY_MINCCA_PWR       0x1FF00000
+#define AR9280_PHY_MINCCA_PWR_S     20
+#define AR9280_PHY_CCA_THRESH62     0x000FF000
+#define AR9280_PHY_CCA_THRESH62_S   12
+#define AR_PHY_EXT_CCA0_THRESH62    0x000000FF
+#define AR_PHY_EXT_CCA0_THRESH62_S  0
+#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK          0x0000003F
+#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S        0
+#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME           0x00001FC0
+#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S         6
+#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV    0x2000
+
+#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR  0x00000200
+#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR_S  9
+#define AR_PHY_DAG_CTRLCCK_RSSI_THR 0x0001FC00
+#define AR_PHY_DAG_CTRLCCK_RSSI_THR_S   10
+
+#define AR_PHY_RIFS_INIT_DELAY         0x3ff0000
+#define AR_PHY_AGC_COARSE_LOW       0x00007F80
+#define AR_PHY_AGC_COARSE_LOW_S     7
+#define AR_PHY_AGC_COARSE_HIGH      0x003F8000
+#define AR_PHY_AGC_COARSE_HIGH_S    15
+#define AR_PHY_AGC_COARSE_PWR_CONST 0x0000007F
+#define AR_PHY_AGC_COARSE_PWR_CONST_S   0
+#define AR_PHY_FIND_SIG_FIRSTEP  0x0003F000
+#define AR_PHY_FIND_SIG_FIRSTEP_S        12
+#define AR_PHY_FIND_SIG_FIRPWR   0x03FC0000
+#define AR_PHY_FIND_SIG_FIRPWR_S         18
+#define AR_PHY_FIND_SIG_FIRPWR_SIGN_BIT  25
+#define AR_PHY_FIND_SIG_RELPWR   (0x1f << 6)
+#define AR_PHY_FIND_SIG_RELPWR_S          6
+#define AR_PHY_FIND_SIG_RELPWR_SIGN_BIT  11
+#define AR_PHY_FIND_SIG_RELSTEP        0x1f
+#define AR_PHY_FIND_SIG_RELSTEP_S         0
+#define AR_PHY_FIND_SIG_RELSTEP_SIGN_BIT  5
+#define AR_PHY_RESTART_DIV_GC   0x001C0000
+#define AR_PHY_RESTART_DIV_GC_S 18
+#define AR_PHY_RESTART_ENA      0x01
+#define AR_PHY_DC_RESTART_DIS   0x40000000
+
+#define AR_PHY_TPC_OLPC_GAIN_DELTA_PAL_ON       0xFF000000
+#define AR_PHY_TPC_OLPC_GAIN_DELTA_PAL_ON_S     24
+#define AR_PHY_TPC_OLPC_GAIN_DELTA              0x00FF0000
+#define AR_PHY_TPC_OLPC_GAIN_DELTA_S            16
+
+#define AR_PHY_TPC_6_ERROR_EST_MODE             0x03000000
+#define AR_PHY_TPC_6_ERROR_EST_MODE_S           24
+
+/*
+ * SM Register Map
+ */
+#define AR_SM_BASE	0xa200
+
+#define AR_PHY_D2_CHIP_ID        (AR_SM_BASE + 0x0)
+#define AR_PHY_GEN_CTRL          (AR_SM_BASE + 0x4)
+#define AR_PHY_MODE              (AR_SM_BASE + 0x8)
+#define AR_PHY_ACTIVE            (AR_SM_BASE + 0xc)
+#define AR_PHY_SPUR_MASK_A       (AR_SM_BASE + 0x20)
+#define AR_PHY_SPUR_MASK_B       (AR_SM_BASE + 0x24)
+#define AR_PHY_SPECTRAL_SCAN     (AR_SM_BASE + 0x28)
+#define AR_PHY_RADAR_BW_FILTER   (AR_SM_BASE + 0x2c)
+#define AR_PHY_SEARCH_START_DELAY (AR_SM_BASE + 0x30)
+#define AR_PHY_MAX_RX_LEN        (AR_SM_BASE + 0x34)
+#define AR_PHY_FRAME_CTL         (AR_SM_BASE + 0x38)
+#define AR_PHY_RFBUS_REQ         (AR_SM_BASE + 0x3c)
+#define AR_PHY_RFBUS_GRANT       (AR_SM_BASE + 0x40)
+#define AR_PHY_RIFS              (AR_SM_BASE + 0x44)
+#define AR_PHY_RX_CLR_DELAY      (AR_SM_BASE + 0x50)
+#define AR_PHY_RX_DELAY          (AR_SM_BASE + 0x54)
+
+#define AR_PHY_XPA_TIMING_CTL    (AR_SM_BASE + 0x64)
+#define AR_PHY_MISC_PA_CTL       (AR_SM_BASE + 0x80)
+#define AR_PHY_SWITCH_CHAIN_0    (AR_SM_BASE + 0x84)
+#define AR_PHY_SWITCH_COM        (AR_SM_BASE + 0x88)
+#define AR_PHY_SWITCH_COM_2      (AR_SM_BASE + 0x8c)
+#define AR_PHY_RX_CHAINMASK      (AR_SM_BASE + 0xa0)
+#define AR_PHY_CAL_CHAINMASK     (AR_SM_BASE + 0xc0)
+#define AR_PHY_CALMODE           (AR_SM_BASE + 0xc8)
+#define AR_PHY_FCAL_1            (AR_SM_BASE + 0xcc)
+#define AR_PHY_FCAL_2_0          (AR_SM_BASE + 0xd0)
+#define AR_PHY_DFT_TONE_CTL_0    (AR_SM_BASE + 0xd4)
+#define AR_PHY_CL_CAL_CTL        (AR_SM_BASE + 0xd8)
+#define AR_PHY_CL_TAB_0          (AR_SM_BASE + 0x100)
+#define AR_PHY_SYNTH_CONTROL     (AR_SM_BASE + 0x140)
+#define AR_PHY_ADDAC_CLK_SEL     (AR_SM_BASE + 0x144)
+#define AR_PHY_PLL_CTL           (AR_SM_BASE + 0x148)
+#define AR_PHY_ANALOG_SWAP       (AR_SM_BASE + 0x14c)
+#define AR_PHY_ADDAC_PARA_CTL    (AR_SM_BASE + 0x150)
+#define AR_PHY_XPA_CFG           (AR_SM_BASE + 0x158)
+
+#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A           0x0001FC00
+#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A_S         10
+#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A                       0x3FF
+#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A_S                     0
+
+#define AR_PHY_TEST              (AR_SM_BASE + 0x160)
+
+#define AR_PHY_TEST_BBB_OBS_SEL       0x780000
+#define AR_PHY_TEST_BBB_OBS_SEL_S     19
+
+#define AR_PHY_TEST_RX_OBS_SEL_BIT5_S 23
+#define AR_PHY_TEST_RX_OBS_SEL_BIT5   (1 << AR_PHY_TEST_RX_OBS_SEL_BIT5_S)
+
+#define AR_PHY_TEST_CHAIN_SEL      0xC0000000
+#define AR_PHY_TEST_CHAIN_SEL_S    30
+
+#define AR_PHY_TEST_CTL_STATUS   (AR_SM_BASE + 0x164)
+#define AR_PHY_TEST_CTL_TSTDAC_EN         0x1
+#define AR_PHY_TEST_CTL_TSTDAC_EN_S       0
+#define AR_PHY_TEST_CTL_TX_OBS_SEL        0x1C
+#define AR_PHY_TEST_CTL_TX_OBS_SEL_S      2
+#define AR_PHY_TEST_CTL_TX_OBS_MUX_SEL    0x60
+#define AR_PHY_TEST_CTL_TX_OBS_MUX_SEL_S  5
+#define AR_PHY_TEST_CTL_TSTADC_EN         0x100
+#define AR_PHY_TEST_CTL_TSTADC_EN_S       8
+#define AR_PHY_TEST_CTL_RX_OBS_SEL        0x3C00
+#define AR_PHY_TEST_CTL_RX_OBS_SEL_S      10
+
+
+#define AR_PHY_TSTDAC            (AR_SM_BASE + 0x168)
+
+#define AR_PHY_CHAN_STATUS       (AR_SM_BASE + 0x16c)
+
+#define AR_PHY_CHAN_INFO_MEMORY				(AR_SM_BASE + 0x170)
+#define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ	0x00000008
+#define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ_S	3
+
+#define AR_PHY_CHNINFO_NOISEPWR  (AR_SM_BASE + 0x174)
+#define AR_PHY_CHNINFO_GAINDIFF  (AR_SM_BASE + 0x178)
+#define AR_PHY_CHNINFO_FINETIM   (AR_SM_BASE + 0x17c)
+#define AR_PHY_CHAN_INFO_GAIN_0  (AR_SM_BASE + 0x180)
+#define AR_PHY_SCRAMBLER_SEED    (AR_SM_BASE + 0x190)
+#define AR_PHY_CCK_TX_CTRL       (AR_SM_BASE + 0x194)
+
+#define AR_PHY_HEAVYCLIP_CTL     (AR_SM_BASE + 0x1a4)
+#define AR_PHY_HEAVYCLIP_20      (AR_SM_BASE + 0x1a8)
+#define AR_PHY_HEAVYCLIP_40      (AR_SM_BASE + 0x1ac)
+#define AR_PHY_ILLEGAL_TXRATE    (AR_SM_BASE + 0x1b0)
+
+#define AR_PHY_POWER_TX_RATE(_d) (AR_SM_BASE + 0x1c0 + ((_d) << 2))
+
+#define AR_PHY_PWRTX_MAX         (AR_SM_BASE + 0x1f0)
+#define AR_PHY_POWER_TX_SUB      (AR_SM_BASE + 0x1f4)
+
+#define AR_PHY_TPC_1				(AR_SM_BASE + 0x1f8)
+#define AR_PHY_TPC_1_FORCED_DAC_GAIN		0x0000003e
+#define AR_PHY_TPC_1_FORCED_DAC_GAIN_S		1
+#define AR_PHY_TPC_1_FORCE_DAC_GAIN		0x00000001
+#define AR_PHY_TPC_1_FORCE_DAC_GAIN_S		0
+
+#define AR_PHY_TPC_4_B0				(AR_SM_BASE + 0x204)
+#define AR_PHY_TPC_5_B0				(AR_SM_BASE + 0x208)
+#define AR_PHY_TPC_6_B0				(AR_SM_BASE + 0x20c)
+
+#define AR_PHY_TPC_11_B0			(AR_SM_BASE + 0x220)
+#define AR_PHY_TPC_11_B1			(AR_SM1_BASE + 0x220)
+#define AR_PHY_TPC_11_B2			(AR_SM2_BASE + 0x220)
+#define AR_PHY_TPC_11_OLPC_GAIN_DELTA		0x00ff0000
+#define AR_PHY_TPC_11_OLPC_GAIN_DELTA_S		16
+
+#define AR_PHY_TPC_12				(AR_SM_BASE + 0x224)
+#define AR_PHY_TPC_12_DESIRED_SCALE_HT40_5	0x3e000000
+#define AR_PHY_TPC_12_DESIRED_SCALE_HT40_5_S	25
+
+#define AR_PHY_TPC_18				(AR_SM_BASE + 0x23c)
+#define AR_PHY_TPC_18_THERM_CAL_VALUE           0x000000ff
+#define AR_PHY_TPC_18_THERM_CAL_VALUE_S         0
+#define AR_PHY_TPC_18_VOLT_CAL_VALUE		0x0000ff00
+#define AR_PHY_TPC_18_VOLT_CAL_VALUE_S		8
+
+#define AR_PHY_TPC_19				(AR_SM_BASE + 0x240)
+#define AR_PHY_TPC_19_ALPHA_VOLT		0x001f0000
+#define AR_PHY_TPC_19_ALPHA_VOLT_S		16
+#define AR_PHY_TPC_19_ALPHA_THERM		0xff
+#define AR_PHY_TPC_19_ALPHA_THERM_S		0
+
+#define AR_PHY_TX_FORCED_GAIN				(AR_SM_BASE + 0x258)
+#define AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN		0x00000001
+#define AR_PHY_TX_FORCED_GAIN_FORCE_TX_GAIN_S		0
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN	0x0000000e
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXBB1DBGAIN_S	1
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN	0x00000030
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXBB6DBGAIN_S	4
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN		0x000003c0
+#define AR_PHY_TX_FORCED_GAIN_FORCED_TXMXRGAIN_S	6
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA		0x00003c00
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNA_S		10
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB		0x0003c000
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNB_S		14
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC		0x003c0000
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGNC_S		18
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND		0x00c00000
+#define AR_PHY_TX_FORCED_GAIN_FORCED_PADRVGND_S		22
+#define AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL		0x01000000
+#define AR_PHY_TX_FORCED_GAIN_FORCED_ENABLE_PAL_S	24
+
+
+#define AR_PHY_PDADC_TAB_0       (AR_SM_BASE + 0x280)
+
+#define AR_PHY_TXGAIN_TABLE      (AR_SM_BASE + 0x300)
+
+#define AR_PHY_TX_IQCAL_CONTROL_1   (AR_SM_BASE + AR_SREV_9485(ah) ? \
+						 0x3c8 : 0x448)
+#define AR_PHY_TX_IQCAL_START       (AR_SM_BASE + AR_SREV_9485(ah) ? \
+						 0x3c4 : 0x440)
+#define AR_PHY_TX_IQCAL_STATUS_B0   (AR_SM_BASE + AR_SREV_9485(ah) ? \
+						 0x3f0 : 0x48c)
+#define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i)    (AR_SM_BASE + \
+					     (AR_SREV_9485(ah) ? \
+					      0x3d0 : 0x450) + ((_i) << 2))
+
+#define AR_PHY_WATCHDOG_STATUS      (AR_SM_BASE + 0x5c0)
+#define AR_PHY_WATCHDOG_CTL_1       (AR_SM_BASE + 0x5c4)
+#define AR_PHY_WATCHDOG_CTL_2       (AR_SM_BASE + 0x5c8)
+#define AR_PHY_WATCHDOG_CTL         (AR_SM_BASE + 0x5cc)
+#define AR_PHY_ONLY_WARMRESET       (AR_SM_BASE + 0x5d0)
+#define AR_PHY_ONLY_CTL             (AR_SM_BASE + 0x5d4)
+#define AR_PHY_ECO_CTRL             (AR_SM_BASE + 0x5dc)
+
+#define AR_PHY_BB_THERM_ADC_1				(AR_SM_BASE + 0x248)
+#define AR_PHY_BB_THERM_ADC_1_INIT_THERM		0x000000ff
+#define AR_PHY_BB_THERM_ADC_1_INIT_THERM_S		0
+
+#define AR_PHY_BB_THERM_ADC_4				(AR_SM_BASE + 0x254)
+#define AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE	0x000000ff
+#define AR_PHY_BB_THERM_ADC_4_LATEST_THERM_VALUE_S	0
+#define AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE		0x0000ff00
+#define AR_PHY_BB_THERM_ADC_4_LATEST_VOLT_VALUE_S	8
+
+
+#define AR_PHY_65NM_CH0_SYNTH4      0x1608c
+#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT   0x00000002
+#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S 1
+#define AR_PHY_65NM_CH0_SYNTH7      0x16098
+#define AR_PHY_65NM_CH0_BIAS1       0x160c0
+#define AR_PHY_65NM_CH0_BIAS2       0x160c4
+#define AR_PHY_65NM_CH0_BIAS4       0x160cc
+#define AR_PHY_65NM_CH0_RXTX4       0x1610c
+#define AR_PHY_65NM_CH0_THERM       (AR_SREV_9300(ah) ? 0x16290 : 0x1628c)
+
+#define AR_PHY_65NM_CH0_THERM_LOCAL   0x80000000
+#define AR_PHY_65NM_CH0_THERM_LOCAL_S 31
+#define AR_PHY_65NM_CH0_THERM_START   0x20000000
+#define AR_PHY_65NM_CH0_THERM_START_S 29
+#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT   0x0000ff00
+#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT_S 8
+
+#define AR_PHY_65NM_CH0_RXTX1       0x16100
+#define AR_PHY_65NM_CH0_RXTX2       0x16104
+#define AR_PHY_65NM_CH1_RXTX1       0x16500
+#define AR_PHY_65NM_CH1_RXTX2       0x16504
+#define AR_PHY_65NM_CH2_RXTX1       0x16900
+#define AR_PHY_65NM_CH2_RXTX2       0x16904
+
+#define AR_CH0_TOP2 (AR_SREV_9485(ah) ? 0x00016284 : 0x0001628c)
+#define AR_CH0_TOP2_XPABIASLVL		0xf000
+#define AR_CH0_TOP2_XPABIASLVL_S	12
+
+#define AR_CH0_XTAL		(AR_SREV_9485(ah) ? 0x16290 : 0x16294)
+#define AR_CH0_XTAL_CAPINDAC	0x7f000000
+#define AR_CH0_XTAL_CAPINDAC_S	24
+#define AR_CH0_XTAL_CAPOUTDAC	0x00fe0000
+#define AR_CH0_XTAL_CAPOUTDAC_S	17
+
+#define AR_PHY_PMU1		0x16c40
+#define AR_PHY_PMU1_PWD		0x1
+#define AR_PHY_PMU1_PWD_S	0
+
+#define AR_PHY_PMU2		0x16c44
+#define AR_PHY_PMU2_PGM		0x00200000
+#define AR_PHY_PMU2_PGM_S	21
+
+#define AR_PHY_RX1DB_BIQUAD_LONG_SHIFT		0x00380000
+#define AR_PHY_RX1DB_BIQUAD_LONG_SHIFT_S	19
+#define AR_PHY_RX6DB_BIQUAD_LONG_SHIFT		0x00c00000
+#define AR_PHY_RX6DB_BIQUAD_LONG_SHIFT_S	22
+#define AR_PHY_LNAGAIN_LONG_SHIFT		0xe0000000
+#define AR_PHY_LNAGAIN_LONG_SHIFT_S		29
+#define AR_PHY_MXRGAIN_LONG_SHIFT		0x03000000
+#define AR_PHY_MXRGAIN_LONG_SHIFT_S		24
+#define AR_PHY_VGAGAIN_LONG_SHIFT		0x1c000000
+#define AR_PHY_VGAGAIN_LONG_SHIFT_S		26
+#define AR_PHY_SCFIR_GAIN_LONG_SHIFT		0x00000001
+#define AR_PHY_SCFIR_GAIN_LONG_SHIFT_S		0
+#define AR_PHY_MANRXGAIN_LONG_SHIFT		0x00000002
+#define AR_PHY_MANRXGAIN_LONG_SHIFT_S		1
+
+/*
+ * SM Field Definitions
+ */
+#define AR_PHY_CL_CAL_ENABLE          0x00000002
+#define AR_PHY_PARALLEL_CAL_ENABLE    0x00000001
+#define AR_PHY_TPCRG1_PD_CAL_ENABLE   0x00400000
+#define AR_PHY_TPCRG1_PD_CAL_ENABLE_S 22
+
+#define AR_PHY_ADDAC_PARACTL_OFF_PWDADC 0x00008000
+
+#define AR_PHY_FCAL20_CAP_STATUS_0    0x01f00000
+#define AR_PHY_FCAL20_CAP_STATUS_0_S  20
+
+#define AR_PHY_RFBUS_REQ_EN     0x00000001  /* request for RF bus */
+#define AR_PHY_RFBUS_GRANT_EN   0x00000001  /* RF bus granted */
+#define AR_PHY_GC_TURBO_MODE       0x00000001  /* set turbo mode bits */
+#define AR_PHY_GC_TURBO_SHORT      0x00000002  /* set short symbols to turbo mode setting */
+#define AR_PHY_GC_DYN2040_EN       0x00000004  /* enable dyn 20/40 mode */
+#define AR_PHY_GC_DYN2040_PRI_ONLY 0x00000008  /* dyn 20/40 - primary only */
+#define AR_PHY_GC_DYN2040_PRI_CH   0x00000010  /* dyn 20/40 - primary ch offset (0=+10MHz, 1=-10MHz)*/
+#define AR_PHY_GC_DYN2040_PRI_CH_S 4
+#define AR_PHY_GC_DYN2040_EXT_CH   0x00000020  /* dyn 20/40 - ext ch spacing (0=20MHz/ 1=25MHz) */
+#define AR_PHY_GC_HT_EN            0x00000040  /* ht enable */
+#define AR_PHY_GC_SHORT_GI_40      0x00000080  /* allow short GI for HT 40 */
+#define AR_PHY_GC_WALSH            0x00000100  /* walsh spatial spreading for 2 chains,2 streams TX */
+#define AR_PHY_GC_SINGLE_HT_LTF1   0x00000200  /* single length (4us) 1st HT long training symbol */
+#define AR_PHY_GC_GF_DETECT_EN     0x00000400  /* enable Green Field detection. Only affects rx, not tx */
+#define AR_PHY_GC_ENABLE_DAC_FIFO  0x00000800  /* fifo between bb and dac */
+#define AR_PHY_RX_DELAY_DELAY      0x00003FFF  /* delay from wakeup to rx ena */
+
+#define AR_PHY_CALMODE_IQ           0x00000000
+#define AR_PHY_CALMODE_ADC_GAIN     0x00000001
+#define AR_PHY_CALMODE_ADC_DC_PER   0x00000002
+#define AR_PHY_CALMODE_ADC_DC_INIT  0x00000003
+#define AR_PHY_SWAP_ALT_CHAIN       0x00000040
+#define AR_PHY_MODE_OFDM            0x00000000
+#define AR_PHY_MODE_CCK             0x00000001
+#define AR_PHY_MODE_DYNAMIC         0x00000004
+#define AR_PHY_MODE_DYNAMIC_S       2
+#define AR_PHY_MODE_HALF            0x00000020
+#define AR_PHY_MODE_QUARTER         0x00000040
+#define AR_PHY_MAC_CLK_MODE         0x00000080
+#define AR_PHY_MODE_DYN_CCK_DISABLE 0x00000100
+#define AR_PHY_MODE_SVD_HALF        0x00000200
+#define AR_PHY_ACTIVE_EN    0x00000001
+#define AR_PHY_ACTIVE_DIS   0x00000000
+#define AR_PHY_FORCE_XPA_CFG    0x000000001
+#define AR_PHY_FORCE_XPA_CFG_S  0
+#define AR_PHY_XPA_TIMING_CTL_TX_END_XPAB_OFF    0xFF000000
+#define AR_PHY_XPA_TIMING_CTL_TX_END_XPAB_OFF_S  24
+#define AR_PHY_XPA_TIMING_CTL_TX_END_XPAA_OFF    0x00FF0000
+#define AR_PHY_XPA_TIMING_CTL_TX_END_XPAA_OFF_S  16
+#define AR_PHY_XPA_TIMING_CTL_FRAME_XPAB_ON      0x0000FF00
+#define AR_PHY_XPA_TIMING_CTL_FRAME_XPAB_ON_S    8
+#define AR_PHY_XPA_TIMING_CTL_FRAME_XPAA_ON      0x000000FF
+#define AR_PHY_XPA_TIMING_CTL_FRAME_XPAA_ON_S    0
+#define AR_PHY_TX_END_TO_A2_RX_ON       0x00FF0000
+#define AR_PHY_TX_END_TO_A2_RX_ON_S     16
+#define AR_PHY_TX_END_DATA_START  0x000000FF
+#define AR_PHY_TX_END_DATA_START_S  0
+#define AR_PHY_TX_END_PA_ON       0x0000FF00
+#define AR_PHY_TX_END_PA_ON_S       8
+#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP   0x0000000F
+#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP_S     0
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1    0x000003F0
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1_S  4
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2    0x0000FC00
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2_S  10
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3    0x003F0000
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3_S  16
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4    0x0FC00000
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S  22
+#define AR_PHY_TPCRG1_NUM_PD_GAIN   0x0000c000
+#define AR_PHY_TPCRG1_NUM_PD_GAIN_S 14
+#define AR_PHY_TPCRG1_PD_GAIN_1    0x00030000
+#define AR_PHY_TPCRG1_PD_GAIN_1_S  16
+#define AR_PHY_TPCRG1_PD_GAIN_2    0x000C0000
+#define AR_PHY_TPCRG1_PD_GAIN_2_S  18
+#define AR_PHY_TPCRG1_PD_GAIN_3    0x00300000
+#define AR_PHY_TPCRG1_PD_GAIN_3_S  20
+#define AR_PHY_TPCGR1_FORCED_DAC_GAIN   0x0000003e
+#define AR_PHY_TPCGR1_FORCED_DAC_GAIN_S 1
+#define AR_PHY_TPCGR1_FORCE_DAC_GAIN    0x00000001
+#define AR_PHY_TXGAIN_FORCE               0x00000001
+#define AR_PHY_TXGAIN_FORCE_S		  0
+#define AR_PHY_TXGAIN_FORCED_PADVGNRA     0x00003c00
+#define AR_PHY_TXGAIN_FORCED_PADVGNRA_S   10
+#define AR_PHY_TXGAIN_FORCED_PADVGNRB     0x0003c000
+#define AR_PHY_TXGAIN_FORCED_PADVGNRB_S   14
+#define AR_PHY_TXGAIN_FORCED_PADVGNRD     0x00c00000
+#define AR_PHY_TXGAIN_FORCED_PADVGNRD_S   22
+#define AR_PHY_TXGAIN_FORCED_TXMXRGAIN    0x000003c0
+#define AR_PHY_TXGAIN_FORCED_TXMXRGAIN_S  6
+#define AR_PHY_TXGAIN_FORCED_TXBB1DBGAIN  0x0000000e
+#define AR_PHY_TXGAIN_FORCED_TXBB1DBGAIN_S 1
+
+#define AR_PHY_POWER_TX_RATE1   0x9934
+#define AR_PHY_POWER_TX_RATE2   0x9938
+#define AR_PHY_POWER_TX_RATE_MAX    0x993c
+#define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040
+#define PHY_AGC_CLR             0x10000000
+#define RFSILENT_BB             0x00002000
+#define AR_PHY_CHAN_INFO_GAIN_DIFF_PPM_MASK          0xFFF
+#define AR_PHY_CHAN_INFO_GAIN_DIFF_PPM_SIGNED_BIT    0x800
+#define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT         320
+#define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK         0x0001
+#define AR_PHY_RX_DELAY_DELAY   0x00003FFF
+#define AR_PHY_CCK_TX_CTRL_JAPAN    0x00000010
+#define AR_PHY_SPECTRAL_SCAN_ENABLE         0x00000001
+#define AR_PHY_SPECTRAL_SCAN_ENABLE_S       0
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE         0x00000002
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S       1
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD     0x000000F0
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S   4
+#define AR_PHY_SPECTRAL_SCAN_PERIOD         0x0000FF00
+#define AR_PHY_SPECTRAL_SCAN_PERIOD_S       8
+#define AR_PHY_SPECTRAL_SCAN_COUNT          0x00FF0000
+#define AR_PHY_SPECTRAL_SCAN_COUNT_S        16
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT   0x01000000
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24
+#define AR_PHY_CHANNEL_STATUS_RX_CLEAR      0x00000004
+#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT             0x01fc0000
+#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S                   18
+#define AR_PHY_TX_IQCAL_START_DO_CAL	    0x00000001
+#define AR_PHY_TX_IQCAL_START_DO_CAL_S	    0
+
+#define AR_PHY_TX_IQCAL_STATUS_FAILED    0x00000001
+#define AR_PHY_CALIBRATED_GAINS_0	 0x3e
+#define AR_PHY_CALIBRATED_GAINS_0_S	 1
+
+#define AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE      0x00003fff
+#define AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE_S    0
+#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE      0x0fffc000
+#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE_S    14
+
+#define AR_PHY_65NM_CH0_RXTX4_THERM_ON          0x10000000
+#define AR_PHY_65NM_CH0_RXTX4_THERM_ON_S        28
+
+/*
+ * Channel 1 Register Map
+ */
+#define AR_CHAN1_BASE	0xa800
+
+#define AR_PHY_EXT_CCA_1            (AR_CHAN1_BASE + 0x30)
+#define AR_PHY_TX_PHASE_RAMP_1      (AR_CHAN1_BASE + 0xd0)
+#define AR_PHY_ADC_GAIN_DC_CORR_1   (AR_CHAN1_BASE + 0xd4)
+
+#define AR_PHY_SPUR_REPORT_1        (AR_CHAN1_BASE + 0xa8)
+#define AR_PHY_CHAN_INFO_TAB_1      (AR_CHAN1_BASE + 0x300)
+#define AR_PHY_RX_IQCAL_CORR_B1     (AR_CHAN1_BASE + 0xdc)
+
+/*
+ * Channel 1 Field Definitions
+ */
+#define AR_PHY_CH1_EXT_MINCCA_PWR   0x01FF0000
+#define AR_PHY_CH1_EXT_MINCCA_PWR_S 16
+
+/*
+ * AGC 1 Register Map
+ */
+#define AR_AGC1_BASE	0xae00
+
+#define AR_PHY_FORCEMAX_GAINS_1      (AR_AGC1_BASE + 0x4)
+#define AR_PHY_EXT_ATTEN_CTL_1       (AR_AGC1_BASE + 0x18)
+#define AR_PHY_CCA_1                 (AR_AGC1_BASE + 0x1c)
+#define AR_PHY_CCA_CTRL_1            (AR_AGC1_BASE + 0x20)
+#define AR_PHY_RSSI_1                (AR_AGC1_BASE + 0x180)
+#define AR_PHY_SPUR_CCK_REP_1        (AR_AGC1_BASE + 0x184)
+#define AR_PHY_RX_OCGAIN_2           (AR_AGC1_BASE + 0x200)
+
+/*
+ * AGC 1 Field Definitions
+ */
+#define AR_PHY_CH1_MINCCA_PWR   0x1FF00000
+#define AR_PHY_CH1_MINCCA_PWR_S 20
+
+/*
+ * SM 1 Register Map
+ */
+#define AR_SM1_BASE	0xb200
+
+#define AR_PHY_SWITCH_CHAIN_1    (AR_SM1_BASE + 0x84)
+#define AR_PHY_FCAL_2_1          (AR_SM1_BASE + 0xd0)
+#define AR_PHY_DFT_TONE_CTL_1    (AR_SM1_BASE + 0xd4)
+#define AR_PHY_CL_TAB_1          (AR_SM1_BASE + 0x100)
+#define AR_PHY_CHAN_INFO_GAIN_1  (AR_SM1_BASE + 0x180)
+#define AR_PHY_TPC_4_B1          (AR_SM1_BASE + 0x204)
+#define AR_PHY_TPC_5_B1          (AR_SM1_BASE + 0x208)
+#define AR_PHY_TPC_6_B1          (AR_SM1_BASE + 0x20c)
+#define AR_PHY_TPC_11_B1         (AR_SM1_BASE + 0x220)
+#define AR_PHY_PDADC_TAB_1       (AR_SM1_BASE + 0x240)
+#define AR_PHY_TX_IQCAL_STATUS_B1   (AR_SM1_BASE + 0x48c)
+#define AR_PHY_TX_IQCAL_CORR_COEFF_B1(_i)    (AR_SM_BASE + 0x450 + ((_i) << 2))
+
+/*
+ * Channel 2 Register Map
+ */
+#define AR_CHAN2_BASE	0xb800
+
+#define AR_PHY_EXT_CCA_2            (AR_CHAN2_BASE + 0x30)
+#define AR_PHY_TX_PHASE_RAMP_2      (AR_CHAN2_BASE + 0xd0)
+#define AR_PHY_ADC_GAIN_DC_CORR_2   (AR_CHAN2_BASE + 0xd4)
+
+#define AR_PHY_SPUR_REPORT_2        (AR_CHAN2_BASE + 0xa8)
+#define AR_PHY_CHAN_INFO_TAB_2      (AR_CHAN2_BASE + 0x300)
+#define AR_PHY_RX_IQCAL_CORR_B2     (AR_CHAN2_BASE + 0xdc)
+
+/*
+ * Channel 2 Field Definitions
+ */
+#define AR_PHY_CH2_EXT_MINCCA_PWR   0x01FF0000
+#define AR_PHY_CH2_EXT_MINCCA_PWR_S 16
+/*
+ * AGC 2 Register Map
+ */
+#define AR_AGC2_BASE	0xbe00
+
+#define AR_PHY_FORCEMAX_GAINS_2      (AR_AGC2_BASE + 0x4)
+#define AR_PHY_EXT_ATTEN_CTL_2       (AR_AGC2_BASE + 0x18)
+#define AR_PHY_CCA_2                 (AR_AGC2_BASE + 0x1c)
+#define AR_PHY_CCA_CTRL_2            (AR_AGC2_BASE + 0x20)
+#define AR_PHY_RSSI_2                (AR_AGC2_BASE + 0x180)
+
+/*
+ * AGC 2 Field Definitions
+ */
+#define AR_PHY_CH2_MINCCA_PWR   0x1FF00000
+#define AR_PHY_CH2_MINCCA_PWR_S 20
+
+/*
+ * SM 2 Register Map
+ */
+#define AR_SM2_BASE	0xc200
+
+#define AR_PHY_SWITCH_CHAIN_2    (AR_SM2_BASE + 0x84)
+#define AR_PHY_FCAL_2_2          (AR_SM2_BASE + 0xd0)
+#define AR_PHY_DFT_TONE_CTL_2    (AR_SM2_BASE + 0xd4)
+#define AR_PHY_CL_TAB_2          (AR_SM2_BASE + 0x100)
+#define AR_PHY_CHAN_INFO_GAIN_2  (AR_SM2_BASE + 0x180)
+#define AR_PHY_TPC_4_B2          (AR_SM2_BASE + 0x204)
+#define AR_PHY_TPC_5_B2          (AR_SM2_BASE + 0x208)
+#define AR_PHY_TPC_6_B2          (AR_SM2_BASE + 0x20c)
+#define AR_PHY_TPC_11_B2         (AR_SM2_BASE + 0x220)
+#define AR_PHY_PDADC_TAB_2       (AR_SM2_BASE + 0x240)
+#define AR_PHY_TX_IQCAL_STATUS_B2   (AR_SM2_BASE + 0x48c)
+#define AR_PHY_TX_IQCAL_CORR_COEFF_B2(_i)    (AR_SM2_BASE + 0x450 + ((_i) << 2))
+
+#define AR_PHY_TX_IQCAL_STATUS_B2_FAILED    0x00000001
+
+/*
+ * AGC 3 Register Map
+ */
+#define AR_AGC3_BASE	0xce00
+
+#define AR_PHY_RSSI_3            (AR_AGC3_BASE + 0x180)
+
+/*
+ * Misc helper defines
+ */
+#define AR_PHY_CHAIN_OFFSET     (AR_CHAN1_BASE - AR_CHAN_BASE)
+
+#define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (AR_PHY_ADC_GAIN_DC_CORR_0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_NEW_ADC_DC_GAIN_CORR_9300_10(_i) (AR_PHY_ADC_GAIN_DC_CORR_0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_SWITCH_CHAIN(_i)     (AR_PHY_SWITCH_CHAIN_0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_EXT_ATTEN_CTL(_i)    (AR_PHY_EXT_ATTEN_CTL_0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+
+#define AR_PHY_RXGAIN(_i)           (AR_PHY_FORCEMAX_GAINS_0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_TPCRG5(_i)           (AR_PHY_TPC_5_B0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_PDADC_TAB(_i)        (AR_PHY_PDADC_TAB_0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+
+#define AR_PHY_CAL_MEAS_0(_i)       (AR_PHY_IQ_ADC_MEAS_0_B0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_CAL_MEAS_1(_i)       (AR_PHY_IQ_ADC_MEAS_1_B0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_CAL_MEAS_2(_i)       (AR_PHY_IQ_ADC_MEAS_2_B0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_CAL_MEAS_3(_i)       (AR_PHY_IQ_ADC_MEAS_3_B0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_CAL_MEAS_0_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_0_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_CAL_MEAS_1_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_1_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_CAL_MEAS_2_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_2_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_CAL_MEAS_3_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_3_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
+
+#define AR_PHY_WATCHDOG_NON_IDLE_ENABLE    0x00000001
+#define AR_PHY_WATCHDOG_IDLE_ENABLE        0x00000002
+#define AR_PHY_WATCHDOG_IDLE_MASK          0xFFFF0000
+#define AR_PHY_WATCHDOG_NON_IDLE_MASK      0x0000FFFC
+
+#define AR_PHY_WATCHDOG_RST_ENABLE         0x00000002
+#define AR_PHY_WATCHDOG_IRQ_ENABLE         0x00000004
+#define AR_PHY_WATCHDOG_CNTL2_MASK         0xFFFFFFF9
+
+#define AR_PHY_WATCHDOG_INFO               0x00000007
+#define AR_PHY_WATCHDOG_INFO_S             0
+#define AR_PHY_WATCHDOG_DET_HANG           0x00000008
+#define AR_PHY_WATCHDOG_DET_HANG_S         3
+#define AR_PHY_WATCHDOG_RADAR_SM           0x000000F0
+#define AR_PHY_WATCHDOG_RADAR_SM_S         4
+#define AR_PHY_WATCHDOG_RX_OFDM_SM         0x00000F00
+#define AR_PHY_WATCHDOG_RX_OFDM_SM_S       8
+#define AR_PHY_WATCHDOG_RX_CCK_SM          0x0000F000
+#define AR_PHY_WATCHDOG_RX_CCK_SM_S        12
+#define AR_PHY_WATCHDOG_TX_OFDM_SM         0x000F0000
+#define AR_PHY_WATCHDOG_TX_OFDM_SM_S       16
+#define AR_PHY_WATCHDOG_TX_CCK_SM          0x00F00000
+#define AR_PHY_WATCHDOG_TX_CCK_SM_S        20
+#define AR_PHY_WATCHDOG_AGC_SM             0x0F000000
+#define AR_PHY_WATCHDOG_AGC_SM_S           24
+#define AR_PHY_WATCHDOG_SRCH_SM            0xF0000000
+#define AR_PHY_WATCHDOG_SRCH_SM_S          28
+
+#define AR_PHY_WATCHDOG_STATUS_CLR         0x00000008
+
+/*
+ * PAPRD registers
+ */
+#define AR_PHY_XPA_TIMING_CTL		(AR_SM_BASE + 0x64)
+
+#define AR_PHY_PAPRD_AM2AM		(AR_CHAN_BASE + 0xe4)
+#define AR_PHY_PAPRD_AM2AM_MASK		0x01ffffff
+#define AR_PHY_PAPRD_AM2AM_MASK_S	0
+
+#define AR_PHY_PAPRD_AM2PM		(AR_CHAN_BASE + 0xe8)
+#define AR_PHY_PAPRD_AM2PM_MASK		0x01ffffff
+#define AR_PHY_PAPRD_AM2PM_MASK_S	0
+
+#define AR_PHY_PAPRD_HT40		(AR_CHAN_BASE + 0xec)
+#define AR_PHY_PAPRD_HT40_MASK		0x01ffffff
+#define AR_PHY_PAPRD_HT40_MASK_S	0
+
+#define AR_PHY_PAPRD_CTRL0_B0				(AR_CHAN_BASE + 0xf0)
+#define AR_PHY_PAPRD_CTRL0_B1				(AR_CHAN1_BASE + 0xf0)
+#define AR_PHY_PAPRD_CTRL0_B2				(AR_CHAN2_BASE + 0xf0)
+#define AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE			0x00000001
+#define AR_PHY_PAPRD_CTRL0_PAPRD_ENABLE_S		0
+#define AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK	0x00000002
+#define AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK_S	1
+#define AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH		0xf8000000
+#define AR_PHY_PAPRD_CTRL0_PAPRD_MAG_THRSH_S		27
+
+#define AR_PHY_PAPRD_CTRL1_B0				(AR_CHAN_BASE + 0xf4)
+#define AR_PHY_PAPRD_CTRL1_B1				(AR_CHAN1_BASE + 0xf4)
+#define AR_PHY_PAPRD_CTRL1_B2				(AR_CHAN2_BASE + 0xf4)
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA		0x00000001
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_SCALING_ENA_S	0
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE	0x00000002
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2AM_ENABLE_S	1
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE	0x00000004
+#define AR_PHY_PAPRD_CTRL1_ADAPTIVE_AM2PM_ENABLE_S	2
+#define AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL	0x000001f8
+#define AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL_S	3
+#define AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK	0x0001fe00
+#define AR_PHY_PAPRD_CTRL1_PA_GAIN_SCALE_FACT_MASK_S	9
+#define AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT		0x0ffe0000
+#define AR_PHY_PAPRD_CTRL1_PAPRD_MAG_SCALE_FACT_S	17
+
+#define AR_PHY_PAPRD_TRAINER_CNTL1				(AR_SM_BASE + \
+								 (AR_SREV_9485(ah) ? \
+								  0x580 : 0x490))
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE	0x00000001
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE_S	0
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING	0x0000007e
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING_S	1
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE	0x00000100
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_IQCORR_ENABLE_S	8
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE	0x00000200
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_RX_BB_GAIN_FORCE_S	9
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE	0x00000400
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_TX_GAIN_FORCE_S	10
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE		0x00000800
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_ENABLE_S		11
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP		0x0003f000
+#define AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_LB_SKIP_S		12
+
+#define AR_PHY_PAPRD_TRAINER_CNTL2				(AR_SM_BASE + \
+								 (AR_SREV_9485(ah) ? \
+								  0x584 : 0x494))
+#define AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN	0xFFFFFFFF
+#define AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN_S	0
+
+#define AR_PHY_PAPRD_TRAINER_CNTL3				(AR_SM_BASE + \
+								 (AR_SREV_9485(ah) ? \
+								  0x588 : 0x498))
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE	0x0000003f
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE_S	0
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP		0x00000fc0
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP_S	6
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL	0x0001f000
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL_S	12
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES	0x000e0000
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES_S	17
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN	0x00f00000
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_COARSE_CORR_LEN_S	20
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN	0x0f000000
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN_S	24
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE	0x20000000
+#define AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE_S	29
+
+#define AR_PHY_PAPRD_TRAINER_CNTL4				(AR_SM_BASE + \
+								 (AR_SREV_9485(ah) ? \
+								  0x58c : 0x49c))
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES	0x03ff0000
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_NUM_TRAIN_SAMPLES_S	16
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA	0x0000f000
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_SAFETY_DELTA_S	12
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR		0x00000fff
+#define AR_PHY_PAPRD_TRAINER_CNTL4_CF_PAPRD_MIN_CORR_S		0
+
+#define AR_PHY_PAPRD_PRE_POST_SCALE_0_B0			(AR_CHAN_BASE + 0x100)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_1_B0			(AR_CHAN_BASE + 0x104)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_2_B0			(AR_CHAN_BASE + 0x108)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_3_B0			(AR_CHAN_BASE + 0x10c)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_4_B0			(AR_CHAN_BASE + 0x110)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_5_B0			(AR_CHAN_BASE + 0x114)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_6_B0			(AR_CHAN_BASE + 0x118)
+#define AR_PHY_PAPRD_PRE_POST_SCALE_7_B0			(AR_CHAN_BASE + 0x11c)
+#define AR_PHY_PAPRD_PRE_POST_SCALING				0x3FFFF
+#define AR_PHY_PAPRD_PRE_POST_SCALING_S				0
+
+#define AR_PHY_PAPRD_TRAINER_STAT1				(AR_SM_BASE + 0x4a0)
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE		0x00000001
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_DONE_S		0
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_INCOMPLETE	0x00000002
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_INCOMPLETE_S	1
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_CORR_ERR		0x00000004
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_CORR_ERR_S		2
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_ACTIVE		0x00000008
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_TRAIN_ACTIVE_S		3
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_RX_GAIN_IDX		0x000001f0
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_RX_GAIN_IDX_S		4
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR		0x0001fe00
+#define AR_PHY_PAPRD_TRAINER_STAT1_PAPRD_AGC2_PWR_S		9
+
+#define AR_PHY_PAPRD_TRAINER_STAT2				(AR_SM_BASE + 0x4a4)
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_VAL		0x0000ffff
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_VAL_S		0
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_COARSE_IDX		0x001f0000
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_COARSE_IDX_S		16
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_IDX		0x00600000
+#define AR_PHY_PAPRD_TRAINER_STAT2_PAPRD_FINE_IDX_S		21
+
+#define AR_PHY_PAPRD_TRAINER_STAT3				(AR_SM_BASE + 0x4a8)
+#define AR_PHY_PAPRD_TRAINER_STAT3_PAPRD_TRAIN_SAMPLES_CNT	0x000fffff
+#define AR_PHY_PAPRD_TRAINER_STAT3_PAPRD_TRAIN_SAMPLES_CNT_S	0
+
+#define AR_PHY_PAPRD_MEM_TAB_B0			(AR_CHAN_BASE + 0x120)
+#define AR_PHY_PAPRD_MEM_TAB_B1			(AR_CHAN1_BASE + 0x120)
+#define AR_PHY_PAPRD_MEM_TAB_B2			(AR_CHAN2_BASE + 0x120)
+
+#define AR_PHY_PA_GAIN123_B0			(AR_CHAN_BASE + 0xf8)
+#define AR_PHY_PA_GAIN123_B1			(AR_CHAN1_BASE + 0xf8)
+#define AR_PHY_PA_GAIN123_B2			(AR_CHAN2_BASE + 0xf8)
+#define AR_PHY_PA_GAIN123_PA_GAIN1		0x3FF
+#define AR_PHY_PA_GAIN123_PA_GAIN1_S		0
+
+#define AR_PHY_POWERTX_RATE5			(AR_SM_BASE + 0x1d0)
+#define AR_PHY_POWERTX_RATE5_POWERTXHT20_0	0x3F
+#define AR_PHY_POWERTX_RATE5_POWERTXHT20_0_S	0
+
+#define AR_PHY_POWERTX_RATE6			(AR_SM_BASE + 0x1d4)
+#define AR_PHY_POWERTX_RATE6_POWERTXHT20_5	0x3F00
+#define AR_PHY_POWERTX_RATE6_POWERTXHT20_5_S	8
+
+#define AR_PHY_POWERTX_RATE8			(AR_SM_BASE + 0x1dc)
+#define AR_PHY_POWERTX_RATE8_POWERTXHT40_5	0x3F00
+#define AR_PHY_POWERTX_RATE8_POWERTXHT40_5_S	8
+
+void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
+
+#endif  /* AR9003_PHY_H */
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ar9340_initvals.h b/roms/ipxe/src/drivers/net/ath/ath9k/ar9340_initvals.h
new file mode 100644
index 0000000000000000000000000000000000000000..815a8af1beefd6684f09c29924a586e3f471dcb1
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ar9340_initvals.h
@@ -0,0 +1,1525 @@
+/*
+ * Copyright (c) 2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INITVALS_9340_H
+#define INITVALS_9340_H
+
+static const u32 ar9340_1p0_radio_postamble[][5] = {
+	/*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+	{0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800},
+	{0x0001610c, 0x08000000, 0x08000000, 0x00000000, 0x00000000},
+	{0x00016140, 0x10804000, 0x10804000, 0x50804000, 0x50804000},
+	{0x0001650c, 0x08000000, 0x08000000, 0x00000000, 0x00000000},
+	{0x00016540, 0x10804000, 0x10804000, 0x50804000, 0x50804000},
+};
+
+static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][5] = {
+	/*   Addr     5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
+	{0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402},
+	{0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404},
+	{0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
+	{0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
+	{0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
+	{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
+	{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
+	{0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
+	{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
+	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
+	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
+	{0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
+	{0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
+	{0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83},
+	{0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84},
+	{0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3},
+	{0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5},
+	{0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9},
+	{0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+	{0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402},
+	{0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+	{0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+	{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+	{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+	{0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+	{0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+	{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+	{0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
+	{0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
+	{0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83},
+	{0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84},
+	{0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3},
+	{0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5},
+	{0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9},
+	{0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb},
+	{0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+	{0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+	{0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+	{0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+};
+
+static const u32 ar9340Modes_fast_clock_1p0[][3] = {
+	/*  Addr      5G_HT20     5G_HT40  */
+	{0x00001030, 0x00000268, 0x000004d0},
+	{0x00001070, 0x0000018c, 0x00000318},
+	{0x000010b0, 0x00000fd0, 0x00001fa0},
+	{0x00008014, 0x044c044c, 0x08980898},
+	{0x0000801c, 0x148ec02b, 0x148ec057},
+	{0x00008318, 0x000044c0, 0x00008980},
+	{0x00009e00, 0x03721821, 0x03721821},
+	{0x0000a230, 0x0000000b, 0x00000016},
+	{0x0000a254, 0x00000898, 0x00001130},
+};
+
+static const u32 ar9340_1p0_radio_core[][2] = {
+	/*  Addr     allmodes  */
+	{0x00016000, 0x36db6db6},
+	{0x00016004, 0x6db6db40},
+	{0x00016008, 0x73f00000},
+	{0x0001600c, 0x00000000},
+	{0x00016040, 0x7f80fff8},
+	{0x00016044, 0x03b6d2db},
+	{0x00016048, 0x24925266},
+	{0x0001604c, 0x000f0278},
+	{0x00016050, 0x6db6db6c},
+	{0x00016054, 0x6db60000},
+	{0x00016080, 0x00080000},
+	{0x00016084, 0x0e48048c},
+	{0x00016088, 0x14214514},
+	{0x0001608c, 0x119f081c},
+	{0x00016090, 0x24926490},
+	{0x00016094, 0x00000000},
+	{0x00016098, 0xd411eb84},
+	{0x0001609c, 0x03e47f32},
+	{0x000160a0, 0xc2108ffe},
+	{0x000160a4, 0x812fc370},
+	{0x000160a8, 0x423c8000},
+	{0x000160ac, 0xa4646800},
+	{0x000160b0, 0x00fe7f46},
+	{0x000160b4, 0x92480000},
+	{0x000160c0, 0x006db6db},
+	{0x000160c4, 0x6db6db60},
+	{0x000160c8, 0x6db6db6c},
+	{0x000160cc, 0x6de6db6c},
+	{0x000160d0, 0xb6da4924},
+	{0x00016100, 0x04cb0001},
+	{0x00016104, 0xfff80000},
+	{0x00016108, 0x00080010},
+	{0x0001610c, 0x00000000},
+	{0x00016140, 0x50804008},
+	{0x00016144, 0x01884080},
+	{0x00016148, 0x000080c0},
+	{0x00016280, 0x01000015},
+	{0x00016284, 0x05530000},
+	{0x00016288, 0x00318000},
+	{0x0001628c, 0x50000000},
+	{0x00016290, 0x4080294f},
+	{0x00016380, 0x00000000},
+	{0x00016384, 0x00000000},
+	{0x00016388, 0x00800700},
+	{0x0001638c, 0x00800700},
+	{0x00016390, 0x00800700},
+	{0x00016394, 0x00000000},
+	{0x00016398, 0x00000000},
+	{0x0001639c, 0x00000000},
+	{0x000163a0, 0x00000001},
+	{0x000163a4, 0x00000001},
+	{0x000163a8, 0x00000000},
+	{0x000163ac, 0x00000000},
+	{0x000163b0, 0x00000000},
+	{0x000163b4, 0x00000000},
+	{0x000163b8, 0x00000000},
+	{0x000163bc, 0x00000000},
+	{0x000163c0, 0x000000a0},
+	{0x000163c4, 0x000c0000},
+	{0x000163c8, 0x14021402},
+	{0x000163cc, 0x00001402},
+	{0x000163d0, 0x00000000},
+	{0x000163d4, 0x00000000},
+	{0x00016400, 0x36db6db6},
+	{0x00016404, 0x6db6db40},
+	{0x00016408, 0x73f00000},
+	{0x0001640c, 0x00000000},
+	{0x00016440, 0x7f80fff8},
+	{0x00016444, 0x03b6d2db},
+	{0x00016448, 0x24927266},
+	{0x0001644c, 0x000f0278},
+	{0x00016450, 0x6db6db6c},
+	{0x00016454, 0x6db60000},
+	{0x00016500, 0x04cb0001},
+	{0x00016504, 0xfff80000},
+	{0x00016508, 0x00080010},
+	{0x0001650c, 0x00000000},
+	{0x00016540, 0x50804008},
+	{0x00016544, 0x01884080},
+	{0x00016548, 0x000080c0},
+	{0x00016780, 0x00000000},
+	{0x00016784, 0x00000000},
+	{0x00016788, 0x00800700},
+	{0x0001678c, 0x00800700},
+	{0x00016790, 0x00800700},
+	{0x00016794, 0x00000000},
+	{0x00016798, 0x00000000},
+	{0x0001679c, 0x00000000},
+	{0x000167a0, 0x00000001},
+	{0x000167a4, 0x00000001},
+	{0x000167a8, 0x00000000},
+	{0x000167ac, 0x00000000},
+	{0x000167b0, 0x00000000},
+	{0x000167b4, 0x00000000},
+	{0x000167b8, 0x00000000},
+	{0x000167bc, 0x00000000},
+	{0x000167c0, 0x000000a0},
+	{0x000167c4, 0x000c0000},
+	{0x000167c8, 0x14021402},
+	{0x000167cc, 0x00001402},
+	{0x000167d0, 0x00000000},
+	{0x000167d4, 0x00000000},
+};
+
+static const u32 ar9340_1p0_radio_core_40M[][2] = {
+	{0x0001609c, 0x02566f3a},
+	{0x000160ac, 0xa4647c00},
+	{0x000160b0, 0x01885f5a},
+};
+
+static const u32 ar9340_1p0_mac_postamble[][5] = {
+	/* Addr       5G_HT20     5G_HT40     2G_HT40    2G_HT20  */
+	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
+	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
+	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
+	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
+	{0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
+	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
+	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
+	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
+};
+
+static const u32 ar9340_1p0_soc_postamble[][5] = {
+	/*   Addr     5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+	{0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023},
+};
+
+static const u32 ar9340_1p0_baseband_postamble[][5] = {
+	/*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
+	{0x00009820, 0x206a022e, 0x206a022e, 0x206a022e, 0x206a022e},
+	{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+	{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+	{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+	{0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
+	{0x00009c00, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044},
+	{0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
+	{0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020},
+	{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
+	{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e},
+	{0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
+	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
+	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+	{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
+	{0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
+	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
+	{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+	{0x0000a204, 0x00003fc0, 0x00003fc4, 0x00003fc4, 0x00003fc0},
+	{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+	{0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+	{0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
+	{0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+	{0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+	{0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
+	{0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+	{0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
+	{0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
+	{0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+	{0x0000a288, 0x00000220, 0x00000220, 0x00000110, 0x00000110},
+	{0x0000a28c, 0x00011111, 0x00011111, 0x00022222, 0x00022222},
+	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+	{0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982},
+	{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
+	{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+	{0x0000ae04, 0x00180000, 0x00180000, 0x00180000, 0x00180000},
+	{0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+	{0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+	{0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+};
+
+static const u32 ar9340_1p0_baseband_core[][2] = {
+	/*  Addr     allmodes  */
+	{0x00009800, 0xafe68e30},
+	{0x00009804, 0xfd14e000},
+	{0x00009808, 0x9c0a9f6b},
+	{0x0000980c, 0x04900000},
+	{0x00009814, 0xb280c00a},
+	{0x00009818, 0x00000000},
+	{0x0000981c, 0x00020028},
+	{0x00009834, 0x5f3ca3de},
+	{0x00009838, 0x0108ecff},
+	{0x0000983c, 0x14750600},
+	{0x00009880, 0x201fff00},
+	{0x00009884, 0x00001042},
+	{0x000098a4, 0x00200400},
+	{0x000098b0, 0x52440bbe},
+	{0x000098d0, 0x004b6a8e},
+	{0x000098d4, 0x00000820},
+	{0x000098dc, 0x00000000},
+	{0x000098f0, 0x00000000},
+	{0x000098f4, 0x00000000},
+	{0x00009c04, 0xff55ff55},
+	{0x00009c08, 0x0320ff55},
+	{0x00009c0c, 0x00000000},
+	{0x00009c10, 0x00000000},
+	{0x00009c14, 0x00046384},
+	{0x00009c18, 0x05b6b440},
+	{0x00009c1c, 0x00b6b440},
+	{0x00009d00, 0xc080a333},
+	{0x00009d04, 0x40206c10},
+	{0x00009d08, 0x009c4060},
+	{0x00009d0c, 0x9883800a},
+	{0x00009d10, 0x01834061},
+	{0x00009d14, 0x00c0040b},
+	{0x00009d18, 0x00000000},
+	{0x00009e08, 0x0038230c},
+	{0x00009e24, 0x990bb515},
+	{0x00009e28, 0x0c6f0000},
+	{0x00009e30, 0x06336f77},
+	{0x00009e34, 0x6af6532f},
+	{0x00009e38, 0x0cc80c00},
+	{0x00009e3c, 0xcf946222},
+	{0x00009e40, 0x0d261820},
+	{0x00009e4c, 0x00001004},
+	{0x00009e50, 0x00ff03f1},
+	{0x00009e54, 0x00000000},
+	{0x00009fc0, 0x803e4788},
+	{0x00009fc4, 0x0001efb5},
+	{0x00009fcc, 0x40000014},
+	{0x00009fd0, 0x01193b93},
+	{0x0000a20c, 0x00000000},
+	{0x0000a220, 0x00000000},
+	{0x0000a224, 0x00000000},
+	{0x0000a228, 0x10002310},
+	{0x0000a22c, 0x01036a1e},
+	{0x0000a234, 0x10000fff},
+	{0x0000a23c, 0x00000000},
+	{0x0000a244, 0x0c000000},
+	{0x0000a2a0, 0x00000001},
+	{0x0000a2c0, 0x00000001},
+	{0x0000a2c8, 0x00000000},
+	{0x0000a2cc, 0x18c43433},
+	{0x0000a2d4, 0x00000000},
+	{0x0000a2dc, 0x00000000},
+	{0x0000a2e0, 0x00000000},
+	{0x0000a2e4, 0x00000000},
+	{0x0000a2e8, 0x00000000},
+	{0x0000a2ec, 0x00000000},
+	{0x0000a2f0, 0x00000000},
+	{0x0000a2f4, 0x00000000},
+	{0x0000a2f8, 0x00000000},
+	{0x0000a344, 0x00000000},
+	{0x0000a34c, 0x00000000},
+	{0x0000a350, 0x0000a000},
+	{0x0000a364, 0x00000000},
+	{0x0000a370, 0x00000000},
+	{0x0000a390, 0x00000001},
+	{0x0000a394, 0x00000444},
+	{0x0000a398, 0x001f0e0f},
+	{0x0000a39c, 0x0075393f},
+	{0x0000a3a0, 0xb79f6427},
+	{0x0000a3a4, 0x00000000},
+	{0x0000a3a8, 0xaaaaaaaa},
+	{0x0000a3ac, 0x3c466478},
+	{0x0000a3c0, 0x20202020},
+	{0x0000a3c4, 0x22222220},
+	{0x0000a3c8, 0x20200020},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3d8, 0x20202020},
+	{0x0000a3dc, 0x20202020},
+	{0x0000a3e0, 0x20202020},
+	{0x0000a3e4, 0x20202020},
+	{0x0000a3e8, 0x20202020},
+	{0x0000a3ec, 0x20202020},
+	{0x0000a3f0, 0x00000000},
+	{0x0000a3f4, 0x00000246},
+	{0x0000a3f8, 0x0cdbd380},
+	{0x0000a3fc, 0x000f0f01},
+	{0x0000a400, 0x8fa91f01},
+	{0x0000a404, 0x00000000},
+	{0x0000a408, 0x0e79e5c6},
+	{0x0000a40c, 0x00820820},
+	{0x0000a414, 0x1ce739ce},
+	{0x0000a418, 0x2d001dce},
+	{0x0000a41c, 0x1ce739ce},
+	{0x0000a420, 0x000001ce},
+	{0x0000a424, 0x1ce739ce},
+	{0x0000a428, 0x000001ce},
+	{0x0000a42c, 0x1ce739ce},
+	{0x0000a430, 0x1ce739ce},
+	{0x0000a434, 0x00000000},
+	{0x0000a438, 0x00001801},
+	{0x0000a43c, 0x00000000},
+	{0x0000a440, 0x00000000},
+	{0x0000a444, 0x00000000},
+	{0x0000a448, 0x04000080},
+	{0x0000a44c, 0x00000001},
+	{0x0000a450, 0x00010000},
+	{0x0000a458, 0x00000000},
+	{0x0000a600, 0x00000000},
+	{0x0000a604, 0x00000000},
+	{0x0000a608, 0x00000000},
+	{0x0000a60c, 0x00000000},
+	{0x0000a610, 0x00000000},
+	{0x0000a614, 0x00000000},
+	{0x0000a618, 0x00000000},
+	{0x0000a61c, 0x00000000},
+	{0x0000a620, 0x00000000},
+	{0x0000a624, 0x00000000},
+	{0x0000a628, 0x00000000},
+	{0x0000a62c, 0x00000000},
+	{0x0000a630, 0x00000000},
+	{0x0000a634, 0x00000000},
+	{0x0000a638, 0x00000000},
+	{0x0000a63c, 0x00000000},
+	{0x0000a640, 0x00000000},
+	{0x0000a644, 0x3fad9d74},
+	{0x0000a648, 0x0048060a},
+	{0x0000a64c, 0x00000637},
+	{0x0000a670, 0x03020100},
+	{0x0000a674, 0x09080504},
+	{0x0000a678, 0x0d0c0b0a},
+	{0x0000a67c, 0x13121110},
+	{0x0000a680, 0x31301514},
+	{0x0000a684, 0x35343332},
+	{0x0000a688, 0x00000036},
+	{0x0000a690, 0x00000838},
+	{0x0000a7c0, 0x00000000},
+	{0x0000a7c4, 0xfffffffc},
+	{0x0000a7c8, 0x00000000},
+	{0x0000a7cc, 0x00000000},
+	{0x0000a7d0, 0x00000000},
+	{0x0000a7d4, 0x00000004},
+	{0x0000a7dc, 0x00000000},
+	{0x0000a8d0, 0x004b6a8e},
+	{0x0000a8d4, 0x00000820},
+	{0x0000a8dc, 0x00000000},
+	{0x0000a8f0, 0x00000000},
+	{0x0000a8f4, 0x00000000},
+	{0x0000b2d0, 0x00000080},
+	{0x0000b2d4, 0x00000000},
+	{0x0000b2dc, 0x00000000},
+	{0x0000b2e0, 0x00000000},
+	{0x0000b2e4, 0x00000000},
+	{0x0000b2e8, 0x00000000},
+	{0x0000b2ec, 0x00000000},
+	{0x0000b2f0, 0x00000000},
+	{0x0000b2f4, 0x00000000},
+	{0x0000b2f8, 0x00000000},
+	{0x0000b408, 0x0e79e5c0},
+	{0x0000b40c, 0x00820820},
+	{0x0000b420, 0x00000000},
+};
+
+static const u32 ar9340Modes_high_power_tx_gain_table_1p0[][5] = {
+	/*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
+	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
+	{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
+	{0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
+	{0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
+	{0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
+	{0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
+	{0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
+	{0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
+	{0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
+	{0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
+	{0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
+	{0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
+	{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
+	{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
+	{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
+	{0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
+	{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
+	{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
+	{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
+	{0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
+	{0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
+	{0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
+	{0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
+	{0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
+	{0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
+	{0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
+	{0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
+	{0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
+	{0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
+	{0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
+	{0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
+	{0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
+	{0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
+	{0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
+	{0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
+	{0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
+	{0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
+	{0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
+	{0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
+	{0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
+	{0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
+	{0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
+	{0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+	{0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+	{0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+	{0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+};
+
+static const u32 ar9340Modes_high_ob_db_tx_gain_table_1p0[][5] = {
+	/*  Addr       5G_HT20    5G_HT40     2G_HT40     2G_HT20  */
+	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
+	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
+	{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
+	{0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
+	{0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
+	{0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
+	{0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
+	{0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
+	{0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
+	{0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
+	{0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
+	{0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
+	{0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
+	{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
+	{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
+	{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
+	{0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
+	{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
+	{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
+	{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
+	{0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
+	{0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
+	{0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
+	{0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
+	{0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
+	{0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
+	{0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
+	{0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
+	{0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
+	{0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
+	{0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
+	{0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
+	{0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
+	{0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
+	{0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
+	{0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
+	{0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
+	{0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
+	{0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
+	{0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
+	{0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
+	{0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
+	{0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
+	{0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x00016044, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4},
+	{0x00016048, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266},
+	{0x00016444, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4},
+	{0x00016448, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266},
+};
+static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = {
+	/*  Addr      5G_HT20      5G_HT40     2G_HT40    2G_HT20  */
+	{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
+	{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
+	{0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400},
+	{0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402},
+	{0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404},
+	{0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603},
+	{0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02},
+	{0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04},
+	{0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20},
+	{0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20},
+	{0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22},
+	{0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24},
+	{0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640},
+	{0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660},
+	{0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861},
+	{0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81},
+	{0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
+	{0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84},
+	{0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3},
+	{0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5},
+	{0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9},
+	{0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb},
+	{0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec},
+	{0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
+	{0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002},
+	{0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400},
+	{0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402},
+	{0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603},
+	{0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02},
+	{0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04},
+	{0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20},
+	{0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20},
+	{0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22},
+	{0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24},
+	{0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640},
+	{0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660},
+	{0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861},
+	{0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81},
+	{0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83},
+	{0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84},
+	{0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3},
+	{0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5},
+	{0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9},
+	{0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb},
+	{0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec},
+	{0x00016044, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db},
+	{0x00016048, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266},
+	{0x00016444, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db},
+	{0x00016448, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266},
+};
+
+
+static const u32 ar9340Common_rx_gain_table_1p0[][2] = {
+	/*   Addr     allmodes */
+	{0x0000a000, 0x00010000},
+	{0x0000a004, 0x00030002},
+	{0x0000a008, 0x00050004},
+	{0x0000a00c, 0x00810080},
+	{0x0000a010, 0x00830082},
+	{0x0000a014, 0x01810180},
+	{0x0000a018, 0x01830182},
+	{0x0000a01c, 0x01850184},
+	{0x0000a020, 0x01890188},
+	{0x0000a024, 0x018b018a},
+	{0x0000a028, 0x018d018c},
+	{0x0000a02c, 0x01910190},
+	{0x0000a030, 0x01930192},
+	{0x0000a034, 0x01950194},
+	{0x0000a038, 0x038a0196},
+	{0x0000a03c, 0x038c038b},
+	{0x0000a040, 0x0390038d},
+	{0x0000a044, 0x03920391},
+	{0x0000a048, 0x03940393},
+	{0x0000a04c, 0x03960395},
+	{0x0000a050, 0x00000000},
+	{0x0000a054, 0x00000000},
+	{0x0000a058, 0x00000000},
+	{0x0000a05c, 0x00000000},
+	{0x0000a060, 0x00000000},
+	{0x0000a064, 0x00000000},
+	{0x0000a068, 0x00000000},
+	{0x0000a06c, 0x00000000},
+	{0x0000a070, 0x00000000},
+	{0x0000a074, 0x00000000},
+	{0x0000a078, 0x00000000},
+	{0x0000a07c, 0x00000000},
+	{0x0000a080, 0x22222229},
+	{0x0000a084, 0x1d1d1d1d},
+	{0x0000a088, 0x1d1d1d1d},
+	{0x0000a08c, 0x1d1d1d1d},
+	{0x0000a090, 0x171d1d1d},
+	{0x0000a094, 0x11111717},
+	{0x0000a098, 0x00030311},
+	{0x0000a09c, 0x00000000},
+	{0x0000a0a0, 0x00000000},
+	{0x0000a0a4, 0x00000000},
+	{0x0000a0a8, 0x00000000},
+	{0x0000a0ac, 0x00000000},
+	{0x0000a0b0, 0x00000000},
+	{0x0000a0b4, 0x00000000},
+	{0x0000a0b8, 0x00000000},
+	{0x0000a0bc, 0x00000000},
+	{0x0000a0c0, 0x001f0000},
+	{0x0000a0c4, 0x01000101},
+	{0x0000a0c8, 0x011e011f},
+	{0x0000a0cc, 0x011c011d},
+	{0x0000a0d0, 0x02030204},
+	{0x0000a0d4, 0x02010202},
+	{0x0000a0d8, 0x021f0200},
+	{0x0000a0dc, 0x0302021e},
+	{0x0000a0e0, 0x03000301},
+	{0x0000a0e4, 0x031e031f},
+	{0x0000a0e8, 0x0402031d},
+	{0x0000a0ec, 0x04000401},
+	{0x0000a0f0, 0x041e041f},
+	{0x0000a0f4, 0x0502041d},
+	{0x0000a0f8, 0x05000501},
+	{0x0000a0fc, 0x051e051f},
+	{0x0000a100, 0x06010602},
+	{0x0000a104, 0x061f0600},
+	{0x0000a108, 0x061d061e},
+	{0x0000a10c, 0x07020703},
+	{0x0000a110, 0x07000701},
+	{0x0000a114, 0x00000000},
+	{0x0000a118, 0x00000000},
+	{0x0000a11c, 0x00000000},
+	{0x0000a120, 0x00000000},
+	{0x0000a124, 0x00000000},
+	{0x0000a128, 0x00000000},
+	{0x0000a12c, 0x00000000},
+	{0x0000a130, 0x00000000},
+	{0x0000a134, 0x00000000},
+	{0x0000a138, 0x00000000},
+	{0x0000a13c, 0x00000000},
+	{0x0000a140, 0x001f0000},
+	{0x0000a144, 0x01000101},
+	{0x0000a148, 0x011e011f},
+	{0x0000a14c, 0x011c011d},
+	{0x0000a150, 0x02030204},
+	{0x0000a154, 0x02010202},
+	{0x0000a158, 0x021f0200},
+	{0x0000a15c, 0x0302021e},
+	{0x0000a160, 0x03000301},
+	{0x0000a164, 0x031e031f},
+	{0x0000a168, 0x0402031d},
+	{0x0000a16c, 0x04000401},
+	{0x0000a170, 0x041e041f},
+	{0x0000a174, 0x0502041d},
+	{0x0000a178, 0x05000501},
+	{0x0000a17c, 0x051e051f},
+	{0x0000a180, 0x06010602},
+	{0x0000a184, 0x061f0600},
+	{0x0000a188, 0x061d061e},
+	{0x0000a18c, 0x07020703},
+	{0x0000a190, 0x07000701},
+	{0x0000a194, 0x00000000},
+	{0x0000a198, 0x00000000},
+	{0x0000a19c, 0x00000000},
+	{0x0000a1a0, 0x00000000},
+	{0x0000a1a4, 0x00000000},
+	{0x0000a1a8, 0x00000000},
+	{0x0000a1ac, 0x00000000},
+	{0x0000a1b0, 0x00000000},
+	{0x0000a1b4, 0x00000000},
+	{0x0000a1b8, 0x00000000},
+	{0x0000a1bc, 0x00000000},
+	{0x0000a1c0, 0x00000000},
+	{0x0000a1c4, 0x00000000},
+	{0x0000a1c8, 0x00000000},
+	{0x0000a1cc, 0x00000000},
+	{0x0000a1d0, 0x00000000},
+	{0x0000a1d4, 0x00000000},
+	{0x0000a1d8, 0x00000000},
+	{0x0000a1dc, 0x00000000},
+	{0x0000a1e0, 0x00000000},
+	{0x0000a1e4, 0x00000000},
+	{0x0000a1e8, 0x00000000},
+	{0x0000a1ec, 0x00000000},
+	{0x0000a1f0, 0x00000396},
+	{0x0000a1f4, 0x00000396},
+	{0x0000a1f8, 0x00000396},
+	{0x0000a1fc, 0x00000196},
+	{0x0000b000, 0x00010000},
+	{0x0000b004, 0x00030002},
+	{0x0000b008, 0x00050004},
+	{0x0000b00c, 0x00810080},
+	{0x0000b010, 0x00830082},
+	{0x0000b014, 0x01810180},
+	{0x0000b018, 0x01830182},
+	{0x0000b01c, 0x01850184},
+	{0x0000b020, 0x02810280},
+	{0x0000b024, 0x02830282},
+	{0x0000b028, 0x02850284},
+	{0x0000b02c, 0x02890288},
+	{0x0000b030, 0x028b028a},
+	{0x0000b034, 0x0388028c},
+	{0x0000b038, 0x038a0389},
+	{0x0000b03c, 0x038c038b},
+	{0x0000b040, 0x0390038d},
+	{0x0000b044, 0x03920391},
+	{0x0000b048, 0x03940393},
+	{0x0000b04c, 0x03960395},
+	{0x0000b050, 0x00000000},
+	{0x0000b054, 0x00000000},
+	{0x0000b058, 0x00000000},
+	{0x0000b05c, 0x00000000},
+	{0x0000b060, 0x00000000},
+	{0x0000b064, 0x00000000},
+	{0x0000b068, 0x00000000},
+	{0x0000b06c, 0x00000000},
+	{0x0000b070, 0x00000000},
+	{0x0000b074, 0x00000000},
+	{0x0000b078, 0x00000000},
+	{0x0000b07c, 0x00000000},
+	{0x0000b080, 0x32323232},
+	{0x0000b084, 0x2f2f3232},
+	{0x0000b088, 0x23282a2d},
+	{0x0000b08c, 0x1c1e2123},
+	{0x0000b090, 0x14171919},
+	{0x0000b094, 0x0e0e1214},
+	{0x0000b098, 0x03050707},
+	{0x0000b09c, 0x00030303},
+	{0x0000b0a0, 0x00000000},
+	{0x0000b0a4, 0x00000000},
+	{0x0000b0a8, 0x00000000},
+	{0x0000b0ac, 0x00000000},
+	{0x0000b0b0, 0x00000000},
+	{0x0000b0b4, 0x00000000},
+	{0x0000b0b8, 0x00000000},
+	{0x0000b0bc, 0x00000000},
+	{0x0000b0c0, 0x003f0020},
+	{0x0000b0c4, 0x00400041},
+	{0x0000b0c8, 0x0140005f},
+	{0x0000b0cc, 0x0160015f},
+	{0x0000b0d0, 0x017e017f},
+	{0x0000b0d4, 0x02410242},
+	{0x0000b0d8, 0x025f0240},
+	{0x0000b0dc, 0x027f0260},
+	{0x0000b0e0, 0x0341027e},
+	{0x0000b0e4, 0x035f0340},
+	{0x0000b0e8, 0x037f0360},
+	{0x0000b0ec, 0x04400441},
+	{0x0000b0f0, 0x0460045f},
+	{0x0000b0f4, 0x0541047f},
+	{0x0000b0f8, 0x055f0540},
+	{0x0000b0fc, 0x057f0560},
+	{0x0000b100, 0x06400641},
+	{0x0000b104, 0x0660065f},
+	{0x0000b108, 0x067e067f},
+	{0x0000b10c, 0x07410742},
+	{0x0000b110, 0x075f0740},
+	{0x0000b114, 0x077f0760},
+	{0x0000b118, 0x07800781},
+	{0x0000b11c, 0x07a0079f},
+	{0x0000b120, 0x07c107bf},
+	{0x0000b124, 0x000007c0},
+	{0x0000b128, 0x00000000},
+	{0x0000b12c, 0x00000000},
+	{0x0000b130, 0x00000000},
+	{0x0000b134, 0x00000000},
+	{0x0000b138, 0x00000000},
+	{0x0000b13c, 0x00000000},
+	{0x0000b140, 0x003f0020},
+	{0x0000b144, 0x00400041},
+	{0x0000b148, 0x0140005f},
+	{0x0000b14c, 0x0160015f},
+	{0x0000b150, 0x017e017f},
+	{0x0000b154, 0x02410242},
+	{0x0000b158, 0x025f0240},
+	{0x0000b15c, 0x027f0260},
+	{0x0000b160, 0x0341027e},
+	{0x0000b164, 0x035f0340},
+	{0x0000b168, 0x037f0360},
+	{0x0000b16c, 0x04400441},
+	{0x0000b170, 0x0460045f},
+	{0x0000b174, 0x0541047f},
+	{0x0000b178, 0x055f0540},
+	{0x0000b17c, 0x057f0560},
+	{0x0000b180, 0x06400641},
+	{0x0000b184, 0x0660065f},
+	{0x0000b188, 0x067e067f},
+	{0x0000b18c, 0x07410742},
+	{0x0000b190, 0x075f0740},
+	{0x0000b194, 0x077f0760},
+	{0x0000b198, 0x07800781},
+	{0x0000b19c, 0x07a0079f},
+	{0x0000b1a0, 0x07c107bf},
+	{0x0000b1a4, 0x000007c0},
+	{0x0000b1a8, 0x00000000},
+	{0x0000b1ac, 0x00000000},
+	{0x0000b1b0, 0x00000000},
+	{0x0000b1b4, 0x00000000},
+	{0x0000b1b8, 0x00000000},
+	{0x0000b1bc, 0x00000000},
+	{0x0000b1c0, 0x00000000},
+	{0x0000b1c4, 0x00000000},
+	{0x0000b1c8, 0x00000000},
+	{0x0000b1cc, 0x00000000},
+	{0x0000b1d0, 0x00000000},
+	{0x0000b1d4, 0x00000000},
+	{0x0000b1d8, 0x00000000},
+	{0x0000b1dc, 0x00000000},
+	{0x0000b1e0, 0x00000000},
+	{0x0000b1e4, 0x00000000},
+	{0x0000b1e8, 0x00000000},
+	{0x0000b1ec, 0x00000000},
+	{0x0000b1f0, 0x00000396},
+	{0x0000b1f4, 0x00000396},
+	{0x0000b1f8, 0x00000396},
+	{0x0000b1fc, 0x00000196},
+};
+
+static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = {
+	/*  Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20  */
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
+	{0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402},
+	{0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404},
+	{0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
+	{0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
+	{0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
+	{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
+	{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
+	{0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
+	{0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
+	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
+	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
+	{0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
+	{0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
+	{0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83},
+	{0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84},
+	{0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3},
+	{0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5},
+	{0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9},
+	{0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+	{0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402},
+	{0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+	{0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+	{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+	{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+	{0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+	{0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+	{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+	{0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
+	{0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
+	{0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83},
+	{0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84},
+	{0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3},
+	{0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5},
+	{0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9},
+	{0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb},
+	{0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+	{0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+	{0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+	{0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+	{0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+};
+
+static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = {
+	/*  Addr       5G_HT20     5G_HT40     2G_HT40    2G_HT20  */
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+	{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+	{0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+	{0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400},
+	{0x0000a518, 0x21020220, 0x21020220, 0x15000402, 0x15000402},
+	{0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404},
+	{0x0000a520, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603},
+	{0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02},
+	{0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04},
+	{0x0000a52c, 0x3a02222a, 0x3a02222a, 0x26000a20, 0x26000a20},
+	{0x0000a530, 0x3e02222c, 0x3e02222c, 0x2a000e20, 0x2a000e20},
+	{0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22},
+	{0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24},
+	{0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640},
+	{0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660},
+	{0x0000a544, 0x5302266c, 0x5302266c, 0x3b001861, 0x3b001861},
+	{0x0000a548, 0x5702286c, 0x5702286c, 0x3e001a81, 0x3e001a81},
+	{0x0000a54c, 0x5c04286b, 0x5c04286b, 0x42001a83, 0x42001a83},
+	{0x0000a550, 0x61042a6c, 0x61042a6c, 0x44001c84, 0x44001c84},
+	{0x0000a554, 0x66062a6c, 0x66062a6c, 0x48001ce3, 0x48001ce3},
+	{0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x4c001ce5, 0x4c001ce5},
+	{0x0000a55c, 0x7006308c, 0x7006308c, 0x50001ce9, 0x50001ce9},
+	{0x0000a560, 0x730a308a, 0x730a308a, 0x54001ceb, 0x54001ceb},
+	{0x0000a564, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+	{0x0000a568, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+	{0x0000a56c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+	{0x0000a570, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+	{0x0000a574, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+	{0x0000a578, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+	{0x0000a57c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+	{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+	{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+	{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+	{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+	{0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+	{0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400},
+	{0x0000a598, 0x21820220, 0x21820220, 0x15800402, 0x15800402},
+	{0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404},
+	{0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603},
+	{0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02},
+	{0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04},
+	{0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20},
+	{0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20},
+	{0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22},
+	{0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24},
+	{0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640},
+	{0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660},
+	{0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b801861, 0x3b801861},
+	{0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e801a81, 0x3e801a81},
+	{0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42801a83, 0x42801a83},
+	{0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x44801c84, 0x44801c84},
+	{0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x48801ce3, 0x48801ce3},
+	{0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c801ce5, 0x4c801ce5},
+	{0x0000a5dc, 0x7086308c, 0x7086308c, 0x50801ce9, 0x50801ce9},
+	{0x0000a5e0, 0x738a308a, 0x738a308a, 0x54801ceb, 0x54801ceb},
+	{0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+	{0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+	{0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+	{0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+	{0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+	{0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+	{0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+	{0x00016044, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4},
+	{0x00016048, 0x24927266, 0x24927266, 0x8e483266, 0x8e483266},
+	{0x00016444, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4},
+	{0x00016448, 0x24927266, 0x24927266, 0x8e482266, 0x8e482266},
+};
+
+static const u32 ar9340_1p0_mac_core[][2] = {
+	/*    Addr        allmodes        */
+	{0x00000008, 0x00000000},
+	{0x00000030, 0x00020085},
+	{0x00000034, 0x00000005},
+	{0x00000040, 0x00000000},
+	{0x00000044, 0x00000000},
+	{0x00000048, 0x00000008},
+	{0x0000004c, 0x00000010},
+	{0x00000050, 0x00000000},
+	{0x00001040, 0x002ffc0f},
+	{0x00001044, 0x002ffc0f},
+	{0x00001048, 0x002ffc0f},
+	{0x0000104c, 0x002ffc0f},
+	{0x00001050, 0x002ffc0f},
+	{0x00001054, 0x002ffc0f},
+	{0x00001058, 0x002ffc0f},
+	{0x0000105c, 0x002ffc0f},
+	{0x00001060, 0x002ffc0f},
+	{0x00001064, 0x002ffc0f},
+	{0x000010f0, 0x00000100},
+	{0x00001270, 0x00000000},
+	{0x000012b0, 0x00000000},
+	{0x000012f0, 0x00000000},
+	{0x0000143c, 0x00000000},
+	{0x0000147c, 0x00000000},
+	{0x00008000, 0x00000000},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000000},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008040, 0x00000000},
+	{0x00008044, 0x00000000},
+	{0x00008048, 0x00000000},
+	{0x0000804c, 0xffffffff},
+	{0x00008054, 0x00000000},
+	{0x00008058, 0x00000000},
+	{0x0000805c, 0x000fc78f},
+	{0x00008060, 0x0000000f},
+	{0x00008064, 0x00000000},
+	{0x00008070, 0x00000310},
+	{0x00008074, 0x00000020},
+	{0x00008078, 0x00000000},
+	{0x0000809c, 0x0000000f},
+	{0x000080a0, 0x00000000},
+	{0x000080a4, 0x02ff0000},
+	{0x000080a8, 0x0e070605},
+	{0x000080ac, 0x0000000d},
+	{0x000080b0, 0x00000000},
+	{0x000080b4, 0x00000000},
+	{0x000080b8, 0x00000000},
+	{0x000080bc, 0x00000000},
+	{0x000080c0, 0x2a800000},
+	{0x000080c4, 0x06900168},
+	{0x000080c8, 0x13881c20},
+	{0x000080cc, 0x01f40000},
+	{0x000080d0, 0x00252500},
+	{0x000080d4, 0x00a00000},
+	{0x000080d8, 0x00400000},
+	{0x000080dc, 0x00000000},
+	{0x000080e0, 0xffffffff},
+	{0x000080e4, 0x0000ffff},
+	{0x000080e8, 0x3f3f3f3f},
+	{0x000080ec, 0x00000000},
+	{0x000080f0, 0x00000000},
+	{0x000080f4, 0x00000000},
+	{0x000080fc, 0x00020000},
+	{0x00008100, 0x00000000},
+	{0x00008108, 0x00000052},
+	{0x0000810c, 0x00000000},
+	{0x00008110, 0x00000000},
+	{0x00008114, 0x000007ff},
+	{0x00008118, 0x000000aa},
+	{0x0000811c, 0x00003210},
+	{0x00008124, 0x00000000},
+	{0x00008128, 0x00000000},
+	{0x0000812c, 0x00000000},
+	{0x00008130, 0x00000000},
+	{0x00008134, 0x00000000},
+	{0x00008138, 0x00000000},
+	{0x0000813c, 0x0000ffff},
+	{0x00008144, 0xffffffff},
+	{0x00008168, 0x00000000},
+	{0x0000816c, 0x00000000},
+	{0x00008170, 0x18486200},
+	{0x00008174, 0x33332210},
+	{0x00008178, 0x00000000},
+	{0x0000817c, 0x00020000},
+	{0x000081c0, 0x00000000},
+	{0x000081c4, 0x33332210},
+	{0x000081c8, 0x00000000},
+	{0x000081cc, 0x00000000},
+	{0x000081d4, 0x00000000},
+	{0x000081ec, 0x00000000},
+	{0x000081f0, 0x00000000},
+	{0x000081f4, 0x00000000},
+	{0x000081f8, 0x00000000},
+	{0x000081fc, 0x00000000},
+	{0x00008240, 0x00100000},
+	{0x00008244, 0x0010f424},
+	{0x00008248, 0x00000800},
+	{0x0000824c, 0x0001e848},
+	{0x00008250, 0x00000000},
+	{0x00008254, 0x00000000},
+	{0x00008258, 0x00000000},
+	{0x0000825c, 0x40000000},
+	{0x00008260, 0x00080922},
+	{0x00008264, 0x9d400010},
+	{0x00008268, 0xffffffff},
+	{0x0000826c, 0x0000ffff},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000004},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x000000ff},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x0000829c, 0x00000000},
+	{0x00008300, 0x00000140},
+	{0x00008314, 0x00000000},
+	{0x0000831c, 0x0000010d},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000007},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000700},
+	{0x00008338, 0x00ff0000},
+	{0x0000833c, 0x02400000},
+	{0x00008340, 0x000107ff},
+	{0x00008344, 0xaa48105b},
+	{0x00008348, 0x008f0000},
+	{0x0000835c, 0x00000000},
+	{0x00008360, 0xffffffff},
+	{0x00008364, 0xffffffff},
+	{0x00008368, 0x00000000},
+	{0x00008370, 0x00000000},
+	{0x00008374, 0x000000ff},
+	{0x00008378, 0x00000000},
+	{0x0000837c, 0x00000000},
+	{0x00008380, 0xffffffff},
+	{0x00008384, 0xffffffff},
+	{0x00008390, 0xffffffff},
+	{0x00008394, 0xffffffff},
+	{0x00008398, 0x00000000},
+	{0x0000839c, 0x00000000},
+	{0x000083a0, 0x00000000},
+	{0x000083a4, 0x0000fa14},
+	{0x000083a8, 0x000f0c00},
+	{0x000083ac, 0x33332210},
+	{0x000083b0, 0x33332210},
+	{0x000083b4, 0x33332210},
+	{0x000083b8, 0x33332210},
+	{0x000083bc, 0x00000000},
+	{0x000083c0, 0x00000000},
+	{0x000083c4, 0x00000000},
+	{0x000083c8, 0x00000000},
+	{0x000083cc, 0x00000200},
+	{0x000083d0, 0x000301ff},
+};
+
+static const u32 ar9340Common_wo_xlna_rx_gain_table_1p0[][2] = {
+	/*    Addr        allmodes        */
+	{0x0000a000, 0x00010000},
+	{0x0000a004, 0x00030002},
+	{0x0000a008, 0x00050004},
+	{0x0000a00c, 0x00810080},
+	{0x0000a010, 0x00830082},
+	{0x0000a014, 0x01810180},
+	{0x0000a018, 0x01830182},
+	{0x0000a01c, 0x01850184},
+	{0x0000a020, 0x01890188},
+	{0x0000a024, 0x018b018a},
+	{0x0000a028, 0x018d018c},
+	{0x0000a02c, 0x03820190},
+	{0x0000a030, 0x03840383},
+	{0x0000a034, 0x03880385},
+	{0x0000a038, 0x038a0389},
+	{0x0000a03c, 0x038c038b},
+	{0x0000a040, 0x0390038d},
+	{0x0000a044, 0x03920391},
+	{0x0000a048, 0x03940393},
+	{0x0000a04c, 0x03960395},
+	{0x0000a050, 0x00000000},
+	{0x0000a054, 0x00000000},
+	{0x0000a058, 0x00000000},
+	{0x0000a05c, 0x00000000},
+	{0x0000a060, 0x00000000},
+	{0x0000a064, 0x00000000},
+	{0x0000a068, 0x00000000},
+	{0x0000a06c, 0x00000000},
+	{0x0000a070, 0x00000000},
+	{0x0000a074, 0x00000000},
+	{0x0000a078, 0x00000000},
+	{0x0000a07c, 0x00000000},
+	{0x0000a080, 0x29292929},
+	{0x0000a084, 0x29292929},
+	{0x0000a088, 0x29292929},
+	{0x0000a08c, 0x29292929},
+	{0x0000a090, 0x22292929},
+	{0x0000a094, 0x1d1d2222},
+	{0x0000a098, 0x0c111117},
+	{0x0000a09c, 0x00030303},
+	{0x0000a0a0, 0x00000000},
+	{0x0000a0a4, 0x00000000},
+	{0x0000a0a8, 0x00000000},
+	{0x0000a0ac, 0x00000000},
+	{0x0000a0b0, 0x00000000},
+	{0x0000a0b4, 0x00000000},
+	{0x0000a0b8, 0x00000000},
+	{0x0000a0bc, 0x00000000},
+	{0x0000a0c0, 0x001f0000},
+	{0x0000a0c4, 0x01000101},
+	{0x0000a0c8, 0x011e011f},
+	{0x0000a0cc, 0x011c011d},
+	{0x0000a0d0, 0x02030204},
+	{0x0000a0d4, 0x02010202},
+	{0x0000a0d8, 0x021f0200},
+	{0x0000a0dc, 0x0302021e},
+	{0x0000a0e0, 0x03000301},
+	{0x0000a0e4, 0x031e031f},
+	{0x0000a0e8, 0x0402031d},
+	{0x0000a0ec, 0x04000401},
+	{0x0000a0f0, 0x041e041f},
+	{0x0000a0f4, 0x0502041d},
+	{0x0000a0f8, 0x05000501},
+	{0x0000a0fc, 0x051e051f},
+	{0x0000a100, 0x06010602},
+	{0x0000a104, 0x061f0600},
+	{0x0000a108, 0x061d061e},
+	{0x0000a10c, 0x07020703},
+	{0x0000a110, 0x07000701},
+	{0x0000a114, 0x00000000},
+	{0x0000a118, 0x00000000},
+	{0x0000a11c, 0x00000000},
+	{0x0000a120, 0x00000000},
+	{0x0000a124, 0x00000000},
+	{0x0000a128, 0x00000000},
+	{0x0000a12c, 0x00000000},
+	{0x0000a130, 0x00000000},
+	{0x0000a134, 0x00000000},
+	{0x0000a138, 0x00000000},
+	{0x0000a13c, 0x00000000},
+	{0x0000a140, 0x001f0000},
+	{0x0000a144, 0x01000101},
+	{0x0000a148, 0x011e011f},
+	{0x0000a14c, 0x011c011d},
+	{0x0000a150, 0x02030204},
+	{0x0000a154, 0x02010202},
+	{0x0000a158, 0x021f0200},
+	{0x0000a15c, 0x0302021e},
+	{0x0000a160, 0x03000301},
+	{0x0000a164, 0x031e031f},
+	{0x0000a168, 0x0402031d},
+	{0x0000a16c, 0x04000401},
+	{0x0000a170, 0x041e041f},
+	{0x0000a174, 0x0502041d},
+	{0x0000a178, 0x05000501},
+	{0x0000a17c, 0x051e051f},
+	{0x0000a180, 0x06010602},
+	{0x0000a184, 0x061f0600},
+	{0x0000a188, 0x061d061e},
+	{0x0000a18c, 0x07020703},
+	{0x0000a190, 0x07000701},
+	{0x0000a194, 0x00000000},
+	{0x0000a198, 0x00000000},
+	{0x0000a19c, 0x00000000},
+	{0x0000a1a0, 0x00000000},
+	{0x0000a1a4, 0x00000000},
+	{0x0000a1a8, 0x00000000},
+	{0x0000a1ac, 0x00000000},
+	{0x0000a1b0, 0x00000000},
+	{0x0000a1b4, 0x00000000},
+	{0x0000a1b8, 0x00000000},
+	{0x0000a1bc, 0x00000000},
+	{0x0000a1c0, 0x00000000},
+	{0x0000a1c4, 0x00000000},
+	{0x0000a1c8, 0x00000000},
+	{0x0000a1cc, 0x00000000},
+	{0x0000a1d0, 0x00000000},
+	{0x0000a1d4, 0x00000000},
+	{0x0000a1d8, 0x00000000},
+	{0x0000a1dc, 0x00000000},
+	{0x0000a1e0, 0x00000000},
+	{0x0000a1e4, 0x00000000},
+	{0x0000a1e8, 0x00000000},
+	{0x0000a1ec, 0x00000000},
+	{0x0000a1f0, 0x00000396},
+	{0x0000a1f4, 0x00000396},
+	{0x0000a1f8, 0x00000396},
+	{0x0000a1fc, 0x00000196},
+	{0x0000b000, 0x00010000},
+	{0x0000b004, 0x00030002},
+	{0x0000b008, 0x00050004},
+	{0x0000b00c, 0x00810080},
+	{0x0000b010, 0x00830082},
+	{0x0000b014, 0x01810180},
+	{0x0000b018, 0x01830182},
+	{0x0000b01c, 0x01850184},
+	{0x0000b020, 0x02810280},
+	{0x0000b024, 0x02830282},
+	{0x0000b028, 0x02850284},
+	{0x0000b02c, 0x02890288},
+	{0x0000b030, 0x028b028a},
+	{0x0000b034, 0x0388028c},
+	{0x0000b038, 0x038a0389},
+	{0x0000b03c, 0x038c038b},
+	{0x0000b040, 0x0390038d},
+	{0x0000b044, 0x03920391},
+	{0x0000b048, 0x03940393},
+	{0x0000b04c, 0x03960395},
+	{0x0000b050, 0x00000000},
+	{0x0000b054, 0x00000000},
+	{0x0000b058, 0x00000000},
+	{0x0000b05c, 0x00000000},
+	{0x0000b060, 0x00000000},
+	{0x0000b064, 0x00000000},
+	{0x0000b068, 0x00000000},
+	{0x0000b06c, 0x00000000},
+	{0x0000b070, 0x00000000},
+	{0x0000b074, 0x00000000},
+	{0x0000b078, 0x00000000},
+	{0x0000b07c, 0x00000000},
+	{0x0000b080, 0x32323232},
+	{0x0000b084, 0x2f2f3232},
+	{0x0000b088, 0x23282a2d},
+	{0x0000b08c, 0x1c1e2123},
+	{0x0000b090, 0x14171919},
+	{0x0000b094, 0x0e0e1214},
+	{0x0000b098, 0x03050707},
+	{0x0000b09c, 0x00030303},
+	{0x0000b0a0, 0x00000000},
+	{0x0000b0a4, 0x00000000},
+	{0x0000b0a8, 0x00000000},
+	{0x0000b0ac, 0x00000000},
+	{0x0000b0b0, 0x00000000},
+	{0x0000b0b4, 0x00000000},
+	{0x0000b0b8, 0x00000000},
+	{0x0000b0bc, 0x00000000},
+	{0x0000b0c0, 0x003f0020},
+	{0x0000b0c4, 0x00400041},
+	{0x0000b0c8, 0x0140005f},
+	{0x0000b0cc, 0x0160015f},
+	{0x0000b0d0, 0x017e017f},
+	{0x0000b0d4, 0x02410242},
+	{0x0000b0d8, 0x025f0240},
+	{0x0000b0dc, 0x027f0260},
+	{0x0000b0e0, 0x0341027e},
+	{0x0000b0e4, 0x035f0340},
+	{0x0000b0e8, 0x037f0360},
+	{0x0000b0ec, 0x04400441},
+	{0x0000b0f0, 0x0460045f},
+	{0x0000b0f4, 0x0541047f},
+	{0x0000b0f8, 0x055f0540},
+	{0x0000b0fc, 0x057f0560},
+	{0x0000b100, 0x06400641},
+	{0x0000b104, 0x0660065f},
+	{0x0000b108, 0x067e067f},
+	{0x0000b10c, 0x07410742},
+	{0x0000b110, 0x075f0740},
+	{0x0000b114, 0x077f0760},
+	{0x0000b118, 0x07800781},
+	{0x0000b11c, 0x07a0079f},
+	{0x0000b120, 0x07c107bf},
+	{0x0000b124, 0x000007c0},
+	{0x0000b128, 0x00000000},
+	{0x0000b12c, 0x00000000},
+	{0x0000b130, 0x00000000},
+	{0x0000b134, 0x00000000},
+	{0x0000b138, 0x00000000},
+	{0x0000b13c, 0x00000000},
+	{0x0000b140, 0x003f0020},
+	{0x0000b144, 0x00400041},
+	{0x0000b148, 0x0140005f},
+	{0x0000b14c, 0x0160015f},
+	{0x0000b150, 0x017e017f},
+	{0x0000b154, 0x02410242},
+	{0x0000b158, 0x025f0240},
+	{0x0000b15c, 0x027f0260},
+	{0x0000b160, 0x0341027e},
+	{0x0000b164, 0x035f0340},
+	{0x0000b168, 0x037f0360},
+	{0x0000b16c, 0x04400441},
+	{0x0000b170, 0x0460045f},
+	{0x0000b174, 0x0541047f},
+	{0x0000b178, 0x055f0540},
+	{0x0000b17c, 0x057f0560},
+	{0x0000b180, 0x06400641},
+	{0x0000b184, 0x0660065f},
+	{0x0000b188, 0x067e067f},
+	{0x0000b18c, 0x07410742},
+	{0x0000b190, 0x075f0740},
+	{0x0000b194, 0x077f0760},
+	{0x0000b198, 0x07800781},
+	{0x0000b19c, 0x07a0079f},
+	{0x0000b1a0, 0x07c107bf},
+	{0x0000b1a4, 0x000007c0},
+	{0x0000b1a8, 0x00000000},
+	{0x0000b1ac, 0x00000000},
+	{0x0000b1b0, 0x00000000},
+	{0x0000b1b4, 0x00000000},
+	{0x0000b1b8, 0x00000000},
+	{0x0000b1bc, 0x00000000},
+	{0x0000b1c0, 0x00000000},
+	{0x0000b1c4, 0x00000000},
+	{0x0000b1c8, 0x00000000},
+	{0x0000b1cc, 0x00000000},
+	{0x0000b1d0, 0x00000000},
+	{0x0000b1d4, 0x00000000},
+	{0x0000b1d8, 0x00000000},
+	{0x0000b1dc, 0x00000000},
+	{0x0000b1e0, 0x00000000},
+	{0x0000b1e4, 0x00000000},
+	{0x0000b1e8, 0x00000000},
+	{0x0000b1ec, 0x00000000},
+	{0x0000b1f0, 0x00000396},
+	{0x0000b1f4, 0x00000396},
+	{0x0000b1f8, 0x00000396},
+	{0x0000b1fc, 0x00000196},
+};
+
+static const u32 ar9340_1p0_soc_preamble[][2] = {
+	/*    Addr        allmodes        */
+	{0x000040a4, 0x00a0c1c9},
+	{0x00007008, 0x00000000},
+	{0x00007020, 0x00000000},
+	{0x00007034, 0x00000002},
+	{0x00007038, 0x000004c2},
+};
+
+#endif
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ar9485_initvals.h b/roms/ipxe/src/drivers/net/ath/ath9k/ar9485_initvals.h
new file mode 100644
index 0000000000000000000000000000000000000000..611ea6ce8508dfb760a1172ea46793e6716c48e3
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ar9485_initvals.h
@@ -0,0 +1,1161 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INITVALS_9485_H
+#define INITVALS_9485_H
+
+static const u32 ar9485_1_1_mac_core[][2] = {
+	/*  Addr       allmodes */
+	{0x00000008, 0x00000000},
+	{0x00000030, 0x00020085},
+	{0x00000034, 0x00000005},
+	{0x00000040, 0x00000000},
+	{0x00000044, 0x00000000},
+	{0x00000048, 0x00000008},
+	{0x0000004c, 0x00000010},
+	{0x00000050, 0x00000000},
+	{0x00001040, 0x002ffc0f},
+	{0x00001044, 0x002ffc0f},
+	{0x00001048, 0x002ffc0f},
+	{0x0000104c, 0x002ffc0f},
+	{0x00001050, 0x002ffc0f},
+	{0x00001054, 0x002ffc0f},
+	{0x00001058, 0x002ffc0f},
+	{0x0000105c, 0x002ffc0f},
+	{0x00001060, 0x002ffc0f},
+	{0x00001064, 0x002ffc0f},
+	{0x000010f0, 0x00000100},
+	{0x00001270, 0x00000000},
+	{0x000012b0, 0x00000000},
+	{0x000012f0, 0x00000000},
+	{0x0000143c, 0x00000000},
+	{0x0000147c, 0x00000000},
+	{0x00008000, 0x00000000},
+	{0x00008004, 0x00000000},
+	{0x00008008, 0x00000000},
+	{0x0000800c, 0x00000000},
+	{0x00008018, 0x00000000},
+	{0x00008020, 0x00000000},
+	{0x00008038, 0x00000000},
+	{0x0000803c, 0x00000000},
+	{0x00008040, 0x00000000},
+	{0x00008044, 0x00000000},
+	{0x00008048, 0x00000000},
+	{0x0000804c, 0xffffffff},
+	{0x00008054, 0x00000000},
+	{0x00008058, 0x00000000},
+	{0x0000805c, 0x000fc78f},
+	{0x00008060, 0x0000000f},
+	{0x00008064, 0x00000000},
+	{0x00008070, 0x00000310},
+	{0x00008074, 0x00000020},
+	{0x00008078, 0x00000000},
+	{0x0000809c, 0x0000000f},
+	{0x000080a0, 0x00000000},
+	{0x000080a4, 0x02ff0000},
+	{0x000080a8, 0x0e070605},
+	{0x000080ac, 0x0000000d},
+	{0x000080b0, 0x00000000},
+	{0x000080b4, 0x00000000},
+	{0x000080b8, 0x00000000},
+	{0x000080bc, 0x00000000},
+	{0x000080c0, 0x2a800000},
+	{0x000080c4, 0x06900168},
+	{0x000080c8, 0x13881c22},
+	{0x000080cc, 0x01f40000},
+	{0x000080d0, 0x00252500},
+	{0x000080d4, 0x00a00000},
+	{0x000080d8, 0x00400000},
+	{0x000080dc, 0x00000000},
+	{0x000080e0, 0xffffffff},
+	{0x000080e4, 0x0000ffff},
+	{0x000080e8, 0x3f3f3f3f},
+	{0x000080ec, 0x00000000},
+	{0x000080f0, 0x00000000},
+	{0x000080f4, 0x00000000},
+	{0x000080fc, 0x00020000},
+	{0x00008100, 0x00000000},
+	{0x00008108, 0x00000052},
+	{0x0000810c, 0x00000000},
+	{0x00008110, 0x00000000},
+	{0x00008114, 0x000007ff},
+	{0x00008118, 0x000000aa},
+	{0x0000811c, 0x00003210},
+	{0x00008124, 0x00000000},
+	{0x00008128, 0x00000000},
+	{0x0000812c, 0x00000000},
+	{0x00008130, 0x00000000},
+	{0x00008134, 0x00000000},
+	{0x00008138, 0x00000000},
+	{0x0000813c, 0x0000ffff},
+	{0x00008144, 0xffffffff},
+	{0x00008168, 0x00000000},
+	{0x0000816c, 0x00000000},
+	{0x00008170, 0x18486200},
+	{0x00008174, 0x33332210},
+	{0x00008178, 0x00000000},
+	{0x0000817c, 0x00020000},
+	{0x000081c0, 0x00000000},
+	{0x000081c4, 0x33332210},
+	{0x000081d4, 0x00000000},
+	{0x000081ec, 0x00000000},
+	{0x000081f0, 0x00000000},
+	{0x000081f4, 0x00000000},
+	{0x000081f8, 0x00000000},
+	{0x000081fc, 0x00000000},
+	{0x00008240, 0x00100000},
+	{0x00008244, 0x0010f400},
+	{0x00008248, 0x00000800},
+	{0x0000824c, 0x0001e800},
+	{0x00008250, 0x00000000},
+	{0x00008254, 0x00000000},
+	{0x00008258, 0x00000000},
+	{0x0000825c, 0x40000000},
+	{0x00008260, 0x00080922},
+	{0x00008264, 0x9ca00010},
+	{0x00008268, 0xffffffff},
+	{0x0000826c, 0x0000ffff},
+	{0x00008270, 0x00000000},
+	{0x00008274, 0x40000000},
+	{0x00008278, 0x003e4180},
+	{0x0000827c, 0x00000004},
+	{0x00008284, 0x0000002c},
+	{0x00008288, 0x0000002c},
+	{0x0000828c, 0x000000ff},
+	{0x00008294, 0x00000000},
+	{0x00008298, 0x00000000},
+	{0x0000829c, 0x00000000},
+	{0x00008300, 0x00000140},
+	{0x00008314, 0x00000000},
+	{0x0000831c, 0x0000010d},
+	{0x00008328, 0x00000000},
+	{0x0000832c, 0x00000007},
+	{0x00008330, 0x00000302},
+	{0x00008334, 0x00000700},
+	{0x00008338, 0x00ff0000},
+	{0x0000833c, 0x02400000},
+	{0x00008340, 0x000107ff},
+	{0x00008344, 0xa248105b},
+	{0x00008348, 0x008f0000},
+	{0x0000835c, 0x00000000},
+	{0x00008360, 0xffffffff},
+	{0x00008364, 0xffffffff},
+	{0x00008368, 0x00000000},
+	{0x00008370, 0x00000000},
+	{0x00008374, 0x000000ff},
+	{0x00008378, 0x00000000},
+	{0x0000837c, 0x00000000},
+	{0x00008380, 0xffffffff},
+	{0x00008384, 0xffffffff},
+	{0x00008390, 0xffffffff},
+	{0x00008394, 0xffffffff},
+	{0x00008398, 0x00000000},
+	{0x0000839c, 0x00000000},
+	{0x000083a0, 0x00000000},
+	{0x000083a4, 0x0000fa14},
+	{0x000083a8, 0x000f0c00},
+	{0x000083ac, 0x33332210},
+	{0x000083b0, 0x33332210},
+	{0x000083b4, 0x33332210},
+	{0x000083b8, 0x33332210},
+	{0x000083bc, 0x00000000},
+	{0x000083c0, 0x00000000},
+	{0x000083c4, 0x00000000},
+	{0x000083c8, 0x00000000},
+	{0x000083cc, 0x00000200},
+	{0x000083d0, 0x000301ff},
+};
+
+static const u32 ar9485_1_1_baseband_core[][2] = {
+	/* Addr       allmodes */
+	{0x00009800, 0xafe68e30},
+	{0x00009804, 0xfd14e000},
+	{0x00009808, 0x9c0a8f6b},
+	{0x0000980c, 0x04800000},
+	{0x00009814, 0x9280c00a},
+	{0x00009818, 0x00000000},
+	{0x0000981c, 0x00020028},
+	{0x00009834, 0x5f3ca3de},
+	{0x00009838, 0x0108ecff},
+	{0x0000983c, 0x14750600},
+	{0x00009880, 0x201fff00},
+	{0x00009884, 0x00001042},
+	{0x000098a4, 0x00200400},
+	{0x000098b0, 0x52440bbe},
+	{0x000098d0, 0x004b6a8e},
+	{0x000098d4, 0x00000820},
+	{0x000098dc, 0x00000000},
+	{0x000098f0, 0x00000000},
+	{0x000098f4, 0x00000000},
+	{0x00009c04, 0x00000000},
+	{0x00009c08, 0x03200000},
+	{0x00009c0c, 0x00000000},
+	{0x00009c10, 0x00000000},
+	{0x00009c14, 0x00046384},
+	{0x00009c18, 0x05b6b440},
+	{0x00009c1c, 0x00b6b440},
+	{0x00009d00, 0xc080a333},
+	{0x00009d04, 0x40206c10},
+	{0x00009d08, 0x009c4060},
+	{0x00009d0c, 0x1883800a},
+	{0x00009d10, 0x01834061},
+	{0x00009d14, 0x00c00400},
+	{0x00009d18, 0x00000000},
+	{0x00009d1c, 0x00000000},
+	{0x00009e08, 0x0038233c},
+	{0x00009e24, 0x9927b515},
+	{0x00009e28, 0x12ef0200},
+	{0x00009e30, 0x06336f77},
+	{0x00009e34, 0x6af6532f},
+	{0x00009e38, 0x0cc80c00},
+	{0x00009e40, 0x0d261820},
+	{0x00009e4c, 0x00001004},
+	{0x00009e50, 0x00ff03f1},
+	{0x00009fc0, 0x80be4788},
+	{0x00009fc4, 0x0001efb5},
+	{0x00009fcc, 0x40000014},
+	{0x0000a20c, 0x00000000},
+	{0x0000a210, 0x00000000},
+	{0x0000a220, 0x00000000},
+	{0x0000a224, 0x00000000},
+	{0x0000a228, 0x10002310},
+	{0x0000a23c, 0x00000000},
+	{0x0000a244, 0x0c000000},
+	{0x0000a2a0, 0x00000001},
+	{0x0000a2c0, 0x00000001},
+	{0x0000a2c8, 0x00000000},
+	{0x0000a2cc, 0x18c43433},
+	{0x0000a2d4, 0x00000000},
+	{0x0000a2dc, 0x00000000},
+	{0x0000a2e0, 0x00000000},
+	{0x0000a2e4, 0x00000000},
+	{0x0000a2e8, 0x00000000},
+	{0x0000a2ec, 0x00000000},
+	{0x0000a2f0, 0x00000000},
+	{0x0000a2f4, 0x00000000},
+	{0x0000a2f8, 0x00000000},
+	{0x0000a344, 0x00000000},
+	{0x0000a34c, 0x00000000},
+	{0x0000a350, 0x0000a000},
+	{0x0000a364, 0x00000000},
+	{0x0000a370, 0x00000000},
+	{0x0000a390, 0x00000001},
+	{0x0000a394, 0x00000444},
+	{0x0000a398, 0x001f0e0f},
+	{0x0000a39c, 0x0075393f},
+	{0x0000a3a0, 0xb79f6427},
+	{0x0000a3a4, 0x000000ff},
+	{0x0000a3a8, 0x3b3b3b3b},
+	{0x0000a3ac, 0x2f2f2f2f},
+	{0x0000a3c0, 0x20202020},
+	{0x0000a3c4, 0x22222220},
+	{0x0000a3c8, 0x20200020},
+	{0x0000a3cc, 0x20202020},
+	{0x0000a3d0, 0x20202020},
+	{0x0000a3d4, 0x20202020},
+	{0x0000a3d8, 0x20202020},
+	{0x0000a3dc, 0x20202020},
+	{0x0000a3e0, 0x20202020},
+	{0x0000a3e4, 0x20202020},
+	{0x0000a3e8, 0x20202020},
+	{0x0000a3ec, 0x20202020},
+	{0x0000a3f0, 0x00000000},
+	{0x0000a3f4, 0x00000006},
+	{0x0000a3f8, 0x0cdbd380},
+	{0x0000a3fc, 0x000f0f01},
+	{0x0000a400, 0x8fa91f01},
+	{0x0000a404, 0x00000000},
+	{0x0000a408, 0x0e79e5c6},
+	{0x0000a40c, 0x00820820},
+	{0x0000a414, 0x1ce739cf},
+	{0x0000a418, 0x2d0019ce},
+	{0x0000a41c, 0x1ce739ce},
+	{0x0000a420, 0x000001ce},
+	{0x0000a424, 0x1ce739ce},
+	{0x0000a428, 0x000001ce},
+	{0x0000a42c, 0x1ce739ce},
+	{0x0000a430, 0x1ce739ce},
+	{0x0000a434, 0x00000000},
+	{0x0000a438, 0x00001801},
+	{0x0000a43c, 0x00000000},
+	{0x0000a440, 0x00000000},
+	{0x0000a444, 0x00000000},
+	{0x0000a448, 0x04000000},
+	{0x0000a44c, 0x00000001},
+	{0x0000a450, 0x00010000},
+	{0x0000a5c4, 0xbfad9d74},
+	{0x0000a5c8, 0x0048060a},
+	{0x0000a5cc, 0x00000637},
+	{0x0000a760, 0x03020100},
+	{0x0000a764, 0x09080504},
+	{0x0000a768, 0x0d0c0b0a},
+	{0x0000a76c, 0x13121110},
+	{0x0000a770, 0x31301514},
+	{0x0000a774, 0x35343332},
+	{0x0000a778, 0x00000036},
+	{0x0000a780, 0x00000838},
+	{0x0000a7c0, 0x00000000},
+	{0x0000a7c4, 0xfffffffc},
+	{0x0000a7c8, 0x00000000},
+	{0x0000a7cc, 0x00000000},
+	{0x0000a7d0, 0x00000000},
+	{0x0000a7d4, 0x00000004},
+	{0x0000a7dc, 0x00000000},
+};
+
+static const u32 ar9485Common_1_1[][2] = {
+	/*  Addr      allmodes */
+	{0x00007010, 0x00000022},
+	{0x00007020, 0x00000000},
+	{0x00007034, 0x00000002},
+	{0x00007038, 0x000004c2},
+};
+
+static const u32 ar9485_1_1_baseband_postamble[][5] = {
+	/* Addr       5G_HT20        5G_HT40       2G_HT40       2G_HT20 */
+	{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005},
+	{0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e},
+	{0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+	{0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+	{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+	{0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c},
+	{0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044},
+	{0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
+	{0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020},
+	{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
+	{0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e},
+	{0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
+	{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
+	{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+	{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
+	{0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
+	{0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324},
+	{0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010},
+	{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+	{0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0},
+	{0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+	{0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
+	{0x0000a234, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff},
+	{0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
+	{0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+	{0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+	{0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
+	{0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+	{0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501},
+	{0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+	{0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
+	{0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0},
+	{0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+	{0x0000a2d0, 0x00071981, 0x00071981, 0x00071982, 0x00071982},
+	{0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
+	{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000be04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
+	{0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+};
+
+static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = {
+	/* Addr        5G_HT20       5G_HT40       2G_HT40       2G_HT20 */
+	{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+	{0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
+	{0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
+	{0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
+	{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
+	{0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
+	{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
+	{0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
+	{0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
+	{0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
+	{0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
+	{0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20},
+	{0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21},
+	{0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
+	{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
+	{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
+	{0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
+	{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
+	{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
+	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
+	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
+	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
+	{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
+};
+
+static const u32 ar9485_modes_lowest_ob_db_tx_gain_1_1[][5] = {
+	/* Addr        5G_HT20       5G_HT40       2G_HT40       2G_HT20  */
+	{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+	{0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
+	{0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
+	{0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
+	{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
+	{0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
+	{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
+	{0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
+	{0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
+	{0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
+	{0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
+	{0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20},
+	{0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21},
+	{0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
+	{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
+	{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
+	{0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
+	{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
+	{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
+	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
+	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
+	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
+	{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
+};
+
+static const u32 ar9485_1_1_radio_postamble[][2] = {
+	/* Addr        allmodes */
+	{0x0001609c, 0x0b283f31},
+	{0x000160ac, 0x24611800},
+	{0x000160b0, 0x03284f3e},
+	{0x0001610c, 0x00170000},
+	{0x00016140, 0x10804008},
+};
+
+static const u32 ar9485_1_1_mac_postamble[][5] = {
+	/* Addr        5G_HT20       5G_HT40       2G_HT40       2G_HT20 */
+	{0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
+	{0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
+	{0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
+	{0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
+	{0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
+	{0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
+	{0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
+	{0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
+};
+
+static const u32 ar9485_1_1_radio_core[][2] = {
+	/* Addr        allmodes */
+	{0x00016000, 0x36db6db6},
+	{0x00016004, 0x6db6db40},
+	{0x00016008, 0x73800000},
+	{0x0001600c, 0x00000000},
+	{0x00016040, 0x7f80fff8},
+	{0x0001604c, 0x000f0278},
+	{0x00016050, 0x4db6db8c},
+	{0x00016054, 0x6db60000},
+	{0x00016080, 0x00080000},
+	{0x00016084, 0x0e48048c},
+	{0x00016088, 0x14214514},
+	{0x0001608c, 0x119f081e},
+	{0x00016090, 0x24926490},
+	{0x00016098, 0xd28b3330},
+	{0x000160a0, 0xc2108ffe},
+	{0x000160a4, 0x812fc370},
+	{0x000160a8, 0x423c8000},
+	{0x000160b4, 0x92480040},
+	{0x000160c0, 0x006db6db},
+	{0x000160c4, 0x0186db60},
+	{0x000160c8, 0x6db6db6c},
+	{0x000160cc, 0x6de6fbe0},
+	{0x000160d0, 0xf7dfcf3c},
+	{0x00016100, 0x04cb0001},
+	{0x00016104, 0xfff80015},
+	{0x00016108, 0x00080010},
+	{0x00016144, 0x01884080},
+	{0x00016148, 0x00008040},
+	{0x00016240, 0x08400000},
+	{0x00016244, 0x1bf90f00},
+	{0x00016248, 0x00000000},
+	{0x0001624c, 0x00000000},
+	{0x00016280, 0x01000015},
+	{0x00016284, 0x00d30000},
+	{0x00016288, 0x00318000},
+	{0x0001628c, 0x50000000},
+	{0x00016290, 0x4b96210f},
+	{0x00016380, 0x00000000},
+	{0x00016384, 0x00000000},
+	{0x00016388, 0x00800700},
+	{0x0001638c, 0x00800700},
+	{0x00016390, 0x00800700},
+	{0x00016394, 0x00000000},
+	{0x00016398, 0x00000000},
+	{0x0001639c, 0x00000000},
+	{0x000163a0, 0x00000001},
+	{0x000163a4, 0x00000001},
+	{0x000163a8, 0x00000000},
+	{0x000163ac, 0x00000000},
+	{0x000163b0, 0x00000000},
+	{0x000163b4, 0x00000000},
+	{0x000163b8, 0x00000000},
+	{0x000163bc, 0x00000000},
+	{0x000163c0, 0x000000a0},
+	{0x000163c4, 0x000c0000},
+	{0x000163c8, 0x14021402},
+	{0x000163cc, 0x00001402},
+	{0x000163d0, 0x00000000},
+	{0x000163d4, 0x00000000},
+	{0x00016c40, 0x13188278},
+	{0x00016c44, 0x12000000},
+};
+
+static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_enable_L1[][2] = {
+	/* Addr        allmodes */
+	{0x00018c00, 0x10052e5e},
+	{0x00018c04, 0x000801d8},
+	{0x00018c08, 0x0000080c},
+};
+
+static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
+	/* Addr        5G_HT20       5G_HT40       2G_HT40       2G_HT20 */
+	{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+	{0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
+	{0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
+	{0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
+	{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
+	{0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
+	{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
+	{0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
+	{0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
+	{0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
+	{0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
+	{0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20},
+	{0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21},
+	{0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
+	{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
+	{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
+	{0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
+	{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
+	{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
+	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
+	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
+	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
+	{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
+};
+
+static const u32 ar9485_1_1[][2] = {
+	/* Addr        allmodes */
+	{0x0000a580, 0x00000000},
+	{0x0000a584, 0x00000000},
+	{0x0000a588, 0x00000000},
+	{0x0000a58c, 0x00000000},
+	{0x0000a590, 0x00000000},
+	{0x0000a594, 0x00000000},
+	{0x0000a598, 0x00000000},
+	{0x0000a59c, 0x00000000},
+	{0x0000a5a0, 0x00000000},
+	{0x0000a5a4, 0x00000000},
+	{0x0000a5a8, 0x00000000},
+	{0x0000a5ac, 0x00000000},
+	{0x0000a5b0, 0x00000000},
+	{0x0000a5b4, 0x00000000},
+	{0x0000a5b8, 0x00000000},
+	{0x0000a5bc, 0x00000000},
+};
+
+static const u32 ar9485_modes_green_ob_db_tx_gain_1_1[][5] = {
+	/* Addr        5G_HT20       5G_HT40       2G_HT40       2G_HT20 */
+	{0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+	{0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},
+	{0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006},
+	{0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201},
+	{0x0000a508, 0x0c002e00, 0x0c002e00, 0x06000203, 0x06000203},
+	{0x0000a50c, 0x11062202, 0x11062202, 0x0a000401, 0x0a000401},
+	{0x0000a510, 0x17022e00, 0x17022e00, 0x0e000403, 0x0e000403},
+	{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x12000405, 0x12000405},
+	{0x0000a518, 0x25020ec0, 0x25020ec0, 0x15000604, 0x15000604},
+	{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x18000605, 0x18000605},
+	{0x0000a520, 0x2f001f04, 0x2f001f04, 0x1c000a04, 0x1c000a04},
+	{0x0000a524, 0x35001fc4, 0x35001fc4, 0x21000a06, 0x21000a06},
+	{0x0000a528, 0x3c022f04, 0x3c022f04, 0x29000a24, 0x29000a24},
+	{0x0000a52c, 0x41023e85, 0x41023e85, 0x2f000e21, 0x2f000e21},
+	{0x0000a530, 0x48023ec6, 0x48023ec6, 0x31000e20, 0x31000e20},
+	{0x0000a534, 0x4d023f01, 0x4d023f01, 0x33000e20, 0x33000e20},
+	{0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
+	{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
+	{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
+	{0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
+	{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
+	{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
+	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
+	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
+	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b50c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b510, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b514, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b518, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b51c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b520, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b524, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b528, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
+	{0x0000b52c, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a},
+	{0x0000b530, 0x0000003a, 0x0000003a, 0x0000003a, 0x0000003a},
+	{0x0000b534, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a},
+	{0x0000b538, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b53c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b540, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b544, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b548, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b54c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b550, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b554, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b558, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b55c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b560, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b564, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b568, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b56c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b570, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b574, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b578, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x0000b57c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b},
+	{0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
+	{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
+};
+
+static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = {
+	/* Addr        allmodes */
+	{0x00018c00, 0x10013e5e},
+	{0x00018c04, 0x000801d8},
+	{0x00018c08, 0x0000080c},
+};
+
+static const u32 ar9485_1_1_soc_preamble[][2] = {
+	/* Addr        allmodes */
+	{0x00004014, 0xba280400},
+	{0x00004090, 0x00aa10aa},
+	{0x000040a4, 0x00a0c9c9},
+	{0x00007010, 0x00000022},
+	{0x00007020, 0x00000000},
+	{0x00007034, 0x00000002},
+	{0x00007038, 0x000004c2},
+	{0x00007048, 0x00000002},
+};
+
+static const u32 ar9485_1_1_baseband_core_txfir_coeff_japan_2484[][2] = {
+	/* Addr        allmodes */
+	{0x0000a398, 0x00000000},
+	{0x0000a39c, 0x6f7f0301},
+	{0x0000a3a0, 0xca9228ee},
+};
+
+static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = {
+	/* Addr        5G_HT20       5G_HT40       2G_HT40       2G_HT20  */
+	{0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
+	{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+	{0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
+	{0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
+	{0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
+	{0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
+	{0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
+	{0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
+	{0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
+	{0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
+	{0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
+	{0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
+	{0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
+	{0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
+	{0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20},
+	{0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21},
+	{0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
+	{0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
+	{0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
+	{0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
+	{0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
+	{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
+	{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
+	{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
+	{0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
+	{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+	{0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+	{0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
+	{0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
+};
+
+static const u32 ar9485_fast_clock_1_1_baseband_postamble[][3] = {
+	/* Addr        5G_HT2        5G_HT40  */
+	{0x00009e00, 0x03721821, 0x03721821},
+	{0x0000a230, 0x0000400b, 0x00004016},
+	{0x0000a254, 0x00000898, 0x00001130},
+};
+
+static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = {
+	/* Addr        allmodes  */
+	{0x00018c00, 0x10012e5e},
+	{0x00018c04, 0x000801d8},
+	{0x00018c08, 0x0000080c},
+};
+
+static const u32 ar9485_common_rx_gain_1_1[][2] = {
+	/* Addr        allmodes */
+	{0x0000a000, 0x00010000},
+	{0x0000a004, 0x00030002},
+	{0x0000a008, 0x00050004},
+	{0x0000a00c, 0x00810080},
+	{0x0000a010, 0x01800082},
+	{0x0000a014, 0x01820181},
+	{0x0000a018, 0x01840183},
+	{0x0000a01c, 0x01880185},
+	{0x0000a020, 0x018a0189},
+	{0x0000a024, 0x02850284},
+	{0x0000a028, 0x02890288},
+	{0x0000a02c, 0x03850384},
+	{0x0000a030, 0x03890388},
+	{0x0000a034, 0x038b038a},
+	{0x0000a038, 0x038d038c},
+	{0x0000a03c, 0x03910390},
+	{0x0000a040, 0x03930392},
+	{0x0000a044, 0x03950394},
+	{0x0000a048, 0x00000396},
+	{0x0000a04c, 0x00000000},
+	{0x0000a050, 0x00000000},
+	{0x0000a054, 0x00000000},
+	{0x0000a058, 0x00000000},
+	{0x0000a05c, 0x00000000},
+	{0x0000a060, 0x00000000},
+	{0x0000a064, 0x00000000},
+	{0x0000a068, 0x00000000},
+	{0x0000a06c, 0x00000000},
+	{0x0000a070, 0x00000000},
+	{0x0000a074, 0x00000000},
+	{0x0000a078, 0x00000000},
+	{0x0000a07c, 0x00000000},
+	{0x0000a080, 0x28282828},
+	{0x0000a084, 0x28282828},
+	{0x0000a088, 0x28282828},
+	{0x0000a08c, 0x28282828},
+	{0x0000a090, 0x28282828},
+	{0x0000a094, 0x21212128},
+	{0x0000a098, 0x171c1c1c},
+	{0x0000a09c, 0x02020212},
+	{0x0000a0a0, 0x00000202},
+	{0x0000a0a4, 0x00000000},
+	{0x0000a0a8, 0x00000000},
+	{0x0000a0ac, 0x00000000},
+	{0x0000a0b0, 0x00000000},
+	{0x0000a0b4, 0x00000000},
+	{0x0000a0b8, 0x00000000},
+	{0x0000a0bc, 0x00000000},
+	{0x0000a0c0, 0x001f0000},
+	{0x0000a0c4, 0x111f1100},
+	{0x0000a0c8, 0x111d111e},
+	{0x0000a0cc, 0x111b111c},
+	{0x0000a0d0, 0x22032204},
+	{0x0000a0d4, 0x22012202},
+	{0x0000a0d8, 0x221f2200},
+	{0x0000a0dc, 0x221d221e},
+	{0x0000a0e0, 0x33013302},
+	{0x0000a0e4, 0x331f3300},
+	{0x0000a0e8, 0x4402331e},
+	{0x0000a0ec, 0x44004401},
+	{0x0000a0f0, 0x441e441f},
+	{0x0000a0f4, 0x55015502},
+	{0x0000a0f8, 0x551f5500},
+	{0x0000a0fc, 0x6602551e},
+	{0x0000a100, 0x66006601},
+	{0x0000a104, 0x661e661f},
+	{0x0000a108, 0x7703661d},
+	{0x0000a10c, 0x77017702},
+	{0x0000a110, 0x00007700},
+	{0x0000a114, 0x00000000},
+	{0x0000a118, 0x00000000},
+	{0x0000a11c, 0x00000000},
+	{0x0000a120, 0x00000000},
+	{0x0000a124, 0x00000000},
+	{0x0000a128, 0x00000000},
+	{0x0000a12c, 0x00000000},
+	{0x0000a130, 0x00000000},
+	{0x0000a134, 0x00000000},
+	{0x0000a138, 0x00000000},
+	{0x0000a13c, 0x00000000},
+	{0x0000a140, 0x001f0000},
+	{0x0000a144, 0x111f1100},
+	{0x0000a148, 0x111d111e},
+	{0x0000a14c, 0x111b111c},
+	{0x0000a150, 0x22032204},
+	{0x0000a154, 0x22012202},
+	{0x0000a158, 0x221f2200},
+	{0x0000a15c, 0x221d221e},
+	{0x0000a160, 0x33013302},
+	{0x0000a164, 0x331f3300},
+	{0x0000a168, 0x4402331e},
+	{0x0000a16c, 0x44004401},
+	{0x0000a170, 0x441e441f},
+	{0x0000a174, 0x55015502},
+	{0x0000a178, 0x551f5500},
+	{0x0000a17c, 0x6602551e},
+	{0x0000a180, 0x66006601},
+	{0x0000a184, 0x661e661f},
+	{0x0000a188, 0x7703661d},
+	{0x0000a18c, 0x77017702},
+	{0x0000a190, 0x00007700},
+	{0x0000a194, 0x00000000},
+	{0x0000a198, 0x00000000},
+	{0x0000a19c, 0x00000000},
+	{0x0000a1a0, 0x00000000},
+	{0x0000a1a4, 0x00000000},
+	{0x0000a1a8, 0x00000000},
+	{0x0000a1ac, 0x00000000},
+	{0x0000a1b0, 0x00000000},
+	{0x0000a1b4, 0x00000000},
+	{0x0000a1b8, 0x00000000},
+	{0x0000a1bc, 0x00000000},
+	{0x0000a1c0, 0x00000000},
+	{0x0000a1c4, 0x00000000},
+	{0x0000a1c8, 0x00000000},
+	{0x0000a1cc, 0x00000000},
+	{0x0000a1d0, 0x00000000},
+	{0x0000a1d4, 0x00000000},
+	{0x0000a1d8, 0x00000000},
+	{0x0000a1dc, 0x00000000},
+	{0x0000a1e0, 0x00000000},
+	{0x0000a1e4, 0x00000000},
+	{0x0000a1e8, 0x00000000},
+	{0x0000a1ec, 0x00000000},
+	{0x0000a1f0, 0x00000396},
+	{0x0000a1f4, 0x00000396},
+	{0x0000a1f8, 0x00000396},
+	{0x0000a1fc, 0x00000296},
+};
+
+static const u32 ar9485_1_1_pcie_phy_clkreq_enable_L1[][2] = {
+	/* Addr        allmodes */
+	{0x00018c00, 0x10053e5e},
+	{0x00018c04, 0x000801d8},
+	{0x00018c08, 0x0000080c},
+};
+
+static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = {
+	/* Addr        allmodes */
+	{0x0000a000, 0x00060005},
+	{0x0000a004, 0x00810080},
+	{0x0000a008, 0x00830082},
+	{0x0000a00c, 0x00850084},
+	{0x0000a010, 0x01820181},
+	{0x0000a014, 0x01840183},
+	{0x0000a018, 0x01880185},
+	{0x0000a01c, 0x018a0189},
+	{0x0000a020, 0x02850284},
+	{0x0000a024, 0x02890288},
+	{0x0000a028, 0x028b028a},
+	{0x0000a02c, 0x03850384},
+	{0x0000a030, 0x03890388},
+	{0x0000a034, 0x038b038a},
+	{0x0000a038, 0x038d038c},
+	{0x0000a03c, 0x03910390},
+	{0x0000a040, 0x03930392},
+	{0x0000a044, 0x03950394},
+	{0x0000a048, 0x00000396},
+	{0x0000a04c, 0x00000000},
+	{0x0000a050, 0x00000000},
+	{0x0000a054, 0x00000000},
+	{0x0000a058, 0x00000000},
+	{0x0000a05c, 0x00000000},
+	{0x0000a060, 0x00000000},
+	{0x0000a064, 0x00000000},
+	{0x0000a068, 0x00000000},
+	{0x0000a06c, 0x00000000},
+	{0x0000a070, 0x00000000},
+	{0x0000a074, 0x00000000},
+	{0x0000a078, 0x00000000},
+	{0x0000a07c, 0x00000000},
+	{0x0000a080, 0x28282828},
+	{0x0000a084, 0x28282828},
+	{0x0000a088, 0x28282828},
+	{0x0000a08c, 0x28282828},
+	{0x0000a090, 0x28282828},
+	{0x0000a094, 0x24242428},
+	{0x0000a098, 0x171e1e1e},
+	{0x0000a09c, 0x02020b0b},
+	{0x0000a0a0, 0x02020202},
+	{0x0000a0a4, 0x00000000},
+	{0x0000a0a8, 0x00000000},
+	{0x0000a0ac, 0x00000000},
+	{0x0000a0b0, 0x00000000},
+	{0x0000a0b4, 0x00000000},
+	{0x0000a0b8, 0x00000000},
+	{0x0000a0bc, 0x00000000},
+	{0x0000a0c0, 0x22072208},
+	{0x0000a0c4, 0x22052206},
+	{0x0000a0c8, 0x22032204},
+	{0x0000a0cc, 0x22012202},
+	{0x0000a0d0, 0x221f2200},
+	{0x0000a0d4, 0x221d221e},
+	{0x0000a0d8, 0x33023303},
+	{0x0000a0dc, 0x33003301},
+	{0x0000a0e0, 0x331e331f},
+	{0x0000a0e4, 0x4402331d},
+	{0x0000a0e8, 0x44004401},
+	{0x0000a0ec, 0x441e441f},
+	{0x0000a0f0, 0x55025503},
+	{0x0000a0f4, 0x55005501},
+	{0x0000a0f8, 0x551e551f},
+	{0x0000a0fc, 0x6602551d},
+	{0x0000a100, 0x66006601},
+	{0x0000a104, 0x661e661f},
+	{0x0000a108, 0x7703661d},
+	{0x0000a10c, 0x77017702},
+	{0x0000a110, 0x00007700},
+	{0x0000a114, 0x00000000},
+	{0x0000a118, 0x00000000},
+	{0x0000a11c, 0x00000000},
+	{0x0000a120, 0x00000000},
+	{0x0000a124, 0x00000000},
+	{0x0000a128, 0x00000000},
+	{0x0000a12c, 0x00000000},
+	{0x0000a130, 0x00000000},
+	{0x0000a134, 0x00000000},
+	{0x0000a138, 0x00000000},
+	{0x0000a13c, 0x00000000},
+	{0x0000a140, 0x001f0000},
+	{0x0000a144, 0x111f1100},
+	{0x0000a148, 0x111d111e},
+	{0x0000a14c, 0x111b111c},
+	{0x0000a150, 0x22032204},
+	{0x0000a154, 0x22012202},
+	{0x0000a158, 0x221f2200},
+	{0x0000a15c, 0x221d221e},
+	{0x0000a160, 0x33013302},
+	{0x0000a164, 0x331f3300},
+	{0x0000a168, 0x4402331e},
+	{0x0000a16c, 0x44004401},
+	{0x0000a170, 0x441e441f},
+	{0x0000a174, 0x55015502},
+	{0x0000a178, 0x551f5500},
+	{0x0000a17c, 0x6602551e},
+	{0x0000a180, 0x66006601},
+	{0x0000a184, 0x661e661f},
+	{0x0000a188, 0x7703661d},
+	{0x0000a18c, 0x77017702},
+	{0x0000a190, 0x00007700},
+	{0x0000a194, 0x00000000},
+	{0x0000a198, 0x00000000},
+	{0x0000a19c, 0x00000000},
+	{0x0000a1a0, 0x00000000},
+	{0x0000a1a4, 0x00000000},
+	{0x0000a1a8, 0x00000000},
+	{0x0000a1ac, 0x00000000},
+	{0x0000a1b0, 0x00000000},
+	{0x0000a1b4, 0x00000000},
+	{0x0000a1b8, 0x00000000},
+	{0x0000a1bc, 0x00000000},
+	{0x0000a1c0, 0x00000000},
+	{0x0000a1c4, 0x00000000},
+	{0x0000a1c8, 0x00000000},
+	{0x0000a1cc, 0x00000000},
+	{0x0000a1d0, 0x00000000},
+	{0x0000a1d4, 0x00000000},
+	{0x0000a1d8, 0x00000000},
+	{0x0000a1dc, 0x00000000},
+	{0x0000a1e0, 0x00000000},
+	{0x0000a1e4, 0x00000000},
+	{0x0000a1e8, 0x00000000},
+	{0x0000a1ec, 0x00000000},
+	{0x0000a1f0, 0x00000396},
+	{0x0000a1f4, 0x00000396},
+	{0x0000a1f8, 0x00000396},
+	{0x0000a1fc, 0x00000296},
+};
+
+#endif
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k.c
new file mode 100644
index 0000000000000000000000000000000000000000..183aa65f681e538e23ab1e19e4788551dbcf4bff
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/pci.h>
+
+#include "ath9k.h"
+
+static struct pci_device_id ath_pci_id_table[] = {
+        PCI_ROM(0x168c, 0x0023, "ar5416", "Atheros 5416 PCI", 0),	/* PCI   */
+        PCI_ROM(0x168c, 0x0024, "ar5416", "Atheros 5416 PCI-E", 0),	/* PCI-E */
+        PCI_ROM(0x168c, 0x0027, "ar9160", "Atheros 9160 PCI", 0),	/* PCI   */
+        PCI_ROM(0x168c, 0x0029, "ar9280", "Atheros 9280 PCI", 0),	/* PCI   */
+        PCI_ROM(0x168c, 0x002A, "ar9280", "Atheros 9280 PCI-E", 0),	/* PCI-E */
+        PCI_ROM(0x168c, 0x002B, "ar9285", "Atheros 9285 PCI-E", 0),	/* PCI-E */
+        PCI_ROM(0x168c, 0x002C, "ar2427", "Atheros 2427 PCI-E", 0),	/* PCI-E 802.11n bonded out */
+        PCI_ROM(0x168c, 0x002D, "ar9287", "Atheros 9287 PCI", 0),	/* PCI   */
+        PCI_ROM(0x168c, 0x002E, "ar9287", "Atheros 9287 PCI-E", 0),	/* PCI-E */
+        PCI_ROM(0x168c, 0x0030, "ar9300", "Atheros 9300 PCI-E", 0),	/* PCI-E  AR9300 */
+        PCI_ROM(0x168c, 0x0032, "ar9485", "Atheros 9485 PCI-E", 0),	/* PCI-E  AR9485 */
+};
+
+
+/* return bus cachesize in 4B word units */
+static void ath_pci_read_cachesize(struct ath_common *common, int *csz)
+{
+	struct ath_softc *sc = (struct ath_softc *) common->priv;
+	u8 u8tmp;
+
+	pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, &u8tmp);
+	*csz = (int)u8tmp;
+
+	/*
+	 * This check was put in to avoid "unpleasant" consequences if
+	 * the bootrom has not fully initialized all PCI devices.
+	 * Sometimes the cache line size register is not set
+	 */
+
+	if (*csz == 0)
+		*csz = DEFAULT_CACHELINE >> 2;   /* Use the default size */
+}
+
+static int ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
+{
+	struct ath_hw *ah = (struct ath_hw *) common->ah;
+
+	common->ops->read(ah, AR5416_EEPROM_OFFSET +
+			      (off << AR5416_EEPROM_S));
+
+	if (!ath9k_hw_wait(ah,
+			   AR_EEPROM_STATUS_DATA,
+			   AR_EEPROM_STATUS_DATA_BUSY |
+			   AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
+			   AH_WAIT_TIMEOUT)) {
+		return 0;
+	}
+
+	*data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA),
+		   AR_EEPROM_STATUS_DATA_VAL);
+
+	return 1;
+}
+
+static void ath_pci_extn_synch_enable(struct ath_common *common)
+{
+	struct ath_softc *sc = (struct ath_softc *) common->priv;
+	struct pci_device *pdev = sc->pdev;
+	u8 lnkctl;
+
+	pci_read_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, &lnkctl);
+	lnkctl |= 0x0080;
+	pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl);
+}
+
+static const struct ath_bus_ops ath_pci_bus_ops = {
+	.ath_bus_type = ATH_PCI,
+	.read_cachesize = ath_pci_read_cachesize,
+	.eeprom_read = ath_pci_eeprom_read,
+	.extn_synch_en = ath_pci_extn_synch_enable,
+};
+
+static int ath_pci_probe(struct pci_device *pdev)
+{
+	void *mem;
+	struct ath_softc *sc;
+	struct net80211_device *dev;
+	u8 csz;
+	u16 subsysid;
+	u32 val;
+	int ret = 0;
+	char hw_name[64];
+
+	adjust_pci_device(pdev);
+
+	/*
+	 * Cache line size is used to size and align various
+	 * structures used to communicate with the hardware.
+	 */
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
+	if (csz == 0) {
+		/*
+		 * Linux 2.4.18 (at least) writes the cache line size
+		 * register as a 16-bit wide register which is wrong.
+		 * We must have this setup properly for rx buffer
+		 * DMA to work so force a reasonable value here if it
+		 * comes up zero.
+		 */
+		csz =16;
+		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
+	}
+	/*
+	 * The default setting of latency timer yields poor results,
+	 * set it to the value used by other systems. It may be worth
+	 * tweaking this setting more.
+	 */
+	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
+
+	/*
+	 * Disable the RETRY_TIMEOUT register (0x41) to keep
+	 * PCI Tx retries from interfering with C3 CPU state.
+	 */
+	pci_read_config_dword(pdev, 0x40, &val);
+	if ((val & 0x0000ff00) != 0)
+		pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+
+	mem = ioremap(pdev->membase, 0x10000);
+	if (!mem) {
+		DBG("ath9K: PCI memory map error\n") ;
+		ret = -EIO;
+		goto err_iomap;
+	}
+
+	dev = net80211_alloc(sizeof(struct ath_softc));
+	if (!dev) {
+		DBG("ath9k: No memory for net80211_device\n");
+		ret = -ENOMEM;
+		goto err_alloc_hw;
+	}
+
+	pci_set_drvdata(pdev, dev);
+	dev->netdev->dev = (struct device *)pdev;
+
+	sc = dev->priv;
+	sc->dev = dev;
+	sc->pdev = pdev;
+	sc->mem = mem;
+
+	/* Will be cleared in ath9k_start() */
+	sc->sc_flags |= SC_OP_INVALID;
+
+	sc->irq = pdev->irq;
+
+	pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid);
+	ret = ath9k_init_device(pdev->device, sc, subsysid, &ath_pci_bus_ops);
+	if (ret) {
+		DBG("ath9k: Failed to initialize device\n");
+		goto err_init;
+	}
+
+	ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name));
+	DBG("ath9k: %s mem=0x%lx, irq=%d\n",
+		   hw_name, (unsigned long)mem, pdev->irq);
+
+	return 0;
+
+err_init:
+	net80211_free(dev);
+err_alloc_hw:
+	iounmap(mem);
+err_iomap:
+	return ret;
+}
+
+static void ath_pci_remove(struct pci_device *pdev)
+{
+	struct net80211_device *dev = pci_get_drvdata(pdev);
+	struct ath_softc *sc = dev->priv;
+	void *mem = sc->mem;
+
+	if (!is_ath9k_unloaded)
+		sc->sc_ah->ah_flags |= AH_UNPLUGGED;
+	ath9k_deinit_device(sc);
+	net80211_free(sc->dev);
+
+	iounmap(mem);
+}
+
+struct pci_driver ath_pci_driver __pci_driver = {
+        .id_count   = ARRAY_SIZE(ath_pci_id_table),
+	.ids        = ath_pci_id_table,
+	.probe      = ath_pci_probe,
+	.remove     = ath_pci_remove,
+};
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k.h b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k.h
new file mode 100644
index 0000000000000000000000000000000000000000..d2dce9b7b0b69c60612f7c5964e9b4d13ef678eb
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k.h
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ATH9K_H
+#define ATH9K_H
+
+#include "common.h"
+
+/*
+ * Header for the ath9k.ko driver core *only* -- hw code nor any other driver
+ * should rely on this file or its contents.
+ */
+
+struct ath_node;
+struct ath_softc;
+
+/* Macro to expand scalars to 64-bit objects */
+
+#define	ito64(x) (sizeof(x) == 1) ?			\
+	(((unsigned long long int)(x)) & (0xff)) :	\
+	(sizeof(x) == 2) ?				\
+	(((unsigned long long int)(x)) & 0xffff) :	\
+	((sizeof(x) == 4) ?				\
+	 (((unsigned long long int)(x)) & 0xffffffff) : \
+	 (unsigned long long int)(x))
+
+/* increment with wrap-around */
+#define INCR(_l, _sz)   do {			\
+		(_l)++;				\
+		(_l) &= ((_sz) - 1);		\
+	} while (0)
+
+/* decrement with wrap-around */
+#define DECR(_l,  _sz)  do {			\
+		(_l)--;				\
+		(_l) &= ((_sz) - 1);		\
+	} while (0)
+
+#define A_MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define TSF_TO_TU(_h,_l) \
+	((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
+
+#define	ATH_TXQ_SETUP(sc, i)        ((sc)->tx.txqsetup & (1<<i))
+
+struct ath_config {
+	u16 txpowlimit;
+	u8 cabqReadytime;
+};
+
+/*************************/
+/* Descriptor Management */
+/*************************/
+
+#define ATH_TXBUF_RESET(_bf) do {				\
+		(_bf)->bf_stale = 0;			\
+		(_bf)->bf_lastbf = NULL;			\
+		(_bf)->bf_next = NULL;				\
+		memset(&((_bf)->bf_state), 0,			\
+		       sizeof(struct ath_buf_state));		\
+	} while (0)
+
+#define ATH_RXBUF_RESET(_bf) do {		\
+		(_bf)->bf_stale = 0;	\
+	} while (0)
+
+/**
+ * enum buffer_type - Buffer type flags
+ *
+ * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX)
+ * @BUF_AGGR: Indicates whether the buffer can be aggregated
+ *	(used in aggregation scheduling)
+ * @BUF_XRETRY: To denote excessive retries of the buffer
+ */
+enum buffer_type {
+	BUF_AMPDU		= BIT(0),
+	BUF_AGGR		= BIT(1),
+	BUF_XRETRY		= BIT(2),
+};
+
+#define bf_isampdu(bf)		(bf->bf_state.bf_type & BUF_AMPDU)
+#define bf_isaggr(bf)		(bf->bf_state.bf_type & BUF_AGGR)
+#define bf_isxretried(bf)	(bf->bf_state.bf_type & BUF_XRETRY)
+
+#define ATH_TXSTATUS_RING_SIZE 64
+
+struct ath_descdma {
+	void *dd_desc;
+	u32 dd_desc_paddr;
+	u32 dd_desc_len;
+	struct ath_buf *dd_bufptr;
+};
+
+int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
+		      struct list_head *head, const char *name,
+		      int nbuf, int ndesc, int is_tx);
+void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
+			 struct list_head *head);
+
+/***********/
+/* RX / TX */
+/***********/
+
+#define ATH_RXBUF               16
+#define ATH_TXBUF               16
+#define ATH_TXBUF_RESERVE       5
+#define ATH_MAX_QDEPTH          (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
+#define ATH_TXMAXTRY            13
+
+#define TID_TO_WME_AC(_tid)				\
+	((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE :	\
+	 (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK :	\
+	 (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI :	\
+	 WME_AC_VO)
+
+#define ATH_AGGR_DELIM_SZ          4
+#define ATH_AGGR_MINPLEN           256 /* in bytes, minimum packet length */
+/* number of delimiters for encryption padding */
+#define ATH_AGGR_ENCRYPTDELIM      10
+/* minimum h/w qdepth to be sustained to maximize aggregation */
+#define ATH_AGGR_MIN_QDEPTH        2
+#define ATH_AMPDU_SUBFRAME_DEFAULT 32
+
+#define FCS_LEN                    4
+#define IEEE80211_SEQ_SEQ_SHIFT    4
+#define IEEE80211_SEQ_MAX          4096
+#define IEEE80211_WEP_IVLEN        3
+#define IEEE80211_WEP_KIDLEN       1
+#define IEEE80211_WEP_CRCLEN       4
+#define IEEE80211_MAX_MPDU_LEN     (3840 + FCS_LEN +		\
+				    (IEEE80211_WEP_IVLEN +	\
+				     IEEE80211_WEP_KIDLEN +	\
+				     IEEE80211_WEP_CRCLEN))
+
+/* return whether a bit at index _n in bitmap _bm is set
+ * _sz is the size of the bitmap  */
+#define ATH_BA_ISSET(_bm, _n)  (((_n) < (WME_BA_BMP_SIZE)) &&		\
+				((_bm)[(_n) >> 5] & (1 << ((_n) & 31))))
+
+/* return block-ack bitmap index given sequence and starting sequence */
+#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1))
+
+/* returns delimiter padding required given the packet length */
+#define ATH_AGGR_GET_NDELIM(_len)					\
+       (((_len) >= ATH_AGGR_MINPLEN) ? 0 :                             \
+        DIV_ROUND_UP(ATH_AGGR_MINPLEN - (_len), ATH_AGGR_DELIM_SZ))
+
+#define BAW_WITHIN(_start, _bawsz, _seqno) \
+	((((_seqno) - (_start)) & 4095) < (_bawsz))
+
+#define ATH_AN_2_TID(_an, _tidno)  (&(_an)->tid[(_tidno)])
+
+#define ATH_TX_COMPLETE_POLL_INT	1000
+
+enum ATH_AGGR_STATUS {
+	ATH_AGGR_DONE,
+	ATH_AGGR_BAW_CLOSED,
+	ATH_AGGR_LIMITED,
+};
+
+#define ATH_TXFIFO_DEPTH 8
+struct ath_txq {
+	int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
+	u32 axq_qnum; /* ath9k hardware queue number */
+	u32 *axq_link;
+	struct list_head axq_q;
+	u32 axq_depth;
+	u32 axq_ampdu_depth;
+	int stopped;
+	int axq_tx_inprogress;
+	struct list_head axq_acq;
+	struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
+	struct list_head txq_fifo_pending;
+	u8 txq_headidx;
+	u8 txq_tailidx;
+	int pending_frames;
+};
+
+struct ath_atx_ac {
+	struct ath_txq *txq;
+	int sched;
+	struct list_head list;
+	struct list_head tid_q;
+	int clear_ps_filter;
+};
+
+struct ath_frame_info {
+	int framelen;
+	u32 keyix;
+	enum ath9k_key_type keytype;
+	u8 retries;
+	u16 seqno;
+};
+
+struct ath_buf_state {
+	u8 bf_type;
+	u8 bfs_paprd;
+	unsigned long bfs_paprd_timestamp;
+};
+
+struct ath_buf {
+	struct list_head list;
+	struct ath_buf *bf_lastbf;	/* last buf of this unit (a frame or
+					   an aggregate) */
+	struct ath_buf *bf_next;	/* next subframe in the aggregate */
+	struct io_buffer *bf_mpdu;	/* enclosing frame structure */
+	void *bf_desc;			/* virtual addr of desc */
+	u32 bf_daddr;			/* physical addr of desc */
+	u32 bf_buf_addr;		/* physical addr of data buffer, for DMA */
+	int bf_stale;
+	u16 bf_flags;
+	struct ath_buf_state bf_state;
+};
+
+struct ath_atx_tid {
+	struct list_head list;
+	struct list_head buf_q;
+	struct ath_node *an;
+	struct ath_atx_ac *ac;
+	unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)];
+	u16 seq_start;
+	u16 seq_next;
+	u16 baw_size;
+	int tidno;
+	int baw_head;   /* first un-acked tx buffer */
+	int baw_tail;   /* next unused tx buffer slot */
+	int sched;
+	int paused;
+	u8 state;
+};
+
+struct ath_node {
+	struct ath_atx_tid tid[WME_NUM_TID];
+	struct ath_atx_ac ac[WME_NUM_AC];
+	int ps_key;
+
+	u16 maxampdu;
+	u8 mpdudensity;
+
+	int sleeping;
+};
+
+#define AGGR_CLEANUP         BIT(1)
+#define AGGR_ADDBA_COMPLETE  BIT(2)
+#define AGGR_ADDBA_PROGRESS  BIT(3)
+
+struct ath_tx_control {
+	struct ath_txq *txq;
+	struct ath_node *an;
+	int if_id;
+	u8 paprd;
+};
+
+#define ATH_TX_ERROR        0x01
+#define ATH_TX_XRETRY       0x02
+#define ATH_TX_BAR          0x04
+
+/**
+ * @txq_map:  Index is mac80211 queue number.  This is
+ *  not necessarily the same as the hardware queue number
+ *  (axq_qnum).
+ */
+struct ath_tx {
+	u16 seq_no;
+	u32 txqsetup;
+	struct list_head txbuf;
+	struct ath_txq txq[ATH9K_NUM_TX_QUEUES];
+	struct ath_descdma txdma;
+	struct ath_txq *txq_map[WME_NUM_AC];
+};
+
+struct ath_rx_edma {
+	struct list_head rx_fifo;
+	struct list_head rx_buffers;
+	u32 rx_fifo_hwsize;
+};
+
+struct ath_rx {
+	u8 defant;
+	u8 rxotherant;
+	u32 *rxlink;
+	unsigned int rxfilter;
+	struct list_head rxbuf;
+	struct ath_descdma rxdma;
+	struct ath_buf *rx_bufptr;
+	struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
+
+	struct io_buffer *frag;
+};
+
+int ath_startrecv(struct ath_softc *sc);
+int ath_stoprecv(struct ath_softc *sc);
+void ath_flushrecv(struct ath_softc *sc);
+u32 ath_calcrxfilter(struct ath_softc *sc);
+int ath_rx_init(struct ath_softc *sc, int nbufs);
+void ath_rx_cleanup(struct ath_softc *sc);
+int ath_rx_tasklet(struct ath_softc *sc, int flush, int hp);
+struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
+void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
+int ath_drain_all_txq(struct ath_softc *sc, int retry_tx);
+void ath_draintxq(struct ath_softc *sc,
+		     struct ath_txq *txq, int retry_tx);
+void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
+int ath_tx_init(struct ath_softc *sc, int nbufs);
+void ath_tx_cleanup(struct ath_softc *sc);
+int ath_txq_update(struct ath_softc *sc, int qnum,
+		   struct ath9k_tx_queue_info *q);
+int ath_tx_start(struct net80211_device *dev, struct io_buffer *iob,
+		 struct ath_tx_control *txctl);
+void ath_tx_tasklet(struct ath_softc *sc);
+
+/*******/
+/* ANI */
+/*******/
+
+#define ATH_STA_SHORT_CALINTERVAL 1000    /* 1 second */
+#define ATH_AP_SHORT_CALINTERVAL  100     /* 100 ms */
+#define ATH_ANI_POLLINTERVAL_OLD  100     /* 100 ms */
+#define ATH_ANI_POLLINTERVAL_NEW  1000    /* 1000 ms */
+#define ATH_LONG_CALINTERVAL_INT  1000    /* 1000 ms */
+#define ATH_LONG_CALINTERVAL      30000   /* 30 seconds */
+#define ATH_RESTART_CALINTERVAL   1200000 /* 20 minutes */
+
+void ath_hw_pll_work(struct ath_softc *sc);
+void ath_ani_calibrate(struct ath_softc *sc);
+
+/********************/
+/* Main driver core */
+/********************/
+
+/*
+ * Default cache line size, in bytes.
+ * Used when PCI device not fully initialized by bootrom/BIOS
+*/
+#define DEFAULT_CACHELINE       32
+#define ATH_REGCLASSIDS_MAX     10
+#define ATH_CABQ_READY_TIME     80      /* % of beacon interval */
+#define ATH_MAX_SW_RETRIES      10
+#define ATH_CHAN_MAX            255
+
+#define ATH_TXPOWER_MAX         100     /* .5 dBm units */
+#define ATH_RATE_DUMMY_MARKER   0
+
+#define SC_OP_INVALID                BIT(0)
+#define SC_OP_BEACONS                BIT(1)
+#define SC_OP_RXAGGR                 BIT(2)
+#define SC_OP_TXAGGR                 BIT(3)
+#define SC_OP_OFFCHANNEL             BIT(4)
+#define SC_OP_PREAMBLE_SHORT         BIT(5)
+#define SC_OP_PROTECT_ENABLE         BIT(6)
+#define SC_OP_RXFLUSH                BIT(7)
+#define SC_OP_LED_ASSOCIATED         BIT(8)
+#define SC_OP_LED_ON                 BIT(9)
+#define SC_OP_TSF_RESET              BIT(11)
+#define SC_OP_BT_PRIORITY_DETECTED   BIT(12)
+#define SC_OP_BT_SCAN		     BIT(13)
+#define SC_OP_ANI_RUN		     BIT(14)
+#define SC_OP_ENABLE_APM	     BIT(15)
+#define SC_OP_PRIM_STA_VIF	     BIT(16)
+
+/* Powersave flags */
+#define PS_WAIT_FOR_BEACON        BIT(0)
+#define PS_WAIT_FOR_CAB           BIT(1)
+#define PS_WAIT_FOR_PSPOLL_DATA   BIT(2)
+#define PS_WAIT_FOR_TX_ACK        BIT(3)
+#define PS_BEACON_SYNC            BIT(4)
+#define PS_TSFOOR_SYNC            BIT(5)
+
+struct ath_rate_table;
+
+struct ath9k_legacy_rate {
+        u16 bitrate;
+        u32 flags;
+        u16 hw_value;
+        u16 hw_value_short;
+};
+
+enum ath9k_rate_control_flags {
+	IEEE80211_TX_RC_USE_RTS_CTS		= BIT(0),
+	IEEE80211_TX_RC_USE_CTS_PROTECT		= BIT(1),
+	IEEE80211_TX_RC_USE_SHORT_PREAMBLE	= BIT(2),
+
+	/* rate index is an MCS rate number instead of an index */
+	IEEE80211_TX_RC_MCS			= BIT(3),
+	IEEE80211_TX_RC_GREEN_FIELD		= BIT(4),
+	IEEE80211_TX_RC_40_MHZ_WIDTH		= BIT(5),
+	IEEE80211_TX_RC_DUP_DATA		= BIT(6),
+	IEEE80211_TX_RC_SHORT_GI		= BIT(7),
+};
+
+struct survey_info {
+	struct net80211_channel *channel;
+	u64 channel_time;
+	u64 channel_time_busy;
+	u64 channel_time_ext_busy;
+	u64 channel_time_rx;
+	u64 channel_time_tx;
+	u32 filled;
+	s8 noise;
+};
+
+enum survey_info_flags {
+	SURVEY_INFO_NOISE_DBM = 1<<0,
+	SURVEY_INFO_IN_USE = 1<<1,
+	SURVEY_INFO_CHANNEL_TIME = 1<<2,
+	SURVEY_INFO_CHANNEL_TIME_BUSY = 1<<3,
+	SURVEY_INFO_CHANNEL_TIME_EXT_BUSY = 1<<4,
+	SURVEY_INFO_CHANNEL_TIME_RX = 1<<5,
+	SURVEY_INFO_CHANNEL_TIME_TX = 1<<6,
+};
+
+struct ath9k_vif_iter_data {
+	const u8 *hw_macaddr; /* phy's hardware address, set
+			       * before starting iteration for
+			       * valid bssid mask.
+			       */
+	u8 mask[ETH_ALEN]; /* bssid mask */
+	int naps;      /* number of AP vifs */
+	int nmeshes;   /* number of mesh vifs */
+	int nstations; /* number of station vifs */
+	int nwds;      /* number of nwd vifs */
+	int nadhocs;   /* number of adhoc vifs */
+	int nothers;   /* number of vifs not specified above. */
+};
+
+struct ath_softc {
+	struct net80211_device *dev;
+	struct pci_device *pdev;
+
+	int chan_idx;
+	int chan_is_ht;
+	struct survey_info *cur_survey;
+	struct survey_info survey[ATH9K_NUM_CHANNELS];
+
+	void (*intr_tq)(struct ath_softc *sc);
+	struct ath_hw *sc_ah;
+	void *mem;
+	int irq;
+
+	void (*paprd_work)(struct ath_softc *sc);
+	void (*hw_check_work)(struct ath_softc *sc);
+	void (*paprd_complete)(struct ath_softc *sc);
+
+	unsigned int hw_busy_count;
+
+	u32 intrstatus;
+	u32 sc_flags; /* SC_OP_* */
+	u16 ps_flags; /* PS_* */
+	u16 curtxpow;
+	int ps_enabled;
+	int ps_idle;
+	short nbcnvifs;
+	short nvifs;
+	unsigned long ps_usecount;
+
+	struct ath_config config;
+	struct ath_rx rx;
+	struct ath_tx tx;
+	struct net80211_hw_info *hwinfo;
+	struct ath9k_legacy_rate rates[NET80211_MAX_RATES];
+	int hw_rix;
+
+	struct ath9k_hw_cal_data caldata;
+	int last_rssi;
+
+	void (*tx_complete_work)(struct ath_softc *sc);
+	unsigned long tx_complete_work_timer;
+	void (*hw_pll_work)(struct ath_softc *sc);
+	unsigned long hw_pll_work_timer;
+
+	struct ath_descdma txsdma;
+};
+
+void ath9k_tasklet(struct ath_softc *sc);
+int ath_reset(struct ath_softc *sc, int retry_tx);
+
+static inline void ath_read_cachesize(struct ath_common *common, int *csz)
+{
+	common->bus_ops->read_cachesize(common, csz);
+}
+
+extern struct net80211_device_operations ath9k_ops;
+extern int ath9k_modparam_nohwcrypt;
+extern int is_ath9k_unloaded;
+
+void ath_isr(struct net80211_device *dev);
+void ath9k_init_crypto(struct ath_softc *sc);
+int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
+		    const struct ath_bus_ops *bus_ops);
+void ath9k_deinit_device(struct ath_softc *sc);
+void ath9k_set_hw_capab(struct ath_softc *sc, struct net80211_device *dev);
+int ath_set_channel(struct ath_softc *sc, struct net80211_device *dev,
+		    struct ath9k_channel *hchan);
+
+void ath_radio_enable(struct ath_softc *sc, struct net80211_device *dev);
+void ath_radio_disable(struct ath_softc *sc, struct net80211_device *dev);
+int ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode);
+int ath9k_uses_beacons(int type);
+
+u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate);
+
+void ath_start_rfkill_poll(struct ath_softc *sc);
+extern void ath9k_rfkill_poll_state(struct net80211_device *dev);
+
+#endif /* ATH9K_H */
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ani.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ani.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff7df497fc925f355d135802633bb3fe1a20ba52
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ani.c
@@ -0,0 +1,733 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "hw.h"
+#include "hw-ops.h"
+
+struct ani_ofdm_level_entry {
+	int spur_immunity_level;
+	int fir_step_level;
+	int ofdm_weak_signal_on;
+};
+
+/* values here are relative to the INI */
+
+/*
+ * Legend:
+ *
+ * SI: Spur immunity
+ * FS: FIR Step
+ * WS: OFDM / CCK Weak Signal detection
+ * MRC-CCK: Maximal Ratio Combining for CCK
+ */
+
+static const struct ani_ofdm_level_entry ofdm_level_table[] = {
+	/* SI  FS  WS */
+	{  0,  0,  1  }, /* lvl 0 */
+	{  1,  1,  1  }, /* lvl 1 */
+	{  2,  2,  1  }, /* lvl 2 */
+	{  3,  2,  1  }, /* lvl 3  (default) */
+	{  4,  3,  1  }, /* lvl 4 */
+	{  5,  4,  1  }, /* lvl 5 */
+	{  6,  5,  1  }, /* lvl 6 */
+	{  7,  6,  1  }, /* lvl 7 */
+	{  7,  7,  1  }, /* lvl 8 */
+	{  7,  8,  0  }  /* lvl 9 */
+};
+#define ATH9K_ANI_OFDM_NUM_LEVEL \
+	ARRAY_SIZE(ofdm_level_table)
+#define ATH9K_ANI_OFDM_MAX_LEVEL \
+	(ATH9K_ANI_OFDM_NUM_LEVEL-1)
+#define ATH9K_ANI_OFDM_DEF_LEVEL \
+	3 /* default level - matches the INI settings */
+
+/*
+ * MRC (Maximal Ratio Combining) has always been used with multi-antenna ofdm.
+ * With OFDM for single stream you just add up all antenna inputs, you're
+ * only interested in what you get after FFT. Signal aligment is also not
+ * required for OFDM because any phase difference adds up in the frequency
+ * domain.
+ *
+ * MRC requires extra work for use with CCK. You need to align the antenna
+ * signals from the different antenna before you can add the signals together.
+ * You need aligment of signals as CCK is in time domain, so addition can cancel
+ * your signal completely if phase is 180 degrees (think of adding sine waves).
+ * You also need to remove noise before the addition and this is where ANI
+ * MRC CCK comes into play. One of the antenna inputs may be stronger but
+ * lower SNR, so just adding after alignment can be dangerous.
+ *
+ * Regardless of alignment in time, the antenna signals add constructively after
+ * FFT and improve your reception. For more information:
+ *
+ * http://en.wikipedia.org/wiki/Maximal-ratio_combining
+ */
+
+struct ani_cck_level_entry {
+	int fir_step_level;
+	int mrc_cck_on;
+};
+
+static const struct ani_cck_level_entry cck_level_table[] = {
+	/* FS  MRC-CCK  */
+	{  0,  1  }, /* lvl 0 */
+	{  1,  1  }, /* lvl 1 */
+	{  2,  1  }, /* lvl 2  (default) */
+	{  3,  1  }, /* lvl 3 */
+	{  4,  0  }, /* lvl 4 */
+	{  5,  0  }, /* lvl 5 */
+	{  6,  0  }, /* lvl 6 */
+	{  7,  0  }, /* lvl 7 (only for high rssi) */
+	{  8,  0  }  /* lvl 8 (only for high rssi) */
+};
+
+#define ATH9K_ANI_CCK_NUM_LEVEL \
+	ARRAY_SIZE(cck_level_table)
+#define ATH9K_ANI_CCK_MAX_LEVEL \
+	(ATH9K_ANI_CCK_NUM_LEVEL-1)
+#define ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI \
+	(ATH9K_ANI_CCK_NUM_LEVEL-3)
+#define ATH9K_ANI_CCK_DEF_LEVEL \
+	2 /* default level - matches the INI settings */
+
+static int use_new_ani(struct ath_hw *ah)
+{
+	return AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani;
+}
+
+static void ath9k_hw_update_mibstats(struct ath_hw *ah,
+				     struct ath9k_mib_stats *stats)
+{
+	stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
+	stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
+	stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
+	stats->rts_good += REG_READ(ah, AR_RTS_OK);
+	stats->beacons += REG_READ(ah, AR_BEACON_CNT);
+}
+
+static void ath9k_ani_restart(struct ath_hw *ah)
+{
+	struct ar5416AniState *aniState;
+	u32 ofdm_base = 0, cck_base = 0;
+
+	if (!DO_ANI(ah))
+		return;
+
+	aniState = &ah->curchan->ani;
+	aniState->listenTime = 0;
+
+	if (!use_new_ani(ah)) {
+		ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
+		cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
+	}
+
+	DBG2("ath9k: "
+		"Writing ofdmbase=%d   cckbase=%d\n", ofdm_base, cck_base);
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
+	REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
+	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+
+	ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
+
+	aniState->ofdmPhyErrCount = 0;
+	aniState->cckPhyErrCount = 0;
+}
+
+static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah)
+{
+	struct ar5416AniState *aniState;
+	int32_t rssi;
+
+	aniState = &ah->curchan->ani;
+
+	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
+		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+					 aniState->noiseImmunityLevel + 1)) {
+			return;
+		}
+	}
+
+	if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
+		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+					 aniState->spurImmunityLevel + 1)) {
+			return;
+		}
+	}
+
+	rssi = BEACON_RSSI(ah);
+	if (rssi > aniState->rssiThrHigh) {
+		if (!aniState->ofdmWeakSigDetectOff) {
+			if (ath9k_hw_ani_control(ah,
+					 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+					 0)) {
+				ath9k_hw_ani_control(ah,
+					ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
+				return;
+			}
+		}
+		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
+			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+					     aniState->firstepLevel + 1);
+			return;
+		}
+	} else if (rssi > aniState->rssiThrLow) {
+		if (aniState->ofdmWeakSigDetectOff)
+			ath9k_hw_ani_control(ah,
+				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+				     1);
+		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
+			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+					     aniState->firstepLevel + 1);
+		return;
+	} else {
+		if ((ah->dev->channels + ah->dev->channel)->band == NET80211_BAND_2GHZ) {
+			if (!aniState->ofdmWeakSigDetectOff)
+				ath9k_hw_ani_control(ah,
+				     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+				     0);
+			if (aniState->firstepLevel > 0)
+				ath9k_hw_ani_control(ah,
+					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
+			return;
+		}
+	}
+}
+
+static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah)
+{
+	struct ar5416AniState *aniState;
+	int32_t rssi;
+
+	aniState = &ah->curchan->ani;
+	if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
+		if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+					 aniState->noiseImmunityLevel + 1)) {
+			return;
+		}
+	}
+	rssi = BEACON_RSSI(ah);
+	if (rssi > aniState->rssiThrLow) {
+		if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
+			ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+					     aniState->firstepLevel + 1);
+	} else {
+		if ((ah->dev->channels + ah->dev->channel)->band == NET80211_BAND_2GHZ) {
+			if (aniState->firstepLevel > 0)
+				ath9k_hw_ani_control(ah,
+					     ATH9K_ANI_FIRSTEP_LEVEL, 0);
+		}
+	}
+}
+
+/* Adjust the OFDM Noise Immunity Level */
+static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
+{
+	struct ar5416AniState *aniState = &ah->curchan->ani;
+	const struct ani_ofdm_level_entry *entry_ofdm;
+	const struct ani_cck_level_entry *entry_cck;
+
+	aniState->noiseFloor = BEACON_RSSI(ah);
+
+	DBG2("ath9k: "
+		"**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
+		aniState->ofdmNoiseImmunityLevel,
+		immunityLevel, aniState->noiseFloor,
+		aniState->rssiThrLow, aniState->rssiThrHigh);
+
+	aniState->ofdmNoiseImmunityLevel = immunityLevel;
+
+	entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
+	entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
+
+	if (aniState->spurImmunityLevel != entry_ofdm->spur_immunity_level)
+		ath9k_hw_ani_control(ah,
+				     ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+				     entry_ofdm->spur_immunity_level);
+
+	if (aniState->firstepLevel != entry_ofdm->fir_step_level &&
+	    entry_ofdm->fir_step_level >= entry_cck->fir_step_level)
+		ath9k_hw_ani_control(ah,
+				     ATH9K_ANI_FIRSTEP_LEVEL,
+				     entry_ofdm->fir_step_level);
+}
+
+static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
+{
+	struct ar5416AniState *aniState;
+
+	if (!DO_ANI(ah))
+		return;
+
+	if (!use_new_ani(ah)) {
+		ath9k_hw_ani_ofdm_err_trigger_old(ah);
+		return;
+	}
+
+	aniState = &ah->curchan->ani;
+
+	if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
+		ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1);
+}
+
+/*
+ * Set the ANI settings to match an CCK level.
+ */
+static void ath9k_hw_set_cck_nil(struct ath_hw *ah, uint8_t immunityLevel)
+{
+	struct ar5416AniState *aniState = &ah->curchan->ani;
+	const struct ani_ofdm_level_entry *entry_ofdm;
+	const struct ani_cck_level_entry *entry_cck;
+
+	aniState->noiseFloor = BEACON_RSSI(ah);
+	DBG2("ath9k: "
+		"**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
+		aniState->cckNoiseImmunityLevel, immunityLevel,
+		aniState->noiseFloor, aniState->rssiThrLow,
+		aniState->rssiThrHigh);
+
+	if (aniState->noiseFloor <= (unsigned int)aniState->rssiThrLow &&
+	    immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
+		immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
+
+	aniState->cckNoiseImmunityLevel = immunityLevel;
+
+	entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
+	entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
+
+	if (aniState->firstepLevel != entry_cck->fir_step_level &&
+	    entry_cck->fir_step_level >= entry_ofdm->fir_step_level)
+		ath9k_hw_ani_control(ah,
+				     ATH9K_ANI_FIRSTEP_LEVEL,
+				     entry_cck->fir_step_level);
+
+	/* Skip MRC CCK for pre AR9003 families */
+	if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah))
+		return;
+
+	if (aniState->mrcCCKOff == entry_cck->mrc_cck_on)
+		ath9k_hw_ani_control(ah,
+				     ATH9K_ANI_MRC_CCK,
+				     entry_cck->mrc_cck_on);
+}
+
+static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
+{
+	struct ar5416AniState *aniState;
+
+	if (!DO_ANI(ah))
+		return;
+
+	if (!use_new_ani(ah)) {
+		ath9k_hw_ani_cck_err_trigger_old(ah);
+		return;
+	}
+
+	aniState = &ah->curchan->ani;
+
+	if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
+		ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1);
+}
+
+static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
+{
+	struct ar5416AniState *aniState;
+	int32_t rssi;
+
+	aniState = &ah->curchan->ani;
+
+	rssi = BEACON_RSSI(ah);
+	if (rssi > aniState->rssiThrHigh) {
+		/* XXX: Handle me */
+	} else if (rssi > aniState->rssiThrLow) {
+		if (aniState->ofdmWeakSigDetectOff) {
+			if (ath9k_hw_ani_control(ah,
+				 ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+				 1) == 1)
+				return;
+		}
+		if (aniState->firstepLevel > 0) {
+			if (ath9k_hw_ani_control(ah,
+				 ATH9K_ANI_FIRSTEP_LEVEL,
+				 aniState->firstepLevel - 1) == 1)
+				return;
+		}
+	} else {
+		if (aniState->firstepLevel > 0) {
+			if (ath9k_hw_ani_control(ah,
+				 ATH9K_ANI_FIRSTEP_LEVEL,
+				 aniState->firstepLevel - 1) == 1)
+				return;
+		}
+	}
+
+	if (aniState->spurImmunityLevel > 0) {
+		if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+					 aniState->spurImmunityLevel - 1))
+			return;
+	}
+
+	if (aniState->noiseImmunityLevel > 0) {
+		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+				     aniState->noiseImmunityLevel - 1);
+		return;
+	}
+}
+
+/*
+ * only lower either OFDM or CCK errors per turn
+ * we lower the other one next time
+ */
+static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
+{
+	struct ar5416AniState *aniState;
+
+	aniState = &ah->curchan->ani;
+
+	if (!use_new_ani(ah)) {
+		ath9k_hw_ani_lower_immunity_old(ah);
+		return;
+	}
+
+	/* lower OFDM noise immunity */
+	if (aniState->ofdmNoiseImmunityLevel > 0 &&
+	    (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) {
+		ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1);
+		return;
+	}
+
+	/* lower CCK noise immunity */
+	if (aniState->cckNoiseImmunityLevel > 0)
+		ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1);
+}
+
+static void ath9k_ani_reset_old(struct ath_hw *ah)
+{
+	struct ar5416AniState *aniState;
+
+	if (!DO_ANI(ah))
+		return;
+
+	aniState = &ah->curchan->ani;
+
+	if (aniState->noiseImmunityLevel != 0)
+		ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+				     aniState->noiseImmunityLevel);
+	if (aniState->spurImmunityLevel != 0)
+		ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+				     aniState->spurImmunityLevel);
+	if (aniState->ofdmWeakSigDetectOff)
+		ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+				     !aniState->ofdmWeakSigDetectOff);
+	if (aniState->cckWeakSigThreshold)
+		ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
+				     aniState->cckWeakSigThreshold);
+	if (aniState->firstepLevel != 0)
+		ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+				     aniState->firstepLevel);
+
+	ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
+			     ~ATH9K_RX_FILTER_PHYERR);
+	ath9k_ani_restart(ah);
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+}
+
+/*
+ * Restore the ANI parameters in the HAL and reset the statistics.
+ * This routine should be called for every hardware reset and for
+ * every channel change.
+ */
+void ath9k_ani_reset(struct ath_hw *ah, int is_scanning)
+{
+	struct ar5416AniState *aniState = &ah->curchan->ani;
+	struct ath9k_channel *chan = ah->curchan;
+
+	if (!DO_ANI(ah))
+		return;
+
+	if (!use_new_ani(ah))
+		return ath9k_ani_reset_old(ah);
+
+	ah->stats.ast_ani_reset++;
+
+	/* always allow mode (on/off) to be controlled */
+	ah->ani_function |= ATH9K_ANI_MODE;
+
+	if (is_scanning) {
+		/*
+		 * If we're scanning or in AP mode, the defaults (ini)
+		 * should be in place. For an AP we assume the historical
+		 * levels for this channel are probably outdated so start
+		 * from defaults instead.
+		 */
+		if (aniState->ofdmNoiseImmunityLevel !=
+		    ATH9K_ANI_OFDM_DEF_LEVEL ||
+		    aniState->cckNoiseImmunityLevel !=
+		    ATH9K_ANI_CCK_DEF_LEVEL) {
+			DBG("ath9k: "
+				"Restore defaults: chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
+				chan->channel,
+				chan->channelFlags,
+				is_scanning,
+				aniState->ofdmNoiseImmunityLevel,
+				aniState->cckNoiseImmunityLevel);
+
+			ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL);
+			ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL);
+		}
+	} else {
+		/*
+		 * restore historical levels for this channel
+		 */
+		DBG2("ath9k: "
+			"Restore history: chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
+			chan->channel,
+			chan->channelFlags,
+			is_scanning,
+			aniState->ofdmNoiseImmunityLevel,
+			aniState->cckNoiseImmunityLevel);
+
+			ath9k_hw_set_ofdm_nil(ah,
+					      aniState->ofdmNoiseImmunityLevel);
+			ath9k_hw_set_cck_nil(ah,
+					     aniState->cckNoiseImmunityLevel);
+	}
+
+	/*
+	 * enable phy counters if hw supports or if not, enable phy
+	 * interrupts (so we can count each one)
+	 */
+	ath9k_ani_restart(ah);
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+	REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+}
+
+static int ath9k_hw_ani_read_counters(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ar5416AniState *aniState = &ah->curchan->ani;
+	u32 ofdm_base = 0;
+	u32 cck_base = 0;
+	u32 ofdmPhyErrCnt, cckPhyErrCnt;
+	u32 phyCnt1, phyCnt2;
+	int32_t listenTime;
+
+	ath_hw_cycle_counters_update(common);
+	listenTime = ath_hw_get_listen_time(common);
+
+	if (listenTime <= 0) {
+		ah->stats.ast_ani_lneg++;
+		ath9k_ani_restart(ah);
+		return 0;
+	}
+
+	if (!use_new_ani(ah)) {
+		ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
+		cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
+	}
+
+	aniState->listenTime += listenTime;
+
+	phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
+	phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
+
+	if (!use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) {
+		if (phyCnt1 < ofdm_base) {
+			DBG2("ath9k: "
+				"phyCnt1 0x%x, resetting counter value to 0x%x\n",
+				phyCnt1, ofdm_base);
+			REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
+			REG_WRITE(ah, AR_PHY_ERR_MASK_1,
+				  AR_PHY_ERR_OFDM_TIMING);
+		}
+		if (phyCnt2 < cck_base) {
+			DBG2("ath9k: "
+				"phyCnt2 0x%x, resetting counter value to 0x%x\n",
+				phyCnt2, cck_base);
+			REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
+			REG_WRITE(ah, AR_PHY_ERR_MASK_2,
+				  AR_PHY_ERR_CCK_TIMING);
+		}
+		return 0;
+	}
+
+	ofdmPhyErrCnt = phyCnt1 - ofdm_base;
+	ah->stats.ast_ani_ofdmerrs +=
+		ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
+	aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+
+	cckPhyErrCnt = phyCnt2 - cck_base;
+	ah->stats.ast_ani_cckerrs +=
+		cckPhyErrCnt - aniState->cckPhyErrCount;
+	aniState->cckPhyErrCount = cckPhyErrCnt;
+	return 1;
+}
+
+void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan __unused)
+{
+	struct ar5416AniState *aniState;
+	u32 ofdmPhyErrRate, cckPhyErrRate;
+
+	if (!DO_ANI(ah))
+		return;
+
+	aniState = &ah->curchan->ani;
+	if (!aniState)
+		return;
+
+	if (!ath9k_hw_ani_read_counters(ah))
+		return;
+
+	ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 /
+			 aniState->listenTime;
+	cckPhyErrRate =  aniState->cckPhyErrCount * 1000 /
+			 aniState->listenTime;
+
+	DBG2("ath9k: "
+		"listenTime=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n",
+		aniState->listenTime,
+		aniState->ofdmNoiseImmunityLevel,
+		ofdmPhyErrRate, aniState->cckNoiseImmunityLevel,
+		cckPhyErrRate, aniState->ofdmsTurn);
+
+	if (aniState->listenTime > 5 * ah->aniperiod) {
+		if (ofdmPhyErrRate <= ah->config.ofdm_trig_low &&
+		    cckPhyErrRate <= ah->config.cck_trig_low) {
+			ath9k_hw_ani_lower_immunity(ah);
+			aniState->ofdmsTurn = !aniState->ofdmsTurn;
+		}
+		ath9k_ani_restart(ah);
+	} else if (aniState->listenTime > ah->aniperiod) {
+		/* check to see if need to raise immunity */
+		if (ofdmPhyErrRate > ah->config.ofdm_trig_high &&
+		    (cckPhyErrRate <= ah->config.cck_trig_high ||
+		     aniState->ofdmsTurn)) {
+			ath9k_hw_ani_ofdm_err_trigger(ah);
+			ath9k_ani_restart(ah);
+			aniState->ofdmsTurn = 0;
+		} else if (cckPhyErrRate > ah->config.cck_trig_high) {
+			ath9k_hw_ani_cck_err_trigger(ah);
+			ath9k_ani_restart(ah);
+			aniState->ofdmsTurn = 1;
+		}
+	}
+}
+
+void ath9k_hw_ani_setup(struct ath_hw *ah)
+{
+	int i;
+
+	static const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
+	static const int coarseHigh[] = { -14, -14, -14, -14, -12 };
+	static const int coarseLow[] = { -64, -64, -64, -64, -70 };
+	static const int firpwr[] = { -78, -78, -78, -78, -80 };
+
+	for (i = 0; i < 5; i++) {
+		ah->totalSizeDesired[i] = totalSizeDesired[i];
+		ah->coarse_high[i] = coarseHigh[i];
+		ah->coarse_low[i] = coarseLow[i];
+		ah->firpwr[i] = firpwr[i];
+	}
+}
+
+void ath9k_hw_ani_init(struct ath_hw *ah)
+{
+	unsigned int i;
+
+	DBG2("ath9k: Initialize ANI\n");
+
+	if (use_new_ani(ah)) {
+		ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW;
+		ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_NEW;
+
+		ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_NEW;
+		ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_NEW;
+	} else {
+		ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
+		ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
+
+		ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
+		ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(ah->channels); i++) {
+		struct ath9k_channel *chan = &ah->channels[i];
+		struct ar5416AniState *ani = &chan->ani;
+
+		if (use_new_ani(ah)) {
+			ani->spurImmunityLevel =
+				ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
+
+			ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
+
+			if (AR_SREV_9300_20_OR_LATER(ah))
+				ani->mrcCCKOff =
+					!ATH9K_ANI_ENABLE_MRC_CCK;
+			else
+				ani->mrcCCKOff = 1;
+
+			ani->ofdmsTurn = 1;
+		} else {
+			ani->spurImmunityLevel =
+				ATH9K_ANI_SPUR_IMMUNE_LVL_OLD;
+			ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD;
+
+			ani->cckWeakSigThreshold =
+				ATH9K_ANI_CCK_WEAK_SIG_THR;
+		}
+
+		ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
+		ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
+		ani->ofdmWeakSigDetectOff =
+			!ATH9K_ANI_USE_OFDM_WEAK_SIG;
+		ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
+	}
+
+	/*
+	 * since we expect some ongoing maintenance on the tables, let's sanity
+	 * check here default level should not modify INI setting.
+	 */
+	if (use_new_ani(ah)) {
+		ah->aniperiod = ATH9K_ANI_PERIOD_NEW;
+		ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW;
+	} else {
+		ah->aniperiod = ATH9K_ANI_PERIOD_OLD;
+		ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD;
+	}
+
+	if (ah->config.enable_ani)
+		ah->proc_phyerr |= HAL_PROCESS_ANI;
+
+	ath9k_ani_restart(ah);
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar5008_phy.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar5008_phy.c
new file mode 100644
index 0000000000000000000000000000000000000000..60e87e9e2625ea350c423d7e80ae9e30bb4717e1
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar5008_phy.c
@@ -0,0 +1,1663 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/malloc.h>
+#include <ipxe/io.h>
+
+#include "hw.h"
+#include "hw-ops.h"
+#include "../regd.h"
+#include "ar9002_phy.h"
+
+/* All code below is for AR5008, AR9001, AR9002 */
+
+static const int firstep_table[] =
+/* level:  0   1   2   3   4   5   6   7   8  */
+	{ -4, -2,  0,  2,  4,  6,  8, 10, 12 }; /* lvl 0-8, default 2 */
+
+static const int cycpwrThr1_table[] =
+/* level:  0   1   2   3   4   5   6   7   8  */
+	{ -6, -4, -2,  0,  2,  4,  6,  8 };     /* lvl 0-7, default 3 */
+
+/*
+ * register values to turn OFDM weak signal detection OFF
+ */
+static const int m1ThreshLow_off = 127;
+static const int m2ThreshLow_off = 127;
+static const int m1Thresh_off = 127;
+static const int m2Thresh_off = 127;
+static const int m2CountThr_off =  31;
+static const int m2CountThrLow_off =  63;
+static const int m1ThreshLowExt_off = 127;
+static const int m2ThreshLowExt_off = 127;
+static const int m1ThreshExt_off = 127;
+static const int m2ThreshExt_off = 127;
+
+
+static void ar5008_rf_bank_setup(u32 *bank, struct ar5416IniArray *array,
+				 int col)
+{
+	unsigned int i;
+
+	for (i = 0; i < array->ia_rows; i++)
+		bank[i] = INI_RA(array, i, col);
+}
+
+
+#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) \
+	ar5008_write_rf_array(ah, iniarray, regData, &(regWr))
+
+static void ar5008_write_rf_array(struct ath_hw *ah, struct ar5416IniArray *array,
+				  u32 *data, unsigned int *writecnt)
+{
+	unsigned int r;
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	for (r = 0; r < array->ia_rows; r++) {
+		REG_WRITE(ah, INI_RA(array, r, 0), data[r]);
+		DO_DELAY(*writecnt);
+	}
+
+	REGWRITE_BUFFER_FLUSH(ah);
+}
+
+/**
+ * ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters
+ * @rfbuf:
+ * @reg32:
+ * @numBits:
+ * @firstBit:
+ * @column:
+ *
+ * Performs analog "swizzling" of parameters into their location.
+ * Used on external AR2133/AR5133 radios.
+ */
+static void ar5008_hw_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32,
+					   u32 numBits, u32 firstBit,
+					   u32 column)
+{
+	u32 tmp32, mask, arrayEntry, lastBit;
+	int32_t bitPosition, bitsLeft;
+
+	tmp32 = ath9k_hw_reverse_bits(reg32, numBits);
+	arrayEntry = (firstBit - 1) / 8;
+	bitPosition = (firstBit - 1) % 8;
+	bitsLeft = numBits;
+	while (bitsLeft > 0) {
+		lastBit = (bitPosition + bitsLeft > 8) ?
+		    8 : bitPosition + bitsLeft;
+		mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) <<
+		    (column * 8);
+		rfBuf[arrayEntry] &= ~mask;
+		rfBuf[arrayEntry] |= ((tmp32 << bitPosition) <<
+				      (column * 8)) & mask;
+		bitsLeft -= 8 - bitPosition;
+		tmp32 = tmp32 >> (8 - bitPosition);
+		bitPosition = 0;
+		arrayEntry++;
+	}
+}
+
+/*
+ * Fix on 2.4 GHz band for orientation sensitivity issue by increasing
+ * rf_pwd_icsyndiv.
+ *
+ * Theoretical Rules:
+ *   if 2 GHz band
+ *      if forceBiasAuto
+ *         if synth_freq < 2412
+ *            bias = 0
+ *         else if 2412 <= synth_freq <= 2422
+ *            bias = 1
+ *         else // synth_freq > 2422
+ *            bias = 2
+ *      else if forceBias > 0
+ *         bias = forceBias & 7
+ *      else
+ *         no change, use value from ini file
+ *   else
+ *      no change, invalid band
+ *
+ *  1st Mod:
+ *    2422 also uses value of 2
+ *    <approved>
+ *
+ *  2nd Mod:
+ *    Less than 2412 uses value of 0, 2412 and above uses value of 2
+ */
+static void ar5008_hw_force_bias(struct ath_hw *ah, u16 synth_freq)
+{
+	u32 tmp_reg;
+	unsigned int reg_writes = 0;
+	u32 new_bias = 0;
+
+	if (!AR_SREV_5416(ah) || synth_freq >= 3000)
+		return;
+
+	if (synth_freq < 2412)
+		new_bias = 0;
+	else if (synth_freq < 2422)
+		new_bias = 1;
+	else
+		new_bias = 2;
+
+	/* pre-reverse this field */
+	tmp_reg = ath9k_hw_reverse_bits(new_bias, 3);
+
+	DBG("ath9k: Force rf_pwd_icsyndiv to %1d on %4d\n",
+		new_bias, synth_freq);
+
+	/* swizzle rf_pwd_icsyndiv */
+	ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data, tmp_reg, 3, 181, 3);
+
+	/* write Bank 6 with new params */
+	REG_WRITE_RF_ARRAY(&ah->iniBank6, ah->analogBank6Data, reg_writes);
+}
+
+/**
+ * ar5008_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios
+ * @ah: atheros hardware structure
+ * @chan:
+ *
+ * For the external AR2133/AR5133 radios, takes the MHz channel value and set
+ * the channel value. Assumes writes enabled to analog bus and bank6 register
+ * cache in ah->analogBank6Data.
+ */
+static int ar5008_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+	u32 channelSel = 0;
+	u32 bModeSynth = 0;
+	u32 aModeRefSel = 0;
+	u32 reg32 = 0;
+	u16 freq;
+	struct chan_centers centers;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+	freq = centers.synth_center;
+
+	if (freq < 4800) {
+		u32 txctl;
+
+		if (((freq - 2192) % 5) == 0) {
+			channelSel = ((freq - 672) * 2 - 3040) / 10;
+			bModeSynth = 0;
+		} else if (((freq - 2224) % 5) == 0) {
+			channelSel = ((freq - 704) * 2 - 3040) / 10;
+			bModeSynth = 1;
+		} else {
+			DBG("ath9k: Invalid channel %d MHz\n", freq);
+			return -EINVAL;
+		}
+
+		channelSel = (channelSel << 2) & 0xff;
+		channelSel = ath9k_hw_reverse_bits(channelSel, 8);
+
+		txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
+		if (freq == 2484) {
+
+			REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+				  txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
+		} else {
+			REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+				  txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN);
+		}
+
+	} else if ((freq % 20) == 0 && freq >= 5120) {
+		channelSel =
+		    ath9k_hw_reverse_bits(((freq - 4800) / 20 << 2), 8);
+		aModeRefSel = ath9k_hw_reverse_bits(1, 2);
+	} else if ((freq % 10) == 0) {
+		channelSel =
+		    ath9k_hw_reverse_bits(((freq - 4800) / 10 << 1), 8);
+		if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah))
+			aModeRefSel = ath9k_hw_reverse_bits(2, 2);
+		else
+			aModeRefSel = ath9k_hw_reverse_bits(1, 2);
+	} else if ((freq % 5) == 0) {
+		channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8);
+		aModeRefSel = ath9k_hw_reverse_bits(1, 2);
+	} else {
+		DBG("ath9k: Invalid channel %d MHz\n", freq);
+		return -EINVAL;
+	}
+
+	ar5008_hw_force_bias(ah, freq);
+
+	reg32 =
+	    (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) |
+	    (1 << 5) | 0x1;
+
+	REG_WRITE(ah, AR_PHY(0x37), reg32);
+
+	ah->curchan = chan;
+	ah->curchan_rad_index = -1;
+
+	return 0;
+}
+
+/**
+ * ar5008_hw_spur_mitigate - convert baseband spur frequency for external radios
+ * @ah: atheros hardware structure
+ * @chan:
+ *
+ * For non single-chip solutions. Converts to baseband spur frequency given the
+ * input channel frequency and compute register settings below.
+ */
+static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
+				    struct ath9k_channel *chan)
+{
+	int bb_spur = AR_NO_SPUR;
+	int bin, cur_bin;
+	int spur_freq_sd;
+	int spur_delta_phase;
+	int denominator;
+	int upper, lower, cur_vit_mask;
+	int tmp, new;
+	int i;
+	static int pilot_mask_reg[4] = {
+		AR_PHY_TIMING7, AR_PHY_TIMING8,
+		AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
+	};
+	static int chan_mask_reg[4] = {
+		AR_PHY_TIMING9, AR_PHY_TIMING10,
+		AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
+	};
+	static int inc[4] = { 0, 100, 0, 0 };
+
+	int8_t mask_m[123];
+	int8_t mask_p[123];
+	int8_t mask_amt;
+	int tmp_mask;
+	int cur_bb_spur;
+	int is2GHz = IS_CHAN_2GHZ(chan);
+
+	memset(&mask_m, 0, sizeof(int8_t) * 123);
+	memset(&mask_p, 0, sizeof(int8_t) * 123);
+
+	for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+		cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
+		if (AR_NO_SPUR == cur_bb_spur)
+			break;
+		cur_bb_spur = cur_bb_spur - (chan->channel * 10);
+		if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) {
+			bb_spur = cur_bb_spur;
+			break;
+		}
+	}
+
+	if (AR_NO_SPUR == bb_spur)
+		return;
+
+	bin = bb_spur * 32;
+
+	tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
+	new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
+		     AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
+		     AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
+		     AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
+
+	REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new);
+
+	new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
+	       AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
+	       AR_PHY_SPUR_REG_MASK_RATE_SELECT |
+	       AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
+	       SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
+	REG_WRITE(ah, AR_PHY_SPUR_REG, new);
+
+	spur_delta_phase = ((bb_spur * 524288) / 100) &
+		AR_PHY_TIMING11_SPUR_DELTA_PHASE;
+
+	denominator = IS_CHAN_2GHZ(chan) ? 440 : 400;
+	spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff;
+
+	new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
+	       SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
+	       SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
+	REG_WRITE(ah, AR_PHY_TIMING11, new);
+
+	cur_bin = -6000;
+	upper = bin + 100;
+	lower = bin - 100;
+
+	for (i = 0; i < 4; i++) {
+		int pilot_mask = 0;
+		int chan_mask = 0;
+		int bp = 0;
+		for (bp = 0; bp < 30; bp++) {
+			if ((cur_bin > lower) && (cur_bin < upper)) {
+				pilot_mask = pilot_mask | 0x1 << bp;
+				chan_mask = chan_mask | 0x1 << bp;
+			}
+			cur_bin += 100;
+		}
+		cur_bin += inc[i];
+		REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
+		REG_WRITE(ah, chan_mask_reg[i], chan_mask);
+	}
+
+	cur_vit_mask = 6100;
+	upper = bin + 120;
+	lower = bin - 120;
+
+	for (i = 0; i < 123; i++) {
+		if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
+
+			/* workaround for gcc bug #37014 */
+			volatile int tmp_v = abs(cur_vit_mask - bin);
+
+			if (tmp_v < 75)
+				mask_amt = 1;
+			else
+				mask_amt = 0;
+			if (cur_vit_mask < 0)
+				mask_m[abs(cur_vit_mask / 100)] = mask_amt;
+			else
+				mask_p[cur_vit_mask / 100] = mask_amt;
+		}
+		cur_vit_mask -= 100;
+	}
+
+	tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
+		| (mask_m[48] << 26) | (mask_m[49] << 24)
+		| (mask_m[50] << 22) | (mask_m[51] << 20)
+		| (mask_m[52] << 18) | (mask_m[53] << 16)
+		| (mask_m[54] << 14) | (mask_m[55] << 12)
+		| (mask_m[56] << 10) | (mask_m[57] << 8)
+		| (mask_m[58] << 6) | (mask_m[59] << 4)
+		| (mask_m[60] << 2) | (mask_m[61] << 0);
+	REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
+	REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
+
+	tmp_mask = (mask_m[31] << 28)
+		| (mask_m[32] << 26) | (mask_m[33] << 24)
+		| (mask_m[34] << 22) | (mask_m[35] << 20)
+		| (mask_m[36] << 18) | (mask_m[37] << 16)
+		| (mask_m[48] << 14) | (mask_m[39] << 12)
+		| (mask_m[40] << 10) | (mask_m[41] << 8)
+		| (mask_m[42] << 6) | (mask_m[43] << 4)
+		| (mask_m[44] << 2) | (mask_m[45] << 0);
+	REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
+	REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
+
+	tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
+		| (mask_m[18] << 26) | (mask_m[18] << 24)
+		| (mask_m[20] << 22) | (mask_m[20] << 20)
+		| (mask_m[22] << 18) | (mask_m[22] << 16)
+		| (mask_m[24] << 14) | (mask_m[24] << 12)
+		| (mask_m[25] << 10) | (mask_m[26] << 8)
+		| (mask_m[27] << 6) | (mask_m[28] << 4)
+		| (mask_m[29] << 2) | (mask_m[30] << 0);
+	REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
+	REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
+
+	tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
+		| (mask_m[2] << 26) | (mask_m[3] << 24)
+		| (mask_m[4] << 22) | (mask_m[5] << 20)
+		| (mask_m[6] << 18) | (mask_m[7] << 16)
+		| (mask_m[8] << 14) | (mask_m[9] << 12)
+		| (mask_m[10] << 10) | (mask_m[11] << 8)
+		| (mask_m[12] << 6) | (mask_m[13] << 4)
+		| (mask_m[14] << 2) | (mask_m[15] << 0);
+	REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
+	REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
+
+	tmp_mask = (mask_p[15] << 28)
+		| (mask_p[14] << 26) | (mask_p[13] << 24)
+		| (mask_p[12] << 22) | (mask_p[11] << 20)
+		| (mask_p[10] << 18) | (mask_p[9] << 16)
+		| (mask_p[8] << 14) | (mask_p[7] << 12)
+		| (mask_p[6] << 10) | (mask_p[5] << 8)
+		| (mask_p[4] << 6) | (mask_p[3] << 4)
+		| (mask_p[2] << 2) | (mask_p[1] << 0);
+	REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
+	REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
+
+	tmp_mask = (mask_p[30] << 28)
+		| (mask_p[29] << 26) | (mask_p[28] << 24)
+		| (mask_p[27] << 22) | (mask_p[26] << 20)
+		| (mask_p[25] << 18) | (mask_p[24] << 16)
+		| (mask_p[23] << 14) | (mask_p[22] << 12)
+		| (mask_p[21] << 10) | (mask_p[20] << 8)
+		| (mask_p[19] << 6) | (mask_p[18] << 4)
+		| (mask_p[17] << 2) | (mask_p[16] << 0);
+	REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
+	REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
+
+	tmp_mask = (mask_p[45] << 28)
+		| (mask_p[44] << 26) | (mask_p[43] << 24)
+		| (mask_p[42] << 22) | (mask_p[41] << 20)
+		| (mask_p[40] << 18) | (mask_p[39] << 16)
+		| (mask_p[38] << 14) | (mask_p[37] << 12)
+		| (mask_p[36] << 10) | (mask_p[35] << 8)
+		| (mask_p[34] << 6) | (mask_p[33] << 4)
+		| (mask_p[32] << 2) | (mask_p[31] << 0);
+	REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
+	REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
+
+	tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
+		| (mask_p[59] << 26) | (mask_p[58] << 24)
+		| (mask_p[57] << 22) | (mask_p[56] << 20)
+		| (mask_p[55] << 18) | (mask_p[54] << 16)
+		| (mask_p[53] << 14) | (mask_p[52] << 12)
+		| (mask_p[51] << 10) | (mask_p[50] << 8)
+		| (mask_p[49] << 6) | (mask_p[48] << 4)
+		| (mask_p[47] << 2) | (mask_p[46] << 0);
+	REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
+	REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
+}
+
+/**
+ * ar5008_hw_rf_alloc_ext_banks - allocates banks for external radio programming
+ * @ah: atheros hardware structure
+ *
+ * Only required for older devices with external AR2133/AR5133 radios.
+ */
+static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah)
+{
+#define ATH_ALLOC_BANK(bank, size) do { \
+		bank = zalloc((sizeof(u32) * size)); \
+		if (!bank) { \
+			DBG("ath9k: Cannot allocate RF banks\n"); \
+			return -ENOMEM; \
+		} \
+	} while (0);
+
+	ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows);
+	ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows);
+	ATH_ALLOC_BANK(ah->analogBank2Data, ah->iniBank2.ia_rows);
+	ATH_ALLOC_BANK(ah->analogBank3Data, ah->iniBank3.ia_rows);
+	ATH_ALLOC_BANK(ah->analogBank6Data, ah->iniBank6.ia_rows);
+	ATH_ALLOC_BANK(ah->analogBank6TPCData, ah->iniBank6TPC.ia_rows);
+	ATH_ALLOC_BANK(ah->analogBank7Data, ah->iniBank7.ia_rows);
+	ATH_ALLOC_BANK(ah->addac5416_21,
+		       ah->iniAddac.ia_rows * ah->iniAddac.ia_columns);
+	ATH_ALLOC_BANK(ah->bank6Temp, ah->iniBank6.ia_rows);
+
+	return 0;
+#undef ATH_ALLOC_BANK
+}
+
+
+/**
+ * ar5008_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers
+ * @ah: atheros hardware struture
+ * For the external AR2133/AR5133 radios banks.
+ */
+static void ar5008_hw_rf_free_ext_banks(struct ath_hw *ah)
+{
+#define ATH_FREE_BANK(bank) do { \
+		free(bank); \
+		bank = NULL; \
+	} while (0);
+
+	ATH_FREE_BANK(ah->analogBank0Data);
+	ATH_FREE_BANK(ah->analogBank1Data);
+	ATH_FREE_BANK(ah->analogBank2Data);
+	ATH_FREE_BANK(ah->analogBank3Data);
+	ATH_FREE_BANK(ah->analogBank6Data);
+	ATH_FREE_BANK(ah->analogBank6TPCData);
+	ATH_FREE_BANK(ah->analogBank7Data);
+	ATH_FREE_BANK(ah->addac5416_21);
+	ATH_FREE_BANK(ah->bank6Temp);
+
+#undef ATH_FREE_BANK
+}
+
+/* *
+ * ar5008_hw_set_rf_regs - programs rf registers based on EEPROM
+ * @ah: atheros hardware structure
+ * @chan:
+ * @modesIndex:
+ *
+ * Used for the external AR2133/AR5133 radios.
+ *
+ * Reads the EEPROM header info from the device structure and programs
+ * all rf registers. This routine requires access to the analog
+ * rf device. This is not required for single-chip devices.
+ */
+static int ar5008_hw_set_rf_regs(struct ath_hw *ah,
+				  struct ath9k_channel *chan,
+				  u16 modesIndex)
+{
+	u32 eepMinorRev;
+	u32 ob5GHz = 0, db5GHz = 0;
+	u32 ob2GHz = 0, db2GHz = 0;
+	unsigned int regWrites = 0;
+
+	/*
+	 * Software does not need to program bank data
+	 * for single chip devices, that is AR9280 or anything
+	 * after that.
+	 */
+	if (AR_SREV_9280_20_OR_LATER(ah))
+		return 1;
+
+	/* Setup rf parameters */
+	eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV);
+
+	/* Setup Bank 0 Write */
+	ar5008_rf_bank_setup(ah->analogBank0Data, &ah->iniBank0, 1);
+
+	/* Setup Bank 1 Write */
+	ar5008_rf_bank_setup(ah->analogBank1Data, &ah->iniBank1, 1);
+
+	/* Setup Bank 2 Write */
+	ar5008_rf_bank_setup(ah->analogBank2Data, &ah->iniBank2, 1);
+
+	/* Setup Bank 6 Write */
+	ar5008_rf_bank_setup(ah->analogBank3Data, &ah->iniBank3,
+		      modesIndex);
+	{
+		unsigned int i;
+		for (i = 0; i < ah->iniBank6TPC.ia_rows; i++) {
+			ah->analogBank6Data[i] =
+			    INI_RA(&ah->iniBank6TPC, i, modesIndex);
+		}
+	}
+
+	/* Only the 5 or 2 GHz OB/DB need to be set for a mode */
+	if (eepMinorRev >= 2) {
+		if (IS_CHAN_2GHZ(chan)) {
+			ob2GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_2);
+			db2GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_2);
+			ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data,
+						       ob2GHz, 3, 197, 0);
+			ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data,
+						       db2GHz, 3, 194, 0);
+		} else {
+			ob5GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_5);
+			db5GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_5);
+			ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data,
+						       ob5GHz, 3, 203, 0);
+			ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data,
+						       db5GHz, 3, 200, 0);
+		}
+	}
+
+	/* Setup Bank 7 Setup */
+	ar5008_rf_bank_setup(ah->analogBank7Data, &ah->iniBank7, 1);
+
+	/* Write Analog registers */
+	REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data,
+			   regWrites);
+	REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data,
+			   regWrites);
+	REG_WRITE_RF_ARRAY(&ah->iniBank2, ah->analogBank2Data,
+			   regWrites);
+	REG_WRITE_RF_ARRAY(&ah->iniBank3, ah->analogBank3Data,
+			   regWrites);
+	REG_WRITE_RF_ARRAY(&ah->iniBank6TPC, ah->analogBank6Data,
+			   regWrites);
+	REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data,
+			   regWrites);
+
+	return 1;
+}
+
+static void ar5008_hw_init_bb(struct ath_hw *ah,
+			      struct ath9k_channel *chan)
+{
+	u32 synthDelay;
+
+	synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+	if (IS_CHAN_B(chan))
+		synthDelay = (4 * synthDelay) / 22;
+	else
+		synthDelay /= 10;
+
+	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+	udelay(synthDelay + BASE_ACTIVATE_DELAY);
+}
+
+static void ar5008_hw_init_chain_masks(struct ath_hw *ah)
+{
+	int rx_chainmask, tx_chainmask;
+
+	rx_chainmask = ah->rxchainmask;
+	tx_chainmask = ah->txchainmask;
+
+
+	switch (rx_chainmask) {
+	case 0x5:
+		REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+			    AR_PHY_SWAP_ALT_CHAIN);
+	case 0x3:
+		if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) {
+			REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
+			REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
+			break;
+		}
+	case 0x1:
+	case 0x2:
+	case 0x7:
+		ENABLE_REGWRITE_BUFFER(ah);
+		REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
+		REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
+		break;
+	default:
+		ENABLE_REGWRITE_BUFFER(ah);
+		break;
+	}
+
+	REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+
+	if (tx_chainmask == 0x5) {
+		REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+			    AR_PHY_SWAP_ALT_CHAIN);
+	}
+	if (AR_SREV_9100(ah))
+		REG_WRITE(ah, AR_PHY_ANALOG_SWAP,
+			  REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001);
+}
+
+static void ar5008_hw_override_ini(struct ath_hw *ah,
+				   struct ath9k_channel *chan __unused)
+{
+	u32 val;
+
+	/*
+	 * Set the RX_ABORT and RX_DIS and clear if off only after
+	 * RXE is set for MAC. This prevents frames with corrupted
+	 * descriptor status.
+	 */
+	REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+
+	if (AR_SREV_9280_20_OR_LATER(ah)) {
+		val = REG_READ(ah, AR_PCU_MISC_MODE2);
+
+		if (!AR_SREV_9271(ah))
+			val &= ~AR_PCU_MISC_MODE2_HWWAR1;
+
+		if (AR_SREV_9287_11_OR_LATER(ah))
+			val = val & (~AR_PCU_MISC_MODE2_HWWAR2);
+
+		REG_WRITE(ah, AR_PCU_MISC_MODE2, val);
+	}
+
+	if (!AR_SREV_5416_20_OR_LATER(ah) ||
+	    AR_SREV_9280_20_OR_LATER(ah))
+		return;
+	/*
+	 * Disable BB clock gating
+	 * Necessary to avoid issues on AR5416 2.0
+	 */
+	REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
+
+	/*
+	 * Disable RIFS search on some chips to avoid baseband
+	 * hang issues.
+	 */
+	if (AR_SREV_9100(ah) || AR_SREV_9160(ah)) {
+		val = REG_READ(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS);
+		val &= ~AR_PHY_RIFS_INIT_DELAY;
+		REG_WRITE(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS, val);
+	}
+}
+
+static void ar5008_hw_set_channel_regs(struct ath_hw *ah,
+				       struct ath9k_channel *chan)
+{
+	u32 phymode;
+	u32 enableDacFifo = 0;
+
+	if (AR_SREV_9285_12_OR_LATER(ah))
+		enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) &
+					 AR_PHY_FC_ENABLE_DAC_FIFO);
+
+	phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40
+		| AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo;
+
+	if (IS_CHAN_HT40(chan)) {
+		phymode |= AR_PHY_FC_DYN2040_EN;
+
+		if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
+		    (chan->chanmode == CHANNEL_G_HT40PLUS))
+			phymode |= AR_PHY_FC_DYN2040_PRI_CH;
+
+	}
+	REG_WRITE(ah, AR_PHY_TURBO, phymode);
+
+	ath9k_hw_set11nmac2040(ah);
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
+	REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+}
+
+
+static int ar5008_hw_process_ini(struct ath_hw *ah,
+				 struct ath9k_channel *chan)
+{
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+	struct ath_common *common = ath9k_hw_common(ah);
+	unsigned int i, regWrites = 0;
+	struct net80211_channel *channel = chan->chan;
+	u32 modesIndex, freqIndex;
+
+	switch (chan->chanmode) {
+	case CHANNEL_A:
+	case CHANNEL_A_HT20:
+		modesIndex = 1;
+		freqIndex = 1;
+		break;
+	case CHANNEL_A_HT40PLUS:
+	case CHANNEL_A_HT40MINUS:
+		modesIndex = 2;
+		freqIndex = 1;
+		break;
+	case CHANNEL_G:
+	case CHANNEL_G_HT20:
+	case CHANNEL_B:
+		modesIndex = 4;
+		freqIndex = 2;
+		break;
+	case CHANNEL_G_HT40PLUS:
+	case CHANNEL_G_HT40MINUS:
+		modesIndex = 3;
+		freqIndex = 2;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * Set correct baseband to analog shift setting to
+	 * access analog chips.
+	 */
+	REG_WRITE(ah, AR_PHY(0), 0x00000007);
+
+	/* Write ADDAC shifts */
+	REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO);
+	ah->eep_ops->set_addac(ah, chan);
+
+	if (AR_SREV_5416_22_OR_LATER(ah)) {
+		REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites);
+	} else {
+		struct ar5416IniArray temp;
+		u32 addacSize =
+			sizeof(u32) * ah->iniAddac.ia_rows *
+			ah->iniAddac.ia_columns;
+
+		/* For AR5416 2.0/2.1 */
+		memcpy(ah->addac5416_21,
+		       ah->iniAddac.ia_array, addacSize);
+
+		/* override CLKDRV value at [row, column] = [31, 1] */
+		(ah->addac5416_21)[31 * ah->iniAddac.ia_columns + 1] = 0;
+
+		temp.ia_array = ah->addac5416_21;
+		temp.ia_columns = ah->iniAddac.ia_columns;
+		temp.ia_rows = ah->iniAddac.ia_rows;
+		REG_WRITE_ARRAY(&temp, 1, regWrites);
+	}
+
+	REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC);
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	for (i = 0; i < ah->iniModes.ia_rows; i++) {
+		u32 reg = INI_RA(&ah->iniModes, i, 0);
+		u32 val = INI_RA(&ah->iniModes, i, modesIndex);
+
+		if (reg == AR_AN_TOP2 && ah->need_an_top2_fixup)
+			val &= ~AR_AN_TOP2_PWDCLKIND;
+
+		REG_WRITE(ah, reg, val);
+
+		if (reg >= 0x7800 && reg < 0x78a0
+		    && ah->config.analog_shiftreg
+		    && (common->bus_ops->ath_bus_type != ATH_USB)) {
+			udelay(100);
+		}
+
+		DO_DELAY(regWrites);
+	}
+
+	REGWRITE_BUFFER_FLUSH(ah);
+
+	if (AR_SREV_9280(ah) || AR_SREV_9287_11_OR_LATER(ah))
+		REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites);
+
+	if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah) ||
+	    AR_SREV_9287_11_OR_LATER(ah))
+		REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
+
+	if (AR_SREV_9271_10(ah))
+		REG_WRITE_ARRAY(&ah->iniModes_9271_1_0_only,
+				modesIndex, regWrites);
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	/* Write common array parameters */
+	for (i = 0; i < ah->iniCommon.ia_rows; i++) {
+		u32 reg = INI_RA(&ah->iniCommon, i, 0);
+		u32 val = INI_RA(&ah->iniCommon, i, 1);
+
+		REG_WRITE(ah, reg, val);
+
+		if (reg >= 0x7800 && reg < 0x78a0
+		    && ah->config.analog_shiftreg
+		    && (common->bus_ops->ath_bus_type != ATH_USB)) {
+			udelay(100);
+		}
+
+		DO_DELAY(regWrites);
+	}
+
+	REGWRITE_BUFFER_FLUSH(ah);
+
+	if (AR_SREV_9271(ah)) {
+		if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == 1)
+			REG_WRITE_ARRAY(&ah->iniModes_high_power_tx_gain_9271,
+					modesIndex, regWrites);
+		else
+			REG_WRITE_ARRAY(&ah->iniModes_normal_power_tx_gain_9271,
+					modesIndex, regWrites);
+	}
+
+	REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites);
+
+	if (IS_CHAN_A_FAST_CLOCK(ah, chan)) {
+		REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex,
+				regWrites);
+	}
+
+	ar5008_hw_override_ini(ah, chan);
+	ar5008_hw_set_channel_regs(ah, chan);
+	ar5008_hw_init_chain_masks(ah);
+	ath9k_olc_init(ah);
+
+	/* Set TX power */
+	ah->eep_ops->set_txpower(ah, chan,
+				 ath9k_regd_get_ctl(regulatory, chan),
+				 0,
+				 channel->maxpower * 2,
+				 min((u32) MAX_RATE_POWER,
+				 (u32) regulatory->power_limit), 0);
+
+	/* Write analog registers */
+	if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
+		DBG("ath9k: ar5416SetRfRegs failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void ar5008_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+	u32 rfMode = 0;
+
+	if (chan == NULL)
+		return;
+
+	rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
+		? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
+
+	if (!AR_SREV_9280_20_OR_LATER(ah))
+		rfMode |= (IS_CHAN_5GHZ(chan)) ?
+			AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ;
+
+	if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+		rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
+
+	REG_WRITE(ah, AR_PHY_MODE, rfMode);
+}
+
+static void ar5008_hw_mark_phy_inactive(struct ath_hw *ah)
+{
+	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+}
+
+static void ar5008_hw_set_delta_slope(struct ath_hw *ah,
+				      struct ath9k_channel *chan)
+{
+	u32 coef_scaled, ds_coef_exp, ds_coef_man;
+	u32 clockMhzScaled = 0x64000000;
+	struct chan_centers centers;
+
+	if (IS_CHAN_HALF_RATE(chan))
+		clockMhzScaled = clockMhzScaled >> 1;
+	else if (IS_CHAN_QUARTER_RATE(chan))
+		clockMhzScaled = clockMhzScaled >> 2;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+	coef_scaled = clockMhzScaled / centers.synth_center;
+
+	ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
+				      &ds_coef_exp);
+
+	REG_RMW_FIELD(ah, AR_PHY_TIMING3,
+		      AR_PHY_TIMING3_DSC_MAN, ds_coef_man);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING3,
+		      AR_PHY_TIMING3_DSC_EXP, ds_coef_exp);
+
+	coef_scaled = (9 * coef_scaled) / 10;
+
+	ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
+				      &ds_coef_exp);
+
+	REG_RMW_FIELD(ah, AR_PHY_HALFGI,
+		      AR_PHY_HALFGI_DSC_MAN, ds_coef_man);
+	REG_RMW_FIELD(ah, AR_PHY_HALFGI,
+		      AR_PHY_HALFGI_DSC_EXP, ds_coef_exp);
+}
+
+static int ar5008_hw_rfbus_req(struct ath_hw *ah)
+{
+	REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
+	return ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
+			   AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT);
+}
+
+static void ar5008_hw_rfbus_done(struct ath_hw *ah)
+{
+	u32 synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+	if (IS_CHAN_B(ah->curchan))
+		synthDelay = (4 * synthDelay) / 22;
+	else
+		synthDelay /= 10;
+
+	udelay(synthDelay + BASE_ACTIVATE_DELAY);
+
+	REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
+}
+
+static void ar5008_restore_chainmask(struct ath_hw *ah)
+{
+	int rx_chainmask = ah->rxchainmask;
+
+	if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
+		REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
+		REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
+	}
+}
+
+static void ar5008_set_diversity(struct ath_hw *ah, int value)
+{
+	u32 v = REG_READ(ah, AR_PHY_CCK_DETECT);
+	if (value)
+		v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+	else
+		v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+	REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
+}
+
+static u32 ar9100_hw_compute_pll_control(struct ath_hw *ah __unused,
+					 struct ath9k_channel *chan)
+{
+	if (chan && IS_CHAN_5GHZ(chan))
+		return 0x1450;
+	return 0x1458;
+}
+
+static u32 ar9160_hw_compute_pll_control(struct ath_hw *ah __unused,
+					 struct ath9k_channel *chan)
+{
+	u32 pll;
+
+	pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
+
+	if (chan && IS_CHAN_HALF_RATE(chan))
+		pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
+	else if (chan && IS_CHAN_QUARTER_RATE(chan))
+		pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
+
+	if (chan && IS_CHAN_5GHZ(chan))
+		pll |= SM(0x50, AR_RTC_9160_PLL_DIV);
+	else
+		pll |= SM(0x58, AR_RTC_9160_PLL_DIV);
+
+	return pll;
+}
+
+static u32 ar5008_hw_compute_pll_control(struct ath_hw *ah __unused,
+					 struct ath9k_channel *chan)
+{
+	u32 pll;
+
+	pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2;
+
+	if (chan && IS_CHAN_HALF_RATE(chan))
+		pll |= SM(0x1, AR_RTC_PLL_CLKSEL);
+	else if (chan && IS_CHAN_QUARTER_RATE(chan))
+		pll |= SM(0x2, AR_RTC_PLL_CLKSEL);
+
+	if (chan && IS_CHAN_5GHZ(chan))
+		pll |= SM(0xa, AR_RTC_PLL_DIV);
+	else
+		pll |= SM(0xb, AR_RTC_PLL_DIV);
+
+	return pll;
+}
+
+static int ar5008_hw_ani_control_old(struct ath_hw *ah,
+				      enum ath9k_ani_cmd cmd,
+				      int param)
+{
+	struct ar5416AniState *aniState = &ah->curchan->ani;
+
+	switch (cmd & ah->ani_function) {
+	case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
+		u32 level = param;
+
+		if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
+			DBG("ath9k: "
+				"level out of range (%d > %zd)\n",
+				level, ARRAY_SIZE(ah->totalSizeDesired));
+			return 0;
+		}
+
+		REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+			      AR_PHY_DESIRED_SZ_TOT_DES,
+			      ah->totalSizeDesired[level]);
+		REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
+			      AR_PHY_AGC_CTL1_COARSE_LOW,
+			      ah->coarse_low[level]);
+		REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
+			      AR_PHY_AGC_CTL1_COARSE_HIGH,
+			      ah->coarse_high[level]);
+		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+			      AR_PHY_FIND_SIG_FIRPWR,
+			      ah->firpwr[level]);
+
+		if (level > aniState->noiseImmunityLevel)
+			ah->stats.ast_ani_niup++;
+		else if (level < aniState->noiseImmunityLevel)
+			ah->stats.ast_ani_nidown++;
+		aniState->noiseImmunityLevel = level;
+		break;
+	}
+	case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
+		static const int m1ThreshLow[] = { 127, 50 };
+		static const int m2ThreshLow[] = { 127, 40 };
+		static const int m1Thresh[] = { 127, 0x4d };
+		static const int m2Thresh[] = { 127, 0x40 };
+		static const int m2CountThr[] = { 31, 16 };
+		static const int m2CountThrLow[] = { 63, 48 };
+		u32 on = param ? 1 : 0;
+
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
+			      m1ThreshLow[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
+			      m2ThreshLow[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M1_THRESH,
+			      m1Thresh[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M2_THRESH,
+			      m2Thresh[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M2COUNT_THR,
+			      m2CountThr[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
+			      m2CountThrLow[on]);
+
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
+			      m1ThreshLow[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
+			      m2ThreshLow[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M1_THRESH,
+			      m1Thresh[on]);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M2_THRESH,
+			      m2Thresh[on]);
+
+		if (on)
+			REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
+				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+		else
+			REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
+				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+
+		if (!on != aniState->ofdmWeakSigDetectOff) {
+			if (on)
+				ah->stats.ast_ani_ofdmon++;
+			else
+				ah->stats.ast_ani_ofdmoff++;
+			aniState->ofdmWeakSigDetectOff = !on;
+		}
+		break;
+	}
+	case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
+		static const int weakSigThrCck[] = { 8, 6 };
+		u32 high = param ? 1 : 0;
+
+		REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
+			      AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
+			      weakSigThrCck[high]);
+		if (high != aniState->cckWeakSigThreshold) {
+			if (high)
+				ah->stats.ast_ani_cckhigh++;
+			else
+				ah->stats.ast_ani_ccklow++;
+			aniState->cckWeakSigThreshold = high;
+		}
+		break;
+	}
+	case ATH9K_ANI_FIRSTEP_LEVEL:{
+		static const int firstep[] = { 0, 4, 8 };
+		u32 level = param;
+
+		if (level >= ARRAY_SIZE(firstep)) {
+			DBG("ath9k: "
+				"level out of range (%d > %zd)\n",
+				level, ARRAY_SIZE(firstep));
+			return 0;
+		}
+		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+			      AR_PHY_FIND_SIG_FIRSTEP,
+			      firstep[level]);
+		if (level > aniState->firstepLevel)
+			ah->stats.ast_ani_stepup++;
+		else if (level < aniState->firstepLevel)
+			ah->stats.ast_ani_stepdown++;
+		aniState->firstepLevel = level;
+		break;
+	}
+	case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
+		static const int cycpwrThr1[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
+		u32 level = param;
+
+		if (level >= ARRAY_SIZE(cycpwrThr1)) {
+			DBG("ath9k: "
+				"level out of range (%d > %zd)\n",
+				level, ARRAY_SIZE(cycpwrThr1));
+			return 0;
+		}
+		REG_RMW_FIELD(ah, AR_PHY_TIMING5,
+			      AR_PHY_TIMING5_CYCPWR_THR1,
+			      cycpwrThr1[level]);
+		if (level > aniState->spurImmunityLevel)
+			ah->stats.ast_ani_spurup++;
+		else if (level < aniState->spurImmunityLevel)
+			ah->stats.ast_ani_spurdown++;
+		aniState->spurImmunityLevel = level;
+		break;
+	}
+	case ATH9K_ANI_PRESENT:
+		break;
+	default:
+		DBG("ath9k: invalid cmd %d\n", cmd);
+		return 0;
+	}
+
+	DBG2("ath9k: ANI parameters:\n");
+	DBG2(
+		"noiseImmunityLevel=%d, spurImmunityLevel=%d, ofdmWeakSigDetectOff=%d\n",
+		aniState->noiseImmunityLevel,
+		aniState->spurImmunityLevel,
+		!aniState->ofdmWeakSigDetectOff);
+	DBG2(
+		"cckWeakSigThreshold=%d, firstepLevel=%d, listenTime=%d\n",
+		aniState->cckWeakSigThreshold,
+		aniState->firstepLevel,
+		aniState->listenTime);
+	DBG2(
+		"ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
+		aniState->ofdmPhyErrCount,
+		aniState->cckPhyErrCount);
+
+	return 1;
+}
+
+static int ar5008_hw_ani_control_new(struct ath_hw *ah,
+				      enum ath9k_ani_cmd cmd,
+				      int param)
+{
+	struct ath9k_channel *chan = ah->curchan;
+	struct ar5416AniState *aniState = &chan->ani;
+	s32 value, value2;
+
+	switch (cmd & ah->ani_function) {
+	case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
+		/*
+		 * on == 1 means ofdm weak signal detection is ON
+		 * on == 1 is the default, for less noise immunity
+		 *
+		 * on == 0 means ofdm weak signal detection is OFF
+		 * on == 0 means more noise imm
+		 */
+		u32 on = param ? 1 : 0;
+		/*
+		 * make register setting for default
+		 * (weak sig detect ON) come from INI file
+		 */
+		int m1ThreshLow = on ?
+			aniState->iniDef.m1ThreshLow : m1ThreshLow_off;
+		int m2ThreshLow = on ?
+			aniState->iniDef.m2ThreshLow : m2ThreshLow_off;
+		int m1Thresh = on ?
+			aniState->iniDef.m1Thresh : m1Thresh_off;
+		int m2Thresh = on ?
+			aniState->iniDef.m2Thresh : m2Thresh_off;
+		int m2CountThr = on ?
+			aniState->iniDef.m2CountThr : m2CountThr_off;
+		int m2CountThrLow = on ?
+			aniState->iniDef.m2CountThrLow : m2CountThrLow_off;
+		int m1ThreshLowExt = on ?
+			aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off;
+		int m2ThreshLowExt = on ?
+			aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off;
+		int m1ThreshExt = on ?
+			aniState->iniDef.m1ThreshExt : m1ThreshExt_off;
+		int m2ThreshExt = on ?
+			aniState->iniDef.m2ThreshExt : m2ThreshExt_off;
+
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
+			      m1ThreshLow);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
+			      m2ThreshLow);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M1_THRESH, m1Thresh);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M2_THRESH, m2Thresh);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M2COUNT_THR, m2CountThr);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
+			      m2CountThrLow);
+
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLowExt);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLowExt);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M1_THRESH, m1ThreshExt);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M2_THRESH, m2ThreshExt);
+
+		if (on)
+			REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
+				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+		else
+			REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
+				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+
+		if (!on != aniState->ofdmWeakSigDetectOff) {
+			DBG2("ath9k: "
+				"** ch %d: ofdm weak signal: %s=>%s\n",
+				chan->channel,
+				!aniState->ofdmWeakSigDetectOff ?
+				"on" : "off",
+				on ? "on" : "off");
+			if (on)
+				ah->stats.ast_ani_ofdmon++;
+			else
+				ah->stats.ast_ani_ofdmoff++;
+			aniState->ofdmWeakSigDetectOff = !on;
+		}
+		break;
+	}
+	case ATH9K_ANI_FIRSTEP_LEVEL:{
+		u32 level = param;
+
+		if (level >= ARRAY_SIZE(firstep_table)) {
+			DBG("ath9k: "
+				"ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%d > %zd)\n",
+				level, ARRAY_SIZE(firstep_table));
+			return 0;
+		}
+
+		/*
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value = firstep_table[level] -
+			firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+			aniState->iniDef.firstep;
+		if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+			value = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+		if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+			value = ATH9K_SIG_FIRSTEP_SETTING_MAX;
+		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+			      AR_PHY_FIND_SIG_FIRSTEP,
+			      value);
+		/*
+		 * we need to set first step low register too
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value2 = firstep_table[level] -
+			 firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+			 aniState->iniDef.firstepLow;
+		if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+			value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+		if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+			value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX;
+
+		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
+			      AR_PHY_FIND_SIG_FIRSTEP_LOW, value2);
+
+		if (level != aniState->firstepLevel) {
+			DBG2("ath9k: "
+				"** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n",
+				chan->channel,
+				aniState->firstepLevel,
+				level,
+				ATH9K_ANI_FIRSTEP_LVL_NEW,
+				value,
+				aniState->iniDef.firstep);
+			DBG2("ath9k: "
+				"** ch %d: level %d=>%d[def:%d] firstep_low[level]=%d ini=%d\n",
+				chan->channel,
+				aniState->firstepLevel,
+				level,
+				ATH9K_ANI_FIRSTEP_LVL_NEW,
+				value2,
+				aniState->iniDef.firstepLow);
+			if (level > aniState->firstepLevel)
+				ah->stats.ast_ani_stepup++;
+			else if (level < aniState->firstepLevel)
+				ah->stats.ast_ani_stepdown++;
+			aniState->firstepLevel = level;
+		}
+		break;
+	}
+	case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
+		u32 level = param;
+
+		if (level >= ARRAY_SIZE(cycpwrThr1_table)) {
+			DBG("ath9k: "
+				"ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%d > %zd)\n",
+				level, ARRAY_SIZE(cycpwrThr1_table));
+			return 0;
+		}
+		/*
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value = cycpwrThr1_table[level] -
+			cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+			aniState->iniDef.cycpwrThr1;
+		if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+			value = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+		if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+			value = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
+		REG_RMW_FIELD(ah, AR_PHY_TIMING5,
+			      AR_PHY_TIMING5_CYCPWR_THR1,
+			      value);
+
+		/*
+		 * set AR_PHY_EXT_CCA for extension channel
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value2 = cycpwrThr1_table[level] -
+			 cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+			 aniState->iniDef.cycpwrThr1Ext;
+		if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+			value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+		if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+			value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
+		REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+			      AR_PHY_EXT_TIMING5_CYCPWR_THR1, value2);
+
+		if (level != aniState->spurImmunityLevel) {
+			DBG2("ath9k: "
+				"** ch %d: level %d=>%d[def:%d] cycpwrThr1[level]=%d ini=%d\n",
+				chan->channel,
+				aniState->spurImmunityLevel,
+				level,
+				ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+				value,
+				aniState->iniDef.cycpwrThr1);
+			DBG2("ath9k: "
+				"** ch %d: level %d=>%d[def:%d] cycpwrThr1Ext[level]=%d ini=%d\n",
+				chan->channel,
+				aniState->spurImmunityLevel,
+				level,
+				ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+				value2,
+				aniState->iniDef.cycpwrThr1Ext);
+			if (level > aniState->spurImmunityLevel)
+				ah->stats.ast_ani_spurup++;
+			else if (level < aniState->spurImmunityLevel)
+				ah->stats.ast_ani_spurdown++;
+			aniState->spurImmunityLevel = level;
+		}
+		break;
+	}
+	case ATH9K_ANI_MRC_CCK:
+		/*
+		 * You should not see this as AR5008, AR9001, AR9002
+		 * does not have hardware support for MRC CCK.
+		 */
+		break;
+	case ATH9K_ANI_PRESENT:
+		break;
+	default:
+		DBG("ath9k: invalid cmd %d\n", cmd);
+		return 0;
+	}
+
+	DBG2("ath9k: "
+		"ANI parameters: SI=%d, ofdmWS=%s FS=%d MRCcck=%s listenTime=%d ofdmErrs=%d cckErrs=%d\n",
+		aniState->spurImmunityLevel,
+		!aniState->ofdmWeakSigDetectOff ? "on" : "off",
+		aniState->firstepLevel,
+		!aniState->mrcCCKOff ? "on" : "off",
+		aniState->listenTime,
+		aniState->ofdmPhyErrCount,
+		aniState->cckPhyErrCount);
+	return 1;
+}
+
+static void ar5008_hw_do_getnf(struct ath_hw *ah,
+			      int16_t nfarray[NUM_NF_READINGS])
+{
+	int16_t nf;
+
+	nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
+	nfarray[0] = sign_extend32(nf, 8);
+
+	nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR_PHY_CH1_MINCCA_PWR);
+	nfarray[1] = sign_extend32(nf, 8);
+
+	nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR);
+	nfarray[2] = sign_extend32(nf, 8);
+
+	if (!IS_CHAN_HT40(ah->curchan))
+		return;
+
+	nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR);
+	nfarray[3] = sign_extend32(nf, 8);
+
+	nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR_PHY_CH1_EXT_MINCCA_PWR);
+	nfarray[4] = sign_extend32(nf, 8);
+
+	nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR);
+	nfarray[5] = sign_extend32(nf, 8);
+}
+
+/*
+ * Initialize the ANI register values with default (ini) values.
+ * This routine is called during a (full) hardware reset after
+ * all the registers are initialised from the INI.
+ */
+static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
+{
+	struct ath9k_channel *chan = ah->curchan;
+	struct ar5416AniState *aniState = &chan->ani;
+	struct ath9k_ani_default *iniDef;
+	u32 val;
+
+	iniDef = &aniState->iniDef;
+
+	DBG2("ath9k: ver %d.%d chan %d Mhz/0x%x\n",
+		ah->hw_version.macVersion,
+		ah->hw_version.macRev,
+		chan->channel,
+		chan->channelFlags);
+
+	val = REG_READ(ah, AR_PHY_SFCORR);
+	iniDef->m1Thresh = MS(val, AR_PHY_SFCORR_M1_THRESH);
+	iniDef->m2Thresh = MS(val, AR_PHY_SFCORR_M2_THRESH);
+	iniDef->m2CountThr = MS(val, AR_PHY_SFCORR_M2COUNT_THR);
+
+	val = REG_READ(ah, AR_PHY_SFCORR_LOW);
+	iniDef->m1ThreshLow = MS(val, AR_PHY_SFCORR_LOW_M1_THRESH_LOW);
+	iniDef->m2ThreshLow = MS(val, AR_PHY_SFCORR_LOW_M2_THRESH_LOW);
+	iniDef->m2CountThrLow = MS(val, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW);
+
+	val = REG_READ(ah, AR_PHY_SFCORR_EXT);
+	iniDef->m1ThreshExt = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH);
+	iniDef->m2ThreshExt = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH);
+	iniDef->m1ThreshLowExt = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH_LOW);
+	iniDef->m2ThreshLowExt = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH_LOW);
+	iniDef->firstep = REG_READ_FIELD(ah,
+					 AR_PHY_FIND_SIG,
+					 AR_PHY_FIND_SIG_FIRSTEP);
+	iniDef->firstepLow = REG_READ_FIELD(ah,
+					    AR_PHY_FIND_SIG_LOW,
+					    AR_PHY_FIND_SIG_FIRSTEP_LOW);
+	iniDef->cycpwrThr1 = REG_READ_FIELD(ah,
+					    AR_PHY_TIMING5,
+					    AR_PHY_TIMING5_CYCPWR_THR1);
+	iniDef->cycpwrThr1Ext = REG_READ_FIELD(ah,
+					       AR_PHY_EXT_CCA,
+					       AR_PHY_EXT_TIMING5_CYCPWR_THR1);
+
+	/* these levels just got reset to defaults by the INI */
+	aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
+	aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
+	aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
+	aniState->mrcCCKOff = 1; /* not available on pre AR9003 */
+}
+
+static void ar5008_hw_set_nf_limits(struct ath_hw *ah)
+{
+	ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_2GHZ;
+	ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_2GHZ;
+	ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_5416_2GHZ;
+	ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_5GHZ;
+	ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_5GHZ;
+	ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_5416_5GHZ;
+}
+
+static void ar5008_hw_set_radar_params(struct ath_hw *ah,
+				       struct ath_hw_radar_conf *conf)
+{
+	u32 radar_0 = 0, radar_1 = 0;
+
+	if (!conf) {
+		REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
+		return;
+	}
+
+	radar_0 |= AR_PHY_RADAR_0_ENA | AR_PHY_RADAR_0_FFT_ENA;
+	radar_0 |= SM(conf->fir_power, AR_PHY_RADAR_0_FIRPWR);
+	radar_0 |= SM(conf->radar_rssi, AR_PHY_RADAR_0_RRSSI);
+	radar_0 |= SM(conf->pulse_height, AR_PHY_RADAR_0_HEIGHT);
+	radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI);
+	radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND);
+
+	radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI;
+	radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK;
+	radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN);
+	radar_1 |= SM(conf->pulse_inband_step, AR_PHY_RADAR_1_RELSTEP_THRESH);
+	radar_1 |= SM(conf->radar_inband, AR_PHY_RADAR_1_RELPWR_THRESH);
+
+	REG_WRITE(ah, AR_PHY_RADAR_0, radar_0);
+	REG_WRITE(ah, AR_PHY_RADAR_1, radar_1);
+	if (conf->ext_channel)
+		REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
+	else
+		REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
+}
+
+static void ar5008_hw_set_radar_conf(struct ath_hw *ah)
+{
+	struct ath_hw_radar_conf *conf = &ah->radar_conf;
+
+	conf->fir_power = -33;
+	conf->radar_rssi = 20;
+	conf->pulse_height = 10;
+	conf->pulse_rssi = 24;
+	conf->pulse_inband = 15;
+	conf->pulse_maxlen = 255;
+	conf->pulse_inband_step = 12;
+	conf->radar_inband = 8;
+}
+
+void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
+{
+	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+	static const u32 ar5416_cca_regs[6] = {
+		AR_PHY_CCA,
+		AR_PHY_CH1_CCA,
+		AR_PHY_CH2_CCA,
+		AR_PHY_EXT_CCA,
+		AR_PHY_CH1_EXT_CCA,
+		AR_PHY_CH2_EXT_CCA
+	};
+
+	priv_ops->rf_set_freq = ar5008_hw_set_channel;
+	priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate;
+
+	priv_ops->rf_alloc_ext_banks = ar5008_hw_rf_alloc_ext_banks;
+	priv_ops->rf_free_ext_banks = ar5008_hw_rf_free_ext_banks;
+	priv_ops->set_rf_regs = ar5008_hw_set_rf_regs;
+	priv_ops->set_channel_regs = ar5008_hw_set_channel_regs;
+	priv_ops->init_bb = ar5008_hw_init_bb;
+	priv_ops->process_ini = ar5008_hw_process_ini;
+	priv_ops->set_rfmode = ar5008_hw_set_rfmode;
+	priv_ops->mark_phy_inactive = ar5008_hw_mark_phy_inactive;
+	priv_ops->set_delta_slope = ar5008_hw_set_delta_slope;
+	priv_ops->rfbus_req = ar5008_hw_rfbus_req;
+	priv_ops->rfbus_done = ar5008_hw_rfbus_done;
+	priv_ops->restore_chainmask = ar5008_restore_chainmask;
+	priv_ops->set_diversity = ar5008_set_diversity;
+	priv_ops->do_getnf = ar5008_hw_do_getnf;
+	priv_ops->set_radar_params = ar5008_hw_set_radar_params;
+
+	if (modparam_force_new_ani) {
+		priv_ops->ani_control = ar5008_hw_ani_control_new;
+		priv_ops->ani_cache_ini_regs = ar5008_hw_ani_cache_ini_regs;
+	} else
+		priv_ops->ani_control = ar5008_hw_ani_control_old;
+
+	if (AR_SREV_9100(ah))
+		priv_ops->compute_pll_control = ar9100_hw_compute_pll_control;
+	else if (AR_SREV_9160_10_OR_LATER(ah))
+		priv_ops->compute_pll_control = ar9160_hw_compute_pll_control;
+	else
+		priv_ops->compute_pll_control = ar5008_hw_compute_pll_control;
+
+	ar5008_hw_set_nf_limits(ah);
+	ar5008_hw_set_radar_conf(ah);
+	memcpy(ah->nf_regs, ar5416_cca_regs, sizeof(ah->nf_regs));
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_calib.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_calib.c
new file mode 100644
index 0000000000000000000000000000000000000000..f8978a55828efd3146b4a92c6346b14b0a5c3840
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_calib.c
@@ -0,0 +1,997 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "hw.h"
+#include "hw-ops.h"
+#include "ar9002_phy.h"
+
+#define AR9285_CLCAL_REDO_THRESH    1
+
+enum ar9002_cal_types {
+	ADC_GAIN_CAL = BIT(0),
+	ADC_DC_CAL = BIT(1),
+	IQ_MISMATCH_CAL = BIT(2),
+};
+
+static int ar9002_hw_is_cal_supported(struct ath_hw *ah,
+				struct ath9k_channel *chan,
+				enum ar9002_cal_types cal_type)
+{
+	int supported = 0;
+	switch (ah->supp_cals & cal_type) {
+	case IQ_MISMATCH_CAL:
+		/* Run IQ Mismatch for non-CCK only */
+		if (!IS_CHAN_B(chan))
+			supported = 1;
+		break;
+	case ADC_GAIN_CAL:
+	case ADC_DC_CAL:
+		/* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */
+		if (!IS_CHAN_B(chan) &&
+		    !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
+			supported = 1;
+		break;
+	}
+	return supported;
+}
+
+static void ar9002_hw_setup_calibration(struct ath_hw *ah,
+					struct ath9k_cal_list *currCal)
+{
+	REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
+		      AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
+		      currCal->calData->calCountMax);
+
+	switch (currCal->calData->calType) {
+	case IQ_MISMATCH_CAL:
+		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
+		DBG2("ath9k: "
+			"starting IQ Mismatch Calibration\n");
+		break;
+	case ADC_GAIN_CAL:
+		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
+		DBG2("ath9k: "
+			"starting ADC Gain Calibration\n");
+		break;
+	case ADC_DC_CAL:
+		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
+		DBG2("ath9k: "
+			"starting ADC DC Calibration\n");
+		break;
+	}
+
+	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
+		    AR_PHY_TIMING_CTRL4_DO_CAL);
+}
+
+static int ar9002_hw_per_calibration(struct ath_hw *ah,
+				      struct ath9k_channel *ichan __unused,
+				      u8 rxchainmask,
+				      struct ath9k_cal_list *currCal)
+{
+	struct ath9k_hw_cal_data *caldata = ah->caldata;
+	int iscaldone = 0;
+
+	if (currCal->calState == CAL_RUNNING) {
+		if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
+		      AR_PHY_TIMING_CTRL4_DO_CAL)) {
+
+			currCal->calData->calCollect(ah);
+			ah->cal_samples++;
+
+			if (ah->cal_samples >=
+			    currCal->calData->calNumSamples) {
+				int i, numChains = 0;
+				for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+					if (rxchainmask & (1 << i))
+						numChains++;
+				}
+
+				currCal->calData->calPostProc(ah, numChains);
+				caldata->CalValid |= currCal->calData->calType;
+				currCal->calState = CAL_DONE;
+				iscaldone = 1;
+			} else {
+				ar9002_hw_setup_calibration(ah, currCal);
+			}
+		}
+	} else if (!(caldata->CalValid & currCal->calData->calType)) {
+		ath9k_hw_reset_calibration(ah, currCal);
+	}
+
+	return iscaldone;
+}
+
+static void ar9002_hw_iqcal_collect(struct ath_hw *ah)
+{
+	int i;
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		ah->totalPowerMeasI[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+		ah->totalPowerMeasQ[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+		ah->totalIqCorrMeas[i] +=
+			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+		DBG2("ath9k: "
+			"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
+			ah->cal_samples, i, ah->totalPowerMeasI[i],
+			ah->totalPowerMeasQ[i],
+			ah->totalIqCorrMeas[i]);
+	}
+}
+
+static void ar9002_hw_adc_gaincal_collect(struct ath_hw *ah)
+{
+	int i;
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		ah->totalAdcIOddPhase[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+		ah->totalAdcIEvenPhase[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+		ah->totalAdcQOddPhase[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+		ah->totalAdcQEvenPhase[i] +=
+			REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
+
+		DBG2("ath9k: "
+			"%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
+			ah->cal_samples, i,
+			ah->totalAdcIOddPhase[i],
+			ah->totalAdcIEvenPhase[i],
+			ah->totalAdcQOddPhase[i],
+			ah->totalAdcQEvenPhase[i]);
+	}
+}
+
+static void ar9002_hw_adc_dccal_collect(struct ath_hw *ah)
+{
+	int i;
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		ah->totalAdcDcOffsetIOddPhase[i] +=
+			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+		ah->totalAdcDcOffsetIEvenPhase[i] +=
+			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+		ah->totalAdcDcOffsetQOddPhase[i] +=
+			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+		ah->totalAdcDcOffsetQEvenPhase[i] +=
+			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
+
+		DBG2("ath9k: "
+			"%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
+			ah->cal_samples, i,
+			ah->totalAdcDcOffsetIOddPhase[i],
+			ah->totalAdcDcOffsetIEvenPhase[i],
+			ah->totalAdcDcOffsetQOddPhase[i],
+			ah->totalAdcDcOffsetQEvenPhase[i]);
+	}
+}
+
+static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
+{
+	u32 powerMeasQ, powerMeasI, iqCorrMeas;
+	u32 qCoffDenom, iCoffDenom;
+	int32_t qCoff, iCoff;
+	int iqCorrNeg, i;
+
+	for (i = 0; i < numChains; i++) {
+		powerMeasI = ah->totalPowerMeasI[i];
+		powerMeasQ = ah->totalPowerMeasQ[i];
+		iqCorrMeas = ah->totalIqCorrMeas[i];
+
+		DBG2("ath9k: "
+			"Starting IQ Cal and Correction for Chain %d\n",
+			i);
+
+		DBG2("ath9k: "
+			"Orignal: Chn %diq_corr_meas = 0x%08x\n",
+			i, ah->totalIqCorrMeas[i]);
+
+		iqCorrNeg = 0;
+
+		if (iqCorrMeas > 0x80000000) {
+			iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
+			iqCorrNeg = 1;
+		}
+
+		DBG2("ath9k: "
+			"Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
+		DBG2("ath9k: "
+			"Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
+		DBG2("ath9k: iqCorrNeg is 0x%08x\n",
+			iqCorrNeg);
+
+		iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
+		qCoffDenom = powerMeasQ / 64;
+
+		if ((powerMeasQ != 0) && (iCoffDenom != 0) &&
+		    (qCoffDenom != 0)) {
+			iCoff = iqCorrMeas / iCoffDenom;
+			qCoff = powerMeasI / qCoffDenom - 64;
+			DBG2("ath9k: "
+				"Chn %d iCoff = 0x%08x\n", i, iCoff);
+			DBG2("ath9k: "
+				"Chn %d qCoff = 0x%08x\n", i, qCoff);
+
+			iCoff = iCoff & 0x3f;
+			DBG2("ath9k: "
+				"New: Chn %d iCoff = 0x%08x\n", i, iCoff);
+			if (iqCorrNeg == 0x0)
+				iCoff = 0x40 - iCoff;
+
+			if (qCoff > 15)
+				qCoff = 15;
+			else if (qCoff <= -16)
+				qCoff = -16;
+
+			DBG2("ath9k: "
+				"Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
+				i, iCoff, qCoff);
+
+			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
+				      AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
+				      iCoff);
+			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
+				      AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
+				      qCoff);
+			DBG2("ath9k: "
+				"IQ Cal and Correction done for Chain %d\n",
+				i);
+		}
+	}
+
+	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
+		    AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
+}
+
+static void ar9002_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
+{
+	u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
+	u32 qGainMismatch, iGainMismatch, val, i;
+
+	for (i = 0; i < numChains; i++) {
+		iOddMeasOffset = ah->totalAdcIOddPhase[i];
+		iEvenMeasOffset = ah->totalAdcIEvenPhase[i];
+		qOddMeasOffset = ah->totalAdcQOddPhase[i];
+		qEvenMeasOffset = ah->totalAdcQEvenPhase[i];
+
+		DBG2("ath9k: "
+			"Starting ADC Gain Cal for Chain %d\n", i);
+
+		DBG2("ath9k: "
+			"Chn %d pwr_meas_odd_i = 0x%08x\n", i,
+			iOddMeasOffset);
+		DBG2("ath9k: "
+			"Chn %d pwr_meas_even_i = 0x%08x\n", i,
+			iEvenMeasOffset);
+		DBG2("ath9k: "
+			"Chn %d pwr_meas_odd_q = 0x%08x\n", i,
+			qOddMeasOffset);
+		DBG2("ath9k: "
+			"Chn %d pwr_meas_even_q = 0x%08x\n", i,
+			qEvenMeasOffset);
+
+		if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
+			iGainMismatch =
+				((iEvenMeasOffset * 32) /
+				 iOddMeasOffset) & 0x3f;
+			qGainMismatch =
+				((qOddMeasOffset * 32) /
+				 qEvenMeasOffset) & 0x3f;
+
+			DBG2("ath9k: "
+				"Chn %d gain_mismatch_i = 0x%08x\n", i,
+				iGainMismatch);
+			DBG2("ath9k: "
+				"Chn %d gain_mismatch_q = 0x%08x\n", i,
+				qGainMismatch);
+
+			val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
+			val &= 0xfffff000;
+			val |= (qGainMismatch) | (iGainMismatch << 6);
+			REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
+
+			DBG2("ath9k: "
+				"ADC Gain Cal done for Chain %d\n", i);
+		}
+	}
+
+	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
+		  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
+		  AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
+}
+
+static void ar9002_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
+{
+	u32 iOddMeasOffset, iEvenMeasOffset, val, i;
+	int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
+	const struct ath9k_percal_data *calData =
+		ah->cal_list_curr->calData;
+	u32 numSamples =
+		(1 << (calData->calCountMax + 5)) * calData->calNumSamples;
+
+	for (i = 0; i < numChains; i++) {
+		iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i];
+		iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i];
+		qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];
+		qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];
+
+		DBG2("ath9k: "
+			"Starting ADC DC Offset Cal for Chain %d\n", i);
+
+		DBG2("ath9k: "
+			"Chn %d pwr_meas_odd_i = %d\n", i,
+			iOddMeasOffset);
+		DBG2("ath9k: "
+			"Chn %d pwr_meas_even_i = %d\n", i,
+			iEvenMeasOffset);
+		DBG2("ath9k: "
+			"Chn %d pwr_meas_odd_q = %d\n", i,
+			qOddMeasOffset);
+		DBG2("ath9k: "
+			"Chn %d pwr_meas_even_q = %d\n", i,
+			qEvenMeasOffset);
+
+		iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
+			       numSamples) & 0x1ff;
+		qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
+			       numSamples) & 0x1ff;
+
+		DBG2("ath9k: "
+			"Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
+			iDcMismatch);
+		DBG2("ath9k: "
+			"Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
+			qDcMismatch);
+
+		val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
+		val &= 0xc0000fff;
+		val |= (qDcMismatch << 12) | (iDcMismatch << 21);
+		REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
+
+		DBG2("ath9k: "
+			"ADC DC Offset Cal done for Chain %d\n", i);
+	}
+
+	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
+		  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
+		  AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
+}
+
+static void ar9287_hw_olc_temp_compensation(struct ath_hw *ah)
+{
+	u32 rddata;
+	int32_t delta, currPDADC, slope;
+
+	rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
+	currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
+
+	if (ah->initPDADC == 0 || currPDADC == 0) {
+		/*
+		 * Zero value indicates that no frames have been transmitted
+		 * yet, can't do temperature compensation until frames are
+		 * transmitted.
+		 */
+		return;
+	} else {
+		slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);
+
+		if (slope == 0) { /* to avoid divide by zero case */
+			delta = 0;
+		} else {
+			delta = ((currPDADC - ah->initPDADC)*4) / slope;
+		}
+		REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
+			      AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
+		REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
+			      AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
+	}
+}
+
+static void ar9280_hw_olc_temp_compensation(struct ath_hw *ah)
+{
+	u32 rddata, i;
+	int delta, currPDADC, regval;
+
+	rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
+	currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
+
+	if (ah->initPDADC == 0 || currPDADC == 0)
+		return;
+
+	if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
+		delta = (currPDADC - ah->initPDADC + 4) / 8;
+	else
+		delta = (currPDADC - ah->initPDADC + 5) / 10;
+
+	if (delta != ah->PDADCdelta) {
+		ah->PDADCdelta = delta;
+		for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
+			regval = ah->originalGain[i] - delta;
+			if (regval < 0)
+				regval = 0;
+
+			REG_RMW_FIELD(ah,
+				      AR_PHY_TX_GAIN_TBL1 + i * 4,
+				      AR_PHY_TX_GAIN, regval);
+		}
+	}
+}
+
+static void ar9271_hw_pa_cal(struct ath_hw *ah, int is_reset)
+{
+	u32 regVal;
+	unsigned int i;
+	u32 regList[][2] = {
+		{ 0x786c, 0 },
+		{ 0x7854, 0 },
+		{ 0x7820, 0 },
+		{ 0x7824, 0 },
+		{ 0x7868, 0 },
+		{ 0x783c, 0 },
+		{ 0x7838, 0 } ,
+		{ 0x7828, 0 } ,
+	};
+
+	for (i = 0; i < ARRAY_SIZE(regList); i++)
+		regList[i][1] = REG_READ(ah, regList[i][0]);
+
+	regVal = REG_READ(ah, 0x7834);
+	regVal &= (~(0x1));
+	REG_WRITE(ah, 0x7834, regVal);
+	regVal = REG_READ(ah, 0x9808);
+	regVal |= (0x1 << 27);
+	REG_WRITE(ah, 0x9808, regVal);
+
+	/* 786c,b23,1, pwddac=1 */
+	REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
+	/* 7854, b5,1, pdrxtxbb=1 */
+	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
+	/* 7854, b7,1, pdv2i=1 */
+	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
+	/* 7854, b8,1, pddacinterface=1 */
+	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
+	/* 7824,b12,0, offcal=0 */
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
+	/* 7838, b1,0, pwddb=0 */
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
+	/* 7820,b11,0, enpacal=0 */
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
+	/* 7820,b25,1, pdpadrv1=0 */
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
+	/* 7820,b24,0, pdpadrv2=0 */
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
+	/* 7820,b23,0, pdpaout=0 */
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
+	/* 783c,b14-16,7, padrvgn2tab_0=7 */
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
+	/*
+	 * 7838,b29-31,0, padrvgn1tab_0=0
+	 * does not matter since we turn it off
+	 */
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
+
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);
+
+	/* Set:
+	 * localmode=1,bmode=1,bmoderxtx=1,synthon=1,
+	 * txon=1,paon=1,oscon=1,synthon_force=1
+	 */
+	REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
+	udelay(30);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0);
+
+	/* find off_6_1; */
+	for (i = 6; i > 0; i--) {
+		regVal = REG_READ(ah, 0x7834);
+		regVal |= (1 << (20 + i));
+		REG_WRITE(ah, 0x7834, regVal);
+		udelay(1);
+		/* regVal = REG_READ(ah, 0x7834); */
+		regVal &= (~(0x1 << (20 + i)));
+		regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9)
+			    << (20 + i));
+		REG_WRITE(ah, 0x7834, regVal);
+	}
+
+	regVal = (regVal >> 20) & 0x7f;
+
+	/* Update PA cal info */
+	if ((!is_reset) && ((unsigned int)ah->pacal_info.prev_offset == regVal)) {
+		if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
+			ah->pacal_info.max_skipcount =
+				2 * ah->pacal_info.max_skipcount;
+		ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
+	} else {
+		ah->pacal_info.max_skipcount = 1;
+		ah->pacal_info.skipcount = 0;
+		ah->pacal_info.prev_offset = regVal;
+	}
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	regVal = REG_READ(ah, 0x7834);
+	regVal |= 0x1;
+	REG_WRITE(ah, 0x7834, regVal);
+	regVal = REG_READ(ah, 0x9808);
+	regVal &= (~(0x1 << 27));
+	REG_WRITE(ah, 0x9808, regVal);
+
+	for (i = 0; i < ARRAY_SIZE(regList); i++)
+		REG_WRITE(ah, regList[i][0], regList[i][1]);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+}
+
+static inline void ar9285_hw_pa_cal(struct ath_hw *ah, int is_reset)
+{
+	u32 regVal;
+	unsigned int i;
+	int offset, offs_6_1, offs_0;
+	u32 ccomp_org, reg_field;
+	u32 regList[][2] = {
+		{ 0x786c, 0 },
+		{ 0x7854, 0 },
+		{ 0x7820, 0 },
+		{ 0x7824, 0 },
+		{ 0x7868, 0 },
+		{ 0x783c, 0 },
+		{ 0x7838, 0 },
+	};
+
+	DBG2("ath9k: Running PA Calibration\n");
+
+	/* PA CAL is not needed for high power solution */
+	if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==
+	    AR5416_EEP_TXGAIN_HIGH_POWER)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(regList); i++)
+		regList[i][1] = REG_READ(ah, regList[i][0]);
+
+	regVal = REG_READ(ah, 0x7834);
+	regVal &= (~(0x1));
+	REG_WRITE(ah, 0x7834, regVal);
+	regVal = REG_READ(ah, 0x9808);
+	regVal |= (0x1 << 27);
+	REG_WRITE(ah, 0x9808, regVal);
+
+	REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
+	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
+	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
+	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
+	ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf);
+
+	REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
+	udelay(30);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0);
+
+	for (i = 6; i > 0; i--) {
+		regVal = REG_READ(ah, 0x7834);
+		regVal |= (1 << (19 + i));
+		REG_WRITE(ah, 0x7834, regVal);
+		udelay(1);
+		regVal = REG_READ(ah, 0x7834);
+		regVal &= (~(0x1 << (19 + i)));
+		reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
+		regVal |= (reg_field << (19 + i));
+		REG_WRITE(ah, 0x7834, regVal);
+	}
+
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1);
+	udelay(1);
+	reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field);
+	offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS);
+	offs_0   = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP);
+
+	offset = (offs_6_1<<1) | offs_0;
+	offset = offset - 0;
+	offs_6_1 = offset>>1;
+	offs_0 = offset & 1;
+
+	if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) {
+		if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
+			ah->pacal_info.max_skipcount =
+				2 * ah->pacal_info.max_skipcount;
+		ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
+	} else {
+		ah->pacal_info.max_skipcount = 1;
+		ah->pacal_info.skipcount = 0;
+		ah->pacal_info.prev_offset = offset;
+	}
+
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);
+
+	regVal = REG_READ(ah, 0x7834);
+	regVal |= 0x1;
+	REG_WRITE(ah, 0x7834, regVal);
+	regVal = REG_READ(ah, 0x9808);
+	regVal &= (~(0x1 << 27));
+	REG_WRITE(ah, 0x9808, regVal);
+
+	for (i = 0; i < ARRAY_SIZE(regList); i++)
+		REG_WRITE(ah, regList[i][0], regList[i][1]);
+
+	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org);
+}
+
+static void ar9002_hw_pa_cal(struct ath_hw *ah, int is_reset)
+{
+	if (AR_SREV_9271(ah)) {
+		if (is_reset || !ah->pacal_info.skipcount)
+			ar9271_hw_pa_cal(ah, is_reset);
+		else
+			ah->pacal_info.skipcount--;
+	} else if (AR_SREV_9285_12_OR_LATER(ah)) {
+		if (is_reset || !ah->pacal_info.skipcount)
+			ar9285_hw_pa_cal(ah, is_reset);
+		else
+			ah->pacal_info.skipcount--;
+	}
+}
+
+static void ar9002_hw_olc_temp_compensation(struct ath_hw *ah)
+{
+	if (OLC_FOR_AR9287_10_LATER)
+		ar9287_hw_olc_temp_compensation(ah);
+	else if (OLC_FOR_AR9280_20_LATER)
+		ar9280_hw_olc_temp_compensation(ah);
+}
+
+static int ar9002_hw_calibrate(struct ath_hw *ah,
+				struct ath9k_channel *chan,
+				u8 rxchainmask,
+				int longcal)
+{
+	int iscaldone = 1;
+	struct ath9k_cal_list *currCal = ah->cal_list_curr;
+	int nfcal, nfcal_pending = 0;
+
+	nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
+	if (ah->caldata)
+		nfcal_pending = ah->caldata->nfcal_pending;
+
+	if (currCal && !nfcal &&
+	    (currCal->calState == CAL_RUNNING ||
+	     currCal->calState == CAL_WAITING)) {
+		iscaldone = ar9002_hw_per_calibration(ah, chan,
+						      rxchainmask, currCal);
+		if (iscaldone) {
+			ah->cal_list_curr = currCal = currCal->calNext;
+
+			if (currCal->calState == CAL_WAITING) {
+				iscaldone = 0;
+				ath9k_hw_reset_calibration(ah, currCal);
+			}
+		}
+	}
+
+	/* Do NF cal only at longer intervals */
+	if (longcal || nfcal_pending) {
+		/*
+		 * Get the value from the previous NF cal and update
+		 * history buffer.
+		 */
+		if (ath9k_hw_getnf(ah, chan)) {
+			/*
+			 * Load the NF from history buffer of the current
+			 * channel.
+			 * NF is slow time-variant, so it is OK to use a
+			 * historical value.
+			 */
+			ath9k_hw_loadnf(ah, ah->curchan);
+		}
+
+		if (longcal) {
+			ath9k_hw_start_nfcal(ah, 0);
+			/* Do periodic PAOffset Cal */
+			ar9002_hw_pa_cal(ah, 0);
+			ar9002_hw_olc_temp_compensation(ah);
+		}
+	}
+
+	return iscaldone;
+}
+
+/* Carrier leakage Calibration fix */
+static int ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+	REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
+	if (IS_CHAN_HT20(chan)) {
+		REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
+		REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
+		REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+			    AR_PHY_AGC_CONTROL_FLTR_CAL);
+		REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
+		REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
+		if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
+				  AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {
+			DBG("ath9k: "
+				"offset calibration failed to complete in 1ms; noisy environment?\n");
+			return 0;
+		}
+		REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
+		REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
+		REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
+	}
+	REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
+	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+	REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
+	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
+	if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
+			  0, AH_WAIT_TIMEOUT)) {
+		DBG("ath9k: "
+			"offset calibration failed to complete in 1ms; noisy environment?\n");
+		return 0;
+	}
+
+	REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
+	REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
+	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+
+	return 1;
+}
+
+static int ar9285_hw_clc(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+	unsigned int i;
+	uint32_t txgain_max;
+	uint32_t clc_gain, gain_mask = 0, clc_num = 0;
+	uint32_t reg_clc_I0, reg_clc_Q0;
+	uint32_t i0_num = 0;
+	uint32_t q0_num = 0;
+	uint32_t total_num = 0;
+	uint32_t reg_rf2g5_org;
+	int retv = 1;
+
+	if (!(ar9285_hw_cl_cal(ah, chan)))
+		return 0;
+
+	txgain_max = MS(REG_READ(ah, AR_PHY_TX_PWRCTRL7),
+			AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX);
+
+	for (i = 0; i < (txgain_max+1); i++) {
+		clc_gain = (REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) &
+			   AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S;
+		if (!(gain_mask & (1 << clc_gain))) {
+			gain_mask |= (1 << clc_gain);
+			clc_num++;
+		}
+	}
+
+	for (i = 0; i < clc_num; i++) {
+		reg_clc_I0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
+			      & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S;
+		reg_clc_Q0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
+			      & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S;
+		if (reg_clc_I0 == 0)
+			i0_num++;
+
+		if (reg_clc_Q0 == 0)
+			q0_num++;
+	}
+	total_num = i0_num + q0_num;
+	if (total_num > AR9285_CLCAL_REDO_THRESH) {
+		reg_rf2g5_org = REG_READ(ah, AR9285_RF2G5);
+		if (AR_SREV_9285E_20(ah)) {
+			REG_WRITE(ah, AR9285_RF2G5,
+				  (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
+				  AR9285_RF2G5_IC50TX_XE_SET);
+		} else {
+			REG_WRITE(ah, AR9285_RF2G5,
+				  (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
+				  AR9285_RF2G5_IC50TX_SET);
+		}
+		retv = ar9285_hw_cl_cal(ah, chan);
+		REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org);
+	}
+	return retv;
+}
+
+static int ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+	if (AR_SREV_9271(ah)) {
+		if (!ar9285_hw_cl_cal(ah, chan))
+			return 0;
+	} else if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) {
+		if (!ar9285_hw_clc(ah, chan))
+			return 0;
+	} else {
+		if (AR_SREV_9280_20_OR_LATER(ah)) {
+			if (!AR_SREV_9287_11_OR_LATER(ah))
+				REG_CLR_BIT(ah, AR_PHY_ADC_CTL,
+					    AR_PHY_ADC_CTL_OFF_PWDADC);
+			REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+				    AR_PHY_AGC_CONTROL_FLTR_CAL);
+		}
+
+		/* Calibrate the AGC */
+		REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+			  REG_READ(ah, AR_PHY_AGC_CONTROL) |
+			  AR_PHY_AGC_CONTROL_CAL);
+
+		/* Poll for offset calibration complete */
+		if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
+				   AR_PHY_AGC_CONTROL_CAL,
+				   0, AH_WAIT_TIMEOUT)) {
+			DBG("ath9k: "
+				"offset calibration failed to complete in 1ms; noisy environment?\n");
+			return 0;
+		}
+
+		if (AR_SREV_9280_20_OR_LATER(ah)) {
+			if (!AR_SREV_9287_11_OR_LATER(ah))
+				REG_SET_BIT(ah, AR_PHY_ADC_CTL,
+					    AR_PHY_ADC_CTL_OFF_PWDADC);
+			REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+				    AR_PHY_AGC_CONTROL_FLTR_CAL);
+		}
+	}
+
+	/* Do PA Calibration */
+	ar9002_hw_pa_cal(ah, 1);
+
+	/* Do NF Calibration after DC offset and other calibrations */
+	ath9k_hw_start_nfcal(ah, 1);
+
+	if (ah->caldata)
+		ah->caldata->nfcal_pending = 1;
+
+	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
+
+	/* Enable IQ, ADC Gain and ADC DC offset CALs */
+	if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
+		ah->supp_cals = IQ_MISMATCH_CAL;
+
+		if (AR_SREV_9160_10_OR_LATER(ah))
+			ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL;
+
+		if (AR_SREV_9287(ah))
+			ah->supp_cals &= ~ADC_GAIN_CAL;
+
+		if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) {
+			INIT_CAL(&ah->adcgain_caldata);
+			INSERT_CAL(ah, &ah->adcgain_caldata);
+			DBG2("ath9k: "
+					"enabling ADC Gain Calibration.\n");
+		}
+
+		if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) {
+			INIT_CAL(&ah->adcdc_caldata);
+			INSERT_CAL(ah, &ah->adcdc_caldata);
+			DBG2("ath9k: "
+					"enabling ADC DC Calibration.\n");
+		}
+
+		if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) {
+			INIT_CAL(&ah->iq_caldata);
+			INSERT_CAL(ah, &ah->iq_caldata);
+			DBG2("ath9k: "
+					"enabling IQ Calibration.\n");
+		}
+
+		ah->cal_list_curr = ah->cal_list;
+
+		if (ah->cal_list_curr)
+			ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
+	}
+
+	if (ah->caldata)
+		ah->caldata->CalValid = 0;
+
+	return 1;
+}
+
+static const struct ath9k_percal_data iq_cal_multi_sample = {
+	IQ_MISMATCH_CAL,
+	MAX_CAL_SAMPLES,
+	PER_MIN_LOG_COUNT,
+	ar9002_hw_iqcal_collect,
+	ar9002_hw_iqcalibrate
+};
+static const struct ath9k_percal_data iq_cal_single_sample = {
+	IQ_MISMATCH_CAL,
+	MIN_CAL_SAMPLES,
+	PER_MAX_LOG_COUNT,
+	ar9002_hw_iqcal_collect,
+	ar9002_hw_iqcalibrate
+};
+static const struct ath9k_percal_data adc_gain_cal_multi_sample = {
+	ADC_GAIN_CAL,
+	MAX_CAL_SAMPLES,
+	PER_MIN_LOG_COUNT,
+	ar9002_hw_adc_gaincal_collect,
+	ar9002_hw_adc_gaincal_calibrate
+};
+static const struct ath9k_percal_data adc_gain_cal_single_sample = {
+	ADC_GAIN_CAL,
+	MIN_CAL_SAMPLES,
+	PER_MAX_LOG_COUNT,
+	ar9002_hw_adc_gaincal_collect,
+	ar9002_hw_adc_gaincal_calibrate
+};
+static const struct ath9k_percal_data adc_dc_cal_multi_sample = {
+	ADC_DC_CAL,
+	MAX_CAL_SAMPLES,
+	PER_MIN_LOG_COUNT,
+	ar9002_hw_adc_dccal_collect,
+	ar9002_hw_adc_dccal_calibrate
+};
+static const struct ath9k_percal_data adc_dc_cal_single_sample = {
+	ADC_DC_CAL,
+	MIN_CAL_SAMPLES,
+	PER_MAX_LOG_COUNT,
+	ar9002_hw_adc_dccal_collect,
+	ar9002_hw_adc_dccal_calibrate
+};
+
+static void ar9002_hw_init_cal_settings(struct ath_hw *ah)
+{
+	if (AR_SREV_9100(ah)) {
+		ah->iq_caldata.calData = &iq_cal_multi_sample;
+		ah->supp_cals = IQ_MISMATCH_CAL;
+		return;
+	}
+
+	if (AR_SREV_9160_10_OR_LATER(ah)) {
+		if (AR_SREV_9280_20_OR_LATER(ah)) {
+			ah->iq_caldata.calData = &iq_cal_single_sample;
+			ah->adcgain_caldata.calData =
+				&adc_gain_cal_single_sample;
+			ah->adcdc_caldata.calData =
+				&adc_dc_cal_single_sample;
+		} else {
+			ah->iq_caldata.calData = &iq_cal_multi_sample;
+			ah->adcgain_caldata.calData =
+				&adc_gain_cal_multi_sample;
+			ah->adcdc_caldata.calData =
+				&adc_dc_cal_multi_sample;
+		}
+		ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
+
+		if (AR_SREV_9287(ah))
+			ah->supp_cals &= ~ADC_GAIN_CAL;
+	}
+}
+
+void ar9002_hw_attach_calib_ops(struct ath_hw *ah)
+{
+	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+	priv_ops->init_cal_settings = ar9002_hw_init_cal_settings;
+	priv_ops->init_cal = ar9002_hw_init_cal;
+	priv_ops->setup_calibration = ar9002_hw_setup_calibration;
+
+	ops->calibrate = ar9002_hw_calibrate;
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_hw.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_hw.c
new file mode 100644
index 0000000000000000000000000000000000000000..cc4edece44cff0b45538599e09384d8d5dd239e1
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_hw.c
@@ -0,0 +1,607 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "hw.h"
+#include "ar5008_initvals.h"
+#include "ar9001_initvals.h"
+#include "ar9002_initvals.h"
+#include "ar9002_phy.h"
+
+int modparam_force_new_ani;
+
+/* General hardware code for the A5008/AR9001/AR9002 hadware families */
+
+static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
+{
+	if (AR_SREV_9271(ah)) {
+		INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271,
+			       ARRAY_SIZE(ar9271Modes_9271), 6);
+		INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271,
+			       ARRAY_SIZE(ar9271Common_9271), 2);
+		INIT_INI_ARRAY(&ah->iniCommon_normal_cck_fir_coeff_9271,
+			       ar9271Common_normal_cck_fir_coeff_9271,
+			       ARRAY_SIZE(ar9271Common_normal_cck_fir_coeff_9271), 2);
+		INIT_INI_ARRAY(&ah->iniCommon_japan_2484_cck_fir_coeff_9271,
+			       ar9271Common_japan_2484_cck_fir_coeff_9271,
+			       ARRAY_SIZE(ar9271Common_japan_2484_cck_fir_coeff_9271), 2);
+		INIT_INI_ARRAY(&ah->iniModes_9271_1_0_only,
+			       ar9271Modes_9271_1_0_only,
+			       ARRAY_SIZE(ar9271Modes_9271_1_0_only), 6);
+		INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg,
+			       ARRAY_SIZE(ar9271Modes_9271_ANI_reg), 6);
+		INIT_INI_ARRAY(&ah->iniModes_high_power_tx_gain_9271,
+			       ar9271Modes_high_power_tx_gain_9271,
+			       ARRAY_SIZE(ar9271Modes_high_power_tx_gain_9271), 6);
+		INIT_INI_ARRAY(&ah->iniModes_normal_power_tx_gain_9271,
+			       ar9271Modes_normal_power_tx_gain_9271,
+			       ARRAY_SIZE(ar9271Modes_normal_power_tx_gain_9271), 6);
+		return;
+	}
+
+	if (AR_SREV_9287_11_OR_LATER(ah)) {
+		INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1,
+				ARRAY_SIZE(ar9287Modes_9287_1_1), 6);
+		INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1,
+				ARRAY_SIZE(ar9287Common_9287_1_1), 2);
+		if (ah->config.pcie_clock_req)
+			INIT_INI_ARRAY(&ah->iniPcieSerdes,
+			ar9287PciePhy_clkreq_off_L1_9287_1_1,
+			ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2);
+		else
+			INIT_INI_ARRAY(&ah->iniPcieSerdes,
+			ar9287PciePhy_clkreq_always_on_L1_9287_1_1,
+			ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1),
+					2);
+	} else if (AR_SREV_9285_12_OR_LATER(ah)) {
+
+
+		INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
+			       ARRAY_SIZE(ar9285Modes_9285_1_2), 6);
+		INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2,
+			       ARRAY_SIZE(ar9285Common_9285_1_2), 2);
+
+		if (ah->config.pcie_clock_req) {
+			INIT_INI_ARRAY(&ah->iniPcieSerdes,
+			ar9285PciePhy_clkreq_off_L1_9285_1_2,
+			ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2);
+		} else {
+			INIT_INI_ARRAY(&ah->iniPcieSerdes,
+			ar9285PciePhy_clkreq_always_on_L1_9285_1_2,
+			ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2),
+				  2);
+		}
+	} else if (AR_SREV_9280_20_OR_LATER(ah)) {
+		INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2,
+			       ARRAY_SIZE(ar9280Modes_9280_2), 6);
+		INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2,
+			       ARRAY_SIZE(ar9280Common_9280_2), 2);
+
+		if (ah->config.pcie_clock_req) {
+			INIT_INI_ARRAY(&ah->iniPcieSerdes,
+			       ar9280PciePhy_clkreq_off_L1_9280,
+			       ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280), 2);
+		} else {
+			INIT_INI_ARRAY(&ah->iniPcieSerdes,
+			       ar9280PciePhy_clkreq_always_on_L1_9280,
+			       ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2);
+		}
+		INIT_INI_ARRAY(&ah->iniModesAdditional,
+			       ar9280Modes_fast_clock_9280_2,
+			       ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
+	} else if (AR_SREV_9160_10_OR_LATER(ah)) {
+		INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160,
+			       ARRAY_SIZE(ar5416Modes_9160), 6);
+		INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160,
+			       ARRAY_SIZE(ar5416Common_9160), 2);
+		INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160,
+			       ARRAY_SIZE(ar5416Bank0_9160), 2);
+		INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9160,
+			       ARRAY_SIZE(ar5416BB_RfGain_9160), 3);
+		INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9160,
+			       ARRAY_SIZE(ar5416Bank1_9160), 2);
+		INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9160,
+			       ARRAY_SIZE(ar5416Bank2_9160), 2);
+		INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9160,
+			       ARRAY_SIZE(ar5416Bank3_9160), 3);
+		INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9160,
+			       ARRAY_SIZE(ar5416Bank6_9160), 3);
+		INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9160,
+			       ARRAY_SIZE(ar5416Bank6TPC_9160), 3);
+		INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9160,
+			       ARRAY_SIZE(ar5416Bank7_9160), 2);
+		if (AR_SREV_9160_11(ah)) {
+			INIT_INI_ARRAY(&ah->iniAddac,
+				       ar5416Addac_9160_1_1,
+				       ARRAY_SIZE(ar5416Addac_9160_1_1), 2);
+		} else {
+			INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160,
+				       ARRAY_SIZE(ar5416Addac_9160), 2);
+		}
+	} else if (AR_SREV_9100_OR_LATER(ah)) {
+		INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100,
+			       ARRAY_SIZE(ar5416Modes_9100), 6);
+		INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100,
+			       ARRAY_SIZE(ar5416Common_9100), 2);
+		INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100,
+			       ARRAY_SIZE(ar5416Bank0_9100), 2);
+		INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9100,
+			       ARRAY_SIZE(ar5416BB_RfGain_9100), 3);
+		INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9100,
+			       ARRAY_SIZE(ar5416Bank1_9100), 2);
+		INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9100,
+			       ARRAY_SIZE(ar5416Bank2_9100), 2);
+		INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9100,
+			       ARRAY_SIZE(ar5416Bank3_9100), 3);
+		INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100,
+			       ARRAY_SIZE(ar5416Bank6_9100), 3);
+		INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100,
+			       ARRAY_SIZE(ar5416Bank6TPC_9100), 3);
+		INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9100,
+			       ARRAY_SIZE(ar5416Bank7_9100), 2);
+		INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100,
+			       ARRAY_SIZE(ar5416Addac_9100), 2);
+	} else {
+		INIT_INI_ARRAY(&ah->iniModes, ar5416Modes,
+			       ARRAY_SIZE(ar5416Modes), 6);
+		INIT_INI_ARRAY(&ah->iniCommon, ar5416Common,
+			       ARRAY_SIZE(ar5416Common), 2);
+		INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0,
+			       ARRAY_SIZE(ar5416Bank0), 2);
+		INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain,
+			       ARRAY_SIZE(ar5416BB_RfGain), 3);
+		INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1,
+			       ARRAY_SIZE(ar5416Bank1), 2);
+		INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2,
+			       ARRAY_SIZE(ar5416Bank2), 2);
+		INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3,
+			       ARRAY_SIZE(ar5416Bank3), 3);
+		INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6,
+			       ARRAY_SIZE(ar5416Bank6), 3);
+		INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC,
+			       ARRAY_SIZE(ar5416Bank6TPC), 3);
+		INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7,
+			       ARRAY_SIZE(ar5416Bank7), 2);
+		INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac,
+			       ARRAY_SIZE(ar5416Addac), 2);
+	}
+}
+
+/* Support for Japan ch.14 (2484) spread */
+void ar9002_hw_cck_chan14_spread(struct ath_hw *ah)
+{
+	if (AR_SREV_9287_11_OR_LATER(ah)) {
+		INIT_INI_ARRAY(&ah->iniCckfirNormal,
+		       ar9287Common_normal_cck_fir_coeff_9287_1_1,
+		       ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_9287_1_1),
+		       2);
+		INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
+		       ar9287Common_japan_2484_cck_fir_coeff_9287_1_1,
+		       ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_9287_1_1),
+		       2);
+	}
+}
+
+static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah)
+{
+	u32 rxgain_type;
+
+	if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >=
+	    AR5416_EEP_MINOR_VER_17) {
+		rxgain_type = ah->eep_ops->get_eeprom(ah, EEP_RXGAIN_TYPE);
+
+		if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF)
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+			ar9280Modes_backoff_13db_rxgain_9280_2,
+			ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6);
+		else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF)
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+			ar9280Modes_backoff_23db_rxgain_9280_2,
+			ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6);
+		else
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+			ar9280Modes_original_rxgain_9280_2,
+			ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
+	} else {
+		INIT_INI_ARRAY(&ah->iniModesRxGain,
+			ar9280Modes_original_rxgain_9280_2,
+			ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
+	}
+}
+
+static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah)
+{
+	u32 txgain_type;
+
+	if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >=
+	    AR5416_EEP_MINOR_VER_19) {
+		txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
+
+		if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+			ar9280Modes_high_power_tx_gain_9280_2,
+			ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6);
+		else
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+			ar9280Modes_original_tx_gain_9280_2,
+			ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
+	} else {
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
+		ar9280Modes_original_tx_gain_9280_2,
+		ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
+	}
+}
+
+static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah)
+{
+	if (AR_SREV_9287_11_OR_LATER(ah))
+		INIT_INI_ARRAY(&ah->iniModesRxGain,
+		ar9287Modes_rx_gain_9287_1_1,
+		ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6);
+	else if (AR_SREV_9280_20(ah))
+		ar9280_20_hw_init_rxgain_ini(ah);
+
+	if (AR_SREV_9287_11_OR_LATER(ah)) {
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
+		ar9287Modes_tx_gain_9287_1_1,
+		ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6);
+	} else if (AR_SREV_9280_20(ah)) {
+		ar9280_20_hw_init_txgain_ini(ah);
+	} else if (AR_SREV_9285_12_OR_LATER(ah)) {
+		u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
+
+		/* txgain table */
+		if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) {
+			if (AR_SREV_9285E_20(ah)) {
+				INIT_INI_ARRAY(&ah->iniModesTxGain,
+				ar9285Modes_XE2_0_high_power,
+				ARRAY_SIZE(
+				  ar9285Modes_XE2_0_high_power), 6);
+			} else {
+				INIT_INI_ARRAY(&ah->iniModesTxGain,
+				ar9285Modes_high_power_tx_gain_9285_1_2,
+				ARRAY_SIZE(
+				  ar9285Modes_high_power_tx_gain_9285_1_2), 6);
+			}
+		} else {
+			if (AR_SREV_9285E_20(ah)) {
+				INIT_INI_ARRAY(&ah->iniModesTxGain,
+				ar9285Modes_XE2_0_normal_power,
+				ARRAY_SIZE(
+				  ar9285Modes_XE2_0_normal_power), 6);
+			} else {
+				INIT_INI_ARRAY(&ah->iniModesTxGain,
+				ar9285Modes_original_tx_gain_9285_1_2,
+				ARRAY_SIZE(
+				  ar9285Modes_original_tx_gain_9285_1_2), 6);
+			}
+		}
+	}
+}
+
+/*
+ * Helper for ASPM support.
+ *
+ * Disable PLL when in L0s as well as receiver clock when in L1.
+ * This power saving option must be enabled through the SerDes.
+ *
+ * Programming the SerDes must go through the same 288 bit serial shift
+ * register as the other analog registers.  Hence the 9 writes.
+ */
+static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
+					 int restore,
+					 int power_off)
+{
+	u8 i;
+	u32 val;
+
+	if (ah->is_pciexpress != 1)
+		return;
+
+	/* Do not touch SerDes registers */
+	if (ah->config.pcie_powersave_enable == 2)
+		return;
+
+	/* Nothing to do on restore for 11N */
+	if (!restore) {
+		if (AR_SREV_9280_20_OR_LATER(ah)) {
+			/*
+			 * AR9280 2.0 or later chips use SerDes values from the
+			 * initvals.h initialized depending on chipset during
+			 * __ath9k_hw_init()
+			 */
+			for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) {
+				REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0),
+					  INI_RA(&ah->iniPcieSerdes, i, 1));
+			}
+		} else {
+			ENABLE_REGWRITE_BUFFER(ah);
+
+			REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
+			REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+
+			/* RX shut off when elecidle is asserted */
+			REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
+			REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
+			REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
+
+			/*
+			 * Ignore ah->ah_config.pcie_clock_req setting for
+			 * pre-AR9280 11n
+			 */
+			REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
+
+			REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+			REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+			REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
+
+			/* Load the new settings */
+			REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+
+			REGWRITE_BUFFER_FLUSH(ah);
+		}
+
+		udelay(1000);
+	}
+
+	if (power_off) {
+		/* clear bit 19 to disable L1 */
+		REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+
+		val = REG_READ(ah, AR_WA);
+
+		/*
+		 * Set PCIe workaround bits
+		 * In AR9280 and AR9285, bit 14 in WA register (disable L1)
+		 * should only  be set when device enters D3 and be
+		 * cleared when device comes back to D0.
+		 */
+		if (ah->config.pcie_waen) {
+			if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
+				val |= AR_WA_D3_L1_DISABLE;
+		} else {
+			if (((AR_SREV_9285(ah) ||
+			      AR_SREV_9271(ah) ||
+			      AR_SREV_9287(ah)) &&
+			     (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) ||
+			    (AR_SREV_9280(ah) &&
+			     (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) {
+				val |= AR_WA_D3_L1_DISABLE;
+			}
+		}
+
+		if (AR_SREV_9280(ah) || AR_SREV_9285(ah) || AR_SREV_9287(ah)) {
+			/*
+			 * Disable bit 6 and 7 before entering D3 to
+			 * prevent system hang.
+			 */
+			val &= ~(AR_WA_BIT6 | AR_WA_BIT7);
+		}
+
+		if (AR_SREV_9280(ah))
+			val |= AR_WA_BIT22;
+
+		if (AR_SREV_9285E_20(ah))
+			val |= AR_WA_BIT23;
+
+		REG_WRITE(ah, AR_WA, val);
+	} else {
+		if (ah->config.pcie_waen) {
+			val = ah->config.pcie_waen;
+			if (!power_off)
+				val &= (~AR_WA_D3_L1_DISABLE);
+		} else {
+			if (AR_SREV_9285(ah) ||
+			    AR_SREV_9271(ah) ||
+			    AR_SREV_9287(ah)) {
+				val = AR9285_WA_DEFAULT;
+				if (!power_off)
+					val &= (~AR_WA_D3_L1_DISABLE);
+			}
+			else if (AR_SREV_9280(ah)) {
+				/*
+				 * For AR9280 chips, bit 22 of 0x4004
+				 * needs to be set.
+				 */
+				val = AR9280_WA_DEFAULT;
+				if (!power_off)
+					val &= (~AR_WA_D3_L1_DISABLE);
+			} else {
+				val = AR_WA_DEFAULT;
+			}
+		}
+
+		/* WAR for ASPM system hang */
+		if (AR_SREV_9285(ah) || AR_SREV_9287(ah))
+			val |= (AR_WA_BIT6 | AR_WA_BIT7);
+
+		if (AR_SREV_9285E_20(ah))
+			val |= AR_WA_BIT23;
+
+		REG_WRITE(ah, AR_WA, val);
+
+		/* set bit 19 to allow forcing of pcie core into L1 state */
+		REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+	}
+}
+
+static int ar9002_hw_get_radiorev(struct ath_hw *ah)
+{
+	u32 val;
+	int i;
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
+	for (i = 0; i < 8; i++)
+		REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+
+	val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
+	val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
+
+	return ath9k_hw_reverse_bits(val, 8);
+}
+
+int ar9002_hw_rf_claim(struct ath_hw *ah)
+{
+	u32 val;
+
+	REG_WRITE(ah, AR_PHY(0), 0x00000007);
+
+	val = ar9002_hw_get_radiorev(ah);
+	switch (val & AR_RADIO_SREV_MAJOR) {
+	case 0:
+		val = AR_RAD5133_SREV_MAJOR;
+		break;
+	case AR_RAD5133_SREV_MAJOR:
+	case AR_RAD5122_SREV_MAJOR:
+	case AR_RAD2133_SREV_MAJOR:
+	case AR_RAD2122_SREV_MAJOR:
+		break;
+	default:
+		DBG("ath9k: "
+			"Radio Chip Rev 0x%02X not supported\n",
+			val & AR_RADIO_SREV_MAJOR);
+		return -EOPNOTSUPP;
+	}
+
+	ah->hw_version.analog5GhzRev = val;
+
+	return 0;
+}
+
+void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
+{
+	if (AR_SREV_9287_13_OR_LATER(ah)) {
+		REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+				AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
+		REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
+		REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+				AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+		REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+				AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+	}
+}
+
+/*
+ * If Async FIFO is enabled, the following counters change as MAC now runs
+ * at 117 Mhz instead of 88/44MHz when async FIFO is disabled.
+ *
+ * The values below tested for ht40 2 chain.
+ * Overwrite the delay/timeouts initialized in process ini.
+ */
+void ar9002_hw_update_async_fifo(struct ath_hw *ah)
+{
+	if (AR_SREV_9287_13_OR_LATER(ah)) {
+		REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
+			  AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
+		REG_WRITE(ah, AR_D_GBL_IFS_SLOT,
+			  AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR);
+		REG_WRITE(ah, AR_D_GBL_IFS_EIFS,
+			  AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR);
+
+		REG_WRITE(ah, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR);
+		REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR);
+
+		REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER,
+			    AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768);
+		REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN,
+			      AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);
+	}
+}
+
+/*
+ * We don't enable WEP aggregation on mac80211 but we keep this
+ * around for HAL unification purposes.
+ */
+void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah)
+{
+	if (AR_SREV_9287_13_OR_LATER(ah)) {
+		REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
+			    AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
+	}
+}
+
+/* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */
+void ar9002_hw_attach_ops(struct ath_hw *ah)
+{
+	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+	priv_ops->init_mode_regs = ar9002_hw_init_mode_regs;
+	priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs;
+
+	ops->config_pci_powersave = ar9002_hw_configpcipowersave;
+
+	ar5008_hw_attach_phy_ops(ah);
+	if (AR_SREV_9280_20_OR_LATER(ah))
+		ar9002_hw_attach_phy_ops(ah);
+
+	ar9002_hw_attach_calib_ops(ah);
+	ar9002_hw_attach_mac_ops(ah);
+}
+
+void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+	u32 modesIndex;
+	unsigned int i;
+
+	switch (chan->chanmode) {
+	case CHANNEL_A:
+	case CHANNEL_A_HT20:
+		modesIndex = 1;
+		break;
+	case CHANNEL_A_HT40PLUS:
+	case CHANNEL_A_HT40MINUS:
+		modesIndex = 2;
+		break;
+	case CHANNEL_G:
+	case CHANNEL_G_HT20:
+	case CHANNEL_B:
+		modesIndex = 4;
+		break;
+	case CHANNEL_G_HT40PLUS:
+	case CHANNEL_G_HT40MINUS:
+		modesIndex = 3;
+		break;
+
+	default:
+		return;
+	}
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	for (i = 0; i < ah->iniModes_9271_ANI_reg.ia_rows; i++) {
+		u32 reg = INI_RA(&ah->iniModes_9271_ANI_reg, i, 0);
+		u32 val = INI_RA(&ah->iniModes_9271_ANI_reg, i, modesIndex);
+		u32 val_orig;
+
+		if (reg == AR_PHY_CCK_DETECT) {
+			val_orig = REG_READ(ah, reg);
+			val &= AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK;
+			val_orig &= ~AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK;
+
+			REG_WRITE(ah, reg, val|val_orig);
+		} else
+			REG_WRITE(ah, reg, val);
+	}
+
+	REGWRITE_BUFFER_FLUSH(ah);
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_mac.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_mac.c
new file mode 100644
index 0000000000000000000000000000000000000000..057756b2eabaaa1966abe19d8bb40e7957954bc2
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_mac.c
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/io.h>
+
+#include "hw.h"
+
+#define AR_BufLen           0x00000fff
+
+static void ar9002_hw_rx_enable(struct ath_hw *ah)
+{
+	REG_WRITE(ah, AR_CR, AR_CR_RXE);
+}
+
+static void ar9002_hw_set_desc_link(void *ds, u32 ds_link)
+{
+	((struct ath_desc*) ds)->ds_link = ds_link;
+}
+
+static void ar9002_hw_get_desc_link(void *ds, u32 **ds_link)
+{
+	*ds_link = &((struct ath_desc *)ds)->ds_link;
+}
+
+static int ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
+{
+	u32 isr = 0;
+	u32 mask2 = 0;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
+	u32 sync_cause = 0;
+	int fatal_int = 0;
+
+	if (!AR_SREV_9100(ah) && (ah->ah_ier & AR_IER_ENABLE)) {
+		if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
+			if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M)
+			    == AR_RTC_STATUS_ON) {
+				isr = REG_READ(ah, AR_ISR);
+			}
+		}
+
+		sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) &
+			AR_INTR_SYNC_DEFAULT;
+
+		*masked = 0;
+
+		if (!isr && !sync_cause)
+			return 0;
+	} else {
+		*masked = 0;
+		isr = REG_READ(ah, AR_ISR);
+	}
+
+	if (isr) {
+		if (isr & AR_ISR_BCNMISC) {
+			u32 isr2;
+			isr2 = REG_READ(ah, AR_ISR_S2);
+			if (isr2 & AR_ISR_S2_TIM)
+				mask2 |= ATH9K_INT_TIM;
+			if (isr2 & AR_ISR_S2_DTIM)
+				mask2 |= ATH9K_INT_DTIM;
+			if (isr2 & AR_ISR_S2_DTIMSYNC)
+				mask2 |= ATH9K_INT_DTIMSYNC;
+			if (isr2 & (AR_ISR_S2_CABEND))
+				mask2 |= ATH9K_INT_CABEND;
+			if (isr2 & AR_ISR_S2_GTT)
+				mask2 |= ATH9K_INT_GTT;
+			if (isr2 & AR_ISR_S2_CST)
+				mask2 |= ATH9K_INT_CST;
+			if (isr2 & AR_ISR_S2_TSFOOR)
+				mask2 |= ATH9K_INT_TSFOOR;
+		}
+
+		isr = REG_READ(ah, AR_ISR_RAC);
+		if (isr == 0xffffffff) {
+			*masked = 0;
+			return 0;
+		}
+
+		*masked = isr & ATH9K_INT_COMMON;
+
+		if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM |
+			   AR_ISR_RXOK | AR_ISR_RXERR))
+			*masked |= ATH9K_INT_RX;
+
+		if (isr &
+		    (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR |
+		     AR_ISR_TXEOL)) {
+			u32 s0_s, s1_s;
+
+			*masked |= ATH9K_INT_TX;
+
+			s0_s = REG_READ(ah, AR_ISR_S0_S);
+			ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK);
+			ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC);
+
+			s1_s = REG_READ(ah, AR_ISR_S1_S);
+			ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR);
+			ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL);
+		}
+
+		if (isr & AR_ISR_RXORN) {
+			DBG("ath9k: "
+				"receive FIFO overrun interrupt\n");
+		}
+
+		*masked |= mask2;
+	}
+
+	if (AR_SREV_9100(ah))
+		return 1;
+
+	if (isr & AR_ISR_GENTMR) {
+		u32 s5_s;
+
+		s5_s = REG_READ(ah, AR_ISR_S5_S);
+		ah->intr_gen_timer_trigger =
+				MS(s5_s, AR_ISR_S5_GENTIMER_TRIG);
+
+		ah->intr_gen_timer_thresh =
+			MS(s5_s, AR_ISR_S5_GENTIMER_THRESH);
+
+		if (ah->intr_gen_timer_trigger)
+			*masked |= ATH9K_INT_GENTIMER;
+
+		if ((s5_s & AR_ISR_S5_TIM_TIMER) &&
+		    !(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+			*masked |= ATH9K_INT_TIM_TIMER;
+	}
+
+	if (sync_cause) {
+		fatal_int =
+			(sync_cause &
+			 (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR))
+			? 1 : 0;
+
+		if (fatal_int) {
+			if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) {
+				DBG("ath9k: "
+					"received PCI FATAL interrupt\n");
+			}
+			if (sync_cause & AR_INTR_SYNC_HOST1_PERR) {
+				DBG("ath9k: "
+					"received PCI PERR interrupt\n");
+			}
+			*masked |= ATH9K_INT_FATAL;
+		}
+		if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
+			DBG("ath9k: "
+				"AR_INTR_SYNC_RADM_CPL_TIMEOUT\n");
+			REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
+			REG_WRITE(ah, AR_RC, 0);
+			*masked |= ATH9K_INT_FATAL;
+		}
+		if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) {
+			DBG("ath9k: "
+				"AR_INTR_SYNC_LOCAL_TIMEOUT\n");
+		}
+
+		REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
+		(void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
+	}
+
+	return 1;
+}
+
+static void ar9002_hw_fill_txdesc(struct ath_hw *ah __unused, void *ds, u32 seglen,
+				  int is_firstseg, int is_lastseg,
+				  const void *ds0, u32 buf_addr,
+				  unsigned int qcu __unused)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	ads->ds_data = buf_addr;
+
+	if (is_firstseg) {
+		ads->ds_ctl1 |= seglen | (is_lastseg ? 0 : AR_TxMore);
+	} else if (is_lastseg) {
+		ads->ds_ctl0 = 0;
+		ads->ds_ctl1 = seglen;
+		ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
+		ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
+	} else {
+		ads->ds_ctl0 = 0;
+		ads->ds_ctl1 = seglen | AR_TxMore;
+		ads->ds_ctl2 = 0;
+		ads->ds_ctl3 = 0;
+	}
+	ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
+	ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
+	ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
+	ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
+	ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
+}
+
+static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds,
+				 struct ath_tx_status *ts)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+	u32 status;
+
+	status = *(volatile typeof(ads->ds_txstatus9) *)&(ads->ds_txstatus9);
+	if ((status & AR_TxDone) == 0)
+		return -EINPROGRESS;
+
+	ts->ts_tstamp = ads->AR_SendTimestamp;
+	ts->ts_status = 0;
+	ts->ts_flags = 0;
+
+	if (status & AR_TxOpExceeded)
+		ts->ts_status |= ATH9K_TXERR_XTXOP;
+	ts->tid = MS(status, AR_TxTid);
+	ts->ts_rateindex = MS(status, AR_FinalTxIdx);
+	ts->ts_seqnum = MS(status, AR_SeqNum);
+
+	status = *(volatile typeof(ads->ds_txstatus0) *)&(ads->ds_txstatus0);
+	ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00);
+	ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01);
+	ts->ts_rssi_ctl2 = MS(status, AR_TxRSSIAnt02);
+	if (status & AR_TxBaStatus) {
+		ts->ts_flags |= ATH9K_TX_BA;
+		ts->ba_low = ads->AR_BaBitmapLow;
+		ts->ba_high = ads->AR_BaBitmapHigh;
+	}
+
+	status = *(volatile typeof(ads->ds_txstatus1) *)&(ads->ds_txstatus1);
+	if (status & AR_FrmXmitOK)
+		ts->ts_status |= ATH9K_TX_ACKED;
+	else {
+		if (status & AR_ExcessiveRetries)
+			ts->ts_status |= ATH9K_TXERR_XRETRY;
+		if (status & AR_Filtered)
+			ts->ts_status |= ATH9K_TXERR_FILT;
+		if (status & AR_FIFOUnderrun) {
+			ts->ts_status |= ATH9K_TXERR_FIFO;
+			ath9k_hw_updatetxtriglevel(ah, 1);
+		}
+	}
+	if (status & AR_TxTimerExpired)
+		ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
+	if (status & AR_DescCfgErr)
+		ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR;
+	if (status & AR_TxDataUnderrun) {
+		ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN;
+		ath9k_hw_updatetxtriglevel(ah, 1);
+	}
+	if (status & AR_TxDelimUnderrun) {
+		ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
+		ath9k_hw_updatetxtriglevel(ah, 1);
+	}
+	ts->ts_shortretry = MS(status, AR_RTSFailCnt);
+	ts->ts_longretry = MS(status, AR_DataFailCnt);
+	ts->ts_virtcol = MS(status, AR_VirtRetryCnt);
+
+	status = *(volatile typeof(ads->ds_txstatus5) *)&(ads->ds_txstatus5);
+	ts->ts_rssi = MS(status, AR_TxRSSICombined);
+	ts->ts_rssi_ext0 = MS(status, AR_TxRSSIAnt10);
+	ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11);
+	ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12);
+
+	ts->evm0 = ads->AR_TxEVM0;
+	ts->evm1 = ads->AR_TxEVM1;
+	ts->evm2 = ads->AR_TxEVM2;
+
+	return 0;
+}
+
+static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
+				    u32 pktLen, enum ath9k_pkt_type type,
+				    u32 txPower, u32 keyIx,
+				    enum ath9k_key_type keyType, u32 flags)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	if (txPower > 63)
+		txPower = 63;
+
+	ads->ds_ctl0 = (pktLen & AR_FrameLen)
+		| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
+		| SM(txPower, AR_XmitPower)
+		| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
+		| (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
+		| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
+
+	ads->ds_ctl1 =
+		(keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
+		| SM(type, AR_FrameType)
+		| (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
+		| (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
+		| (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
+
+	ads->ds_ctl6 = SM(keyType, AR_EncrType);
+
+	if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
+		ads->ds_ctl8 = 0;
+		ads->ds_ctl9 = 0;
+		ads->ds_ctl10 = 0;
+		ads->ds_ctl11 = 0;
+	}
+}
+
+static void ar9002_hw_set_clrdmask(struct ath_hw *ah __unused, void *ds, int val)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	if (val)
+		ads->ds_ctl0 |= AR_ClrDestMask;
+	else
+		ads->ds_ctl0 &= ~AR_ClrDestMask;
+}
+
+static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah __unused, void *ds,
+					  void *lastds,
+					  u32 durUpdateEn, u32 rtsctsRate,
+					  u32 rtsctsDuration __unused,
+					  struct ath9k_11n_rate_series series[],
+					  u32 nseries __unused, u32 flags)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+	struct ar5416_desc *last_ads = AR5416DESC(lastds);
+	u32 ds_ctl0;
+
+	if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
+		ds_ctl0 = ads->ds_ctl0;
+
+		if (flags & ATH9K_TXDESC_RTSENA) {
+			ds_ctl0 &= ~AR_CTSEnable;
+			ds_ctl0 |= AR_RTSEnable;
+		} else {
+			ds_ctl0 &= ~AR_RTSEnable;
+			ds_ctl0 |= AR_CTSEnable;
+		}
+
+		ads->ds_ctl0 = ds_ctl0;
+	} else {
+		ads->ds_ctl0 =
+			(ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
+	}
+
+	ads->ds_ctl2 = set11nTries(series, 0)
+		| set11nTries(series, 1)
+		| set11nTries(series, 2)
+		| set11nTries(series, 3)
+		| (durUpdateEn ? AR_DurUpdateEna : 0)
+		| SM(0, AR_BurstDur);
+
+	ads->ds_ctl3 = set11nRate(series, 0)
+		| set11nRate(series, 1)
+		| set11nRate(series, 2)
+		| set11nRate(series, 3);
+
+	ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
+		| set11nPktDurRTSCTS(series, 1);
+
+	ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
+		| set11nPktDurRTSCTS(series, 3);
+
+	ads->ds_ctl7 = set11nRateFlags(series, 0)
+		| set11nRateFlags(series, 1)
+		| set11nRateFlags(series, 2)
+		| set11nRateFlags(series, 3)
+		| SM(rtsctsRate, AR_RTSCTSRate);
+	last_ads->ds_ctl2 = ads->ds_ctl2;
+	last_ads->ds_ctl3 = ads->ds_ctl3;
+}
+
+static void ar9002_hw_set11n_aggr_first(struct ath_hw *ah __unused, void *ds,
+					u32 aggrLen)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+	ads->ds_ctl6 &= ~AR_AggrLen;
+	ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
+}
+
+static void ar9002_hw_set11n_aggr_middle(struct ath_hw *ah __unused, void *ds,
+					 u32 numDelims)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+	unsigned int ctl6;
+
+	ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+
+	ctl6 = ads->ds_ctl6;
+	ctl6 &= ~AR_PadDelim;
+	ctl6 |= SM(numDelims, AR_PadDelim);
+	ads->ds_ctl6 = ctl6;
+}
+
+static void ar9002_hw_set11n_aggr_last(struct ath_hw *ah __unused, void *ds)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	ads->ds_ctl1 |= AR_IsAggr;
+	ads->ds_ctl1 &= ~AR_MoreAggr;
+	ads->ds_ctl6 &= ~AR_PadDelim;
+}
+
+static void ar9002_hw_clr11n_aggr(struct ath_hw *ah __unused, void *ds)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+
+	ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
+}
+
+void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
+			  u32 size, u32 flags)
+{
+	struct ar5416_desc *ads = AR5416DESC(ds);
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
+
+	ads->ds_ctl1 = size & AR_BufLen;
+	if (flags & ATH9K_RXDESC_INTREQ)
+		ads->ds_ctl1 |= AR_RxIntrReq;
+
+	ads->ds_rxstatus8 &= ~AR_RxDone;
+	if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+		memset(&(ads->u), 0, sizeof(ads->u));
+}
+
+void ar9002_hw_attach_mac_ops(struct ath_hw *ah)
+{
+	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+	ops->rx_enable = ar9002_hw_rx_enable;
+	ops->set_desc_link = ar9002_hw_set_desc_link;
+	ops->get_desc_link = ar9002_hw_get_desc_link;
+	ops->get_isr = ar9002_hw_get_isr;
+	ops->fill_txdesc = ar9002_hw_fill_txdesc;
+	ops->proc_txdesc = ar9002_hw_proc_txdesc;
+	ops->set11n_txdesc = ar9002_hw_set11n_txdesc;
+	ops->set11n_ratescenario = ar9002_hw_set11n_ratescenario;
+	ops->set11n_aggr_first = ar9002_hw_set11n_aggr_first;
+	ops->set11n_aggr_middle = ar9002_hw_set11n_aggr_middle;
+	ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last;
+	ops->clr11n_aggr = ar9002_hw_clr11n_aggr;
+	ops->set_clrdmask = ar9002_hw_set_clrdmask;
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_phy.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_phy.c
new file mode 100644
index 0000000000000000000000000000000000000000..72203ba48f0b2429dcce0bfab3abb0094f2aec15
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9002_phy.c
@@ -0,0 +1,578 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: Programming Atheros 802.11n analog front end radios
+ *
+ * AR5416 MAC based PCI devices and AR518 MAC based PCI-Express
+ * devices have either an external AR2133 analog front end radio for single
+ * band 2.4 GHz communication or an AR5133 analog front end radio for dual
+ * band 2.4 GHz / 5 GHz communication.
+ *
+ * All devices after the AR5416 and AR5418 family starting with the AR9280
+ * have their analog front radios, MAC/BB and host PCIe/USB interface embedded
+ * into a single-chip and require less programming.
+ *
+ * The following single-chips exist with a respective embedded radio:
+ *
+ * AR9280 - 11n dual-band 2x2 MIMO for PCIe
+ * AR9281 - 11n single-band 1x2 MIMO for PCIe
+ * AR9285 - 11n single-band 1x1 for PCIe
+ * AR9287 - 11n single-band 2x2 MIMO for PCIe
+ *
+ * AR9220 - 11n dual-band 2x2 MIMO for PCI
+ * AR9223 - 11n single-band 2x2 MIMO for PCI
+ *
+ * AR9287 - 11n single-band 1x1 MIMO for USB
+ */
+
+#include <ipxe/io.h>
+
+#include "hw.h"
+#include "ar9002_phy.h"
+
+/**
+ * ar9002_hw_set_channel - set channel on single-chip device
+ * @ah: atheros hardware structure
+ * @chan:
+ *
+ * This is the function to change channel on single-chip devices, that is
+ * all devices after ar9280.
+ *
+ * This function takes the channel value in MHz and sets
+ * hardware channel value. Assumes writes have been enabled to analog bus.
+ *
+ * Actual Expression,
+ *
+ * For 2GHz channel,
+ * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17)
+ * (freq_ref = 40MHz)
+ *
+ * For 5GHz channel,
+ * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10)
+ * (freq_ref = 40MHz/(24>>amodeRefSel))
+ */
+static int ar9002_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+	u16 bMode, fracMode, aModeRefSel = 0;
+	u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0;
+	struct chan_centers centers;
+	u32 refDivA = 24;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+	freq = centers.synth_center;
+
+	reg32 = REG_READ(ah, AR_PHY_SYNTH_CONTROL);
+	reg32 &= 0xc0000000;
+
+	if (freq < 4800) { /* 2 GHz, fractional mode */
+		u32 txctl;
+		unsigned int regWrites = 0;
+
+		bMode = 1;
+		fracMode = 1;
+		aModeRefSel = 0;
+		channelSel = CHANSEL_2G(freq);
+
+		if (AR_SREV_9287_11_OR_LATER(ah)) {
+			if (freq == 2484) {
+				/* Enable channel spreading for channel 14 */
+				REG_WRITE_ARRAY(&ah->iniCckfirJapan2484,
+						1, regWrites);
+			} else {
+				REG_WRITE_ARRAY(&ah->iniCckfirNormal,
+						1, regWrites);
+			}
+		} else {
+			txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
+			if (freq == 2484) {
+				/* Enable channel spreading for channel 14 */
+				REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+					  txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
+			} else {
+				REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+					  txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN);
+			}
+		}
+	} else {
+		bMode = 0;
+		fracMode = 0;
+
+		switch (ah->eep_ops->get_eeprom(ah, EEP_FRAC_N_5G)) {
+		case 0:
+			if ((freq % 20) == 0)
+				aModeRefSel = 3;
+			else if ((freq % 10) == 0)
+				aModeRefSel = 2;
+			if (aModeRefSel)
+				break;
+		case 1:
+		default:
+			aModeRefSel = 0;
+			/*
+			 * Enable 2G (fractional) mode for channels
+			 * which are 5MHz spaced.
+			 */
+			fracMode = 1;
+			refDivA = 1;
+			channelSel = CHANSEL_5G(freq);
+
+			/* RefDivA setting */
+			REG_RMW_FIELD(ah, AR_AN_SYNTH9,
+				      AR_AN_SYNTH9_REFDIVA, refDivA);
+
+		}
+
+		if (!fracMode) {
+			ndiv = (freq * (refDivA >> aModeRefSel)) / 60;
+			channelSel = ndiv & 0x1ff;
+			channelFrac = (ndiv & 0xfffffe00) * 2;
+			channelSel = (channelSel << 17) | channelFrac;
+		}
+	}
+
+	reg32 = reg32 |
+	    (bMode << 29) |
+	    (fracMode << 28) | (aModeRefSel << 26) | (channelSel);
+
+	REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);
+
+	ah->curchan = chan;
+	ah->curchan_rad_index = -1;
+
+	return 0;
+}
+
+/**
+ * ar9002_hw_spur_mitigate - convert baseband spur frequency
+ * @ah: atheros hardware structure
+ * @chan:
+ *
+ * For single-chip solutions. Converts to baseband spur frequency given the
+ * input channel frequency and compute register settings below.
+ */
+static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
+				    struct ath9k_channel *chan)
+{
+	int bb_spur = AR_NO_SPUR;
+	int freq;
+	int bin, cur_bin;
+	int bb_spur_off, spur_subchannel_sd;
+	int spur_freq_sd;
+	int spur_delta_phase;
+	int denominator;
+	int upper, lower, cur_vit_mask;
+	int tmp, newVal;
+	int i;
+	static const int pilot_mask_reg[4] = {
+		AR_PHY_TIMING7, AR_PHY_TIMING8,
+		AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
+	};
+	static const int chan_mask_reg[4] = {
+		AR_PHY_TIMING9, AR_PHY_TIMING10,
+		AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
+	};
+	static const int inc[4] = { 0, 100, 0, 0 };
+	struct chan_centers centers;
+
+	int8_t mask_m[123];
+	int8_t mask_p[123];
+	int8_t mask_amt;
+	int tmp_mask;
+	int cur_bb_spur;
+	int is2GHz = IS_CHAN_2GHZ(chan);
+
+	memset(&mask_m, 0, sizeof(int8_t) * 123);
+	memset(&mask_p, 0, sizeof(int8_t) * 123);
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+	freq = centers.synth_center;
+
+	ah->config.spurmode = SPUR_ENABLE_EEPROM;
+	for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+		cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
+
+		if (AR_NO_SPUR == cur_bb_spur)
+			break;
+
+		if (is2GHz)
+			cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ;
+		else
+			cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ;
+
+		cur_bb_spur = cur_bb_spur - freq;
+
+		if (IS_CHAN_HT40(chan)) {
+			if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) &&
+			    (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) {
+				bb_spur = cur_bb_spur;
+				break;
+			}
+		} else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) &&
+			   (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) {
+			bb_spur = cur_bb_spur;
+			break;
+		}
+	}
+
+	if (AR_NO_SPUR == bb_spur) {
+		REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK,
+			    AR_PHY_FORCE_CLKEN_CCK_MRC_MUX);
+		return;
+	} else {
+		REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK,
+			    AR_PHY_FORCE_CLKEN_CCK_MRC_MUX);
+	}
+
+	bin = bb_spur * 320;
+
+	tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
+			AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
+			AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
+			AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
+	REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal);
+
+	newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
+		  AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
+		  AR_PHY_SPUR_REG_MASK_RATE_SELECT |
+		  AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
+		  SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
+	REG_WRITE(ah, AR_PHY_SPUR_REG, newVal);
+
+	if (IS_CHAN_HT40(chan)) {
+		if (bb_spur < 0) {
+			spur_subchannel_sd = 1;
+			bb_spur_off = bb_spur + 10;
+		} else {
+			spur_subchannel_sd = 0;
+			bb_spur_off = bb_spur - 10;
+		}
+	} else {
+		spur_subchannel_sd = 0;
+		bb_spur_off = bb_spur;
+	}
+
+	if (IS_CHAN_HT40(chan))
+		spur_delta_phase =
+			((bb_spur * 262144) /
+			 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE;
+	else
+		spur_delta_phase =
+			((bb_spur * 524288) /
+			 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE;
+
+	denominator = IS_CHAN_2GHZ(chan) ? 44 : 40;
+	spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff;
+
+	newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
+		  SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
+		  SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
+	REG_WRITE(ah, AR_PHY_TIMING11, newVal);
+
+	newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S;
+	REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal);
+
+	cur_bin = -6000;
+	upper = bin + 100;
+	lower = bin - 100;
+
+	for (i = 0; i < 4; i++) {
+		int pilot_mask = 0;
+		int chan_mask = 0;
+		int bp = 0;
+		for (bp = 0; bp < 30; bp++) {
+			if ((cur_bin > lower) && (cur_bin < upper)) {
+				pilot_mask = pilot_mask | 0x1 << bp;
+				chan_mask = chan_mask | 0x1 << bp;
+			}
+			cur_bin += 100;
+		}
+		cur_bin += inc[i];
+		REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
+		REG_WRITE(ah, chan_mask_reg[i], chan_mask);
+	}
+
+	cur_vit_mask = 6100;
+	upper = bin + 120;
+	lower = bin - 120;
+
+	for (i = 0; i < 123; i++) {
+		if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
+
+			/* workaround for gcc bug #37014 */
+			volatile int tmp_v = abs(cur_vit_mask - bin);
+
+			if (tmp_v < 75)
+				mask_amt = 1;
+			else
+				mask_amt = 0;
+			if (cur_vit_mask < 0)
+				mask_m[abs(cur_vit_mask / 100)] = mask_amt;
+			else
+				mask_p[cur_vit_mask / 100] = mask_amt;
+		}
+		cur_vit_mask -= 100;
+	}
+
+	tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
+		| (mask_m[48] << 26) | (mask_m[49] << 24)
+		| (mask_m[50] << 22) | (mask_m[51] << 20)
+		| (mask_m[52] << 18) | (mask_m[53] << 16)
+		| (mask_m[54] << 14) | (mask_m[55] << 12)
+		| (mask_m[56] << 10) | (mask_m[57] << 8)
+		| (mask_m[58] << 6) | (mask_m[59] << 4)
+		| (mask_m[60] << 2) | (mask_m[61] << 0);
+	REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
+	REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
+
+	tmp_mask = (mask_m[31] << 28)
+		| (mask_m[32] << 26) | (mask_m[33] << 24)
+		| (mask_m[34] << 22) | (mask_m[35] << 20)
+		| (mask_m[36] << 18) | (mask_m[37] << 16)
+		| (mask_m[48] << 14) | (mask_m[39] << 12)
+		| (mask_m[40] << 10) | (mask_m[41] << 8)
+		| (mask_m[42] << 6) | (mask_m[43] << 4)
+		| (mask_m[44] << 2) | (mask_m[45] << 0);
+	REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
+	REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
+
+	tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
+		| (mask_m[18] << 26) | (mask_m[18] << 24)
+		| (mask_m[20] << 22) | (mask_m[20] << 20)
+		| (mask_m[22] << 18) | (mask_m[22] << 16)
+		| (mask_m[24] << 14) | (mask_m[24] << 12)
+		| (mask_m[25] << 10) | (mask_m[26] << 8)
+		| (mask_m[27] << 6) | (mask_m[28] << 4)
+		| (mask_m[29] << 2) | (mask_m[30] << 0);
+	REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
+	REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
+
+	tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
+		| (mask_m[2] << 26) | (mask_m[3] << 24)
+		| (mask_m[4] << 22) | (mask_m[5] << 20)
+		| (mask_m[6] << 18) | (mask_m[7] << 16)
+		| (mask_m[8] << 14) | (mask_m[9] << 12)
+		| (mask_m[10] << 10) | (mask_m[11] << 8)
+		| (mask_m[12] << 6) | (mask_m[13] << 4)
+		| (mask_m[14] << 2) | (mask_m[15] << 0);
+	REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
+	REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
+
+	tmp_mask = (mask_p[15] << 28)
+		| (mask_p[14] << 26) | (mask_p[13] << 24)
+		| (mask_p[12] << 22) | (mask_p[11] << 20)
+		| (mask_p[10] << 18) | (mask_p[9] << 16)
+		| (mask_p[8] << 14) | (mask_p[7] << 12)
+		| (mask_p[6] << 10) | (mask_p[5] << 8)
+		| (mask_p[4] << 6) | (mask_p[3] << 4)
+		| (mask_p[2] << 2) | (mask_p[1] << 0);
+	REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
+	REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
+
+	tmp_mask = (mask_p[30] << 28)
+		| (mask_p[29] << 26) | (mask_p[28] << 24)
+		| (mask_p[27] << 22) | (mask_p[26] << 20)
+		| (mask_p[25] << 18) | (mask_p[24] << 16)
+		| (mask_p[23] << 14) | (mask_p[22] << 12)
+		| (mask_p[21] << 10) | (mask_p[20] << 8)
+		| (mask_p[19] << 6) | (mask_p[18] << 4)
+		| (mask_p[17] << 2) | (mask_p[16] << 0);
+	REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
+	REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
+
+	tmp_mask = (mask_p[45] << 28)
+		| (mask_p[44] << 26) | (mask_p[43] << 24)
+		| (mask_p[42] << 22) | (mask_p[41] << 20)
+		| (mask_p[40] << 18) | (mask_p[39] << 16)
+		| (mask_p[38] << 14) | (mask_p[37] << 12)
+		| (mask_p[36] << 10) | (mask_p[35] << 8)
+		| (mask_p[34] << 6) | (mask_p[33] << 4)
+		| (mask_p[32] << 2) | (mask_p[31] << 0);
+	REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
+	REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
+
+	tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
+		| (mask_p[59] << 26) | (mask_p[58] << 24)
+		| (mask_p[57] << 22) | (mask_p[56] << 20)
+		| (mask_p[55] << 18) | (mask_p[54] << 16)
+		| (mask_p[53] << 14) | (mask_p[52] << 12)
+		| (mask_p[51] << 10) | (mask_p[50] << 8)
+		| (mask_p[49] << 6) | (mask_p[48] << 4)
+		| (mask_p[47] << 2) | (mask_p[46] << 0);
+	REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
+	REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+}
+
+static void ar9002_olc_init(struct ath_hw *ah)
+{
+	u32 i;
+
+	if (!OLC_FOR_AR9280_20_LATER)
+		return;
+
+	if (OLC_FOR_AR9287_10_LATER) {
+		REG_SET_BIT(ah, AR_PHY_TX_PWRCTRL9,
+				AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL);
+		ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TXPC0,
+				AR9287_AN_TXPC0_TXPCMODE,
+				AR9287_AN_TXPC0_TXPCMODE_S,
+				AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE);
+		udelay(100);
+	} else {
+		for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++)
+			ah->originalGain[i] =
+				MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4),
+						AR_PHY_TX_GAIN);
+		ah->PDADCdelta = 0;
+	}
+}
+
+static u32 ar9002_hw_compute_pll_control(struct ath_hw *ah,
+					 struct ath9k_channel *chan)
+{
+	u32 pll;
+
+	pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
+
+	if (chan && IS_CHAN_HALF_RATE(chan))
+		pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
+	else if (chan && IS_CHAN_QUARTER_RATE(chan))
+		pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
+
+	if (chan && IS_CHAN_5GHZ(chan)) {
+		if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+			pll = 0x142c;
+		else if (AR_SREV_9280_20(ah))
+			pll = 0x2850;
+		else
+			pll |= SM(0x28, AR_RTC_9160_PLL_DIV);
+	} else {
+		pll |= SM(0x2c, AR_RTC_9160_PLL_DIV);
+	}
+
+	return pll;
+}
+
+static void ar9002_hw_do_getnf(struct ath_hw *ah,
+			      int16_t nfarray[NUM_NF_READINGS])
+{
+	int16_t nf;
+
+	nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
+	nfarray[0] = sign_extend32(nf, 8);
+
+	nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR9280_PHY_EXT_MINCCA_PWR);
+	if (IS_CHAN_HT40(ah->curchan))
+		nfarray[3] = sign_extend32(nf, 8);
+
+	if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+		return;
+
+	nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR9280_PHY_CH1_MINCCA_PWR);
+	nfarray[1] = sign_extend32(nf, 8);
+
+	nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR9280_PHY_CH1_EXT_MINCCA_PWR);
+	if (IS_CHAN_HT40(ah->curchan))
+		nfarray[4] = sign_extend32(nf, 8);
+}
+
+static void ar9002_hw_set_nf_limits(struct ath_hw *ah)
+{
+	if (AR_SREV_9285(ah)) {
+		ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9285_2GHZ;
+		ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9285_2GHZ;
+		ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9285_2GHZ;
+	} else if (AR_SREV_9287(ah)) {
+		ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ;
+		ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ;
+		ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9287_2GHZ;
+	} else if (AR_SREV_9271(ah)) {
+		ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9271_2GHZ;
+		ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9271_2GHZ;
+		ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9271_2GHZ;
+	} else {
+		ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9280_2GHZ;
+		ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9280_2GHZ;
+		ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9280_2GHZ;
+		ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9280_5GHZ;
+		ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9280_5GHZ;
+		ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9280_5GHZ;
+	}
+}
+
+static void ar9002_hw_antdiv_comb_conf_get(struct ath_hw *ah,
+				   struct ath_hw_antcomb_conf *antconf)
+{
+	u32 regval;
+
+	regval = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
+	antconf->main_lna_conf = (regval & AR_PHY_9285_ANT_DIV_MAIN_LNACONF) >>
+				  AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S;
+	antconf->alt_lna_conf = (regval & AR_PHY_9285_ANT_DIV_ALT_LNACONF) >>
+				 AR_PHY_9285_ANT_DIV_ALT_LNACONF_S;
+	antconf->fast_div_bias = (regval & AR_PHY_9285_FAST_DIV_BIAS) >>
+				  AR_PHY_9285_FAST_DIV_BIAS_S;
+	antconf->lna1_lna2_delta = -3;
+	antconf->div_group = 0;
+}
+
+static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah,
+				   struct ath_hw_antcomb_conf *antconf)
+{
+	u32 regval;
+
+	regval = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
+	regval &= ~(AR_PHY_9285_ANT_DIV_MAIN_LNACONF |
+		    AR_PHY_9285_ANT_DIV_ALT_LNACONF |
+		    AR_PHY_9285_FAST_DIV_BIAS);
+	regval |= ((antconf->main_lna_conf << AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S)
+		   & AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
+	regval |= ((antconf->alt_lna_conf << AR_PHY_9285_ANT_DIV_ALT_LNACONF_S)
+		   & AR_PHY_9285_ANT_DIV_ALT_LNACONF);
+	regval |= ((antconf->fast_div_bias << AR_PHY_9285_FAST_DIV_BIAS_S)
+		   & AR_PHY_9285_FAST_DIV_BIAS);
+
+	REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
+}
+
+void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
+{
+	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+	priv_ops->set_rf_regs = NULL;
+	priv_ops->rf_alloc_ext_banks = NULL;
+	priv_ops->rf_free_ext_banks = NULL;
+	priv_ops->rf_set_freq = ar9002_hw_set_channel;
+	priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate;
+	priv_ops->olc_init = ar9002_olc_init;
+	priv_ops->compute_pll_control = ar9002_hw_compute_pll_control;
+	priv_ops->do_getnf = ar9002_hw_do_getnf;
+
+	ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get;
+	ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set;
+
+	ar9002_hw_set_nf_limits(ah);
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_calib.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_calib.c
new file mode 100644
index 0000000000000000000000000000000000000000..c37168bd2d4e1b03a7f42010ccad1e4733ae1110
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_calib.c
@@ -0,0 +1,932 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/io.h>
+
+#include "hw.h"
+#include "hw-ops.h"
+#include "ar9003_phy.h"
+
+#define MAX_MEASUREMENT	8
+#define MAX_MAG_DELTA	11
+#define MAX_PHS_DELTA	10
+
+struct coeff {
+	int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
+	int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
+	int iqc_coeff[2];
+};
+
+enum ar9003_cal_types {
+	IQ_MISMATCH_CAL = BIT(0),
+	TEMP_COMP_CAL = BIT(1),
+};
+
+static void ar9003_hw_setup_calibration(struct ath_hw *ah,
+					struct ath9k_cal_list *currCal)
+{
+	/* Select calibration to run */
+	switch (currCal->calData->calType) {
+	case IQ_MISMATCH_CAL:
+		/*
+		 * Start calibration with
+		 * 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples
+		 */
+		REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+			      AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX,
+		currCal->calData->calCountMax);
+		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
+
+		DBG2("ath9k: "
+			"starting IQ Mismatch Calibration\n");
+
+		/* Kick-off cal */
+		REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
+		break;
+	case TEMP_COMP_CAL:
+		REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
+			      AR_PHY_65NM_CH0_THERM_LOCAL, 1);
+		REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
+			      AR_PHY_65NM_CH0_THERM_START, 1);
+
+		DBG2("ath9k: "
+			"starting Temperature Compensation Calibration\n");
+		break;
+	}
+}
+
+/*
+ * Generic calibration routine.
+ * Recalibrate the lower PHY chips to account for temperature/environment
+ * changes.
+ */
+static int ar9003_hw_per_calibration(struct ath_hw *ah,
+				      struct ath9k_channel *ichan __unused,
+				      u8 rxchainmask,
+				      struct ath9k_cal_list *currCal)
+{
+	struct ath9k_hw_cal_data *caldata = ah->caldata;
+	/* Cal is assumed not done until explicitly set below */
+	int iscaldone = 0;
+
+	/* Calibration in progress. */
+	if (currCal->calState == CAL_RUNNING) {
+		/* Check to see if it has finished. */
+		if (!(REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) {
+			/*
+			* Accumulate cal measures for active chains
+			*/
+			currCal->calData->calCollect(ah);
+			ah->cal_samples++;
+
+			if (ah->cal_samples >=
+			    currCal->calData->calNumSamples) {
+				unsigned int i, numChains = 0;
+				for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+					if (rxchainmask & (1 << i))
+						numChains++;
+				}
+
+				/*
+				* Process accumulated data
+				*/
+				currCal->calData->calPostProc(ah, numChains);
+
+				/* Calibration has finished. */
+				caldata->CalValid |= currCal->calData->calType;
+				currCal->calState = CAL_DONE;
+				iscaldone = 1;
+			} else {
+			/*
+			 * Set-up collection of another sub-sample until we
+			 * get desired number
+			 */
+			ar9003_hw_setup_calibration(ah, currCal);
+			}
+		}
+	} else if (!(caldata->CalValid & currCal->calData->calType)) {
+		/* If current cal is marked invalid in channel, kick it off */
+		ath9k_hw_reset_calibration(ah, currCal);
+	}
+
+	return iscaldone;
+}
+
+static int ar9003_hw_calibrate(struct ath_hw *ah,
+				struct ath9k_channel *chan,
+				u8 rxchainmask,
+				int longcal)
+{
+	int iscaldone = 1;
+	struct ath9k_cal_list *currCal = ah->cal_list_curr;
+
+	/*
+	 * For given calibration:
+	 * 1. Call generic cal routine
+	 * 2. When this cal is done (isCalDone) if we have more cals waiting
+	 *    (eg after reset), mask this to upper layers by not propagating
+	 *    isCalDone if it is set to TRUE.
+	 *    Instead, change isCalDone to FALSE and setup the waiting cal(s)
+	 *    to be run.
+	 */
+	if (currCal &&
+	    (currCal->calState == CAL_RUNNING ||
+	     currCal->calState == CAL_WAITING)) {
+		iscaldone = ar9003_hw_per_calibration(ah, chan,
+						      rxchainmask, currCal);
+		if (iscaldone) {
+			ah->cal_list_curr = currCal = currCal->calNext;
+
+			if (currCal->calState == CAL_WAITING) {
+				iscaldone = 0;
+				ath9k_hw_reset_calibration(ah, currCal);
+			}
+		}
+	}
+
+	/* Do NF cal only at longer intervals */
+	if (longcal) {
+		/*
+		 * Get the value from the previous NF cal and update
+		 * history buffer.
+		 */
+		ath9k_hw_getnf(ah, chan);
+
+		/*
+		 * Load the NF from history buffer of the current channel.
+		 * NF is slow time-variant, so it is OK to use a historical
+		 * value.
+		 */
+		ath9k_hw_loadnf(ah, ah->curchan);
+
+		/* start NF calibration, without updating BB NF register */
+		ath9k_hw_start_nfcal(ah, 0);
+	}
+
+	return iscaldone;
+}
+
+static void ar9003_hw_iqcal_collect(struct ath_hw *ah)
+{
+	int i;
+
+	/* Accumulate IQ cal measures for active chains */
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		if (ah->txchainmask & BIT(i)) {
+			ah->totalPowerMeasI[i] +=
+				REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+			ah->totalPowerMeasQ[i] +=
+				REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+			ah->totalIqCorrMeas[i] +=
+				(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+			DBG2("ath9k: "
+				"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
+				ah->cal_samples, i, ah->totalPowerMeasI[i],
+				ah->totalPowerMeasQ[i],
+				ah->totalIqCorrMeas[i]);
+		}
+	}
+}
+
+static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
+{
+	u32 powerMeasQ, powerMeasI, iqCorrMeas;
+	u32 qCoffDenom, iCoffDenom;
+	int32_t qCoff, iCoff;
+	int iqCorrNeg, i;
+	static const uint32_t offset_array[3] = {
+		AR_PHY_RX_IQCAL_CORR_B0,
+		AR_PHY_RX_IQCAL_CORR_B1,
+		AR_PHY_RX_IQCAL_CORR_B2,
+	};
+
+	for (i = 0; i < numChains; i++) {
+		powerMeasI = ah->totalPowerMeasI[i];
+		powerMeasQ = ah->totalPowerMeasQ[i];
+		iqCorrMeas = ah->totalIqCorrMeas[i];
+
+		DBG2("ath9k: "
+			"Starting IQ Cal and Correction for Chain %d\n",
+			i);
+
+		DBG2("ath9k: "
+			"Orignal: Chn %diq_corr_meas = 0x%08x\n",
+			i, ah->totalIqCorrMeas[i]);
+
+		iqCorrNeg = 0;
+
+		if (iqCorrMeas > 0x80000000) {
+			iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
+			iqCorrNeg = 1;
+		}
+
+		DBG2("ath9k: "
+			"Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
+		DBG2("ath9k: "
+			"Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
+		DBG2("ath9k: iqCorrNeg is 0x%08x\n",
+			iqCorrNeg);
+
+		iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256;
+		qCoffDenom = powerMeasQ / 64;
+
+		if ((iCoffDenom != 0) && (qCoffDenom != 0)) {
+			iCoff = iqCorrMeas / iCoffDenom;
+			qCoff = powerMeasI / qCoffDenom - 64;
+			DBG2("ath9k: "
+				"Chn %d iCoff = 0x%08x\n", i, iCoff);
+			DBG2("ath9k: "
+				"Chn %d qCoff = 0x%08x\n", i, qCoff);
+
+			/* Force bounds on iCoff */
+			if (iCoff >= 63)
+				iCoff = 63;
+			else if (iCoff <= -63)
+				iCoff = -63;
+
+			/* Negate iCoff if iqCorrNeg == 0 */
+			if (iqCorrNeg == 0x0)
+				iCoff = -iCoff;
+
+			/* Force bounds on qCoff */
+			if (qCoff >= 63)
+				qCoff = 63;
+			else if (qCoff <= -63)
+				qCoff = -63;
+
+			iCoff = iCoff & 0x7f;
+			qCoff = qCoff & 0x7f;
+
+			DBG2("ath9k: "
+				"Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
+				i, iCoff, qCoff);
+			DBG2("ath9k: "
+				"Register offset (0x%04x) before update = 0x%x\n",
+				offset_array[i],
+				REG_READ(ah, offset_array[i]));
+
+			REG_RMW_FIELD(ah, offset_array[i],
+				      AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
+				      iCoff);
+			REG_RMW_FIELD(ah, offset_array[i],
+				      AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
+				      qCoff);
+			DBG2("ath9k: "
+				"Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x\n",
+				offset_array[i],
+				AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
+				REG_READ(ah, offset_array[i]));
+			DBG2("ath9k: "
+				"Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x\n",
+				offset_array[i],
+				AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
+				REG_READ(ah, offset_array[i]));
+
+			DBG2("ath9k: "
+				"IQ Cal and Correction done for Chain %d\n", i);
+		}
+	}
+
+	REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0,
+		    AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE);
+	DBG2("ath9k: "
+		"IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x\n",
+		(unsigned) (AR_PHY_RX_IQCAL_CORR_B0),
+		AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,
+		REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));
+}
+
+static const struct ath9k_percal_data iq_cal_single_sample = {
+	IQ_MISMATCH_CAL,
+	MIN_CAL_SAMPLES,
+	PER_MAX_LOG_COUNT,
+	ar9003_hw_iqcal_collect,
+	ar9003_hw_iqcalibrate
+};
+
+static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
+{
+	ah->iq_caldata.calData = &iq_cal_single_sample;
+}
+
+/*
+ * solve 4x4 linear equation used in loopback iq cal.
+ */
+static int ar9003_hw_solve_iq_cal(struct ath_hw *ah __unused,
+				   s32 sin_2phi_1,
+				   s32 cos_2phi_1,
+				   s32 sin_2phi_2,
+				   s32 cos_2phi_2,
+				   s32 mag_a0_d0,
+				   s32 phs_a0_d0,
+				   s32 mag_a1_d0,
+				   s32 phs_a1_d0,
+				   s32 solved_eq[])
+{
+	s32 f1 = cos_2phi_1 - cos_2phi_2,
+	    f3 = sin_2phi_1 - sin_2phi_2,
+	    f2;
+	s32 mag_tx, phs_tx, mag_rx, phs_rx;
+	const s32 result_shift = 1 << 15;
+
+	f2 = (f1 * f1 + f3 * f3) / result_shift;
+
+	if (!f2) {
+		DBG("ath9k: Divide by 0\n");
+		return 0;
+	}
+
+	/* mag mismatch, tx */
+	mag_tx = f1 * (mag_a0_d0  - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0);
+	/* phs mismatch, tx */
+	phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0);
+
+	mag_tx = (mag_tx / f2);
+	phs_tx = (phs_tx / f2);
+
+	/* mag mismatch, rx */
+	mag_rx = mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) /
+		 result_shift;
+	/* phs mismatch, rx */
+	phs_rx = phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) /
+		 result_shift;
+
+	solved_eq[0] = mag_tx;
+	solved_eq[1] = phs_tx;
+	solved_eq[2] = mag_rx;
+	solved_eq[3] = phs_rx;
+
+	return 1;
+}
+
+static s32 ar9003_hw_find_mag_approx(struct ath_hw *ah __unused, s32 in_re, s32 in_im)
+{
+	s32 abs_i = abs(in_re),
+	    abs_q = abs(in_im),
+	    max_abs, min_abs;
+
+	if (abs_i > abs_q) {
+		max_abs = abs_i;
+		min_abs = abs_q;
+	} else {
+		max_abs = abs_q;
+		min_abs = abs_i;
+	}
+
+	return max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4);
+}
+
+#define DELPT 32
+
+static int ar9003_hw_calc_iq_corr(struct ath_hw *ah,
+				   s32 chain_idx,
+				   const s32 iq_res[],
+				   s32 iqc_coeff[])
+{
+	s32 i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0,
+	    i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1,
+	    i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0,
+	    i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1;
+	s32 mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1,
+	    phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1,
+	    sin_2phi_1, cos_2phi_1,
+	    sin_2phi_2, cos_2phi_2;
+	s32 mag_tx, phs_tx, mag_rx, phs_rx;
+	s32 solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx,
+	    q_q_coff, q_i_coff;
+	const s32 res_scale = 1 << 15;
+	const s32 delpt_shift = 1 << 8;
+	s32 mag1, mag2;
+
+	i2_m_q2_a0_d0 = iq_res[0] & 0xfff;
+	i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff;
+	iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8);
+
+	if (i2_m_q2_a0_d0 > 0x800)
+		i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1);
+
+	if (i2_p_q2_a0_d0 > 0x800)
+		i2_p_q2_a0_d0 = -((0xfff - i2_p_q2_a0_d0) + 1);
+
+	if (iq_corr_a0_d0 > 0x800)
+		iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1);
+
+	i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff;
+	i2_p_q2_a0_d1 = (iq_res[2] & 0xfff);
+	iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff;
+
+	if (i2_m_q2_a0_d1 > 0x800)
+		i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);
+
+	if (i2_p_q2_a0_d1 > 0x800)
+		i2_p_q2_a0_d1 = -((0xfff - i2_p_q2_a0_d1) + 1);
+
+	if (iq_corr_a0_d1 > 0x800)
+		iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);
+
+	i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8);
+	i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff;
+	iq_corr_a1_d0 = iq_res[4] & 0xfff;
+
+	if (i2_m_q2_a1_d0 > 0x800)
+		i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1);
+
+	if (i2_p_q2_a1_d0 > 0x800)
+		i2_p_q2_a1_d0 = -((0xfff - i2_p_q2_a1_d0) + 1);
+
+	if (iq_corr_a1_d0 > 0x800)
+		iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1);
+
+	i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff;
+	i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8);
+	iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff;
+
+	if (i2_m_q2_a1_d1 > 0x800)
+		i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1);
+
+	if (i2_p_q2_a1_d1 > 0x800)
+		i2_p_q2_a1_d1 = -((0xfff - i2_p_q2_a1_d1) + 1);
+
+	if (iq_corr_a1_d1 > 0x800)
+		iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1);
+
+	if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) ||
+	    (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) {
+		DBG("ath9k: "
+			"Divide by 0:\n"
+			"a0_d0=%d\n"
+			"a0_d1=%d\n"
+			"a2_d0=%d\n"
+			"a1_d1=%d\n",
+			i2_p_q2_a0_d0, i2_p_q2_a0_d1,
+			i2_p_q2_a1_d0, i2_p_q2_a1_d1);
+		return 0;
+	}
+
+	mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0;
+	phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0;
+
+	mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1;
+	phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1;
+
+	mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0;
+	phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0;
+
+	mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1;
+	phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1;
+
+	/* w/o analog phase shift */
+	sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT);
+	/* w/o analog phase shift */
+	cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT);
+	/* w/  analog phase shift */
+	sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT);
+	/* w/  analog phase shift */
+	cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT);
+
+	/*
+	 * force sin^2 + cos^2 = 1;
+	 * find magnitude by approximation
+	 */
+	mag1 = ar9003_hw_find_mag_approx(ah, cos_2phi_1, sin_2phi_1);
+	mag2 = ar9003_hw_find_mag_approx(ah, cos_2phi_2, sin_2phi_2);
+
+	if ((mag1 == 0) || (mag2 == 0)) {
+		DBG("ath9k: "
+			"Divide by 0: mag1=%d, mag2=%d\n",
+			mag1, mag2);
+		return 0;
+	}
+
+	/* normalization sin and cos by mag */
+	sin_2phi_1 = (sin_2phi_1 * res_scale / mag1);
+	cos_2phi_1 = (cos_2phi_1 * res_scale / mag1);
+	sin_2phi_2 = (sin_2phi_2 * res_scale / mag2);
+	cos_2phi_2 = (cos_2phi_2 * res_scale / mag2);
+
+	/* calculate IQ mismatch */
+	if (!ar9003_hw_solve_iq_cal(ah,
+			     sin_2phi_1, cos_2phi_1,
+			     sin_2phi_2, cos_2phi_2,
+			     mag_a0_d0, phs_a0_d0,
+			     mag_a1_d0,
+			     phs_a1_d0, solved_eq)) {
+		DBG("ath9k: "
+			"Call to ar9003_hw_solve_iq_cal() failed.\n");
+		return 0;
+	}
+
+	mag_tx = solved_eq[0];
+	phs_tx = solved_eq[1];
+	mag_rx = solved_eq[2];
+	phs_rx = solved_eq[3];
+
+	DBG2("ath9k: "
+		"chain %d: mag mismatch=%d phase mismatch=%d\n",
+		chain_idx, mag_tx/res_scale, phs_tx/res_scale);
+
+	if (res_scale == mag_tx) {
+		DBG("ath9k: "
+			"Divide by 0: mag_tx=%d, res_scale=%d\n",
+			mag_tx, res_scale);
+		return 0;
+	}
+
+	/* calculate and quantize Tx IQ correction factor */
+	mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx);
+	phs_corr_tx = -phs_tx;
+
+	q_q_coff = (mag_corr_tx * 128 / res_scale);
+	q_i_coff = (phs_corr_tx * 256 / res_scale);
+
+	DBG2("ath9k: "
+		"tx chain %d: mag corr=%d  phase corr=%d\n",
+		chain_idx, q_q_coff, q_i_coff);
+
+	if (q_i_coff < -63)
+		q_i_coff = -63;
+	if (q_i_coff > 63)
+		q_i_coff = 63;
+	if (q_q_coff < -63)
+		q_q_coff = -63;
+	if (q_q_coff > 63)
+		q_q_coff = 63;
+
+	iqc_coeff[0] = (q_q_coff * 128) + q_i_coff;
+
+	DBG2("ath9k: "
+		"tx chain %d: iq corr coeff=%x\n",
+		chain_idx, iqc_coeff[0]);
+
+	if (-mag_rx == res_scale) {
+		DBG("ath9k: "
+			"Divide by 0: mag_rx=%d, res_scale=%d\n",
+			mag_rx, res_scale);
+		return 0;
+	}
+
+	/* calculate and quantize Rx IQ correction factors */
+	mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx);
+	phs_corr_rx = -phs_rx;
+
+	q_q_coff = (mag_corr_rx * 128 / res_scale);
+	q_i_coff = (phs_corr_rx * 256 / res_scale);
+
+	DBG("ath9k: "
+		"rx chain %d: mag corr=%d  phase corr=%d\n",
+		chain_idx, q_q_coff, q_i_coff);
+
+	if (q_i_coff < -63)
+		q_i_coff = -63;
+	if (q_i_coff > 63)
+		q_i_coff = 63;
+	if (q_q_coff < -63)
+		q_q_coff = -63;
+	if (q_q_coff > 63)
+		q_q_coff = 63;
+
+	iqc_coeff[1] = (q_q_coff * 128) + q_i_coff;
+
+	DBG2("ath9k: "
+		"rx chain %d: iq corr coeff=%x\n",
+		chain_idx, iqc_coeff[1]);
+
+	return 1;
+}
+
+static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
+				     int max_delta)
+{
+	int mp_max = -64, max_idx = 0;
+	int mp_min = 63, min_idx = 0;
+	int mp_avg = 0, i, outlier_idx = 0;
+
+	/* find min/max mismatch across all calibrated gains */
+	for (i = 0; i < nmeasurement; i++) {
+		mp_avg += mp_coeff[i];
+		if (mp_coeff[i] > mp_max) {
+			mp_max = mp_coeff[i];
+			max_idx = i;
+		} else if (mp_coeff[i] < mp_min) {
+			mp_min = mp_coeff[i];
+			min_idx = i;
+		}
+	}
+
+	/* find average (exclude max abs value) */
+	for (i = 0; i < nmeasurement; i++) {
+		if ((abs(mp_coeff[i]) < abs(mp_max)) ||
+		    (abs(mp_coeff[i]) < abs(mp_min)))
+			mp_avg += mp_coeff[i];
+	}
+	mp_avg /= (nmeasurement - 1);
+
+	/* detect outlier */
+	if (abs(mp_max - mp_min) > max_delta) {
+		if (abs(mp_max - mp_avg) > abs(mp_min - mp_avg))
+			outlier_idx = max_idx;
+		else
+			outlier_idx = min_idx;
+	}
+	mp_coeff[outlier_idx] = mp_avg;
+}
+
+static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
+						 u8 num_chains,
+						 struct coeff *coeff)
+{
+	int i, im, nmeasurement;
+	u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
+
+	memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));
+	for (i = 0; i < MAX_MEASUREMENT / 2; i++) {
+		tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =
+					AR_PHY_TX_IQCAL_CORR_COEFF_B0(i);
+		if (!AR_SREV_9485(ah)) {
+			tx_corr_coeff[i * 2][1] =
+			tx_corr_coeff[(i * 2) + 1][1] =
+					AR_PHY_TX_IQCAL_CORR_COEFF_B1(i);
+
+			tx_corr_coeff[i * 2][2] =
+			tx_corr_coeff[(i * 2) + 1][2] =
+					AR_PHY_TX_IQCAL_CORR_COEFF_B2(i);
+		}
+	}
+
+	/* Load the average of 2 passes */
+	for (i = 0; i < num_chains; i++) {
+		nmeasurement = REG_READ_FIELD(ah,
+				AR_PHY_TX_IQCAL_STATUS_B0,
+				AR_PHY_CALIBRATED_GAINS_0);
+
+		if (nmeasurement > MAX_MEASUREMENT)
+			nmeasurement = MAX_MEASUREMENT;
+
+		/* detect outlier only if nmeasurement > 1 */
+		if (nmeasurement > 1) {
+			/* Detect magnitude outlier */
+			ar9003_hw_detect_outlier(coeff->mag_coeff[i],
+					nmeasurement, MAX_MAG_DELTA);
+
+			/* Detect phase outlier */
+			ar9003_hw_detect_outlier(coeff->phs_coeff[i],
+					nmeasurement, MAX_PHS_DELTA);
+		}
+
+		for (im = 0; im < nmeasurement; im++) {
+
+			coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) |
+				((coeff->phs_coeff[i][im] & 0x7f) << 7);
+
+			if ((im % 2) == 0)
+				REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
+					AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
+					coeff->iqc_coeff[0]);
+			else
+				REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
+					AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
+					coeff->iqc_coeff[0]);
+		}
+	}
+
+	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
+		      AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
+	REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
+		      AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
+
+	return;
+
+}
+
+static int ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
+{
+	u8 tx_gain_forced;
+
+	tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+					AR_PHY_TXGAIN_FORCE);
+	if (tx_gain_forced)
+		REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+			      AR_PHY_TXGAIN_FORCE, 0);
+
+	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
+		      AR_PHY_TX_IQCAL_START_DO_CAL, 1);
+
+	if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
+			AR_PHY_TX_IQCAL_START_DO_CAL, 0,
+			AH_WAIT_TIMEOUT)) {
+		DBG2("ath9k: "
+			"Tx IQ Cal is not completed.\n");
+		return 0;
+	}
+	return 1;
+}
+
+static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah)
+{
+	const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
+		AR_PHY_TX_IQCAL_STATUS_B0,
+		AR_PHY_TX_IQCAL_STATUS_B1,
+		AR_PHY_TX_IQCAL_STATUS_B2,
+	};
+	const uint32_t chan_info_tab[] = {
+		AR_PHY_CHAN_INFO_TAB_0,
+		AR_PHY_CHAN_INFO_TAB_1,
+		AR_PHY_CHAN_INFO_TAB_2,
+	};
+	struct coeff coeff;
+	s32 iq_res[6];
+	u8 num_chains = 0;
+	int i, im, j;
+	int nmeasurement;
+
+	for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+		if (ah->txchainmask & (1 << i))
+			num_chains++;
+	}
+
+	for (i = 0; i < num_chains; i++) {
+		nmeasurement = REG_READ_FIELD(ah,
+				AR_PHY_TX_IQCAL_STATUS_B0,
+				AR_PHY_CALIBRATED_GAINS_0);
+		if (nmeasurement > MAX_MEASUREMENT)
+			nmeasurement = MAX_MEASUREMENT;
+
+		for (im = 0; im < nmeasurement; im++) {
+			DBG2("ath9k: "
+				"Doing Tx IQ Cal for chain %d.\n", i);
+
+			if (REG_READ(ah, txiqcal_status[i]) &
+					AR_PHY_TX_IQCAL_STATUS_FAILED) {
+				DBG("ath9k: "
+					"Tx IQ Cal failed for chain %d.\n", i);
+				goto tx_iqcal_fail;
+			}
+
+			for (j = 0; j < 3; j++) {
+				u32 idx = 2 * j, offset = 4 * (3 * im + j);
+
+				REG_RMW_FIELD(ah,
+						AR_PHY_CHAN_INFO_MEMORY,
+						AR_PHY_CHAN_INFO_TAB_S2_READ,
+						0);
+
+				/* 32 bits */
+				iq_res[idx] = REG_READ(ah,
+						chan_info_tab[i] +
+						offset);
+
+				REG_RMW_FIELD(ah,
+						AR_PHY_CHAN_INFO_MEMORY,
+						AR_PHY_CHAN_INFO_TAB_S2_READ,
+						1);
+
+				/* 16 bits */
+				iq_res[idx + 1] = 0xffff & REG_READ(ah,
+						chan_info_tab[i] + offset);
+
+				DBG2("ath9k: "
+					"IQ RES[%d]=0x%x"
+					"IQ_RES[%d]=0x%x\n",
+					idx, iq_res[idx], idx + 1,
+					iq_res[idx + 1]);
+			}
+
+			if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
+						coeff.iqc_coeff)) {
+				DBG("ath9k: "
+					"Failed in calculation of \
+					IQ correction.\n");
+				goto tx_iqcal_fail;
+			}
+
+			coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f;
+			coeff.phs_coeff[i][im] =
+				(coeff.iqc_coeff[0] >> 7) & 0x7f;
+
+			if (coeff.mag_coeff[i][im] > 63)
+				coeff.mag_coeff[i][im] -= 128;
+			if (coeff.phs_coeff[i][im] > 63)
+				coeff.phs_coeff[i][im] -= 128;
+		}
+	}
+	ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, &coeff);
+
+	return;
+
+tx_iqcal_fail:
+	DBG("ath9k: Tx IQ Cal failed\n");
+	return;
+}
+static int ar9003_hw_init_cal(struct ath_hw *ah,
+			       struct ath9k_channel *chan __unused)
+{
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
+	int val;
+	int txiqcal_done = 0;
+
+	val = REG_READ(ah, AR_ENT_OTP);
+	DBG2("ath9k: ath9k: AR_ENT_OTP 0x%x\n", val);
+
+	/* Configure rx/tx chains before running AGC/TxiQ cals */
+	if (val & AR_ENT_OTP_CHAIN2_DISABLE)
+		ar9003_hw_set_chain_masks(ah, 0x3, 0x3);
+	else
+		ar9003_hw_set_chain_masks(ah, pCap->rx_chainmask,
+					  pCap->tx_chainmask);
+
+	/* Do Tx IQ Calibration */
+	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
+		      AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
+		      DELPT);
+
+	/*
+	 * For AR9485 or later chips, TxIQ cal runs as part of
+	 * AGC calibration
+	 */
+	if (AR_SREV_9485_OR_LATER(ah))
+		txiqcal_done = 1;
+	else {
+		txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
+		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+		udelay(5);
+		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+	}
+
+	/* Calibrate the AGC */
+	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+		  REG_READ(ah, AR_PHY_AGC_CONTROL) |
+		  AR_PHY_AGC_CONTROL_CAL);
+
+	/* Poll for offset calibration complete */
+	if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
+			   0, AH_WAIT_TIMEOUT)) {
+		DBG("ath9k: "
+			"offset calibration failed to complete in 1ms; noisy environment?\n");
+		return 0;
+	}
+
+	if (txiqcal_done)
+		ar9003_hw_tx_iq_cal_post_proc(ah);
+
+	/* Revert chainmasks to their original values before NF cal */
+	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
+
+	ath9k_hw_start_nfcal(ah, 1);
+
+	/* Initialize list pointers */
+	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
+	ah->supp_cals = IQ_MISMATCH_CAL;
+
+	if (ah->supp_cals & IQ_MISMATCH_CAL) {
+		INIT_CAL(&ah->iq_caldata);
+		INSERT_CAL(ah, &ah->iq_caldata);
+		DBG2("ath9k: "
+			"enabling IQ Calibration.\n");
+	}
+
+	if (ah->supp_cals & TEMP_COMP_CAL) {
+		INIT_CAL(&ah->tempCompCalData);
+		INSERT_CAL(ah, &ah->tempCompCalData);
+		DBG2("ath9k: "
+			"enabling Temperature Compensation Calibration.\n");
+	}
+
+	/* Initialize current pointer to first element in list */
+	ah->cal_list_curr = ah->cal_list;
+
+	if (ah->cal_list_curr)
+		ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
+
+	if (ah->caldata)
+		ah->caldata->CalValid = 0;
+
+	return 1;
+}
+
+void ar9003_hw_attach_calib_ops(struct ath_hw *ah)
+{
+	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+	priv_ops->init_cal_settings = ar9003_hw_init_cal_settings;
+	priv_ops->init_cal = ar9003_hw_init_cal;
+	priv_ops->setup_calibration = ar9003_hw_setup_calibration;
+
+	ops->calibrate = ar9003_hw_calibrate;
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_eeprom.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_eeprom.c
new file mode 100644
index 0000000000000000000000000000000000000000..95e54b9b2a75c19a124f860c83b0a1eb7deed4a5
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_eeprom.c
@@ -0,0 +1,5005 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/io.h>
+#include <ipxe/malloc.h>
+
+#include "hw.h"
+#include "ar9003_phy.h"
+#include "ar9003_eeprom.h"
+
+#define COMP_HDR_LEN 4
+#define COMP_CKSUM_LEN 2
+
+#define AR_CH0_TOP (0x00016288)
+#define AR_CH0_TOP_XPABIASLVL (0x300)
+#define AR_CH0_TOP_XPABIASLVL_S (8)
+
+#define AR_CH0_THERM (0x00016290)
+#define AR_CH0_THERM_XPABIASLVL_MSB 0x3
+#define AR_CH0_THERM_XPABIASLVL_MSB_S 0
+#define AR_CH0_THERM_XPASHORT2GND 0x4
+#define AR_CH0_THERM_XPASHORT2GND_S 2
+
+#define AR_SWITCH_TABLE_COM_ALL (0xffff)
+#define AR_SWITCH_TABLE_COM_ALL_S (0)
+
+#define AR_SWITCH_TABLE_COM2_ALL (0xffffff)
+#define AR_SWITCH_TABLE_COM2_ALL_S (0)
+
+#define AR_SWITCH_TABLE_ALL (0xfff)
+#define AR_SWITCH_TABLE_ALL_S (0)
+
+#define LE16(x) (uint16_t)(x)
+#define LE32(x) (uint32_t)(x)
+
+/* Local defines to distinguish between extension and control CTL's */
+#define EXT_ADDITIVE (0x8000)
+#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE)
+#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE)
+#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE)
+#define REDUCE_SCALED_POWER_BY_TWO_CHAIN     6  /* 10*log10(2)*2 */
+#define REDUCE_SCALED_POWER_BY_THREE_CHAIN   9  /* 10*log10(3)*2 */
+#define PWRINCR_3_TO_1_CHAIN      9             /* 10*log(3)*2 */
+#define PWRINCR_3_TO_2_CHAIN      3             /* floor(10*log(3/2)*2) */
+#define PWRINCR_2_TO_1_CHAIN      6             /* 10*log(2)*2 */
+
+#define SUB_NUM_CTL_MODES_AT_5G_40 2    /* excluding HT40, EXT-OFDM */
+#define SUB_NUM_CTL_MODES_AT_2G_40 3    /* excluding HT40, EXT-OFDM, EXT-CCK */
+
+#define CTL(_tpower, _flag) ((_tpower) | ((_flag) << 6))
+
+#define EEPROM_DATA_LEN_9485	1088
+
+static int ar9003_hw_power_interpolate(int32_t x,
+				       int32_t *px, int32_t *py, uint16_t np);
+
+
+static const struct ar9300_eeprom ar9300_default = {
+	.eepromVersion = 2,
+	.templateVersion = 2,
+	.macAddr = {1, 2, 3, 4, 5, 6},
+	.custData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		     0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	.baseEepHeader = {
+		.regDmn = { LE16(0), LE16(0x1f) },
+		.txrxMask =  0x77, /* 4 bits tx and 4 bits rx */
+		.opCapFlags = {
+			.opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A,
+			.eepMisc = 0,
+		},
+		.rfSilent = 0,
+		.blueToothOptions = 0,
+		.deviceCap = 0,
+		.deviceType = 5, /* takes lower byte in eeprom location */
+		.pwrTableOffset = AR9300_PWR_TABLE_OFFSET,
+		.params_for_tuning_caps = {0, 0},
+		.featureEnable = 0x0c,
+		 /*
+		  * bit0 - enable tx temp comp - disabled
+		  * bit1 - enable tx volt comp - disabled
+		  * bit2 - enable fastClock - enabled
+		  * bit3 - enable doubling - enabled
+		  * bit4 - enable internal regulator - disabled
+		  * bit5 - enable pa predistortion - disabled
+		  */
+		.miscConfiguration = 0, /* bit0 - turn down drivestrength */
+		.eepromWriteEnableGpio = 3,
+		.wlanDisableGpio = 0,
+		.wlanLedGpio = 8,
+		.rxBandSelectGpio = 0xff,
+		.txrxgain = 0,
+		.swreg = 0,
+	 },
+	.modalHeader2G = {
+	/* ar9300_modal_eep_header  2g */
+		/* 4 idle,t1,t2,b(4 bits per setting) */
+		.antCtrlCommon = LE32(0x110),
+		/* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
+		.antCtrlCommon2 = LE32(0x22222),
+
+		/*
+		 * antCtrlChain[AR9300_MAX_CHAINS]; 6 idle, t, r,
+		 * rx1, rx12, b (2 bits each)
+		 */
+		.antCtrlChain = { LE16(0x150), LE16(0x150), LE16(0x150) },
+
+		/*
+		 * xatten1DB[AR9300_MAX_CHAINS];  3 xatten1_db
+		 * for ar9280 (0xa20c/b20c 5:0)
+		 */
+		.xatten1DB = {0, 0, 0},
+
+		/*
+		 * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+		 * for ar9280 (0xa20c/b20c 16:12
+		 */
+		.xatten1Margin = {0, 0, 0},
+		.tempSlope = 36,
+		.voltSlope = 0,
+
+		/*
+		 * spurChans[OSPREY_EEPROM_MODAL_SPURS]; spur
+		 * channels in usual fbin coding format
+		 */
+		.spurChans = {0, 0, 0, 0, 0},
+
+		/*
+		 * noiseFloorThreshCh[AR9300_MAX_CHAINS]; 3 Check
+		 * if the register is per chain
+		 */
+		.noiseFloorThreshCh = {-1, 0, 0},
+		.ob = {1, 1, 1},/* 3 chain */
+		.db_stage2 = {1, 1, 1}, /* 3 chain  */
+		.db_stage3 = {0, 0, 0},
+		.db_stage4 = {0, 0, 0},
+		.xpaBiasLvl = 0,
+		.txFrameToDataStart = 0x0e,
+		.txFrameToPaOn = 0x0e,
+		.txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+		.antennaGain = 0,
+		.switchSettling = 0x2c,
+		.adcDesiredSize = -30,
+		.txEndToXpaOff = 0,
+		.txEndToRxOn = 0x2,
+		.txFrameToXpaOn = 0xe,
+		.thresh62 = 28,
+		.papdRateMaskHt20 = LE32(0x0cf0e0e0),
+		.papdRateMaskHt40 = LE32(0x6cf0e0e0),
+		.futureModal = {
+			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		},
+	 },
+	.base_ext1 = {
+		.ant_div_control = 0,
+		.future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+	},
+	.calFreqPier2G = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1),
+	 },
+	/* ar9300_cal_data_per_freq_op_loop 2g */
+	.calPierData2G = {
+		{ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+		{ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+		{ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+	 },
+	.calTarget_freqbin_Cck = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2484, 1),
+	 },
+	.calTarget_freqbin_2G = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1)
+	 },
+	.calTarget_freqbin_2GHT20 = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1)
+	 },
+	.calTarget_freqbin_2GHT40 = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1)
+	 },
+	.calTargetPowerCck = {
+		 /* 1L-5L,5S,11L,11S */
+		 { {36, 36, 36, 36} },
+		 { {36, 36, 36, 36} },
+	},
+	.calTargetPower2G = {
+		 /* 6-24,36,48,54 */
+		 { {32, 32, 28, 24} },
+		 { {32, 32, 28, 24} },
+		 { {32, 32, 28, 24} },
+	},
+	.calTargetPower2GHT20 = {
+		{ {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} },
+		{ {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} },
+		{ {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} },
+	},
+	.calTargetPower2GHT40 = {
+		{ {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} },
+		{ {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} },
+		{ {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} },
+	},
+	.ctlIndex_2G =  {
+		0x11, 0x12, 0x15, 0x17, 0x41, 0x42,
+		0x45, 0x47, 0x31, 0x32, 0x35, 0x37,
+	},
+	.ctl_freqbin_2G = {
+		{
+			FREQ2FBIN(2412, 1),
+			FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2457, 1),
+			FREQ2FBIN(2462, 1)
+		},
+		{
+			FREQ2FBIN(2412, 1),
+			FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2462, 1),
+			0xFF,
+		},
+
+		{
+			FREQ2FBIN(2412, 1),
+			FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2462, 1),
+			0xFF,
+		},
+		{
+			FREQ2FBIN(2422, 1),
+			FREQ2FBIN(2427, 1),
+			FREQ2FBIN(2447, 1),
+			FREQ2FBIN(2452, 1)
+		},
+
+		{
+			/* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			/* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(2484, 1),
+		},
+
+		{
+			/* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			0,
+		},
+
+		{
+			/* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2472, 1),
+			0,
+		},
+
+		{
+			/* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+			/* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+			/* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+			/* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
+		},
+
+		{
+			/* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+		},
+
+		{
+			/* Data[9].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[9].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[9].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			0
+		},
+
+		{
+			/* Data[10].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[10].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[10].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			0
+		},
+
+		{
+			/* Data[11].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+			/* Data[11].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+			/* Data[11].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+			/* Data[11].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
+		}
+	 },
+	.ctlPowerData_2G = {
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		 { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
+
+		 { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+	 },
+	.modalHeader5G = {
+		/* 4 idle,t1,t2,b (4 bits per setting) */
+		.antCtrlCommon = LE32(0x110),
+		/* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */
+		.antCtrlCommon2 = LE32(0x22222),
+		 /* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */
+		.antCtrlChain = {
+			LE16(0x000), LE16(0x000), LE16(0x000),
+		},
+		 /* xatten1DB 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
+		.xatten1DB = {0, 0, 0},
+
+		/*
+		 * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+		 * for merlin (0xa20c/b20c 16:12
+		 */
+		.xatten1Margin = {0, 0, 0},
+		.tempSlope = 68,
+		.voltSlope = 0,
+		/* spurChans spur channels in usual fbin coding format */
+		.spurChans = {0, 0, 0, 0, 0},
+		/* noiseFloorThreshCh Check if the register is per chain */
+		.noiseFloorThreshCh = {-1, 0, 0},
+		.ob = {3, 3, 3}, /* 3 chain */
+		.db_stage2 = {3, 3, 3}, /* 3 chain */
+		.db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
+		.db_stage4 = {3, 3, 3},	 /* don't exist for 2G */
+		.xpaBiasLvl = 0,
+		.txFrameToDataStart = 0x0e,
+		.txFrameToPaOn = 0x0e,
+		.txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+		.antennaGain = 0,
+		.switchSettling = 0x2d,
+		.adcDesiredSize = -30,
+		.txEndToXpaOff = 0,
+		.txEndToRxOn = 0x2,
+		.txFrameToXpaOn = 0xe,
+		.thresh62 = 28,
+		.papdRateMaskHt20 = LE32(0x0c80c080),
+		.papdRateMaskHt40 = LE32(0x0080c080),
+		.futureModal = {
+			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		},
+	 },
+	.base_ext2 = {
+		.tempSlopeLow = 0,
+		.tempSlopeHigh = 0,
+		.xatten1DBLow = {0, 0, 0},
+		.xatten1MarginLow = {0, 0, 0},
+		.xatten1DBHigh = {0, 0, 0},
+		.xatten1MarginHigh = {0, 0, 0}
+	},
+	.calFreqPier5G = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5220, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5600, 0),
+		FREQ2FBIN(5725, 0),
+		FREQ2FBIN(5825, 0)
+	},
+	.calPierData5G = {
+			{
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+			},
+			{
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+			},
+			{
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+			},
+
+	},
+	.calTarget_freqbin_5G = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5220, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5600, 0),
+		FREQ2FBIN(5725, 0),
+		FREQ2FBIN(5825, 0)
+	},
+	.calTarget_freqbin_5GHT20 = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5240, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5700, 0),
+		FREQ2FBIN(5745, 0),
+		FREQ2FBIN(5725, 0),
+		FREQ2FBIN(5825, 0)
+	},
+	.calTarget_freqbin_5GHT40 = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5240, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5700, 0),
+		FREQ2FBIN(5745, 0),
+		FREQ2FBIN(5725, 0),
+		FREQ2FBIN(5825, 0)
+	 },
+	.calTargetPower5G = {
+		/* 6-24,36,48,54 */
+		{ {20, 20, 20, 10} },
+		{ {20, 20, 20, 10} },
+		{ {20, 20, 20, 10} },
+		{ {20, 20, 20, 10} },
+		{ {20, 20, 20, 10} },
+		{ {20, 20, 20, 10} },
+		{ {20, 20, 20, 10} },
+		{ {20, 20, 20, 10} },
+	 },
+	.calTargetPower5GHT20 = {
+		/*
+		 * 0_8_16,1-3_9-11_17-19,
+		 * 4,5,6,7,12,13,14,15,20,21,22,23
+		 */
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+	 },
+	.calTargetPower5GHT40 =  {
+		/*
+		 * 0_8_16,1-3_9-11_17-19,
+		 * 4,5,6,7,12,13,14,15,20,21,22,23
+		 */
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+		{ {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+	 },
+	.ctlIndex_5G =  {
+		0x10, 0x16, 0x18, 0x40, 0x46,
+		0x48, 0x30, 0x36, 0x38
+	},
+	.ctl_freqbin_5G =  {
+		{
+			/* Data[0].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[0].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[0].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+			/* Data[0].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[0].ctlEdges[4].bChannel */ FREQ2FBIN(5600, 0),
+			/* Data[0].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[0].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+			/* Data[0].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+		},
+		{
+			/* Data[1].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[1].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[1].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+			/* Data[1].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[1].ctlEdges[4].bChannel */ FREQ2FBIN(5520, 0),
+			/* Data[1].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[1].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+			/* Data[1].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+		},
+
+		{
+			/* Data[2].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+			/* Data[2].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+			/* Data[2].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+			/* Data[2].ctlEdges[3].bChannel */ FREQ2FBIN(5310, 0),
+			/* Data[2].ctlEdges[4].bChannel */ FREQ2FBIN(5510, 0),
+			/* Data[2].ctlEdges[5].bChannel */ FREQ2FBIN(5550, 0),
+			/* Data[2].ctlEdges[6].bChannel */ FREQ2FBIN(5670, 0),
+			/* Data[2].ctlEdges[7].bChannel */ FREQ2FBIN(5755, 0)
+		},
+
+		{
+			/* Data[3].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[3].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+			/* Data[3].ctlEdges[2].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[3].ctlEdges[3].bChannel */ FREQ2FBIN(5320, 0),
+			/* Data[3].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[3].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[3].ctlEdges[6].bChannel */ 0xFF,
+			/* Data[3].ctlEdges[7].bChannel */ 0xFF,
+		},
+
+		{
+			/* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[4].ctlEdges[4].bChannel */ 0xFF,
+			/* Data[4].ctlEdges[5].bChannel */ 0xFF,
+			/* Data[4].ctlEdges[6].bChannel */ 0xFF,
+			/* Data[4].ctlEdges[7].bChannel */ 0xFF,
+		},
+
+		{
+			/* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+			/* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(5270, 0),
+			/* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(5310, 0),
+			/* Data[5].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+			/* Data[5].ctlEdges[4].bChannel */ FREQ2FBIN(5590, 0),
+			/* Data[5].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+			/* Data[5].ctlEdges[6].bChannel */ 0xFF,
+			/* Data[5].ctlEdges[7].bChannel */ 0xFF
+		},
+
+		{
+			/* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+			/* Data[6].ctlEdges[2].bChannel */ FREQ2FBIN(5220, 0),
+			/* Data[6].ctlEdges[3].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[6].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[6].ctlEdges[5].bChannel */ FREQ2FBIN(5600, 0),
+			/* Data[6].ctlEdges[6].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[6].ctlEdges[7].bChannel */ FREQ2FBIN(5745, 0)
+		},
+
+		{
+			/* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(5320, 0),
+			/* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[7].ctlEdges[4].bChannel */ FREQ2FBIN(5560, 0),
+			/* Data[7].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[7].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+			/* Data[7].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+		},
+
+		{
+			/* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+			/* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+			/* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+			/* Data[8].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+			/* Data[8].ctlEdges[4].bChannel */ FREQ2FBIN(5550, 0),
+			/* Data[8].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+			/* Data[8].ctlEdges[6].bChannel */ FREQ2FBIN(5755, 0),
+			/* Data[8].ctlEdges[7].bChannel */ FREQ2FBIN(5795, 0)
+		}
+	 },
+	.ctlPowerData_5G = {
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+			}
+		},
+		{
+			{
+				CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+				CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+				CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+			}
+		},
+	 }
+};
+
+static const struct ar9300_eeprom ar9300_x113 = {
+	.eepromVersion = 2,
+	.templateVersion = 6,
+	.macAddr = {0x00, 0x03, 0x7f, 0x0, 0x0, 0x0},
+	.custData = {"x113-023-f0000"},
+	.baseEepHeader = {
+		.regDmn = { LE16(0), LE16(0x1f) },
+		.txrxMask =  0x77, /* 4 bits tx and 4 bits rx */
+		.opCapFlags = {
+			.opFlags = AR5416_OPFLAGS_11A,
+			.eepMisc = 0,
+		},
+		.rfSilent = 0,
+		.blueToothOptions = 0,
+		.deviceCap = 0,
+		.deviceType = 5, /* takes lower byte in eeprom location */
+		.pwrTableOffset = AR9300_PWR_TABLE_OFFSET,
+		.params_for_tuning_caps = {0, 0},
+		.featureEnable = 0x0d,
+		 /*
+		  * bit0 - enable tx temp comp - disabled
+		  * bit1 - enable tx volt comp - disabled
+		  * bit2 - enable fastClock - enabled
+		  * bit3 - enable doubling - enabled
+		  * bit4 - enable internal regulator - disabled
+		  * bit5 - enable pa predistortion - disabled
+		  */
+		.miscConfiguration = 0, /* bit0 - turn down drivestrength */
+		.eepromWriteEnableGpio = 6,
+		.wlanDisableGpio = 0,
+		.wlanLedGpio = 8,
+		.rxBandSelectGpio = 0xff,
+		.txrxgain = 0x21,
+		.swreg = 0,
+	 },
+	.modalHeader2G = {
+	/* ar9300_modal_eep_header  2g */
+		/* 4 idle,t1,t2,b(4 bits per setting) */
+		.antCtrlCommon = LE32(0x110),
+		/* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
+		.antCtrlCommon2 = LE32(0x44444),
+
+		/*
+		 * antCtrlChain[AR9300_MAX_CHAINS]; 6 idle, t, r,
+		 * rx1, rx12, b (2 bits each)
+		 */
+		.antCtrlChain = { LE16(0x150), LE16(0x150), LE16(0x150) },
+
+		/*
+		 * xatten1DB[AR9300_MAX_CHAINS];  3 xatten1_db
+		 * for ar9280 (0xa20c/b20c 5:0)
+		 */
+		.xatten1DB = {0, 0, 0},
+
+		/*
+		 * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+		 * for ar9280 (0xa20c/b20c 16:12
+		 */
+		.xatten1Margin = {0, 0, 0},
+		.tempSlope = 25,
+		.voltSlope = 0,
+
+		/*
+		 * spurChans[OSPREY_EEPROM_MODAL_SPURS]; spur
+		 * channels in usual fbin coding format
+		 */
+		.spurChans = {FREQ2FBIN(2464, 1), 0, 0, 0, 0},
+
+		/*
+		 * noiseFloorThreshCh[AR9300_MAX_CHAINS]; 3 Check
+		 * if the register is per chain
+		 */
+		.noiseFloorThreshCh = {-1, 0, 0},
+		.ob = {1, 1, 1},/* 3 chain */
+		.db_stage2 = {1, 1, 1}, /* 3 chain  */
+		.db_stage3 = {0, 0, 0},
+		.db_stage4 = {0, 0, 0},
+		.xpaBiasLvl = 0,
+		.txFrameToDataStart = 0x0e,
+		.txFrameToPaOn = 0x0e,
+		.txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+		.antennaGain = 0,
+		.switchSettling = 0x2c,
+		.adcDesiredSize = -30,
+		.txEndToXpaOff = 0,
+		.txEndToRxOn = 0x2,
+		.txFrameToXpaOn = 0xe,
+		.thresh62 = 28,
+		.papdRateMaskHt20 = LE32(0x0c80c080),
+		.papdRateMaskHt40 = LE32(0x0080c080),
+		.futureModal = {
+			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		},
+	 },
+	 .base_ext1 = {
+		.ant_div_control = 0,
+		.future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+	 },
+	.calFreqPier2G = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1),
+	 },
+	/* ar9300_cal_data_per_freq_op_loop 2g */
+	.calPierData2G = {
+		{ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+		{ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+		{ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+	 },
+	.calTarget_freqbin_Cck = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2472, 1),
+	 },
+	.calTarget_freqbin_2G = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1)
+	 },
+	.calTarget_freqbin_2GHT20 = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1)
+	 },
+	.calTarget_freqbin_2GHT40 = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1)
+	 },
+	.calTargetPowerCck = {
+		 /* 1L-5L,5S,11L,11S */
+		 { {34, 34, 34, 34} },
+		 { {34, 34, 34, 34} },
+	},
+	.calTargetPower2G = {
+		 /* 6-24,36,48,54 */
+		 { {34, 34, 32, 32} },
+		 { {34, 34, 32, 32} },
+		 { {34, 34, 32, 32} },
+	},
+	.calTargetPower2GHT20 = {
+		{ {32, 32, 32, 32, 32, 28, 32, 32, 30, 28, 0, 0, 0, 0} },
+		{ {32, 32, 32, 32, 32, 28, 32, 32, 30, 28, 0, 0, 0, 0} },
+		{ {32, 32, 32, 32, 32, 28, 32, 32, 30, 28, 0, 0, 0, 0} },
+	},
+	.calTargetPower2GHT40 = {
+		{ {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} },
+		{ {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} },
+		{ {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} },
+	},
+	.ctlIndex_2G =  {
+		0x11, 0x12, 0x15, 0x17, 0x41, 0x42,
+		0x45, 0x47, 0x31, 0x32, 0x35, 0x37,
+	},
+	.ctl_freqbin_2G = {
+		{
+			FREQ2FBIN(2412, 1),
+			FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2457, 1),
+			FREQ2FBIN(2462, 1)
+		},
+		{
+			FREQ2FBIN(2412, 1),
+			FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2462, 1),
+			0xFF,
+		},
+
+		{
+			FREQ2FBIN(2412, 1),
+			FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2462, 1),
+			0xFF,
+		},
+		{
+			FREQ2FBIN(2422, 1),
+			FREQ2FBIN(2427, 1),
+			FREQ2FBIN(2447, 1),
+			FREQ2FBIN(2452, 1)
+		},
+
+		{
+			/* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			/* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(2484, 1),
+		},
+
+		{
+			/* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			0,
+		},
+
+		{
+			/* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2472, 1),
+			0,
+		},
+
+		{
+			/* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+			/* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+			/* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+			/* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
+		},
+
+		{
+			/* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+		},
+
+		{
+			/* Data[9].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[9].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[9].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			0
+		},
+
+		{
+			/* Data[10].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[10].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[10].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			0
+		},
+
+		{
+			/* Data[11].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+			/* Data[11].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+			/* Data[11].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+			/* Data[11].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
+		}
+	 },
+	.ctlPowerData_2G = {
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		 { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
+
+		 { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+	 },
+	.modalHeader5G = {
+		/* 4 idle,t1,t2,b (4 bits per setting) */
+		.antCtrlCommon = LE32(0x220),
+		/* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */
+		.antCtrlCommon2 = LE32(0x11111),
+		 /* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */
+		.antCtrlChain = {
+			LE16(0x150), LE16(0x150), LE16(0x150),
+		},
+		 /* xatten1DB 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
+		.xatten1DB = {0, 0, 0},
+
+		/*
+		 * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+		 * for merlin (0xa20c/b20c 16:12
+		 */
+		.xatten1Margin = {0, 0, 0},
+		.tempSlope = 68,
+		.voltSlope = 0,
+		/* spurChans spur channels in usual fbin coding format */
+		.spurChans = {FREQ2FBIN(5500, 0), 0, 0, 0, 0},
+		/* noiseFloorThreshCh Check if the register is per chain */
+		.noiseFloorThreshCh = {-1, 0, 0},
+		.ob = {3, 3, 3}, /* 3 chain */
+		.db_stage2 = {3, 3, 3}, /* 3 chain */
+		.db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
+		.db_stage4 = {3, 3, 3},	 /* don't exist for 2G */
+		.xpaBiasLvl = 0xf,
+		.txFrameToDataStart = 0x0e,
+		.txFrameToPaOn = 0x0e,
+		.txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+		.antennaGain = 0,
+		.switchSettling = 0x2d,
+		.adcDesiredSize = -30,
+		.txEndToXpaOff = 0,
+		.txEndToRxOn = 0x2,
+		.txFrameToXpaOn = 0xe,
+		.thresh62 = 28,
+		.papdRateMaskHt20 = LE32(0x0cf0e0e0),
+		.papdRateMaskHt40 = LE32(0x6cf0e0e0),
+		.futureModal = {
+			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		},
+	 },
+	.base_ext2 = {
+		.tempSlopeLow = 72,
+		.tempSlopeHigh = 105,
+		.xatten1DBLow = {0, 0, 0},
+		.xatten1MarginLow = {0, 0, 0},
+		.xatten1DBHigh = {0, 0, 0},
+		.xatten1MarginHigh = {0, 0, 0}
+	 },
+	.calFreqPier5G = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5240, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5600, 0),
+		FREQ2FBIN(5745, 0),
+		FREQ2FBIN(5785, 0)
+	},
+	.calPierData5G = {
+			{
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+			},
+			{
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+			},
+			{
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+			},
+
+	},
+	.calTarget_freqbin_5G = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5220, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5600, 0),
+		FREQ2FBIN(5745, 0),
+		FREQ2FBIN(5785, 0)
+	},
+	.calTarget_freqbin_5GHT20 = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5240, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5700, 0),
+		FREQ2FBIN(5745, 0),
+		FREQ2FBIN(5825, 0)
+	},
+	.calTarget_freqbin_5GHT40 = {
+		FREQ2FBIN(5190, 0),
+		FREQ2FBIN(5230, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5410, 0),
+		FREQ2FBIN(5510, 0),
+		FREQ2FBIN(5670, 0),
+		FREQ2FBIN(5755, 0),
+		FREQ2FBIN(5825, 0)
+	 },
+	.calTargetPower5G = {
+		/* 6-24,36,48,54 */
+		{ {42, 40, 40, 34} },
+		{ {42, 40, 40, 34} },
+		{ {42, 40, 40, 34} },
+		{ {42, 40, 40, 34} },
+		{ {42, 40, 40, 34} },
+		{ {42, 40, 40, 34} },
+		{ {42, 40, 40, 34} },
+		{ {42, 40, 40, 34} },
+	 },
+	.calTargetPower5GHT20 = {
+		/*
+		 * 0_8_16,1-3_9-11_17-19,
+		 * 4,5,6,7,12,13,14,15,20,21,22,23
+		 */
+		{ {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} },
+		{ {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} },
+		{ {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} },
+		{ {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} },
+		{ {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} },
+		{ {40, 40, 40, 40, 32, 28, 40, 40, 32, 28, 40, 40, 32, 20} },
+		{ {38, 38, 38, 38, 32, 28, 38, 38, 32, 28, 38, 38, 32, 26} },
+		{ {36, 36, 36, 36, 32, 28, 36, 36, 32, 28, 36, 36, 32, 26} },
+	 },
+	.calTargetPower5GHT40 =  {
+		/*
+		 * 0_8_16,1-3_9-11_17-19,
+		 * 4,5,6,7,12,13,14,15,20,21,22,23
+		 */
+		{ {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} },
+		{ {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} },
+		{ {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} },
+		{ {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} },
+		{ {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} },
+		{ {40, 40, 40, 38, 30, 26, 40, 40, 30, 26, 40, 40, 30, 24} },
+		{ {36, 36, 36, 36, 30, 26, 36, 36, 30, 26, 36, 36, 30, 24} },
+		{ {34, 34, 34, 34, 30, 26, 34, 34, 30, 26, 34, 34, 30, 24} },
+	 },
+	.ctlIndex_5G =  {
+		0x10, 0x16, 0x18, 0x40, 0x46,
+		0x48, 0x30, 0x36, 0x38
+	},
+	.ctl_freqbin_5G =  {
+		{
+			/* Data[0].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[0].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[0].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+			/* Data[0].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[0].ctlEdges[4].bChannel */ FREQ2FBIN(5600, 0),
+			/* Data[0].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[0].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+			/* Data[0].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+		},
+		{
+			/* Data[1].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[1].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[1].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+			/* Data[1].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[1].ctlEdges[4].bChannel */ FREQ2FBIN(5520, 0),
+			/* Data[1].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[1].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+			/* Data[1].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+		},
+
+		{
+			/* Data[2].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+			/* Data[2].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+			/* Data[2].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+			/* Data[2].ctlEdges[3].bChannel */ FREQ2FBIN(5310, 0),
+			/* Data[2].ctlEdges[4].bChannel */ FREQ2FBIN(5510, 0),
+			/* Data[2].ctlEdges[5].bChannel */ FREQ2FBIN(5550, 0),
+			/* Data[2].ctlEdges[6].bChannel */ FREQ2FBIN(5670, 0),
+			/* Data[2].ctlEdges[7].bChannel */ FREQ2FBIN(5755, 0)
+		},
+
+		{
+			/* Data[3].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[3].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+			/* Data[3].ctlEdges[2].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[3].ctlEdges[3].bChannel */ FREQ2FBIN(5320, 0),
+			/* Data[3].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[3].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[3].ctlEdges[6].bChannel */ 0xFF,
+			/* Data[3].ctlEdges[7].bChannel */ 0xFF,
+		},
+
+		{
+			/* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[4].ctlEdges[4].bChannel */ 0xFF,
+			/* Data[4].ctlEdges[5].bChannel */ 0xFF,
+			/* Data[4].ctlEdges[6].bChannel */ 0xFF,
+			/* Data[4].ctlEdges[7].bChannel */ 0xFF,
+		},
+
+		{
+			/* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+			/* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(5270, 0),
+			/* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(5310, 0),
+			/* Data[5].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+			/* Data[5].ctlEdges[4].bChannel */ FREQ2FBIN(5590, 0),
+			/* Data[5].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+			/* Data[5].ctlEdges[6].bChannel */ 0xFF,
+			/* Data[5].ctlEdges[7].bChannel */ 0xFF
+		},
+
+		{
+			/* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+			/* Data[6].ctlEdges[2].bChannel */ FREQ2FBIN(5220, 0),
+			/* Data[6].ctlEdges[3].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[6].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[6].ctlEdges[5].bChannel */ FREQ2FBIN(5600, 0),
+			/* Data[6].ctlEdges[6].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[6].ctlEdges[7].bChannel */ FREQ2FBIN(5745, 0)
+		},
+
+		{
+			/* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(5320, 0),
+			/* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[7].ctlEdges[4].bChannel */ FREQ2FBIN(5560, 0),
+			/* Data[7].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[7].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+			/* Data[7].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+		},
+
+		{
+			/* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+			/* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+			/* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+			/* Data[8].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+			/* Data[8].ctlEdges[4].bChannel */ FREQ2FBIN(5550, 0),
+			/* Data[8].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+			/* Data[8].ctlEdges[6].bChannel */ FREQ2FBIN(5755, 0),
+			/* Data[8].ctlEdges[7].bChannel */ FREQ2FBIN(5795, 0)
+		}
+	 },
+	.ctlPowerData_5G = {
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+			}
+		},
+		{
+			{
+				CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+				CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+				CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+			}
+		},
+	 }
+};
+
+
+static const struct ar9300_eeprom ar9300_h112 = {
+	.eepromVersion = 2,
+	.templateVersion = 3,
+	.macAddr = {0x00, 0x03, 0x7f, 0x0, 0x0, 0x0},
+	.custData = {"h112-241-f0000"},
+	.baseEepHeader = {
+		.regDmn = { LE16(0), LE16(0x1f) },
+		.txrxMask =  0x77, /* 4 bits tx and 4 bits rx */
+		.opCapFlags = {
+			.opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A,
+			.eepMisc = 0,
+		},
+		.rfSilent = 0,
+		.blueToothOptions = 0,
+		.deviceCap = 0,
+		.deviceType = 5, /* takes lower byte in eeprom location */
+		.pwrTableOffset = AR9300_PWR_TABLE_OFFSET,
+		.params_for_tuning_caps = {0, 0},
+		.featureEnable = 0x0d,
+		/*
+		 * bit0 - enable tx temp comp - disabled
+		 * bit1 - enable tx volt comp - disabled
+		 * bit2 - enable fastClock - enabled
+		 * bit3 - enable doubling - enabled
+		 * bit4 - enable internal regulator - disabled
+		 * bit5 - enable pa predistortion - disabled
+		 */
+		.miscConfiguration = 0, /* bit0 - turn down drivestrength */
+		.eepromWriteEnableGpio = 6,
+		.wlanDisableGpio = 0,
+		.wlanLedGpio = 8,
+		.rxBandSelectGpio = 0xff,
+		.txrxgain = 0x10,
+		.swreg = 0,
+	},
+	.modalHeader2G = {
+		/* ar9300_modal_eep_header  2g */
+		/* 4 idle,t1,t2,b(4 bits per setting) */
+		.antCtrlCommon = LE32(0x110),
+		/* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
+		.antCtrlCommon2 = LE32(0x44444),
+
+		/*
+		 * antCtrlChain[AR9300_MAX_CHAINS]; 6 idle, t, r,
+		 * rx1, rx12, b (2 bits each)
+		 */
+		.antCtrlChain = { LE16(0x150), LE16(0x150), LE16(0x150) },
+
+		/*
+		 * xatten1DB[AR9300_MAX_CHAINS];  3 xatten1_db
+		 * for ar9280 (0xa20c/b20c 5:0)
+		 */
+		.xatten1DB = {0, 0, 0},
+
+		/*
+		 * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+		 * for ar9280 (0xa20c/b20c 16:12
+		 */
+		.xatten1Margin = {0, 0, 0},
+		.tempSlope = 25,
+		.voltSlope = 0,
+
+		/*
+		 * spurChans[OSPREY_EEPROM_MODAL_SPURS]; spur
+		 * channels in usual fbin coding format
+		 */
+		.spurChans = {FREQ2FBIN(2464, 1), 0, 0, 0, 0},
+
+		/*
+		 * noiseFloorThreshCh[AR9300_MAX_CHAINS]; 3 Check
+		 * if the register is per chain
+		 */
+		.noiseFloorThreshCh = {-1, 0, 0},
+		.ob = {1, 1, 1},/* 3 chain */
+		.db_stage2 = {1, 1, 1}, /* 3 chain  */
+		.db_stage3 = {0, 0, 0},
+		.db_stage4 = {0, 0, 0},
+		.xpaBiasLvl = 0,
+		.txFrameToDataStart = 0x0e,
+		.txFrameToPaOn = 0x0e,
+		.txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+		.antennaGain = 0,
+		.switchSettling = 0x2c,
+		.adcDesiredSize = -30,
+		.txEndToXpaOff = 0,
+		.txEndToRxOn = 0x2,
+		.txFrameToXpaOn = 0xe,
+		.thresh62 = 28,
+		.papdRateMaskHt20 = LE32(0x80c080),
+		.papdRateMaskHt40 = LE32(0x80c080),
+		.futureModal = {
+			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		},
+	},
+	.base_ext1 = {
+		.ant_div_control = 0,
+		.future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+	},
+	.calFreqPier2G = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1),
+	},
+	/* ar9300_cal_data_per_freq_op_loop 2g */
+	.calPierData2G = {
+		{ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+		{ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+		{ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+	},
+	.calTarget_freqbin_Cck = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2484, 1),
+	},
+	.calTarget_freqbin_2G = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1)
+	},
+	.calTarget_freqbin_2GHT20 = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1)
+	},
+	.calTarget_freqbin_2GHT40 = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1)
+	},
+	.calTargetPowerCck = {
+		/* 1L-5L,5S,11L,11S */
+		{ {34, 34, 34, 34} },
+		{ {34, 34, 34, 34} },
+	},
+	.calTargetPower2G = {
+		/* 6-24,36,48,54 */
+		{ {34, 34, 32, 32} },
+		{ {34, 34, 32, 32} },
+		{ {34, 34, 32, 32} },
+	},
+	.calTargetPower2GHT20 = {
+		{ {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 28, 28, 28, 24} },
+		{ {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 28, 28, 28, 24} },
+		{ {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 28, 28, 28, 24} },
+	},
+	.calTargetPower2GHT40 = {
+		{ {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 26, 26, 26, 22} },
+		{ {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 26, 26, 26, 22} },
+		{ {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 26, 26, 26, 22} },
+	},
+	.ctlIndex_2G =  {
+		0x11, 0x12, 0x15, 0x17, 0x41, 0x42,
+		0x45, 0x47, 0x31, 0x32, 0x35, 0x37,
+	},
+	.ctl_freqbin_2G = {
+		{
+			FREQ2FBIN(2412, 1),
+			FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2457, 1),
+			FREQ2FBIN(2462, 1)
+		},
+		{
+			FREQ2FBIN(2412, 1),
+			FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2462, 1),
+			0xFF,
+		},
+
+		{
+			FREQ2FBIN(2412, 1),
+			FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2462, 1),
+			0xFF,
+		},
+		{
+			FREQ2FBIN(2422, 1),
+			FREQ2FBIN(2427, 1),
+			FREQ2FBIN(2447, 1),
+			FREQ2FBIN(2452, 1)
+		},
+
+		{
+			/* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			/* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(2484, 1),
+		},
+
+		{
+			/* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			0,
+		},
+
+		{
+			/* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2472, 1),
+			0,
+		},
+
+		{
+			/* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+			/* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+			/* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+			/* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
+		},
+
+		{
+			/* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+		},
+
+		{
+			/* Data[9].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[9].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[9].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			0
+		},
+
+		{
+			/* Data[10].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[10].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[10].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			0
+		},
+
+		{
+			/* Data[11].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+			/* Data[11].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+			/* Data[11].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+			/* Data[11].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
+		}
+	},
+	.ctlPowerData_2G = {
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		{ { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
+
+		{ { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+	},
+	.modalHeader5G = {
+		/* 4 idle,t1,t2,b (4 bits per setting) */
+		.antCtrlCommon = LE32(0x220),
+		/* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */
+		.antCtrlCommon2 = LE32(0x44444),
+		/* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */
+		.antCtrlChain = {
+			LE16(0x150), LE16(0x150), LE16(0x150),
+		},
+		/* xatten1DB 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
+		.xatten1DB = {0, 0, 0},
+
+		/*
+		 * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+		 * for merlin (0xa20c/b20c 16:12
+		 */
+		.xatten1Margin = {0, 0, 0},
+		.tempSlope = 45,
+		.voltSlope = 0,
+		/* spurChans spur channels in usual fbin coding format */
+		.spurChans = {0, 0, 0, 0, 0},
+		/* noiseFloorThreshCh Check if the register is per chain */
+		.noiseFloorThreshCh = {-1, 0, 0},
+		.ob = {3, 3, 3}, /* 3 chain */
+		.db_stage2 = {3, 3, 3}, /* 3 chain */
+		.db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
+		.db_stage4 = {3, 3, 3},	 /* don't exist for 2G */
+		.xpaBiasLvl = 0,
+		.txFrameToDataStart = 0x0e,
+		.txFrameToPaOn = 0x0e,
+		.txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+		.antennaGain = 0,
+		.switchSettling = 0x2d,
+		.adcDesiredSize = -30,
+		.txEndToXpaOff = 0,
+		.txEndToRxOn = 0x2,
+		.txFrameToXpaOn = 0xe,
+		.thresh62 = 28,
+		.papdRateMaskHt20 = LE32(0x0cf0e0e0),
+		.papdRateMaskHt40 = LE32(0x6cf0e0e0),
+		.futureModal = {
+			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		},
+	},
+	.base_ext2 = {
+		.tempSlopeLow = 40,
+		.tempSlopeHigh = 50,
+		.xatten1DBLow = {0, 0, 0},
+		.xatten1MarginLow = {0, 0, 0},
+		.xatten1DBHigh = {0, 0, 0},
+		.xatten1MarginHigh = {0, 0, 0}
+	},
+	.calFreqPier5G = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5220, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5600, 0),
+		FREQ2FBIN(5700, 0),
+		FREQ2FBIN(5825, 0)
+	},
+	.calPierData5G = {
+		{
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+		},
+		{
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+		},
+		{
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+		},
+
+	},
+	.calTarget_freqbin_5G = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5240, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5600, 0),
+		FREQ2FBIN(5700, 0),
+		FREQ2FBIN(5825, 0)
+	},
+	.calTarget_freqbin_5GHT20 = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5240, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5700, 0),
+		FREQ2FBIN(5745, 0),
+		FREQ2FBIN(5825, 0)
+	},
+	.calTarget_freqbin_5GHT40 = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5240, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5700, 0),
+		FREQ2FBIN(5745, 0),
+		FREQ2FBIN(5825, 0)
+	},
+	.calTargetPower5G = {
+		/* 6-24,36,48,54 */
+		{ {30, 30, 28, 24} },
+		{ {30, 30, 28, 24} },
+		{ {30, 30, 28, 24} },
+		{ {30, 30, 28, 24} },
+		{ {30, 30, 28, 24} },
+		{ {30, 30, 28, 24} },
+		{ {30, 30, 28, 24} },
+		{ {30, 30, 28, 24} },
+	},
+	.calTargetPower5GHT20 = {
+		/*
+		 * 0_8_16,1-3_9-11_17-19,
+		 * 4,5,6,7,12,13,14,15,20,21,22,23
+		 */
+		{ {30, 30, 30, 28, 24, 20, 30, 28, 24, 20, 20, 20, 20, 16} },
+		{ {30, 30, 30, 28, 24, 20, 30, 28, 24, 20, 20, 20, 20, 16} },
+		{ {30, 30, 30, 26, 22, 18, 30, 26, 22, 18, 18, 18, 18, 16} },
+		{ {30, 30, 30, 26, 22, 18, 30, 26, 22, 18, 18, 18, 18, 16} },
+		{ {30, 30, 30, 24, 20, 16, 30, 24, 20, 16, 16, 16, 16, 14} },
+		{ {30, 30, 30, 24, 20, 16, 30, 24, 20, 16, 16, 16, 16, 14} },
+		{ {30, 30, 30, 22, 18, 14, 30, 22, 18, 14, 14, 14, 14, 12} },
+		{ {30, 30, 30, 22, 18, 14, 30, 22, 18, 14, 14, 14, 14, 12} },
+	},
+	.calTargetPower5GHT40 =  {
+		/*
+		 * 0_8_16,1-3_9-11_17-19,
+		 * 4,5,6,7,12,13,14,15,20,21,22,23
+		 */
+		{ {28, 28, 28, 26, 22, 18, 28, 26, 22, 18, 18, 18, 18, 14} },
+		{ {28, 28, 28, 26, 22, 18, 28, 26, 22, 18, 18, 18, 18, 14} },
+		{ {28, 28, 28, 24, 20, 16, 28, 24, 20, 16, 16, 16, 16, 12} },
+		{ {28, 28, 28, 24, 20, 16, 28, 24, 20, 16, 16, 16, 16, 12} },
+		{ {28, 28, 28, 22, 18, 14, 28, 22, 18, 14, 14, 14, 14, 10} },
+		{ {28, 28, 28, 22, 18, 14, 28, 22, 18, 14, 14, 14, 14, 10} },
+		{ {28, 28, 28, 20, 16, 12, 28, 20, 16, 12, 12, 12, 12, 8} },
+		{ {28, 28, 28, 20, 16, 12, 28, 20, 16, 12, 12, 12, 12, 8} },
+	},
+	.ctlIndex_5G =  {
+		0x10, 0x16, 0x18, 0x40, 0x46,
+		0x48, 0x30, 0x36, 0x38
+	},
+	.ctl_freqbin_5G =  {
+		{
+			/* Data[0].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[0].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[0].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+			/* Data[0].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[0].ctlEdges[4].bChannel */ FREQ2FBIN(5600, 0),
+			/* Data[0].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[0].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+			/* Data[0].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+		},
+		{
+			/* Data[1].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[1].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[1].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+			/* Data[1].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[1].ctlEdges[4].bChannel */ FREQ2FBIN(5520, 0),
+			/* Data[1].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[1].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+			/* Data[1].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+		},
+
+		{
+			/* Data[2].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+			/* Data[2].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+			/* Data[2].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+			/* Data[2].ctlEdges[3].bChannel */ FREQ2FBIN(5310, 0),
+			/* Data[2].ctlEdges[4].bChannel */ FREQ2FBIN(5510, 0),
+			/* Data[2].ctlEdges[5].bChannel */ FREQ2FBIN(5550, 0),
+			/* Data[2].ctlEdges[6].bChannel */ FREQ2FBIN(5670, 0),
+			/* Data[2].ctlEdges[7].bChannel */ FREQ2FBIN(5755, 0)
+		},
+
+		{
+			/* Data[3].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[3].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+			/* Data[3].ctlEdges[2].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[3].ctlEdges[3].bChannel */ FREQ2FBIN(5320, 0),
+			/* Data[3].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[3].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[3].ctlEdges[6].bChannel */ 0xFF,
+			/* Data[3].ctlEdges[7].bChannel */ 0xFF,
+		},
+
+		{
+			/* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[4].ctlEdges[4].bChannel */ 0xFF,
+			/* Data[4].ctlEdges[5].bChannel */ 0xFF,
+			/* Data[4].ctlEdges[6].bChannel */ 0xFF,
+			/* Data[4].ctlEdges[7].bChannel */ 0xFF,
+		},
+
+		{
+			/* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+			/* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(5270, 0),
+			/* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(5310, 0),
+			/* Data[5].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+			/* Data[5].ctlEdges[4].bChannel */ FREQ2FBIN(5590, 0),
+			/* Data[5].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+			/* Data[5].ctlEdges[6].bChannel */ 0xFF,
+			/* Data[5].ctlEdges[7].bChannel */ 0xFF
+		},
+
+		{
+			/* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+			/* Data[6].ctlEdges[2].bChannel */ FREQ2FBIN(5220, 0),
+			/* Data[6].ctlEdges[3].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[6].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[6].ctlEdges[5].bChannel */ FREQ2FBIN(5600, 0),
+			/* Data[6].ctlEdges[6].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[6].ctlEdges[7].bChannel */ FREQ2FBIN(5745, 0)
+		},
+
+		{
+			/* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(5320, 0),
+			/* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[7].ctlEdges[4].bChannel */ FREQ2FBIN(5560, 0),
+			/* Data[7].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[7].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+			/* Data[7].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+		},
+
+		{
+			/* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+			/* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+			/* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+			/* Data[8].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+			/* Data[8].ctlEdges[4].bChannel */ FREQ2FBIN(5550, 0),
+			/* Data[8].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+			/* Data[8].ctlEdges[6].bChannel */ FREQ2FBIN(5755, 0),
+			/* Data[8].ctlEdges[7].bChannel */ FREQ2FBIN(5795, 0)
+		}
+	},
+	.ctlPowerData_5G = {
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+			}
+		},
+		{
+			{
+				CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+				CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+				CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+			}
+		},
+	}
+};
+
+
+static const struct ar9300_eeprom ar9300_x112 = {
+	.eepromVersion = 2,
+	.templateVersion = 5,
+	.macAddr = {0x00, 0x03, 0x7f, 0x0, 0x0, 0x0},
+	.custData = {"x112-041-f0000"},
+	.baseEepHeader = {
+		.regDmn = { LE16(0), LE16(0x1f) },
+		.txrxMask =  0x77, /* 4 bits tx and 4 bits rx */
+		.opCapFlags = {
+			.opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A,
+			.eepMisc = 0,
+		},
+		.rfSilent = 0,
+		.blueToothOptions = 0,
+		.deviceCap = 0,
+		.deviceType = 5, /* takes lower byte in eeprom location */
+		.pwrTableOffset = AR9300_PWR_TABLE_OFFSET,
+		.params_for_tuning_caps = {0, 0},
+		.featureEnable = 0x0d,
+		/*
+		 * bit0 - enable tx temp comp - disabled
+		 * bit1 - enable tx volt comp - disabled
+		 * bit2 - enable fastclock - enabled
+		 * bit3 - enable doubling - enabled
+		 * bit4 - enable internal regulator - disabled
+		 * bit5 - enable pa predistortion - disabled
+		 */
+		.miscConfiguration = 0, /* bit0 - turn down drivestrength */
+		.eepromWriteEnableGpio = 6,
+		.wlanDisableGpio = 0,
+		.wlanLedGpio = 8,
+		.rxBandSelectGpio = 0xff,
+		.txrxgain = 0x0,
+		.swreg = 0,
+	},
+	.modalHeader2G = {
+		/* ar9300_modal_eep_header  2g */
+		/* 4 idle,t1,t2,b(4 bits per setting) */
+		.antCtrlCommon = LE32(0x110),
+		/* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
+		.antCtrlCommon2 = LE32(0x22222),
+
+		/*
+		 * antCtrlChain[ar9300_max_chains]; 6 idle, t, r,
+		 * rx1, rx12, b (2 bits each)
+		 */
+		.antCtrlChain = { LE16(0x10), LE16(0x10), LE16(0x10) },
+
+		/*
+		 * xatten1DB[AR9300_max_chains];  3 xatten1_db
+		 * for ar9280 (0xa20c/b20c 5:0)
+		 */
+		.xatten1DB = {0x1b, 0x1b, 0x1b},
+
+		/*
+		 * xatten1Margin[ar9300_max_chains]; 3 xatten1_margin
+		 * for ar9280 (0xa20c/b20c 16:12
+		 */
+		.xatten1Margin = {0x15, 0x15, 0x15},
+		.tempSlope = 50,
+		.voltSlope = 0,
+
+		/*
+		 * spurChans[OSPrey_eeprom_modal_sPURS]; spur
+		 * channels in usual fbin coding format
+		 */
+		.spurChans = {FREQ2FBIN(2464, 1), 0, 0, 0, 0},
+
+		/*
+		 * noiseFloorThreshch[ar9300_max_cHAINS]; 3 Check
+		 * if the register is per chain
+		 */
+		.noiseFloorThreshCh = {-1, 0, 0},
+		.ob = {1, 1, 1},/* 3 chain */
+		.db_stage2 = {1, 1, 1}, /* 3 chain  */
+		.db_stage3 = {0, 0, 0},
+		.db_stage4 = {0, 0, 0},
+		.xpaBiasLvl = 0,
+		.txFrameToDataStart = 0x0e,
+		.txFrameToPaOn = 0x0e,
+		.txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+		.antennaGain = 0,
+		.switchSettling = 0x2c,
+		.adcDesiredSize = -30,
+		.txEndToXpaOff = 0,
+		.txEndToRxOn = 0x2,
+		.txFrameToXpaOn = 0xe,
+		.thresh62 = 28,
+		.papdRateMaskHt20 = LE32(0x0c80c080),
+		.papdRateMaskHt40 = LE32(0x0080c080),
+		.futureModal = {
+			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		},
+	},
+	.base_ext1 = {
+		.ant_div_control = 0,
+		.future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+	},
+	.calFreqPier2G = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1),
+	},
+	/* ar9300_cal_data_per_freq_op_loop 2g */
+	.calPierData2G = {
+		{ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+		{ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+		{ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+	},
+	.calTarget_freqbin_Cck = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2472, 1),
+	},
+	.calTarget_freqbin_2G = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1)
+	},
+	.calTarget_freqbin_2GHT20 = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1)
+	},
+	.calTarget_freqbin_2GHT40 = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1)
+	},
+	.calTargetPowerCck = {
+		/* 1L-5L,5S,11L,11s */
+		{ {38, 38, 38, 38} },
+		{ {38, 38, 38, 38} },
+	},
+	.calTargetPower2G = {
+		/* 6-24,36,48,54 */
+		{ {38, 38, 36, 34} },
+		{ {38, 38, 36, 34} },
+		{ {38, 38, 34, 32} },
+	},
+	.calTargetPower2GHT20 = {
+		{ {36, 36, 36, 36, 36, 34, 34, 32, 30, 28, 28, 28, 28, 26} },
+		{ {36, 36, 36, 36, 36, 34, 36, 34, 32, 30, 30, 30, 28, 26} },
+		{ {36, 36, 36, 36, 36, 34, 34, 32, 30, 28, 28, 28, 28, 26} },
+	},
+	.calTargetPower2GHT40 = {
+		{ {36, 36, 36, 36, 34, 32, 32, 30, 28, 26, 26, 26, 26, 24} },
+		{ {36, 36, 36, 36, 34, 32, 34, 32, 30, 28, 28, 28, 28, 24} },
+		{ {36, 36, 36, 36, 34, 32, 32, 30, 28, 26, 26, 26, 26, 24} },
+	},
+	.ctlIndex_2G =  {
+		0x11, 0x12, 0x15, 0x17, 0x41, 0x42,
+		0x45, 0x47, 0x31, 0x32, 0x35, 0x37,
+	},
+	.ctl_freqbin_2G = {
+		{
+			FREQ2FBIN(2412, 1),
+			FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2457, 1),
+			FREQ2FBIN(2462, 1)
+		},
+		{
+			FREQ2FBIN(2412, 1),
+			FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2462, 1),
+			0xFF,
+		},
+
+		{
+			FREQ2FBIN(2412, 1),
+			FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2462, 1),
+			0xFF,
+		},
+		{
+			FREQ2FBIN(2422, 1),
+			FREQ2FBIN(2427, 1),
+			FREQ2FBIN(2447, 1),
+			FREQ2FBIN(2452, 1)
+		},
+
+		{
+			/* Data[4].ctledges[0].bchannel */ FREQ2FBIN(2412, 1),
+			/* Data[4].ctledges[1].bchannel */ FREQ2FBIN(2417, 1),
+			/* Data[4].ctledges[2].bchannel */ FREQ2FBIN(2472, 1),
+			/* Data[4].ctledges[3].bchannel */ FREQ2FBIN(2484, 1),
+		},
+
+		{
+			/* Data[5].ctledges[0].bchannel */ FREQ2FBIN(2412, 1),
+			/* Data[5].ctledges[1].bchannel */ FREQ2FBIN(2417, 1),
+			/* Data[5].ctledges[2].bchannel */ FREQ2FBIN(2472, 1),
+			0,
+		},
+
+		{
+			/* Data[6].ctledges[0].bchannel */ FREQ2FBIN(2412, 1),
+			/* Data[6].ctledges[1].bchannel */ FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2472, 1),
+			0,
+		},
+
+		{
+			/* Data[7].ctledges[0].bchannel */ FREQ2FBIN(2422, 1),
+			/* Data[7].ctledges[1].bchannel */ FREQ2FBIN(2427, 1),
+			/* Data[7].ctledges[2].bchannel */ FREQ2FBIN(2447, 1),
+			/* Data[7].ctledges[3].bchannel */ FREQ2FBIN(2462, 1),
+		},
+
+		{
+			/* Data[8].ctledges[0].bchannel */ FREQ2FBIN(2412, 1),
+			/* Data[8].ctledges[1].bchannel */ FREQ2FBIN(2417, 1),
+			/* Data[8].ctledges[2].bchannel */ FREQ2FBIN(2472, 1),
+		},
+
+		{
+			/* Data[9].ctledges[0].bchannel */ FREQ2FBIN(2412, 1),
+			/* Data[9].ctledges[1].bchannel */ FREQ2FBIN(2417, 1),
+			/* Data[9].ctledges[2].bchannel */ FREQ2FBIN(2472, 1),
+			0
+		},
+
+		{
+			/* Data[10].ctledges[0].bchannel */ FREQ2FBIN(2412, 1),
+			/* Data[10].ctledges[1].bchannel */ FREQ2FBIN(2417, 1),
+			/* Data[10].ctledges[2].bchannel */ FREQ2FBIN(2472, 1),
+			0
+		},
+
+		{
+			/* Data[11].ctledges[0].bchannel */ FREQ2FBIN(2422, 1),
+			/* Data[11].ctledges[1].bchannel */ FREQ2FBIN(2427, 1),
+			/* Data[11].ctledges[2].bchannel */ FREQ2FBIN(2447, 1),
+			/* Data[11].ctledges[3].bchannel */ FREQ2FBIN(2462, 1),
+		}
+	},
+	.ctlPowerData_2G = {
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		{ { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
+
+		{ { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+		{ { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+	},
+	.modalHeader5G = {
+		/* 4 idle,t1,t2,b (4 bits per setting) */
+		.antCtrlCommon = LE32(0x110),
+		/* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */
+		.antCtrlCommon2 = LE32(0x22222),
+		/* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */
+		.antCtrlChain = {
+			LE16(0x0), LE16(0x0), LE16(0x0),
+		},
+		/* xatten1DB 3 xatten1_db for ar9280 (0xa20c/b20c 5:0) */
+		.xatten1DB = {0x13, 0x19, 0x17},
+
+		/*
+		 * xatten1Margin[ar9300_max_chains]; 3 xatten1_margin
+		 * for merlin (0xa20c/b20c 16:12
+		 */
+		.xatten1Margin = {0x19, 0x19, 0x19},
+		.tempSlope = 70,
+		.voltSlope = 15,
+		/* spurChans spur channels in usual fbin coding format */
+		.spurChans = {0, 0, 0, 0, 0},
+		/* noiseFloorThreshch check if the register is per chain */
+		.noiseFloorThreshCh = {-1, 0, 0},
+		.ob = {3, 3, 3}, /* 3 chain */
+		.db_stage2 = {3, 3, 3}, /* 3 chain */
+		.db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
+		.db_stage4 = {3, 3, 3},	 /* don't exist for 2G */
+		.xpaBiasLvl = 0,
+		.txFrameToDataStart = 0x0e,
+		.txFrameToPaOn = 0x0e,
+		.txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+		.antennaGain = 0,
+		.switchSettling = 0x2d,
+		.adcDesiredSize = -30,
+		.txEndToXpaOff = 0,
+		.txEndToRxOn = 0x2,
+		.txFrameToXpaOn = 0xe,
+		.thresh62 = 28,
+		.papdRateMaskHt20 = LE32(0x0cf0e0e0),
+		.papdRateMaskHt40 = LE32(0x6cf0e0e0),
+		.futureModal = {
+			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		},
+	},
+	.base_ext2 = {
+		.tempSlopeLow = 72,
+		.tempSlopeHigh = 105,
+		.xatten1DBLow = {0x10, 0x14, 0x10},
+		.xatten1MarginLow = {0x19, 0x19 , 0x19},
+		.xatten1DBHigh = {0x1d, 0x20, 0x24},
+		.xatten1MarginHigh = {0x10, 0x10, 0x10}
+	},
+	.calFreqPier5G = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5220, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5600, 0),
+		FREQ2FBIN(5700, 0),
+		FREQ2FBIN(5785, 0)
+	},
+	.calPierData5G = {
+		{
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+		},
+		{
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+		},
+		{
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 0},
+		},
+
+	},
+	.calTarget_freqbin_5G = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5220, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5600, 0),
+		FREQ2FBIN(5725, 0),
+		FREQ2FBIN(5825, 0)
+	},
+	.calTarget_freqbin_5GHT20 = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5220, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5600, 0),
+		FREQ2FBIN(5725, 0),
+		FREQ2FBIN(5825, 0)
+	},
+	.calTarget_freqbin_5GHT40 = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5220, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5600, 0),
+		FREQ2FBIN(5725, 0),
+		FREQ2FBIN(5825, 0)
+	},
+	.calTargetPower5G = {
+		/* 6-24,36,48,54 */
+		{ {32, 32, 28, 26} },
+		{ {32, 32, 28, 26} },
+		{ {32, 32, 28, 26} },
+		{ {32, 32, 26, 24} },
+		{ {32, 32, 26, 24} },
+		{ {32, 32, 24, 22} },
+		{ {30, 30, 24, 22} },
+		{ {30, 30, 24, 22} },
+	},
+	.calTargetPower5GHT20 = {
+		/*
+		 * 0_8_16,1-3_9-11_17-19,
+		 * 4,5,6,7,12,13,14,15,20,21,22,23
+		 */
+		{ {32, 32, 32, 32, 28, 26, 32, 28, 26, 24, 24, 24, 22, 22} },
+		{ {32, 32, 32, 32, 28, 26, 32, 28, 26, 24, 24, 24, 22, 22} },
+		{ {32, 32, 32, 32, 28, 26, 32, 28, 26, 24, 24, 24, 22, 22} },
+		{ {32, 32, 32, 32, 28, 26, 32, 26, 24, 22, 22, 22, 20, 20} },
+		{ {32, 32, 32, 32, 28, 26, 32, 26, 24, 22, 20, 18, 16, 16} },
+		{ {32, 32, 32, 32, 28, 26, 32, 24, 20, 16, 18, 16, 14, 14} },
+		{ {30, 30, 30, 30, 28, 26, 30, 24, 20, 16, 18, 16, 14, 14} },
+		{ {30, 30, 30, 30, 28, 26, 30, 24, 20, 16, 18, 16, 14, 14} },
+	},
+	.calTargetPower5GHT40 =  {
+		/*
+		 * 0_8_16,1-3_9-11_17-19,
+		 * 4,5,6,7,12,13,14,15,20,21,22,23
+		 */
+		{ {32, 32, 32, 30, 28, 26, 30, 28, 26, 24, 24, 24, 22, 22} },
+		{ {32, 32, 32, 30, 28, 26, 30, 28, 26, 24, 24, 24, 22, 22} },
+		{ {32, 32, 32, 30, 28, 26, 30, 28, 26, 24, 24, 24, 22, 22} },
+		{ {32, 32, 32, 30, 28, 26, 30, 26, 24, 22, 22, 22, 20, 20} },
+		{ {32, 32, 32, 30, 28, 26, 30, 26, 24, 22, 20, 18, 16, 16} },
+		{ {32, 32, 32, 30, 28, 26, 30, 22, 20, 16, 18, 16, 14, 14} },
+		{ {30, 30, 30, 30, 28, 26, 30, 22, 20, 16, 18, 16, 14, 14} },
+		{ {30, 30, 30, 30, 28, 26, 30, 22, 20, 16, 18, 16, 14, 14} },
+	},
+	.ctlIndex_5G =  {
+		0x10, 0x16, 0x18, 0x40, 0x46,
+		0x48, 0x30, 0x36, 0x38
+	},
+	.ctl_freqbin_5G =  {
+		{
+			/* Data[0].ctledges[0].bchannel */ FREQ2FBIN(5180, 0),
+			/* Data[0].ctledges[1].bchannel */ FREQ2FBIN(5260, 0),
+			/* Data[0].ctledges[2].bchannel */ FREQ2FBIN(5280, 0),
+			/* Data[0].ctledges[3].bchannel */ FREQ2FBIN(5500, 0),
+			/* Data[0].ctledges[4].bchannel */ FREQ2FBIN(5600, 0),
+			/* Data[0].ctledges[5].bchannel */ FREQ2FBIN(5700, 0),
+			/* Data[0].ctledges[6].bchannel */ FREQ2FBIN(5745, 0),
+			/* Data[0].ctledges[7].bchannel */ FREQ2FBIN(5825, 0)
+		},
+		{
+			/* Data[1].ctledges[0].bchannel */ FREQ2FBIN(5180, 0),
+			/* Data[1].ctledges[1].bchannel */ FREQ2FBIN(5260, 0),
+			/* Data[1].ctledges[2].bchannel */ FREQ2FBIN(5280, 0),
+			/* Data[1].ctledges[3].bchannel */ FREQ2FBIN(5500, 0),
+			/* Data[1].ctledges[4].bchannel */ FREQ2FBIN(5520, 0),
+			/* Data[1].ctledges[5].bchannel */ FREQ2FBIN(5700, 0),
+			/* Data[1].ctledges[6].bchannel */ FREQ2FBIN(5745, 0),
+			/* Data[1].ctledges[7].bchannel */ FREQ2FBIN(5825, 0)
+		},
+
+		{
+			/* Data[2].ctledges[0].bchannel */ FREQ2FBIN(5190, 0),
+			/* Data[2].ctledges[1].bchannel */ FREQ2FBIN(5230, 0),
+			/* Data[2].ctledges[2].bchannel */ FREQ2FBIN(5270, 0),
+			/* Data[2].ctledges[3].bchannel */ FREQ2FBIN(5310, 0),
+			/* Data[2].ctledges[4].bchannel */ FREQ2FBIN(5510, 0),
+			/* Data[2].ctledges[5].bchannel */ FREQ2FBIN(5550, 0),
+			/* Data[2].ctledges[6].bchannel */ FREQ2FBIN(5670, 0),
+			/* Data[2].ctledges[7].bchannel */ FREQ2FBIN(5755, 0)
+		},
+
+		{
+			/* Data[3].ctledges[0].bchannel */ FREQ2FBIN(5180, 0),
+			/* Data[3].ctledges[1].bchannel */ FREQ2FBIN(5200, 0),
+			/* Data[3].ctledges[2].bchannel */ FREQ2FBIN(5260, 0),
+			/* Data[3].ctledges[3].bchannel */ FREQ2FBIN(5320, 0),
+			/* Data[3].ctledges[4].bchannel */ FREQ2FBIN(5500, 0),
+			/* Data[3].ctledges[5].bchannel */ FREQ2FBIN(5700, 0),
+			/* Data[3].ctledges[6].bchannel */ 0xFF,
+			/* Data[3].ctledges[7].bchannel */ 0xFF,
+		},
+
+		{
+			/* Data[4].ctledges[0].bchannel */ FREQ2FBIN(5180, 0),
+			/* Data[4].ctledges[1].bchannel */ FREQ2FBIN(5260, 0),
+			/* Data[4].ctledges[2].bchannel */ FREQ2FBIN(5500, 0),
+			/* Data[4].ctledges[3].bchannel */ FREQ2FBIN(5700, 0),
+			/* Data[4].ctledges[4].bchannel */ 0xFF,
+			/* Data[4].ctledges[5].bchannel */ 0xFF,
+			/* Data[4].ctledges[6].bchannel */ 0xFF,
+			/* Data[4].ctledges[7].bchannel */ 0xFF,
+		},
+
+		{
+			/* Data[5].ctledges[0].bchannel */ FREQ2FBIN(5190, 0),
+			/* Data[5].ctledges[1].bchannel */ FREQ2FBIN(5270, 0),
+			/* Data[5].ctledges[2].bchannel */ FREQ2FBIN(5310, 0),
+			/* Data[5].ctledges[3].bchannel */ FREQ2FBIN(5510, 0),
+			/* Data[5].ctledges[4].bchannel */ FREQ2FBIN(5590, 0),
+			/* Data[5].ctledges[5].bchannel */ FREQ2FBIN(5670, 0),
+			/* Data[5].ctledges[6].bchannel */ 0xFF,
+			/* Data[5].ctledges[7].bchannel */ 0xFF
+		},
+
+		{
+			/* Data[6].ctledges[0].bchannel */ FREQ2FBIN(5180, 0),
+			/* Data[6].ctledges[1].bchannel */ FREQ2FBIN(5200, 0),
+			/* Data[6].ctledges[2].bchannel */ FREQ2FBIN(5220, 0),
+			/* Data[6].ctledges[3].bchannel */ FREQ2FBIN(5260, 0),
+			/* Data[6].ctledges[4].bchannel */ FREQ2FBIN(5500, 0),
+			/* Data[6].ctledges[5].bchannel */ FREQ2FBIN(5600, 0),
+			/* Data[6].ctledges[6].bchannel */ FREQ2FBIN(5700, 0),
+			/* Data[6].ctledges[7].bchannel */ FREQ2FBIN(5745, 0)
+		},
+
+		{
+			/* Data[7].ctledges[0].bchannel */ FREQ2FBIN(5180, 0),
+			/* Data[7].ctledges[1].bchannel */ FREQ2FBIN(5260, 0),
+			/* Data[7].ctledges[2].bchannel */ FREQ2FBIN(5320, 0),
+			/* Data[7].ctledges[3].bchannel */ FREQ2FBIN(5500, 0),
+			/* Data[7].ctledges[4].bchannel */ FREQ2FBIN(5560, 0),
+			/* Data[7].ctledges[5].bchannel */ FREQ2FBIN(5700, 0),
+			/* Data[7].ctledges[6].bchannel */ FREQ2FBIN(5745, 0),
+			/* Data[7].ctledges[7].bchannel */ FREQ2FBIN(5825, 0)
+		},
+
+		{
+			/* Data[8].ctledges[0].bchannel */ FREQ2FBIN(5190, 0),
+			/* Data[8].ctledges[1].bchannel */ FREQ2FBIN(5230, 0),
+			/* Data[8].ctledges[2].bchannel */ FREQ2FBIN(5270, 0),
+			/* Data[8].ctledges[3].bchannel */ FREQ2FBIN(5510, 0),
+			/* Data[8].ctledges[4].bchannel */ FREQ2FBIN(5550, 0),
+			/* Data[8].ctledges[5].bchannel */ FREQ2FBIN(5670, 0),
+			/* Data[8].ctledges[6].bchannel */ FREQ2FBIN(5755, 0),
+			/* Data[8].ctledges[7].bchannel */ FREQ2FBIN(5795, 0)
+		}
+	},
+	.ctlPowerData_5G = {
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+			}
+		},
+		{
+			{
+				CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+				CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+				CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+			}
+		},
+	}
+};
+
+static const struct ar9300_eeprom ar9300_h116 = {
+	.eepromVersion = 2,
+	.templateVersion = 4,
+	.macAddr = {0x00, 0x03, 0x7f, 0x0, 0x0, 0x0},
+	.custData = {"h116-041-f0000"},
+	.baseEepHeader = {
+		.regDmn = { LE16(0), LE16(0x1f) },
+		.txrxMask =  0x33, /* 4 bits tx and 4 bits rx */
+		.opCapFlags = {
+			.opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A,
+			.eepMisc = 0,
+		},
+		.rfSilent = 0,
+		.blueToothOptions = 0,
+		.deviceCap = 0,
+		.deviceType = 5, /* takes lower byte in eeprom location */
+		.pwrTableOffset = AR9300_PWR_TABLE_OFFSET,
+		.params_for_tuning_caps = {0, 0},
+		.featureEnable = 0x0d,
+		 /*
+		  * bit0 - enable tx temp comp - disabled
+		  * bit1 - enable tx volt comp - disabled
+		  * bit2 - enable fastClock - enabled
+		  * bit3 - enable doubling - enabled
+		  * bit4 - enable internal regulator - disabled
+		  * bit5 - enable pa predistortion - disabled
+		  */
+		.miscConfiguration = 0, /* bit0 - turn down drivestrength */
+		.eepromWriteEnableGpio = 6,
+		.wlanDisableGpio = 0,
+		.wlanLedGpio = 8,
+		.rxBandSelectGpio = 0xff,
+		.txrxgain = 0x10,
+		.swreg = 0,
+	 },
+	.modalHeader2G = {
+	/* ar9300_modal_eep_header  2g */
+		/* 4 idle,t1,t2,b(4 bits per setting) */
+		.antCtrlCommon = LE32(0x110),
+		/* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
+		.antCtrlCommon2 = LE32(0x44444),
+
+		/*
+		 * antCtrlChain[AR9300_MAX_CHAINS]; 6 idle, t, r,
+		 * rx1, rx12, b (2 bits each)
+		 */
+		.antCtrlChain = { LE16(0x10), LE16(0x10), LE16(0x10) },
+
+		/*
+		 * xatten1DB[AR9300_MAX_CHAINS];  3 xatten1_db
+		 * for ar9280 (0xa20c/b20c 5:0)
+		 */
+		.xatten1DB = {0x1f, 0x1f, 0x1f},
+
+		/*
+		 * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+		 * for ar9280 (0xa20c/b20c 16:12
+		 */
+		.xatten1Margin = {0x12, 0x12, 0x12},
+		.tempSlope = 25,
+		.voltSlope = 0,
+
+		/*
+		 * spurChans[OSPREY_EEPROM_MODAL_SPURS]; spur
+		 * channels in usual fbin coding format
+		 */
+		.spurChans = {FREQ2FBIN(2464, 1), 0, 0, 0, 0},
+
+		/*
+		 * noiseFloorThreshCh[AR9300_MAX_CHAINS]; 3 Check
+		 * if the register is per chain
+		 */
+		.noiseFloorThreshCh = {-1, 0, 0},
+		.ob = {1, 1, 1},/* 3 chain */
+		.db_stage2 = {1, 1, 1}, /* 3 chain  */
+		.db_stage3 = {0, 0, 0},
+		.db_stage4 = {0, 0, 0},
+		.xpaBiasLvl = 0,
+		.txFrameToDataStart = 0x0e,
+		.txFrameToPaOn = 0x0e,
+		.txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+		.antennaGain = 0,
+		.switchSettling = 0x2c,
+		.adcDesiredSize = -30,
+		.txEndToXpaOff = 0,
+		.txEndToRxOn = 0x2,
+		.txFrameToXpaOn = 0xe,
+		.thresh62 = 28,
+		.papdRateMaskHt20 = LE32(0x0c80C080),
+		.papdRateMaskHt40 = LE32(0x0080C080),
+		.futureModal = {
+			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		},
+	 },
+	 .base_ext1 = {
+		.ant_div_control = 0,
+		.future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+	 },
+	.calFreqPier2G = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1),
+	 },
+	/* ar9300_cal_data_per_freq_op_loop 2g */
+	.calPierData2G = {
+		{ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+		{ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+		{ {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+	 },
+	.calTarget_freqbin_Cck = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2472, 1),
+	 },
+	.calTarget_freqbin_2G = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1)
+	 },
+	.calTarget_freqbin_2GHT20 = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1)
+	 },
+	.calTarget_freqbin_2GHT40 = {
+		FREQ2FBIN(2412, 1),
+		FREQ2FBIN(2437, 1),
+		FREQ2FBIN(2472, 1)
+	 },
+	.calTargetPowerCck = {
+		 /* 1L-5L,5S,11L,11S */
+		 { {34, 34, 34, 34} },
+		 { {34, 34, 34, 34} },
+	},
+	.calTargetPower2G = {
+		 /* 6-24,36,48,54 */
+		 { {34, 34, 32, 32} },
+		 { {34, 34, 32, 32} },
+		 { {34, 34, 32, 32} },
+	},
+	.calTargetPower2GHT20 = {
+		{ {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 0, 0, 0, 0} },
+		{ {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 0, 0, 0, 0} },
+		{ {32, 32, 32, 32, 32, 30, 32, 32, 30, 28, 0, 0, 0, 0} },
+	},
+	.calTargetPower2GHT40 = {
+		{ {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} },
+		{ {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} },
+		{ {30, 30, 30, 30, 30, 28, 30, 30, 28, 26, 0, 0, 0, 0} },
+	},
+	.ctlIndex_2G =  {
+		0x11, 0x12, 0x15, 0x17, 0x41, 0x42,
+		0x45, 0x47, 0x31, 0x32, 0x35, 0x37,
+	},
+	.ctl_freqbin_2G = {
+		{
+			FREQ2FBIN(2412, 1),
+			FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2457, 1),
+			FREQ2FBIN(2462, 1)
+		},
+		{
+			FREQ2FBIN(2412, 1),
+			FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2462, 1),
+			0xFF,
+		},
+
+		{
+			FREQ2FBIN(2412, 1),
+			FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2462, 1),
+			0xFF,
+		},
+		{
+			FREQ2FBIN(2422, 1),
+			FREQ2FBIN(2427, 1),
+			FREQ2FBIN(2447, 1),
+			FREQ2FBIN(2452, 1)
+		},
+
+		{
+			/* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			/* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(2484, 1),
+		},
+
+		{
+			/* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			0,
+		},
+
+		{
+			/* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			FREQ2FBIN(2472, 1),
+			0,
+		},
+
+		{
+			/* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+			/* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+			/* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+			/* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
+		},
+
+		{
+			/* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+		},
+
+		{
+			/* Data[9].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[9].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[9].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			0
+		},
+
+		{
+			/* Data[10].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+			/* Data[10].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+			/* Data[10].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+			0
+		},
+
+		{
+			/* Data[11].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+			/* Data[11].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+			/* Data[11].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+			/* Data[11].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
+		}
+	 },
+	.ctlPowerData_2G = {
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		 { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
+
+		 { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+		 { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+	 },
+	.modalHeader5G = {
+		/* 4 idle,t1,t2,b (4 bits per setting) */
+		.antCtrlCommon = LE32(0x220),
+		/* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */
+		.antCtrlCommon2 = LE32(0x44444),
+		 /* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */
+		.antCtrlChain = {
+			LE16(0x150), LE16(0x150), LE16(0x150),
+		},
+		 /* xatten1DB 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
+		.xatten1DB = {0x19, 0x19, 0x19},
+
+		/*
+		 * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+		 * for merlin (0xa20c/b20c 16:12
+		 */
+		.xatten1Margin = {0x14, 0x14, 0x14},
+		.tempSlope = 70,
+		.voltSlope = 0,
+		/* spurChans spur channels in usual fbin coding format */
+		.spurChans = {0, 0, 0, 0, 0},
+		/* noiseFloorThreshCh Check if the register is per chain */
+		.noiseFloorThreshCh = {-1, 0, 0},
+		.ob = {3, 3, 3}, /* 3 chain */
+		.db_stage2 = {3, 3, 3}, /* 3 chain */
+		.db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
+		.db_stage4 = {3, 3, 3},	 /* don't exist for 2G */
+		.xpaBiasLvl = 0,
+		.txFrameToDataStart = 0x0e,
+		.txFrameToPaOn = 0x0e,
+		.txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+		.antennaGain = 0,
+		.switchSettling = 0x2d,
+		.adcDesiredSize = -30,
+		.txEndToXpaOff = 0,
+		.txEndToRxOn = 0x2,
+		.txFrameToXpaOn = 0xe,
+		.thresh62 = 28,
+		.papdRateMaskHt20 = LE32(0x0cf0e0e0),
+		.papdRateMaskHt40 = LE32(0x6cf0e0e0),
+		.futureModal = {
+			0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		},
+	 },
+	.base_ext2 = {
+		.tempSlopeLow = 35,
+		.tempSlopeHigh = 50,
+		.xatten1DBLow = {0, 0, 0},
+		.xatten1MarginLow = {0, 0, 0},
+		.xatten1DBHigh = {0, 0, 0},
+		.xatten1MarginHigh = {0, 0, 0}
+	 },
+	.calFreqPier5G = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5220, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5600, 0),
+		FREQ2FBIN(5700, 0),
+		FREQ2FBIN(5785, 0)
+	},
+	.calPierData5G = {
+			{
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+			},
+			{
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+			},
+			{
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+				{0, 0, 0, 0, 0, 0},
+			},
+
+	},
+	.calTarget_freqbin_5G = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5240, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5600, 0),
+		FREQ2FBIN(5700, 0),
+		FREQ2FBIN(5825, 0)
+	},
+	.calTarget_freqbin_5GHT20 = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5240, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5700, 0),
+		FREQ2FBIN(5745, 0),
+		FREQ2FBIN(5825, 0)
+	},
+	.calTarget_freqbin_5GHT40 = {
+		FREQ2FBIN(5180, 0),
+		FREQ2FBIN(5240, 0),
+		FREQ2FBIN(5320, 0),
+		FREQ2FBIN(5400, 0),
+		FREQ2FBIN(5500, 0),
+		FREQ2FBIN(5700, 0),
+		FREQ2FBIN(5745, 0),
+		FREQ2FBIN(5825, 0)
+	 },
+	.calTargetPower5G = {
+		/* 6-24,36,48,54 */
+		{ {30, 30, 28, 24} },
+		{ {30, 30, 28, 24} },
+		{ {30, 30, 28, 24} },
+		{ {30, 30, 28, 24} },
+		{ {30, 30, 28, 24} },
+		{ {30, 30, 28, 24} },
+		{ {30, 30, 28, 24} },
+		{ {30, 30, 28, 24} },
+	 },
+	.calTargetPower5GHT20 = {
+		/*
+		 * 0_8_16,1-3_9-11_17-19,
+		 * 4,5,6,7,12,13,14,15,20,21,22,23
+		 */
+		{ {30, 30, 30, 28, 24, 20, 30, 28, 24, 20, 0, 0, 0, 0} },
+		{ {30, 30, 30, 28, 24, 20, 30, 28, 24, 20, 0, 0, 0, 0} },
+		{ {30, 30, 30, 26, 22, 18, 30, 26, 22, 18, 0, 0, 0, 0} },
+		{ {30, 30, 30, 26, 22, 18, 30, 26, 22, 18, 0, 0, 0, 0} },
+		{ {30, 30, 30, 24, 20, 16, 30, 24, 20, 16, 0, 0, 0, 0} },
+		{ {30, 30, 30, 24, 20, 16, 30, 24, 20, 16, 0, 0, 0, 0} },
+		{ {30, 30, 30, 22, 18, 14, 30, 22, 18, 14, 0, 0, 0, 0} },
+		{ {30, 30, 30, 22, 18, 14, 30, 22, 18, 14, 0, 0, 0, 0} },
+	 },
+	.calTargetPower5GHT40 =  {
+		/*
+		 * 0_8_16,1-3_9-11_17-19,
+		 * 4,5,6,7,12,13,14,15,20,21,22,23
+		 */
+		{ {28, 28, 28, 26, 22, 18, 28, 26, 22, 18, 0, 0, 0, 0} },
+		{ {28, 28, 28, 26, 22, 18, 28, 26, 22, 18, 0, 0, 0, 0} },
+		{ {28, 28, 28, 24, 20, 16, 28, 24, 20, 16, 0, 0, 0, 0} },
+		{ {28, 28, 28, 24, 20, 16, 28, 24, 20, 16, 0, 0, 0, 0} },
+		{ {28, 28, 28, 22, 18, 14, 28, 22, 18, 14, 0, 0, 0, 0} },
+		{ {28, 28, 28, 22, 18, 14, 28, 22, 18, 14, 0, 0, 0, 0} },
+		{ {28, 28, 28, 20, 16, 12, 28, 20, 16, 12, 0, 0, 0, 0} },
+		{ {28, 28, 28, 20, 16, 12, 28, 20, 16, 12, 0, 0, 0, 0} },
+	 },
+	.ctlIndex_5G =  {
+		0x10, 0x16, 0x18, 0x40, 0x46,
+		0x48, 0x30, 0x36, 0x38
+	},
+	.ctl_freqbin_5G =  {
+		{
+			/* Data[0].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[0].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[0].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+			/* Data[0].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[0].ctlEdges[4].bChannel */ FREQ2FBIN(5600, 0),
+			/* Data[0].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[0].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+			/* Data[0].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+		},
+		{
+			/* Data[1].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[1].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[1].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+			/* Data[1].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[1].ctlEdges[4].bChannel */ FREQ2FBIN(5520, 0),
+			/* Data[1].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[1].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+			/* Data[1].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+		},
+
+		{
+			/* Data[2].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+			/* Data[2].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+			/* Data[2].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+			/* Data[2].ctlEdges[3].bChannel */ FREQ2FBIN(5310, 0),
+			/* Data[2].ctlEdges[4].bChannel */ FREQ2FBIN(5510, 0),
+			/* Data[2].ctlEdges[5].bChannel */ FREQ2FBIN(5550, 0),
+			/* Data[2].ctlEdges[6].bChannel */ FREQ2FBIN(5670, 0),
+			/* Data[2].ctlEdges[7].bChannel */ FREQ2FBIN(5755, 0)
+		},
+
+		{
+			/* Data[3].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[3].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+			/* Data[3].ctlEdges[2].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[3].ctlEdges[3].bChannel */ FREQ2FBIN(5320, 0),
+			/* Data[3].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[3].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[3].ctlEdges[6].bChannel */ 0xFF,
+			/* Data[3].ctlEdges[7].bChannel */ 0xFF,
+		},
+
+		{
+			/* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[4].ctlEdges[4].bChannel */ 0xFF,
+			/* Data[4].ctlEdges[5].bChannel */ 0xFF,
+			/* Data[4].ctlEdges[6].bChannel */ 0xFF,
+			/* Data[4].ctlEdges[7].bChannel */ 0xFF,
+		},
+
+		{
+			/* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+			/* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(5270, 0),
+			/* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(5310, 0),
+			/* Data[5].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+			/* Data[5].ctlEdges[4].bChannel */ FREQ2FBIN(5590, 0),
+			/* Data[5].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+			/* Data[5].ctlEdges[6].bChannel */ 0xFF,
+			/* Data[5].ctlEdges[7].bChannel */ 0xFF
+		},
+
+		{
+			/* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+			/* Data[6].ctlEdges[2].bChannel */ FREQ2FBIN(5220, 0),
+			/* Data[6].ctlEdges[3].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[6].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[6].ctlEdges[5].bChannel */ FREQ2FBIN(5600, 0),
+			/* Data[6].ctlEdges[6].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[6].ctlEdges[7].bChannel */ FREQ2FBIN(5745, 0)
+		},
+
+		{
+			/* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+			/* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+			/* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(5320, 0),
+			/* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+			/* Data[7].ctlEdges[4].bChannel */ FREQ2FBIN(5560, 0),
+			/* Data[7].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+			/* Data[7].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+			/* Data[7].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+		},
+
+		{
+			/* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+			/* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+			/* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+			/* Data[8].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+			/* Data[8].ctlEdges[4].bChannel */ FREQ2FBIN(5550, 0),
+			/* Data[8].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+			/* Data[8].ctlEdges[6].bChannel */ FREQ2FBIN(5755, 0),
+			/* Data[8].ctlEdges[7].bChannel */ FREQ2FBIN(5795, 0)
+		}
+	 },
+	.ctlPowerData_5G = {
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+			}
+		},
+		{
+			{
+				CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+				CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+				CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+			}
+		},
+		{
+			{
+				CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+				CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+			}
+		},
+	 }
+};
+
+
+static const struct ar9300_eeprom *ar9300_eep_templates[] = {
+	&ar9300_default,
+	&ar9300_x112,
+	&ar9300_h116,
+	&ar9300_h112,
+	&ar9300_x113,
+};
+
+static const struct ar9300_eeprom *ar9003_eeprom_struct_find_by_id(int id)
+{
+#define N_LOOP (sizeof(ar9300_eep_templates) / sizeof(ar9300_eep_templates[0]))
+	unsigned int it;
+
+	for (it = 0; it < N_LOOP; it++)
+		if (ar9300_eep_templates[it]->templateVersion == id)
+			return ar9300_eep_templates[it];
+	return NULL;
+#undef N_LOOP
+}
+
+
+static u16 ath9k_hw_fbin2freq(u8 fbin, int is2GHz)
+{
+	if (fbin == AR5416_BCHAN_UNUSED)
+		return fbin;
+
+	return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
+}
+
+static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah __unused)
+{
+	return 0;
+}
+
+static int interpolate(int x, int xa, int xb, int ya, int yb)
+{
+	int bf, factor, plus;
+
+	bf = 2 * (yb - ya) * (x - xa) / (xb - xa);
+	factor = bf / 2;
+	plus = bf % 2;
+	return ya + factor + plus;
+}
+
+static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
+				      enum eeprom_param param)
+{
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	struct ar9300_base_eep_hdr *pBase = &eep->baseEepHeader;
+
+	switch (param) {
+	case EEP_MAC_LSW:
+		return eep->macAddr[0] << 8 | eep->macAddr[1];
+	case EEP_MAC_MID:
+		return eep->macAddr[2] << 8 | eep->macAddr[3];
+	case EEP_MAC_MSW:
+		return eep->macAddr[4] << 8 | eep->macAddr[5];
+	case EEP_REG_0:
+		return (uint16_t)(pBase->regDmn[0]);
+	case EEP_REG_1:
+		return (uint16_t)(pBase->regDmn[1]);
+	case EEP_OP_CAP:
+		return pBase->deviceCap;
+	case EEP_OP_MODE:
+		return pBase->opCapFlags.opFlags;
+	case EEP_RF_SILENT:
+		return pBase->rfSilent;
+	case EEP_TX_MASK:
+		return (pBase->txrxMask >> 4) & 0xf;
+	case EEP_RX_MASK:
+		return pBase->txrxMask & 0xf;
+	case EEP_DRIVE_STRENGTH:
+#define AR9300_EEP_BASE_DRIV_STRENGTH	0x1
+		return pBase->miscConfiguration & AR9300_EEP_BASE_DRIV_STRENGTH;
+	case EEP_INTERNAL_REGULATOR:
+		/* Bit 4 is internal regulator flag */
+		return (pBase->featureEnable & 0x10) >> 4;
+	case EEP_SWREG:
+		return (uint32_t)(pBase->swreg);
+	case EEP_PAPRD:
+		return !!(pBase->featureEnable & BIT(5));
+	case EEP_CHAIN_MASK_REDUCE:
+		return (pBase->miscConfiguration >> 0x3) & 0x1;
+	case EEP_ANT_DIV_CTL1:
+		return (uint32_t)(eep->base_ext1.ant_div_control);
+	default:
+		return 0;
+	}
+}
+
+static int ar9300_eeprom_read_byte(struct ath_common *common, int address,
+				    u8 *buffer)
+{
+	u16 val;
+
+	if (!ath9k_hw_nvram_read(common, address / 2, &val))
+		return 0;
+
+	*buffer = (val >> (8 * (address % 2))) & 0xff;
+	return 1;
+}
+
+static int ar9300_eeprom_read_word(struct ath_common *common, int address,
+				    u8 *buffer)
+{
+	u16 val;
+
+	if (!ath9k_hw_nvram_read(common, address / 2, &val))
+		return 0;
+
+	buffer[0] = val >> 8;
+	buffer[1] = val & 0xff;
+
+	return 1;
+}
+
+static int ar9300_read_eeprom(struct ath_hw *ah, int address, u8 *buffer,
+			       int count)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	int i;
+
+	if ((address < 0) || ((address + count) / 2 > AR9300_EEPROM_SIZE - 1)) {
+		DBG("ath9k: "
+			"eeprom address not in range\n");
+		return 0;
+	}
+
+	/*
+	 * Since we're reading the bytes in reverse order from a little-endian
+	 * word stream, an even address means we only use the lower half of
+	 * the 16-bit word at that address
+	 */
+	if (address % 2 == 0) {
+		if (!ar9300_eeprom_read_byte(common, address--, buffer++))
+			goto error;
+
+		count--;
+	}
+
+	for (i = 0; i < count / 2; i++) {
+		if (!ar9300_eeprom_read_word(common, address, buffer))
+			goto error;
+
+		address -= 2;
+		buffer += 2;
+	}
+
+	if (count % 2)
+		if (!ar9300_eeprom_read_byte(common, address, buffer))
+			goto error;
+
+	return 1;
+
+error:
+	DBG("ath9k: "
+		"unable to read eeprom region at offset %d\n", address);
+	return 0;
+}
+
+static int ar9300_otp_read_word(struct ath_hw *ah, int addr, u32 *data)
+{
+	REG_READ(ah, AR9300_OTP_BASE + (4 * addr));
+
+	if (!ath9k_hw_wait(ah, AR9300_OTP_STATUS, AR9300_OTP_STATUS_TYPE,
+			   AR9300_OTP_STATUS_VALID, 1000))
+		return 0;
+
+	*data = REG_READ(ah, AR9300_OTP_READ_DATA);
+	return 1;
+}
+
+static int ar9300_read_otp(struct ath_hw *ah, int address, u8 *buffer,
+			    int count)
+{
+	u32 data;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		int offset = 8 * ((address - i) % 4);
+		if (!ar9300_otp_read_word(ah, (address - i) / 4, &data))
+			return 0;
+
+		buffer[i] = (data >> offset) & 0xff;
+	}
+
+	return 1;
+}
+
+
+static void ar9300_comp_hdr_unpack(u8 *best, int *code, int *reference,
+				   int *length, int *major, int *minor)
+{
+	unsigned long value[4];
+
+	value[0] = best[0];
+	value[1] = best[1];
+	value[2] = best[2];
+	value[3] = best[3];
+	*code = ((value[0] >> 5) & 0x0007);
+	*reference = (value[0] & 0x001f) | ((value[1] >> 2) & 0x0020);
+	*length = ((value[1] << 4) & 0x07f0) | ((value[2] >> 4) & 0x000f);
+	*major = (value[2] & 0x000f);
+	*minor = (value[3] & 0x00ff);
+}
+
+static u16 ar9300_comp_cksum(u8 *data, int dsize)
+{
+	int it, checksum = 0;
+
+	for (it = 0; it < dsize; it++) {
+		checksum += data[it];
+		checksum &= 0xffff;
+	}
+
+	return checksum;
+}
+
+static int ar9300_uncompress_block(struct ath_hw *ah __unused,
+				    u8 *mptr,
+				    int mdataSize,
+				    u8 *block,
+				    int size)
+{
+	int it;
+	int spot;
+	int offset;
+	int length;
+
+	spot = 0;
+
+	for (it = 0; it < size; it += (length+2)) {
+		offset = block[it];
+		offset &= 0xff;
+		spot += offset;
+		length = block[it+1];
+		length &= 0xff;
+
+		if (length > 0 && spot >= 0 && spot+length <= mdataSize) {
+			DBG2("ath9k: "
+				"Restore at %d: spot=%d offset=%d length=%d\n",
+				it, spot, offset, length);
+			memcpy(&mptr[spot], &block[it+2], length);
+			spot += length;
+		} else if (length > 0) {
+			DBG("ath9k: "
+				"Bad restore at %d: spot=%d offset=%d length=%d\n",
+				it, spot, offset, length);
+			return 0;
+		}
+	}
+	return 1;
+}
+
+static int ar9300_compress_decision(struct ath_hw *ah,
+				    int it,
+				    int code,
+				    int reference,
+				    u8 *mptr,
+				    u8 *word, int length, int mdata_size)
+{
+	const struct ar9300_eeprom *eep = NULL;
+
+	switch (code) {
+	case _CompressNone:
+		if (length != mdata_size) {
+			DBG("ath9k: "
+				"EEPROM structure size mismatch memory=%d eeprom=%d\n",
+				mdata_size, length);
+			return -1;
+		}
+		memcpy(mptr, (u8 *) (word + COMP_HDR_LEN), length);
+		DBG2("ath9k: "
+			"restored eeprom %d: uncompressed, length %d\n",
+			it, length);
+		break;
+	case _CompressBlock:
+		if (reference == 0) {
+		} else {
+			eep = ar9003_eeprom_struct_find_by_id(reference);
+			if (eep == NULL) {
+				DBG("ath9k: "
+					"can't find reference eeprom struct %d\n",
+					reference);
+				return -1;
+			}
+			memcpy(mptr, eep, mdata_size);
+		}
+		DBG2("ath9k: "
+			"restore eeprom %d: block, reference %d, length %d\n",
+			it, reference, length);
+		ar9300_uncompress_block(ah, mptr, mdata_size,
+					(u8 *) (word + COMP_HDR_LEN), length);
+		break;
+	default:
+		DBG("ath9k: "
+			"unknown compression code %d\n", code);
+		return -1;
+	}
+	return 0;
+}
+
+typedef int (*eeprom_read_op)(struct ath_hw *ah, int address, u8 *buffer,
+			       int count);
+
+static int ar9300_check_header(void *data)
+{
+	u32 *word = data;
+	return !(*word == 0 || *word == (unsigned int)~0);
+}
+
+static int ar9300_check_eeprom_header(struct ath_hw *ah, eeprom_read_op read,
+				       int base_addr)
+{
+	u8 header[4];
+
+	if (!read(ah, base_addr, header, 4))
+		return 0;
+
+	return ar9300_check_header(header);
+}
+
+static int ar9300_eeprom_restore_flash(struct ath_hw *ah, u8 *mptr,
+				       int mdata_size)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	u16 *data = (u16 *) mptr;
+	int i;
+
+	for (i = 0; i < mdata_size / 2; i++, data++)
+		ath9k_hw_nvram_read(common, i, data);
+
+	return 0;
+}
+/*
+ * Read the configuration data from the eeprom.
+ * The data can be put in any specified memory buffer.
+ *
+ * Returns -1 on error.
+ * Returns address of next memory location on success.
+ */
+static int ar9300_eeprom_restore_internal(struct ath_hw *ah,
+					  u8 *mptr, int mdata_size)
+{
+#define MDEFAULT 15
+#define MSTATE 100
+	int cptr;
+	u8 *word;
+	int code;
+	int reference, length, major, minor;
+	int osize;
+	int it;
+	u16 checksum, mchecksum;
+	eeprom_read_op read;
+
+	if (ath9k_hw_use_flash(ah))
+		return ar9300_eeprom_restore_flash(ah, mptr, mdata_size);
+
+	word = zalloc(2048);
+	if (!word)
+		return -1;
+
+	memcpy(mptr, &ar9300_default, mdata_size);
+
+	read = ar9300_read_eeprom;
+	if (AR_SREV_9485(ah))
+		cptr = AR9300_BASE_ADDR_4K;
+	else
+		cptr = AR9300_BASE_ADDR;
+	DBG2("ath9k: "
+		"Trying EEPROM access at Address 0x%04x\n", cptr);
+	if (ar9300_check_eeprom_header(ah, read, cptr))
+		goto found;
+
+	cptr = AR9300_BASE_ADDR_512;
+	DBG2("ath9k: "
+		"Trying EEPROM access at Address 0x%04x\n", cptr);
+	if (ar9300_check_eeprom_header(ah, read, cptr))
+		goto found;
+
+	read = ar9300_read_otp;
+	cptr = AR9300_BASE_ADDR;
+	DBG2("ath9k: "
+		"Trying OTP access at Address 0x%04x\n", cptr);
+	if (ar9300_check_eeprom_header(ah, read, cptr))
+		goto found;
+
+	cptr = AR9300_BASE_ADDR_512;
+	DBG2("ath9k: "
+		"Trying OTP access at Address 0x%04x\n", cptr);
+	if (ar9300_check_eeprom_header(ah, read, cptr))
+		goto found;
+
+	goto fail;
+
+found:
+	DBG2("ath9k: Found valid EEPROM data\n");
+
+	for (it = 0; it < MSTATE; it++) {
+		if (!read(ah, cptr, word, COMP_HDR_LEN))
+			goto fail;
+
+		if (!ar9300_check_header(word))
+			break;
+
+		ar9300_comp_hdr_unpack(word, &code, &reference,
+				       &length, &major, &minor);
+		DBG2("ath9k: "
+			"Found block at %x: code=%d ref=%d length=%d major=%d minor=%d\n",
+			cptr, code, reference, length, major, minor);
+		if ((!AR_SREV_9485(ah) && length >= 1024) ||
+		    (AR_SREV_9485(ah) && length > EEPROM_DATA_LEN_9485)) {
+			DBG2("ath9k: "
+				"Skipping bad header\n");
+			cptr -= COMP_HDR_LEN;
+			continue;
+		}
+
+		osize = length;
+		read(ah, cptr, word, COMP_HDR_LEN + osize + COMP_CKSUM_LEN);
+		checksum = ar9300_comp_cksum(&word[COMP_HDR_LEN], length);
+		mchecksum = word[COMP_HDR_LEN + osize] |
+		    (word[COMP_HDR_LEN + osize + 1] << 8);
+		DBG2("ath9k: "
+			"checksum %x %x\n", checksum, mchecksum);
+		if (checksum == mchecksum) {
+			ar9300_compress_decision(ah, it, code, reference, mptr,
+						 word, length, mdata_size);
+		} else {
+			DBG2("ath9k: "
+				"skipping block with bad checksum\n");
+		}
+		cptr -= (COMP_HDR_LEN + osize + COMP_CKSUM_LEN);
+	}
+
+	free(word);
+	return cptr;
+
+fail:
+	free(word);
+	return -1;
+}
+
+/*
+ * Restore the configuration structure by reading the eeprom.
+ * This function destroys any existing in-memory structure
+ * content.
+ */
+static int ath9k_hw_ar9300_fill_eeprom(struct ath_hw *ah)
+{
+	u8 *mptr = (u8 *) &ah->eeprom.ar9300_eep;
+
+	if (ar9300_eeprom_restore_internal(ah, mptr,
+			sizeof(struct ar9300_eeprom)) < 0)
+		return 0;
+
+	return 1;
+}
+
+/* XXX: review hardware docs */
+static int ath9k_hw_ar9300_get_eeprom_ver(struct ath_hw *ah)
+{
+	return ah->eeprom.ar9300_eep.eepromVersion;
+}
+
+/* XXX: could be read from the eepromVersion, not sure yet */
+static int ath9k_hw_ar9300_get_eeprom_rev(struct ath_hw *ah __unused)
+{
+	return 0;
+}
+
+static s32 ar9003_hw_xpa_bias_level_get(struct ath_hw *ah, int is2ghz)
+{
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+	if (is2ghz)
+		return eep->modalHeader2G.xpaBiasLvl;
+	else
+		return eep->modalHeader5G.xpaBiasLvl;
+}
+
+static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, int is2ghz)
+{
+	int bias = ar9003_hw_xpa_bias_level_get(ah, is2ghz);
+
+	if (AR_SREV_9485(ah) || AR_SREV_9340(ah))
+		REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias);
+	else {
+		REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias);
+		REG_RMW_FIELD(ah, AR_CH0_THERM,
+				AR_CH0_THERM_XPABIASLVL_MSB,
+				bias >> 2);
+		REG_RMW_FIELD(ah, AR_CH0_THERM,
+				AR_CH0_THERM_XPASHORT2GND, 1);
+	}
+}
+
+static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, int is2ghz)
+{
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	uint32_t val;
+
+	if (is2ghz)
+		val = eep->modalHeader2G.antCtrlCommon;
+	else
+		val = eep->modalHeader5G.antCtrlCommon;
+	return (uint32_t)(val);
+}
+
+static u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, int is2ghz)
+{
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	uint32_t val;
+
+	if (is2ghz)
+		val = eep->modalHeader2G.antCtrlCommon2;
+	else
+		val = eep->modalHeader5G.antCtrlCommon2;
+	return (uint32_t)(val);
+}
+
+static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah,
+					int chain,
+					int is2ghz)
+{
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	uint16_t val = 0;
+
+	if (chain >= 0 && chain < AR9300_MAX_CHAINS) {
+		if (is2ghz)
+			val = eep->modalHeader2G.antCtrlChain[chain];
+		else
+			val = eep->modalHeader5G.antCtrlChain[chain];
+	}
+
+	return (uint16_t)(val);
+}
+
+static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, int is2ghz)
+{
+	int chain;
+	u32 regval;
+	u32 ant_div_ctl1;
+	static const u32 switch_chain_reg[AR9300_MAX_CHAINS] = {
+			AR_PHY_SWITCH_CHAIN_0,
+			AR_PHY_SWITCH_CHAIN_1,
+			AR_PHY_SWITCH_CHAIN_2,
+	};
+
+	u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz);
+
+	REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_ALL, value);
+
+	value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz);
+	REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value);
+
+	for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+		if ((ah->rxchainmask & BIT(chain)) ||
+		    (ah->txchainmask & BIT(chain))) {
+			value = ar9003_hw_ant_ctrl_chain_get(ah, chain,
+							     is2ghz);
+			REG_RMW_FIELD(ah, switch_chain_reg[chain],
+				      AR_SWITCH_TABLE_ALL, value);
+		}
+	}
+
+	if (AR_SREV_9485(ah)) {
+		value = ath9k_hw_ar9300_get_eeprom(ah, EEP_ANT_DIV_CTL1);
+		/*
+		 * main_lnaconf, alt_lnaconf, main_tb, alt_tb
+		 * are the fields present
+		 */
+		regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
+		regval &= (~AR_ANT_DIV_CTRL_ALL);
+		regval |= (value & 0x3f) << AR_ANT_DIV_CTRL_ALL_S;
+		/* enable_lnadiv */
+		regval &= (~AR_PHY_9485_ANT_DIV_LNADIV);
+		regval |= ((value >> 6) & 0x1) <<
+				AR_PHY_9485_ANT_DIV_LNADIV_S;
+		REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
+
+		/*enable fast_div */
+		regval = REG_READ(ah, AR_PHY_CCK_DETECT);
+		regval &= (~AR_FAST_DIV_ENABLE);
+		regval |= ((value >> 7) & 0x1) <<
+				AR_FAST_DIV_ENABLE_S;
+		REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
+		ant_div_ctl1 =
+			ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
+		/* check whether antenna diversity is enabled */
+		if ((ant_div_ctl1 >> 0x6) == 0x3) {
+			regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
+			/*
+			 * clear bits 25-30 main_lnaconf, alt_lnaconf,
+			 * main_tb, alt_tb
+			 */
+			regval &= (~(AR_PHY_9485_ANT_DIV_MAIN_LNACONF |
+					AR_PHY_9485_ANT_DIV_ALT_LNACONF |
+					AR_PHY_9485_ANT_DIV_ALT_GAINTB |
+					AR_PHY_9485_ANT_DIV_MAIN_GAINTB));
+			/* by default use LNA1 for the main antenna */
+			regval |= (AR_PHY_9485_ANT_DIV_LNA1 <<
+					AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S);
+			regval |= (AR_PHY_9485_ANT_DIV_LNA2 <<
+					AR_PHY_9485_ANT_DIV_ALT_LNACONF_S);
+			REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
+		}
+
+
+	}
+
+}
+
+static void ar9003_hw_drive_strength_apply(struct ath_hw *ah)
+{
+	int drive_strength;
+	unsigned long reg;
+
+	drive_strength = ath9k_hw_ar9300_get_eeprom(ah, EEP_DRIVE_STRENGTH);
+
+	if (!drive_strength)
+		return;
+
+	reg = REG_READ(ah, AR_PHY_65NM_CH0_BIAS1);
+	reg &= ~0x00ffffc0;
+	reg |= 0x5 << 21;
+	reg |= 0x5 << 18;
+	reg |= 0x5 << 15;
+	reg |= 0x5 << 12;
+	reg |= 0x5 << 9;
+	reg |= 0x5 << 6;
+	REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS1, reg);
+
+	reg = REG_READ(ah, AR_PHY_65NM_CH0_BIAS2);
+	reg &= ~0xffffffe0;
+	reg |= 0x5 << 29;
+	reg |= 0x5 << 26;
+	reg |= 0x5 << 23;
+	reg |= 0x5 << 20;
+	reg |= 0x5 << 17;
+	reg |= 0x5 << 14;
+	reg |= 0x5 << 11;
+	reg |= 0x5 << 8;
+	reg |= 0x5 << 5;
+	REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS2, reg);
+
+	reg = REG_READ(ah, AR_PHY_65NM_CH0_BIAS4);
+	reg &= ~0xff800000;
+	reg |= 0x5 << 29;
+	reg |= 0x5 << 26;
+	reg |= 0x5 << 23;
+	REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS4, reg);
+}
+
+static u16 ar9003_hw_atten_chain_get(struct ath_hw *ah, int chain,
+				     struct ath9k_channel *chan)
+{
+	int f[3], t[3];
+	u16 value;
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+	if (chain >= 0 && chain < 3) {
+		if (IS_CHAN_2GHZ(chan))
+			return eep->modalHeader2G.xatten1DB[chain];
+		else if (eep->base_ext2.xatten1DBLow[chain] != 0) {
+			t[0] = eep->base_ext2.xatten1DBLow[chain];
+			f[0] = 5180;
+			t[1] = eep->modalHeader5G.xatten1DB[chain];
+			f[1] = 5500;
+			t[2] = eep->base_ext2.xatten1DBHigh[chain];
+			f[2] = 5785;
+			value = ar9003_hw_power_interpolate((s32) chan->channel,
+							    f, t, 3);
+			return value;
+		} else
+			return eep->modalHeader5G.xatten1DB[chain];
+	}
+
+	return 0;
+}
+
+
+static u16 ar9003_hw_atten_chain_get_margin(struct ath_hw *ah, int chain,
+					    struct ath9k_channel *chan)
+{
+	int f[3], t[3];
+	u16 value;
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+	if (chain >= 0 && chain < 3) {
+		if (IS_CHAN_2GHZ(chan))
+			return eep->modalHeader2G.xatten1Margin[chain];
+		else if (eep->base_ext2.xatten1MarginLow[chain] != 0) {
+			t[0] = eep->base_ext2.xatten1MarginLow[chain];
+			f[0] = 5180;
+			t[1] = eep->modalHeader5G.xatten1Margin[chain];
+			f[1] = 5500;
+			t[2] = eep->base_ext2.xatten1MarginHigh[chain];
+			f[2] = 5785;
+			value = ar9003_hw_power_interpolate((s32) chan->channel,
+							    f, t, 3);
+			return value;
+		} else
+			return eep->modalHeader5G.xatten1Margin[chain];
+	}
+
+	return 0;
+}
+
+static void ar9003_hw_atten_apply(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+	int i;
+	u16 value;
+	unsigned long ext_atten_reg[3] = {AR_PHY_EXT_ATTEN_CTL_0,
+					  AR_PHY_EXT_ATTEN_CTL_1,
+					  AR_PHY_EXT_ATTEN_CTL_2,
+					 };
+
+	/* Test value. if 0 then attenuation is unused. Don't load anything. */
+	for (i = 0; i < 3; i++) {
+		if (ah->txchainmask & BIT(i)) {
+			value = ar9003_hw_atten_chain_get(ah, i, chan);
+			REG_RMW_FIELD(ah, ext_atten_reg[i],
+				      AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
+
+			value = ar9003_hw_atten_chain_get_margin(ah, i, chan);
+			REG_RMW_FIELD(ah, ext_atten_reg[i],
+				      AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN,
+				      value);
+		}
+	}
+}
+
+static int is_pmu_set(struct ath_hw *ah, u32 pmu_reg, int pmu_set)
+{
+	int timeout = 100;
+
+	while ((unsigned int)pmu_set != REG_READ(ah, pmu_reg)) {
+		if (timeout-- == 0)
+			return 0;
+		REG_WRITE(ah, pmu_reg, pmu_set);
+		udelay(10);
+	}
+
+	return 1;
+}
+
+static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah)
+{
+	int internal_regulator =
+		ath9k_hw_ar9300_get_eeprom(ah, EEP_INTERNAL_REGULATOR);
+
+	if (internal_regulator) {
+		if (AR_SREV_9485(ah)) {
+			int reg_pmu_set;
+
+			reg_pmu_set = REG_READ(ah, AR_PHY_PMU2) & ~AR_PHY_PMU2_PGM;
+			REG_WRITE(ah, AR_PHY_PMU2, reg_pmu_set);
+			if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set))
+				return;
+
+			reg_pmu_set = (5 << 1) | (7 << 4) | (1 << 8) |
+				      (2 << 14) | (6 << 17) | (1 << 20) |
+				      (3 << 24) | (1 << 28);
+
+			REG_WRITE(ah, AR_PHY_PMU1, reg_pmu_set);
+			if (!is_pmu_set(ah, AR_PHY_PMU1, reg_pmu_set))
+				return;
+
+			reg_pmu_set = (REG_READ(ah, AR_PHY_PMU2) & ~0xFFC00000)
+					| (4 << 26);
+			REG_WRITE(ah, AR_PHY_PMU2, reg_pmu_set);
+			if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set))
+				return;
+
+			reg_pmu_set = (REG_READ(ah, AR_PHY_PMU2) & ~0x00200000)
+					| (1 << 21);
+			REG_WRITE(ah, AR_PHY_PMU2, reg_pmu_set);
+			if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set))
+				return;
+		} else {
+			/* Internal regulator is ON. Write swreg register. */
+			int swreg = ath9k_hw_ar9300_get_eeprom(ah, EEP_SWREG);
+			REG_WRITE(ah, AR_RTC_REG_CONTROL1,
+				  REG_READ(ah, AR_RTC_REG_CONTROL1) &
+				  (~AR_RTC_REG_CONTROL1_SWREG_PROGRAM));
+			REG_WRITE(ah, AR_RTC_REG_CONTROL0, swreg);
+			/* Set REG_CONTROL1.SWREG_PROGRAM */
+			REG_WRITE(ah, AR_RTC_REG_CONTROL1,
+				  REG_READ(ah,
+					   AR_RTC_REG_CONTROL1) |
+					   AR_RTC_REG_CONTROL1_SWREG_PROGRAM);
+		}
+	} else {
+		if (AR_SREV_9485(ah)) {
+			REG_RMW_FIELD(ah, AR_PHY_PMU2, AR_PHY_PMU2_PGM, 0);
+			while (REG_READ_FIELD(ah, AR_PHY_PMU2,
+					      AR_PHY_PMU2_PGM))
+				udelay(10);
+
+			REG_RMW_FIELD(ah, AR_PHY_PMU1, AR_PHY_PMU1_PWD, 0x1);
+			while (!REG_READ_FIELD(ah, AR_PHY_PMU1,
+					       AR_PHY_PMU1_PWD))
+				udelay(10);
+			REG_RMW_FIELD(ah, AR_PHY_PMU2, AR_PHY_PMU2_PGM, 0x1);
+			while (!REG_READ_FIELD(ah, AR_PHY_PMU2,
+					      AR_PHY_PMU2_PGM))
+				udelay(10);
+		} else
+			REG_WRITE(ah, AR_RTC_SLEEP_CLK,
+				  (REG_READ(ah,
+				   AR_RTC_SLEEP_CLK) |
+				   AR_RTC_FORCE_SWREG_PRD));
+	}
+
+}
+
+static void ar9003_hw_apply_tuning_caps(struct ath_hw *ah)
+{
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	u8 tuning_caps_param = eep->baseEepHeader.params_for_tuning_caps[0];
+
+	if (eep->baseEepHeader.featureEnable & 0x40) {
+		tuning_caps_param &= 0x7f;
+		REG_RMW_FIELD(ah, AR_CH0_XTAL, AR_CH0_XTAL_CAPINDAC,
+			      tuning_caps_param);
+		REG_RMW_FIELD(ah, AR_CH0_XTAL, AR_CH0_XTAL_CAPOUTDAC,
+			      tuning_caps_param);
+	}
+}
+
+static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
+					     struct ath9k_channel *chan)
+{
+	ar9003_hw_xpa_bias_level_apply(ah, IS_CHAN_2GHZ(chan));
+	ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan));
+	ar9003_hw_drive_strength_apply(ah);
+	ar9003_hw_atten_apply(ah, chan);
+	if (!AR_SREV_9340(ah))
+		ar9003_hw_internal_regulator_apply(ah);
+	if (AR_SREV_9485(ah) || AR_SREV_9340(ah))
+		ar9003_hw_apply_tuning_caps(ah);
+}
+
+static void ath9k_hw_ar9300_set_addac(struct ath_hw *ah __unused,
+				      struct ath9k_channel *chan __unused)
+{
+}
+
+/*
+ * Returns the interpolated y value corresponding to the specified x value
+ * from the np ordered pairs of data (px,py).
+ * The pairs do not have to be in any order.
+ * If the specified x value is less than any of the px,
+ * the returned y value is equal to the py for the lowest px.
+ * If the specified x value is greater than any of the px,
+ * the returned y value is equal to the py for the highest px.
+ */
+static int ar9003_hw_power_interpolate(int32_t x,
+				       int32_t *px, int32_t *py, uint16_t np)
+{
+	int ip = 0;
+	int lx = 0, ly = 0, lhave = 0;
+	int hx = 0, hy = 0, hhave = 0;
+	int dx = 0;
+	int y = 0;
+
+	lhave = 0;
+	hhave = 0;
+
+	/* identify best lower and higher x calibration measurement */
+	for (ip = 0; ip < np; ip++) {
+		dx = x - px[ip];
+
+		/* this measurement is higher than our desired x */
+		if (dx <= 0) {
+			if (!hhave || dx > (x - hx)) {
+				/* new best higher x measurement */
+				hx = px[ip];
+				hy = py[ip];
+				hhave = 1;
+			}
+		}
+		/* this measurement is lower than our desired x */
+		if (dx >= 0) {
+			if (!lhave || dx < (x - lx)) {
+				/* new best lower x measurement */
+				lx = px[ip];
+				ly = py[ip];
+				lhave = 1;
+			}
+		}
+	}
+
+	/* the low x is good */
+	if (lhave) {
+		/* so is the high x */
+		if (hhave) {
+			/* they're the same, so just pick one */
+			if (hx == lx)
+				y = ly;
+			else	/* interpolate  */
+				y = interpolate(x, lx, hx, ly, hy);
+		} else		/* only low is good, use it */
+			y = ly;
+	} else if (hhave)	/* only high is good, use it */
+		y = hy;
+	else /* nothing is good,this should never happen unless np=0, ???? */
+		y = -(1 << 30);
+	return y;
+}
+
+static u8 ar9003_hw_eeprom_get_tgt_pwr(struct ath_hw *ah,
+				       u16 rateIndex, u16 freq, int is2GHz)
+{
+	u16 numPiers, i;
+	s32 targetPowerArray[AR9300_NUM_5G_20_TARGET_POWERS];
+	s32 freqArray[AR9300_NUM_5G_20_TARGET_POWERS];
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	struct cal_tgt_pow_legacy *pEepromTargetPwr;
+	u8 *pFreqBin;
+
+	if (is2GHz) {
+		numPiers = AR9300_NUM_2G_20_TARGET_POWERS;
+		pEepromTargetPwr = eep->calTargetPower2G;
+		pFreqBin = eep->calTarget_freqbin_2G;
+	} else {
+		numPiers = AR9300_NUM_5G_20_TARGET_POWERS;
+		pEepromTargetPwr = eep->calTargetPower5G;
+		pFreqBin = eep->calTarget_freqbin_5G;
+	}
+
+	/*
+	 * create array of channels and targetpower from
+	 * targetpower piers stored on eeprom
+	 */
+	for (i = 0; i < numPiers; i++) {
+		freqArray[i] = FBIN2FREQ(pFreqBin[i], is2GHz);
+		targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex];
+	}
+
+	/* interpolate to get target power for given frequency */
+	return (u8) ar9003_hw_power_interpolate((s32) freq,
+						 freqArray,
+						 targetPowerArray, numPiers);
+}
+
+static u8 ar9003_hw_eeprom_get_ht20_tgt_pwr(struct ath_hw *ah,
+					    u16 rateIndex,
+					    u16 freq, int is2GHz)
+{
+	u16 numPiers, i;
+	s32 targetPowerArray[AR9300_NUM_5G_20_TARGET_POWERS];
+	s32 freqArray[AR9300_NUM_5G_20_TARGET_POWERS];
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	struct cal_tgt_pow_ht *pEepromTargetPwr;
+	u8 *pFreqBin;
+
+	if (is2GHz) {
+		numPiers = AR9300_NUM_2G_20_TARGET_POWERS;
+		pEepromTargetPwr = eep->calTargetPower2GHT20;
+		pFreqBin = eep->calTarget_freqbin_2GHT20;
+	} else {
+		numPiers = AR9300_NUM_5G_20_TARGET_POWERS;
+		pEepromTargetPwr = eep->calTargetPower5GHT20;
+		pFreqBin = eep->calTarget_freqbin_5GHT20;
+	}
+
+	/*
+	 * create array of channels and targetpower
+	 * from targetpower piers stored on eeprom
+	 */
+	for (i = 0; i < numPiers; i++) {
+		freqArray[i] = FBIN2FREQ(pFreqBin[i], is2GHz);
+		targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex];
+	}
+
+	/* interpolate to get target power for given frequency */
+	return (u8) ar9003_hw_power_interpolate((s32) freq,
+						 freqArray,
+						 targetPowerArray, numPiers);
+}
+
+static u8 ar9003_hw_eeprom_get_ht40_tgt_pwr(struct ath_hw *ah,
+					    u16 rateIndex,
+					    u16 freq, int is2GHz)
+{
+	u16 numPiers, i;
+	s32 targetPowerArray[AR9300_NUM_5G_40_TARGET_POWERS];
+	s32 freqArray[AR9300_NUM_5G_40_TARGET_POWERS];
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	struct cal_tgt_pow_ht *pEepromTargetPwr;
+	u8 *pFreqBin;
+
+	if (is2GHz) {
+		numPiers = AR9300_NUM_2G_40_TARGET_POWERS;
+		pEepromTargetPwr = eep->calTargetPower2GHT40;
+		pFreqBin = eep->calTarget_freqbin_2GHT40;
+	} else {
+		numPiers = AR9300_NUM_5G_40_TARGET_POWERS;
+		pEepromTargetPwr = eep->calTargetPower5GHT40;
+		pFreqBin = eep->calTarget_freqbin_5GHT40;
+	}
+
+	/*
+	 * create array of channels and targetpower from
+	 * targetpower piers stored on eeprom
+	 */
+	for (i = 0; i < numPiers; i++) {
+		freqArray[i] = FBIN2FREQ(pFreqBin[i], is2GHz);
+		targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex];
+	}
+
+	/* interpolate to get target power for given frequency */
+	return (u8) ar9003_hw_power_interpolate((s32) freq,
+						 freqArray,
+						 targetPowerArray, numPiers);
+}
+
+static u8 ar9003_hw_eeprom_get_cck_tgt_pwr(struct ath_hw *ah,
+					   u16 rateIndex, u16 freq)
+{
+	u16 numPiers = AR9300_NUM_2G_CCK_TARGET_POWERS, i;
+	s32 targetPowerArray[AR9300_NUM_2G_CCK_TARGET_POWERS];
+	s32 freqArray[AR9300_NUM_2G_CCK_TARGET_POWERS];
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	struct cal_tgt_pow_legacy *pEepromTargetPwr = eep->calTargetPowerCck;
+	u8 *pFreqBin = eep->calTarget_freqbin_Cck;
+
+	/*
+	 * create array of channels and targetpower from
+	 * targetpower piers stored on eeprom
+	 */
+	for (i = 0; i < numPiers; i++) {
+		freqArray[i] = FBIN2FREQ(pFreqBin[i], 1);
+		targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex];
+	}
+
+	/* interpolate to get target power for given frequency */
+	return (u8) ar9003_hw_power_interpolate((s32) freq,
+						 freqArray,
+						 targetPowerArray, numPiers);
+}
+
+/* Set tx power registers to array of values passed in */
+static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
+{
+#define POW_SM(_r, _s)     (((_r) & 0x3f) << (_s))
+	/* make sure forced gain is not set */
+	REG_WRITE(ah, AR_PHY_TX_FORCED_GAIN, 0);
+
+	/* Write the OFDM power per rate set */
+
+	/* 6 (LSB), 9, 12, 18 (MSB) */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE(0),
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) |
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 16) |
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 8) |
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 0));
+
+	/* 24 (LSB), 36, 48, 54 (MSB) */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE(1),
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_54], 24) |
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_48], 16) |
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_36], 8) |
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 0));
+
+	/* Write the CCK power per rate set */
+
+	/* 1L (LSB), reserved, 2L, 2S (MSB) */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE(2),
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 24) |
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) |
+		  /* POW_SM(txPowerTimes2,  8) | this is reserved for AR9003 */
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0));
+
+	/* 5.5L (LSB), 5.5S, 11L, 11S (MSB) */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE(3),
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_11S], 24) |
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_11L], 16) |
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_5S], 8) |
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0)
+	    );
+
+        /* Write the power for duplicated frames - HT40 */
+
+        /* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */
+	REG_WRITE(ah, 0xa3e0,
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) |
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) |
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24],  8) |
+		  POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L],  0)
+	    );
+
+	/* Write the HT20 power per rate set */
+
+	/* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE(4),
+		  POW_SM(pPwrArray[ALL_TARGET_HT20_5], 24) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT20_4], 16) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT20_1_3_9_11_17_19], 8) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT20_0_8_16], 0)
+	    );
+
+	/* 6 (LSB), 7, 12, 13 (MSB) */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE(5),
+		  POW_SM(pPwrArray[ALL_TARGET_HT20_13], 24) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT20_12], 16) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT20_7], 8) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT20_6], 0)
+	    );
+
+	/* 14 (LSB), 15, 20, 21 */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE(9),
+		  POW_SM(pPwrArray[ALL_TARGET_HT20_21], 24) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT20_20], 16) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT20_15], 8) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT20_14], 0)
+	    );
+
+	/* Mixed HT20 and HT40 rates */
+
+	/* HT20 22 (LSB), HT20 23, HT40 22, HT40 23 (MSB) */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE(10),
+		  POW_SM(pPwrArray[ALL_TARGET_HT40_23], 24) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT40_22], 16) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT20_23], 8) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT20_22], 0)
+	    );
+
+	/*
+	 * Write the HT40 power per rate set
+	 * correct PAR difference between HT40 and HT20/LEGACY
+	 * 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB)
+	 */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE(6),
+		  POW_SM(pPwrArray[ALL_TARGET_HT40_5], 24) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT40_4], 16) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT40_1_3_9_11_17_19], 8) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT40_0_8_16], 0)
+	    );
+
+	/* 6 (LSB), 7, 12, 13 (MSB) */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE(7),
+		  POW_SM(pPwrArray[ALL_TARGET_HT40_13], 24) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT40_12], 16) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT40_7], 8) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT40_6], 0)
+	    );
+
+	/* 14 (LSB), 15, 20, 21 */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE(11),
+		  POW_SM(pPwrArray[ALL_TARGET_HT40_21], 24) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT40_20], 16) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT40_15], 8) |
+		  POW_SM(pPwrArray[ALL_TARGET_HT40_14], 0)
+	    );
+
+	return 0;
+#undef POW_SM
+}
+
+static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq,
+					      u8 *targetPowerValT2)
+{
+	/* XXX: hard code for now, need to get from eeprom struct */
+	u8 ht40PowerIncForPdadc = 0;
+	int is2GHz = 0;
+	unsigned int i = 0;
+
+	if (freq < 4000)
+		is2GHz = 1;
+
+	targetPowerValT2[ALL_TARGET_LEGACY_6_24] =
+	    ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_6_24, freq,
+					 is2GHz);
+	targetPowerValT2[ALL_TARGET_LEGACY_36] =
+	    ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_36, freq,
+					 is2GHz);
+	targetPowerValT2[ALL_TARGET_LEGACY_48] =
+	    ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_48, freq,
+					 is2GHz);
+	targetPowerValT2[ALL_TARGET_LEGACY_54] =
+	    ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_54, freq,
+					 is2GHz);
+	targetPowerValT2[ALL_TARGET_LEGACY_1L_5L] =
+	    ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_1L_5L,
+					     freq);
+	targetPowerValT2[ALL_TARGET_LEGACY_5S] =
+	    ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_5S, freq);
+	targetPowerValT2[ALL_TARGET_LEGACY_11L] =
+	    ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_11L, freq);
+	targetPowerValT2[ALL_TARGET_LEGACY_11S] =
+	    ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_11S, freq);
+	targetPowerValT2[ALL_TARGET_HT20_0_8_16] =
+	    ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_0_8_16, freq,
+					      is2GHz);
+	targetPowerValT2[ALL_TARGET_HT20_1_3_9_11_17_19] =
+	    ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_1_3_9_11_17_19,
+					      freq, is2GHz);
+	targetPowerValT2[ALL_TARGET_HT20_4] =
+	    ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_4, freq,
+					      is2GHz);
+	targetPowerValT2[ALL_TARGET_HT20_5] =
+	    ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_5, freq,
+					      is2GHz);
+	targetPowerValT2[ALL_TARGET_HT20_6] =
+	    ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_6, freq,
+					      is2GHz);
+	targetPowerValT2[ALL_TARGET_HT20_7] =
+	    ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_7, freq,
+					      is2GHz);
+	targetPowerValT2[ALL_TARGET_HT20_12] =
+	    ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_12, freq,
+					      is2GHz);
+	targetPowerValT2[ALL_TARGET_HT20_13] =
+	    ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_13, freq,
+					      is2GHz);
+	targetPowerValT2[ALL_TARGET_HT20_14] =
+	    ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_14, freq,
+					      is2GHz);
+	targetPowerValT2[ALL_TARGET_HT20_15] =
+	    ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_15, freq,
+					      is2GHz);
+	targetPowerValT2[ALL_TARGET_HT20_20] =
+	    ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_20, freq,
+					      is2GHz);
+	targetPowerValT2[ALL_TARGET_HT20_21] =
+	    ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_21, freq,
+					      is2GHz);
+	targetPowerValT2[ALL_TARGET_HT20_22] =
+	    ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_22, freq,
+					      is2GHz);
+	targetPowerValT2[ALL_TARGET_HT20_23] =
+	    ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_23, freq,
+					      is2GHz);
+	targetPowerValT2[ALL_TARGET_HT40_0_8_16] =
+	    ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_0_8_16, freq,
+					      is2GHz) + ht40PowerIncForPdadc;
+	targetPowerValT2[ALL_TARGET_HT40_1_3_9_11_17_19] =
+	    ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_1_3_9_11_17_19,
+					      freq,
+					      is2GHz) + ht40PowerIncForPdadc;
+	targetPowerValT2[ALL_TARGET_HT40_4] =
+	    ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_4, freq,
+					      is2GHz) + ht40PowerIncForPdadc;
+	targetPowerValT2[ALL_TARGET_HT40_5] =
+	    ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_5, freq,
+					      is2GHz) + ht40PowerIncForPdadc;
+	targetPowerValT2[ALL_TARGET_HT40_6] =
+	    ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_6, freq,
+					      is2GHz) + ht40PowerIncForPdadc;
+	targetPowerValT2[ALL_TARGET_HT40_7] =
+	    ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_7, freq,
+					      is2GHz) + ht40PowerIncForPdadc;
+	targetPowerValT2[ALL_TARGET_HT40_12] =
+	    ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_12, freq,
+					      is2GHz) + ht40PowerIncForPdadc;
+	targetPowerValT2[ALL_TARGET_HT40_13] =
+	    ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_13, freq,
+					      is2GHz) + ht40PowerIncForPdadc;
+	targetPowerValT2[ALL_TARGET_HT40_14] =
+	    ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_14, freq,
+					      is2GHz) + ht40PowerIncForPdadc;
+	targetPowerValT2[ALL_TARGET_HT40_15] =
+	    ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_15, freq,
+					      is2GHz) + ht40PowerIncForPdadc;
+	targetPowerValT2[ALL_TARGET_HT40_20] =
+	    ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_20, freq,
+					      is2GHz) + ht40PowerIncForPdadc;
+	targetPowerValT2[ALL_TARGET_HT40_21] =
+	    ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_21, freq,
+					      is2GHz) + ht40PowerIncForPdadc;
+	targetPowerValT2[ALL_TARGET_HT40_22] =
+	    ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_22, freq,
+					      is2GHz) + ht40PowerIncForPdadc;
+	targetPowerValT2[ALL_TARGET_HT40_23] =
+	    ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_23, freq,
+					      is2GHz) + ht40PowerIncForPdadc;
+
+	for (i = 0; i < ar9300RateSize; i++) {
+		DBG2("ath9k: "
+			"TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]);
+	}
+}
+
+static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
+				  int mode,
+				  int ipier,
+				  int ichain,
+				  int *pfrequency,
+				  int *pcorrection,
+				  int *ptemperature, int *pvoltage)
+{
+	u8 *pCalPier;
+	struct ar9300_cal_data_per_freq_op_loop *pCalPierStruct;
+	int is2GHz;
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+	if (ichain >= AR9300_MAX_CHAINS) {
+		DBG("ath9k: "
+			"Invalid chain index, must be less than %d\n",
+			AR9300_MAX_CHAINS);
+		return -1;
+	}
+
+	if (mode) {		/* 5GHz */
+		if (ipier >= AR9300_NUM_5G_CAL_PIERS) {
+			DBG("ath9k: "
+				"Invalid 5GHz cal pier index, must be less than %d\n",
+				AR9300_NUM_5G_CAL_PIERS);
+			return -1;
+		}
+		pCalPier = &(eep->calFreqPier5G[ipier]);
+		pCalPierStruct = &(eep->calPierData5G[ichain][ipier]);
+		is2GHz = 0;
+	} else {
+		if (ipier >= AR9300_NUM_2G_CAL_PIERS) {
+			DBG("ath9k: "
+				"Invalid 2GHz cal pier index, must be less than %d\n",
+				AR9300_NUM_2G_CAL_PIERS);
+			return -1;
+		}
+
+		pCalPier = &(eep->calFreqPier2G[ipier]);
+		pCalPierStruct = &(eep->calPierData2G[ichain][ipier]);
+		is2GHz = 1;
+	}
+
+	*pfrequency = FBIN2FREQ(*pCalPier, is2GHz);
+	*pcorrection = pCalPierStruct->refPower;
+	*ptemperature = pCalPierStruct->tempMeas;
+	*pvoltage = pCalPierStruct->voltMeas;
+
+	return 0;
+}
+
+static int ar9003_hw_power_control_override(struct ath_hw *ah,
+					    int frequency,
+					    int *correction,
+					    int *voltage __unused, int *temperature)
+{
+	int tempSlope = 0;
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	int f[3], t[3];
+
+	REG_RMW(ah, AR_PHY_TPC_11_B0,
+		(correction[0] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
+		AR_PHY_TPC_OLPC_GAIN_DELTA);
+	if (ah->caps.tx_chainmask & BIT(1))
+		REG_RMW(ah, AR_PHY_TPC_11_B1,
+			(correction[1] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
+			AR_PHY_TPC_OLPC_GAIN_DELTA);
+	if (ah->caps.tx_chainmask & BIT(2))
+		REG_RMW(ah, AR_PHY_TPC_11_B2,
+			(correction[2] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
+			AR_PHY_TPC_OLPC_GAIN_DELTA);
+
+	/* enable open loop power control on chip */
+	REG_RMW(ah, AR_PHY_TPC_6_B0,
+		(3 << AR_PHY_TPC_6_ERROR_EST_MODE_S),
+		AR_PHY_TPC_6_ERROR_EST_MODE);
+	if (ah->caps.tx_chainmask & BIT(1))
+		REG_RMW(ah, AR_PHY_TPC_6_B1,
+			(3 << AR_PHY_TPC_6_ERROR_EST_MODE_S),
+			AR_PHY_TPC_6_ERROR_EST_MODE);
+	if (ah->caps.tx_chainmask & BIT(2))
+		REG_RMW(ah, AR_PHY_TPC_6_B2,
+			(3 << AR_PHY_TPC_6_ERROR_EST_MODE_S),
+			AR_PHY_TPC_6_ERROR_EST_MODE);
+
+	/*
+	 * enable temperature compensation
+	 * Need to use register names
+	 */
+	if (frequency < 4000)
+		tempSlope = eep->modalHeader2G.tempSlope;
+	else if (eep->base_ext2.tempSlopeLow != 0) {
+		t[0] = eep->base_ext2.tempSlopeLow;
+		f[0] = 5180;
+		t[1] = eep->modalHeader5G.tempSlope;
+		f[1] = 5500;
+		t[2] = eep->base_ext2.tempSlopeHigh;
+		f[2] = 5785;
+		tempSlope = ar9003_hw_power_interpolate((s32) frequency,
+							f, t, 3);
+	} else
+		tempSlope = eep->modalHeader5G.tempSlope;
+
+	REG_RMW_FIELD(ah, AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, tempSlope);
+	REG_RMW_FIELD(ah, AR_PHY_TPC_18, AR_PHY_TPC_18_THERM_CAL_VALUE,
+		      temperature[0]);
+
+	return 0;
+}
+
+/* Apply the recorded correction values. */
+static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
+{
+	int ichain, ipier, npier;
+	int mode;
+	int lfrequency[AR9300_MAX_CHAINS],
+	    lcorrection[AR9300_MAX_CHAINS],
+	    ltemperature[AR9300_MAX_CHAINS], lvoltage[AR9300_MAX_CHAINS];
+	int hfrequency[AR9300_MAX_CHAINS],
+	    hcorrection[AR9300_MAX_CHAINS],
+	    htemperature[AR9300_MAX_CHAINS], hvoltage[AR9300_MAX_CHAINS];
+	int fdiff;
+	int correction[AR9300_MAX_CHAINS],
+	    voltage[AR9300_MAX_CHAINS], temperature[AR9300_MAX_CHAINS];
+	int pfrequency, pcorrection, ptemperature, pvoltage;
+
+	mode = (frequency >= 4000);
+	if (mode)
+		npier = AR9300_NUM_5G_CAL_PIERS;
+	else
+		npier = AR9300_NUM_2G_CAL_PIERS;
+
+	for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) {
+		lfrequency[ichain] = 0;
+		hfrequency[ichain] = 100000;
+	}
+	/* identify best lower and higher frequency calibration measurement */
+	for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) {
+		for (ipier = 0; ipier < npier; ipier++) {
+			if (!ar9003_hw_cal_pier_get(ah, mode, ipier, ichain,
+						    &pfrequency, &pcorrection,
+						    &ptemperature, &pvoltage)) {
+				fdiff = frequency - pfrequency;
+
+				/*
+				 * this measurement is higher than
+				 * our desired frequency
+				 */
+				if (fdiff <= 0) {
+					if (hfrequency[ichain] <= 0 ||
+					    hfrequency[ichain] >= 100000 ||
+					    fdiff >
+					    (frequency - hfrequency[ichain])) {
+						/*
+						 * new best higher
+						 * frequency measurement
+						 */
+						hfrequency[ichain] = pfrequency;
+						hcorrection[ichain] =
+						    pcorrection;
+						htemperature[ichain] =
+						    ptemperature;
+						hvoltage[ichain] = pvoltage;
+					}
+				}
+				if (fdiff >= 0) {
+					if (lfrequency[ichain] <= 0
+					    || fdiff <
+					    (frequency - lfrequency[ichain])) {
+						/*
+						 * new best lower
+						 * frequency measurement
+						 */
+						lfrequency[ichain] = pfrequency;
+						lcorrection[ichain] =
+						    pcorrection;
+						ltemperature[ichain] =
+						    ptemperature;
+						lvoltage[ichain] = pvoltage;
+					}
+				}
+			}
+		}
+	}
+
+	/* interpolate  */
+	for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) {
+		DBG2("ath9k: "
+			"ch=%d f=%d low=%d %d h=%d %d\n",
+			ichain, frequency, lfrequency[ichain],
+			lcorrection[ichain], hfrequency[ichain],
+			hcorrection[ichain]);
+		/* they're the same, so just pick one */
+		if (hfrequency[ichain] == lfrequency[ichain]) {
+			correction[ichain] = lcorrection[ichain];
+			voltage[ichain] = lvoltage[ichain];
+			temperature[ichain] = ltemperature[ichain];
+		}
+		/* the low frequency is good */
+		else if (frequency - lfrequency[ichain] < 1000) {
+			/* so is the high frequency, interpolate */
+			if (hfrequency[ichain] - frequency < 1000) {
+
+				correction[ichain] = interpolate(frequency,
+						lfrequency[ichain],
+						hfrequency[ichain],
+						lcorrection[ichain],
+						hcorrection[ichain]);
+
+				temperature[ichain] = interpolate(frequency,
+						lfrequency[ichain],
+						hfrequency[ichain],
+						ltemperature[ichain],
+						htemperature[ichain]);
+
+				voltage[ichain] = interpolate(frequency,
+						lfrequency[ichain],
+						hfrequency[ichain],
+						lvoltage[ichain],
+						hvoltage[ichain]);
+			}
+			/* only low is good, use it */
+			else {
+				correction[ichain] = lcorrection[ichain];
+				temperature[ichain] = ltemperature[ichain];
+				voltage[ichain] = lvoltage[ichain];
+			}
+		}
+		/* only high is good, use it */
+		else if (hfrequency[ichain] - frequency < 1000) {
+			correction[ichain] = hcorrection[ichain];
+			temperature[ichain] = htemperature[ichain];
+			voltage[ichain] = hvoltage[ichain];
+		} else {	/* nothing is good, presume 0???? */
+			correction[ichain] = 0;
+			temperature[ichain] = 0;
+			voltage[ichain] = 0;
+		}
+	}
+
+	ar9003_hw_power_control_override(ah, frequency, correction, voltage,
+					 temperature);
+
+	DBG2("ath9k: "
+		"for frequency=%d, calibration correction = %d %d %d\n",
+		frequency, correction[0], correction[1], correction[2]);
+
+	return 0;
+}
+
+static u16 ar9003_hw_get_direct_edge_power(struct ar9300_eeprom *eep,
+					   int idx,
+					   int edge,
+					   int is2GHz)
+{
+	struct cal_ctl_data_2g *ctl_2g = eep->ctlPowerData_2G;
+	struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G;
+
+	if (is2GHz)
+		return CTL_EDGE_TPOWER(ctl_2g[idx].ctlEdges[edge]);
+	else
+		return CTL_EDGE_TPOWER(ctl_5g[idx].ctlEdges[edge]);
+}
+
+static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep,
+					     int idx,
+					     unsigned int edge,
+					     u16 freq,
+					     int is2GHz)
+{
+	struct cal_ctl_data_2g *ctl_2g = eep->ctlPowerData_2G;
+	struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G;
+
+	u8 *ctl_freqbin = is2GHz ?
+		&eep->ctl_freqbin_2G[idx][0] :
+		&eep->ctl_freqbin_5G[idx][0];
+
+	if (is2GHz) {
+		if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 1) < freq &&
+		    CTL_EDGE_FLAGS(ctl_2g[idx].ctlEdges[edge - 1]))
+			return CTL_EDGE_TPOWER(ctl_2g[idx].ctlEdges[edge - 1]);
+	} else {
+		if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 0) < freq &&
+		    CTL_EDGE_FLAGS(ctl_5g[idx].ctlEdges[edge - 1]))
+			return CTL_EDGE_TPOWER(ctl_5g[idx].ctlEdges[edge - 1]);
+	}
+
+	return MAX_RATE_POWER;
+}
+
+/*
+ * Find the maximum conformance test limit for the given channel and CTL info
+ */
+static u16 ar9003_hw_get_max_edge_power(struct ar9300_eeprom *eep,
+					u16 freq, int idx, int is2GHz)
+{
+	u16 twiceMaxEdgePower = MAX_RATE_POWER;
+	u8 *ctl_freqbin = is2GHz ?
+		&eep->ctl_freqbin_2G[idx][0] :
+		&eep->ctl_freqbin_5G[idx][0];
+	u16 num_edges = is2GHz ?
+		AR9300_NUM_BAND_EDGES_2G : AR9300_NUM_BAND_EDGES_5G;
+	unsigned int edge;
+
+	/* Get the edge power */
+	for (edge = 0;
+	     (edge < num_edges) && (ctl_freqbin[edge] != AR5416_BCHAN_UNUSED);
+	     edge++) {
+		/*
+		 * If there's an exact channel match or an inband flag set
+		 * on the lower channel use the given rdEdgePower
+		 */
+		if (freq == ath9k_hw_fbin2freq(ctl_freqbin[edge], is2GHz)) {
+			twiceMaxEdgePower =
+				ar9003_hw_get_direct_edge_power(eep, idx,
+								edge, is2GHz);
+			break;
+		} else if ((edge > 0) &&
+			   (freq < ath9k_hw_fbin2freq(ctl_freqbin[edge],
+						      is2GHz))) {
+			twiceMaxEdgePower =
+				ar9003_hw_get_indirect_edge_power(eep, idx,
+								  edge, freq,
+								  is2GHz);
+			/*
+			 * Leave loop - no more affecting edges possible in
+			 * this monotonic increasing list
+			 */
+			break;
+		}
+	}
+	return twiceMaxEdgePower;
+}
+
+static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
+					       struct ath9k_channel *chan,
+					       u8 *pPwrArray, u16 cfgCtl,
+					       u8 twiceAntennaReduction,
+					       u8 twiceMaxRegulatoryPower,
+					       u16 powerLimit)
+{
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+	struct ar9300_eeprom *pEepData = &ah->eeprom.ar9300_eep;
+	u16 twiceMaxEdgePower = MAX_RATE_POWER;
+	static const u16 tpScaleReductionTable[5] = {
+		0, 3, 6, 9, MAX_RATE_POWER
+	};
+	int i;
+	int16_t  twiceLargestAntenna;
+	u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+	static const u16 ctlModesFor11a[] = {
+		CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40
+	};
+	static const u16 ctlModesFor11g[] = {
+		CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT,
+		CTL_11G_EXT, CTL_2GHT40
+	};
+	u16 numCtlModes;
+	const u16 *pCtlMode;
+	u16 ctlMode, freq;
+	struct chan_centers centers;
+	u8 *ctlIndex;
+	u8 ctlNum;
+	u16 twiceMinEdgePower;
+	int is2ghz = IS_CHAN_2GHZ(chan);
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+	/* Compute TxPower reduction due to Antenna Gain */
+	if (is2ghz)
+		twiceLargestAntenna = pEepData->modalHeader2G.antennaGain;
+	else
+		twiceLargestAntenna = pEepData->modalHeader5G.antennaGain;
+
+	twiceLargestAntenna = (int16_t)min((twiceAntennaReduction) -
+				twiceLargestAntenna, 0);
+
+	/*
+	 * scaledPower is the minimum of the user input power level
+	 * and the regulatory allowed power level
+	 */
+	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
+	if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) {
+		maxRegAllowedPower -=
+			(tpScaleReductionTable[(regulatory->tp_scale)] * 2);
+	}
+
+	scaledPower = min(powerLimit, maxRegAllowedPower);
+
+	/*
+	 * Reduce scaled Power by number of chains active to get
+	 * to per chain tx power level
+	 */
+	switch (ar5416_get_ntxchains(ah->txchainmask)) {
+	case 1:
+		break;
+	case 2:
+		if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
+			scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+		else
+			scaledPower = 0;
+		break;
+	case 3:
+		if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
+			scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+		else
+			scaledPower = 0;
+		break;
+	}
+
+	scaledPower = max((u16)0, scaledPower);
+
+	/*
+	 * Get target powers from EEPROM - our baseline for TX Power
+	 */
+	if (is2ghz) {
+		/* Setup for CTL modes */
+		/* CTL_11B, CTL_11G, CTL_2GHT20 */
+		numCtlModes =
+			ARRAY_SIZE(ctlModesFor11g) -
+				   SUB_NUM_CTL_MODES_AT_2G_40;
+		pCtlMode = ctlModesFor11g;
+		if (IS_CHAN_HT40(chan))
+			/* All 2G CTL's */
+			numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+	} else {
+		/* Setup for CTL modes */
+		/* CTL_11A, CTL_5GHT20 */
+		numCtlModes = ARRAY_SIZE(ctlModesFor11a) -
+					 SUB_NUM_CTL_MODES_AT_5G_40;
+		pCtlMode = ctlModesFor11a;
+		if (IS_CHAN_HT40(chan))
+			/* All 5G CTL's */
+			numCtlModes = ARRAY_SIZE(ctlModesFor11a);
+	}
+
+	/*
+	 * For MIMO, need to apply regulatory caps individually across
+	 * dynamically running modes: CCK, OFDM, HT20, HT40
+	 *
+	 * The outer loop walks through each possible applicable runtime mode.
+	 * The inner loop walks through each ctlIndex entry in EEPROM.
+	 * The ctl value is encoded as [7:4] == test group, [3:0] == test mode.
+	 */
+	for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+		int isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
+			(pCtlMode[ctlMode] == CTL_2GHT40);
+		if (isHt40CtlMode)
+			freq = centers.synth_center;
+		else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+			freq = centers.ext_center;
+		else
+			freq = centers.ctl_center;
+
+		DBG2("ath9k: "
+			"LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, EXT_ADDITIVE %d\n",
+			ctlMode, numCtlModes, isHt40CtlMode,
+			(pCtlMode[ctlMode] & EXT_ADDITIVE));
+
+		/* walk through each CTL index stored in EEPROM */
+		if (is2ghz) {
+			ctlIndex = pEepData->ctlIndex_2G;
+			ctlNum = AR9300_NUM_CTLS_2G;
+		} else {
+			ctlIndex = pEepData->ctlIndex_5G;
+			ctlNum = AR9300_NUM_CTLS_5G;
+		}
+
+		for (i = 0; (i < ctlNum) && ctlIndex[i]; i++) {
+			DBG2("ath9k: "
+				"LOOP-Ctlidx %d: cfgCtl 0x%2.2x pCtlMode 0x%2.2x ctlIndex 0x%2.2x chan %d\n",
+				i, cfgCtl, pCtlMode[ctlMode], ctlIndex[i],
+				chan->channel);
+
+				/*
+				 * compare test group from regulatory
+				 * channel list with test mode from pCtlMode
+				 * list
+				 */
+				if ((((cfgCtl & ~CTL_MODE_M) |
+				       (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+					ctlIndex[i]) ||
+				    (((cfgCtl & ~CTL_MODE_M) |
+				       (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+				     ((ctlIndex[i] & CTL_MODE_M) |
+				       SD_NO_CTL))) {
+					twiceMinEdgePower =
+					  ar9003_hw_get_max_edge_power(pEepData,
+								       freq, i,
+								       is2ghz);
+
+					if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL)
+						/*
+						 * Find the minimum of all CTL
+						 * edge powers that apply to
+						 * this channel
+						 */
+						twiceMaxEdgePower =
+							min(twiceMaxEdgePower,
+							    twiceMinEdgePower);
+						else {
+							/* specific */
+							twiceMaxEdgePower =
+							  twiceMinEdgePower;
+							break;
+						}
+				}
+			}
+
+			minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
+
+			DBG2("ath9k: "
+				"SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d sP %d minCtlPwr %d\n",
+				ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
+				scaledPower, minCtlPower);
+
+			/* Apply ctl mode to correct target power set */
+			switch (pCtlMode[ctlMode]) {
+			case CTL_11B:
+				for (i = ALL_TARGET_LEGACY_1L_5L;
+				     i <= ALL_TARGET_LEGACY_11S; i++)
+					pPwrArray[i] =
+					  (u8)min((u16)pPwrArray[i],
+						  minCtlPower);
+				break;
+			case CTL_11A:
+			case CTL_11G:
+				for (i = ALL_TARGET_LEGACY_6_24;
+				     i <= ALL_TARGET_LEGACY_54; i++)
+					pPwrArray[i] =
+					  (u8)min((u16)pPwrArray[i],
+						  minCtlPower);
+				break;
+			case CTL_5GHT20:
+			case CTL_2GHT20:
+				for (i = ALL_TARGET_HT20_0_8_16;
+				     i <= ALL_TARGET_HT20_21; i++)
+					pPwrArray[i] =
+					  (u8)min((u16)pPwrArray[i],
+						  minCtlPower);
+				pPwrArray[ALL_TARGET_HT20_22] =
+				  (u8)min((u16)pPwrArray[ALL_TARGET_HT20_22],
+					  minCtlPower);
+				pPwrArray[ALL_TARGET_HT20_23] =
+				  (u8)min((u16)pPwrArray[ALL_TARGET_HT20_23],
+					   minCtlPower);
+				break;
+			case CTL_5GHT40:
+			case CTL_2GHT40:
+				for (i = ALL_TARGET_HT40_0_8_16;
+				     i <= ALL_TARGET_HT40_23; i++)
+					pPwrArray[i] =
+					  (u8)min((u16)pPwrArray[i],
+						  minCtlPower);
+				break;
+			default:
+			    break;
+			}
+	} /* end ctl mode checking */
+}
+
+static inline u8 mcsidx_to_tgtpwridx(unsigned int mcs_idx, u8 base_pwridx)
+{
+	u8 mod_idx = mcs_idx % 8;
+
+	if (mod_idx <= 3)
+		return mod_idx ? (base_pwridx + 1) : base_pwridx;
+	else
+		return base_pwridx + 4 * (mcs_idx / 8) + mod_idx - 2;
+}
+
+static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
+					struct ath9k_channel *chan, u16 cfgCtl,
+					u8 twiceAntennaReduction,
+					u8 twiceMaxRegulatoryPower,
+					u8 powerLimit, int test)
+{
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+	struct ar9300_modal_eep_header *modal_hdr;
+	u8 targetPowerValT2[ar9300RateSize];
+	u8 target_power_val_t2_eep[ar9300RateSize];
+	unsigned int i = 0, paprd_scale_factor = 0;
+	u8 pwr_idx, min_pwridx = 0;
+
+	ar9003_hw_set_target_power_eeprom(ah, chan->channel, targetPowerValT2);
+
+	if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) {
+		if (IS_CHAN_2GHZ(chan))
+			modal_hdr = &eep->modalHeader2G;
+		else
+			modal_hdr = &eep->modalHeader5G;
+
+		ah->paprd_ratemask =
+				(uint32_t)(modal_hdr->papdRateMaskHt20) &
+			AR9300_PAPRD_RATE_MASK;
+
+		ah->paprd_ratemask_ht40 =
+				(uint32_t)(modal_hdr->papdRateMaskHt40) &
+			AR9300_PAPRD_RATE_MASK;
+
+		paprd_scale_factor = ar9003_get_paprd_scale_factor(ah, chan);
+		min_pwridx = IS_CHAN_HT40(chan) ? ALL_TARGET_HT40_0_8_16 :
+						  ALL_TARGET_HT20_0_8_16;
+
+		if (!ah->paprd_table_write_done) {
+			memcpy(target_power_val_t2_eep, targetPowerValT2,
+			       sizeof(targetPowerValT2));
+			for (i = 0; i < 24; i++) {
+				pwr_idx = mcsidx_to_tgtpwridx(i, min_pwridx);
+				if (ah->paprd_ratemask & (1 << i)) {
+					if (targetPowerValT2[pwr_idx] &&
+					    targetPowerValT2[pwr_idx] ==
+					    target_power_val_t2_eep[pwr_idx])
+						targetPowerValT2[pwr_idx] -=
+							paprd_scale_factor;
+				}
+			}
+		}
+		memcpy(target_power_val_t2_eep, targetPowerValT2,
+		       sizeof(targetPowerValT2));
+	}
+
+	ar9003_hw_set_power_per_rate_table(ah, chan,
+					   targetPowerValT2, cfgCtl,
+					   twiceAntennaReduction,
+					   twiceMaxRegulatoryPower,
+					   powerLimit);
+
+	if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) {
+		for (i = 0; i < ar9300RateSize; i++) {
+			if ((ah->paprd_ratemask & (1 << i)) &&
+			    ((unsigned int)abs(targetPowerValT2[i] -
+				target_power_val_t2_eep[i]) >
+			    paprd_scale_factor)) {
+				ah->paprd_ratemask &= ~(1 << i);
+				DBG2("ath9k: "
+					"paprd disabled for mcs %d\n", i);
+			}
+		}
+	}
+
+	regulatory->max_power_level = 0;
+	for (i = 0; i < ar9300RateSize; i++) {
+		if (targetPowerValT2[i] > regulatory->max_power_level)
+			regulatory->max_power_level = targetPowerValT2[i];
+	}
+
+	if (test)
+		return;
+
+	for (i = 0; i < ar9300RateSize; i++) {
+		DBG2("ath9k: "
+			"TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]);
+	}
+
+	/*
+	 * This is the TX power we send back to driver core,
+	 * and it can use to pass to userspace to display our
+	 * currently configured TX power setting.
+	 *
+	 * Since power is rate dependent, use one of the indices
+	 * from the AR9300_Rates enum to select an entry from
+	 * targetPowerValT2[] to report. Currently returns the
+	 * power for HT40 MCS 0, HT20 MCS 0, or OFDM 6 Mbps
+	 * as CCK power is less interesting (?).
+	 */
+	i = ALL_TARGET_LEGACY_6_24; /* legacy */
+	if (IS_CHAN_HT40(chan))
+		i = ALL_TARGET_HT40_0_8_16; /* ht40 */
+	else if (IS_CHAN_HT20(chan))
+		i = ALL_TARGET_HT20_0_8_16; /* ht20 */
+
+	ah->txpower_limit = targetPowerValT2[i];
+	regulatory->max_power_level = targetPowerValT2[i];
+
+	/* Write target power array to registers */
+	ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
+	ar9003_hw_calibration_apply(ah, chan->channel);
+
+	if (IS_CHAN_2GHZ(chan)) {
+		if (IS_CHAN_HT40(chan))
+			i = ALL_TARGET_HT40_0_8_16;
+		else
+			i = ALL_TARGET_HT20_0_8_16;
+	} else {
+		if (IS_CHAN_HT40(chan))
+			i = ALL_TARGET_HT40_7;
+		else
+			i = ALL_TARGET_HT20_7;
+	}
+	ah->paprd_target_power = targetPowerValT2[i];
+}
+
+static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah __unused,
+					    u16 i __unused, int is2GHz __unused)
+{
+	return AR_NO_SPUR;
+}
+
+s32 ar9003_hw_get_tx_gain_idx(struct ath_hw *ah)
+{
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+	return (eep->baseEepHeader.txrxgain >> 4) & 0xf; /* bits 7:4 */
+}
+
+s32 ar9003_hw_get_rx_gain_idx(struct ath_hw *ah)
+{
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+	return (eep->baseEepHeader.txrxgain) & 0xf; /* bits 3:0 */
+}
+
+u8 *ar9003_get_spur_chan_ptr(struct ath_hw *ah, int is_2ghz)
+{
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+	if (is_2ghz)
+		return eep->modalHeader2G.spurChans;
+	else
+		return eep->modalHeader5G.spurChans;
+}
+
+unsigned int ar9003_get_paprd_scale_factor(struct ath_hw *ah,
+					   struct ath9k_channel *chan)
+{
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+	if (IS_CHAN_2GHZ(chan))
+		return MS((uint32_t)(eep->modalHeader2G.papdRateMaskHt20),
+			  AR9300_PAPRD_SCALE_1);
+	else {
+		if (chan->channel >= 5700)
+		return MS((uint32_t)(eep->modalHeader5G.papdRateMaskHt20),
+			  AR9300_PAPRD_SCALE_1);
+		else if (chan->channel >= 5400)
+			return MS((uint32_t)(eep->modalHeader5G.papdRateMaskHt40),
+				   AR9300_PAPRD_SCALE_2);
+		else
+			return MS((uint32_t)(eep->modalHeader5G.papdRateMaskHt40),
+				  AR9300_PAPRD_SCALE_1);
+	}
+}
+
+const struct eeprom_ops eep_ar9300_ops = {
+	.check_eeprom = ath9k_hw_ar9300_check_eeprom,
+	.get_eeprom = ath9k_hw_ar9300_get_eeprom,
+	.fill_eeprom = ath9k_hw_ar9300_fill_eeprom,
+	.get_eeprom_ver = ath9k_hw_ar9300_get_eeprom_ver,
+	.get_eeprom_rev = ath9k_hw_ar9300_get_eeprom_rev,
+	.set_board_values = ath9k_hw_ar9300_set_board_values,
+	.set_addac = ath9k_hw_ar9300_set_addac,
+	.set_txpower = ath9k_hw_ar9300_set_txpower,
+	.get_spur_channel = ath9k_hw_ar9300_get_spur_channel
+};
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_hw.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_hw.c
new file mode 100644
index 0000000000000000000000000000000000000000..f3020fd7e9e664b9ac1c8bc1c50e7ff73d7750e3
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_hw.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "hw.h"
+#include "ar9003_mac.h"
+#include "ar9003_2p2_initvals.h"
+#include "ar9485_initvals.h"
+#include "ar9340_initvals.h"
+
+/* General hardware code for the AR9003 hadware family */
+
+/*
+ * The AR9003 family uses a new INI format (pre, core, post
+ * arrays per subsystem). This provides support for the
+ * AR9003 2.2 chipsets.
+ */
+static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
+{
+	if (AR_SREV_9340(ah)) {
+		/* mac */
+		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+				ar9340_1p0_mac_core,
+				ARRAY_SIZE(ar9340_1p0_mac_core), 2);
+		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+				ar9340_1p0_mac_postamble,
+				ARRAY_SIZE(ar9340_1p0_mac_postamble), 5);
+
+		/* bb */
+		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+				ar9340_1p0_baseband_core,
+				ARRAY_SIZE(ar9340_1p0_baseband_core), 2);
+		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+				ar9340_1p0_baseband_postamble,
+				ARRAY_SIZE(ar9340_1p0_baseband_postamble), 5);
+
+		/* radio */
+		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+				ar9340_1p0_radio_core,
+				ARRAY_SIZE(ar9340_1p0_radio_core), 2);
+		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+				ar9340_1p0_radio_postamble,
+				ARRAY_SIZE(ar9340_1p0_radio_postamble), 5);
+
+		/* soc */
+		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+				ar9340_1p0_soc_preamble,
+				ARRAY_SIZE(ar9340_1p0_soc_preamble), 2);
+		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+				ar9340_1p0_soc_postamble,
+				ARRAY_SIZE(ar9340_1p0_soc_postamble), 5);
+
+		/* rx/tx gain */
+		INIT_INI_ARRAY(&ah->iniModesRxGain,
+				ar9340Common_wo_xlna_rx_gain_table_1p0,
+				ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0),
+				5);
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
+				ar9340Modes_high_ob_db_tx_gain_table_1p0,
+				ARRAY_SIZE(ar9340Modes_high_ob_db_tx_gain_table_1p0),
+				5);
+
+		INIT_INI_ARRAY(&ah->iniModesAdditional,
+				ar9340Modes_fast_clock_1p0,
+				ARRAY_SIZE(ar9340Modes_fast_clock_1p0),
+				3);
+
+		INIT_INI_ARRAY(&ah->iniModesAdditional_40M,
+				ar9340_1p0_radio_core_40M,
+				ARRAY_SIZE(ar9340_1p0_radio_core_40M),
+				2);
+	} else if (AR_SREV_9485_11(ah)) {
+		/* mac */
+		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+				ar9485_1_1_mac_core,
+				ARRAY_SIZE(ar9485_1_1_mac_core), 2);
+		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+				ar9485_1_1_mac_postamble,
+				ARRAY_SIZE(ar9485_1_1_mac_postamble), 5);
+
+		/* bb */
+		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_1,
+				ARRAY_SIZE(ar9485_1_1), 2);
+		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+				ar9485_1_1_baseband_core,
+				ARRAY_SIZE(ar9485_1_1_baseband_core), 2);
+		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+				ar9485_1_1_baseband_postamble,
+				ARRAY_SIZE(ar9485_1_1_baseband_postamble), 5);
+
+		/* radio */
+		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+				ar9485_1_1_radio_core,
+				ARRAY_SIZE(ar9485_1_1_radio_core), 2);
+		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+				ar9485_1_1_radio_postamble,
+				ARRAY_SIZE(ar9485_1_1_radio_postamble), 2);
+
+		/* soc */
+		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+				ar9485_1_1_soc_preamble,
+				ARRAY_SIZE(ar9485_1_1_soc_preamble), 2);
+		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], NULL, 0, 0);
+
+		/* rx/tx gain */
+		INIT_INI_ARRAY(&ah->iniModesRxGain,
+				ar9485Common_wo_xlna_rx_gain_1_1,
+				ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2);
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
+				ar9485_modes_lowest_ob_db_tx_gain_1_1,
+				ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1),
+				5);
+
+		/* Load PCIE SERDES settings from INI */
+
+		/* Awake Setting */
+
+		INIT_INI_ARRAY(&ah->iniPcieSerdes,
+				ar9485_1_1_pcie_phy_clkreq_disable_L1,
+				ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1),
+				2);
+
+		/* Sleep Setting */
+
+		INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
+				ar9485_1_1_pcie_phy_clkreq_disable_L1,
+				ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1),
+				2);
+	} else {
+		/* mac */
+		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+				ar9300_2p2_mac_core,
+				ARRAY_SIZE(ar9300_2p2_mac_core), 2);
+		INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+				ar9300_2p2_mac_postamble,
+				ARRAY_SIZE(ar9300_2p2_mac_postamble), 5);
+
+		/* bb */
+		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+				ar9300_2p2_baseband_core,
+				ARRAY_SIZE(ar9300_2p2_baseband_core), 2);
+		INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+				ar9300_2p2_baseband_postamble,
+				ARRAY_SIZE(ar9300_2p2_baseband_postamble), 5);
+
+		/* radio */
+		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+				ar9300_2p2_radio_core,
+				ARRAY_SIZE(ar9300_2p2_radio_core), 2);
+		INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+				ar9300_2p2_radio_postamble,
+				ARRAY_SIZE(ar9300_2p2_radio_postamble), 5);
+
+		/* soc */
+		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+				ar9300_2p2_soc_preamble,
+				ARRAY_SIZE(ar9300_2p2_soc_preamble), 2);
+		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
+		INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+				ar9300_2p2_soc_postamble,
+				ARRAY_SIZE(ar9300_2p2_soc_postamble), 5);
+
+		/* rx/tx gain */
+		INIT_INI_ARRAY(&ah->iniModesRxGain,
+				ar9300Common_rx_gain_table_2p2,
+				ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), 2);
+		INIT_INI_ARRAY(&ah->iniModesTxGain,
+				ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
+				ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
+				5);
+
+		/* Load PCIE SERDES settings from INI */
+
+		/* Awake Setting */
+
+		INIT_INI_ARRAY(&ah->iniPcieSerdes,
+				ar9300PciePhy_pll_on_clkreq_disable_L1_2p2,
+				ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p2),
+				2);
+
+		/* Sleep Setting */
+
+		INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
+				ar9300PciePhy_pll_on_clkreq_disable_L1_2p2,
+				ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p2),
+				2);
+
+		/* Fast clock modal settings */
+		INIT_INI_ARRAY(&ah->iniModesAdditional,
+				ar9300Modes_fast_clock_2p2,
+				ARRAY_SIZE(ar9300Modes_fast_clock_2p2),
+				3);
+	}
+}
+
+static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
+{
+	switch (ar9003_hw_get_tx_gain_idx(ah)) {
+	case 0:
+	default:
+		if (AR_SREV_9340(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+					ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+				       ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
+				       5);
+		else if (AR_SREV_9485_11(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				       ar9485_modes_lowest_ob_db_tx_gain_1_1,
+				       ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1),
+				       5);
+		else
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				       ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
+				       ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
+				       5);
+		break;
+	case 1:
+		if (AR_SREV_9340(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+					ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+				       ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
+				       5);
+		else if (AR_SREV_9485_11(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				       ar9485Modes_high_ob_db_tx_gain_1_1,
+				       ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1),
+				       5);
+		else
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				       ar9300Modes_high_ob_db_tx_gain_table_2p2,
+				       ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2),
+				       5);
+		break;
+	case 2:
+		if (AR_SREV_9340(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+					ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+				       ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
+				       5);
+		else if (AR_SREV_9485_11(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				       ar9485Modes_low_ob_db_tx_gain_1_1,
+				       ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1),
+				       5);
+		else
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				       ar9300Modes_low_ob_db_tx_gain_table_2p2,
+				       ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2),
+				       5);
+		break;
+	case 3:
+		if (AR_SREV_9340(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+					ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+				       ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
+				       5);
+		else if (AR_SREV_9485_11(ah))
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				       ar9485Modes_high_power_tx_gain_1_1,
+				       ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1),
+				       5);
+		else
+			INIT_INI_ARRAY(&ah->iniModesTxGain,
+				       ar9300Modes_high_power_tx_gain_table_2p2,
+				       ARRAY_SIZE(ar9300Modes_high_power_tx_gain_table_2p2),
+				       5);
+		break;
+	}
+}
+
+static void ar9003_rx_gain_table_apply(struct ath_hw *ah)
+{
+	switch (ar9003_hw_get_rx_gain_idx(ah)) {
+	case 0:
+	default:
+		if (AR_SREV_9340(ah))
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+				       ar9340Common_rx_gain_table_1p0,
+				       ARRAY_SIZE(ar9340Common_rx_gain_table_1p0),
+				       2);
+		else if (AR_SREV_9485_11(ah))
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+				       ar9485Common_wo_xlna_rx_gain_1_1,
+				       ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
+				       2);
+		else
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+				       ar9300Common_rx_gain_table_2p2,
+				       ARRAY_SIZE(ar9300Common_rx_gain_table_2p2),
+				       2);
+		break;
+	case 1:
+		if (AR_SREV_9340(ah))
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+				       ar9340Common_wo_xlna_rx_gain_table_1p0,
+				       ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0),
+				       2);
+		else if (AR_SREV_9485_11(ah))
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+				       ar9485Common_wo_xlna_rx_gain_1_1,
+				       ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
+				       2);
+		else
+			INIT_INI_ARRAY(&ah->iniModesRxGain,
+				       ar9300Common_wo_xlna_rx_gain_table_2p2,
+				       ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2),
+				       2);
+		break;
+	}
+}
+
+/* set gain table pointers according to values read from the eeprom */
+static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah)
+{
+	ar9003_tx_gain_table_apply(ah);
+	ar9003_rx_gain_table_apply(ah);
+}
+
+/*
+ * Helper for ASPM support.
+ *
+ * Disable PLL when in L0s as well as receiver clock when in L1.
+ * This power saving option must be enabled through the SerDes.
+ *
+ * Programming the SerDes must go through the same 288 bit serial shift
+ * register as the other analog registers.  Hence the 9 writes.
+ */
+static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
+					 int restore,
+					 int power_off)
+{
+	if (ah->is_pciexpress != 1)
+		return;
+
+	/* Do not touch SerDes registers */
+	if (ah->config.pcie_powersave_enable == 2)
+		return;
+
+	/* Nothing to do on restore for 11N */
+	if (!restore) {
+		/* set bit 19 to allow forcing of pcie core into L1 state */
+		REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+
+		/* Several PCIe massages to ensure proper behaviour */
+		if (ah->config.pcie_waen)
+			REG_WRITE(ah, AR_WA, ah->config.pcie_waen);
+		else
+			REG_WRITE(ah, AR_WA, ah->WARegVal);
+	}
+
+	/*
+	 * Configire PCIE after Ini init. SERDES values now come from ini file
+	 * This enables PCIe low power mode.
+	 */
+	if (ah->config.pcieSerDesWrite) {
+		unsigned int i;
+		struct ar5416IniArray *array;
+
+		array = power_off ? &ah->iniPcieSerdes :
+				    &ah->iniPcieSerdesLowPower;
+
+		for (i = 0; i < array->ia_rows; i++) {
+			REG_WRITE(ah,
+				  INI_RA(array, i, 0),
+				  INI_RA(array, i, 1));
+		}
+	}
+}
+
+/* Sets up the AR9003 hardware familiy callbacks */
+void ar9003_hw_attach_ops(struct ath_hw *ah)
+{
+	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+	priv_ops->init_mode_regs = ar9003_hw_init_mode_regs;
+	priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs;
+
+	ops->config_pci_powersave = ar9003_hw_configpcipowersave;
+
+	ar9003_hw_attach_phy_ops(ah);
+	ar9003_hw_attach_calib_ops(ah);
+	ar9003_hw_attach_mac_ops(ah);
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_mac.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_mac.c
new file mode 100644
index 0000000000000000000000000000000000000000..1fa4039ccead97dea0cef920c4c17a1447205270
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_mac.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <ipxe/io.h>
+
+#include "hw.h"
+#include "ar9003_mac.h"
+
+static void ar9003_hw_rx_enable(struct ath_hw *hw)
+{
+	REG_WRITE(hw, AR_CR, 0);
+}
+
+static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads)
+{
+	int checksum;
+
+	checksum = ads->info + ads->link
+		+ ads->data0 + ads->ctl3
+		+ ads->data1 + ads->ctl5
+		+ ads->data2 + ads->ctl7
+		+ ads->data3 + ads->ctl9;
+
+	return ((checksum & 0xffff) + (checksum >> 16)) & AR_TxPtrChkSum;
+}
+
+static void ar9003_hw_set_desc_link(void *ds, u32 ds_link)
+{
+	struct ar9003_txc *ads = ds;
+
+	ads->link = ds_link;
+	ads->ctl10 &= ~AR_TxPtrChkSum;
+	ads->ctl10 |= ar9003_calc_ptr_chksum(ads);
+}
+
+static void ar9003_hw_get_desc_link(void *ds, u32 **ds_link)
+{
+	struct ar9003_txc *ads = ds;
+
+	*ds_link = &ads->link;
+}
+
+static int ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
+{
+	u32 isr = 0;
+	u32 mask2 = 0;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
+	u32 sync_cause = 0;
+
+	if (ah->ah_ier & AR_IER_ENABLE) {
+		if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
+			if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M)
+					== AR_RTC_STATUS_ON)
+				isr = REG_READ(ah, AR_ISR);
+		}
+
+		sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT;
+
+		*masked = 0;
+
+		if (!isr && !sync_cause)
+			return 0;
+	} else {
+		*masked = 0;
+		isr = REG_READ(ah, AR_ISR);
+	}
+
+	if (isr) {
+		if (isr & AR_ISR_BCNMISC) {
+			u32 isr2;
+			isr2 = REG_READ(ah, AR_ISR_S2);
+
+			mask2 |= ((isr2 & AR_ISR_S2_TIM) >>
+				  MAP_ISR_S2_TIM);
+			mask2 |= ((isr2 & AR_ISR_S2_DTIM) >>
+				  MAP_ISR_S2_DTIM);
+			mask2 |= ((isr2 & AR_ISR_S2_DTIMSYNC) >>
+				  MAP_ISR_S2_DTIMSYNC);
+			mask2 |= ((isr2 & AR_ISR_S2_CABEND) >>
+				  MAP_ISR_S2_CABEND);
+			mask2 |= ((isr2 & AR_ISR_S2_GTT) <<
+				  MAP_ISR_S2_GTT);
+			mask2 |= ((isr2 & AR_ISR_S2_CST) <<
+				  MAP_ISR_S2_CST);
+			mask2 |= ((isr2 & AR_ISR_S2_TSFOOR) >>
+				  MAP_ISR_S2_TSFOOR);
+			mask2 |= ((isr2 & AR_ISR_S2_BB_WATCHDOG) >>
+				  MAP_ISR_S2_BB_WATCHDOG);
+
+			if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
+				REG_WRITE(ah, AR_ISR_S2, isr2);
+				isr &= ~AR_ISR_BCNMISC;
+			}
+		}
+
+		if ((pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED))
+			isr = REG_READ(ah, AR_ISR_RAC);
+
+		if (isr == 0xffffffff) {
+			*masked = 0;
+			return 0;
+		}
+
+		*masked = isr & ATH9K_INT_COMMON;
+
+		if (ah->config.rx_intr_mitigation)
+			if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
+				*masked |= ATH9K_INT_RXLP;
+
+		if (ah->config.tx_intr_mitigation)
+			if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM))
+				*masked |= ATH9K_INT_TX;
+
+		if (isr & (AR_ISR_LP_RXOK | AR_ISR_RXERR))
+			*masked |= ATH9K_INT_RXLP;
+
+		if (isr & AR_ISR_HP_RXOK)
+			*masked |= ATH9K_INT_RXHP;
+
+		if (isr & (AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL)) {
+			*masked |= ATH9K_INT_TX;
+
+			if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
+				u32 s0, s1;
+				s0 = REG_READ(ah, AR_ISR_S0);
+				REG_WRITE(ah, AR_ISR_S0, s0);
+				s1 = REG_READ(ah, AR_ISR_S1);
+				REG_WRITE(ah, AR_ISR_S1, s1);
+
+				isr &= ~(AR_ISR_TXOK | AR_ISR_TXERR |
+					 AR_ISR_TXEOL);
+			}
+		}
+
+		if (isr & AR_ISR_GENTMR) {
+			u32 s5;
+
+			if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)
+				s5 = REG_READ(ah, AR_ISR_S5_S);
+			else
+				s5 = REG_READ(ah, AR_ISR_S5);
+
+			ah->intr_gen_timer_trigger =
+				MS(s5, AR_ISR_S5_GENTIMER_TRIG);
+
+			ah->intr_gen_timer_thresh =
+				MS(s5, AR_ISR_S5_GENTIMER_THRESH);
+
+			if (ah->intr_gen_timer_trigger)
+				*masked |= ATH9K_INT_GENTIMER;
+
+			if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
+				REG_WRITE(ah, AR_ISR_S5, s5);
+				isr &= ~AR_ISR_GENTMR;
+			}
+
+		}
+
+		*masked |= mask2;
+
+		if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
+			REG_WRITE(ah, AR_ISR, isr);
+
+			(void) REG_READ(ah, AR_ISR);
+		}
+	}
+
+	if (sync_cause) {
+		if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
+			REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
+			REG_WRITE(ah, AR_RC, 0);
+			*masked |= ATH9K_INT_FATAL;
+		}
+
+		if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT)
+			DBG("ath9k: "
+				"AR_INTR_SYNC_LOCAL_TIMEOUT\n");
+
+		REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
+		(void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
+
+	}
+	return 1;
+}
+
+static void ar9003_hw_fill_txdesc(struct ath_hw *ah __unused, void *ds, u32 seglen,
+				  int is_firstseg, int is_lastseg,
+				  const void *ds0, u32 buf_addr,
+				  unsigned int qcu)
+{
+	struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+	unsigned int descid = 0;
+
+	ads->info = (ATHEROS_VENDOR_ID << AR_DescId_S) |
+				     (1 << AR_TxRxDesc_S) |
+				     (1 << AR_CtrlStat_S) |
+				     (qcu << AR_TxQcuNum_S) | 0x17;
+
+	ads->data0 = buf_addr;
+	ads->data1 = 0;
+	ads->data2 = 0;
+	ads->data3 = 0;
+
+	ads->ctl3 = (seglen << AR_BufLen_S);
+	ads->ctl3 &= AR_BufLen;
+
+	/* Fill in pointer checksum and descriptor id */
+	ads->ctl10 = ar9003_calc_ptr_chksum(ads);
+	ads->ctl10 |= (descid << AR_TxDescId_S);
+
+	if (is_firstseg) {
+		ads->ctl12 |= (is_lastseg ? 0 : AR_TxMore);
+	} else if (is_lastseg) {
+		ads->ctl11 = 0;
+		ads->ctl12 = 0;
+		ads->ctl13 = AR9003TXC_CONST(ds0)->ctl13;
+		ads->ctl14 = AR9003TXC_CONST(ds0)->ctl14;
+	} else {
+		/* XXX Intermediate descriptor in a multi-descriptor frame.*/
+		ads->ctl11 = 0;
+		ads->ctl12 = AR_TxMore;
+		ads->ctl13 = 0;
+		ads->ctl14 = 0;
+	}
+}
+
+static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds __unused,
+				 struct ath_tx_status *ts)
+{
+	struct ar9003_txs *ads;
+	u32 status;
+
+	ads = &ah->ts_ring[ah->ts_tail];
+
+	status = *(volatile typeof(ads->status8) *)&(ads->status8);
+	if ((status & AR_TxDone) == 0)
+		return -EINPROGRESS;
+
+	ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size;
+
+	if ((MS(ads->ds_info, AR_DescId) != ATHEROS_VENDOR_ID) ||
+	    (MS(ads->ds_info, AR_TxRxDesc) != 1)) {
+		DBG("ath9k: "
+			"Tx Descriptor error %x\n", ads->ds_info);
+		memset(ads, 0, sizeof(*ads));
+		return -EIO;
+	}
+
+	if (status & AR_TxOpExceeded)
+		ts->ts_status |= ATH9K_TXERR_XTXOP;
+	ts->ts_rateindex = MS(status, AR_FinalTxIdx);
+	ts->ts_seqnum = MS(status, AR_SeqNum);
+	ts->tid = MS(status, AR_TxTid);
+
+	ts->qid = MS(ads->ds_info, AR_TxQcuNum);
+	ts->desc_id = MS(ads->status1, AR_TxDescId);
+	ts->ts_tstamp = ads->status4;
+	ts->ts_status = 0;
+	ts->ts_flags  = 0;
+
+	status = *(volatile typeof(ads->status2) *)&(ads->status2);
+	ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00);
+	ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01);
+	ts->ts_rssi_ctl2 = MS(status, AR_TxRSSIAnt02);
+	if (status & AR_TxBaStatus) {
+		ts->ts_flags |= ATH9K_TX_BA;
+		ts->ba_low = ads->status5;
+		ts->ba_high = ads->status6;
+	}
+
+	status = *(volatile typeof(ads->status3) *)&(ads->status3);
+	if (status & AR_ExcessiveRetries)
+		ts->ts_status |= ATH9K_TXERR_XRETRY;
+	if (status & AR_Filtered)
+		ts->ts_status |= ATH9K_TXERR_FILT;
+	if (status & AR_FIFOUnderrun) {
+		ts->ts_status |= ATH9K_TXERR_FIFO;
+		ath9k_hw_updatetxtriglevel(ah, 1);
+	}
+	if (status & AR_TxTimerExpired)
+		ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
+	if (status & AR_DescCfgErr)
+		ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR;
+	if (status & AR_TxDataUnderrun) {
+		ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN;
+		ath9k_hw_updatetxtriglevel(ah, 1);
+	}
+	if (status & AR_TxDelimUnderrun) {
+		ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
+		ath9k_hw_updatetxtriglevel(ah, 1);
+	}
+	ts->ts_shortretry = MS(status, AR_RTSFailCnt);
+	ts->ts_longretry = MS(status, AR_DataFailCnt);
+	ts->ts_virtcol = MS(status, AR_VirtRetryCnt);
+
+	status = *(volatile typeof(ads->status7) *)&(ads->status7);
+	ts->ts_rssi = MS(status, AR_TxRSSICombined);
+	ts->ts_rssi_ext0 = MS(status, AR_TxRSSIAnt10);
+	ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11);
+	ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12);
+
+	memset(ads, 0, sizeof(*ads));
+
+	return 0;
+}
+
+static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
+		u32 pktlen, enum ath9k_pkt_type type, u32 txpower,
+		u32 keyIx, enum ath9k_key_type keyType, u32 flags)
+{
+	struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+
+	if (txpower > ah->txpower_limit)
+		txpower = ah->txpower_limit;
+
+	if (txpower > 63)
+		txpower = 63;
+
+	ads->ctl11 = (pktlen & AR_FrameLen)
+		| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
+		| SM(txpower, AR_XmitPower)
+		| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
+		| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
+		| (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0);
+
+	ads->ctl12 =
+		(keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
+		| SM(type, AR_FrameType)
+		| (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
+		| (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
+		| (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
+
+	ads->ctl17 = SM(keyType, AR_EncrType) |
+		     (flags & ATH9K_TXDESC_LDPC ? AR_LDPC : 0);
+	ads->ctl18 = 0;
+	ads->ctl19 = AR_Not_Sounding;
+
+	ads->ctl20 = 0;
+	ads->ctl21 = 0;
+	ads->ctl22 = 0;
+}
+
+static void ar9003_hw_set_clrdmask(struct ath_hw *ah __unused, void *ds, int val)
+{
+	struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+
+	if (val)
+		ads->ctl11 |= AR_ClrDestMask;
+	else
+		ads->ctl11 &= ~AR_ClrDestMask;
+}
+
+static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah __unused, void *ds,
+					  void *lastds,
+					  u32 durUpdateEn, u32 rtsctsRate,
+					  u32 rtsctsDuration __unused,
+					  struct ath9k_11n_rate_series series[],
+					  u32 nseries __unused, u32 flags)
+{
+	struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+	struct ar9003_txc *last_ads = (struct ar9003_txc *) lastds;
+	uint32_t ctl11;
+
+	if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
+		ctl11 = ads->ctl11;
+
+		if (flags & ATH9K_TXDESC_RTSENA) {
+			ctl11 &= ~AR_CTSEnable;
+			ctl11 |= AR_RTSEnable;
+		} else {
+			ctl11 &= ~AR_RTSEnable;
+			ctl11 |= AR_CTSEnable;
+		}
+
+		ads->ctl11 = ctl11;
+	} else {
+		ads->ctl11 = (ads->ctl11 & ~(AR_RTSEnable | AR_CTSEnable));
+	}
+
+	ads->ctl13 = set11nTries(series, 0)
+		|  set11nTries(series, 1)
+		|  set11nTries(series, 2)
+		|  set11nTries(series, 3)
+		|  (durUpdateEn ? AR_DurUpdateEna : 0)
+		|  SM(0, AR_BurstDur);
+
+	ads->ctl14 = set11nRate(series, 0)
+		|  set11nRate(series, 1)
+		|  set11nRate(series, 2)
+		|  set11nRate(series, 3);
+
+	ads->ctl15 = set11nPktDurRTSCTS(series, 0)
+		|  set11nPktDurRTSCTS(series, 1);
+
+	ads->ctl16 = set11nPktDurRTSCTS(series, 2)
+		|  set11nPktDurRTSCTS(series, 3);
+
+	ads->ctl18 = set11nRateFlags(series, 0)
+		|  set11nRateFlags(series, 1)
+		|  set11nRateFlags(series, 2)
+		|  set11nRateFlags(series, 3)
+		| SM(rtsctsRate, AR_RTSCTSRate);
+	ads->ctl19 = AR_Not_Sounding;
+
+	last_ads->ctl13 = ads->ctl13;
+	last_ads->ctl14 = ads->ctl14;
+}
+
+static void ar9003_hw_set11n_aggr_first(struct ath_hw *ah, void *ds,
+					u32 aggrLen)
+{
+#define FIRST_DESC_NDELIMS 60
+	struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+
+	ads->ctl12 |= (AR_IsAggr | AR_MoreAggr);
+
+	if (ah->ent_mode & AR_ENT_OTP_MPSD) {
+		u32 ctl17, ndelim;
+		/*
+		 * Add delimiter when using RTS/CTS with aggregation
+		 * and non enterprise AR9003 card
+		 */
+		ctl17 = ads->ctl17;
+		ndelim = MS(ctl17, AR_PadDelim);
+
+		if (ndelim < FIRST_DESC_NDELIMS) {
+			aggrLen += (FIRST_DESC_NDELIMS - ndelim) * 4;
+			ndelim = FIRST_DESC_NDELIMS;
+		}
+
+		ctl17 &= ~AR_AggrLen;
+		ctl17 |= SM(aggrLen, AR_AggrLen);
+
+		ctl17 &= ~AR_PadDelim;
+		ctl17 |= SM(ndelim, AR_PadDelim);
+
+		ads->ctl17 = ctl17;
+	} else {
+		ads->ctl17 &= ~AR_AggrLen;
+		ads->ctl17 |= SM(aggrLen, AR_AggrLen);
+	}
+}
+
+static void ar9003_hw_set11n_aggr_middle(struct ath_hw *ah __unused, void *ds,
+					 u32 numDelims)
+{
+	struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+	unsigned int ctl17;
+
+	ads->ctl12 |= (AR_IsAggr | AR_MoreAggr);
+
+	/*
+	 * We use a stack variable to manipulate ctl6 to reduce uncached
+	 * read modify, modfiy, write.
+	 */
+	ctl17 = ads->ctl17;
+	ctl17 &= ~AR_PadDelim;
+	ctl17 |= SM(numDelims, AR_PadDelim);
+	ads->ctl17 = ctl17;
+}
+
+static void ar9003_hw_set11n_aggr_last(struct ath_hw *ah __unused, void *ds)
+{
+	struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+
+	ads->ctl12 |= AR_IsAggr;
+	ads->ctl12 &= ~AR_MoreAggr;
+	ads->ctl17 &= ~AR_PadDelim;
+}
+
+static void ar9003_hw_clr11n_aggr(struct ath_hw *ah __unused, void *ds)
+{
+	struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+
+	ads->ctl12 &= (~AR_IsAggr & ~AR_MoreAggr);
+}
+
+void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah __unused, void *ds, u8 chains)
+{
+	struct ar9003_txc *ads = ds;
+
+	ads->ctl12 |= SM(chains, AR_PAPRDChainMask);
+}
+
+void ar9003_hw_attach_mac_ops(struct ath_hw *hw)
+{
+	struct ath_hw_ops *ops = ath9k_hw_ops(hw);
+
+	ops->rx_enable = ar9003_hw_rx_enable;
+	ops->set_desc_link = ar9003_hw_set_desc_link;
+	ops->get_desc_link = ar9003_hw_get_desc_link;
+	ops->get_isr = ar9003_hw_get_isr;
+	ops->fill_txdesc = ar9003_hw_fill_txdesc;
+	ops->proc_txdesc = ar9003_hw_proc_txdesc;
+	ops->set11n_txdesc = ar9003_hw_set11n_txdesc;
+	ops->set11n_ratescenario = ar9003_hw_set11n_ratescenario;
+	ops->set11n_aggr_first = ar9003_hw_set11n_aggr_first;
+	ops->set11n_aggr_middle = ar9003_hw_set11n_aggr_middle;
+	ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last;
+	ops->clr11n_aggr = ar9003_hw_clr11n_aggr;
+	ops->set_clrdmask = ar9003_hw_set_clrdmask;
+}
+
+void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size)
+{
+	REG_WRITE(ah, AR_DATABUF_SIZE, buf_size & AR_DATABUF_SIZE_MASK);
+}
+
+void ath9k_hw_addrxbuf_edma(struct ath_hw *ah, u32 rxdp,
+			    enum ath9k_rx_qtype qtype)
+{
+	if (qtype == ATH9K_RX_QUEUE_HP)
+		REG_WRITE(ah, AR_HP_RXDP, rxdp);
+	else
+		REG_WRITE(ah, AR_LP_RXDP, rxdp);
+}
+
+int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah __unused, struct ath_rx_status *rxs,
+				 void *buf_addr)
+{
+	struct ar9003_rxs *rxsp = (struct ar9003_rxs *) buf_addr;
+	unsigned int phyerr;
+
+	/* TODO: byte swap on big endian for ar9300_10 */
+
+	if ((rxsp->status11 & AR_RxDone) == 0)
+		return -EINPROGRESS;
+
+	if (MS(rxsp->ds_info, AR_DescId) != 0x168c)
+		return -EINVAL;
+
+	if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0)
+		return -EINPROGRESS;
+
+	if (!rxs)
+		return 0;
+
+	rxs->rs_status = 0;
+	rxs->rs_flags =  0;
+
+	rxs->rs_datalen = rxsp->status2 & AR_DataLen;
+	rxs->rs_tstamp =  rxsp->status3;
+
+	/* XXX: Keycache */
+	rxs->rs_rssi = MS(rxsp->status5, AR_RxRSSICombined);
+	rxs->rs_rssi_ctl0 = MS(rxsp->status1, AR_RxRSSIAnt00);
+	rxs->rs_rssi_ctl1 = MS(rxsp->status1, AR_RxRSSIAnt01);
+	rxs->rs_rssi_ctl2 = MS(rxsp->status1, AR_RxRSSIAnt02);
+	rxs->rs_rssi_ext0 = MS(rxsp->status5, AR_RxRSSIAnt10);
+	rxs->rs_rssi_ext1 = MS(rxsp->status5, AR_RxRSSIAnt11);
+	rxs->rs_rssi_ext2 = MS(rxsp->status5, AR_RxRSSIAnt12);
+
+	if (rxsp->status11 & AR_RxKeyIdxValid)
+		rxs->rs_keyix = MS(rxsp->status11, AR_KeyIdx);
+	else
+		rxs->rs_keyix = ATH9K_RXKEYIX_INVALID;
+
+	rxs->rs_rate = MS(rxsp->status1, AR_RxRate);
+	rxs->rs_more = (rxsp->status2 & AR_RxMore) ? 1 : 0;
+
+	rxs->rs_isaggr = (rxsp->status11 & AR_RxAggr) ? 1 : 0;
+	rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0;
+	rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7);
+	rxs->rs_flags  = (rxsp->status4 & AR_GI) ? ATH9K_RX_GI : 0;
+	rxs->rs_flags  |= (rxsp->status4 & AR_2040) ? ATH9K_RX_2040 : 0;
+
+	rxs->evm0 = rxsp->status6;
+	rxs->evm1 = rxsp->status7;
+	rxs->evm2 = rxsp->status8;
+	rxs->evm3 = rxsp->status9;
+	rxs->evm4 = (rxsp->status10 & 0xffff);
+
+	if (rxsp->status11 & AR_PreDelimCRCErr)
+		rxs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
+
+	if (rxsp->status11 & AR_PostDelimCRCErr)
+		rxs->rs_flags |= ATH9K_RX_DELIM_CRC_POST;
+
+	if (rxsp->status11 & AR_DecryptBusyErr)
+		rxs->rs_flags |= ATH9K_RX_DECRYPT_BUSY;
+
+	if ((rxsp->status11 & AR_RxFrameOK) == 0) {
+		/*
+		 * AR_CRCErr will bet set to true if we're on the last
+		 * subframe and the AR_PostDelimCRCErr is caught.
+		 * In a way this also gives us a guarantee that when
+		 * (!(AR_CRCErr) && (AR_PostDelimCRCErr)) we cannot
+		 * possibly be reviewing the last subframe. AR_CRCErr
+		 * is the CRC of the actual data.
+		 */
+		if (rxsp->status11 & AR_CRCErr)
+			rxs->rs_status |= ATH9K_RXERR_CRC;
+		else if (rxsp->status11 & AR_PHYErr) {
+			phyerr = MS(rxsp->status11, AR_PHYErrCode);
+			/*
+			 * If we reach a point here where AR_PostDelimCRCErr is
+			 * true it implies we're *not* on the last subframe. In
+			 * in that case that we know already that the CRC of
+			 * the frame was OK, and MAC would send an ACK for that
+			 * subframe, even if we did get a phy error of type
+			 * ATH9K_PHYERR_OFDM_RESTART. This is only applicable
+			 * to frame that are prior to the last subframe.
+			 * The AR_PostDelimCRCErr is the CRC for the MPDU
+			 * delimiter, which contains the 4 reserved bits,
+			 * the MPDU length (12 bits), and follows the MPDU
+			 * delimiter for an A-MPDU subframe (0x4E = 'N' ASCII).
+			 */
+			if ((phyerr == ATH9K_PHYERR_OFDM_RESTART) &&
+			    (rxsp->status11 & AR_PostDelimCRCErr)) {
+				rxs->rs_phyerr = 0;
+			} else {
+				rxs->rs_status |= ATH9K_RXERR_PHY;
+				rxs->rs_phyerr = phyerr;
+			}
+
+		} else if (rxsp->status11 & AR_DecryptCRCErr)
+			rxs->rs_status |= ATH9K_RXERR_DECRYPT;
+		else if (rxsp->status11 & AR_MichaelErr)
+			rxs->rs_status |= ATH9K_RXERR_MIC;
+		else if (rxsp->status11 & AR_KeyMiss)
+			rxs->rs_status |= ATH9K_RXERR_DECRYPT;
+	}
+
+	return 0;
+}
+
+void ath9k_hw_reset_txstatus_ring(struct ath_hw *ah)
+{
+	ah->ts_tail = 0;
+
+	memset((void *) ah->ts_ring, 0,
+		ah->ts_size * sizeof(struct ar9003_txs));
+
+	DBG2("ath9k: "
+		"TS Start 0x%x End 0x%x Virt %p, Size %d\n",
+		ah->ts_paddr_start, ah->ts_paddr_end,
+		ah->ts_ring, ah->ts_size);
+
+	REG_WRITE(ah, AR_Q_STATUS_RING_START, ah->ts_paddr_start);
+	REG_WRITE(ah, AR_Q_STATUS_RING_END, ah->ts_paddr_end);
+}
+
+void ath9k_hw_setup_statusring(struct ath_hw *ah, void *ts_start,
+			       u32 ts_paddr_start,
+			       u8 size)
+{
+
+	ah->ts_paddr_start = ts_paddr_start;
+	ah->ts_paddr_end = ts_paddr_start + (size * sizeof(struct ar9003_txs));
+	ah->ts_size = size;
+	ah->ts_ring = (struct ar9003_txs *) ts_start;
+
+	ath9k_hw_reset_txstatus_ring(ah);
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_phy.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_phy.c
new file mode 100644
index 0000000000000000000000000000000000000000..6103040abfb2b868cef7a02052bfabaf31ca8d09
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_ar9003_phy.c
@@ -0,0 +1,1277 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/io.h>
+
+#include "hw.h"
+#include "ar9003_phy.h"
+
+static const int firstep_table[] =
+/* level:  0   1   2   3   4   5   6   7   8  */
+	{ -4, -2,  0,  2,  4,  6,  8, 10, 12 }; /* lvl 0-8, default 2 */
+
+static const int cycpwrThr1_table[] =
+/* level:  0   1   2   3   4   5   6   7   8  */
+	{ -6, -4, -2,  0,  2,  4,  6,  8 };     /* lvl 0-7, default 3 */
+
+/*
+ * register values to turn OFDM weak signal detection OFF
+ */
+static const int m1ThreshLow_off = 127;
+static const int m2ThreshLow_off = 127;
+static const int m1Thresh_off = 127;
+static const int m2Thresh_off = 127;
+static const int m2CountThr_off =  31;
+static const int m2CountThrLow_off =  63;
+static const int m1ThreshLowExt_off = 127;
+static const int m2ThreshLowExt_off = 127;
+static const int m1ThreshExt_off = 127;
+static const int m2ThreshExt_off = 127;
+
+/**
+ * ar9003_hw_set_channel - set channel on single-chip device
+ * @ah: atheros hardware structure
+ * @chan:
+ *
+ * This is the function to change channel on single-chip devices, that is
+ * all devices after ar9280.
+ *
+ * This function takes the channel value in MHz and sets
+ * hardware channel value. Assumes writes have been enabled to analog bus.
+ *
+ * Actual Expression,
+ *
+ * For 2GHz channel,
+ * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17)
+ * (freq_ref = 40MHz)
+ *
+ * For 5GHz channel,
+ * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10)
+ * (freq_ref = 40MHz/(24>>amodeRefSel))
+ *
+ * For 5GHz channels which are 5MHz spaced,
+ * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17)
+ * (freq_ref = 40MHz)
+ */
+static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+	u16 bMode, fracMode = 0, aModeRefSel = 0;
+	u32 freq, channelSel = 0, reg32 = 0;
+	struct chan_centers centers;
+	int loadSynthChannel;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+	freq = centers.synth_center;
+
+	if (freq < 4800) {     /* 2 GHz, fractional mode */
+		if (AR_SREV_9485(ah)) {
+			u32 chan_frac;
+
+			/*
+			 * freq_ref = 40 / (refdiva >> amoderefsel); where refdiva=1 and amoderefsel=0
+			 * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
+			 * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000
+			 */
+			channelSel = (freq * 4) / 120;
+			chan_frac = (((freq * 4) % 120) * 0x20000) / 120;
+			channelSel = (channelSel << 17) | chan_frac;
+		} else if (AR_SREV_9340(ah)) {
+			if (ah->is_clk_25mhz) {
+				u32 chan_frac;
+
+				channelSel = (freq * 2) / 75;
+				chan_frac = (((freq * 2) % 75) * 0x20000) / 75;
+				channelSel = (channelSel << 17) | chan_frac;
+			} else
+				channelSel = CHANSEL_2G(freq) >> 1;
+		} else
+			channelSel = CHANSEL_2G(freq);
+		/* Set to 2G mode */
+		bMode = 1;
+	} else {
+		if (AR_SREV_9340(ah) && ah->is_clk_25mhz) {
+			u32 chan_frac;
+
+			channelSel = (freq * 2) / 75;
+			chan_frac = ((freq % 75) * 0x20000) / 75;
+			channelSel = (channelSel << 17) | chan_frac;
+		} else {
+			channelSel = CHANSEL_5G(freq);
+			/* Doubler is ON, so, divide channelSel by 2. */
+			channelSel >>= 1;
+		}
+		/* Set to 5G mode */
+		bMode = 0;
+	}
+
+	/* Enable fractional mode for all channels */
+	fracMode = 1;
+	aModeRefSel = 0;
+	loadSynthChannel = 0;
+
+	reg32 = (bMode << 29);
+	REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);
+
+	/* Enable Long shift Select for Synthesizer */
+	REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_SYNTH4,
+		      AR_PHY_SYNTH4_LONG_SHIFT_SELECT, 1);
+
+	/* Program Synth. setting */
+	reg32 = (channelSel << 2) | (fracMode << 30) |
+		(aModeRefSel << 28) | (loadSynthChannel << 31);
+	REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32);
+
+	/* Toggle Load Synth channel bit */
+	loadSynthChannel = 1;
+	reg32 = (channelSel << 2) | (fracMode << 30) |
+		(aModeRefSel << 28) | (loadSynthChannel << 31);
+	REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32);
+
+	ah->curchan = chan;
+	ah->curchan_rad_index = -1;
+
+	return 0;
+}
+
+/**
+ * ar9003_hw_spur_mitigate_mrc_cck - convert baseband spur frequency
+ * @ah: atheros hardware structure
+ * @chan:
+ *
+ * For single-chip solutions. Converts to baseband spur frequency given the
+ * input channel frequency and compute register settings below.
+ *
+ * Spur mitigation for MRC CCK
+ */
+static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
+					    struct ath9k_channel *chan)
+{
+	static const u32 spur_freq[4] = { 2420, 2440, 2464, 2480 };
+	int cur_bb_spur, negative = 0, cck_spur_freq;
+	int i;
+	int range, max_spur_cnts, synth_freq;
+	u8 *spur_fbin_ptr = NULL;
+
+	/*
+	 * Need to verify range +/- 10 MHz in control channel, otherwise spur
+	 * is out-of-band and can be ignored.
+	 */
+
+	if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) {
+		spur_fbin_ptr = ar9003_get_spur_chan_ptr(ah,
+							 IS_CHAN_2GHZ(chan));
+		if (spur_fbin_ptr[0] == 0) /* No spur */
+			return;
+		max_spur_cnts = 5;
+		if (IS_CHAN_HT40(chan)) {
+			range = 19;
+			if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL,
+					   AR_PHY_GC_DYN2040_PRI_CH) == 0)
+				synth_freq = chan->channel + 10;
+			else
+				synth_freq = chan->channel - 10;
+		} else {
+			range = 10;
+			synth_freq = chan->channel;
+		}
+	} else {
+		range = 10;
+		max_spur_cnts = 4;
+		synth_freq = chan->channel;
+	}
+
+	for (i = 0; i < max_spur_cnts; i++) {
+		negative = 0;
+		if (AR_SREV_9485(ah) || AR_SREV_9340(ah))
+			cur_bb_spur = FBIN2FREQ(spur_fbin_ptr[i],
+					IS_CHAN_2GHZ(chan)) - synth_freq;
+		else
+			cur_bb_spur = spur_freq[i] - synth_freq;
+
+		if (cur_bb_spur < 0) {
+			negative = 1;
+			cur_bb_spur = -cur_bb_spur;
+		}
+		if (cur_bb_spur < range) {
+			cck_spur_freq = (int)((cur_bb_spur << 19) / 11);
+
+			if (negative == 1)
+				cck_spur_freq = -cck_spur_freq;
+
+			cck_spur_freq = cck_spur_freq & 0xfffff;
+
+			REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL,
+				      AR_PHY_AGC_CONTROL_YCOK_MAX, 0x7);
+			REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT,
+				      AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR, 0x7f);
+			REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT,
+				      AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE,
+				      0x2);
+			REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT,
+				      AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT,
+				      0x1);
+			REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT,
+				      AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ,
+				      cck_spur_freq);
+
+			return;
+		}
+	}
+
+	REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL,
+		      AR_PHY_AGC_CONTROL_YCOK_MAX, 0x5);
+	REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT,
+		      AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT, 0x0);
+	REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT,
+		      AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, 0x0);
+}
+
+/* Clean all spur register fields */
+static void ar9003_hw_spur_ofdm_clear(struct ath_hw *ah)
+{
+	REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+		      AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+		      AR_PHY_TIMING11_SPUR_FREQ_SD, 0);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+		      AR_PHY_TIMING11_SPUR_DELTA_PHASE, 0);
+	REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+		      AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD, 0);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+		      AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+		      AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR, 0);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+		      AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0);
+	REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+		      AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 0);
+	REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+		      AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 0);
+
+	REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+		      AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+		      AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+		      AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0);
+	REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK,
+		      AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, 0);
+	REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A,
+		      AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, 0);
+	REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK,
+		      AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, 0);
+	REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK,
+		      AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0);
+	REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK,
+		      AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0);
+	REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A,
+		      AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0);
+	REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+		      AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0);
+}
+
+static void ar9003_hw_spur_ofdm(struct ath_hw *ah,
+				int freq_offset,
+				int spur_freq_sd,
+				int spur_delta_phase,
+				int spur_subchannel_sd)
+{
+	int mask_index = 0;
+
+	/* OFDM Spur mitigation */
+	REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+		 AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0x1);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+		      AR_PHY_TIMING11_SPUR_FREQ_SD, spur_freq_sd);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+		      AR_PHY_TIMING11_SPUR_DELTA_PHASE, spur_delta_phase);
+	REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+		      AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD, spur_subchannel_sd);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+		      AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0x1);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+		      AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR, 0x1);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+		      AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0x1);
+	REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+		      AR_PHY_SPUR_REG_SPUR_RSSI_THRESH, 34);
+	REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+		      AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 1);
+
+	if (REG_READ_FIELD(ah, AR_PHY_MODE,
+			   AR_PHY_MODE_DYNAMIC) == 0x1)
+		REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+			      AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 1);
+
+	mask_index = (freq_offset << 4) / 5;
+	if (mask_index < 0)
+		mask_index = mask_index - 1;
+
+	mask_index = mask_index & 0x7f;
+
+	REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+		      AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0x1);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+		      AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0x1);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+		      AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0x1);
+	REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK,
+		      AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, mask_index);
+	REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A,
+		      AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, mask_index);
+	REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK,
+		      AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, mask_index);
+	REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK,
+		      AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0xc);
+	REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK,
+		      AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0xc);
+	REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A,
+		      AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0xa0);
+	REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+		      AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0xff);
+}
+
+static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah,
+				     struct ath9k_channel *chan,
+				     int freq_offset)
+{
+	int spur_freq_sd = 0;
+	int spur_subchannel_sd = 0;
+	int spur_delta_phase = 0;
+
+	if (IS_CHAN_HT40(chan)) {
+		if (freq_offset < 0) {
+			if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL,
+					   AR_PHY_GC_DYN2040_PRI_CH) == 0x0)
+				spur_subchannel_sd = 1;
+			else
+				spur_subchannel_sd = 0;
+
+			spur_freq_sd = ((freq_offset + 10) << 9) / 11;
+
+		} else {
+			if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL,
+			    AR_PHY_GC_DYN2040_PRI_CH) == 0x0)
+				spur_subchannel_sd = 0;
+			else
+				spur_subchannel_sd = 1;
+
+			spur_freq_sd = ((freq_offset - 10) << 9) / 11;
+
+		}
+
+		spur_delta_phase = (freq_offset << 17) / 5;
+
+	} else {
+		spur_subchannel_sd = 0;
+		spur_freq_sd = (freq_offset << 9) /11;
+		spur_delta_phase = (freq_offset << 18) / 5;
+	}
+
+	spur_freq_sd = spur_freq_sd & 0x3ff;
+	spur_delta_phase = spur_delta_phase & 0xfffff;
+
+	ar9003_hw_spur_ofdm(ah,
+			    freq_offset,
+			    spur_freq_sd,
+			    spur_delta_phase,
+			    spur_subchannel_sd);
+}
+
+/* Spur mitigation for OFDM */
+static void ar9003_hw_spur_mitigate_ofdm(struct ath_hw *ah,
+					 struct ath9k_channel *chan)
+{
+	int synth_freq;
+	int range = 10;
+	int freq_offset = 0;
+	int mode;
+	u8* spurChansPtr;
+	unsigned int i;
+	struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+	if (IS_CHAN_5GHZ(chan)) {
+		spurChansPtr = &(eep->modalHeader5G.spurChans[0]);
+		mode = 0;
+	}
+	else {
+		spurChansPtr = &(eep->modalHeader2G.spurChans[0]);
+		mode = 1;
+	}
+
+	if (spurChansPtr[0] == 0)
+		return; /* No spur in the mode */
+
+	if (IS_CHAN_HT40(chan)) {
+		range = 19;
+		if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL,
+				   AR_PHY_GC_DYN2040_PRI_CH) == 0x0)
+			synth_freq = chan->channel - 10;
+		else
+			synth_freq = chan->channel + 10;
+	} else {
+		range = 10;
+		synth_freq = chan->channel;
+	}
+
+	ar9003_hw_spur_ofdm_clear(ah);
+
+	for (i = 0; i < AR_EEPROM_MODAL_SPURS && spurChansPtr[i]; i++) {
+		freq_offset = FBIN2FREQ(spurChansPtr[i], mode) - synth_freq;
+		if (abs(freq_offset) < range) {
+			ar9003_hw_spur_ofdm_work(ah, chan, freq_offset);
+			break;
+		}
+	}
+}
+
+static void ar9003_hw_spur_mitigate(struct ath_hw *ah,
+				    struct ath9k_channel *chan)
+{
+	ar9003_hw_spur_mitigate_mrc_cck(ah, chan);
+	ar9003_hw_spur_mitigate_ofdm(ah, chan);
+}
+
+static u32 ar9003_hw_compute_pll_control(struct ath_hw *ah __unused,
+					 struct ath9k_channel *chan)
+{
+	u32 pll;
+
+	pll = SM(0x5, AR_RTC_9300_PLL_REFDIV);
+
+	if (chan && IS_CHAN_HALF_RATE(chan))
+		pll |= SM(0x1, AR_RTC_9300_PLL_CLKSEL);
+	else if (chan && IS_CHAN_QUARTER_RATE(chan))
+		pll |= SM(0x2, AR_RTC_9300_PLL_CLKSEL);
+
+	pll |= SM(0x2c, AR_RTC_9300_PLL_DIV);
+
+	return pll;
+}
+
+static void ar9003_hw_set_channel_regs(struct ath_hw *ah,
+				       struct ath9k_channel *chan)
+{
+	u32 phymode;
+	u32 enableDacFifo = 0;
+
+	enableDacFifo =
+		(REG_READ(ah, AR_PHY_GEN_CTRL) & AR_PHY_GC_ENABLE_DAC_FIFO);
+
+	/* Enable 11n HT, 20 MHz */
+	phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 | AR_PHY_GC_WALSH |
+		  AR_PHY_GC_SHORT_GI_40 | enableDacFifo;
+
+	/* Configure baseband for dynamic 20/40 operation */
+	if (IS_CHAN_HT40(chan)) {
+		phymode |= AR_PHY_GC_DYN2040_EN;
+		/* Configure control (primary) channel at +-10MHz */
+		if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
+		    (chan->chanmode == CHANNEL_G_HT40PLUS))
+			phymode |= AR_PHY_GC_DYN2040_PRI_CH;
+
+	}
+
+	/* make sure we preserve INI settings */
+	phymode |= REG_READ(ah, AR_PHY_GEN_CTRL);
+	/* turn off Green Field detection for STA for now */
+	phymode &= ~AR_PHY_GC_GF_DETECT_EN;
+
+	REG_WRITE(ah, AR_PHY_GEN_CTRL, phymode);
+
+	/* Configure MAC for 20/40 operation */
+	ath9k_hw_set11nmac2040(ah);
+
+	/* global transmit timeout (25 TUs default)*/
+	REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
+	/* carrier sense timeout */
+	REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
+}
+
+static void ar9003_hw_init_bb(struct ath_hw *ah,
+			      struct ath9k_channel *chan)
+{
+	u32 synthDelay;
+
+	/*
+	 * Wait for the frequency synth to settle (synth goes on
+	 * via AR_PHY_ACTIVE_EN).  Read the phy active delay register.
+	 * Value is in 100ns increments.
+	 */
+	synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+	if (IS_CHAN_B(chan))
+		synthDelay = (4 * synthDelay) / 22;
+	else
+		synthDelay /= 10;
+
+	/* Activate the PHY (includes baseband activate + synthesizer on) */
+	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+	/*
+	 * There is an issue if the AP starts the calibration before
+	 * the base band timeout completes.  This could result in the
+	 * rx_clear false triggering.  As a workaround we add delay an
+	 * extra BASE_ACTIVATE_DELAY usecs to ensure this condition
+	 * does not happen.
+	 */
+	udelay(synthDelay + BASE_ACTIVATE_DELAY);
+}
+
+void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
+{
+	switch (rx) {
+	case 0x5:
+		REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+			    AR_PHY_SWAP_ALT_CHAIN);
+	case 0x3:
+	case 0x1:
+	case 0x2:
+	case 0x7:
+		REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx);
+		REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx);
+		break;
+	default:
+		break;
+	}
+
+	if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7))
+		REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
+	else
+		REG_WRITE(ah, AR_SELFGEN_MASK, tx);
+
+	if (tx == 0x5) {
+		REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+			    AR_PHY_SWAP_ALT_CHAIN);
+	}
+}
+
+/*
+ * Override INI values with chip specific configuration.
+ */
+static void ar9003_hw_override_ini(struct ath_hw *ah)
+{
+	u32 val;
+
+	/*
+	 * Set the RX_ABORT and RX_DIS and clear it only after
+	 * RXE is set for MAC. This prevents frames with
+	 * corrupted descriptor status.
+	 */
+	REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+
+	/*
+	 * For AR9280 and above, there is a new feature that allows
+	 * Multicast search based on both MAC Address and Key ID. By default,
+	 * this feature is enabled. But since the driver is not using this
+	 * feature, we switch it off; otherwise multicast search based on
+	 * MAC addr only will fail.
+	 */
+	val = REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE);
+	REG_WRITE(ah, AR_PCU_MISC_MODE2,
+		  val | AR_AGG_WEP_ENABLE_FIX | AR_AGG_WEP_ENABLE);
+}
+
+static void ar9003_hw_prog_ini(struct ath_hw *ah,
+			       struct ar5416IniArray *iniArr,
+			       int column)
+{
+	unsigned int i, regWrites = 0;
+
+	/* New INI format: Array may be undefined (pre, core, post arrays) */
+	if (!iniArr->ia_array)
+		return;
+
+	/*
+	 * New INI format: Pre, core, and post arrays for a given subsystem
+	 * may be modal (> 2 columns) or non-modal (2 columns). Determine if
+	 * the array is non-modal and force the column to 1.
+	 */
+	if ((unsigned int)column >= iniArr->ia_columns)
+		column = 1;
+
+	for (i = 0; i < iniArr->ia_rows; i++) {
+		u32 reg = INI_RA(iniArr, i, 0);
+		u32 val = INI_RA(iniArr, i, column);
+
+		REG_WRITE(ah, reg, val);
+
+		DO_DELAY(regWrites);
+	}
+}
+
+static int ar9003_hw_process_ini(struct ath_hw *ah,
+				 struct ath9k_channel *chan)
+{
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+	unsigned int regWrites = 0, i;
+	struct net80211_channel *channel = chan->chan;
+	u32 modesIndex;
+
+	switch (chan->chanmode) {
+	case CHANNEL_A:
+	case CHANNEL_A_HT20:
+		modesIndex = 1;
+		break;
+	case CHANNEL_A_HT40PLUS:
+	case CHANNEL_A_HT40MINUS:
+		modesIndex = 2;
+		break;
+	case CHANNEL_G:
+	case CHANNEL_G_HT20:
+	case CHANNEL_B:
+		modesIndex = 4;
+		break;
+	case CHANNEL_G_HT40PLUS:
+	case CHANNEL_G_HT40MINUS:
+		modesIndex = 3;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ATH_INI_NUM_SPLIT; i++) {
+		ar9003_hw_prog_ini(ah, &ah->iniSOC[i], modesIndex);
+		ar9003_hw_prog_ini(ah, &ah->iniMac[i], modesIndex);
+		ar9003_hw_prog_ini(ah, &ah->iniBB[i], modesIndex);
+		ar9003_hw_prog_ini(ah, &ah->iniRadio[i], modesIndex);
+	}
+
+	REG_WRITE_ARRAY(&ah->iniModesRxGain, 1, regWrites);
+	REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
+
+	/*
+	 * For 5GHz channels requiring Fast Clock, apply
+	 * different modal values.
+	 */
+	if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+		REG_WRITE_ARRAY(&ah->iniModesAdditional,
+				modesIndex, regWrites);
+
+	if (AR_SREV_9340(ah) && !ah->is_clk_25mhz)
+		REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites);
+
+	ar9003_hw_override_ini(ah);
+	ar9003_hw_set_channel_regs(ah, chan);
+	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
+
+	/* Set TX power */
+	ah->eep_ops->set_txpower(ah, chan,
+				 ath9k_regd_get_ctl(regulatory, chan),
+				 0,
+				 channel->maxpower * 2,
+				 min((u32) MAX_RATE_POWER,
+				 (u32) regulatory->power_limit), 0);
+
+	return 0;
+}
+
+static void ar9003_hw_set_rfmode(struct ath_hw *ah,
+				 struct ath9k_channel *chan)
+{
+	u32 rfMode = 0;
+
+	if (chan == NULL)
+		return;
+
+	rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
+		? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
+
+	if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+		rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
+
+	REG_WRITE(ah, AR_PHY_MODE, rfMode);
+}
+
+static void ar9003_hw_mark_phy_inactive(struct ath_hw *ah)
+{
+	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+}
+
+static void ar9003_hw_set_delta_slope(struct ath_hw *ah,
+				      struct ath9k_channel *chan)
+{
+	u32 coef_scaled, ds_coef_exp, ds_coef_man;
+	u32 clockMhzScaled = 0x64000000;
+	struct chan_centers centers;
+
+	/*
+	 * half and quarter rate can divide the scaled clock by 2 or 4
+	 * scale for selected channel bandwidth
+	 */
+	if (IS_CHAN_HALF_RATE(chan))
+		clockMhzScaled = clockMhzScaled >> 1;
+	else if (IS_CHAN_QUARTER_RATE(chan))
+		clockMhzScaled = clockMhzScaled >> 2;
+
+	/*
+	 * ALGO -> coef = 1e8/fcarrier*fclock/40;
+	 * scaled coef to provide precision for this floating calculation
+	 */
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+	coef_scaled = clockMhzScaled / centers.synth_center;
+
+	ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
+				      &ds_coef_exp);
+
+	REG_RMW_FIELD(ah, AR_PHY_TIMING3,
+		      AR_PHY_TIMING3_DSC_MAN, ds_coef_man);
+	REG_RMW_FIELD(ah, AR_PHY_TIMING3,
+		      AR_PHY_TIMING3_DSC_EXP, ds_coef_exp);
+
+	/*
+	 * For Short GI,
+	 * scaled coeff is 9/10 that of normal coeff
+	 */
+	coef_scaled = (9 * coef_scaled) / 10;
+
+	ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
+				      &ds_coef_exp);
+
+	/* for short gi */
+	REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA,
+		      AR_PHY_SGI_DSC_MAN, ds_coef_man);
+	REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA,
+		      AR_PHY_SGI_DSC_EXP, ds_coef_exp);
+}
+
+static int ar9003_hw_rfbus_req(struct ath_hw *ah)
+{
+	REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
+	return ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
+			     AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT);
+}
+
+/*
+ * Wait for the frequency synth to settle (synth goes on via PHY_ACTIVE_EN).
+ * Read the phy active delay register. Value is in 100ns increments.
+ */
+static void ar9003_hw_rfbus_done(struct ath_hw *ah)
+{
+	u32 synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+	if (IS_CHAN_B(ah->curchan))
+		synthDelay = (4 * synthDelay) / 22;
+	else
+		synthDelay /= 10;
+
+	udelay(synthDelay + BASE_ACTIVATE_DELAY);
+
+	REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
+}
+
+static void ar9003_hw_set_diversity(struct ath_hw *ah, int value)
+{
+	u32 v = REG_READ(ah, AR_PHY_CCK_DETECT);
+	if (value)
+		v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+	else
+		v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+	REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
+}
+
+static int ar9003_hw_ani_control(struct ath_hw *ah,
+				  enum ath9k_ani_cmd cmd, int param)
+{
+	struct ath9k_channel *chan = ah->curchan;
+	struct ar5416AniState *aniState = &chan->ani;
+	s32 value, value2;
+
+	switch (cmd & ah->ani_function) {
+	case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
+		/*
+		 * on == 1 means ofdm weak signal detection is ON
+		 * on == 1 is the default, for less noise immunity
+		 *
+		 * on == 0 means ofdm weak signal detection is OFF
+		 * on == 0 means more noise imm
+		 */
+		u32 on = param ? 1 : 0;
+		/*
+		 * make register setting for default
+		 * (weak sig detect ON) come from INI file
+		 */
+		int m1ThreshLow = on ?
+			aniState->iniDef.m1ThreshLow : m1ThreshLow_off;
+		int m2ThreshLow = on ?
+			aniState->iniDef.m2ThreshLow : m2ThreshLow_off;
+		int m1Thresh = on ?
+			aniState->iniDef.m1Thresh : m1Thresh_off;
+		int m2Thresh = on ?
+			aniState->iniDef.m2Thresh : m2Thresh_off;
+		int m2CountThr = on ?
+			aniState->iniDef.m2CountThr : m2CountThr_off;
+		int m2CountThrLow = on ?
+			aniState->iniDef.m2CountThrLow : m2CountThrLow_off;
+		int m1ThreshLowExt = on ?
+			aniState->iniDef.m1ThreshLowExt : m1ThreshLowExt_off;
+		int m2ThreshLowExt = on ?
+			aniState->iniDef.m2ThreshLowExt : m2ThreshLowExt_off;
+		int m1ThreshExt = on ?
+			aniState->iniDef.m1ThreshExt : m1ThreshExt_off;
+		int m2ThreshExt = on ?
+			aniState->iniDef.m2ThreshExt : m2ThreshExt_off;
+
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
+			      m1ThreshLow);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
+			      m2ThreshLow);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M1_THRESH, m1Thresh);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M2_THRESH, m2Thresh);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+			      AR_PHY_SFCORR_M2COUNT_THR, m2CountThr);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+			      AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
+			      m2CountThrLow);
+
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLowExt);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLowExt);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M1_THRESH, m1ThreshExt);
+		REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+			      AR_PHY_SFCORR_EXT_M2_THRESH, m2ThreshExt);
+
+		if (on)
+			REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
+				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+		else
+			REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
+				    AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+
+		if (!on != aniState->ofdmWeakSigDetectOff) {
+			DBG2("ath9k: "
+				"** ch %d: ofdm weak signal: %s=>%s\n",
+				chan->channel,
+				!aniState->ofdmWeakSigDetectOff ?
+				"on" : "off",
+				on ? "on" : "off");
+			if (on)
+				ah->stats.ast_ani_ofdmon++;
+			else
+				ah->stats.ast_ani_ofdmoff++;
+			aniState->ofdmWeakSigDetectOff = !on;
+		}
+		break;
+	}
+	case ATH9K_ANI_FIRSTEP_LEVEL:{
+		u32 level = param;
+
+		if (level >= ARRAY_SIZE(firstep_table)) {
+			DBG("ath9k: "
+				"ATH9K_ANI_FIRSTEP_LEVEL: level out of range (%d > %zd)\n",
+				level, ARRAY_SIZE(firstep_table));
+			return 0;
+		}
+
+		/*
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value = firstep_table[level] -
+			firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+			aniState->iniDef.firstep;
+		if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+			value = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+		if (value > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+			value = ATH9K_SIG_FIRSTEP_SETTING_MAX;
+		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+			      AR_PHY_FIND_SIG_FIRSTEP,
+			      value);
+		/*
+		 * we need to set first step low register too
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value2 = firstep_table[level] -
+			 firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] +
+			 aniState->iniDef.firstepLow;
+		if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN)
+			value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN;
+		if (value2 > ATH9K_SIG_FIRSTEP_SETTING_MAX)
+			value2 = ATH9K_SIG_FIRSTEP_SETTING_MAX;
+
+		REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW,
+			      AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2);
+
+		if (level != aniState->firstepLevel) {
+			DBG2("ath9k: "
+				"** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n",
+				chan->channel,
+				aniState->firstepLevel,
+				level,
+				ATH9K_ANI_FIRSTEP_LVL_NEW,
+				value,
+				aniState->iniDef.firstep);
+			DBG2("ath9k: "
+				"** ch %d: level %d=>%d[def:%d] firstep_low[level]=%d ini=%d\n",
+				chan->channel,
+				aniState->firstepLevel,
+				level,
+				ATH9K_ANI_FIRSTEP_LVL_NEW,
+				value2,
+				aniState->iniDef.firstepLow);
+			if (level > aniState->firstepLevel)
+				ah->stats.ast_ani_stepup++;
+			else if (level < aniState->firstepLevel)
+				ah->stats.ast_ani_stepdown++;
+			aniState->firstepLevel = level;
+		}
+		break;
+	}
+	case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
+		u32 level = param;
+
+		if (level >= ARRAY_SIZE(cycpwrThr1_table)) {
+			DBG("ath9k: "
+				"ATH9K_ANI_SPUR_IMMUNITY_LEVEL: level out of range (%d > %zd)\n",
+				level, ARRAY_SIZE(cycpwrThr1_table));
+			return 0;
+		}
+		/*
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value = cycpwrThr1_table[level] -
+			cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+			aniState->iniDef.cycpwrThr1;
+		if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+			value = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+		if (value > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+			value = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
+		REG_RMW_FIELD(ah, AR_PHY_TIMING5,
+			      AR_PHY_TIMING5_CYCPWR_THR1,
+			      value);
+
+		/*
+		 * set AR_PHY_EXT_CCA for extension channel
+		 * make register setting relative to default
+		 * from INI file & cap value
+		 */
+		value2 = cycpwrThr1_table[level] -
+			 cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] +
+			 aniState->iniDef.cycpwrThr1Ext;
+		if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN)
+			value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN;
+		if (value2 > ATH9K_SIG_SPUR_IMM_SETTING_MAX)
+			value2 = ATH9K_SIG_SPUR_IMM_SETTING_MAX;
+		REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+			      AR_PHY_EXT_CYCPWR_THR1, value2);
+
+		if (level != aniState->spurImmunityLevel) {
+			DBG2("ath9k: "
+				"** ch %d: level %d=>%d[def:%d] cycpwrThr1[level]=%d ini=%d\n",
+				chan->channel,
+				aniState->spurImmunityLevel,
+				level,
+				ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+				value,
+				aniState->iniDef.cycpwrThr1);
+			DBG2("ath9k: "
+				"** ch %d: level %d=>%d[def:%d] cycpwrThr1Ext[level]=%d ini=%d\n",
+				chan->channel,
+				aniState->spurImmunityLevel,
+				level,
+				ATH9K_ANI_SPUR_IMMUNE_LVL_NEW,
+				value2,
+				aniState->iniDef.cycpwrThr1Ext);
+			if (level > aniState->spurImmunityLevel)
+				ah->stats.ast_ani_spurup++;
+			else if (level < aniState->spurImmunityLevel)
+				ah->stats.ast_ani_spurdown++;
+			aniState->spurImmunityLevel = level;
+		}
+		break;
+	}
+	case ATH9K_ANI_MRC_CCK:{
+		/*
+		 * is_on == 1 means MRC CCK ON (default, less noise imm)
+		 * is_on == 0 means MRC CCK is OFF (more noise imm)
+		 */
+		int is_on = param ? 1 : 0;
+		REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
+			      AR_PHY_MRC_CCK_ENABLE, is_on);
+		REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL,
+			      AR_PHY_MRC_CCK_MUX_REG, is_on);
+		if (!is_on != aniState->mrcCCKOff) {
+			DBG2("ath9k: "
+				"** ch %d: MRC CCK: %s=>%s\n",
+				chan->channel,
+				!aniState->mrcCCKOff ? "on" : "off",
+				is_on ? "on" : "off");
+		if (is_on)
+			ah->stats.ast_ani_ccklow++;
+		else
+			ah->stats.ast_ani_cckhigh++;
+		aniState->mrcCCKOff = !is_on;
+		}
+	break;
+	}
+	case ATH9K_ANI_PRESENT:
+		break;
+	default:
+		DBG2("ath9k: invalid cmd %d\n", cmd);
+		return 0;
+	}
+
+	DBG2("ath9k: "
+		"ANI parameters: SI=%d, ofdmWS=%s FS=%d MRCcck=%s listenTime=%d ofdmErrs=%d cckErrs=%d\n",
+		aniState->spurImmunityLevel,
+		!aniState->ofdmWeakSigDetectOff ? "on" : "off",
+		aniState->firstepLevel,
+		!aniState->mrcCCKOff ? "on" : "off",
+		aniState->listenTime,
+		aniState->ofdmPhyErrCount,
+		aniState->cckPhyErrCount);
+	return 1;
+}
+
+static void ar9003_hw_do_getnf(struct ath_hw *ah,
+			      int16_t nfarray[NUM_NF_READINGS])
+{
+#define AR_PHY_CH_MINCCA_PWR	0x1FF00000
+#define AR_PHY_CH_MINCCA_PWR_S	20
+#define AR_PHY_CH_EXT_MINCCA_PWR 0x01FF0000
+#define AR_PHY_CH_EXT_MINCCA_PWR_S 16
+
+	int16_t nf;
+	int i;
+
+	for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+		if (ah->rxchainmask & BIT(i)) {
+			nf = MS(REG_READ(ah, ah->nf_regs[i]),
+					 AR_PHY_CH_MINCCA_PWR);
+			nfarray[i] = sign_extend32(nf, 8);
+
+			if (IS_CHAN_HT40(ah->curchan)) {
+				u8 ext_idx = AR9300_MAX_CHAINS + i;
+
+				nf = MS(REG_READ(ah, ah->nf_regs[ext_idx]),
+						 AR_PHY_CH_EXT_MINCCA_PWR);
+				nfarray[ext_idx] = sign_extend32(nf, 8);
+			}
+		}
+	}
+}
+
+static void ar9003_hw_set_nf_limits(struct ath_hw *ah)
+{
+	ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ;
+	ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ;
+	ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9300_2GHZ;
+	ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ;
+	ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ;
+	ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9300_5GHZ;
+}
+
+/*
+ * Initialize the ANI register values with default (ini) values.
+ * This routine is called during a (full) hardware reset after
+ * all the registers are initialised from the INI.
+ */
+static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
+{
+	struct ar5416AniState *aniState;
+	struct ath9k_channel *chan = ah->curchan;
+	struct ath9k_ani_default *iniDef;
+	u32 val;
+
+	aniState = &ah->curchan->ani;
+	iniDef = &aniState->iniDef;
+
+	DBG2("ath9k: "
+		"ver %d.%d chan %d Mhz/0x%x\n",
+		ah->hw_version.macVersion,
+		ah->hw_version.macRev,
+		chan->channel,
+		chan->channelFlags);
+
+	val = REG_READ(ah, AR_PHY_SFCORR);
+	iniDef->m1Thresh = MS(val, AR_PHY_SFCORR_M1_THRESH);
+	iniDef->m2Thresh = MS(val, AR_PHY_SFCORR_M2_THRESH);
+	iniDef->m2CountThr = MS(val, AR_PHY_SFCORR_M2COUNT_THR);
+
+	val = REG_READ(ah, AR_PHY_SFCORR_LOW);
+	iniDef->m1ThreshLow = MS(val, AR_PHY_SFCORR_LOW_M1_THRESH_LOW);
+	iniDef->m2ThreshLow = MS(val, AR_PHY_SFCORR_LOW_M2_THRESH_LOW);
+	iniDef->m2CountThrLow = MS(val, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW);
+
+	val = REG_READ(ah, AR_PHY_SFCORR_EXT);
+	iniDef->m1ThreshExt = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH);
+	iniDef->m2ThreshExt = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH);
+	iniDef->m1ThreshLowExt = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH_LOW);
+	iniDef->m2ThreshLowExt = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH_LOW);
+	iniDef->firstep = REG_READ_FIELD(ah,
+					 AR_PHY_FIND_SIG,
+					 AR_PHY_FIND_SIG_FIRSTEP);
+	iniDef->firstepLow = REG_READ_FIELD(ah,
+					    AR_PHY_FIND_SIG_LOW,
+					    AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW);
+	iniDef->cycpwrThr1 = REG_READ_FIELD(ah,
+					    AR_PHY_TIMING5,
+					    AR_PHY_TIMING5_CYCPWR_THR1);
+	iniDef->cycpwrThr1Ext = REG_READ_FIELD(ah,
+					       AR_PHY_EXT_CCA,
+					       AR_PHY_EXT_CYCPWR_THR1);
+
+	/* these levels just got reset to defaults by the INI */
+	aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
+	aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
+	aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG;
+	aniState->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK;
+}
+
+static void ar9003_hw_set_radar_params(struct ath_hw *ah,
+				       struct ath_hw_radar_conf *conf)
+{
+	u32 radar_0 = 0, radar_1 = 0;
+
+	if (!conf) {
+		REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
+		return;
+	}
+
+	radar_0 |= AR_PHY_RADAR_0_ENA | AR_PHY_RADAR_0_FFT_ENA;
+	radar_0 |= SM(conf->fir_power, AR_PHY_RADAR_0_FIRPWR);
+	radar_0 |= SM(conf->radar_rssi, AR_PHY_RADAR_0_RRSSI);
+	radar_0 |= SM(conf->pulse_height, AR_PHY_RADAR_0_HEIGHT);
+	radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI);
+	radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND);
+
+	radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI;
+	radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK;
+	radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN);
+	radar_1 |= SM(conf->pulse_inband_step, AR_PHY_RADAR_1_RELSTEP_THRESH);
+	radar_1 |= SM(conf->radar_inband, AR_PHY_RADAR_1_RELPWR_THRESH);
+
+	REG_WRITE(ah, AR_PHY_RADAR_0, radar_0);
+	REG_WRITE(ah, AR_PHY_RADAR_1, radar_1);
+	if (conf->ext_channel)
+		REG_SET_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
+	else
+		REG_CLR_BIT(ah, AR_PHY_RADAR_EXT, AR_PHY_RADAR_EXT_ENA);
+}
+
+static void ar9003_hw_set_radar_conf(struct ath_hw *ah)
+{
+	struct ath_hw_radar_conf *conf = &ah->radar_conf;
+
+	conf->fir_power = -28;
+	conf->radar_rssi = 0;
+	conf->pulse_height = 10;
+	conf->pulse_rssi = 24;
+	conf->pulse_inband = 8;
+	conf->pulse_maxlen = 255;
+	conf->pulse_inband_step = 12;
+	conf->radar_inband = 8;
+}
+
+static void ar9003_hw_antdiv_comb_conf_get(struct ath_hw *ah,
+				   struct ath_hw_antcomb_conf *antconf)
+{
+	u32 regval;
+
+	regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
+	antconf->main_lna_conf = (regval & AR_PHY_9485_ANT_DIV_MAIN_LNACONF) >>
+				  AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S;
+	antconf->alt_lna_conf = (regval & AR_PHY_9485_ANT_DIV_ALT_LNACONF) >>
+				 AR_PHY_9485_ANT_DIV_ALT_LNACONF_S;
+	antconf->fast_div_bias = (regval & AR_PHY_9485_ANT_FAST_DIV_BIAS) >>
+				  AR_PHY_9485_ANT_FAST_DIV_BIAS_S;
+	antconf->lna1_lna2_delta = -9;
+	antconf->div_group = 2;
+}
+
+static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah,
+				   struct ath_hw_antcomb_conf *antconf)
+{
+	u32 regval;
+
+	regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
+	regval &= ~(AR_PHY_9485_ANT_DIV_MAIN_LNACONF |
+		    AR_PHY_9485_ANT_DIV_ALT_LNACONF |
+		    AR_PHY_9485_ANT_FAST_DIV_BIAS |
+		    AR_PHY_9485_ANT_DIV_MAIN_GAINTB |
+		    AR_PHY_9485_ANT_DIV_ALT_GAINTB);
+	regval |= ((antconf->main_lna_conf <<
+					AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S)
+		   & AR_PHY_9485_ANT_DIV_MAIN_LNACONF);
+	regval |= ((antconf->alt_lna_conf << AR_PHY_9485_ANT_DIV_ALT_LNACONF_S)
+		   & AR_PHY_9485_ANT_DIV_ALT_LNACONF);
+	regval |= ((antconf->fast_div_bias << AR_PHY_9485_ANT_FAST_DIV_BIAS_S)
+		   & AR_PHY_9485_ANT_FAST_DIV_BIAS);
+	regval |= ((antconf->main_gaintb << AR_PHY_9485_ANT_DIV_MAIN_GAINTB_S)
+		   & AR_PHY_9485_ANT_DIV_MAIN_GAINTB);
+	regval |= ((antconf->alt_gaintb << AR_PHY_9485_ANT_DIV_ALT_GAINTB_S)
+		   & AR_PHY_9485_ANT_DIV_ALT_GAINTB);
+
+	REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
+}
+
+void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
+{
+	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+	static const u32 ar9300_cca_regs[6] = {
+		AR_PHY_CCA_0,
+		AR_PHY_CCA_1,
+		AR_PHY_CCA_2,
+		AR_PHY_EXT_CCA,
+		AR_PHY_EXT_CCA_1,
+		AR_PHY_EXT_CCA_2,
+	};
+
+	priv_ops->rf_set_freq = ar9003_hw_set_channel;
+	priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate;
+	priv_ops->compute_pll_control = ar9003_hw_compute_pll_control;
+	priv_ops->set_channel_regs = ar9003_hw_set_channel_regs;
+	priv_ops->init_bb = ar9003_hw_init_bb;
+	priv_ops->process_ini = ar9003_hw_process_ini;
+	priv_ops->set_rfmode = ar9003_hw_set_rfmode;
+	priv_ops->mark_phy_inactive = ar9003_hw_mark_phy_inactive;
+	priv_ops->set_delta_slope = ar9003_hw_set_delta_slope;
+	priv_ops->rfbus_req = ar9003_hw_rfbus_req;
+	priv_ops->rfbus_done = ar9003_hw_rfbus_done;
+	priv_ops->set_diversity = ar9003_hw_set_diversity;
+	priv_ops->ani_control = ar9003_hw_ani_control;
+	priv_ops->do_getnf = ar9003_hw_do_getnf;
+	priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs;
+	priv_ops->set_radar_params = ar9003_hw_set_radar_params;
+
+	ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
+	ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
+
+	ar9003_hw_set_nf_limits(ah);
+	ar9003_hw_set_radar_conf(ah);
+	memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs));
+}
+
+void ar9003_hw_disable_phy_restart(struct ath_hw *ah)
+{
+	u32 val;
+
+	val = REG_READ(ah, AR_PHY_RESTART);
+	val &= ~AR_PHY_RESTART_ENA;
+
+	REG_WRITE(ah, AR_PHY_RESTART, val);
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_calib.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_calib.c
new file mode 100644
index 0000000000000000000000000000000000000000..6f3e07e6d076f9320b9fe98fb8d52cf90e05fe92
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_calib.c
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "hw.h"
+#include "hw-ops.h"
+
+/* Common calibration code */
+
+#define ATH9K_NF_TOO_HIGH	-60
+
+static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
+{
+	int16_t nfval;
+	int16_t sort[ATH9K_NF_CAL_HIST_MAX];
+	int i, j;
+
+	for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
+		sort[i] = nfCalBuffer[i];
+
+	for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
+		for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
+			if (sort[j] > sort[j - 1]) {
+				nfval = sort[j];
+				sort[j] = sort[j - 1];
+				sort[j - 1] = nfval;
+			}
+		}
+	}
+	nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
+
+	return nfval;
+}
+
+static struct ath_nf_limits *ath9k_hw_get_nf_limits(struct ath_hw *ah,
+						    struct ath9k_channel *chan)
+{
+	struct ath_nf_limits *limit;
+
+	if (!chan || IS_CHAN_2GHZ(chan))
+		limit = &ah->nf_2g;
+	else
+		limit = &ah->nf_5g;
+
+	return limit;
+}
+
+static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
+				   struct ath9k_channel *chan)
+{
+	return ath9k_hw_get_nf_limits(ah, chan)->nominal;
+}
+
+
+static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
+					      struct ath9k_hw_cal_data *cal,
+					      int16_t *nfarray)
+{
+	struct ath_nf_limits *limit;
+	struct ath9k_nfcal_hist *h;
+	int high_nf_mid = 0;
+	u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
+	int i;
+
+	h = cal->nfCalHist;
+	limit = ath9k_hw_get_nf_limits(ah, ah->curchan);
+
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		if (!(chainmask & (1 << i)) ||
+		    (i >= AR5416_MAX_CHAINS))
+			continue;
+
+		h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
+
+		if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
+			h[i].currIndex = 0;
+
+		if (h[i].invalidNFcount > 0) {
+			h[i].invalidNFcount--;
+			h[i].privNF = nfarray[i];
+		} else {
+			h[i].privNF =
+				ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
+		}
+
+		if (!h[i].privNF)
+			continue;
+
+		if (h[i].privNF > limit->max) {
+			high_nf_mid = 1;
+
+			DBG2("ath9k: "
+				"NFmid[%d] (%d) > MAX (%d), %s\n",
+				i, h[i].privNF, limit->max,
+				(cal->nfcal_interference ?
+				 "not corrected (due to interference)" :
+				 "correcting to MAX"));
+
+			/*
+			 * Normally we limit the average noise floor by the
+			 * hardware specific maximum here. However if we have
+			 * encountered stuck beacons because of interference,
+			 * we bypass this limit here in order to better deal
+			 * with our environment.
+			 */
+			if (!cal->nfcal_interference)
+				h[i].privNF = limit->max;
+		}
+	}
+
+	/*
+	 * If the noise floor seems normal for all chains, assume that
+	 * there is no significant interference in the environment anymore.
+	 * Re-enable the enforcement of the NF maximum again.
+	 */
+	if (!high_nf_mid)
+		cal->nfcal_interference = 0;
+}
+
+static int ath9k_hw_get_nf_thresh(struct ath_hw *ah,
+				   int band,
+				   int16_t *nft)
+{
+	switch (band) {
+	case NET80211_BAND_5GHZ:
+		*nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5);
+		break;
+	case NET80211_BAND_2GHZ:
+		*nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2);
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+void ath9k_hw_reset_calibration(struct ath_hw *ah,
+				struct ath9k_cal_list *currCal)
+{
+	int i;
+
+	ath9k_hw_setup_calibration(ah, currCal);
+
+	currCal->calState = CAL_RUNNING;
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		ah->meas0.sign[i] = 0;
+		ah->meas1.sign[i] = 0;
+		ah->meas2.sign[i] = 0;
+		ah->meas3.sign[i] = 0;
+	}
+
+	ah->cal_samples = 0;
+}
+
+/* This is done for the currently configured channel */
+int ath9k_hw_reset_calvalid(struct ath_hw *ah)
+{
+	struct ath9k_cal_list *currCal = ah->cal_list_curr;
+
+	if (!ah->caldata)
+		return 1;
+
+	if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
+		return 1;
+
+	if (currCal == NULL)
+		return 1;
+
+	if (currCal->calState != CAL_DONE) {
+		DBG("ath9k: "
+			"Calibration state incorrect, %d\n",
+			currCal->calState);
+		return 1;
+	}
+
+	if (!(ah->supp_cals & currCal->calData->calType))
+		return 1;
+
+	DBG("ath9k: "
+		"Resetting Cal %d state for channel %d\n",
+		currCal->calData->calType, (ah->dev->channels + ah->dev->channel)->center_freq);
+
+	ah->caldata->CalValid &= ~currCal->calData->calType;
+	currCal->calState = CAL_WAITING;
+
+	return 0;
+}
+
+void ath9k_hw_start_nfcal(struct ath_hw *ah, int update)
+{
+	if (ah->caldata)
+		ah->caldata->nfcal_pending = 1;
+
+	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+		    AR_PHY_AGC_CONTROL_ENABLE_NF);
+
+	if (update)
+		REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+	else
+		REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+
+	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+}
+
+void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+	struct ath9k_nfcal_hist *h = NULL;
+	unsigned i, j;
+	int32_t val;
+	u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
+	s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
+
+	if (ah->caldata)
+		h = ah->caldata->nfCalHist;
+
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		if (chainmask & (1 << i)) {
+			s16 nfval;
+
+			if (i >= AR5416_MAX_CHAINS)
+				continue;
+
+			if (h)
+				nfval = h[i].privNF;
+			else
+				nfval = default_nf;
+
+			val = REG_READ(ah, ah->nf_regs[i]);
+			val &= 0xFFFFFE00;
+			val |= (((u32) nfval << 1) & 0x1ff);
+			REG_WRITE(ah, ah->nf_regs[i], val);
+		}
+	}
+
+	/*
+	 * Load software filtered NF value into baseband internal minCCApwr
+	 * variable.
+	 */
+	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+		    AR_PHY_AGC_CONTROL_ENABLE_NF);
+	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+		    AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+
+	/*
+	 * Wait for load to complete, should be fast, a few 10s of us.
+	 * The max delay was changed from an original 250us to 10000us
+	 * since 250us often results in NF load timeout and causes deaf
+	 * condition during stress testing 12/12/2009
+	 */
+	for (j = 0; j < 10000; j++) {
+		if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
+		     AR_PHY_AGC_CONTROL_NF) == 0)
+			break;
+		udelay(10);
+	}
+
+	/*
+	 * We timed out waiting for the noisefloor to load, probably due to an
+	 * in-progress rx. Simply return here and allow the load plenty of time
+	 * to complete before the next calibration interval.  We need to avoid
+	 * trying to load -50 (which happens below) while the previous load is
+	 * still in progress as this can cause rx deafness. Instead by returning
+	 * here, the baseband nf cal will just be capped by our present
+	 * noisefloor until the next calibration timer.
+	 */
+	if (j == 10000) {
+		DBG("ath9k: "
+			"Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
+			REG_READ(ah, AR_PHY_AGC_CONTROL));
+		return;
+	}
+
+	/*
+	 * Restore maxCCAPower register parameter again so that we're not capped
+	 * by the median we just loaded.  This will be initial (and max) value
+	 * of next noise floor calibration the baseband does.
+	 */
+	ENABLE_REGWRITE_BUFFER(ah);
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		if (chainmask & (1 << i)) {
+			if (i >= AR5416_MAX_CHAINS)
+				continue;
+
+			val = REG_READ(ah, ah->nf_regs[i]);
+			val &= 0xFFFFFE00;
+			val |= (((u32) (-50) << 1) & 0x1ff);
+			REG_WRITE(ah, ah->nf_regs[i], val);
+		}
+	}
+	REGWRITE_BUFFER_FLUSH(ah);
+}
+
+
+static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
+{
+	struct ath_nf_limits *limit;
+	int i;
+
+	if (IS_CHAN_2GHZ(ah->curchan))
+		limit = &ah->nf_2g;
+	else
+		limit = &ah->nf_5g;
+
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		if (!nf[i])
+			continue;
+
+		DBG2("ath9k: "
+			"NF calibrated [%s] [chain %d] is %d\n",
+			(i >= 3 ? "ext" : "ctl"), i % 3, nf[i]);
+
+		if (nf[i] > ATH9K_NF_TOO_HIGH) {
+			DBG("ath9k: "
+				"NF[%d] (%d) > MAX (%d), correcting to MAX\n",
+				i, nf[i], ATH9K_NF_TOO_HIGH);
+			nf[i] = limit->max;
+		} else if (nf[i] < limit->min) {
+			DBG("ath9k: "
+				"NF[%d] (%d) < MIN (%d), correcting to NOM\n",
+				i, nf[i], limit->min);
+			nf[i] = limit->nominal;
+		}
+	}
+}
+
+int ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+	int16_t nf, nfThresh;
+	int16_t nfarray[NUM_NF_READINGS] = { 0 };
+	struct ath9k_nfcal_hist *h;
+	struct net80211_channel *c = chan->chan;
+	struct ath9k_hw_cal_data *caldata = ah->caldata;
+
+	chan->channelFlags &= (~CHANNEL_CW_INT);
+	if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
+		DBG("ath9k: "
+			"NF did not complete in calibration window\n");
+		return 0;
+	}
+
+	ath9k_hw_do_getnf(ah, nfarray);
+	ath9k_hw_nf_sanitize(ah, nfarray);
+	nf = nfarray[0];
+	if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
+	    && nf > nfThresh) {
+		DBG2("ath9k: "
+			"noise floor failed detected; detected %d, threshold %d\n",
+			nf, nfThresh);
+		chan->channelFlags |= CHANNEL_CW_INT;
+	}
+
+	if (!caldata) {
+		chan->noisefloor = nf;
+		return 0;
+	}
+
+	h = caldata->nfCalHist;
+	caldata->nfcal_pending = 0;
+	ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray);
+	chan->noisefloor = h[0].privNF;
+	return 1;
+}
+
+void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
+				  struct ath9k_channel *chan)
+{
+	struct ath9k_nfcal_hist *h;
+	s16 default_nf;
+	int i, j;
+
+	ah->caldata->channel = chan->channel;
+	ah->caldata->channelFlags = chan->channelFlags & ~CHANNEL_CW_INT;
+	h = ah->caldata->nfCalHist;
+	default_nf = ath9k_hw_get_default_nf(ah, chan);
+	for (i = 0; i < NUM_NF_READINGS; i++) {
+		h[i].currIndex = 0;
+		h[i].privNF = default_nf;
+		h[i].invalidNFcount = AR_PHY_CCA_FILTERWINDOW_LENGTH;
+		for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
+			h[i].nfCalBuffer[j] = default_nf;
+		}
+	}
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_common.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_common.c
new file mode 100644
index 0000000000000000000000000000000000000000..ce33afbd4e494ac4b7b10f2928047af7c0155da8
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_common.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2009-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Module for common driver code between ath9k and ath9k_htc
+ */
+
+#include "common.h"
+
+/*
+ * Update internal channel flags.
+ */
+void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
+			       struct net80211_channel *chan)
+{
+	ichan->channel = chan->center_freq;
+	ichan->chan = chan;
+
+	if (chan->band == NET80211_BAND_2GHZ) {
+		ichan->chanmode = CHANNEL_G;
+		ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM;
+	} else {
+		ichan->chanmode = CHANNEL_A;
+		ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
+	}
+}
+
+/*
+ * Get the internal channel reference.
+ */
+struct ath9k_channel *ath9k_cmn_get_curchannel(struct net80211_device *dev,
+					       struct ath_hw *ah)
+{
+	struct net80211_channel *curchan = dev->channels + dev->channel;
+	struct ath9k_channel *channel;
+	u8 chan_idx;
+
+	chan_idx = curchan->hw_value;
+	channel = &ah->channels[chan_idx];
+	ath9k_cmn_update_ichannel(channel, curchan);
+
+	return channel;
+}
+
+void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow,
+			    u16 new_txpow, u16 *txpower)
+{
+	if (cur_txpow != new_txpow) {
+		ath9k_hw_set_txpowerlimit(ah, new_txpow, 0);
+		/* read back in case value is clamped */
+		*txpower = ath9k_hw_regulatory(ah)->power_limit;
+	}
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_eeprom.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_eeprom.c
new file mode 100644
index 0000000000000000000000000000000000000000..f552acaa34cbc3fc726c19be06005b5818258728
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_eeprom.c
@@ -0,0 +1,551 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/io.h>
+
+#include "hw.h"
+
+static inline u16 ath9k_hw_fbin2freq(u8 fbin, int is2GHz)
+{
+	if (fbin == AR5416_BCHAN_UNUSED)
+		return fbin;
+
+	return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
+}
+
+void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
+{
+        REG_WRITE(ah, reg, val);
+
+        if (ah->config.analog_shiftreg)
+		udelay(100);
+}
+
+void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
+			       u32 shift, u32 val)
+{
+	u32 regVal;
+
+	regVal = REG_READ(ah, reg) & ~mask;
+	regVal |= (val << shift) & mask;
+
+	REG_WRITE(ah, reg, regVal);
+
+	if (ah->config.analog_shiftreg)
+		udelay(100);
+}
+
+int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
+			     int16_t targetLeft, int16_t targetRight)
+{
+	int16_t rv;
+
+	if (srcRight == srcLeft) {
+		rv = targetLeft;
+	} else {
+		rv = (int16_t) (((target - srcLeft) * targetRight +
+				 (srcRight - target) * targetLeft) /
+				(srcRight - srcLeft));
+	}
+	return rv;
+}
+
+int ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
+				    u16 *indexL, u16 *indexR)
+{
+	u16 i;
+
+	if (target <= pList[0]) {
+		*indexL = *indexR = 0;
+		return 1;
+	}
+	if (target >= pList[listSize - 1]) {
+		*indexL = *indexR = (u16) (listSize - 1);
+		return 1;
+	}
+
+	for (i = 0; i < listSize - 1; i++) {
+		if (pList[i] == target) {
+			*indexL = *indexR = i;
+			return 1;
+		}
+		if (target < pList[i + 1]) {
+			*indexL = i;
+			*indexR = (u16) (i + 1);
+			return 0;
+		}
+	}
+	return 0;
+}
+
+void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
+				  int eep_start_loc, int size)
+{
+	int i = 0, j, addr;
+	u32 addrdata[8];
+	u32 data[8];
+
+	for (addr = 0; addr < size; addr++) {
+		addrdata[i] = AR5416_EEPROM_OFFSET +
+			((addr + eep_start_loc) << AR5416_EEPROM_S);
+		i++;
+		if (i == 8) {
+			REG_READ_MULTI(ah, addrdata, data, i);
+
+			for (j = 0; j < i; j++) {
+				*eep_data = data[j];
+				eep_data++;
+			}
+			i = 0;
+		}
+	}
+
+	if (i != 0) {
+		REG_READ_MULTI(ah, addrdata, data, i);
+
+		for (j = 0; j < i; j++) {
+			*eep_data = data[j];
+			eep_data++;
+		}
+	}
+}
+
+int ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data)
+{
+	return common->bus_ops->eeprom_read(common, off, data);
+}
+
+void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
+			     u8 *pVpdList, u16 numIntercepts,
+			     u8 *pRetVpdList)
+{
+	u16 i, k;
+	u8 currPwr = pwrMin;
+	u16 idxL = 0, idxR = 0;
+
+	for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
+		ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
+					       numIntercepts, &(idxL),
+					       &(idxR));
+		if (idxR < 1)
+			idxR = 1;
+		if (idxL == numIntercepts - 1)
+			idxL = (u16) (numIntercepts - 2);
+		if (pPwrList[idxL] == pPwrList[idxR])
+			k = pVpdList[idxL];
+		else
+			k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
+				   (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
+				  (pPwrList[idxR] - pPwrList[idxL]));
+		pRetVpdList[i] = (u8) k;
+		currPwr += 2;
+	}
+}
+
+void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
+				       struct ath9k_channel *chan,
+				       struct cal_target_power_leg *powInfo,
+				       u16 numChannels,
+				       struct cal_target_power_leg *pNewPower,
+				       u16 numRates, int isExtTarget)
+{
+	struct chan_centers centers;
+	u16 clo, chi;
+	int i;
+	int matchIndex = -1, lowIndex = -1;
+	u16 freq;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+	freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
+
+	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
+				       IS_CHAN_2GHZ(chan))) {
+		matchIndex = 0;
+	} else {
+		for (i = 0; (i < numChannels) &&
+			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						       IS_CHAN_2GHZ(chan))) {
+				matchIndex = i;
+				break;
+			} else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						IS_CHAN_2GHZ(chan)) && i > 0 &&
+				   freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+						IS_CHAN_2GHZ(chan))) {
+				lowIndex = i - 1;
+				break;
+			}
+		}
+		if ((matchIndex == -1) && (lowIndex == -1))
+			matchIndex = i - 1;
+	}
+
+	if (matchIndex != -1) {
+		*pNewPower = powInfo[matchIndex];
+	} else {
+		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
+					 IS_CHAN_2GHZ(chan));
+		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
+					 IS_CHAN_2GHZ(chan));
+
+		for (i = 0; i < numRates; i++) {
+			pNewPower->tPow2x[i] =
+				(u8)ath9k_hw_interpolate(freq, clo, chi,
+						powInfo[lowIndex].tPow2x[i],
+						powInfo[lowIndex + 1].tPow2x[i]);
+		}
+	}
+}
+
+void ath9k_hw_get_target_powers(struct ath_hw *ah,
+				struct ath9k_channel *chan,
+				struct cal_target_power_ht *powInfo,
+				u16 numChannels,
+				struct cal_target_power_ht *pNewPower,
+				u16 numRates, int isHt40Target)
+{
+	struct chan_centers centers;
+	u16 clo, chi;
+	int i;
+	int matchIndex = -1, lowIndex = -1;
+	u16 freq;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+	freq = isHt40Target ? centers.synth_center : centers.ctl_center;
+
+	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
+		matchIndex = 0;
+	} else {
+		for (i = 0; (i < numChannels) &&
+			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						       IS_CHAN_2GHZ(chan))) {
+				matchIndex = i;
+				break;
+			} else
+				if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+						IS_CHAN_2GHZ(chan)) && i > 0 &&
+				    freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+						IS_CHAN_2GHZ(chan))) {
+					lowIndex = i - 1;
+					break;
+				}
+		}
+		if ((matchIndex == -1) && (lowIndex == -1))
+			matchIndex = i - 1;
+	}
+
+	if (matchIndex != -1) {
+		*pNewPower = powInfo[matchIndex];
+	} else {
+		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
+					 IS_CHAN_2GHZ(chan));
+		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
+					 IS_CHAN_2GHZ(chan));
+
+		for (i = 0; i < numRates; i++) {
+			pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
+						clo, chi,
+						powInfo[lowIndex].tPow2x[i],
+						powInfo[lowIndex + 1].tPow2x[i]);
+		}
+	}
+}
+
+u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
+				int is2GHz, int num_band_edges)
+{
+	u16 twiceMaxEdgePower = MAX_RATE_POWER;
+	int i;
+
+	for (i = 0; (i < num_band_edges) &&
+		     (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+		if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
+			twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
+			break;
+		} else if ((i > 0) &&
+			   (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
+						      is2GHz))) {
+			if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
+					       is2GHz) < freq &&
+			    CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
+				twiceMaxEdgePower =
+					CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
+			}
+			break;
+		}
+	}
+
+	return twiceMaxEdgePower;
+}
+
+void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
+{
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+
+	switch (ar5416_get_ntxchains(ah->txchainmask)) {
+	case 1:
+		break;
+	case 2:
+		regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
+		break;
+	case 3:
+		regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
+		break;
+	default:
+		DBG2("ath9k: "
+			"Invalid chainmask configuration\n");
+		break;
+	}
+}
+
+void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
+				struct ath9k_channel *chan,
+				void *pRawDataSet,
+				u8 *bChans, u16 availPiers,
+				u16 tPdGainOverlap,
+				u16 *pPdGainBoundaries, u8 *pPDADCValues,
+				u16 numXpdGains)
+{
+	int i, j, k;
+	int16_t ss;
+	u16 idxL = 0, idxR = 0, numPiers;
+	static u8 vpdTableL[AR5416_NUM_PD_GAINS]
+		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+	static u8 vpdTableR[AR5416_NUM_PD_GAINS]
+		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+	static u8 vpdTableI[AR5416_NUM_PD_GAINS]
+		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+
+	u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+	u8 minPwrT4[AR5416_NUM_PD_GAINS];
+	u8 maxPwrT4[AR5416_NUM_PD_GAINS];
+	int16_t vpdStep;
+	int16_t tmpVal;
+	u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+	int match;
+	int16_t minDelta = 0;
+	struct chan_centers centers;
+	int pdgain_boundary_default;
+	struct cal_data_per_freq *data_def = pRawDataSet;
+	struct cal_data_per_freq_4k *data_4k = pRawDataSet;
+	struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet;
+	int eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah);
+	int intercepts;
+
+	if (AR_SREV_9287(ah))
+		intercepts = AR9287_PD_GAIN_ICEPTS;
+	else
+		intercepts = AR5416_PD_GAIN_ICEPTS;
+
+	memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS);
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+	for (numPiers = 0; numPiers < availPiers; numPiers++) {
+		if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
+			break;
+	}
+
+	match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
+							     IS_CHAN_2GHZ(chan)),
+					       bChans, numPiers, &idxL, &idxR);
+
+	if (match) {
+		if (AR_SREV_9287(ah)) {
+			/* FIXME: array overrun? */
+			for (i = 0; i < numXpdGains; i++) {
+				minPwrT4[i] = data_9287[idxL].pwrPdg[i][0];
+				maxPwrT4[i] = data_9287[idxL].pwrPdg[i][4];
+				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+						data_9287[idxL].pwrPdg[i],
+						data_9287[idxL].vpdPdg[i],
+						intercepts,
+						vpdTableI[i]);
+			}
+		} else if (eeprom_4k) {
+			for (i = 0; i < numXpdGains; i++) {
+				minPwrT4[i] = data_4k[idxL].pwrPdg[i][0];
+				maxPwrT4[i] = data_4k[idxL].pwrPdg[i][4];
+				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+						data_4k[idxL].pwrPdg[i],
+						data_4k[idxL].vpdPdg[i],
+						intercepts,
+						vpdTableI[i]);
+			}
+		} else {
+			for (i = 0; i < numXpdGains; i++) {
+				minPwrT4[i] = data_def[idxL].pwrPdg[i][0];
+				maxPwrT4[i] = data_def[idxL].pwrPdg[i][4];
+				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+						data_def[idxL].pwrPdg[i],
+						data_def[idxL].vpdPdg[i],
+						intercepts,
+						vpdTableI[i]);
+			}
+		}
+	} else {
+		for (i = 0; i < numXpdGains; i++) {
+			if (AR_SREV_9287(ah)) {
+				pVpdL = data_9287[idxL].vpdPdg[i];
+				pPwrL = data_9287[idxL].pwrPdg[i];
+				pVpdR = data_9287[idxR].vpdPdg[i];
+				pPwrR = data_9287[idxR].pwrPdg[i];
+			} else if (eeprom_4k) {
+				pVpdL = data_4k[idxL].vpdPdg[i];
+				pPwrL = data_4k[idxL].pwrPdg[i];
+				pVpdR = data_4k[idxR].vpdPdg[i];
+				pPwrR = data_4k[idxR].pwrPdg[i];
+			} else {
+				pVpdL = data_def[idxL].vpdPdg[i];
+				pPwrL = data_def[idxL].pwrPdg[i];
+				pVpdR = data_def[idxR].vpdPdg[i];
+				pPwrR = data_def[idxR].pwrPdg[i];
+			}
+
+			minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
+
+			maxPwrT4[i] =
+				min(pPwrL[intercepts - 1],
+				    pPwrR[intercepts - 1]);
+
+
+			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+						pPwrL, pVpdL,
+						intercepts,
+						vpdTableL[i]);
+			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+						pPwrR, pVpdR,
+						intercepts,
+						vpdTableR[i]);
+
+			for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
+				vpdTableI[i][j] =
+					(u8)(ath9k_hw_interpolate((u16)
+					     FREQ2FBIN(centers.
+						       synth_center,
+						       IS_CHAN_2GHZ
+						       (chan)),
+					     bChans[idxL], bChans[idxR],
+					     vpdTableL[i][j], vpdTableR[i][j]));
+			}
+		}
+	}
+
+	k = 0;
+
+	for (i = 0; i < numXpdGains; i++) {
+		if (i == (numXpdGains - 1))
+			pPdGainBoundaries[i] =
+				(u16)(maxPwrT4[i] / 2);
+		else
+			pPdGainBoundaries[i] =
+				(u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
+
+		pPdGainBoundaries[i] =
+			min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]);
+
+		if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
+			minDelta = pPdGainBoundaries[0] - 23;
+			pPdGainBoundaries[0] = 23;
+		} else {
+			minDelta = 0;
+		}
+
+		if (i == 0) {
+			if (AR_SREV_9280_20_OR_LATER(ah))
+				ss = (int16_t)(0 - (minPwrT4[i] / 2));
+			else
+				ss = 0;
+		} else {
+			ss = (int16_t)((pPdGainBoundaries[i - 1] -
+					(minPwrT4[i] / 2)) -
+				       tPdGainOverlap + 1 + minDelta);
+		}
+		vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
+		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+		while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+			tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
+			pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
+			ss++;
+		}
+
+		sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
+		tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
+				(minPwrT4[i] / 2));
+		maxIndex = (tgtIndex < sizeCurrVpdTable) ?
+			tgtIndex : sizeCurrVpdTable;
+
+		while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+			pPDADCValues[k++] = vpdTableI[i][ss++];
+		}
+
+		vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
+				    vpdTableI[i][sizeCurrVpdTable - 2]);
+		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
+		if (tgtIndex >= maxIndex) {
+			while ((ss <= tgtIndex) &&
+			       (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+				tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
+						    (ss - maxIndex + 1) * vpdStep));
+				pPDADCValues[k++] = (u8)((tmpVal > 255) ?
+							 255 : tmpVal);
+				ss++;
+			}
+		}
+	}
+
+	if (eeprom_4k)
+		pdgain_boundary_default = 58;
+	else
+		pdgain_boundary_default = pPdGainBoundaries[i - 1];
+
+	while (i < AR5416_PD_GAINS_IN_MASK) {
+		pPdGainBoundaries[i] = pdgain_boundary_default;
+		i++;
+	}
+
+	while (k < AR5416_NUM_PDADC_VALUES) {
+		pPDADCValues[k] = pPDADCValues[k - 1];
+		k++;
+	}
+}
+
+int ath9k_hw_eeprom_init(struct ath_hw *ah)
+{
+	int status;
+
+	if (AR_SREV_9300_20_OR_LATER(ah))
+		ah->eep_ops = &eep_ar9300_ops;
+	else if (AR_SREV_9287(ah)) {
+		ah->eep_ops = &eep_ar9287_ops;
+	} else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
+		ah->eep_ops = &eep_4k_ops;
+	} else {
+		ah->eep_ops = &eep_def_ops;
+	}
+
+	if (!ah->eep_ops->fill_eeprom(ah))
+		return -EIO;
+
+	status = ah->eep_ops->check_eeprom(ah);
+
+	return status;
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_eeprom_4k.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_eeprom_4k.c
new file mode 100644
index 0000000000000000000000000000000000000000..a42ad3d97e6df7c0bc4a91f15d0e85c5e56157e5
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_eeprom_4k.c
@@ -0,0 +1,1078 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/io.h>
+
+#include "hw.h"
+#include "ar9002_phy.h"
+
+static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah)
+{
+	return ((ah->eeprom.map4k.baseEepHeader.version >> 12) & 0xF);
+}
+
+static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah)
+{
+	return ((ah->eeprom.map4k.baseEepHeader.version) & 0xFFF);
+}
+
+#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
+
+static int __ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	u16 *eep_data = (u16 *)&ah->eeprom.map4k;
+	unsigned int addr;
+	int eep_start_loc = 64;
+
+	for (addr = 0; addr < SIZE_EEPROM_4K; addr++) {
+		if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) {
+			DBG("ath9k: "
+				"Unable to read eeprom region\n");
+			return 0;
+		}
+		eep_data++;
+	}
+
+	return 1;
+}
+
+static int __ath9k_hw_usb_4k_fill_eeprom(struct ath_hw *ah)
+{
+	u16 *eep_data = (u16 *)&ah->eeprom.map4k;
+
+	ath9k_hw_usb_gen_fill_eeprom(ah, eep_data, 64, SIZE_EEPROM_4K);
+
+	return 1;
+}
+
+static int ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	if (!ath9k_hw_use_flash(ah)) {
+		DBG2("ath9k: "
+			"Reading from EEPROM, not flash\n");
+	}
+
+	if (common->bus_ops->ath_bus_type == ATH_USB)
+		return __ath9k_hw_usb_4k_fill_eeprom(ah);
+	else
+		return __ath9k_hw_4k_fill_eeprom(ah);
+}
+
+#undef SIZE_EEPROM_4K
+
+static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
+{
+#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16))
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ar5416_eeprom_4k *eep =
+		(struct ar5416_eeprom_4k *) &ah->eeprom.map4k;
+	u16 *eepdata, temp, magic, magic2;
+	u32 sum = 0, el;
+	int need_swap = 0;
+	unsigned int i, addr;
+
+
+	if (!ath9k_hw_use_flash(ah)) {
+		if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET,
+					 &magic)) {
+			DBG("ath9k: Reading Magic # failed\n");
+			return 0;
+		}
+
+		DBG2("ath9k: "
+			"Read Magic = 0x%04X\n", magic);
+
+		if (magic != AR5416_EEPROM_MAGIC) {
+			magic2 = swab16(magic);
+
+			if (magic2 == AR5416_EEPROM_MAGIC) {
+				need_swap = 1;
+				eepdata = (u16 *) (&ah->eeprom);
+
+				for (addr = 0; addr < EEPROM_4K_SIZE; addr++) {
+					temp = swab16(*eepdata);
+					*eepdata = temp;
+					eepdata++;
+				}
+			} else {
+				DBG("ath9k: "
+					"Invalid EEPROM Magic. Endianness mismatch.\n");
+				return -EINVAL;
+			}
+		}
+	}
+
+	DBG2("ath9k: need_swap = %s.\n",
+		need_swap ? "True" : "False");
+
+	if (need_swap)
+		el = swab16(ah->eeprom.map4k.baseEepHeader.length);
+	else
+		el = ah->eeprom.map4k.baseEepHeader.length;
+
+	if (el > sizeof(struct ar5416_eeprom_4k))
+		el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16);
+	else
+		el = el / sizeof(u16);
+
+	eepdata = (u16 *)(&ah->eeprom);
+
+	for (i = 0; i < el; i++)
+		sum ^= *eepdata++;
+
+	if (need_swap) {
+		u32 integer;
+		u16 word;
+
+		DBG("ath9k: "
+			"EEPROM Endianness is not native.. Changing\n");
+
+		word = swab16(eep->baseEepHeader.length);
+		eep->baseEepHeader.length = word;
+
+		word = swab16(eep->baseEepHeader.checksum);
+		eep->baseEepHeader.checksum = word;
+
+		word = swab16(eep->baseEepHeader.version);
+		eep->baseEepHeader.version = word;
+
+		word = swab16(eep->baseEepHeader.regDmn[0]);
+		eep->baseEepHeader.regDmn[0] = word;
+
+		word = swab16(eep->baseEepHeader.regDmn[1]);
+		eep->baseEepHeader.regDmn[1] = word;
+
+		word = swab16(eep->baseEepHeader.rfSilent);
+		eep->baseEepHeader.rfSilent = word;
+
+		word = swab16(eep->baseEepHeader.blueToothOptions);
+		eep->baseEepHeader.blueToothOptions = word;
+
+		word = swab16(eep->baseEepHeader.deviceCap);
+		eep->baseEepHeader.deviceCap = word;
+
+		integer = swab32(eep->modalHeader.antCtrlCommon);
+		eep->modalHeader.antCtrlCommon = integer;
+
+		for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
+			integer = swab32(eep->modalHeader.antCtrlChain[i]);
+			eep->modalHeader.antCtrlChain[i] = integer;
+		}
+
+		for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+			word = swab16(eep->modalHeader.spurChans[i].spurChan);
+			eep->modalHeader.spurChans[i].spurChan = word;
+		}
+	}
+
+	if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
+	    ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
+		DBG("ath9k: Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+			sum, ah->eep_ops->get_eeprom_ver(ah));
+		return -EINVAL;
+	}
+
+	return 0;
+#undef EEPROM_4K_SIZE
+}
+
+static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
+				  enum eeprom_param param)
+{
+	struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+	struct modal_eep_4k_header *pModal = &eep->modalHeader;
+	struct base_eep_header_4k *pBase = &eep->baseEepHeader;
+	u16 ver_minor;
+
+	ver_minor = pBase->version & AR5416_EEP_VER_MINOR_MASK;
+
+	switch (param) {
+	case EEP_NFTHRESH_2:
+		return pModal->noiseFloorThreshCh[0];
+	case EEP_MAC_LSW:
+		return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+	case EEP_MAC_MID:
+		return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+	case EEP_MAC_MSW:
+		return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+	case EEP_REG_0:
+		return pBase->regDmn[0];
+	case EEP_REG_1:
+		return pBase->regDmn[1];
+	case EEP_OP_CAP:
+		return pBase->deviceCap;
+	case EEP_OP_MODE:
+		return pBase->opCapFlags;
+	case EEP_RF_SILENT:
+		return pBase->rfSilent;
+	case EEP_OB_2:
+		return pModal->ob_0;
+	case EEP_DB_2:
+		return pModal->db1_1;
+	case EEP_MINOR_REV:
+		return ver_minor;
+	case EEP_TX_MASK:
+		return pBase->txMask;
+	case EEP_RX_MASK:
+		return pBase->rxMask;
+	case EEP_FRAC_N_5G:
+		return 0;
+	case EEP_PWR_TABLE_OFFSET:
+		return AR5416_PWR_TABLE_OFFSET_DB;
+	case EEP_MODAL_VER:
+		return pModal->version;
+	case EEP_ANT_DIV_CTL1:
+		return pModal->antdiv_ctl1;
+	case EEP_TXGAIN_TYPE:
+		if (ver_minor >= AR5416_EEP_MINOR_VER_19)
+			return pBase->txGainType;
+		else
+			return AR5416_EEP_TXGAIN_ORIGINAL;
+	default:
+		return 0;
+	}
+}
+
+static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
+				  struct ath9k_channel *chan,
+				  int16_t *pTxPowerIndexOffset)
+{
+	struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
+	struct cal_data_per_freq_4k *pRawDataset;
+	u8 *pCalBChans = NULL;
+	u16 pdGainOverlap_t2;
+	static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
+	u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
+	u16 numPiers, i, j;
+	u16 numXpdGain, xpdMask;
+	u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 };
+	u32 reg32, regOffset, regChainOffset;
+
+	xpdMask = pEepData->modalHeader.xpdGain;
+
+	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_2) {
+		pdGainOverlap_t2 =
+			pEepData->modalHeader.pdGainOverlap;
+	} else {
+		pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+					    AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+	}
+
+	pCalBChans = pEepData->calFreqPier2G;
+	numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS;
+
+	numXpdGain = 0;
+
+	for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
+		if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
+			if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS)
+				break;
+			xpdGainValues[numXpdGain] =
+				(u16)(AR5416_PD_GAINS_IN_MASK - i);
+			numXpdGain++;
+		}
+	}
+
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+		      (numXpdGain - 1) & 0x3);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+		      xpdGainValues[0]);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+		      xpdGainValues[1]);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0);
+
+	for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
+		if (AR_SREV_5416_20_OR_LATER(ah) &&
+		    (ah->rxchainmask == 5 || ah->txchainmask == 5) &&
+		    (i != 0)) {
+			regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+		} else
+			regChainOffset = i * 0x1000;
+
+		if (pEepData->baseEepHeader.txMask & (1 << i)) {
+			pRawDataset = pEepData->calPierData2G[i];
+
+			ath9k_hw_get_gain_boundaries_pdadcs(ah, chan,
+					    pRawDataset, pCalBChans,
+					    numPiers, pdGainOverlap_t2,
+					    gainBoundaries,
+					    pdadcValues, numXpdGain);
+
+			ENABLE_REGWRITE_BUFFER(ah);
+
+			if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
+				REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
+					  SM(pdGainOverlap_t2,
+					     AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
+					  | SM(gainBoundaries[0],
+					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+					  | SM(gainBoundaries[1],
+					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+					  | SM(gainBoundaries[2],
+					       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+					  | SM(gainBoundaries[3],
+				       AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
+			}
+
+			regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
+			for (j = 0; j < 32; j++) {
+				reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
+					((pdadcValues[4 * j + 1] & 0xFF) << 8) |
+					((pdadcValues[4 * j + 2] & 0xFF) << 16)|
+					((pdadcValues[4 * j + 3] & 0xFF) << 24);
+				REG_WRITE(ah, regOffset, reg32);
+
+				DBG2("ath9k: "
+					"PDADC (%d,%4x): %4.4x %8.8x\n",
+					i, regChainOffset, regOffset,
+					reg32);
+				DBG2("ath9k: "
+					"PDADC: Chain %d | "
+					"PDADC %3d Value %3d | "
+					"PDADC %3d Value %3d | "
+					"PDADC %3d Value %3d | "
+					"PDADC %3d Value %3d |\n",
+					i, 4 * j, pdadcValues[4 * j],
+					4 * j + 1, pdadcValues[4 * j + 1],
+					4 * j + 2, pdadcValues[4 * j + 2],
+					4 * j + 3, pdadcValues[4 * j + 3]);
+
+				regOffset += 4;
+			}
+
+			REGWRITE_BUFFER_FLUSH(ah);
+		}
+	}
+
+	*pTxPowerIndexOffset = 0;
+}
+
+static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
+						 struct ath9k_channel *chan,
+						 int16_t *ratesArray,
+						 u16 cfgCtl,
+						 u16 AntennaReduction,
+						 u16 twiceMaxRegulatoryPower,
+						 u16 powerLimit)
+{
+#define CMP_TEST_GRP \
+	(((cfgCtl & ~CTL_MODE_M)| (pCtlMode[ctlMode] & CTL_MODE_M)) ==	\
+	 pEepData->ctlIndex[i])						\
+	|| (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
+	    ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))
+
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+	unsigned int i;
+	int16_t twiceLargestAntenna;
+	u16 twiceMinEdgePower;
+	u16 twiceMaxEdgePower = MAX_RATE_POWER;
+	u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+	u16 numCtlModes;
+	const u16 *pCtlMode;
+	u16 ctlMode, freq;
+	struct chan_centers centers;
+	struct cal_ctl_data_4k *rep;
+	struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
+	static const u16 tpScaleReductionTable[5] =
+		{ 0, 3, 6, 9, MAX_RATE_POWER };
+	struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
+		0, { 0, 0, 0, 0}
+	};
+	struct cal_target_power_leg targetPowerOfdmExt = {
+		0, { 0, 0, 0, 0} }, targetPowerCckExt = {
+		0, { 0, 0, 0, 0 }
+	};
+	struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
+		0, {0, 0, 0, 0}
+	};
+	static const u16 ctlModesFor11g[] = {
+		CTL_11B, CTL_11G, CTL_2GHT20,
+		CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40
+	};
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+	twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0];
+	twiceLargestAntenna = (int16_t)min(AntennaReduction -
+					   twiceLargestAntenna, 0);
+
+	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+	if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) {
+		maxRegAllowedPower -=
+			(tpScaleReductionTable[(regulatory->tp_scale)] * 2);
+	}
+
+	scaledPower = min(powerLimit, maxRegAllowedPower);
+	scaledPower = max((u16)0, scaledPower);
+
+	numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
+	pCtlMode = ctlModesFor11g;
+
+	ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPowerCck,
+			AR5416_NUM_2G_CCK_TARGET_POWERS,
+			&targetPowerCck, 4, 0);
+	ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPower2G,
+			AR5416_NUM_2G_20_TARGET_POWERS,
+			&targetPowerOfdm, 4, 0);
+	ath9k_hw_get_target_powers(ah, chan,
+			pEepData->calTargetPower2GHT20,
+			AR5416_NUM_2G_20_TARGET_POWERS,
+			&targetPowerHt20, 8, 0);
+
+	if (IS_CHAN_HT40(chan)) {
+		numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+		ath9k_hw_get_target_powers(ah, chan,
+				pEepData->calTargetPower2GHT40,
+				AR5416_NUM_2G_40_TARGET_POWERS,
+				&targetPowerHt40, 8, 1);
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPowerCck,
+				AR5416_NUM_2G_CCK_TARGET_POWERS,
+				&targetPowerCckExt, 4, 1);
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPower2G,
+				AR5416_NUM_2G_20_TARGET_POWERS,
+				&targetPowerOfdmExt, 4, 1);
+	}
+
+	for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+		int isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
+			(pCtlMode[ctlMode] == CTL_2GHT40);
+
+		if (isHt40CtlMode)
+			freq = centers.synth_center;
+		else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+			freq = centers.ext_center;
+		else
+			freq = centers.ctl_center;
+
+		if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
+		    ah->eep_ops->get_eeprom_rev(ah) <= 2)
+			twiceMaxEdgePower = MAX_RATE_POWER;
+
+		for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) &&
+			     pEepData->ctlIndex[i]; i++) {
+
+			if (CMP_TEST_GRP) {
+				rep = &(pEepData->ctlData[i]);
+
+				twiceMinEdgePower = ath9k_hw_get_max_edge_power(
+					freq,
+					rep->ctlEdges[
+					ar5416_get_ntxchains(ah->txchainmask) - 1],
+					IS_CHAN_2GHZ(chan),
+					AR5416_EEP4K_NUM_BAND_EDGES);
+
+				if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+					twiceMaxEdgePower =
+						min(twiceMaxEdgePower,
+						    twiceMinEdgePower);
+				} else {
+					twiceMaxEdgePower = twiceMinEdgePower;
+					break;
+				}
+			}
+		}
+
+		minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
+
+		switch (pCtlMode[ctlMode]) {
+		case CTL_11B:
+			for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
+				targetPowerCck.tPow2x[i] =
+					min((u16)targetPowerCck.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_11G:
+			for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
+				targetPowerOfdm.tPow2x[i] =
+					min((u16)targetPowerOfdm.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_2GHT20:
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
+				targetPowerHt20.tPow2x[i] =
+					min((u16)targetPowerHt20.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_11B_EXT:
+			targetPowerCckExt.tPow2x[0] =
+				min((u16)targetPowerCckExt.tPow2x[0],
+				    minCtlPower);
+			break;
+		case CTL_11G_EXT:
+			targetPowerOfdmExt.tPow2x[0] =
+				min((u16)targetPowerOfdmExt.tPow2x[0],
+				    minCtlPower);
+			break;
+		case CTL_2GHT40:
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+				targetPowerHt40.tPow2x[i] =
+					min((u16)targetPowerHt40.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	ratesArray[rate6mb] =
+	ratesArray[rate9mb] =
+	ratesArray[rate12mb] =
+	ratesArray[rate18mb] =
+	ratesArray[rate24mb] =
+	targetPowerOfdm.tPow2x[0];
+
+	ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
+	ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
+	ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
+	ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
+
+	for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
+		ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
+
+	ratesArray[rate1l] = targetPowerCck.tPow2x[0];
+	ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1];
+	ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2];
+	ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3];
+
+	if (IS_CHAN_HT40(chan)) {
+		for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+			ratesArray[rateHt40_0 + i] =
+				targetPowerHt40.tPow2x[i];
+		}
+		ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
+		ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
+		ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+		ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0];
+	}
+
+#undef CMP_TEST_GRP
+}
+
+static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
+				    struct ath9k_channel *chan,
+				    u16 cfgCtl,
+				    u8 twiceAntennaReduction,
+				    u8 twiceMaxRegulatoryPower,
+				    u8 powerLimit, int test)
+{
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+	struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k;
+	struct modal_eep_4k_header *pModal = &pEepData->modalHeader;
+	int16_t ratesArray[Ar5416RateSize];
+	int16_t txPowerIndexOffset = 0;
+	u8 ht40PowerIncForPdadc = 2;
+	unsigned int i;
+
+	memset(ratesArray, 0, sizeof(ratesArray));
+
+	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_2) {
+		ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+	}
+
+	ath9k_hw_set_4k_power_per_rate_table(ah, chan,
+					     &ratesArray[0], cfgCtl,
+					     twiceAntennaReduction,
+					     twiceMaxRegulatoryPower,
+					     powerLimit);
+
+	ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset);
+
+	regulatory->max_power_level = 0;
+	for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
+		ratesArray[i] =	(int16_t)(txPowerIndexOffset + ratesArray[i]);
+		if (ratesArray[i] > MAX_RATE_POWER)
+			ratesArray[i] = MAX_RATE_POWER;
+
+		if (ratesArray[i] > regulatory->max_power_level)
+			regulatory->max_power_level = ratesArray[i];
+	}
+
+	if (test)
+	    return;
+
+	/* Update regulatory */
+	i = rate6mb;
+	if (IS_CHAN_HT40(chan))
+		i = rateHt40_0;
+	else if (IS_CHAN_HT20(chan))
+		i = rateHt20_0;
+
+	regulatory->max_power_level = ratesArray[i];
+
+	if (AR_SREV_9280_20_OR_LATER(ah)) {
+		for (i = 0; i < Ar5416RateSize; i++)
+			ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
+	}
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	/* OFDM power per rate */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+		  ATH9K_POW_SM(ratesArray[rate18mb], 24)
+		  | ATH9K_POW_SM(ratesArray[rate12mb], 16)
+		  | ATH9K_POW_SM(ratesArray[rate9mb], 8)
+		  | ATH9K_POW_SM(ratesArray[rate6mb], 0));
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+		  ATH9K_POW_SM(ratesArray[rate54mb], 24)
+		  | ATH9K_POW_SM(ratesArray[rate48mb], 16)
+		  | ATH9K_POW_SM(ratesArray[rate36mb], 8)
+		  | ATH9K_POW_SM(ratesArray[rate24mb], 0));
+
+	/* CCK power per rate */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+		  ATH9K_POW_SM(ratesArray[rate2s], 24)
+		  | ATH9K_POW_SM(ratesArray[rate2l], 16)
+		  | ATH9K_POW_SM(ratesArray[rateXr], 8)
+		  | ATH9K_POW_SM(ratesArray[rate1l], 0));
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+		  ATH9K_POW_SM(ratesArray[rate11s], 24)
+		  | ATH9K_POW_SM(ratesArray[rate11l], 16)
+		  | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+		  | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
+
+	/* HT20 power per rate */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
+		  ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
+		  ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
+
+	/* HT40 power per rate */
+	if (IS_CHAN_HT40(chan)) {
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+			  ATH9K_POW_SM(ratesArray[rateHt40_3] +
+				       ht40PowerIncForPdadc, 24)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_2] +
+					 ht40PowerIncForPdadc, 16)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_1] +
+					 ht40PowerIncForPdadc, 8)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_0] +
+					 ht40PowerIncForPdadc, 0));
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+			  ATH9K_POW_SM(ratesArray[rateHt40_7] +
+				       ht40PowerIncForPdadc, 24)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_6] +
+					 ht40PowerIncForPdadc, 16)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_5] +
+					 ht40PowerIncForPdadc, 8)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_4] +
+					 ht40PowerIncForPdadc, 0));
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+			  ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+			  | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+			  | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+			  | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+	}
+
+	REGWRITE_BUFFER_FLUSH(ah);
+}
+
+static void ath9k_hw_4k_set_addac(struct ath_hw *ah,
+				  struct ath9k_channel *chan __unused)
+{
+	struct modal_eep_4k_header *pModal;
+	struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+	u8 biaslevel;
+
+	if (ah->hw_version.macVersion != AR_SREV_VERSION_9160)
+		return;
+
+	if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7)
+		return;
+
+	pModal = &eep->modalHeader;
+
+	if (pModal->xpaBiasLvl != 0xff) {
+		biaslevel = pModal->xpaBiasLvl;
+		INI_RA(&ah->iniAddac, 7, 1) =
+		  (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3;
+	}
+}
+
+static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
+				 struct modal_eep_4k_header *pModal,
+				 struct ar5416_eeprom_4k *eep,
+				 u8 txRxAttenLocal)
+{
+	REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0,
+		  pModal->antCtrlChain[0]);
+
+	REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0),
+		  (REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
+		   ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+		     AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+		  SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+		  SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
+
+	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_3) {
+		txRxAttenLocal = pModal->txRxAttenCh[0];
+
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ,
+			      AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]);
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ,
+			      AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]);
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ,
+			      AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+			      pModal->xatten2Margin[0]);
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ,
+			      AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]);
+
+		/* Set the block 1 value to block 0 value */
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+			      AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+			      pModal->bswMargin[0]);
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+			      AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]);
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+			      AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+			      pModal->xatten2Margin[0]);
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+			      AR_PHY_GAIN_2GHZ_XATTEN2_DB,
+			      pModal->xatten2Db[0]);
+	}
+
+	REG_RMW_FIELD(ah, AR_PHY_RXGAIN,
+		      AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
+	REG_RMW_FIELD(ah, AR_PHY_RXGAIN,
+		      AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
+
+	REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
+		      AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
+	REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
+		      AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
+}
+
+/*
+ * Read EEPROM header info and program the device for correct operation
+ * given the channel value.
+ */
+static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
+					 struct ath9k_channel *chan)
+{
+	struct modal_eep_4k_header *pModal;
+	struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+	struct base_eep_header_4k *pBase = &eep->baseEepHeader;
+	u8 txRxAttenLocal;
+	u8 ob[5], db1[5], db2[5];
+	u8 ant_div_control1, ant_div_control2;
+	u32 regVal;
+
+	pModal = &eep->modalHeader;
+	txRxAttenLocal = 23;
+
+	REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon);
+
+	/* Single chain for 4K EEPROM*/
+	ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal);
+
+	/* Initialize Ant Diversity settings from EEPROM */
+	if (pModal->version >= 3) {
+		ant_div_control1 = pModal->antdiv_ctl1;
+		ant_div_control2 = pModal->antdiv_ctl2;
+
+		regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
+		regVal &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL));
+
+		regVal |= SM(ant_div_control1,
+			     AR_PHY_9285_ANT_DIV_CTL);
+		regVal |= SM(ant_div_control2,
+			     AR_PHY_9285_ANT_DIV_ALT_LNACONF);
+		regVal |= SM((ant_div_control2 >> 2),
+			     AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
+		regVal |= SM((ant_div_control1 >> 1),
+			     AR_PHY_9285_ANT_DIV_ALT_GAINTB);
+		regVal |= SM((ant_div_control1 >> 2),
+			     AR_PHY_9285_ANT_DIV_MAIN_GAINTB);
+
+
+		REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal);
+		regVal = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
+		regVal = REG_READ(ah, AR_PHY_CCK_DETECT);
+		regVal &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
+		regVal |= SM((ant_div_control1 >> 3),
+			     AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
+
+		REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal);
+		regVal = REG_READ(ah, AR_PHY_CCK_DETECT);
+	}
+
+	if (pModal->version >= 2) {
+		ob[0] = pModal->ob_0;
+		ob[1] = pModal->ob_1;
+		ob[2] = pModal->ob_2;
+		ob[3] = pModal->ob_3;
+		ob[4] = pModal->ob_4;
+
+		db1[0] = pModal->db1_0;
+		db1[1] = pModal->db1_1;
+		db1[2] = pModal->db1_2;
+		db1[3] = pModal->db1_3;
+		db1[4] = pModal->db1_4;
+
+		db2[0] = pModal->db2_0;
+		db2[1] = pModal->db2_1;
+		db2[2] = pModal->db2_2;
+		db2[3] = pModal->db2_3;
+		db2[4] = pModal->db2_4;
+	} else if (pModal->version == 1) {
+		ob[0] = pModal->ob_0;
+		ob[1] = ob[2] = ob[3] = ob[4] = pModal->ob_1;
+		db1[0] = pModal->db1_0;
+		db1[1] = db1[2] = db1[3] = db1[4] = pModal->db1_1;
+		db2[0] = pModal->db2_0;
+		db2[1] = db2[2] = db2[3] = db2[4] = pModal->db2_1;
+	} else {
+		int i;
+
+		for (i = 0; i < 5; i++) {
+			ob[i] = pModal->ob_0;
+			db1[i] = pModal->db1_0;
+			db2[i] = pModal->db1_0;
+		}
+	}
+
+	if (AR_SREV_9271(ah)) {
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G3,
+					  AR9271_AN_RF2G3_OB_cck,
+					  AR9271_AN_RF2G3_OB_cck_S,
+					  ob[0]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G3,
+					  AR9271_AN_RF2G3_OB_psk,
+					  AR9271_AN_RF2G3_OB_psk_S,
+					  ob[1]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G3,
+					  AR9271_AN_RF2G3_OB_qam,
+					  AR9271_AN_RF2G3_OB_qam_S,
+					  ob[2]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G3,
+					  AR9271_AN_RF2G3_DB_1,
+					  AR9271_AN_RF2G3_DB_1_S,
+					  db1[0]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G4,
+					  AR9271_AN_RF2G4_DB_2,
+					  AR9271_AN_RF2G4_DB_2_S,
+					  db2[0]);
+	} else {
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G3,
+					  AR9285_AN_RF2G3_OB_0,
+					  AR9285_AN_RF2G3_OB_0_S,
+					  ob[0]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G3,
+					  AR9285_AN_RF2G3_OB_1,
+					  AR9285_AN_RF2G3_OB_1_S,
+					  ob[1]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G3,
+					  AR9285_AN_RF2G3_OB_2,
+					  AR9285_AN_RF2G3_OB_2_S,
+					  ob[2]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G3,
+					  AR9285_AN_RF2G3_OB_3,
+					  AR9285_AN_RF2G3_OB_3_S,
+					  ob[3]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G3,
+					  AR9285_AN_RF2G3_OB_4,
+					  AR9285_AN_RF2G3_OB_4_S,
+					  ob[4]);
+
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G3,
+					  AR9285_AN_RF2G3_DB1_0,
+					  AR9285_AN_RF2G3_DB1_0_S,
+					  db1[0]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G3,
+					  AR9285_AN_RF2G3_DB1_1,
+					  AR9285_AN_RF2G3_DB1_1_S,
+					  db1[1]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G3,
+					  AR9285_AN_RF2G3_DB1_2,
+					  AR9285_AN_RF2G3_DB1_2_S,
+					  db1[2]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G4,
+					  AR9285_AN_RF2G4_DB1_3,
+					  AR9285_AN_RF2G4_DB1_3_S,
+					  db1[3]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G4,
+					  AR9285_AN_RF2G4_DB1_4,
+					  AR9285_AN_RF2G4_DB1_4_S, db1[4]);
+
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G4,
+					  AR9285_AN_RF2G4_DB2_0,
+					  AR9285_AN_RF2G4_DB2_0_S,
+					  db2[0]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G4,
+					  AR9285_AN_RF2G4_DB2_1,
+					  AR9285_AN_RF2G4_DB2_1_S,
+					  db2[1]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G4,
+					  AR9285_AN_RF2G4_DB2_2,
+					  AR9285_AN_RF2G4_DB2_2_S,
+					  db2[2]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G4,
+					  AR9285_AN_RF2G4_DB2_3,
+					  AR9285_AN_RF2G4_DB2_3_S,
+					  db2[3]);
+		ath9k_hw_analog_shift_rmw(ah,
+					  AR9285_AN_RF2G4,
+					  AR9285_AN_RF2G4_DB2_4,
+					  AR9285_AN_RF2G4_DB2_4_S,
+					  db2[4]);
+	}
+
+
+	REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
+		      pModal->switchSettling);
+	REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
+		      pModal->adcDesiredSize);
+
+	REG_WRITE(ah, AR_PHY_RF_CTL4,
+		  SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) |
+		  SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) |
+		  SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON)  |
+		  SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));
+
+	REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
+		      pModal->txEndToRxOn);
+
+	if (AR_SREV_9271_10(ah))
+		REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
+			      pModal->txEndToRxOn);
+	REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
+		      pModal->thresh62);
+	REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62,
+		      pModal->thresh62);
+
+	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+						AR5416_EEP_MINOR_VER_2) {
+		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START,
+			      pModal->txFrameToDataStart);
+		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
+			      pModal->txFrameToPaOn);
+	}
+
+	if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+						AR5416_EEP_MINOR_VER_3) {
+		if (IS_CHAN_HT40(chan))
+			REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+				      AR_PHY_SETTLING_SWITCH,
+				      pModal->swSettleHt40);
+	}
+	if (AR_SREV_9271(ah) || AR_SREV_9285(ah)) {
+		u8 bb_desired_scale = (pModal->bb_scale_smrt_antenna &
+				EEP_4K_BB_DESIRED_SCALE_MASK);
+		if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) {
+			u32 pwrctrl, mask, clr;
+
+			mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25);
+			pwrctrl = mask * bb_desired_scale;
+			clr = mask * 0x1f;
+			REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr);
+			REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr);
+			REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr);
+
+			mask = BIT(0)|BIT(5)|BIT(15);
+			pwrctrl = mask * bb_desired_scale;
+			clr = mask * 0x1f;
+			REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr);
+
+			mask = BIT(0)|BIT(5);
+			pwrctrl = mask * bb_desired_scale;
+			clr = mask * 0x1f;
+			REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr);
+			REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr);
+		}
+	}
+}
+
+static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, int is2GHz)
+{
+#define EEP_MAP4K_SPURCHAN \
+	(ah->eeprom.map4k.modalHeader.spurChans[i].spurChan)
+
+	u16 spur_val = AR_NO_SPUR;
+
+	DBG2("ath9k: "
+		"Getting spur idx:%d is2Ghz:%d val:%x\n",
+		i, is2GHz, ah->config.spurchans[i][is2GHz]);
+
+	switch (ah->config.spurmode) {
+	case SPUR_DISABLE:
+		break;
+	case SPUR_ENABLE_IOCTL:
+		spur_val = ah->config.spurchans[i][is2GHz];
+		DBG2("ath9k: "
+			"Getting spur val from new loc. %d\n", spur_val);
+		break;
+	case SPUR_ENABLE_EEPROM:
+		spur_val = EEP_MAP4K_SPURCHAN;
+		break;
+	}
+
+	return spur_val;
+
+#undef EEP_MAP4K_SPURCHAN
+}
+
+const struct eeprom_ops eep_4k_ops = {
+	.check_eeprom		= ath9k_hw_4k_check_eeprom,
+	.get_eeprom		= ath9k_hw_4k_get_eeprom,
+	.fill_eeprom		= ath9k_hw_4k_fill_eeprom,
+	.get_eeprom_ver		= ath9k_hw_4k_get_eeprom_ver,
+	.get_eeprom_rev		= ath9k_hw_4k_get_eeprom_rev,
+	.set_board_values	= ath9k_hw_4k_set_board_values,
+	.set_addac		= ath9k_hw_4k_set_addac,
+	.set_txpower		= ath9k_hw_4k_set_txpower,
+	.get_spur_channel	= ath9k_hw_4k_get_spur_channel
+};
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_eeprom_9287.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_eeprom_9287.c
new file mode 100644
index 0000000000000000000000000000000000000000..ee16a6f1802c0895d067067db1ddc197fb937ed0
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_eeprom_9287.c
@@ -0,0 +1,1019 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/io.h>
+
+#include "hw.h"
+#include "ar9002_phy.h"
+
+#define SIZE_EEPROM_AR9287 (sizeof(struct ar9287_eeprom) / sizeof(u16))
+
+static int ath9k_hw_ar9287_get_eeprom_ver(struct ath_hw *ah)
+{
+	return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF;
+}
+
+static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah)
+{
+	return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF;
+}
+
+static int __ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
+{
+	struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+	struct ath_common *common = ath9k_hw_common(ah);
+	u16 *eep_data;
+	unsigned int addr;
+	int eep_start_loc = AR9287_EEP_START_LOC;
+	eep_data = (u16 *)eep;
+
+	for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) {
+		if (!ath9k_hw_nvram_read(common, addr + eep_start_loc,
+					 eep_data)) {
+			DBG("ath9k: "
+				"Unable to read eeprom region\n");
+			return 0;
+		}
+		eep_data++;
+	}
+
+	return 1;
+}
+
+static int __ath9k_hw_usb_ar9287_fill_eeprom(struct ath_hw *ah)
+{
+	u16 *eep_data = (u16 *)&ah->eeprom.map9287;
+
+	ath9k_hw_usb_gen_fill_eeprom(ah, eep_data,
+				     AR9287_HTC_EEP_START_LOC,
+				     SIZE_EEPROM_AR9287);
+	return 1;
+}
+
+static int ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	if (!ath9k_hw_use_flash(ah)) {
+		DBG2("ath9k: "
+			"Reading from EEPROM, not flash\n");
+	}
+
+	if (common->bus_ops->ath_bus_type == ATH_USB)
+		return __ath9k_hw_usb_ar9287_fill_eeprom(ah);
+	else
+		return __ath9k_hw_ar9287_fill_eeprom(ah);
+}
+
+static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
+{
+	u32 sum = 0, el, integer;
+	u16 temp, word, magic, magic2, *eepdata;
+	unsigned int i, addr;
+	int need_swap = 0;
+	struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	if (!ath9k_hw_use_flash(ah)) {
+		if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET,
+					 &magic)) {
+			DBG("ath9k: Reading Magic # failed\n");
+			return 0;
+		}
+
+		DBG2("ath9k: "
+			"Read Magic = 0x%04X\n", magic);
+
+		if (magic != AR5416_EEPROM_MAGIC) {
+			magic2 = swab16(magic);
+
+			if (magic2 == AR5416_EEPROM_MAGIC) {
+				need_swap = 1;
+				eepdata = (u16 *)(&ah->eeprom);
+
+				for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) {
+					temp = swab16(*eepdata);
+					*eepdata = temp;
+					eepdata++;
+				}
+			} else {
+				DBG("ath9k: "
+					"Invalid EEPROM Magic. Endianness mismatch.\n");
+				return -EINVAL;
+			}
+		}
+	}
+
+	DBG2("ath9k: need_swap = %s.\n",
+		need_swap ? "True" : "False");
+
+	if (need_swap)
+		el = swab16(ah->eeprom.map9287.baseEepHeader.length);
+	else
+		el = ah->eeprom.map9287.baseEepHeader.length;
+
+	if (el > sizeof(struct ar9287_eeprom))
+		el = sizeof(struct ar9287_eeprom) / sizeof(u16);
+	else
+		el = el / sizeof(u16);
+
+	eepdata = (u16 *)(&ah->eeprom);
+
+	for (i = 0; i < el; i++)
+		sum ^= *eepdata++;
+
+	if (need_swap) {
+		word = swab16(eep->baseEepHeader.length);
+		eep->baseEepHeader.length = word;
+
+		word = swab16(eep->baseEepHeader.checksum);
+		eep->baseEepHeader.checksum = word;
+
+		word = swab16(eep->baseEepHeader.version);
+		eep->baseEepHeader.version = word;
+
+		word = swab16(eep->baseEepHeader.regDmn[0]);
+		eep->baseEepHeader.regDmn[0] = word;
+
+		word = swab16(eep->baseEepHeader.regDmn[1]);
+		eep->baseEepHeader.regDmn[1] = word;
+
+		word = swab16(eep->baseEepHeader.rfSilent);
+		eep->baseEepHeader.rfSilent = word;
+
+		word = swab16(eep->baseEepHeader.blueToothOptions);
+		eep->baseEepHeader.blueToothOptions = word;
+
+		word = swab16(eep->baseEepHeader.deviceCap);
+		eep->baseEepHeader.deviceCap = word;
+
+		integer = swab32(eep->modalHeader.antCtrlCommon);
+		eep->modalHeader.antCtrlCommon = integer;
+
+		for (i = 0; i < AR9287_MAX_CHAINS; i++) {
+			integer = swab32(eep->modalHeader.antCtrlChain[i]);
+			eep->modalHeader.antCtrlChain[i] = integer;
+		}
+
+		for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+			word = swab16(eep->modalHeader.spurChans[i].spurChan);
+			eep->modalHeader.spurChans[i].spurChan = word;
+		}
+	}
+
+	if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER
+	    || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
+		DBG("ath9k: Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+			sum, ah->eep_ops->get_eeprom_ver(ah));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah,
+				      enum eeprom_param param)
+{
+	struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+	struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
+	struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
+	u16 ver_minor;
+
+	ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK;
+
+	switch (param) {
+	case EEP_NFTHRESH_2:
+		return pModal->noiseFloorThreshCh[0];
+	case EEP_MAC_LSW:
+		return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+	case EEP_MAC_MID:
+		return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+	case EEP_MAC_MSW:
+		return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+	case EEP_REG_0:
+		return pBase->regDmn[0];
+	case EEP_REG_1:
+		return pBase->regDmn[1];
+	case EEP_OP_CAP:
+		return pBase->deviceCap;
+	case EEP_OP_MODE:
+		return pBase->opCapFlags;
+	case EEP_RF_SILENT:
+		return pBase->rfSilent;
+	case EEP_MINOR_REV:
+		return ver_minor;
+	case EEP_TX_MASK:
+		return pBase->txMask;
+	case EEP_RX_MASK:
+		return pBase->rxMask;
+	case EEP_DEV_TYPE:
+		return pBase->deviceType;
+	case EEP_OL_PWRCTRL:
+		return pBase->openLoopPwrCntl;
+	case EEP_TEMPSENSE_SLOPE:
+		if (ver_minor >= AR9287_EEP_MINOR_VER_2)
+			return pBase->tempSensSlope;
+		else
+			return 0;
+	case EEP_TEMPSENSE_SLOPE_PAL_ON:
+		if (ver_minor >= AR9287_EEP_MINOR_VER_3)
+			return pBase->tempSensSlopePalOn;
+		else
+			return 0;
+	default:
+		return 0;
+	}
+}
+
+static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
+			    struct ath9k_channel *chan,
+			    struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop,
+			    u8 *pCalChans,  u16 availPiers, int8_t *pPwr)
+{
+	u16 idxL = 0, idxR = 0, numPiers;
+	int match;
+	struct chan_centers centers;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+	for (numPiers = 0; numPiers < availPiers; numPiers++) {
+		if (pCalChans[numPiers] == AR5416_BCHAN_UNUSED)
+			break;
+	}
+
+	match = ath9k_hw_get_lower_upper_index(
+		(u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
+		pCalChans, numPiers, &idxL, &idxR);
+
+	if (match) {
+		*pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0];
+	} else {
+		*pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] +
+			 (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
+	}
+
+}
+
+static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
+					  int32_t txPower, u16 chain)
+{
+	u32 tmpVal;
+	u32 a;
+
+	/* Enable OLPC for chain 0 */
+
+	tmpVal = REG_READ(ah, 0xa270);
+	tmpVal = tmpVal & 0xFCFFFFFF;
+	tmpVal = tmpVal | (0x3 << 24);
+	REG_WRITE(ah, 0xa270, tmpVal);
+
+	/* Enable OLPC for chain 1 */
+
+	tmpVal = REG_READ(ah, 0xb270);
+	tmpVal = tmpVal & 0xFCFFFFFF;
+	tmpVal = tmpVal | (0x3 << 24);
+	REG_WRITE(ah, 0xb270, tmpVal);
+
+	/* Write the OLPC ref power for chain 0 */
+
+	if (chain == 0) {
+		tmpVal = REG_READ(ah, 0xa398);
+		tmpVal = tmpVal & 0xff00ffff;
+		a = (txPower)&0xff;
+		tmpVal = tmpVal | (a << 16);
+		REG_WRITE(ah, 0xa398, tmpVal);
+	}
+
+	/* Write the OLPC ref power for chain 1 */
+
+	if (chain == 1) {
+		tmpVal = REG_READ(ah, 0xb398);
+		tmpVal = tmpVal & 0xff00ffff;
+		a = (txPower)&0xff;
+		tmpVal = tmpVal | (a << 16);
+		REG_WRITE(ah, 0xb398, tmpVal);
+	}
+}
+
+static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
+						struct ath9k_channel *chan,
+						int16_t *pTxPowerIndexOffset)
+{
+	struct cal_data_per_freq_ar9287 *pRawDataset;
+	struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
+	u8 *pCalBChans = NULL;
+	u16 pdGainOverlap_t2;
+	u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
+	u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
+	u16 numPiers = 0, i, j;
+	u16 numXpdGain, xpdMask;
+	u16 xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0};
+	u32 reg32, regOffset, regChainOffset, regval;
+	int16_t diff = 0;
+	struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
+
+	xpdMask = pEepData->modalHeader.xpdGain;
+
+	if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
+	    AR9287_EEP_MINOR_VER_2)
+		pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap;
+	else
+		pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+					    AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+
+	if (IS_CHAN_2GHZ(chan)) {
+		pCalBChans = pEepData->calFreqPier2G;
+		numPiers = AR9287_NUM_2G_CAL_PIERS;
+		if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+			pRawDatasetOpenLoop =
+			(struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0];
+			ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0];
+		}
+	}
+
+	numXpdGain = 0;
+
+	/* Calculate the value of xpdgains from the xpdGain Mask */
+	for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
+		if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
+			if (numXpdGain >= AR5416_NUM_PD_GAINS)
+				break;
+			xpdGainValues[numXpdGain] =
+				(u16)(AR5416_PD_GAINS_IN_MASK-i);
+			numXpdGain++;
+		}
+	}
+
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+		      (numXpdGain - 1) & 0x3);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+		      xpdGainValues[0]);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+		      xpdGainValues[1]);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
+		      xpdGainValues[2]);
+
+	for (i = 0; i < AR9287_MAX_CHAINS; i++)	{
+		regChainOffset = i * 0x1000;
+
+		if (pEepData->baseEepHeader.txMask & (1 << i)) {
+			pRawDatasetOpenLoop =
+			(struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i];
+
+			if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+				int8_t txPower;
+				ar9287_eeprom_get_tx_gain_index(ah, chan,
+							pRawDatasetOpenLoop,
+							pCalBChans, numPiers,
+							&txPower);
+				ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i);
+			} else {
+				pRawDataset =
+					(struct cal_data_per_freq_ar9287 *)
+					pEepData->calPierData2G[i];
+
+				ath9k_hw_get_gain_boundaries_pdadcs(ah, chan,
+							   pRawDataset,
+							   pCalBChans, numPiers,
+							   pdGainOverlap_t2,
+							   gainBoundaries,
+							   pdadcValues,
+							   numXpdGain);
+			}
+
+			ENABLE_REGWRITE_BUFFER(ah);
+
+			if (i == 0) {
+				if (!ath9k_hw_ar9287_get_eeprom(ah,
+							EEP_OL_PWRCTRL)) {
+
+					regval = SM(pdGainOverlap_t2,
+						    AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
+						| SM(gainBoundaries[0],
+						     AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+						| SM(gainBoundaries[1],
+						     AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+						| SM(gainBoundaries[2],
+						     AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+						| SM(gainBoundaries[3],
+						     AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4);
+
+					REG_WRITE(ah,
+						  AR_PHY_TPCRG5 + regChainOffset,
+						  regval);
+				}
+			}
+
+			if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB !=
+			    pEepData->baseEepHeader.pwrTableOffset) {
+				diff = (u16)(pEepData->baseEepHeader.pwrTableOffset -
+					     (int32_t)AR9287_PWR_TABLE_OFFSET_DB);
+				diff *= 2;
+
+				for (j = 0; j < ((u16)AR5416_NUM_PDADC_VALUES-diff); j++)
+					pdadcValues[j] = pdadcValues[j+diff];
+
+				for (j = (u16)(AR5416_NUM_PDADC_VALUES-diff);
+				     j < AR5416_NUM_PDADC_VALUES; j++)
+					pdadcValues[j] =
+					  pdadcValues[AR5416_NUM_PDADC_VALUES-diff];
+			}
+
+			if (!ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+				regOffset = AR_PHY_BASE +
+					(672 << 2) + regChainOffset;
+
+				for (j = 0; j < 32; j++) {
+					reg32 = ((pdadcValues[4*j + 0] & 0xFF) << 0)
+						| ((pdadcValues[4*j + 1] & 0xFF) << 8)
+						| ((pdadcValues[4*j + 2] & 0xFF) << 16)
+						| ((pdadcValues[4*j + 3] & 0xFF) << 24);
+
+					REG_WRITE(ah, regOffset, reg32);
+					regOffset += 4;
+				}
+			}
+			REGWRITE_BUFFER_FLUSH(ah);
+		}
+	}
+
+	*pTxPowerIndexOffset = 0;
+}
+
+static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
+						     struct ath9k_channel *chan,
+						     int16_t *ratesArray,
+						     u16 cfgCtl,
+						     u16 AntennaReduction,
+						     u16 twiceMaxRegulatoryPower,
+						     u16 powerLimit)
+{
+#define CMP_CTL \
+	(((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
+	 pEepData->ctlIndex[i])
+
+#define CMP_NO_CTL \
+	(((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
+	 ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))
+
+#define REDUCE_SCALED_POWER_BY_TWO_CHAIN     6
+#define REDUCE_SCALED_POWER_BY_THREE_CHAIN   10
+
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+	u16 twiceMaxEdgePower = MAX_RATE_POWER;
+	static const u16 tpScaleReductionTable[5] =
+		{ 0, 3, 6, 9, MAX_RATE_POWER };
+	unsigned int i;
+	int16_t twiceLargestAntenna;
+	struct cal_ctl_data_ar9287 *rep;
+	struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} },
+				    targetPowerCck = {0, {0, 0, 0, 0} };
+	struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} },
+				    targetPowerCckExt = {0, {0, 0, 0, 0} };
+	struct cal_target_power_ht targetPowerHt20,
+				    targetPowerHt40 = {0, {0, 0, 0, 0} };
+	u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+	static const u16 ctlModesFor11g[] = {
+		CTL_11B, CTL_11G, CTL_2GHT20,
+		CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40
+	};
+	u16 numCtlModes = 0;
+	const u16 *pCtlMode = NULL;
+	u16 ctlMode, freq;
+	struct chan_centers centers;
+	int tx_chainmask;
+	u16 twiceMinEdgePower;
+	struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
+	tx_chainmask = ah->txchainmask;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+	/* Compute TxPower reduction due to Antenna Gain */
+	twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0],
+				  pEepData->modalHeader.antennaGainCh[1]);
+	twiceLargestAntenna = (int16_t)min((AntennaReduction) -
+					   twiceLargestAntenna, 0);
+
+	/*
+	 * scaledPower is the minimum of the user input power level
+	 * and the regulatory allowed power level.
+	 */
+	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
+	if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX)
+		maxRegAllowedPower -=
+			(tpScaleReductionTable[(regulatory->tp_scale)] * 2);
+
+	scaledPower = min(powerLimit, maxRegAllowedPower);
+
+	/*
+	 * Reduce scaled Power by number of chains active
+	 * to get the per chain tx power level.
+	 */
+	switch (ar5416_get_ntxchains(tx_chainmask)) {
+	case 1:
+		break;
+	case 2:
+		if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
+			scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+		else
+			scaledPower = 0;
+		break;
+	case 3:
+		if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
+			scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+		else
+			scaledPower = 0;
+		break;
+	}
+	scaledPower = max((u16)0, scaledPower);
+
+	/*
+	 * Get TX power from EEPROM.
+	 */
+	if (IS_CHAN_2GHZ(chan))	{
+		/* CTL_11B, CTL_11G, CTL_2GHT20 */
+		numCtlModes =
+			ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
+
+		pCtlMode = ctlModesFor11g;
+
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+						  pEepData->calTargetPowerCck,
+						  AR9287_NUM_2G_CCK_TARGET_POWERS,
+						  &targetPowerCck, 4, 0);
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+						  pEepData->calTargetPower2G,
+						  AR9287_NUM_2G_20_TARGET_POWERS,
+						  &targetPowerOfdm, 4, 0);
+		ath9k_hw_get_target_powers(ah, chan,
+					   pEepData->calTargetPower2GHT20,
+					   AR9287_NUM_2G_20_TARGET_POWERS,
+					   &targetPowerHt20, 8, 0);
+
+		if (IS_CHAN_HT40(chan))	{
+			/* All 2G CTLs */
+			numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+			ath9k_hw_get_target_powers(ah, chan,
+						   pEepData->calTargetPower2GHT40,
+						   AR9287_NUM_2G_40_TARGET_POWERS,
+						   &targetPowerHt40, 8, 1);
+			ath9k_hw_get_legacy_target_powers(ah, chan,
+						  pEepData->calTargetPowerCck,
+						  AR9287_NUM_2G_CCK_TARGET_POWERS,
+						  &targetPowerCckExt, 4, 1);
+			ath9k_hw_get_legacy_target_powers(ah, chan,
+						  pEepData->calTargetPower2G,
+						  AR9287_NUM_2G_20_TARGET_POWERS,
+						  &targetPowerOfdmExt, 4, 1);
+		}
+	}
+
+	for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+		int isHt40CtlMode =
+			(pCtlMode[ctlMode] == CTL_2GHT40) ? 1 : 0;
+
+		if (isHt40CtlMode)
+			freq = centers.synth_center;
+		else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+			freq = centers.ext_center;
+		else
+			freq = centers.ctl_center;
+
+		/* Walk through the CTL indices stored in EEPROM */
+		for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
+			struct cal_ctl_edges *pRdEdgesPower;
+
+			/*
+			 * Compare test group from regulatory channel list
+			 * with test mode from pCtlMode list
+			 */
+			if (CMP_CTL || CMP_NO_CTL) {
+				rep = &(pEepData->ctlData[i]);
+				pRdEdgesPower =
+				rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1];
+
+				twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
+								pRdEdgesPower,
+								IS_CHAN_2GHZ(chan),
+								AR5416_NUM_BAND_EDGES);
+
+				if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+					twiceMaxEdgePower = min(twiceMaxEdgePower,
+								twiceMinEdgePower);
+				} else {
+					twiceMaxEdgePower = twiceMinEdgePower;
+					break;
+				}
+			}
+		}
+
+		minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
+
+		/* Apply ctl mode to correct target power set */
+		switch (pCtlMode[ctlMode]) {
+		case CTL_11B:
+			for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
+				targetPowerCck.tPow2x[i] =
+					(u8)min((u16)targetPowerCck.tPow2x[i],
+						minCtlPower);
+			}
+			break;
+		case CTL_11A:
+		case CTL_11G:
+			for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
+				targetPowerOfdm.tPow2x[i] =
+					(u8)min((u16)targetPowerOfdm.tPow2x[i],
+						minCtlPower);
+			}
+			break;
+		case CTL_5GHT20:
+		case CTL_2GHT20:
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
+				targetPowerHt20.tPow2x[i] =
+					(u8)min((u16)targetPowerHt20.tPow2x[i],
+						minCtlPower);
+			}
+			break;
+		case CTL_11B_EXT:
+			targetPowerCckExt.tPow2x[0] =
+				(u8)min((u16)targetPowerCckExt.tPow2x[0],
+					minCtlPower);
+			break;
+		case CTL_11A_EXT:
+		case CTL_11G_EXT:
+			targetPowerOfdmExt.tPow2x[0] =
+				(u8)min((u16)targetPowerOfdmExt.tPow2x[0],
+					minCtlPower);
+			break;
+		case CTL_5GHT40:
+		case CTL_2GHT40:
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+				targetPowerHt40.tPow2x[i] =
+					(u8)min((u16)targetPowerHt40.tPow2x[i],
+						minCtlPower);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* Now set the rates array */
+
+	ratesArray[rate6mb] =
+	ratesArray[rate9mb] =
+	ratesArray[rate12mb] =
+	ratesArray[rate18mb] =
+	ratesArray[rate24mb] = targetPowerOfdm.tPow2x[0];
+
+	ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
+	ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
+	ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
+	ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
+
+	for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
+		ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
+
+	if (IS_CHAN_2GHZ(chan))	{
+		ratesArray[rate1l] = targetPowerCck.tPow2x[0];
+		ratesArray[rate2s] =
+		ratesArray[rate2l] = targetPowerCck.tPow2x[1];
+		ratesArray[rate5_5s] =
+		ratesArray[rate5_5l] = targetPowerCck.tPow2x[2];
+		ratesArray[rate11s] =
+		ratesArray[rate11l] = targetPowerCck.tPow2x[3];
+	}
+	if (IS_CHAN_HT40(chan))	{
+		for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++)
+			ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i];
+
+		ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
+		ratesArray[rateDupCck]  = targetPowerHt40.tPow2x[0];
+		ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+
+		if (IS_CHAN_2GHZ(chan))
+			ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0];
+	}
+
+#undef CMP_CTL
+#undef CMP_NO_CTL
+#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN
+#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN
+}
+
+static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
+					struct ath9k_channel *chan, u16 cfgCtl,
+					u8 twiceAntennaReduction,
+					u8 twiceMaxRegulatoryPower,
+					u8 powerLimit, int test)
+{
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+	struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
+	struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
+	int16_t ratesArray[Ar5416RateSize];
+	int16_t txPowerIndexOffset = 0;
+	u8 ht40PowerIncForPdadc = 2;
+	unsigned int i;
+
+	memset(ratesArray, 0, sizeof(ratesArray));
+
+	if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
+	    AR9287_EEP_MINOR_VER_2)
+		ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+
+	ath9k_hw_set_ar9287_power_per_rate_table(ah, chan,
+						 &ratesArray[0], cfgCtl,
+						 twiceAntennaReduction,
+						 twiceMaxRegulatoryPower,
+						 powerLimit);
+
+	ath9k_hw_set_ar9287_power_cal_table(ah, chan, &txPowerIndexOffset);
+
+	regulatory->max_power_level = 0;
+	for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
+		ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
+		if (ratesArray[i] > MAX_RATE_POWER)
+			ratesArray[i] = MAX_RATE_POWER;
+
+		if (ratesArray[i] > regulatory->max_power_level)
+			regulatory->max_power_level = ratesArray[i];
+	}
+
+	if (test)
+		return;
+
+	if (IS_CHAN_2GHZ(chan))
+		i = rate1l;
+	else
+		i = rate6mb;
+
+	regulatory->max_power_level = ratesArray[i];
+
+	if (AR_SREV_9280_20_OR_LATER(ah)) {
+		for (i = 0; i < Ar5416RateSize; i++)
+			ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
+	}
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	/* OFDM power per rate */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+		  ATH9K_POW_SM(ratesArray[rate18mb], 24)
+		  | ATH9K_POW_SM(ratesArray[rate12mb], 16)
+		  | ATH9K_POW_SM(ratesArray[rate9mb], 8)
+		  | ATH9K_POW_SM(ratesArray[rate6mb], 0));
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+		  ATH9K_POW_SM(ratesArray[rate54mb], 24)
+		  | ATH9K_POW_SM(ratesArray[rate48mb], 16)
+		  | ATH9K_POW_SM(ratesArray[rate36mb], 8)
+		  | ATH9K_POW_SM(ratesArray[rate24mb], 0));
+
+	/* CCK power per rate */
+	if (IS_CHAN_2GHZ(chan))	{
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+			  ATH9K_POW_SM(ratesArray[rate2s], 24)
+			  | ATH9K_POW_SM(ratesArray[rate2l], 16)
+			  | ATH9K_POW_SM(ratesArray[rateXr], 8)
+			  | ATH9K_POW_SM(ratesArray[rate1l], 0));
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+			  ATH9K_POW_SM(ratesArray[rate11s], 24)
+			  | ATH9K_POW_SM(ratesArray[rate11l], 16)
+			  | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+			  | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
+	}
+
+	/* HT20 power per rate */
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
+		  ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
+		  ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
+
+	/* HT40 power per rate */
+	if (IS_CHAN_HT40(chan))	{
+		if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+			REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+				  ATH9K_POW_SM(ratesArray[rateHt40_3], 24)
+				  | ATH9K_POW_SM(ratesArray[rateHt40_2], 16)
+				  | ATH9K_POW_SM(ratesArray[rateHt40_1], 8)
+				  | ATH9K_POW_SM(ratesArray[rateHt40_0], 0));
+
+			REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+				  ATH9K_POW_SM(ratesArray[rateHt40_7], 24)
+				  | ATH9K_POW_SM(ratesArray[rateHt40_6], 16)
+				  | ATH9K_POW_SM(ratesArray[rateHt40_5], 8)
+				  | ATH9K_POW_SM(ratesArray[rateHt40_4], 0));
+		} else {
+			REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+				  ATH9K_POW_SM(ratesArray[rateHt40_3] +
+					       ht40PowerIncForPdadc, 24)
+				  | ATH9K_POW_SM(ratesArray[rateHt40_2] +
+						 ht40PowerIncForPdadc, 16)
+				  | ATH9K_POW_SM(ratesArray[rateHt40_1] +
+						 ht40PowerIncForPdadc, 8)
+				  | ATH9K_POW_SM(ratesArray[rateHt40_0] +
+						 ht40PowerIncForPdadc, 0));
+
+			REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+				  ATH9K_POW_SM(ratesArray[rateHt40_7] +
+					       ht40PowerIncForPdadc, 24)
+				  | ATH9K_POW_SM(ratesArray[rateHt40_6] +
+						 ht40PowerIncForPdadc, 16)
+				  | ATH9K_POW_SM(ratesArray[rateHt40_5] +
+						 ht40PowerIncForPdadc, 8)
+				  | ATH9K_POW_SM(ratesArray[rateHt40_4] +
+						 ht40PowerIncForPdadc, 0));
+		}
+
+		/* Dup/Ext power per rate */
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+			  ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+			  | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+			  | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+			  | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+	}
+	REGWRITE_BUFFER_FLUSH(ah);
+}
+
+static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah __unused,
+				      struct ath9k_channel *chan __unused)
+{
+}
+
+static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
+					     struct ath9k_channel *chan)
+{
+	struct ar9287_eeprom *eep = &ah->eeprom.map9287;
+	struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
+	u32 regChainOffset, regval;
+	u8 txRxAttenLocal;
+	int i;
+
+	pModal = &eep->modalHeader;
+
+	REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon);
+
+	for (i = 0; i < AR9287_MAX_CHAINS; i++)	{
+		regChainOffset = i * 0x1000;
+
+		REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
+			  pModal->antCtrlChain[i]);
+
+		REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
+			  (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset)
+			   & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+			       AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+			  SM(pModal->iqCalICh[i],
+			     AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+			  SM(pModal->iqCalQCh[i],
+			     AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
+
+		txRxAttenLocal = pModal->txRxAttenCh[i];
+
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			      AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+			      pModal->bswMargin[i]);
+		REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			      AR_PHY_GAIN_2GHZ_XATTEN1_DB,
+			      pModal->bswAtten[i]);
+		REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
+			      AR9280_PHY_RXGAIN_TXRX_ATTEN,
+			      txRxAttenLocal);
+		REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
+			      AR9280_PHY_RXGAIN_TXRX_MARGIN,
+			      pModal->rxTxMarginCh[i]);
+	}
+
+
+	if (IS_CHAN_HT40(chan))
+		REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+			      AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40);
+	else
+		REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+			      AR_PHY_SETTLING_SWITCH, pModal->switchSettling);
+
+	REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+		      AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize);
+
+	REG_WRITE(ah, AR_PHY_RF_CTL4,
+		  SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
+		  | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
+		  | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON)
+		  | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));
+
+	REG_RMW_FIELD(ah, AR_PHY_RF_CTL3,
+		      AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn);
+
+	REG_RMW_FIELD(ah, AR_PHY_CCA,
+		      AR9280_PHY_CCA_THRESH62, pModal->thresh62);
+	REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
+		      AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62);
+
+	regval = REG_READ(ah, AR9287_AN_RF2G3_CH0);
+	regval &= ~(AR9287_AN_RF2G3_DB1 |
+		    AR9287_AN_RF2G3_DB2 |
+		    AR9287_AN_RF2G3_OB_CCK |
+		    AR9287_AN_RF2G3_OB_PSK |
+		    AR9287_AN_RF2G3_OB_QAM |
+		    AR9287_AN_RF2G3_OB_PAL_OFF);
+	regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
+		   SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
+		   SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
+		   SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
+		   SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
+		   SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
+
+	ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH0, regval);
+
+	regval = REG_READ(ah, AR9287_AN_RF2G3_CH1);
+	regval &= ~(AR9287_AN_RF2G3_DB1 |
+		    AR9287_AN_RF2G3_DB2 |
+		    AR9287_AN_RF2G3_OB_CCK |
+		    AR9287_AN_RF2G3_OB_PSK |
+		    AR9287_AN_RF2G3_OB_QAM |
+		    AR9287_AN_RF2G3_OB_PAL_OFF);
+	regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
+		   SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
+		   SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
+		   SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
+		   SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
+		   SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
+
+	ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH1, regval);
+
+	REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
+		      AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart);
+	REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
+		      AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn);
+
+	ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2,
+				  AR9287_AN_TOP2_XPABIAS_LVL,
+				  AR9287_AN_TOP2_XPABIAS_LVL_S,
+				  pModal->xpaBiasLvl);
+}
+
+static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,
+					    u16 i, int is2GHz)
+{
+#define EEP_MAP9287_SPURCHAN \
+	(ah->eeprom.map9287.modalHeader.spurChans[i].spurChan)
+
+	u16 spur_val = AR_NO_SPUR;
+
+	DBG2("ath9k: "
+		"Getting spur idx:%d is2Ghz:%d val:%x\n",
+		i, is2GHz, ah->config.spurchans[i][is2GHz]);
+
+	switch (ah->config.spurmode) {
+	case SPUR_DISABLE:
+		break;
+	case SPUR_ENABLE_IOCTL:
+		spur_val = ah->config.spurchans[i][is2GHz];
+		DBG2("ath9k: "
+			"Getting spur val from new loc. %d\n", spur_val);
+		break;
+	case SPUR_ENABLE_EEPROM:
+		spur_val = EEP_MAP9287_SPURCHAN;
+		break;
+	}
+
+	return spur_val;
+
+#undef EEP_MAP9287_SPURCHAN
+}
+
+const struct eeprom_ops eep_ar9287_ops = {
+	.check_eeprom		= ath9k_hw_ar9287_check_eeprom,
+	.get_eeprom		= ath9k_hw_ar9287_get_eeprom,
+	.fill_eeprom		= ath9k_hw_ar9287_fill_eeprom,
+	.get_eeprom_ver		= ath9k_hw_ar9287_get_eeprom_ver,
+	.get_eeprom_rev		= ath9k_hw_ar9287_get_eeprom_rev,
+	.set_board_values	= ath9k_hw_ar9287_set_board_values,
+	.set_addac		= ath9k_hw_ar9287_set_addac,
+	.set_txpower		= ath9k_hw_ar9287_set_txpower,
+	.get_spur_channel	= ath9k_hw_ar9287_get_spur_channel
+};
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_eeprom_def.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_eeprom_def.c
new file mode 100644
index 0000000000000000000000000000000000000000..9b144d70b063797e6a0136db0e3c8a053c71ba8b
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_eeprom_def.c
@@ -0,0 +1,1351 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/io.h>
+
+#include "hw.h"
+#include "ar9002_phy.h"
+
+static void ath9k_get_txgain_index(struct ath_hw *ah,
+		struct ath9k_channel *chan,
+		struct calDataPerFreqOpLoop *rawDatasetOpLoop,
+		u8 *calChans,  u16 availPiers, u8 *pwr, u8 *pcdacIdx)
+{
+	u8 pcdac, i = 0;
+	u16 idxL = 0, idxR = 0, numPiers;
+	int match;
+	struct chan_centers centers;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+	for (numPiers = 0; numPiers < availPiers; numPiers++)
+		if (calChans[numPiers] == AR5416_BCHAN_UNUSED)
+			break;
+
+	match = ath9k_hw_get_lower_upper_index(
+			(u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
+			calChans, numPiers, &idxL, &idxR);
+	if (match) {
+		pcdac = rawDatasetOpLoop[idxL].pcdac[0][0];
+		*pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0];
+	} else {
+		pcdac = rawDatasetOpLoop[idxR].pcdac[0][0];
+		*pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] +
+				rawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
+	}
+
+	while (pcdac > ah->originalGain[i] &&
+			i < (AR9280_TX_GAIN_TABLE_SIZE - 1))
+		i++;
+
+	*pcdacIdx = i;
+}
+
+static void ath9k_olc_get_pdadcs(struct ath_hw *ah,
+				u32 initTxGain,
+				int txPower,
+				u8 *pPDADCValues)
+{
+	u32 i;
+	u32 offset;
+
+	REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0,
+			AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
+	REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1,
+			AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
+
+	REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7,
+			AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain);
+
+	offset = txPower;
+	for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++)
+		if (i < offset)
+			pPDADCValues[i] = 0x0;
+		else
+			pPDADCValues[i] = 0xFF;
+}
+
+static int ath9k_hw_def_get_eeprom_ver(struct ath_hw *ah)
+{
+	return ((ah->eeprom.def.baseEepHeader.version >> 12) & 0xF);
+}
+
+static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah)
+{
+	return ((ah->eeprom.def.baseEepHeader.version) & 0xFFF);
+}
+
+#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16))
+
+static int __ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	u16 *eep_data = (u16 *)&ah->eeprom.def;
+	unsigned int addr;
+	int ar5416_eep_start_loc = 0x100;
+
+	for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) {
+		if (!ath9k_hw_nvram_read(common, addr + ar5416_eep_start_loc,
+					 eep_data)) {
+			DBG("ath9k: "
+				"Unable to read eeprom region\n");
+			return 0;
+		}
+		eep_data++;
+	}
+	return 1;
+}
+
+static int __ath9k_hw_usb_def_fill_eeprom(struct ath_hw *ah)
+{
+	u16 *eep_data = (u16 *)&ah->eeprom.def;
+
+	ath9k_hw_usb_gen_fill_eeprom(ah, eep_data,
+				     0x100, SIZE_EEPROM_DEF);
+	return 1;
+}
+
+static int ath9k_hw_def_fill_eeprom(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	if (!ath9k_hw_use_flash(ah)) {
+		DBG2("ath9k: "
+			"Reading from EEPROM, not flash\n");
+	}
+
+	if (common->bus_ops->ath_bus_type == ATH_USB)
+		return __ath9k_hw_usb_def_fill_eeprom(ah);
+	else
+		return __ath9k_hw_def_fill_eeprom(ah);
+}
+
+#undef SIZE_EEPROM_DEF
+
+static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
+{
+	struct ar5416_eeprom_def *eep =
+		(struct ar5416_eeprom_def *) &ah->eeprom.def;
+	struct ath_common *common = ath9k_hw_common(ah);
+	u16 *eepdata, temp, magic, magic2;
+	u32 sum = 0, el;
+	int need_swap = 0;
+	unsigned int i, addr, size;
+
+	if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
+		DBG("ath9k: Reading Magic # failed\n");
+		return 0;
+	}
+
+	if (!ath9k_hw_use_flash(ah)) {
+		DBG2("ath9k: "
+			"Read Magic = 0x%04X\n", magic);
+
+		if (magic != AR5416_EEPROM_MAGIC) {
+			magic2 = swab16(magic);
+
+			if (magic2 == AR5416_EEPROM_MAGIC) {
+				size = sizeof(struct ar5416_eeprom_def);
+				need_swap = 1;
+				eepdata = (u16 *) (&ah->eeprom);
+
+				for (addr = 0; addr < size / sizeof(u16); addr++) {
+					temp = swab16(*eepdata);
+					*eepdata = temp;
+					eepdata++;
+				}
+			} else {
+				DBG("ath9k: "
+					"Invalid EEPROM Magic. Endianness mismatch.\n");
+				return -EINVAL;
+			}
+		}
+	}
+
+	DBG2("ath9k: need_swap = %s.\n",
+		need_swap ? "True" : "False");
+
+	if (need_swap)
+		el = swab16(ah->eeprom.def.baseEepHeader.length);
+	else
+		el = ah->eeprom.def.baseEepHeader.length;
+
+	if (el > sizeof(struct ar5416_eeprom_def))
+		el = sizeof(struct ar5416_eeprom_def) / sizeof(u16);
+	else
+		el = el / sizeof(u16);
+
+	eepdata = (u16 *)(&ah->eeprom);
+
+	for (i = 0; i < el; i++)
+		sum ^= *eepdata++;
+
+	if (need_swap) {
+		u32 integer, j;
+		u16 word;
+
+		DBG("ath9k: "
+			"EEPROM Endianness is not native.. Changing.\n");
+
+		word = swab16(eep->baseEepHeader.length);
+		eep->baseEepHeader.length = word;
+
+		word = swab16(eep->baseEepHeader.checksum);
+		eep->baseEepHeader.checksum = word;
+
+		word = swab16(eep->baseEepHeader.version);
+		eep->baseEepHeader.version = word;
+
+		word = swab16(eep->baseEepHeader.regDmn[0]);
+		eep->baseEepHeader.regDmn[0] = word;
+
+		word = swab16(eep->baseEepHeader.regDmn[1]);
+		eep->baseEepHeader.regDmn[1] = word;
+
+		word = swab16(eep->baseEepHeader.rfSilent);
+		eep->baseEepHeader.rfSilent = word;
+
+		word = swab16(eep->baseEepHeader.blueToothOptions);
+		eep->baseEepHeader.blueToothOptions = word;
+
+		word = swab16(eep->baseEepHeader.deviceCap);
+		eep->baseEepHeader.deviceCap = word;
+
+		for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) {
+			struct modal_eep_header *pModal =
+				&eep->modalHeader[j];
+			integer = swab32(pModal->antCtrlCommon);
+			pModal->antCtrlCommon = integer;
+
+			for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+				integer = swab32(pModal->antCtrlChain[i]);
+				pModal->antCtrlChain[i] = integer;
+			}
+			for (i = 0; i < 3; i++) {
+				word = swab16(pModal->xpaBiasLvlFreq[i]);
+				pModal->xpaBiasLvlFreq[i] = word;
+			}
+
+			for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+				word = swab16(pModal->spurChans[i].spurChan);
+				pModal->spurChans[i].spurChan = word;
+			}
+		}
+	}
+
+	if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER ||
+	    ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) {
+		DBG("ath9k: Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+			sum, ah->eep_ops->get_eeprom_ver(ah));
+		return -EINVAL;
+	}
+
+	/* Enable fixup for AR_AN_TOP2 if necessary */
+	if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
+	    ((eep->baseEepHeader.version & 0xff) > 0x0a) &&
+	    (eep->baseEepHeader.pwdclkind == 0))
+		ah->need_an_top2_fixup = 1;
+
+	if ((common->bus_ops->ath_bus_type == ATH_USB) &&
+	    (AR_SREV_9280(ah)))
+		eep->modalHeader[0].xpaBiasLvl = 0;
+
+	return 0;
+}
+
+static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
+				   enum eeprom_param param)
+{
+	struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+	struct modal_eep_header *pModal = eep->modalHeader;
+	struct base_eep_header *pBase = &eep->baseEepHeader;
+
+	switch (param) {
+	case EEP_NFTHRESH_5:
+		return pModal[0].noiseFloorThreshCh[0];
+	case EEP_NFTHRESH_2:
+		return pModal[1].noiseFloorThreshCh[0];
+	case EEP_MAC_LSW:
+		return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+	case EEP_MAC_MID:
+		return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+	case EEP_MAC_MSW:
+		return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+	case EEP_REG_0:
+		return pBase->regDmn[0];
+	case EEP_REG_1:
+		return pBase->regDmn[1];
+	case EEP_OP_CAP:
+		return pBase->deviceCap;
+	case EEP_OP_MODE:
+		return pBase->opCapFlags;
+	case EEP_RF_SILENT:
+		return pBase->rfSilent;
+	case EEP_OB_5:
+		return pModal[0].ob;
+	case EEP_DB_5:
+		return pModal[0].db;
+	case EEP_OB_2:
+		return pModal[1].ob;
+	case EEP_DB_2:
+		return pModal[1].db;
+	case EEP_MINOR_REV:
+		return AR5416_VER_MASK;
+	case EEP_TX_MASK:
+		return pBase->txMask;
+	case EEP_RX_MASK:
+		return pBase->rxMask;
+	case EEP_FSTCLK_5G:
+		return pBase->fastClk5g;
+	case EEP_RXGAIN_TYPE:
+		return pBase->rxGainType;
+	case EEP_TXGAIN_TYPE:
+		return pBase->txGainType;
+	case EEP_OL_PWRCTRL:
+		if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19)
+			return pBase->openLoopPwrCntl ? 1 : 0;
+		else
+			return 0;
+	case EEP_RC_CHAIN_MASK:
+		if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19)
+			return pBase->rcChainMask;
+		else
+			return 0;
+	case EEP_DAC_HPWR_5G:
+		if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20)
+			return pBase->dacHiPwrMode_5G;
+		else
+			return 0;
+	case EEP_FRAC_N_5G:
+		if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22)
+			return pBase->frac_n_5g;
+		else
+			return 0;
+	case EEP_PWR_TABLE_OFFSET:
+		if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_21)
+			return pBase->pwr_table_offset;
+		else
+			return AR5416_PWR_TABLE_OFFSET_DB;
+	default:
+		return 0;
+	}
+}
+
+static void ath9k_hw_def_set_gain(struct ath_hw *ah,
+				  struct modal_eep_header *pModal,
+				  struct ar5416_eeprom_def *eep,
+				  u8 txRxAttenLocal, int regChainOffset, int i)
+{
+	if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) {
+		txRxAttenLocal = pModal->txRxAttenCh[i];
+
+		if (AR_SREV_9280_20_OR_LATER(ah)) {
+			REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			      AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+			      pModal->bswMargin[i]);
+			REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			      AR_PHY_GAIN_2GHZ_XATTEN1_DB,
+			      pModal->bswAtten[i]);
+			REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			      AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+			      pModal->xatten2Margin[i]);
+			REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			      AR_PHY_GAIN_2GHZ_XATTEN2_DB,
+			      pModal->xatten2Db[i]);
+		} else {
+			REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			  (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
+			   ~AR_PHY_GAIN_2GHZ_BSW_MARGIN)
+			  | SM(pModal-> bswMargin[i],
+			       AR_PHY_GAIN_2GHZ_BSW_MARGIN));
+			REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
+			  (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
+			   ~AR_PHY_GAIN_2GHZ_BSW_ATTEN)
+			  | SM(pModal->bswAtten[i],
+			       AR_PHY_GAIN_2GHZ_BSW_ATTEN));
+		}
+	}
+
+	if (AR_SREV_9280_20_OR_LATER(ah)) {
+		REG_RMW_FIELD(ah,
+		      AR_PHY_RXGAIN + regChainOffset,
+		      AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
+		REG_RMW_FIELD(ah,
+		      AR_PHY_RXGAIN + regChainOffset,
+		      AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]);
+	} else {
+		REG_WRITE(ah,
+			  AR_PHY_RXGAIN + regChainOffset,
+			  (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) &
+			   ~AR_PHY_RXGAIN_TXRX_ATTEN)
+			  | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN));
+		REG_WRITE(ah,
+			  AR_PHY_GAIN_2GHZ + regChainOffset,
+			  (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) &
+			   ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) |
+			  SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN));
+	}
+}
+
+static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
+					  struct ath9k_channel *chan)
+{
+	struct modal_eep_header *pModal;
+	struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+	int i, regChainOffset;
+	u8 txRxAttenLocal;
+
+	pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+	txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
+
+	REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon & 0xffff);
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		if (AR_SREV_9280(ah)) {
+			if (i >= 2)
+				break;
+		}
+
+		if (AR_SREV_5416_20_OR_LATER(ah) &&
+		    (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0))
+			regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+		else
+			regChainOffset = i * 0x1000;
+
+		REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
+			  pModal->antCtrlChain[i]);
+
+		REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
+			  (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) &
+			   ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+			     AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+			  SM(pModal->iqCalICh[i],
+			     AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+			  SM(pModal->iqCalQCh[i],
+			     AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
+
+		if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah))
+			ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal,
+					      regChainOffset, i);
+	}
+
+	if (AR_SREV_9280_20_OR_LATER(ah)) {
+		if (IS_CHAN_2GHZ(chan)) {
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
+						  AR_AN_RF2G1_CH0_OB,
+						  AR_AN_RF2G1_CH0_OB_S,
+						  pModal->ob);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
+						  AR_AN_RF2G1_CH0_DB,
+						  AR_AN_RF2G1_CH0_DB_S,
+						  pModal->db);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
+						  AR_AN_RF2G1_CH1_OB,
+						  AR_AN_RF2G1_CH1_OB_S,
+						  pModal->ob_ch1);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
+						  AR_AN_RF2G1_CH1_DB,
+						  AR_AN_RF2G1_CH1_DB_S,
+						  pModal->db_ch1);
+		} else {
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
+						  AR_AN_RF5G1_CH0_OB5,
+						  AR_AN_RF5G1_CH0_OB5_S,
+						  pModal->ob);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
+						  AR_AN_RF5G1_CH0_DB5,
+						  AR_AN_RF5G1_CH0_DB5_S,
+						  pModal->db);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
+						  AR_AN_RF5G1_CH1_OB5,
+						  AR_AN_RF5G1_CH1_OB5_S,
+						  pModal->ob_ch1);
+			ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
+						  AR_AN_RF5G1_CH1_DB5,
+						  AR_AN_RF5G1_CH1_DB5_S,
+						  pModal->db_ch1);
+		}
+		ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
+					  AR_AN_TOP2_XPABIAS_LVL,
+					  AR_AN_TOP2_XPABIAS_LVL_S,
+					  pModal->xpaBiasLvl);
+		ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
+					  AR_AN_TOP2_LOCALBIAS,
+					  AR_AN_TOP2_LOCALBIAS_S,
+					  !!(pModal->lna_ctl &
+					     LNA_CTL_LOCAL_BIAS));
+		REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,
+			      !!(pModal->lna_ctl & LNA_CTL_FORCE_XPA));
+	}
+
+	REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
+		      pModal->switchSettling);
+	REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
+		      pModal->adcDesiredSize);
+
+	if (!AR_SREV_9280_20_OR_LATER(ah))
+		REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+			      AR_PHY_DESIRED_SZ_PGA,
+			      pModal->pgaDesiredSize);
+
+	REG_WRITE(ah, AR_PHY_RF_CTL4,
+		  SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
+		  | SM(pModal->txEndToXpaOff,
+		       AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
+		  | SM(pModal->txFrameToXpaOn,
+		       AR_PHY_RF_CTL4_FRAME_XPAA_ON)
+		  | SM(pModal->txFrameToXpaOn,
+		       AR_PHY_RF_CTL4_FRAME_XPAB_ON));
+
+	REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
+		      pModal->txEndToRxOn);
+
+	if (AR_SREV_9280_20_OR_LATER(ah)) {
+		REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
+			      pModal->thresh62);
+		REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
+			      AR_PHY_EXT_CCA0_THRESH62,
+			      pModal->thresh62);
+	} else {
+		REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62,
+			      pModal->thresh62);
+		REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+			      AR_PHY_EXT_CCA_THRESH62,
+			      pModal->thresh62);
+	}
+
+	if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) {
+		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
+			      AR_PHY_TX_END_DATA_START,
+			      pModal->txFrameToDataStart);
+		REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
+			      pModal->txFrameToPaOn);
+	}
+
+	if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) {
+		if (IS_CHAN_HT40(chan))
+			REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+				      AR_PHY_SETTLING_SWITCH,
+				      pModal->swSettleHt40);
+	}
+
+	if (AR_SREV_9280_20_OR_LATER(ah) &&
+	    AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19)
+		REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL,
+			      AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK,
+			      pModal->miscBits);
+
+
+	if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) {
+		if (IS_CHAN_2GHZ(chan))
+			REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE,
+					eep->baseEepHeader.dacLpMode);
+		else if (eep->baseEepHeader.dacHiPwrMode_5G)
+			REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0);
+		else
+			REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE,
+				      eep->baseEepHeader.dacLpMode);
+
+		udelay(100);
+
+		REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP,
+			      pModal->miscBits >> 2);
+
+		REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9,
+			      AR_PHY_TX_DESIRED_SCALE_CCK,
+			      eep->baseEepHeader.desiredScaleCCK);
+	}
+}
+
+static void ath9k_hw_def_set_addac(struct ath_hw *ah,
+				   struct ath9k_channel *chan)
+{
+#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt])
+	struct modal_eep_header *pModal;
+	struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+	u8 biaslevel;
+
+	if (ah->hw_version.macVersion != AR_SREV_VERSION_9160)
+		return;
+
+	if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7)
+		return;
+
+	pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+
+	if (pModal->xpaBiasLvl != 0xff) {
+		biaslevel = pModal->xpaBiasLvl;
+	} else {
+		u16 resetFreqBin, freqBin, freqCount = 0;
+		struct chan_centers centers;
+
+		ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+		resetFreqBin = FREQ2FBIN(centers.synth_center,
+					 IS_CHAN_2GHZ(chan));
+		freqBin = XPA_LVL_FREQ(0) & 0xff;
+		biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14);
+
+		freqCount++;
+
+		while (freqCount < 3) {
+			if (XPA_LVL_FREQ(freqCount) == 0x0)
+				break;
+
+			freqBin = XPA_LVL_FREQ(freqCount) & 0xff;
+			if (resetFreqBin >= freqBin)
+				biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14);
+			else
+				break;
+			freqCount++;
+		}
+	}
+
+	if (IS_CHAN_2GHZ(chan)) {
+		INI_RA(&ah->iniAddac, 7, 1) = (INI_RA(&ah->iniAddac,
+					7, 1) & (~0x18)) | biaslevel << 3;
+	} else {
+		INI_RA(&ah->iniAddac, 6, 1) = (INI_RA(&ah->iniAddac,
+					6, 1) & (~0xc0)) | biaslevel << 6;
+	}
+#undef XPA_LVL_FREQ
+}
+
+static int16_t ath9k_change_gain_boundary_setting(struct ath_hw *ah,
+				u16 *gb,
+				u16 numXpdGain,
+				u16 pdGainOverlap_t2,
+				int8_t pwr_table_offset,
+				int16_t *diff)
+
+{
+	u16 k;
+
+	/* Prior to writing the boundaries or the pdadc vs. power table
+	 * into the chip registers the default starting point on the pdadc
+	 * vs. power table needs to be checked and the curve boundaries
+	 * adjusted accordingly
+	 */
+	if (AR_SREV_9280_20_OR_LATER(ah)) {
+		u16 gb_limit;
+
+		if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) {
+			/* get the difference in dB */
+			*diff = (u16)(pwr_table_offset - AR5416_PWR_TABLE_OFFSET_DB);
+			/* get the number of half dB steps */
+			*diff *= 2;
+			/* change the original gain boundary settings
+			 * by the number of half dB steps
+			 */
+			for (k = 0; k < numXpdGain; k++)
+				gb[k] = (u16)(gb[k] - *diff);
+		}
+		/* Because of a hardware limitation, ensure the gain boundary
+		 * is not larger than (63 - overlap)
+		 */
+		gb_limit = (u16)(MAX_RATE_POWER - pdGainOverlap_t2);
+
+		for (k = 0; k < numXpdGain; k++)
+			gb[k] = (u16)min(gb_limit, gb[k]);
+	}
+
+	return *diff;
+}
+
+static void ath9k_adjust_pdadc_values(struct ath_hw *ah,
+				      int8_t pwr_table_offset,
+				      int16_t diff,
+				      u8 *pdadcValues)
+{
+#define NUM_PDADC(diff) (AR5416_NUM_PDADC_VALUES - diff)
+	u16 k;
+
+	/* If this is a board that has a pwrTableOffset that differs from
+	 * the default AR5416_PWR_TABLE_OFFSET_DB then the start of the
+	 * pdadc vs pwr table needs to be adjusted prior to writing to the
+	 * chip.
+	 */
+	if (AR_SREV_9280_20_OR_LATER(ah)) {
+		if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) {
+			/* shift the table to start at the new offset */
+			for (k = 0; k < (u16)NUM_PDADC(diff); k++ ) {
+				pdadcValues[k] = pdadcValues[k + diff];
+			}
+
+			/* fill the back of the table */
+			for (k = (u16)NUM_PDADC(diff); k < NUM_PDADC(0); k++) {
+				pdadcValues[k] = pdadcValues[NUM_PDADC(diff)];
+			}
+		}
+	}
+#undef NUM_PDADC
+}
+
+static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
+				  struct ath9k_channel *chan,
+				  int16_t *pTxPowerIndexOffset)
+{
+#define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x)
+#define SM_PDGAIN_B(x, y) \
+		SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y)
+	struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
+	struct cal_data_per_freq *pRawDataset;
+	u8 *pCalBChans = NULL;
+	u16 pdGainOverlap_t2;
+	static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
+	u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
+	u16 numPiers, i, j;
+	int16_t diff = 0;
+	u16 numXpdGain, xpdMask;
+	u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
+	u32 reg32, regOffset, regChainOffset;
+	int16_t modalIdx;
+	int8_t pwr_table_offset;
+
+	modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
+	xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
+
+	pwr_table_offset = ah->eep_ops->get_eeprom(ah, EEP_PWR_TABLE_OFFSET);
+
+	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_2) {
+		pdGainOverlap_t2 =
+			pEepData->modalHeader[modalIdx].pdGainOverlap;
+	} else {
+		pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
+					    AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+	}
+
+	if (IS_CHAN_2GHZ(chan)) {
+		pCalBChans = pEepData->calFreqPier2G;
+		numPiers = AR5416_NUM_2G_CAL_PIERS;
+	} else {
+		pCalBChans = pEepData->calFreqPier5G;
+		numPiers = AR5416_NUM_5G_CAL_PIERS;
+	}
+
+	if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) {
+		pRawDataset = pEepData->calPierData2G[0];
+		ah->initPDADC = ((struct calDataPerFreqOpLoop *)
+				 pRawDataset)->vpdPdg[0][0];
+	}
+
+	numXpdGain = 0;
+
+	for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
+		if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
+			if (numXpdGain >= AR5416_NUM_PD_GAINS)
+				break;
+			xpdGainValues[numXpdGain] =
+				(u16)(AR5416_PD_GAINS_IN_MASK - i);
+			numXpdGain++;
+		}
+	}
+
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+		      (numXpdGain - 1) & 0x3);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+		      xpdGainValues[0]);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+		      xpdGainValues[1]);
+	REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
+		      xpdGainValues[2]);
+
+	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+		if (AR_SREV_5416_20_OR_LATER(ah) &&
+		    (ah->rxchainmask == 5 || ah->txchainmask == 5) &&
+		    (i != 0)) {
+			regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+		} else
+			regChainOffset = i * 0x1000;
+
+		if (pEepData->baseEepHeader.txMask & (1 << i)) {
+			if (IS_CHAN_2GHZ(chan))
+				pRawDataset = pEepData->calPierData2G[i];
+			else
+				pRawDataset = pEepData->calPierData5G[i];
+
+
+			if (OLC_FOR_AR9280_20_LATER) {
+				u8 pcdacIdx;
+				u8 txPower;
+
+				ath9k_get_txgain_index(ah, chan,
+				(struct calDataPerFreqOpLoop *)pRawDataset,
+				pCalBChans, numPiers, &txPower, &pcdacIdx);
+				ath9k_olc_get_pdadcs(ah, pcdacIdx,
+						     txPower/2, pdadcValues);
+			} else {
+				ath9k_hw_get_gain_boundaries_pdadcs(ah,
+							chan, pRawDataset,
+							pCalBChans, numPiers,
+							pdGainOverlap_t2,
+							gainBoundaries,
+							pdadcValues,
+							numXpdGain);
+			}
+
+			diff = ath9k_change_gain_boundary_setting(ah,
+							   gainBoundaries,
+							   numXpdGain,
+							   pdGainOverlap_t2,
+							   pwr_table_offset,
+							   &diff);
+
+			ENABLE_REGWRITE_BUFFER(ah);
+
+			if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
+				if (OLC_FOR_AR9280_20_LATER) {
+					REG_WRITE(ah,
+						AR_PHY_TPCRG5 + regChainOffset,
+						SM(0x6,
+						AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
+						SM_PD_GAIN(1) | SM_PD_GAIN(2) |
+						SM_PD_GAIN(3) | SM_PD_GAIN(4));
+				} else {
+					REG_WRITE(ah,
+						AR_PHY_TPCRG5 + regChainOffset,
+						SM(pdGainOverlap_t2,
+						AR_PHY_TPCRG5_PD_GAIN_OVERLAP)|
+						SM_PDGAIN_B(0, 1) |
+						SM_PDGAIN_B(1, 2) |
+						SM_PDGAIN_B(2, 3) |
+						SM_PDGAIN_B(3, 4));
+				}
+			}
+
+
+			ath9k_adjust_pdadc_values(ah, pwr_table_offset,
+						  diff, pdadcValues);
+
+			regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
+			for (j = 0; j < 32; j++) {
+				reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) |
+					((pdadcValues[4 * j + 1] & 0xFF) << 8) |
+					((pdadcValues[4 * j + 2] & 0xFF) << 16)|
+					((pdadcValues[4 * j + 3] & 0xFF) << 24);
+				REG_WRITE(ah, regOffset, reg32);
+
+				DBG2("ath9k: "
+					"PDADC (%d,%4x): %4.4x %8.8x\n",
+					i, regChainOffset, regOffset,
+					reg32);
+				DBG2("ath9k: "
+					"PDADC: Chain %d | PDADC %3d "
+					"Value %3d | PDADC %3d Value %3d | "
+					"PDADC %3d Value %3d | PDADC %3d "
+					"Value %3d |\n",
+					i, 4 * j, pdadcValues[4 * j],
+					4 * j + 1, pdadcValues[4 * j + 1],
+					4 * j + 2, pdadcValues[4 * j + 2],
+					4 * j + 3, pdadcValues[4 * j + 3]);
+
+				regOffset += 4;
+			}
+			REGWRITE_BUFFER_FLUSH(ah);
+		}
+	}
+
+	*pTxPowerIndexOffset = 0;
+#undef SM_PD_GAIN
+#undef SM_PDGAIN_B
+}
+
+static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
+						  struct ath9k_channel *chan,
+						  int16_t *ratesArray,
+						  u16 cfgCtl,
+						  u16 AntennaReduction,
+						  u16 twiceMaxRegulatoryPower,
+						  u16 powerLimit)
+{
+#define REDUCE_SCALED_POWER_BY_TWO_CHAIN     6  /* 10*log10(2)*2 */
+#define REDUCE_SCALED_POWER_BY_THREE_CHAIN   9 /* 10*log10(3)*2 */
+
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+	struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
+	u16 twiceMaxEdgePower = MAX_RATE_POWER;
+	static const u16 tpScaleReductionTable[5] =
+		{ 0, 3, 6, 9, MAX_RATE_POWER };
+
+	unsigned int i;
+	int16_t twiceLargestAntenna;
+	struct cal_ctl_data *rep;
+	struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
+		0, { 0, 0, 0, 0}
+	};
+	struct cal_target_power_leg targetPowerOfdmExt = {
+		0, { 0, 0, 0, 0} }, targetPowerCckExt = {
+		0, { 0, 0, 0, 0 }
+	};
+	struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
+		0, {0, 0, 0, 0}
+	};
+	u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+	static const u16 ctlModesFor11a[] = {
+		CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40
+	};
+	static const u16 ctlModesFor11g[] = {
+		CTL_11B, CTL_11G, CTL_2GHT20,
+		CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40
+	};
+	u16 numCtlModes;
+	const u16 *pCtlMode;
+	u16 ctlMode, freq;
+	struct chan_centers centers;
+	int tx_chainmask;
+	u16 twiceMinEdgePower;
+
+	tx_chainmask = ah->txchainmask;
+
+	ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+	twiceLargestAntenna = max(
+		pEepData->modalHeader
+			[IS_CHAN_2GHZ(chan)].antennaGainCh[0],
+		pEepData->modalHeader
+			[IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
+
+	twiceLargestAntenna = max((u8)twiceLargestAntenna,
+				  pEepData->modalHeader
+				  [IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
+
+	twiceLargestAntenna = (int16_t)min(AntennaReduction -
+					   twiceLargestAntenna, 0);
+
+	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
+	if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) {
+		maxRegAllowedPower -=
+			(tpScaleReductionTable[(regulatory->tp_scale)] * 2);
+	}
+
+	scaledPower = min(powerLimit, maxRegAllowedPower);
+
+	switch (ar5416_get_ntxchains(tx_chainmask)) {
+	case 1:
+		break;
+	case 2:
+		if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
+			scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+		else
+			scaledPower = 0;
+		break;
+	case 3:
+		if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
+			scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+		else
+			scaledPower = 0;
+		break;
+	}
+
+	if (IS_CHAN_2GHZ(chan)) {
+		numCtlModes = ARRAY_SIZE(ctlModesFor11g) -
+			SUB_NUM_CTL_MODES_AT_2G_40;
+		pCtlMode = ctlModesFor11g;
+
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPowerCck,
+			AR5416_NUM_2G_CCK_TARGET_POWERS,
+			&targetPowerCck, 4, 0);
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPower2G,
+			AR5416_NUM_2G_20_TARGET_POWERS,
+			&targetPowerOfdm, 4, 0);
+		ath9k_hw_get_target_powers(ah, chan,
+			pEepData->calTargetPower2GHT20,
+			AR5416_NUM_2G_20_TARGET_POWERS,
+			&targetPowerHt20, 8, 0);
+
+		if (IS_CHAN_HT40(chan)) {
+			numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+			ath9k_hw_get_target_powers(ah, chan,
+				pEepData->calTargetPower2GHT40,
+				AR5416_NUM_2G_40_TARGET_POWERS,
+				&targetPowerHt40, 8, 1);
+			ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPowerCck,
+				AR5416_NUM_2G_CCK_TARGET_POWERS,
+				&targetPowerCckExt, 4, 1);
+			ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPower2G,
+				AR5416_NUM_2G_20_TARGET_POWERS,
+				&targetPowerOfdmExt, 4, 1);
+		}
+	} else {
+		numCtlModes = ARRAY_SIZE(ctlModesFor11a) -
+			SUB_NUM_CTL_MODES_AT_5G_40;
+		pCtlMode = ctlModesFor11a;
+
+		ath9k_hw_get_legacy_target_powers(ah, chan,
+			pEepData->calTargetPower5G,
+			AR5416_NUM_5G_20_TARGET_POWERS,
+			&targetPowerOfdm, 4, 0);
+		ath9k_hw_get_target_powers(ah, chan,
+			pEepData->calTargetPower5GHT20,
+			AR5416_NUM_5G_20_TARGET_POWERS,
+			&targetPowerHt20, 8, 0);
+
+		if (IS_CHAN_HT40(chan)) {
+			numCtlModes = ARRAY_SIZE(ctlModesFor11a);
+			ath9k_hw_get_target_powers(ah, chan,
+				pEepData->calTargetPower5GHT40,
+				AR5416_NUM_5G_40_TARGET_POWERS,
+				&targetPowerHt40, 8, 1);
+			ath9k_hw_get_legacy_target_powers(ah, chan,
+				pEepData->calTargetPower5G,
+				AR5416_NUM_5G_20_TARGET_POWERS,
+				&targetPowerOfdmExt, 4, 1);
+		}
+	}
+
+	for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+		int isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
+			(pCtlMode[ctlMode] == CTL_2GHT40);
+		if (isHt40CtlMode)
+			freq = centers.synth_center;
+		else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+			freq = centers.ext_center;
+		else
+			freq = centers.ctl_center;
+
+		if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
+		    ah->eep_ops->get_eeprom_rev(ah) <= 2)
+			twiceMaxEdgePower = MAX_RATE_POWER;
+
+		for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
+			if ((((cfgCtl & ~CTL_MODE_M) |
+			      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+			     pEepData->ctlIndex[i]) ||
+			    (((cfgCtl & ~CTL_MODE_M) |
+			      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+			     ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) {
+				rep = &(pEepData->ctlData[i]);
+
+				twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
+				rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1],
+				IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES);
+
+				if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+					twiceMaxEdgePower = min(twiceMaxEdgePower,
+								twiceMinEdgePower);
+				} else {
+					twiceMaxEdgePower = twiceMinEdgePower;
+					break;
+				}
+			}
+		}
+
+		minCtlPower = min(twiceMaxEdgePower, scaledPower);
+
+		switch (pCtlMode[ctlMode]) {
+		case CTL_11B:
+			for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
+				targetPowerCck.tPow2x[i] =
+					min((u16)targetPowerCck.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_11A:
+		case CTL_11G:
+			for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
+				targetPowerOfdm.tPow2x[i] =
+					min((u16)targetPowerOfdm.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_5GHT20:
+		case CTL_2GHT20:
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
+				targetPowerHt20.tPow2x[i] =
+					min((u16)targetPowerHt20.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		case CTL_11B_EXT:
+			targetPowerCckExt.tPow2x[0] = min((u16)
+					targetPowerCckExt.tPow2x[0],
+					minCtlPower);
+			break;
+		case CTL_11A_EXT:
+		case CTL_11G_EXT:
+			targetPowerOfdmExt.tPow2x[0] = min((u16)
+					targetPowerOfdmExt.tPow2x[0],
+					minCtlPower);
+			break;
+		case CTL_5GHT40:
+		case CTL_2GHT40:
+			for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+				targetPowerHt40.tPow2x[i] =
+					min((u16)targetPowerHt40.tPow2x[i],
+					    minCtlPower);
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
+		ratesArray[rate18mb] = ratesArray[rate24mb] =
+		targetPowerOfdm.tPow2x[0];
+	ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
+	ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
+	ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
+	ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
+
+	for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
+		ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
+
+	if (IS_CHAN_2GHZ(chan)) {
+		ratesArray[rate1l] = targetPowerCck.tPow2x[0];
+		ratesArray[rate2s] = ratesArray[rate2l] =
+			targetPowerCck.tPow2x[1];
+		ratesArray[rate5_5s] = ratesArray[rate5_5l] =
+			targetPowerCck.tPow2x[2];
+		ratesArray[rate11s] = ratesArray[rate11l] =
+			targetPowerCck.tPow2x[3];
+	}
+	if (IS_CHAN_HT40(chan)) {
+		for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+			ratesArray[rateHt40_0 + i] =
+				targetPowerHt40.tPow2x[i];
+		}
+		ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
+		ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
+		ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+		if (IS_CHAN_2GHZ(chan)) {
+			ratesArray[rateExtCck] =
+				targetPowerCckExt.tPow2x[0];
+		}
+	}
+}
+
+static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
+				    struct ath9k_channel *chan,
+				    u16 cfgCtl,
+				    u8 twiceAntennaReduction,
+				    u8 twiceMaxRegulatoryPower,
+				    u8 powerLimit, int test)
+{
+#define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta)
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+	struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
+	struct modal_eep_header *pModal =
+		&(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
+	int16_t ratesArray[Ar5416RateSize];
+	int16_t txPowerIndexOffset = 0;
+	u8 ht40PowerIncForPdadc = 2;
+	unsigned int i, cck_ofdm_delta = 0;
+
+	memset(ratesArray, 0, sizeof(ratesArray));
+
+	if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+	    AR5416_EEP_MINOR_VER_2) {
+		ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+	}
+
+	ath9k_hw_set_def_power_per_rate_table(ah, chan,
+					       &ratesArray[0], cfgCtl,
+					       twiceAntennaReduction,
+					       twiceMaxRegulatoryPower,
+					       powerLimit);
+
+	ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset);
+
+	regulatory->max_power_level = 0;
+	for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
+		ratesArray[i] =	(int16_t)(txPowerIndexOffset + ratesArray[i]);
+		if (ratesArray[i] > MAX_RATE_POWER)
+			ratesArray[i] = MAX_RATE_POWER;
+		if (ratesArray[i] > regulatory->max_power_level)
+			regulatory->max_power_level = ratesArray[i];
+	}
+
+	if (!test) {
+		i = rate6mb;
+
+		if (IS_CHAN_HT40(chan))
+			i = rateHt40_0;
+		else if (IS_CHAN_HT20(chan))
+			i = rateHt20_0;
+
+		regulatory->max_power_level = ratesArray[i];
+	}
+
+	switch(ar5416_get_ntxchains(ah->txchainmask)) {
+	case 1:
+		break;
+	case 2:
+		regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
+		break;
+	case 3:
+		regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
+		break;
+	default:
+		DBG2("ath9k: "
+			"Invalid chainmask configuration\n");
+		break;
+	}
+
+	if (test)
+		return;
+
+	if (AR_SREV_9280_20_OR_LATER(ah)) {
+		for (i = 0; i < Ar5416RateSize; i++) {
+			int8_t pwr_table_offset;
+
+			pwr_table_offset = ah->eep_ops->get_eeprom(ah,
+							EEP_PWR_TABLE_OFFSET);
+			ratesArray[i] -= pwr_table_offset * 2;
+		}
+	}
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+		  ATH9K_POW_SM(ratesArray[rate18mb], 24)
+		  | ATH9K_POW_SM(ratesArray[rate12mb], 16)
+		  | ATH9K_POW_SM(ratesArray[rate9mb], 8)
+		  | ATH9K_POW_SM(ratesArray[rate6mb], 0));
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+		  ATH9K_POW_SM(ratesArray[rate54mb], 24)
+		  | ATH9K_POW_SM(ratesArray[rate48mb], 16)
+		  | ATH9K_POW_SM(ratesArray[rate36mb], 8)
+		  | ATH9K_POW_SM(ratesArray[rate24mb], 0));
+
+	if (IS_CHAN_2GHZ(chan)) {
+		if (OLC_FOR_AR9280_20_LATER) {
+			cck_ofdm_delta = 2;
+			REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+				ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24)
+				| ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16)
+				| ATH9K_POW_SM(ratesArray[rateXr], 8)
+				| ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0));
+			REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+				ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24)
+				| ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16)
+				| ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8)
+				| ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0));
+		} else {
+			REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+				ATH9K_POW_SM(ratesArray[rate2s], 24)
+				| ATH9K_POW_SM(ratesArray[rate2l], 16)
+				| ATH9K_POW_SM(ratesArray[rateXr], 8)
+				| ATH9K_POW_SM(ratesArray[rate1l], 0));
+			REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+				ATH9K_POW_SM(ratesArray[rate11s], 24)
+				| ATH9K_POW_SM(ratesArray[rate11l], 16)
+				| ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+				| ATH9K_POW_SM(ratesArray[rate5_5l], 0));
+		}
+	}
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
+		  ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
+	REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
+		  ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
+		  | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
+
+	if (IS_CHAN_HT40(chan)) {
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+			  ATH9K_POW_SM(ratesArray[rateHt40_3] +
+				       ht40PowerIncForPdadc, 24)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_2] +
+					 ht40PowerIncForPdadc, 16)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_1] +
+					 ht40PowerIncForPdadc, 8)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_0] +
+					 ht40PowerIncForPdadc, 0));
+		REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+			  ATH9K_POW_SM(ratesArray[rateHt40_7] +
+				       ht40PowerIncForPdadc, 24)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_6] +
+					 ht40PowerIncForPdadc, 16)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_5] +
+					 ht40PowerIncForPdadc, 8)
+			  | ATH9K_POW_SM(ratesArray[rateHt40_4] +
+					 ht40PowerIncForPdadc, 0));
+		if (OLC_FOR_AR9280_20_LATER) {
+			REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+				ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+				| ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16)
+				| ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+				| ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0));
+		} else {
+			REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+				ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+				| ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+				| ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+				| ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+		}
+	}
+
+	REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
+		  ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
+		  | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
+
+	REGWRITE_BUFFER_FLUSH(ah);
+}
+
+static u16 ath9k_hw_def_get_spur_channel(struct ath_hw *ah, u16 i, int is2GHz)
+{
+#define EEP_DEF_SPURCHAN \
+	(ah->eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan)
+
+	u16 spur_val = AR_NO_SPUR;
+
+	DBG2("ath9k: "
+		"Getting spur idx:%d is2Ghz:%d val:%x\n",
+		i, is2GHz, ah->config.spurchans[i][is2GHz]);
+
+	switch (ah->config.spurmode) {
+	case SPUR_DISABLE:
+		break;
+	case SPUR_ENABLE_IOCTL:
+		spur_val = ah->config.spurchans[i][is2GHz];
+		DBG2("ath9k: "
+			"Getting spur val from new loc. %d\n", spur_val);
+		break;
+	case SPUR_ENABLE_EEPROM:
+		spur_val = EEP_DEF_SPURCHAN;
+		break;
+	}
+
+	return spur_val;
+
+#undef EEP_DEF_SPURCHAN
+}
+
+const struct eeprom_ops eep_def_ops = {
+	.check_eeprom		= ath9k_hw_def_check_eeprom,
+	.get_eeprom		= ath9k_hw_def_get_eeprom,
+	.fill_eeprom		= ath9k_hw_def_fill_eeprom,
+	.get_eeprom_ver		= ath9k_hw_def_get_eeprom_ver,
+	.get_eeprom_rev		= ath9k_hw_def_get_eeprom_rev,
+	.set_board_values	= ath9k_hw_def_set_board_values,
+	.set_addac		= ath9k_hw_def_set_addac,
+	.set_txpower		= ath9k_hw_def_set_txpower,
+	.get_spur_channel	= ath9k_hw_def_get_spur_channel
+};
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_hw.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_hw.c
new file mode 100644
index 0000000000000000000000000000000000000000..554e9be3ca2cb52c990da0158fae6e1aad737caa
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_hw.c
@@ -0,0 +1,2067 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/vsprintf.h>
+#include <ipxe/io.h>
+
+#include "hw.h"
+#include "hw-ops.h"
+#include "ar9003_mac.h"
+
+static int ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type);
+
+/* Private hardware callbacks */
+
+static void ath9k_hw_init_cal_settings(struct ath_hw *ah)
+{
+	ath9k_hw_private_ops(ah)->init_cal_settings(ah);
+}
+
+static void ath9k_hw_init_mode_regs(struct ath_hw *ah)
+{
+	ath9k_hw_private_ops(ah)->init_mode_regs(ah);
+}
+
+static u32 ath9k_hw_compute_pll_control(struct ath_hw *ah,
+					struct ath9k_channel *chan)
+{
+	return ath9k_hw_private_ops(ah)->compute_pll_control(ah, chan);
+}
+
+static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
+{
+	if (!ath9k_hw_private_ops(ah)->init_mode_gain_regs)
+		return;
+
+	ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah);
+}
+
+static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah)
+{
+	/* You will not have this callback if using the old ANI */
+	if (!ath9k_hw_private_ops(ah)->ani_cache_ini_regs)
+		return;
+
+	ath9k_hw_private_ops(ah)->ani_cache_ini_regs(ah);
+}
+
+/********************/
+/* Helper Functions */
+/********************/
+
+static void ath9k_hw_set_clockrate(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct net80211_device *dev = common->dev;
+	unsigned int clockrate;
+
+	if (!ah->curchan) /* should really check for CCK instead */
+		clockrate = ATH9K_CLOCK_RATE_CCK;
+	else if ((dev->channels + dev->channel)->band == NET80211_BAND_2GHZ)
+		clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM;
+	else if (ah->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK)
+		clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM;
+	else
+		clockrate = ATH9K_CLOCK_RATE_5GHZ_OFDM;
+
+	common->clockrate = clockrate;
+}
+
+static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	return usecs * common->clockrate;
+}
+
+int ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
+{
+	unsigned int i;
+
+	for (i = 0; i < (timeout / AH_TIME_QUANTUM); i++) {
+		if ((REG_READ(ah, reg) & mask) == val)
+			return 1;
+
+		udelay(AH_TIME_QUANTUM);
+	}
+
+	DBG("ath9k: "
+		"timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
+		timeout, reg, REG_READ(ah, reg), mask, val);
+
+	return 0;
+}
+
+void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
+			  int column, unsigned int *writecnt)
+{
+	unsigned int r;
+
+	ENABLE_REGWRITE_BUFFER(ah);
+	for (r = 0; r < array->ia_rows; r++) {
+		REG_WRITE(ah, INI_RA(array, r, 0),
+			  INI_RA(array, r, column));
+		DO_DELAY(*writecnt);
+	}
+	REGWRITE_BUFFER_FLUSH(ah);
+}
+
+u32 ath9k_hw_reverse_bits(u32 val, u32 n)
+{
+	u32 retval;
+	unsigned int i;
+
+	for (i = 0, retval = 0; i < n; i++) {
+		retval = (retval << 1) | (val & 1);
+		val >>= 1;
+	}
+	return retval;
+}
+
+u16 ath9k_hw_computetxtime(struct ath_hw *ah,
+			   u8 phy, int kbps,
+			   u32 frameLen, u16 rateix,
+			   int shortPreamble)
+{
+	u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
+
+	if (kbps == 0)
+		return 0;
+
+	switch (phy) {
+	case CHANNEL_CCK:
+		phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
+		if (shortPreamble)
+			phyTime >>= 1;
+		numBits = frameLen << 3;
+		txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps);
+		break;
+	case CHANNEL_OFDM:
+		if (ah->curchan && IS_CHAN_QUARTER_RATE(ah->curchan)) {
+			bitsPerSymbol =	(kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
+			numBits = OFDM_PLCP_BITS + (frameLen << 3);
+			numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
+			txTime = OFDM_SIFS_TIME_QUARTER
+				+ OFDM_PREAMBLE_TIME_QUARTER
+				+ (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
+		} else if (ah->curchan &&
+			   IS_CHAN_HALF_RATE(ah->curchan)) {
+			bitsPerSymbol =	(kbps * OFDM_SYMBOL_TIME_HALF) / 1000;
+			numBits = OFDM_PLCP_BITS + (frameLen << 3);
+			numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
+			txTime = OFDM_SIFS_TIME_HALF +
+				OFDM_PREAMBLE_TIME_HALF
+				+ (numSymbols * OFDM_SYMBOL_TIME_HALF);
+		} else {
+			bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000;
+			numBits = OFDM_PLCP_BITS + (frameLen << 3);
+			numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
+			txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME
+				+ (numSymbols * OFDM_SYMBOL_TIME);
+		}
+		break;
+	default:
+		DBG("ath9k: "
+			"Unknown phy %d (rate ix %d)\n", phy, rateix);
+		txTime = 0;
+		break;
+	}
+
+	return txTime;
+}
+
+void ath9k_hw_get_channel_centers(struct ath_hw *ah __unused,
+				  struct ath9k_channel *chan,
+				  struct chan_centers *centers)
+{
+	int8_t extoff;
+
+	if (!IS_CHAN_HT40(chan)) {
+		centers->ctl_center = centers->ext_center =
+			centers->synth_center = chan->channel;
+		return;
+	}
+
+	if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
+	    (chan->chanmode == CHANNEL_G_HT40PLUS)) {
+		centers->synth_center =
+			chan->channel + HT40_CHANNEL_CENTER_SHIFT;
+		extoff = 1;
+	} else {
+		centers->synth_center =
+			chan->channel - HT40_CHANNEL_CENTER_SHIFT;
+		extoff = -1;
+	}
+
+	centers->ctl_center =
+		centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT);
+	/* 25 MHz spacing is supported by hw but not on upper layers */
+	centers->ext_center =
+		centers->synth_center + (extoff * HT40_CHANNEL_CENTER_SHIFT);
+}
+
+/******************/
+/* Chip Revisions */
+/******************/
+
+static void ath9k_hw_read_revisions(struct ath_hw *ah)
+{
+	u32 val;
+
+	switch (ah->hw_version.devid) {
+	case AR5416_AR9100_DEVID:
+		ah->hw_version.macVersion = AR_SREV_VERSION_9100;
+		break;
+	case AR9300_DEVID_AR9340:
+		ah->hw_version.macVersion = AR_SREV_VERSION_9340;
+		val = REG_READ(ah, AR_SREV);
+		ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
+		return;
+	}
+
+	val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
+
+	if (val == 0xFF) {
+		val = REG_READ(ah, AR_SREV);
+		ah->hw_version.macVersion =
+			(val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
+		ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
+		ah->is_pciexpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
+	} else {
+		if (!AR_SREV_9100(ah))
+			ah->hw_version.macVersion = MS(val, AR_SREV_VERSION);
+
+		ah->hw_version.macRev = val & AR_SREV_REVISION;
+
+		if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE)
+			ah->is_pciexpress = 1;
+	}
+}
+
+/************************************/
+/* HW Attach, Detach, Init Routines */
+/************************************/
+
+static void ath9k_hw_disablepcie(struct ath_hw *ah)
+{
+	if (!AR_SREV_5416(ah))
+		return;
+
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+	REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007);
+
+	REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+}
+
+/* This should work for all families including legacy */
+static int ath9k_hw_chip_test(struct ath_hw *ah)
+{
+	u32 regAddr[2] = { AR_STA_ID0 };
+	u32 regHold[2];
+	static const u32 patternData[4] = {
+		0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999
+	};
+	int i, j, loop_max;
+
+	if (!AR_SREV_9300_20_OR_LATER(ah)) {
+		loop_max = 2;
+		regAddr[1] = AR_PHY_BASE + (8 << 2);
+	} else
+		loop_max = 1;
+
+	for (i = 0; i < loop_max; i++) {
+		u32 addr = regAddr[i];
+		u32 wrData, rdData;
+
+		regHold[i] = REG_READ(ah, addr);
+		for (j = 0; j < 0x100; j++) {
+			wrData = (j << 16) | j;
+			REG_WRITE(ah, addr, wrData);
+			rdData = REG_READ(ah, addr);
+			if (rdData != wrData) {
+				DBG("ath9k: "
+					"address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
+					addr, wrData, rdData);
+				return 0;
+			}
+		}
+		for (j = 0; j < 4; j++) {
+			wrData = patternData[j];
+			REG_WRITE(ah, addr, wrData);
+			rdData = REG_READ(ah, addr);
+			if (wrData != rdData) {
+				DBG("ath9k: "
+					"address test failed addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
+					addr, wrData, rdData);
+				return 0;
+			}
+		}
+		REG_WRITE(ah, regAddr[i], regHold[i]);
+	}
+	udelay(100);
+
+	return 1;
+}
+
+static void ath9k_hw_init_config(struct ath_hw *ah)
+{
+	int i;
+
+	ah->config.dma_beacon_response_time = 2;
+	ah->config.sw_beacon_response_time = 10;
+	ah->config.additional_swba_backoff = 0;
+	ah->config.ack_6mb = 0x0;
+	ah->config.cwm_ignore_extcca = 0;
+	ah->config.pcie_powersave_enable = 0;
+	ah->config.pcie_clock_req = 0;
+	ah->config.pcie_waen = 0;
+	ah->config.analog_shiftreg = 1;
+	ah->config.enable_ani = 1;
+
+	for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+		ah->config.spurchans[i][0] = AR_NO_SPUR;
+		ah->config.spurchans[i][1] = AR_NO_SPUR;
+	}
+
+	/* PAPRD needs some more work to be enabled */
+	ah->config.paprd_disable = 1;
+
+	ah->config.rx_intr_mitigation = 1;
+	ah->config.pcieSerDesWrite = 1;
+}
+
+static void ath9k_hw_init_defaults(struct ath_hw *ah)
+{
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+
+	regulatory->country_code = CTRY_DEFAULT;
+	regulatory->power_limit = MAX_RATE_POWER;
+	regulatory->tp_scale = ATH9K_TP_SCALE_MAX;
+
+	ah->hw_version.magic = AR5416_MAGIC;
+	ah->hw_version.subvendorid = 0;
+
+	ah->atim_window = 0;
+	ah->sta_id1_defaults =
+		AR_STA_ID1_CRPT_MIC_ENABLE |
+		AR_STA_ID1_MCAST_KSRCH;
+	if (AR_SREV_9100(ah))
+		ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX;
+	ah->enable_32kHz_clock = DONT_USE_32KHZ;
+	ah->slottime = 20;
+	ah->globaltxtimeout = (u32) -1;
+	ah->power_mode = ATH9K_PM_UNDEFINED;
+}
+
+static int ath9k_hw_init_macaddr(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	u32 sum;
+	int i;
+	u16 eeval;
+	static const u32 EEP_MAC[] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW };
+
+	sum = 0;
+	for (i = 0; i < 3; i++) {
+		eeval = ah->eep_ops->get_eeprom(ah, EEP_MAC[i]);
+		sum += eeval;
+		common->macaddr[2 * i] = eeval >> 8;
+		common->macaddr[2 * i + 1] = eeval & 0xff;
+	}
+	if (sum == 0 || sum == 0xffff * 3)
+		return -EADDRNOTAVAIL;
+
+	return 0;
+}
+
+static int ath9k_hw_post_init(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	int ecode;
+
+	if (common->bus_ops->ath_bus_type != ATH_USB) {
+		if (!ath9k_hw_chip_test(ah))
+			return -ENODEV;
+	}
+
+	if (!AR_SREV_9300_20_OR_LATER(ah)) {
+		ecode = ar9002_hw_rf_claim(ah);
+		if (ecode != 0)
+			return ecode;
+	}
+
+	ecode = ath9k_hw_eeprom_init(ah);
+	if (ecode != 0)
+		return ecode;
+
+	DBG("ath9k: "
+		"Eeprom VER: %d, REV: %d\n",
+		ah->eep_ops->get_eeprom_ver(ah),
+		ah->eep_ops->get_eeprom_rev(ah));
+
+	ecode = ath9k_hw_rf_alloc_ext_banks(ah);
+	if (ecode) {
+		DBG("ath9k: "
+			"Failed allocating banks for external radio\n");
+		ath9k_hw_rf_free_ext_banks(ah);
+		return ecode;
+	}
+
+	if (!AR_SREV_9100(ah) && !AR_SREV_9340(ah)) {
+		ath9k_hw_ani_setup(ah);
+		ath9k_hw_ani_init(ah);
+	}
+
+	return 0;
+}
+
+static void ath9k_hw_attach_ops(struct ath_hw *ah)
+{
+	if (AR_SREV_9300_20_OR_LATER(ah))
+		ar9003_hw_attach_ops(ah);
+	else
+		ar9002_hw_attach_ops(ah);
+}
+
+/* Called for all hardware families */
+static int __ath9k_hw_init(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	int r = 0;
+
+	ath9k_hw_read_revisions(ah);
+
+	/*
+	 * Read back AR_WA into a permanent copy and set bits 14 and 17.
+	 * We need to do this to avoid RMW of this register. We cannot
+	 * read the reg when chip is asleep.
+	 */
+	ah->WARegVal = REG_READ(ah, AR_WA);
+	ah->WARegVal |= (AR_WA_D3_L1_DISABLE |
+			 AR_WA_ASPM_TIMER_BASED_DISABLE);
+
+	if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
+		DBG("ath9k: Couldn't reset chip\n");
+		return -EIO;
+	}
+
+	ath9k_hw_init_defaults(ah);
+	ath9k_hw_init_config(ah);
+
+	ath9k_hw_attach_ops(ah);
+
+	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
+		DBG("ath9k: Couldn't wakeup chip\n");
+		return -EIO;
+	}
+
+	if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
+		if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
+		    ((AR_SREV_9160(ah) || AR_SREV_9280(ah)) &&
+		     !ah->is_pciexpress)) {
+			ah->config.serialize_regmode =
+				SER_REG_MODE_ON;
+		} else {
+			ah->config.serialize_regmode =
+				SER_REG_MODE_OFF;
+		}
+	}
+
+	DBG2("ath9k: serialize_regmode is %d\n",
+		ah->config.serialize_regmode);
+
+	if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+		ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1;
+	else
+		ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD;
+
+	switch (ah->hw_version.macVersion) {
+	case AR_SREV_VERSION_5416_PCI:
+	case AR_SREV_VERSION_5416_PCIE:
+	case AR_SREV_VERSION_9160:
+	case AR_SREV_VERSION_9100:
+	case AR_SREV_VERSION_9280:
+	case AR_SREV_VERSION_9285:
+	case AR_SREV_VERSION_9287:
+	case AR_SREV_VERSION_9271:
+	case AR_SREV_VERSION_9300:
+	case AR_SREV_VERSION_9485:
+	case AR_SREV_VERSION_9340:
+		break;
+	default:
+		DBG("ath9k: "
+			"Mac Chip Rev 0x%02x.%x is not supported by this driver\n",
+			ah->hw_version.macVersion, ah->hw_version.macRev);
+		return -EOPNOTSUPP;
+	}
+
+	if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah))
+		ah->is_pciexpress = 0;
+
+	ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
+	ath9k_hw_init_cal_settings(ah);
+
+	ah->ani_function = ATH9K_ANI_ALL;
+	if (AR_SREV_9280_20_OR_LATER(ah) && !AR_SREV_9300_20_OR_LATER(ah))
+		ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
+	if (!AR_SREV_9300_20_OR_LATER(ah))
+		ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
+
+	ath9k_hw_init_mode_regs(ah);
+
+
+	if (ah->is_pciexpress)
+		ath9k_hw_configpcipowersave(ah, 0, 0);
+	else
+		ath9k_hw_disablepcie(ah);
+
+	if (!AR_SREV_9300_20_OR_LATER(ah))
+		ar9002_hw_cck_chan14_spread(ah);
+
+	r = ath9k_hw_post_init(ah);
+	if (r)
+		return r;
+
+	ath9k_hw_init_mode_gain_regs(ah);
+	r = ath9k_hw_fill_cap_info(ah);
+	if (r)
+		return r;
+
+	r = ath9k_hw_init_macaddr(ah);
+	if (r) {
+		DBG("ath9k: Failed to initialize MAC address\n");
+		return r;
+	}
+
+	if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+		ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S);
+	else
+		ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
+
+	common->state = ATH_HW_INITIALIZED;
+
+	return 0;
+}
+
+int ath9k_hw_init(struct ath_hw *ah)
+{
+	int ret;
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	/* These are all the AR5008/AR9001/AR9002 hardware family of chipsets */
+	switch (ah->hw_version.devid) {
+	case AR5416_DEVID_PCI:
+	case AR5416_DEVID_PCIE:
+	case AR5416_AR9100_DEVID:
+	case AR9160_DEVID_PCI:
+	case AR9280_DEVID_PCI:
+	case AR9280_DEVID_PCIE:
+	case AR9285_DEVID_PCIE:
+	case AR9287_DEVID_PCI:
+	case AR9287_DEVID_PCIE:
+	case AR2427_DEVID_PCIE:
+	case AR9300_DEVID_PCIE:
+	case AR9300_DEVID_AR9485_PCIE:
+	case AR9300_DEVID_AR9340:
+		break;
+	default:
+		if (common->bus_ops->ath_bus_type == ATH_USB)
+			break;
+		DBG("ath9k: Hardware device ID 0x%04x not supported\n",
+			ah->hw_version.devid);
+		return -EOPNOTSUPP;
+	}
+
+	ret = __ath9k_hw_init(ah);
+	if (ret) {
+		DBG("ath9k: "
+			"Unable to initialize hardware; initialization status: %d\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah)
+{
+	REG_CLR_BIT(ah, PLL3, PLL3_DO_MEAS_MASK);
+	udelay(100);
+	REG_SET_BIT(ah, PLL3, PLL3_DO_MEAS_MASK);
+
+	while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0)
+		udelay(100);
+
+	return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3;
+}
+
+static void ath9k_hw_init_pll(struct ath_hw *ah,
+			      struct ath9k_channel *chan)
+{
+	u32 pll;
+
+	if (AR_SREV_9485(ah)) {
+
+		/* program BB PLL ki and kd value, ki=0x4, kd=0x40 */
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+			      AR_CH0_BB_DPLL2_PLL_PWD, 0x1);
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+			      AR_CH0_DPLL2_KD, 0x40);
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+			      AR_CH0_DPLL2_KI, 0x4);
+
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
+			      AR_CH0_BB_DPLL1_REFDIV, 0x5);
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
+			      AR_CH0_BB_DPLL1_NINI, 0x58);
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
+			      AR_CH0_BB_DPLL1_NFRAC, 0x0);
+
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+			      AR_CH0_BB_DPLL2_OUTDIV, 0x1);
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+			      AR_CH0_BB_DPLL2_LOCAL_PLL, 0x1);
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+			      AR_CH0_BB_DPLL2_EN_NEGTRIG, 0x1);
+
+		/* program BB PLL phase_shift to 0x6 */
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,
+			      AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x6);
+
+		REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+			      AR_CH0_BB_DPLL2_PLL_PWD, 0x0);
+		udelay(1000);
+	} else if (AR_SREV_9340(ah)) {
+		u32 regval, pll2_divint, pll2_divfrac, refdiv;
+
+		REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
+		udelay(1000);
+
+		REG_SET_BIT(ah, AR_PHY_PLL_MODE, 0x1 << 16);
+		udelay(100);
+
+		if (ah->is_clk_25mhz) {
+			pll2_divint = 0x54;
+			pll2_divfrac = 0x1eb85;
+			refdiv = 3;
+		} else {
+			pll2_divint = 88;
+			pll2_divfrac = 0;
+			refdiv = 5;
+		}
+
+		regval = REG_READ(ah, AR_PHY_PLL_MODE);
+		regval |= (0x1 << 16);
+		REG_WRITE(ah, AR_PHY_PLL_MODE, regval);
+		udelay(100);
+
+		REG_WRITE(ah, AR_PHY_PLL_CONTROL, (refdiv << 27) |
+			  (pll2_divint << 18) | pll2_divfrac);
+		udelay(100);
+
+		regval = REG_READ(ah, AR_PHY_PLL_MODE);
+		regval = (regval & 0x80071fff) | (0x1 << 30) | (0x1 << 13) |
+			 (0x4 << 26) | (0x18 << 19);
+		REG_WRITE(ah, AR_PHY_PLL_MODE, regval);
+		REG_WRITE(ah, AR_PHY_PLL_MODE,
+			  REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff);
+		udelay(1000);
+	}
+
+	pll = ath9k_hw_compute_pll_control(ah, chan);
+
+	REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
+
+	if (AR_SREV_9485(ah) || AR_SREV_9340(ah))
+		udelay(1000);
+
+	/* Switch the core clock for ar9271 to 117Mhz */
+	if (AR_SREV_9271(ah)) {
+		udelay(500);
+		REG_WRITE(ah, 0x50040, 0x304);
+	}
+
+	udelay(RTC_PLL_SETTLE_DELAY);
+
+	REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
+
+	if (AR_SREV_9340(ah)) {
+		if (ah->is_clk_25mhz) {
+			REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1);
+			REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7);
+			REG_WRITE(ah,  AR_SLP32_INC, 0x0001e7ae);
+		} else {
+			REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1);
+			REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400);
+			REG_WRITE(ah,  AR_SLP32_INC, 0x0001e800);
+		}
+		udelay(100);
+	}
+}
+
+static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah)
+{
+	u32 sync_default = AR_INTR_SYNC_DEFAULT;
+	u32 imr_reg = AR_IMR_TXERR |
+		AR_IMR_TXURN |
+		AR_IMR_RXERR |
+		AR_IMR_RXORN;;
+
+	if (AR_SREV_9340(ah))
+		sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
+
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		imr_reg |= AR_IMR_RXOK_HP;
+		if (ah->config.rx_intr_mitigation)
+			imr_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
+		else
+			imr_reg |= AR_IMR_RXOK_LP;
+
+	} else {
+		if (ah->config.rx_intr_mitigation)
+			imr_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
+		else
+			imr_reg |= AR_IMR_RXOK;
+	}
+
+	if (ah->config.tx_intr_mitigation)
+		imr_reg |= AR_IMR_TXINTM | AR_IMR_TXMINTR;
+	else
+		imr_reg |= AR_IMR_TXOK;
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	REG_WRITE(ah, AR_IMR, imr_reg);
+//	ah->imrs2_reg |= AR_IMR_S2_GTT;
+	REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
+
+	if (!AR_SREV_9100(ah)) {
+		REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF);
+		REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default);
+		REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
+	}
+
+	REGWRITE_BUFFER_FLUSH(ah);
+
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE, 0);
+		REG_WRITE(ah, AR_INTR_PRIO_ASYNC_MASK, 0);
+		REG_WRITE(ah, AR_INTR_PRIO_SYNC_ENABLE, 0);
+		REG_WRITE(ah, AR_INTR_PRIO_SYNC_MASK, 0);
+	}
+}
+
+static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
+{
+	u32 val = ath9k_hw_mac_to_clks(ah, us);
+	val = min(val, (u32) 0xFFFF);
+	REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val);
+}
+
+static void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us)
+{
+	u32 val = ath9k_hw_mac_to_clks(ah, us);
+	val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK));
+	REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val);
+}
+
+static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us)
+{
+	u32 val = ath9k_hw_mac_to_clks(ah, us);
+	val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS));
+	REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_CTS, val);
+}
+
+static int ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
+{
+	if (tu > 0xFFFF) {
+		DBG("ath9k: "
+			"bad global tx timeout %d\n", tu);
+		ah->globaltxtimeout = (u32) -1;
+		return 0;
+	} else {
+		REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu);
+		ah->globaltxtimeout = tu;
+		return 1;
+	}
+}
+
+void ath9k_hw_init_global_settings(struct ath_hw *ah)
+{
+	int acktimeout;
+	int slottime;
+	int sifstime;
+
+	DBG2("ath9k: ah->misc_mode 0x%x\n",
+		ah->misc_mode);
+
+	if (ah->misc_mode != 0)
+		REG_SET_BIT(ah, AR_PCU_MISC, ah->misc_mode);
+
+	if ((ah->dev->channels + ah->dev->channel)->band == NET80211_BAND_5GHZ)
+		sifstime = 16;
+	else
+		sifstime = 10;
+
+	/* As defined by IEEE 802.11-2007 17.3.8.6 */
+	slottime = ah->slottime + 3 * ah->coverage_class;
+	acktimeout = slottime + sifstime;
+
+	/*
+	 * Workaround for early ACK timeouts, add an offset to match the
+	 * initval's 64us ack timeout value.
+	 * This was initially only meant to work around an issue with delayed
+	 * BA frames in some implementations, but it has been found to fix ACK
+	 * timeout issues in other cases as well.
+	 */
+	if ((ah->dev->channels + ah->dev->channel)->band == NET80211_BAND_2GHZ)
+		acktimeout += 64 - sifstime - ah->slottime;
+
+	ath9k_hw_setslottime(ah, ah->slottime);
+	ath9k_hw_set_ack_timeout(ah, acktimeout);
+	ath9k_hw_set_cts_timeout(ah, acktimeout);
+	if (ah->globaltxtimeout != (u32) -1)
+		ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout);
+}
+
+void ath9k_hw_deinit(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	if (common->state < ATH_HW_INITIALIZED)
+		goto free_hw;
+
+	ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
+
+free_hw:
+	ath9k_hw_rf_free_ext_banks(ah);
+}
+
+/*******/
+/* INI */
+/*******/
+
+u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan)
+{
+	u32 ctl = ath_regd_get_band_ctl(reg, chan->chan->band);
+
+	if (IS_CHAN_B(chan))
+		ctl |= CTL_11B;
+	else if (IS_CHAN_G(chan))
+		ctl |= CTL_11G;
+	else
+		ctl |= CTL_11A;
+
+	return ctl;
+}
+
+/****************************************/
+/* Reset and Channel Switching Routines */
+/****************************************/
+
+static inline void ath9k_hw_set_dma(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	/*
+	 * set AHB_MODE not to do cacheline prefetches
+	*/
+	if (!AR_SREV_9300_20_OR_LATER(ah))
+		REG_SET_BIT(ah, AR_AHB_MODE, AR_AHB_PREFETCH_RD_EN);
+
+	/*
+	 * let mac dma reads be in 128 byte chunks
+	 */
+	REG_RMW(ah, AR_TXCFG, AR_TXCFG_DMASZ_128B, AR_TXCFG_DMASZ_MASK);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+
+	/*
+	 * Restore TX Trigger Level to its pre-reset value.
+	 * The initial value depends on whether aggregation is enabled, and is
+	 * adjusted whenever underruns are detected.
+	 */
+	if (!AR_SREV_9300_20_OR_LATER(ah))
+		REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level);
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	/*
+	 * let mac dma writes be in 128 byte chunks
+	 */
+	REG_RMW(ah, AR_RXCFG, AR_RXCFG_DMASZ_128B, AR_RXCFG_DMASZ_MASK);
+
+	/*
+	 * Setup receive FIFO threshold to hold off TX activities
+	 */
+	REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);
+
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_HP, 0x1);
+		REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_LP, 0x1);
+
+		ath9k_hw_set_rx_bufsize(ah, common->rx_bufsize -
+			ah->caps.rx_status_len);
+	}
+
+	/*
+	 * reduce the number of usable entries in PCU TXBUF to avoid
+	 * wrap around issues.
+	 */
+	if (AR_SREV_9285(ah)) {
+		/* For AR9285 the number of Fifos are reduced to half.
+		 * So set the usable tx buf size also to half to
+		 * avoid data/delimiter underruns
+		 */
+		REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
+			  AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE);
+	} else if (!AR_SREV_9271(ah)) {
+		REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
+			  AR_PCU_TXBUF_CTRL_USABLE_SIZE);
+	}
+
+	REGWRITE_BUFFER_FLUSH(ah);
+
+	if (AR_SREV_9300_20_OR_LATER(ah))
+		ath9k_hw_reset_txstatus_ring(ah);
+}
+
+static void ath9k_hw_set_operating_mode(struct ath_hw *ah)
+{
+	u32 mask = AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC;
+	u32 set = AR_STA_ID1_KSRCH_MODE;
+
+	REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
+
+	REG_RMW(ah, AR_STA_ID1, set, mask);
+}
+
+void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah __unused, u32 coef_scaled,
+				   u32 *coef_mantissa, u32 *coef_exponent)
+{
+	u32 coef_exp, coef_man;
+
+	for (coef_exp = 31; coef_exp > 0; coef_exp--)
+		if ((coef_scaled >> coef_exp) & 0x1)
+			break;
+
+	coef_exp = 14 - (coef_exp - COEF_SCALE_S);
+
+	coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1));
+
+	*coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp);
+	*coef_exponent = coef_exp - 16;
+}
+
+static int ath9k_hw_set_reset(struct ath_hw *ah, int type)
+{
+	u32 rst_flags;
+	u32 tmpReg;
+
+	if (AR_SREV_9100(ah)) {
+		REG_RMW_FIELD(ah, AR_RTC_DERIVED_CLK,
+			      AR_RTC_DERIVED_CLK_PERIOD, 1);
+		(void)REG_READ(ah, AR_RTC_DERIVED_CLK);
+	}
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		REG_WRITE(ah, AR_WA, ah->WARegVal);
+		udelay(10);
+	}
+
+	REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
+		  AR_RTC_FORCE_WAKE_ON_INT);
+
+	if (AR_SREV_9100(ah)) {
+		rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD |
+			AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET;
+	} else {
+		tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE);
+		if (tmpReg &
+		    (AR_INTR_SYNC_LOCAL_TIMEOUT |
+		     AR_INTR_SYNC_RADM_CPL_TIMEOUT)) {
+			u32 val;
+			REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
+
+			val = AR_RC_HOSTIF;
+			if (!AR_SREV_9300_20_OR_LATER(ah))
+				val |= AR_RC_AHB;
+			REG_WRITE(ah, AR_RC, val);
+
+		} else if (!AR_SREV_9300_20_OR_LATER(ah))
+			REG_WRITE(ah, AR_RC, AR_RC_AHB);
+
+		rst_flags = AR_RTC_RC_MAC_WARM;
+		if (type == ATH9K_RESET_COLD)
+			rst_flags |= AR_RTC_RC_MAC_COLD;
+	}
+
+	REG_WRITE(ah, AR_RTC_RC, rst_flags);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+
+	udelay(50);
+
+	REG_WRITE(ah, AR_RTC_RC, 0);
+	if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) {
+		DBG("ath9k: "
+			"RTC stuck in MAC reset\n");
+		return 0;
+	}
+
+	if (!AR_SREV_9100(ah))
+		REG_WRITE(ah, AR_RC, 0);
+
+	if (AR_SREV_9100(ah))
+		udelay(50);
+
+	return 1;
+}
+
+static int ath9k_hw_set_reset_power_on(struct ath_hw *ah)
+{
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		REG_WRITE(ah, AR_WA, ah->WARegVal);
+		udelay(10);
+	}
+
+	REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
+		  AR_RTC_FORCE_WAKE_ON_INT);
+
+	if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
+		REG_WRITE(ah, AR_RC, AR_RC_AHB);
+
+	REG_WRITE(ah, AR_RTC_RESET, 0);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+
+	if (!AR_SREV_9300_20_OR_LATER(ah))
+		udelay(2);
+
+	if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
+		REG_WRITE(ah, AR_RC, 0);
+
+	REG_WRITE(ah, AR_RTC_RESET, 1);
+
+	if (!ath9k_hw_wait(ah,
+			   AR_RTC_STATUS,
+			   AR_RTC_STATUS_M,
+			   AR_RTC_STATUS_ON,
+			   AH_WAIT_TIMEOUT)) {
+		DBG("ath9k: "
+			"RTC not waking up\n");
+		return 0;
+	}
+
+	return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM);
+}
+
+static int ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
+{
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		REG_WRITE(ah, AR_WA, ah->WARegVal);
+		udelay(10);
+	}
+
+	REG_WRITE(ah, AR_RTC_FORCE_WAKE,
+		  AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
+
+	switch (type) {
+	case ATH9K_RESET_POWER_ON:
+		return ath9k_hw_set_reset_power_on(ah);
+	case ATH9K_RESET_WARM:
+	case ATH9K_RESET_COLD:
+		return ath9k_hw_set_reset(ah, type);
+	default:
+		return 0;
+	}
+}
+
+static int ath9k_hw_chip_reset(struct ath_hw *ah,
+				struct ath9k_channel *chan)
+{
+	if (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) {
+		if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON))
+			return 0;
+	} else if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
+		return 0;
+
+	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
+		return 0;
+
+	ah->chip_fullsleep = 0;
+	ath9k_hw_init_pll(ah, chan);
+	ath9k_hw_set_rfmode(ah, chan);
+
+	return 1;
+}
+
+static int ath9k_hw_channel_change(struct ath_hw *ah,
+				    struct ath9k_channel *chan)
+{
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+	struct net80211_channel *channel = chan->chan;
+	u32 qnum;
+	int r;
+
+	for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
+		if (ath9k_hw_numtxpending(ah, qnum)) {
+			DBG("ath9k: "
+				"Transmit frames pending on queue %d\n", qnum);
+			return 0;
+		}
+	}
+
+	if (!ath9k_hw_rfbus_req(ah)) {
+		DBG("ath9k: Could not kill baseband RX\n");
+		return 0;
+	}
+
+	ath9k_hw_set_channel_regs(ah, chan);
+
+	r = ath9k_hw_rf_set_freq(ah, chan);
+	if (r) {
+		DBG("ath9k: Failed to set channel\n");
+		return 0;
+	}
+	ath9k_hw_set_clockrate(ah);
+
+	ah->eep_ops->set_txpower(ah, chan,
+			     ath9k_regd_get_ctl(regulatory, chan),
+			     0,
+			     channel->maxpower * 2,
+			     min((u32) MAX_RATE_POWER,
+			     (u32) regulatory->power_limit), 0);
+
+	ath9k_hw_rfbus_done(ah);
+
+	if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
+		ath9k_hw_set_delta_slope(ah, chan);
+
+	ath9k_hw_spur_mitigate_freq(ah, chan);
+
+	return 1;
+}
+
+static void ath9k_hw_apply_gpio_override(struct ath_hw *ah)
+{
+	u32 gpio_mask = ah->gpio_mask;
+	int i;
+
+	for (i = 0; gpio_mask; i++, gpio_mask >>= 1) {
+		if (!(gpio_mask & 1))
+			continue;
+
+		ath9k_hw_cfg_output(ah, i, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+		ath9k_hw_set_gpio(ah, i, !!(ah->gpio_val & BIT(i)));
+	}
+}
+
+int ath9k_hw_check_alive(struct ath_hw *ah)
+{
+	int count = 50;
+	u32 reg;
+
+	if (AR_SREV_9285_12_OR_LATER(ah))
+		return 1;
+
+	do {
+		reg = REG_READ(ah, AR_OBS_BUS_1);
+
+		if ((reg & 0x7E7FFFEF) == 0x00702400)
+			continue;
+
+		switch (reg & 0x7E000B00) {
+		case 0x1E000000:
+		case 0x52000B00:
+		case 0x18000B00:
+			continue;
+		default:
+			return 1;
+		}
+	} while (count-- > 0);
+
+	return 0;
+}
+
+int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
+		   struct ath9k_hw_cal_data *caldata, int bChannelChange)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+	u32 saveLedState;
+	struct ath9k_channel *curchan = ah->curchan;
+	u32 saveDefAntenna;
+	u32 macStaId1;
+	int i, r;
+
+	ah->txchainmask = common->tx_chainmask;
+	ah->rxchainmask = common->rx_chainmask;
+
+	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
+		return -EIO;
+
+	if (curchan && !ah->chip_fullsleep)
+		ath9k_hw_getnf(ah, curchan);
+
+	ah->caldata = caldata;
+	if (caldata &&
+	    (chan->channel != caldata->channel ||
+	     (chan->channelFlags & ~CHANNEL_CW_INT) !=
+	     (caldata->channelFlags & ~CHANNEL_CW_INT))) {
+		/* Operating channel changed, reset channel calibration data */
+		memset(caldata, 0, sizeof(*caldata));
+		ath9k_init_nfcal_hist_buffer(ah, chan);
+	}
+
+	if (bChannelChange &&
+	    (ah->chip_fullsleep != 1) &&
+	    (ah->curchan != NULL) &&
+	    (chan->channel != ah->curchan->channel) &&
+	    ((chan->channelFlags & CHANNEL_ALL) ==
+	     (ah->curchan->channelFlags & CHANNEL_ALL)) &&
+	    (!AR_SREV_9280(ah) || AR_DEVID_7010(ah))) {
+
+		if (ath9k_hw_channel_change(ah, chan)) {
+			ath9k_hw_loadnf(ah, ah->curchan);
+			ath9k_hw_start_nfcal(ah, 1);
+			if (AR_SREV_9271(ah))
+				ar9002_hw_load_ani_reg(ah, chan);
+			return 0;
+		}
+	}
+
+	saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA);
+	if (saveDefAntenna == 0)
+		saveDefAntenna = 1;
+
+	macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
+
+	saveLedState = REG_READ(ah, AR_CFG_LED) &
+		(AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
+		 AR_CFG_LED_BLINK_THRESH_SEL | AR_CFG_LED_BLINK_SLOW);
+
+	ath9k_hw_mark_phy_inactive(ah);
+
+	ah->paprd_table_write_done = 0;
+
+	/* Only required on the first reset */
+	if (AR_SREV_9271(ah) && ah->htc_reset_init) {
+		REG_WRITE(ah,
+			  AR9271_RESET_POWER_DOWN_CONTROL,
+			  AR9271_RADIO_RF_RST);
+		udelay(50);
+	}
+
+	if (!ath9k_hw_chip_reset(ah, chan)) {
+		DBG("ath9k: Chip reset failed\n");
+		return -EINVAL;
+	}
+
+	/* Only required on the first reset */
+	if (AR_SREV_9271(ah) && ah->htc_reset_init) {
+		ah->htc_reset_init = 0;
+		REG_WRITE(ah,
+			  AR9271_RESET_POWER_DOWN_CONTROL,
+			  AR9271_GATE_MAC_CTL);
+		udelay(50);
+	}
+
+	if (AR_SREV_9280_20_OR_LATER(ah))
+		REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
+
+	if (!AR_SREV_9300_20_OR_LATER(ah))
+		ar9002_hw_enable_async_fifo(ah);
+
+	r = ath9k_hw_process_ini(ah, chan);
+	if (r)
+		return r;
+
+	/* Setup MFP options for CCMP */
+	if (AR_SREV_9280_20_OR_LATER(ah)) {
+		/* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt
+		 * frames when constructing CCMP AAD. */
+		REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT,
+			      0xc7ff);
+		ah->sw_mgmt_crypto = 0;
+	} else if (AR_SREV_9160_10_OR_LATER(ah)) {
+		/* Disable hardware crypto for management frames */
+		REG_CLR_BIT(ah, AR_PCU_MISC_MODE2,
+			    AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE);
+		REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
+			    AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT);
+		ah->sw_mgmt_crypto = 1;
+	} else
+		ah->sw_mgmt_crypto = 1;
+
+	if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
+		ath9k_hw_set_delta_slope(ah, chan);
+
+	ath9k_hw_spur_mitigate_freq(ah, chan);
+	ah->eep_ops->set_board_values(ah, chan);
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
+	REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
+		  | macStaId1
+		  | AR_STA_ID1_RTS_USE_DEF
+		  | (ah->config.
+		     ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
+		  | ah->sta_id1_defaults);
+	ath_hw_setbssidmask(common);
+	REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
+	ath9k_hw_write_associd(ah);
+	REG_WRITE(ah, AR_ISR, ~0);
+	REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+
+	ath9k_hw_set_operating_mode(ah);
+
+	r = ath9k_hw_rf_set_freq(ah, chan);
+	if (r)
+		return r;
+
+	ath9k_hw_set_clockrate(ah);
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	for (i = 0; i < AR_NUM_DCU; i++)
+		REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+
+	ah->intr_txqs = 0;
+	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+		ath9k_hw_resettxqueue(ah, i);
+
+	ath9k_hw_init_interrupt_masks(ah);
+	ath9k_hw_ani_cache_ini_regs(ah);
+
+	if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio);
+
+	ath9k_hw_init_global_settings(ah);
+
+	if (!AR_SREV_9300_20_OR_LATER(ah)) {
+		ar9002_hw_update_async_fifo(ah);
+		ar9002_hw_enable_wep_aggregation(ah);
+	}
+
+	REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
+
+	ath9k_hw_set_dma(ah);
+
+	REG_WRITE(ah, AR_OBS, 8);
+
+	if (ah->config.rx_intr_mitigation) {
+		REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
+		REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);
+	}
+
+	if (ah->config.tx_intr_mitigation) {
+		REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, 300);
+		REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, 750);
+	}
+
+	ath9k_hw_init_bb(ah, chan);
+
+	if (!ath9k_hw_init_cal(ah, chan))
+		return -EIO;
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	ath9k_hw_restore_chainmask(ah);
+	REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+
+	/*
+	 * For big endian systems turn on swapping for descriptors
+	 */
+	if (AR_SREV_9100(ah)) {
+		u32 mask;
+		mask = REG_READ(ah, AR_CFG);
+		if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) {
+			DBG2("ath9k: "
+				"CFG Byte Swap Set 0x%x\n", mask);
+		} else {
+			mask =
+				INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB;
+			REG_WRITE(ah, AR_CFG, mask);
+			DBG2("ath9k: "
+				"Setting CFG 0x%x\n", REG_READ(ah, AR_CFG));
+		}
+	} else {
+		if (common->bus_ops->ath_bus_type == ATH_USB) {
+			/* Configure AR9271 target WLAN */
+			if (AR_SREV_9271(ah))
+				REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
+			else
+				REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+		}
+#if __BYTE_ORDER == __BIG_ENDIAN
+		else if (AR_SREV_9340(ah))
+			REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0);
+		else
+			REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+#endif
+	}
+
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		ar9003_hw_disable_phy_restart(ah);
+	}
+
+	ath9k_hw_apply_gpio_override(ah);
+
+	return 0;
+}
+
+/******************************/
+/* Power Management (Chipset) */
+/******************************/
+
+/*
+ * Notify Power Mgt is disabled in self-generated frames.
+ * If requested, force chip to sleep.
+ */
+static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
+{
+	REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+	if (setChip) {
+		/*
+		 * Clear the RTC force wake bit to allow the
+		 * mac to go to sleep.
+		 */
+		REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
+			    AR_RTC_FORCE_WAKE_EN);
+		if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
+			REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
+
+		/* Shutdown chip. Active low */
+		if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah))
+			REG_CLR_BIT(ah, (AR_RTC_RESET),
+				    AR_RTC_RESET_EN);
+	}
+
+	/* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */
+	if (AR_SREV_9300_20_OR_LATER(ah))
+		REG_WRITE(ah, AR_WA,
+			  ah->WARegVal & ~AR_WA_D3_L1_DISABLE);
+}
+
+static int ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
+{
+	u32 val;
+	int i;
+
+	/* Set Bits 14 and 17 of AR_WA before powering on the chip. */
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		REG_WRITE(ah, AR_WA, ah->WARegVal);
+		udelay(10);
+	}
+
+	if (setChip) {
+		if ((REG_READ(ah, AR_RTC_STATUS) &
+		     AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) {
+			if (ath9k_hw_set_reset_reg(ah,
+					   ATH9K_RESET_POWER_ON) != 1) {
+				return 0;
+			}
+			if (!AR_SREV_9300_20_OR_LATER(ah))
+				ath9k_hw_init_pll(ah, NULL);
+		}
+		if (AR_SREV_9100(ah))
+			REG_SET_BIT(ah, AR_RTC_RESET,
+				    AR_RTC_RESET_EN);
+
+		REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
+			    AR_RTC_FORCE_WAKE_EN);
+		udelay(50);
+
+		for (i = POWER_UP_TIME / 50; i > 0; i--) {
+			val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
+			if (val == AR_RTC_STATUS_ON)
+				break;
+			udelay(50);
+			REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
+				    AR_RTC_FORCE_WAKE_EN);
+		}
+		if (i == 0) {
+			DBG("ath9k: "
+				"Failed to wakeup in %dus\n",
+				POWER_UP_TIME / 20);
+			return 0;
+		}
+	}
+
+	REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+
+	return 1;
+}
+
+int ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
+{
+	int status = 1, setChip = 1;
+	static const char *modes[] = {
+		"AWAKE",
+		"FULL-SLEEP",
+		"NETWORK SLEEP",
+		"UNDEFINED"
+	};
+
+	if (ah->power_mode == mode)
+		return status;
+
+	DBG2("ath9k: %s -> %s\n",
+		modes[ah->power_mode], modes[mode]);
+
+	switch (mode) {
+	case ATH9K_PM_AWAKE:
+		status = ath9k_hw_set_power_awake(ah, setChip);
+		break;
+	case ATH9K_PM_FULL_SLEEP:
+		ath9k_set_power_sleep(ah, setChip);
+		ah->chip_fullsleep = 1;
+		break;
+	default:
+		DBG("ath9k: Unknown power mode %d\n", mode);
+		return 0;
+	}
+	ah->power_mode = mode;
+
+	return status;
+}
+
+/*******************/
+/* HW Capabilities */
+/*******************/
+
+int ath9k_hw_fill_cap_info(struct ath_hw *ah)
+{
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	u16 eeval;
+	u8 ant_div_ctl1, tx_chainmask, rx_chainmask;
+
+	eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
+	regulatory->current_rd = eeval;
+
+	eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1);
+	if (AR_SREV_9285_12_OR_LATER(ah))
+		eeval |= AR9285_RDEXT_DEFAULT;
+	regulatory->current_rd_ext = eeval;
+
+	if (ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) {
+		if (regulatory->current_rd == 0x64 ||
+		    regulatory->current_rd == 0x65)
+			regulatory->current_rd += 5;
+		else if (regulatory->current_rd == 0x41)
+			regulatory->current_rd = 0x43;
+		DBG2("ath9k: "
+			"regdomain mapped to 0x%x\n", regulatory->current_rd);
+	}
+
+	eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
+	if ((eeval & (AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A)) == 0) {
+		DBG("ath9k: "
+			"no band has been marked as supported in EEPROM\n");
+		return -EINVAL;
+	}
+
+	if (eeval & AR5416_OPFLAGS_11A)
+		pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
+
+	if (eeval & AR5416_OPFLAGS_11G)
+		pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
+
+	pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK);
+	/*
+	 * For AR9271 we will temporarilly uses the rx chainmax as read from
+	 * the EEPROM.
+	 */
+	if ((ah->hw_version.devid == AR5416_DEVID_PCI) &&
+	    !(eeval & AR5416_OPFLAGS_11A) &&
+	    !(AR_SREV_9271(ah)))
+		/* CB71: GPIO 0 is pulled down to indicate 3 rx chains */
+		pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7;
+	else if (AR_SREV_9100(ah))
+		pCap->rx_chainmask = 0x7;
+	else
+		/* Use rx_chainmask from EEPROM. */
+		pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK);
+
+	ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA;
+
+	/* enable key search for every frame in an aggregate */
+	if (AR_SREV_9300_20_OR_LATER(ah))
+		ah->misc_mode |= AR_PCU_ALWAYS_PERFORM_KEYSEARCH;
+
+	common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
+
+	pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
+
+	if (AR_SREV_9271(ah))
+		pCap->num_gpio_pins = AR9271_NUM_GPIO;
+	else if (AR_DEVID_7010(ah))
+		pCap->num_gpio_pins = AR7010_NUM_GPIO;
+	else if (AR_SREV_9285_12_OR_LATER(ah))
+		pCap->num_gpio_pins = AR9285_NUM_GPIO;
+	else if (AR_SREV_9280_20_OR_LATER(ah))
+		pCap->num_gpio_pins = AR928X_NUM_GPIO;
+	else
+		pCap->num_gpio_pins = AR_NUM_GPIO;
+
+	if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) {
+		pCap->hw_caps |= ATH9K_HW_CAP_CST;
+		pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX;
+	} else {
+		pCap->rts_aggr_limit = (8 * 1024);
+	}
+
+	ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT);
+	if (ah->rfsilent & EEP_RFSILENT_ENABLED) {
+		ah->rfkill_gpio =
+			MS(ah->rfsilent, EEP_RFSILENT_GPIO_SEL);
+		ah->rfkill_polarity =
+			MS(ah->rfsilent, EEP_RFSILENT_POLARITY);
+
+		pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
+	}
+
+	pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
+
+	if (AR_SREV_9280(ah) || AR_SREV_9285(ah))
+		pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS;
+	else
+		pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
+
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		pCap->hw_caps |= ATH9K_HW_CAP_FASTCLOCK;
+		if (!AR_SREV_9485(ah))
+			pCap->hw_caps |= ATH9K_HW_CAP_LDPC;
+
+		pCap->rx_hp_qdepth = ATH9K_HW_RX_HP_QDEPTH;
+		pCap->rx_lp_qdepth = ATH9K_HW_RX_LP_QDEPTH;
+		pCap->rx_status_len = sizeof(struct ar9003_rxs);
+		pCap->tx_desc_len = sizeof(struct ar9003_txc);
+		pCap->txs_len = sizeof(struct ar9003_txs);
+		if (!ah->config.paprd_disable &&
+		    ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
+			pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
+	} else {
+		pCap->tx_desc_len = sizeof(struct ath_desc);
+		if (AR_SREV_9280_20(ah) &&
+		    ((ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) <=
+		      AR5416_EEP_MINOR_VER_16) ||
+		     ah->eep_ops->get_eeprom(ah, EEP_FSTCLK_5G)))
+			pCap->hw_caps |= ATH9K_HW_CAP_FASTCLOCK;
+	}
+
+	if (AR_SREV_9300_20_OR_LATER(ah))
+		pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED;
+
+	if (AR_SREV_9300_20_OR_LATER(ah))
+		ah->ent_mode = REG_READ(ah, AR_ENT_OTP);
+
+	if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah))
+		pCap->hw_caps |= ATH9K_HW_CAP_SGI_20;
+
+	if (AR_SREV_9285(ah))
+		if (ah->eep_ops->get_eeprom(ah, EEP_MODAL_VER) >= 3) {
+			ant_div_ctl1 =
+				ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
+			if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1))
+				pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
+		}
+	if (AR_SREV_9300_20_OR_LATER(ah)) {
+		if (ah->eep_ops->get_eeprom(ah, EEP_CHAIN_MASK_REDUCE))
+			pCap->hw_caps |= ATH9K_HW_CAP_APM;
+	}
+
+
+	if (AR_SREV_9485(ah)) {
+		ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
+		/*
+		 * enable the diversity-combining algorithm only when
+		 * both enable_lna_div and enable_fast_div are set
+		 *		Table for Diversity
+		 * ant_div_alt_lnaconf		bit 0-1
+		 * ant_div_main_lnaconf		bit 2-3
+		 * ant_div_alt_gaintb		bit 4
+		 * ant_div_main_gaintb		bit 5
+		 * enable_ant_div_lnadiv	bit 6
+		 * enable_ant_fast_div		bit 7
+		 */
+		if ((ant_div_ctl1 >> 0x6) == 0x3)
+			pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
+	}
+
+	if (AR_SREV_9485_10(ah)) {
+		pCap->pcie_lcr_extsync_en = 1;
+		pCap->pcie_lcr_offset = 0x80;
+	}
+
+	tx_chainmask = pCap->tx_chainmask;
+	rx_chainmask = pCap->rx_chainmask;
+	while (tx_chainmask || rx_chainmask) {
+		if (tx_chainmask & BIT(0))
+			pCap->max_txchains++;
+		if (rx_chainmask & BIT(0))
+			pCap->max_rxchains++;
+
+		tx_chainmask >>= 1;
+		rx_chainmask >>= 1;
+	}
+
+	return 0;
+}
+
+/****************************/
+/* GPIO / RFKILL / Antennae */
+/****************************/
+
+static void ath9k_hw_gpio_cfg_output_mux(struct ath_hw *ah,
+					 u32 gpio, u32 type)
+{
+	int addr;
+	u32 gpio_shift, tmp;
+
+	if (gpio > 11)
+		addr = AR_GPIO_OUTPUT_MUX3;
+	else if (gpio > 5)
+		addr = AR_GPIO_OUTPUT_MUX2;
+	else
+		addr = AR_GPIO_OUTPUT_MUX1;
+
+	gpio_shift = (gpio % 6) * 5;
+
+	if (AR_SREV_9280_20_OR_LATER(ah)
+	    || (addr != AR_GPIO_OUTPUT_MUX1)) {
+		REG_RMW(ah, addr, (type << gpio_shift),
+			(0x1f << gpio_shift));
+	} else {
+		tmp = REG_READ(ah, addr);
+		tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0);
+		tmp &= ~(0x1f << gpio_shift);
+		tmp |= (type << gpio_shift);
+		REG_WRITE(ah, addr, tmp);
+	}
+}
+
+void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio)
+{
+	u32 gpio_shift;
+
+	if (AR_DEVID_7010(ah)) {
+		gpio_shift = gpio;
+		REG_RMW(ah, AR7010_GPIO_OE,
+			(AR7010_GPIO_OE_AS_INPUT << gpio_shift),
+			(AR7010_GPIO_OE_MASK << gpio_shift));
+		return;
+	}
+
+	gpio_shift = gpio << 1;
+	REG_RMW(ah,
+		AR_GPIO_OE_OUT,
+		(AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
+		(AR_GPIO_OE_OUT_DRV << gpio_shift));
+}
+
+u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
+{
+#define MS_REG_READ(x, y) \
+	(MS(REG_READ(ah, AR_GPIO_IN_OUT), x##_GPIO_IN_VAL) & (AR_GPIO_BIT(y)))
+
+	if (gpio >= ah->caps.num_gpio_pins)
+		return 0xffffffff;
+
+	if (AR_DEVID_7010(ah)) {
+		u32 val;
+		val = REG_READ(ah, AR7010_GPIO_IN);
+		return (MS(val, AR7010_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) == 0;
+	} else if (AR_SREV_9300_20_OR_LATER(ah))
+		return (MS(REG_READ(ah, AR_GPIO_IN), AR9300_GPIO_IN_VAL) &
+			AR_GPIO_BIT(gpio)) != 0;
+	else if (AR_SREV_9271(ah))
+		return MS_REG_READ(AR9271, gpio) != 0;
+	else if (AR_SREV_9287_11_OR_LATER(ah))
+		return MS_REG_READ(AR9287, gpio) != 0;
+	else if (AR_SREV_9285_12_OR_LATER(ah))
+		return MS_REG_READ(AR9285, gpio) != 0;
+	else if (AR_SREV_9280_20_OR_LATER(ah))
+		return MS_REG_READ(AR928X, gpio) != 0;
+	else
+		return MS_REG_READ(AR, gpio) != 0;
+}
+
+void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
+			 u32 ah_signal_type)
+{
+	u32 gpio_shift;
+
+	if (AR_DEVID_7010(ah)) {
+		gpio_shift = gpio;
+		REG_RMW(ah, AR7010_GPIO_OE,
+			(AR7010_GPIO_OE_AS_OUTPUT << gpio_shift),
+			(AR7010_GPIO_OE_MASK << gpio_shift));
+		return;
+	}
+
+	ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
+	gpio_shift = 2 * gpio;
+	REG_RMW(ah,
+		AR_GPIO_OE_OUT,
+		(AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
+		(AR_GPIO_OE_OUT_DRV << gpio_shift));
+}
+
+void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
+{
+	if (AR_DEVID_7010(ah)) {
+		val = val ? 0 : 1;
+		REG_RMW(ah, AR7010_GPIO_OUT, ((val&1) << gpio),
+			AR_GPIO_BIT(gpio));
+		return;
+	}
+
+	if (AR_SREV_9271(ah))
+		val = ~val;
+
+	REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
+		AR_GPIO_BIT(gpio));
+}
+
+u32 ath9k_hw_getdefantenna(struct ath_hw *ah)
+{
+	return REG_READ(ah, AR_DEF_ANTENNA) & 0x7;
+}
+
+void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna)
+{
+	REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
+}
+
+/*********************/
+/* General Operation */
+/*********************/
+
+u32 ath9k_hw_getrxfilter(struct ath_hw *ah)
+{
+	u32 bits = REG_READ(ah, AR_RX_FILTER);
+	u32 phybits = REG_READ(ah, AR_PHY_ERR);
+
+	if (phybits & AR_PHY_ERR_RADAR)
+		bits |= ATH9K_RX_FILTER_PHYRADAR;
+	if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING))
+		bits |= ATH9K_RX_FILTER_PHYERR;
+
+	return bits;
+}
+
+void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
+{
+	u32 phybits;
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	REG_WRITE(ah, AR_RX_FILTER, bits);
+
+	phybits = 0;
+	if (bits & ATH9K_RX_FILTER_PHYRADAR)
+		phybits |= AR_PHY_ERR_RADAR;
+	if (bits & ATH9K_RX_FILTER_PHYERR)
+		phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING;
+	REG_WRITE(ah, AR_PHY_ERR, phybits);
+
+	if (phybits)
+		REG_SET_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA);
+	else
+		REG_CLR_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+}
+
+int ath9k_hw_phy_disable(struct ath_hw *ah)
+{
+	if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
+		return 0;
+
+	ath9k_hw_init_pll(ah, NULL);
+	return 1;
+}
+
+int ath9k_hw_disable(struct ath_hw *ah)
+{
+	if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
+		return 0;
+
+	if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD))
+		return 0;
+
+	ath9k_hw_init_pll(ah, NULL);
+	return 1;
+}
+
+void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, int test)
+{
+	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+	struct ath9k_channel *chan = ah->curchan;
+	struct net80211_channel *channel = chan->chan;
+
+	regulatory->power_limit = min(limit, (u32) MAX_RATE_POWER);
+
+	ah->eep_ops->set_txpower(ah, chan,
+				 ath9k_regd_get_ctl(regulatory, chan),
+				 0,
+				 channel->maxpower * 2,
+				 min((u32) MAX_RATE_POWER,
+				 (u32) regulatory->power_limit), test);
+}
+
+void ath9k_hw_setopmode(struct ath_hw *ah)
+{
+	ath9k_hw_set_operating_mode(ah);
+}
+
+void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1)
+{
+	REG_WRITE(ah, AR_MCAST_FIL0, filter0);
+	REG_WRITE(ah, AR_MCAST_FIL1, filter1);
+}
+
+void ath9k_hw_write_associd(struct ath_hw *ah)
+{
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(common->curbssid));
+	REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(common->curbssid + 4) |
+		  ((common->curaid & 0x3fff) << AR_BSS_ID1_AID_S));
+}
+
+void ath9k_hw_set11nmac2040(struct ath_hw *ah)
+{
+	u32 macmode;
+
+	macmode = 0;
+
+	REG_WRITE(ah, AR_2040_MODE, macmode);
+}
+
+static struct {
+	u32 version;
+	const char * name;
+} ath_mac_bb_names[] = {
+	/* Devices with external radios */
+	{ AR_SREV_VERSION_5416_PCI,	"5416" },
+	{ AR_SREV_VERSION_5416_PCIE,	"5418" },
+	{ AR_SREV_VERSION_9100,		"9100" },
+	{ AR_SREV_VERSION_9160,		"9160" },
+	/* Single-chip solutions */
+	{ AR_SREV_VERSION_9280,		"9280" },
+	{ AR_SREV_VERSION_9285,		"9285" },
+	{ AR_SREV_VERSION_9287,         "9287" },
+	{ AR_SREV_VERSION_9271,         "9271" },
+	{ AR_SREV_VERSION_9300,         "9300" },
+	{ AR_SREV_VERSION_9485,         "9485" },
+};
+
+/* For devices with external radios */
+static struct {
+	u16 version;
+	const char * name;
+} ath_rf_names[] = {
+	{ 0,				"5133" },
+	{ AR_RAD5133_SREV_MAJOR,	"5133" },
+	{ AR_RAD5122_SREV_MAJOR,	"5122" },
+	{ AR_RAD2133_SREV_MAJOR,	"2133" },
+	{ AR_RAD2122_SREV_MAJOR,	"2122" }
+};
+
+/*
+ * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown.
+ */
+static const char *ath9k_hw_mac_bb_name(u32 mac_bb_version)
+{
+	unsigned int i;
+
+	for (i=0; i<ARRAY_SIZE(ath_mac_bb_names); i++) {
+		if (ath_mac_bb_names[i].version == mac_bb_version) {
+			return ath_mac_bb_names[i].name;
+		}
+	}
+
+	return "????";
+}
+
+/*
+ * Return the RF name. "????" is returned if the RF is unknown.
+ * Used for devices with external radios.
+ */
+static const char *ath9k_hw_rf_name(u16 rf_version)
+{
+	unsigned int i;
+
+	for (i=0; i<ARRAY_SIZE(ath_rf_names); i++) {
+		if (ath_rf_names[i].version == rf_version) {
+			return ath_rf_names[i].name;
+		}
+	}
+
+	return "????";
+}
+
+void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len)
+{
+	int used;
+
+	/* chipsets >= AR9280 are single-chip */
+	if (AR_SREV_9280_20_OR_LATER(ah)) {
+		used = snprintf(hw_name, len,
+			       "Atheros AR%s Rev:%x",
+			       ath9k_hw_mac_bb_name(ah->hw_version.macVersion),
+			       ah->hw_version.macRev);
+	}
+	else {
+		used = snprintf(hw_name, len,
+			       "Atheros AR%s MAC/BB Rev:%x AR%s RF Rev:%x",
+			       ath9k_hw_mac_bb_name(ah->hw_version.macVersion),
+			       ah->hw_version.macRev,
+			       ath9k_hw_rf_name((ah->hw_version.analog5GhzRev &
+						AR_RADIO_SREV_MAJOR)),
+			       ah->hw_version.phyRev);
+	}
+
+	hw_name[used] = '\0';
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_init.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_init.c
new file mode 100644
index 0000000000000000000000000000000000000000..93fbe7733d295731ee6b5d1df1ebd99787adefa8
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_init.c
@@ -0,0 +1,593 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/malloc.h>
+#include <ipxe/pci_io.h>
+#include <ipxe/pci.h>
+
+#include "ath9k.h"
+
+int is_ath9k_unloaded;
+/* We use the hw_value as an index into our private channel structure */
+
+#define CHAN2G(_freq, _idx)  { \
+	.band = NET80211_BAND_2GHZ, \
+	.center_freq = (_freq), \
+	.hw_value = (_idx), \
+	.maxpower = 20, \
+}
+
+#define CHAN5G(_freq, _idx) { \
+	.band = NET80211_BAND_5GHZ, \
+	.center_freq = (_freq), \
+	.hw_value = (_idx), \
+	.maxpower = 20, \
+}
+
+/* Some 2 GHz radios are actually tunable on 2312-2732
+ * on 5 MHz steps, we support the channels which we know
+ * we have calibration data for all cards though to make
+ * this static */
+static const struct net80211_channel ath9k_2ghz_chantable[] = {
+	CHAN2G(2412, 0), /* Channel 1 */
+	CHAN2G(2417, 1), /* Channel 2 */
+	CHAN2G(2422, 2), /* Channel 3 */
+	CHAN2G(2427, 3), /* Channel 4 */
+	CHAN2G(2432, 4), /* Channel 5 */
+	CHAN2G(2437, 5), /* Channel 6 */
+	CHAN2G(2442, 6), /* Channel 7 */
+	CHAN2G(2447, 7), /* Channel 8 */
+	CHAN2G(2452, 8), /* Channel 9 */
+	CHAN2G(2457, 9), /* Channel 10 */
+	CHAN2G(2462, 10), /* Channel 11 */
+	CHAN2G(2467, 11), /* Channel 12 */
+	CHAN2G(2472, 12), /* Channel 13 */
+	CHAN2G(2484, 13), /* Channel 14 */
+};
+
+/* Some 5 GHz radios are actually tunable on XXXX-YYYY
+ * on 5 MHz steps, we support the channels which we know
+ * we have calibration data for all cards though to make
+ * this static */
+static const struct net80211_channel ath9k_5ghz_chantable[] = {
+	/* _We_ call this UNII 1 */
+	CHAN5G(5180, 14), /* Channel 36 */
+	CHAN5G(5200, 15), /* Channel 40 */
+	CHAN5G(5220, 16), /* Channel 44 */
+	CHAN5G(5240, 17), /* Channel 48 */
+	/* _We_ call this UNII 2 */
+	CHAN5G(5260, 18), /* Channel 52 */
+	CHAN5G(5280, 19), /* Channel 56 */
+	CHAN5G(5300, 20), /* Channel 60 */
+	CHAN5G(5320, 21), /* Channel 64 */
+	/* _We_ call this "Middle band" */
+	CHAN5G(5500, 22), /* Channel 100 */
+	CHAN5G(5520, 23), /* Channel 104 */
+	CHAN5G(5540, 24), /* Channel 108 */
+	CHAN5G(5560, 25), /* Channel 112 */
+	CHAN5G(5580, 26), /* Channel 116 */
+	CHAN5G(5600, 27), /* Channel 120 */
+	CHAN5G(5620, 28), /* Channel 124 */
+	CHAN5G(5640, 29), /* Channel 128 */
+	CHAN5G(5660, 30), /* Channel 132 */
+	CHAN5G(5680, 31), /* Channel 136 */
+	CHAN5G(5700, 32), /* Channel 140 */
+	/* _We_ call this UNII 3 */
+	CHAN5G(5745, 33), /* Channel 149 */
+	CHAN5G(5765, 34), /* Channel 153 */
+	CHAN5G(5785, 35), /* Channel 157 */
+	CHAN5G(5805, 36), /* Channel 161 */
+	CHAN5G(5825, 37), /* Channel 165 */
+};
+
+/* Atheros hardware rate code addition for short premble */
+#define SHPCHECK(__hw_rate, __flags) \
+	((__flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
+
+#define RATE(_bitrate, _hw_rate, _flags) {              \
+	.bitrate        = (_bitrate),                   \
+	.flags          = (_flags),                     \
+	.hw_value       = (_hw_rate),                   \
+	.hw_value_short = (SHPCHECK(_hw_rate, _flags))  \
+}
+
+static struct ath9k_legacy_rate ath9k_legacy_rates[] = {
+	RATE(10, 0x1b, 0),
+	RATE(20, 0x1a, IEEE80211_TX_RC_USE_SHORT_PREAMBLE),
+	RATE(55, 0x19, IEEE80211_TX_RC_USE_SHORT_PREAMBLE),
+	RATE(110, 0x18, IEEE80211_TX_RC_USE_SHORT_PREAMBLE),
+	RATE(60, 0x0b, 0),
+	RATE(90, 0x0f, 0),
+	RATE(120, 0x0a, 0),
+	RATE(180, 0x0e, 0),
+	RATE(240, 0x09, 0),
+	RATE(360, 0x0d, 0),
+	RATE(480, 0x08, 0),
+	RATE(540, 0x0c, 0),
+};
+
+static void ath9k_deinit_softc(struct ath_softc *sc);
+
+/*
+ * Read and write, they both share the same lock. We do this to serialize
+ * reads and writes on Atheros 802.11n PCI devices only. This is required
+ * as the FIFO on these devices can only accept sanely 2 requests.
+ */
+
+static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
+{
+	struct ath_hw *ah = (struct ath_hw *) hw_priv;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath_softc *sc = (struct ath_softc *) common->priv;
+
+	writel(val, sc->mem + reg_offset);
+}
+
+static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
+{
+	struct ath_hw *ah = (struct ath_hw *) hw_priv;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath_softc *sc = (struct ath_softc *) common->priv;
+	u32 val;
+
+	val = readl(sc->mem + reg_offset);
+	return val;
+}
+
+static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
+{
+	struct ath_hw *ah = (struct ath_hw *) hw_priv;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath_softc *sc = (struct ath_softc *) common->priv;
+	u32 val;
+
+	val = readl(sc->mem + reg_offset);
+	val &= ~clr;
+	val |= set;
+	writel(val, sc->mem + reg_offset);
+
+	return val;
+}
+
+/**************************/
+/*     Initialization     */
+/**************************/
+
+/*
+ *  This function will allocate both the DMA descriptor structure, and the
+ *  buffers it contains.  These are used to contain the descriptors used
+ *  by the system.
+*/
+int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
+		      struct list_head *head, const char *name,
+		      int nbuf, int ndesc, int is_tx)
+{
+#define	DS2PHYS(_dd, _ds)						\
+	((_dd)->dd_desc_paddr + ((char *)(_ds) - (char *)(_dd)->dd_desc))
+#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF9F) ? 1 : 0)
+	u8 *ds;
+	struct ath_buf *bf;
+	int i, bsize, error, desc_len;
+
+	DBG2("ath9k: %s DMA: %d buffers %d desc/buf\n",
+		name, nbuf, ndesc);
+
+	INIT_LIST_HEAD(head);
+
+	if (is_tx)
+		desc_len = sc->sc_ah->caps.tx_desc_len;
+	else
+		desc_len = sizeof(struct ath_desc);
+
+	/* ath_desc must be a multiple of DWORDs */
+	if ((desc_len % 4) != 0) {
+		DBG("ath9k: ath_desc not DWORD aligned\n");
+		error = -ENOMEM;
+		goto fail;
+	}
+
+	dd->dd_desc_len = desc_len * nbuf * ndesc;
+
+	/*
+	 * Need additional DMA memory because we can't use
+	 * descriptors that cross the 4K page boundary.
+	 * However, iPXE only utilizes 16 buffers, which
+	 * will never make up more than half of one page,
+	 * so we will only ever skip 1 descriptor, if that.
+	 */
+	if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+		u32 ndesc_skipped = 1;
+		u32 dma_len;
+
+		dma_len = ndesc_skipped * desc_len;
+		dd->dd_desc_len += dma_len;
+	}
+
+	/* allocate descriptors */
+	dd->dd_desc = malloc_dma(dd->dd_desc_len, 16);
+	if (dd->dd_desc == NULL) {
+		error = -ENOMEM;
+		goto fail;
+	}
+	dd->dd_desc_paddr = virt_to_bus(dd->dd_desc);
+	ds = (u8 *) dd->dd_desc;
+	DBG2("ath9k: %s DMA map: %p (%d) -> %llx (%d)\n",
+		name, ds, (u32) dd->dd_desc_len,
+		ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
+
+	/* allocate buffers */
+	bsize = sizeof(struct ath_buf) * nbuf;
+	bf = zalloc(bsize);
+	if (bf == NULL) {
+		error = -ENOMEM;
+		goto fail2;
+	}
+	dd->dd_bufptr = bf;
+
+	for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) {
+		bf->bf_desc = ds;
+		bf->bf_daddr = DS2PHYS(dd, ds);
+
+		if (!(sc->sc_ah->caps.hw_caps &
+		      ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+			/*
+			 * Skip descriptor addresses which can cause 4KB
+			 * boundary crossing (addr + length) with a 32 dword
+			 * descriptor fetch.
+			 */
+			while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
+				ds += (desc_len * ndesc);
+				bf->bf_desc = ds;
+				bf->bf_daddr = DS2PHYS(dd, ds);
+			}
+		}
+		list_add_tail(&bf->list, head);
+	}
+	return 0;
+fail2:
+	free_dma(dd->dd_desc, dd->dd_desc_len);
+fail:
+	memset(dd, 0, sizeof(*dd));
+	return error;
+#undef ATH_DESC_4KB_BOUND_CHECK
+#undef DS2PHYS
+}
+
+void ath9k_init_crypto(struct ath_softc *sc)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	unsigned int i = 0;
+
+	/* Get the hardware key cache size. */
+	common->keymax = AR_KEYTABLE_SIZE;
+
+	/*
+	 * Reset the key cache since some parts do not
+	 * reset the contents on initial power up.
+	 */
+	for (i = 0; i < common->keymax; i++)
+		ath_hw_keyreset(common, (u16) i);
+
+	/*
+	 * Check whether the separate key cache entries
+	 * are required to handle both tx+rx MIC keys.
+	 * With split mic keys the number of stations is limited
+	 * to 27 otherwise 59.
+	 */
+	if (sc->sc_ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
+		common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
+}
+
+static int ath9k_init_queues(struct ath_softc *sc)
+{
+	int i = 0;
+
+	for (i = 0; i < WME_NUM_AC; i++) {
+		sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
+		sc->tx.txq_map[i]->mac80211_qnum = i;
+	}
+	return 0;
+}
+
+static int ath9k_init_channels_rates(struct ath_softc *sc)
+{
+	unsigned int i;
+
+	memcpy(&sc->rates, ath9k_legacy_rates, sizeof(ath9k_legacy_rates));
+
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
+		memcpy(&sc->hwinfo->channels[sc->hwinfo->nr_channels], ath9k_2ghz_chantable, sizeof(ath9k_2ghz_chantable));
+
+		sc->hwinfo->nr_channels += ARRAY_SIZE(ath9k_2ghz_chantable);
+
+		for (i = 0; i < ARRAY_SIZE(ath9k_legacy_rates); i++)
+			sc->hwinfo->rates[NET80211_BAND_2GHZ][i] = ath9k_legacy_rates[i].bitrate;
+		sc->hwinfo->nr_rates[NET80211_BAND_2GHZ] = ARRAY_SIZE(ath9k_legacy_rates);
+	}
+
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
+		memcpy(&sc->hwinfo->channels[sc->hwinfo->nr_channels], ath9k_5ghz_chantable, sizeof(ath9k_5ghz_chantable));
+
+		sc->hwinfo->nr_channels += ARRAY_SIZE(ath9k_5ghz_chantable);
+
+		for (i = 4; i < ARRAY_SIZE(ath9k_legacy_rates); i++)
+			sc->hwinfo->rates[NET80211_BAND_5GHZ][i - 4] = ath9k_legacy_rates[i].bitrate;
+		sc->hwinfo->nr_rates[NET80211_BAND_5GHZ] = ARRAY_SIZE(ath9k_legacy_rates) - 4;
+	}
+	return 0;
+}
+
+static void ath9k_init_misc(struct ath_softc *sc)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+	common->ani.timer = 0;
+
+	sc->config.txpowlimit = ATH_TXPOWER_MAX;
+
+	common->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
+	common->rx_chainmask = sc->sc_ah->caps.rx_chainmask;
+
+	ath9k_hw_set_diversity(sc->sc_ah, 1);
+	sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah);
+
+	memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
+}
+
+static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
+			    const struct ath_bus_ops *bus_ops)
+{
+	struct ath_hw *ah = NULL;
+	struct ath_common *common;
+	int ret = 0, i;
+	int csz = 0;
+
+	ah = zalloc(sizeof(struct ath_hw));
+	if (!ah)
+		return -ENOMEM;
+
+	ah->dev = sc->dev;
+	ah->hw_version.devid = devid;
+	ah->hw_version.subsysid = subsysid;
+	ah->reg_ops.read = ath9k_ioread32;
+	ah->reg_ops.write = ath9k_iowrite32;
+	ah->reg_ops.rmw = ath9k_reg_rmw;
+	sc->sc_ah = ah;
+
+	sc->hwinfo = zalloc(sizeof(*sc->hwinfo));
+	if (!sc->hwinfo) {
+		DBG("ath9k: cannot allocate 802.11 hardware info structure\n");
+		return -ENOMEM;
+	}
+
+	ah->ah_flags |= AH_USE_EEPROM;
+	sc->sc_ah->led_pin = -1;
+
+	common = ath9k_hw_common(ah);
+	common->ops = &ah->reg_ops;
+	common->bus_ops = bus_ops;
+	common->ah = ah;
+	common->dev = sc->dev;
+	common->priv = sc;
+
+	sc->intr_tq = ath9k_tasklet;
+
+	/*
+	 * Cache line size is used to size and align various
+	 * structures used to communicate with the hardware.
+	 */
+	ath_read_cachesize(common, &csz);
+	common->cachelsz = csz << 2; /* convert to bytes */
+
+	/* Initializes the hardware for all supported chipsets */
+	ret = ath9k_hw_init(ah);
+	if (ret)
+		goto err_hw;
+
+	memcpy(sc->hwinfo->hwaddr, common->macaddr, ETH_ALEN);
+
+	ret = ath9k_init_queues(sc);
+	if (ret)
+		goto err_queues;
+
+	ret = ath9k_init_channels_rates(sc);
+	if (ret)
+		goto err_btcoex;
+
+	ath9k_init_crypto(sc);
+	ath9k_init_misc(sc);
+
+	return 0;
+
+err_btcoex:
+	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+		if (ATH_TXQ_SETUP(sc, i))
+			ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+err_queues:
+	ath9k_hw_deinit(ah);
+err_hw:
+	free(sc->hwinfo);
+	sc->hwinfo = NULL;
+
+	free(ah);
+	sc->sc_ah = NULL;
+
+	return ret;
+}
+
+static void ath9k_init_band_txpower(struct ath_softc *sc, int band)
+{
+	struct net80211_channel *chan;
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
+	int i;
+
+	for (i = 0; i < sc->hwinfo->nr_channels; i++) {
+		chan = &sc->hwinfo->channels[i];
+		if(chan->band != band)
+			continue;
+		ah->curchan = &ah->channels[chan->hw_value];
+		ath9k_hw_set_txpowerlimit(ah, MAX_RATE_POWER, 1);
+		chan->maxpower = reg->max_power_level / 2;
+	}
+}
+
+static void ath9k_init_txpower_limits(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath9k_channel *curchan = ah->curchan;
+
+	if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
+		ath9k_init_band_txpower(sc, NET80211_BAND_2GHZ);
+	if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
+		ath9k_init_band_txpower(sc, NET80211_BAND_5GHZ);
+
+	ah->curchan = curchan;
+}
+
+void ath9k_set_hw_capab(struct ath_softc *sc, struct net80211_device *dev __unused)
+{
+	sc->hwinfo->flags = NET80211_HW_RX_HAS_FCS;
+	sc->hwinfo->signal_type = NET80211_SIGNAL_DB;
+	sc->hwinfo->signal_max = 40; /* 35dB should give perfect 54Mbps */
+	sc->hwinfo->channel_change_time = 5000;
+
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
+	{
+		sc->hwinfo->bands |= NET80211_BAND_BIT_2GHZ;
+		sc->hwinfo->modes |= NET80211_MODE_B | NET80211_MODE_G;
+	}
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
+	{
+		sc->hwinfo->bands |= NET80211_BAND_BIT_5GHZ;
+		sc->hwinfo->modes |= NET80211_MODE_A;
+	}
+}
+
+int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
+		    const struct ath_bus_ops *bus_ops)
+{
+	struct net80211_device *dev = sc->dev;
+	/*struct ath_common *common;
+	struct ath_hw *ah;*/
+	int error = 0;
+	/*struct ath_regulatory *reg;*/
+
+	/* Bring up device */
+	error = ath9k_init_softc(devid, sc, subsysid, bus_ops);
+	if (error != 0)
+		goto error_init;
+
+	/*ah = sc->sc_ah;
+	common = ath9k_hw_common(ah);*/
+	ath9k_set_hw_capab(sc, dev);
+	/* TODO Cottsay: reg */
+	/* Initialize regulatory */
+	/*error = ath_regd_init(&common->regulatory, sc->dev->wiphy,
+			      ath9k_reg_notifier);
+	if (error)
+		goto error_regd;
+
+	reg = &common->regulatory;*/
+
+	/* Setup TX DMA */
+	error = ath_tx_init(sc, ATH_TXBUF);
+	if (error != 0)
+		goto error_tx;
+
+	/* Setup RX DMA */
+	error = ath_rx_init(sc, ATH_RXBUF);
+	if (error != 0)
+		goto error_rx;
+
+	ath9k_init_txpower_limits(sc);
+
+	/* Register with mac80211 */
+	error = net80211_register(dev, &ath9k_ops, sc->hwinfo);
+	if (error)
+		goto error_register;
+
+	/* TODO Cottsay: reg */
+	/* Handle world regulatory */
+	/*if (!ath_is_world_regd(reg)) {
+		error = regulatory_hint(hw->wiphy, reg->alpha2);
+		if (error)
+			goto error_world;
+	}*/
+
+	sc->hw_pll_work = ath_hw_pll_work;
+	sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
+
+	/* TODO Cottsay: rfkill */
+	/*ath_start_rfkill_poll(sc);*/
+
+	return 0;
+
+//error_world:
+//	net80211_unregister(dev);
+error_register:
+	ath_rx_cleanup(sc);
+error_rx:
+	ath_tx_cleanup(sc);
+error_tx:
+	ath9k_deinit_softc(sc);
+error_init:
+	return error;
+}
+
+/*****************************/
+/*     De-Initialization     */
+/*****************************/
+
+static void ath9k_deinit_softc(struct ath_softc *sc)
+{
+	int i = 0;
+
+	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+		if (ATH_TXQ_SETUP(sc, i))
+			ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+
+	ath9k_hw_deinit(sc->sc_ah);
+
+	free(sc->hwinfo);
+	sc->hwinfo = NULL;
+	free(sc->sc_ah);
+	sc->sc_ah = NULL;
+}
+
+void ath9k_deinit_device(struct ath_softc *sc)
+{
+	struct net80211_device *dev = sc->dev;
+
+	net80211_unregister(dev);
+	ath_rx_cleanup(sc);
+	ath_tx_cleanup(sc);
+	ath9k_deinit_softc(sc);
+}
+
+void ath_descdma_cleanup(struct ath_softc *sc __unused,
+			 struct ath_descdma *dd,
+			 struct list_head *head)
+{
+	free_dma(dd->dd_desc, dd->dd_desc_len);
+
+	INIT_LIST_HEAD(head);
+	free(dd->dd_bufptr);
+	memset(dd, 0, sizeof(*dd));
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_mac.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_mac.c
new file mode 100644
index 0000000000000000000000000000000000000000..c2f6d630afb80e93a3e2af40e0ecc50c9e41aadc
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_mac.c
@@ -0,0 +1,733 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/io.h>
+
+#include "hw.h"
+#include "hw-ops.h"
+
+static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
+					struct ath9k_tx_queue_info *qi __unused)
+{
+	DBG2("ath9k: "
+		"tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
+		ah->txok_interrupt_mask, ah->txerr_interrupt_mask,
+		ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
+		ah->txurn_interrupt_mask);
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	REG_WRITE(ah, AR_IMR_S0,
+		  SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK)
+		  | SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC));
+	REG_WRITE(ah, AR_IMR_S1,
+		  SM(ah->txerr_interrupt_mask, AR_IMR_S1_QCU_TXERR)
+		  | SM(ah->txeol_interrupt_mask, AR_IMR_S1_QCU_TXEOL));
+
+	ah->imrs2_reg &= ~AR_IMR_S2_QCU_TXURN;
+	ah->imrs2_reg |= (ah->txurn_interrupt_mask & AR_IMR_S2_QCU_TXURN);
+	REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+}
+
+void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp)
+{
+	REG_WRITE(ah, AR_QTXDP(q), txdp);
+}
+
+void ath9k_hw_txstart(struct ath_hw *ah, u32 q)
+{
+	DBG2("ath9k: "
+		"Enable TXE on queue: %d\n", q);
+	REG_WRITE(ah, AR_Q_TXE, 1 << q);
+}
+
+u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
+{
+	u32 npend;
+
+	npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
+	if (npend == 0) {
+
+		if (REG_READ(ah, AR_Q_TXE) & (1 << q))
+			npend = 1;
+	}
+
+	return npend;
+}
+
+/**
+ * ath9k_hw_updatetxtriglevel - adjusts the frame trigger level
+ *
+ * @ah: atheros hardware struct
+ * @bIncTrigLevel: whether or not the frame trigger level should be updated
+ *
+ * The frame trigger level specifies the minimum number of bytes,
+ * in units of 64 bytes, that must be DMA'ed into the PCU TX FIFO
+ * before the PCU will initiate sending the frame on the air. This can
+ * mean we initiate transmit before a full frame is on the PCU TX FIFO.
+ * Resets to 0x1 (meaning 64 bytes or a full frame, whichever occurs
+ * first)
+ *
+ * Caution must be taken to ensure to set the frame trigger level based
+ * on the DMA request size. For example if the DMA request size is set to
+ * 128 bytes the trigger level cannot exceed 6 * 64 = 384. This is because
+ * there need to be enough space in the tx FIFO for the requested transfer
+ * size. Hence the tx FIFO will stop with 512 - 128 = 384 bytes. If we set
+ * the threshold to a value beyond 6, then the transmit will hang.
+ *
+ * Current dual   stream devices have a PCU TX FIFO size of 8 KB.
+ * Current single stream devices have a PCU TX FIFO size of 4 KB, however,
+ * there is a hardware issue which forces us to use 2 KB instead so the
+ * frame trigger level must not exceed 2 KB for these chipsets.
+ */
+int ath9k_hw_updatetxtriglevel(struct ath_hw *ah, int bIncTrigLevel)
+{
+	u32 txcfg, curLevel, newLevel;
+
+	if (ah->tx_trig_level >= ah->config.max_txtrig_level)
+		return 0;
+
+	ath9k_hw_disable_interrupts(ah);
+
+	txcfg = REG_READ(ah, AR_TXCFG);
+	curLevel = MS(txcfg, AR_FTRIG);
+	newLevel = curLevel;
+	if (bIncTrigLevel) {
+		if (curLevel < ah->config.max_txtrig_level)
+			newLevel++;
+	} else if (curLevel > MIN_TX_FIFO_THRESHOLD)
+		newLevel--;
+	if (newLevel != curLevel)
+		REG_WRITE(ah, AR_TXCFG,
+			  (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
+
+	ath9k_hw_enable_interrupts(ah);
+
+	ah->tx_trig_level = newLevel;
+
+	return newLevel != curLevel;
+}
+
+void ath9k_hw_abort_tx_dma(struct ath_hw *ah)
+{
+	int i, q;
+
+	REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M);
+
+	REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
+	REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+	REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
+
+	for (q = 0; q < AR_NUM_QCU; q++) {
+		for (i = 0; i < 1000; i++) {
+			if (i)
+				udelay(5);
+
+			if (!ath9k_hw_numtxpending(ah, q))
+				break;
+		}
+	}
+
+	REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF);
+	REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+	REG_CLR_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF);
+
+	REG_WRITE(ah, AR_Q_TXD, 0);
+}
+
+void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
+{
+	*txqs &= ah->intr_txqs;
+	ah->intr_txqs &= ~(*txqs);
+}
+
+int ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
+			    const struct ath9k_tx_queue_info *qinfo)
+{
+	u32 cw;
+	struct ath9k_tx_queue_info *qi;
+
+	qi = &ah->txq[q];
+	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+		DBG("ath9k: "
+			"Set TXQ properties, inactive queue: %d\n", q);
+		return 0;
+	}
+
+	DBG2("ath9k: Set queue properties for: %d\n", q);
+
+	qi->tqi_ver = qinfo->tqi_ver;
+	qi->tqi_subtype = qinfo->tqi_subtype;
+	qi->tqi_qflags = qinfo->tqi_qflags;
+	qi->tqi_priority = qinfo->tqi_priority;
+	if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
+		qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
+	else
+		qi->tqi_aifs = INIT_AIFS;
+	if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
+		cw = min(qinfo->tqi_cwmin, 1024U);
+		qi->tqi_cwmin = 1;
+		while (qi->tqi_cwmin < cw)
+			qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
+	} else
+		qi->tqi_cwmin = qinfo->tqi_cwmin;
+	if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
+		cw = min(qinfo->tqi_cwmax, 1024U);
+		qi->tqi_cwmax = 1;
+		while (qi->tqi_cwmax < cw)
+			qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
+	} else
+		qi->tqi_cwmax = INIT_CWMAX;
+
+	if (qinfo->tqi_shretry != 0)
+		qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
+	else
+		qi->tqi_shretry = INIT_SH_RETRY;
+	if (qinfo->tqi_lgretry != 0)
+		qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
+	else
+		qi->tqi_lgretry = INIT_LG_RETRY;
+	qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
+	qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
+	qi->tqi_burstTime = qinfo->tqi_burstTime;
+	qi->tqi_readyTime = qinfo->tqi_readyTime;
+
+	return 1;
+}
+
+int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
+			  const struct ath9k_tx_queue_info *qinfo)
+{
+	struct ath9k_tx_queue_info *qi;
+	int q;
+
+	for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++)
+		if (ah->txq[q].tqi_type ==
+		    ATH9K_TX_QUEUE_INACTIVE)
+			break;
+	if (q == ATH9K_NUM_TX_QUEUES) {
+		DBG("No available TX queue\n");
+		return -1;
+	}
+
+	DBG2("ath9K: Setup TX queue: %d\n", q);
+
+	qi = &ah->txq[q];
+	if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
+		DBG("ath9k: TX queue: %d already active\n", q);
+		return -1;
+	}
+	memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
+	qi->tqi_type = type;
+	if (qinfo == NULL) {
+		qi->tqi_qflags =
+			TXQ_FLAG_TXOKINT_ENABLE
+			| TXQ_FLAG_TXERRINT_ENABLE
+			| TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
+		qi->tqi_aifs = INIT_AIFS;
+		qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
+		qi->tqi_cwmax = INIT_CWMAX;
+		qi->tqi_shretry = INIT_SH_RETRY;
+		qi->tqi_lgretry = INIT_LG_RETRY;
+		qi->tqi_physCompBuf = 0;
+	} else {
+		qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
+		(void) ath9k_hw_set_txq_props(ah, q, qinfo);
+	}
+
+	return q;
+}
+
+int ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
+{
+	struct ath9k_tx_queue_info *qi;
+
+	qi = &ah->txq[q];
+	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+		DBG("ath9k: "
+			"Release TXQ, inactive queue: %d\n", q);
+		return 0;
+	}
+
+	DBG2("ath9k: Release TX queue: %d\n", q);
+
+	qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
+	ah->txok_interrupt_mask &= ~(1 << q);
+	ah->txerr_interrupt_mask &= ~(1 << q);
+	ah->txdesc_interrupt_mask &= ~(1 << q);
+	ah->txeol_interrupt_mask &= ~(1 << q);
+	ah->txurn_interrupt_mask &= ~(1 << q);
+	ath9k_hw_set_txq_interrupts(ah, qi);
+
+	return 1;
+}
+
+int ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
+{
+	struct ath9k_channel *chan = ah->curchan;
+	struct ath9k_tx_queue_info *qi;
+	u32 cwMin, chanCwMin, value __unused;
+
+	qi = &ah->txq[q];
+	if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+		DBG("ath9k: "
+			"Reset TXQ, inactive queue: %d\n", q);
+		return 1;
+	}
+
+	DBG2("ath9k: Reset TX queue: %d\n", q);
+
+	if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
+		if (chan && IS_CHAN_B(chan))
+			chanCwMin = INIT_CWMIN_11B;
+		else
+			chanCwMin = INIT_CWMIN;
+
+		for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
+	} else
+		cwMin = qi->tqi_cwmin;
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	REG_WRITE(ah, AR_DLCL_IFS(q),
+		  SM(cwMin, AR_D_LCL_IFS_CWMIN) |
+		  SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
+		  SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
+
+	REG_WRITE(ah, AR_DRETRY_LIMIT(q),
+		  SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) |
+		  SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) |
+		  SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
+
+	REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
+
+	if (AR_SREV_9340(ah))
+		REG_WRITE(ah, AR_DMISC(q),
+			  AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x1);
+	else
+		REG_WRITE(ah, AR_DMISC(q),
+			  AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
+
+	if (qi->tqi_cbrPeriod) {
+		REG_WRITE(ah, AR_QCBRCFG(q),
+			  SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
+			  SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
+		REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_FSP_CBR |
+			    (qi->tqi_cbrOverflowLimit ?
+			     AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
+	}
+	if (qi->tqi_readyTime) {
+		REG_WRITE(ah, AR_QRDYTIMECFG(q),
+			  SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
+			  AR_Q_RDYTIMECFG_EN);
+	}
+
+	REG_WRITE(ah, AR_DCHNTIME(q),
+		  SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
+		  (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
+
+	if (qi->tqi_burstTime
+	    && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE))
+		REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_RDYTIME_EXP_POLICY);
+
+	if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE)
+		REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS);
+
+	REGWRITE_BUFFER_FLUSH(ah);
+
+	if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
+		REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_FRAG_BKOFF_EN);
+
+	if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
+		REG_SET_BIT(ah, AR_DMISC(q),
+			    SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
+			       AR_D_MISC_ARB_LOCKOUT_CNTRL) |
+			    AR_D_MISC_POST_FR_BKOFF_DIS);
+	}
+
+	if (AR_SREV_9300_20_OR_LATER(ah))
+		REG_WRITE(ah, AR_Q_DESC_CRCCHK, AR_Q_DESC_CRCCHK_EN);
+
+	if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
+		ah->txok_interrupt_mask |= 1 << q;
+	else
+		ah->txok_interrupt_mask &= ~(1 << q);
+	if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
+		ah->txerr_interrupt_mask |= 1 << q;
+	else
+		ah->txerr_interrupt_mask &= ~(1 << q);
+	if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
+		ah->txdesc_interrupt_mask |= 1 << q;
+	else
+		ah->txdesc_interrupt_mask &= ~(1 << q);
+	if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
+		ah->txeol_interrupt_mask |= 1 << q;
+	else
+		ah->txeol_interrupt_mask &= ~(1 << q);
+	if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
+		ah->txurn_interrupt_mask |= 1 << q;
+	else
+		ah->txurn_interrupt_mask &= ~(1 << q);
+	ath9k_hw_set_txq_interrupts(ah, qi);
+
+	return 1;
+}
+
+int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
+			struct ath_rx_status *rs, u64 tsf __unused)
+{
+	struct ar5416_desc ads;
+	struct ar5416_desc *adsp = AR5416DESC(ds);
+	u32 phyerr;
+
+	if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
+		return -EINPROGRESS;
+
+	ads.u.rx = adsp->u.rx;
+
+	rs->rs_status = 0;
+	rs->rs_flags = 0;
+
+	rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
+	rs->rs_tstamp = ads.AR_RcvTimestamp;
+
+	if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
+		rs->rs_rssi = ATH9K_RSSI_BAD;
+		rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD;
+		rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD;
+		rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD;
+		rs->rs_rssi_ext0 = ATH9K_RSSI_BAD;
+		rs->rs_rssi_ext1 = ATH9K_RSSI_BAD;
+		rs->rs_rssi_ext2 = ATH9K_RSSI_BAD;
+	} else {
+		rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
+		rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
+						AR_RxRSSIAnt00);
+		rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
+						AR_RxRSSIAnt01);
+		rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
+						AR_RxRSSIAnt02);
+		rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4,
+						AR_RxRSSIAnt10);
+		rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4,
+						AR_RxRSSIAnt11);
+		rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4,
+						AR_RxRSSIAnt12);
+	}
+	if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
+		rs->rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
+	else
+		rs->rs_keyix = ATH9K_RXKEYIX_INVALID;
+
+	rs->rs_rate = RXSTATUS_RATE(ah, (&ads));
+	rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
+
+	rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
+	rs->rs_moreaggr =
+		(ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
+	rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
+	rs->rs_flags =
+		(ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
+	rs->rs_flags |=
+		(ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
+
+	if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
+		rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
+	if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
+		rs->rs_flags |= ATH9K_RX_DELIM_CRC_POST;
+	if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
+		rs->rs_flags |= ATH9K_RX_DECRYPT_BUSY;
+
+	if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
+		/*
+		 * Treat these errors as mutually exclusive to avoid spurious
+		 * extra error reports from the hardware. If a CRC error is
+		 * reported, then decryption and MIC errors are irrelevant,
+		 * the frame is going to be dropped either way
+		 */
+		if (ads.ds_rxstatus8 & AR_CRCErr)
+			rs->rs_status |= ATH9K_RXERR_CRC;
+		else if (ads.ds_rxstatus8 & AR_PHYErr) {
+			rs->rs_status |= ATH9K_RXERR_PHY;
+			phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
+			rs->rs_phyerr = phyerr;
+		} else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
+			rs->rs_status |= ATH9K_RXERR_DECRYPT;
+		else if (ads.ds_rxstatus8 & AR_MichaelErr)
+			rs->rs_status |= ATH9K_RXERR_MIC;
+		else if (ads.ds_rxstatus8 & AR_KeyMiss)
+			rs->rs_status |= ATH9K_RXERR_DECRYPT;
+	}
+
+	return 0;
+}
+
+/*
+ * This can stop or re-enables RX.
+ *
+ * If bool is set this will kill any frame which is currently being
+ * transferred between the MAC and baseband and also prevent any new
+ * frames from getting started.
+ */
+int ath9k_hw_setrxabort(struct ath_hw *ah, int set)
+{
+	u32 reg;
+
+	if (set) {
+		REG_SET_BIT(ah, AR_DIAG_SW,
+			    (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+
+		if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE,
+				   0, AH_WAIT_TIMEOUT)) {
+			REG_CLR_BIT(ah, AR_DIAG_SW,
+				    (AR_DIAG_RX_DIS |
+				     AR_DIAG_RX_ABORT));
+
+			reg = REG_READ(ah, AR_OBS_BUS_1);
+			DBG("ath9k: "
+				"RX failed to go idle in 10 ms RXSM=0x%x\n",
+				reg);
+
+			return 0;
+		}
+	} else {
+		REG_CLR_BIT(ah, AR_DIAG_SW,
+			    (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+	}
+
+	return 1;
+}
+
+void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp)
+{
+	REG_WRITE(ah, AR_RXDP, rxdp);
+}
+
+void ath9k_hw_startpcureceive(struct ath_hw *ah, int is_scanning)
+{
+	ath9k_ani_reset(ah, is_scanning);
+
+	REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+}
+
+void ath9k_hw_abortpcurecv(struct ath_hw *ah)
+{
+	REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_ABORT | AR_DIAG_RX_DIS);
+}
+
+int ath9k_hw_stopdmarecv(struct ath_hw *ah, int *reset)
+{
+#define AH_RX_STOP_DMA_TIMEOUT 10000   /* usec */
+	u32 mac_status, last_mac_status = 0;
+	int i;
+
+	/* Enable access to the DMA observation bus */
+	REG_WRITE(ah, AR_MACMISC,
+		  ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
+		   (AR_MACMISC_MISC_OBS_BUS_1 <<
+		    AR_MACMISC_MISC_OBS_BUS_MSB_S)));
+
+	REG_WRITE(ah, AR_CR, AR_CR_RXD);
+
+	/* Wait for rx enable bit to go low */
+	for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) {
+		if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0)
+			break;
+
+		if (!AR_SREV_9300_20_OR_LATER(ah)) {
+			mac_status = REG_READ(ah, AR_DMADBG_7) & 0x7f0;
+			if (mac_status == 0x1c0 && mac_status == last_mac_status) {
+				*reset = 1;
+				break;
+			}
+
+			last_mac_status = mac_status;
+		}
+
+		udelay(AH_TIME_QUANTUM);
+	}
+
+	if (i == 0) {
+		DBG("ath9k: "
+			"DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n",
+			AH_RX_STOP_DMA_TIMEOUT / 1000,
+			REG_READ(ah, AR_CR),
+			REG_READ(ah, AR_DIAG_SW),
+			REG_READ(ah, AR_DMADBG_7));
+		return 0;
+	} else {
+		return 1;
+	}
+
+#undef AH_RX_STOP_DMA_TIMEOUT
+}
+
+int ath9k_hw_intrpend(struct ath_hw *ah)
+{
+	u32 host_isr;
+
+	if (AR_SREV_9100(ah) || !(ah->ah_ier & AR_IER_ENABLE))
+		return 1;
+
+	host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
+	if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS))
+		return 1;
+
+	host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE);
+	if ((host_isr & AR_INTR_SYNC_DEFAULT)
+	    && (host_isr != AR_INTR_SPURIOUS))
+		return 1;
+
+	return 0;
+}
+
+void ath9k_hw_disable_interrupts(struct ath_hw *ah)
+{
+	DBG2("ath9k: disable IER\n");
+	REG_WRITE(ah, AR_IER, ah->ah_ier);
+	(void) REG_READ(ah, AR_IER);
+	if (!AR_SREV_9100(ah)) {
+		REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0);
+		(void) REG_READ(ah, AR_INTR_ASYNC_ENABLE);
+
+		REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
+		(void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
+	}
+}
+
+void ath9k_hw_enable_interrupts(struct ath_hw *ah)
+{
+	u32 sync_default = AR_INTR_SYNC_DEFAULT;
+
+	if (!(ah->imask & ATH9K_INT_GLOBAL))
+		return;
+
+	if (AR_SREV_9340(ah))
+		sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
+
+	DBG2("ath9k: enable IER\n");
+	REG_WRITE(ah, AR_IER, ah->ah_ier);
+	if (!AR_SREV_9100(ah)) {
+		REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
+			  AR_INTR_MAC_IRQ);
+		REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
+
+
+		REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default);
+		REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default);
+	}
+	DBG2("ath9k: AR_IMR 0x%x IER 0x%x\n",
+		REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
+}
+
+void ath9k_hw_set_interrupts(struct ath_hw *ah, unsigned int ints)
+{
+	enum ath9k_int omask = ah->imask;
+	u32 mask, mask2;
+	struct ath9k_hw_capabilities *pCap = &ah->caps;
+
+	if (!(ints & ATH9K_INT_GLOBAL))
+		ath9k_hw_disable_interrupts(ah);
+
+	DBG2("ath9k: 0x%x => 0x%x\n", omask, ints);
+
+	/* TODO: global int Ref count */
+	mask = ints & ATH9K_INT_COMMON;
+	mask2 = 0;
+
+	if (ints & ATH9K_INT_TX) {
+		if (ah->config.tx_intr_mitigation)
+			mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM;
+		else {
+			if (ah->txok_interrupt_mask)
+				mask |= AR_IMR_TXOK;
+			if (ah->txdesc_interrupt_mask)
+				mask |= AR_IMR_TXDESC;
+		}
+		if (ah->txerr_interrupt_mask)
+			mask |= AR_IMR_TXERR;
+		if (ah->txeol_interrupt_mask)
+			mask |= AR_IMR_TXEOL;
+	}
+	if (ints & ATH9K_INT_RX) {
+		if (AR_SREV_9300_20_OR_LATER(ah)) {
+			mask |= AR_IMR_RXERR | AR_IMR_RXOK_HP;
+			if (ah->config.rx_intr_mitigation) {
+				mask &= ~AR_IMR_RXOK_LP;
+				mask |=  AR_IMR_RXMINTR | AR_IMR_RXINTM;
+			} else {
+				mask |= AR_IMR_RXOK_LP;
+			}
+		} else {
+			if (ah->config.rx_intr_mitigation)
+				mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
+			else
+				mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
+		}
+		if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+			mask |= AR_IMR_GENTMR;
+	}
+
+	if (ints & ATH9K_INT_GENTIMER)
+		mask |= AR_IMR_GENTMR;
+
+	if (ints & (ATH9K_INT_BMISC)) {
+		mask |= AR_IMR_BCNMISC;
+		if (ints & ATH9K_INT_TIM)
+			mask2 |= AR_IMR_S2_TIM;
+		if (ints & ATH9K_INT_DTIM)
+			mask2 |= AR_IMR_S2_DTIM;
+		if (ints & ATH9K_INT_DTIMSYNC)
+			mask2 |= AR_IMR_S2_DTIMSYNC;
+		if (ints & ATH9K_INT_CABEND)
+			mask2 |= AR_IMR_S2_CABEND;
+		if (ints & ATH9K_INT_TSFOOR)
+			mask2 |= AR_IMR_S2_TSFOOR;
+	}
+
+	if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) {
+		mask |= AR_IMR_BCNMISC;
+		if (ints & ATH9K_INT_GTT)
+			mask2 |= AR_IMR_S2_GTT;
+		if (ints & ATH9K_INT_CST)
+			mask2 |= AR_IMR_S2_CST;
+	}
+
+	DBG2("ath9k: new IMR 0x%x\n", mask);
+	REG_WRITE(ah, AR_IMR, mask);
+	ah->imrs2_reg &= ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC |
+			   AR_IMR_S2_CABEND | AR_IMR_S2_CABTO |
+			   AR_IMR_S2_TSFOOR | AR_IMR_S2_GTT | AR_IMR_S2_CST);
+	ah->imrs2_reg |= mask2;
+	REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
+
+	if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+		if (ints & ATH9K_INT_TIM_TIMER)
+			REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
+		else
+			REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
+	}
+
+	if (ints & ATH9K_INT_GLOBAL)
+		ath9k_hw_enable_interrupts(ah);
+
+	return;
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_main.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_main.c
new file mode 100644
index 0000000000000000000000000000000000000000..0a17b9bcb872c044eb92199af6379fe704f38661
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_main.c
@@ -0,0 +1,916 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/io.h>
+
+#include "ath9k.h"
+
+static void ath9k_bss_info_changed(struct net80211_device *dev, u32 changed);
+
+int ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
+{
+	int ret;
+
+	ret = ath9k_hw_setpower(sc->sc_ah, mode);
+
+	return ret;
+}
+
+static void ath_start_ani(struct ath_common *common)
+{
+	struct ath_hw *ah = common->ah;
+	unsigned long timestamp = ( currticks() * 1000 ) / TICKS_PER_SEC;
+	struct ath_softc *sc = (struct ath_softc *) common->priv;
+
+	if (!(sc->sc_flags & SC_OP_ANI_RUN))
+		return;
+
+	if (sc->sc_flags & SC_OP_OFFCHANNEL)
+		return;
+
+	common->ani.longcal_timer = timestamp;
+	common->ani.shortcal_timer = timestamp;
+	common->ani.checkani_timer = timestamp;
+
+	common->ani.timer = timestamp + ah->config.ani_poll_interval;
+}
+
+static void ath_update_survey_nf(struct ath_softc *sc, int channel)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath9k_channel *chan = &ah->channels[channel];
+	struct survey_info *survey = &sc->survey[channel];
+
+	if (chan->noisefloor) {
+		survey->filled |= SURVEY_INFO_NOISE_DBM;
+		survey->noise = chan->noisefloor;
+	}
+}
+
+/*
+ * Updates the survey statistics and returns the busy time since last
+ * update in %, if the measurement duration was long enough for the
+ * result to be useful, -1 otherwise.
+ */
+static int ath_update_survey_stats(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	int pos = ah->curchan - &ah->channels[0];
+	struct survey_info *survey = &sc->survey[pos];
+	struct ath_cycle_counters *cc = &common->cc_survey;
+	unsigned int div = common->clockrate * 1000;
+	int ret = 0;
+
+	if (!ah->curchan)
+		return -1;
+
+	if (ah->power_mode == ATH9K_PM_AWAKE)
+		ath_hw_cycle_counters_update(common);
+
+	if (cc->cycles > 0) {
+		survey->filled |= SURVEY_INFO_CHANNEL_TIME |
+			SURVEY_INFO_CHANNEL_TIME_BUSY |
+			SURVEY_INFO_CHANNEL_TIME_RX |
+			SURVEY_INFO_CHANNEL_TIME_TX;
+		survey->channel_time += cc->cycles / div;
+		survey->channel_time_busy += cc->rx_busy / div;
+		survey->channel_time_rx += cc->rx_frame / div;
+		survey->channel_time_tx += cc->tx_frame / div;
+	}
+
+	if (cc->cycles < div)
+		return -1;
+
+	if (cc->cycles > 0)
+		ret = cc->rx_busy * 100 / cc->cycles;
+
+	memset(cc, 0, sizeof(*cc));
+
+	ath_update_survey_nf(sc, pos);
+
+	return ret;
+}
+
+/*
+ * Set/change channels.  If the channel is really being changed, it's done
+ * by reseting the chip.  To accomplish this we must first cleanup any pending
+ * DMA, then restart stuff.
+*/
+int ath_set_channel(struct ath_softc *sc, struct net80211_device *dev,
+		    struct ath9k_channel *hchan)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	int fastcc __unused = 1, stopped __unused;
+	struct net80211_channel *channel = dev->channels + dev->channel;
+	struct ath9k_hw_cal_data *caldata = NULL;
+	int r;
+
+	if (sc->sc_flags & SC_OP_INVALID)
+		return -EIO;
+
+	sc->hw_busy_count = 0;
+
+	common->ani.timer = 0;
+	sc->tx_complete_work_timer = 0;
+	sc->hw_pll_work_timer = 0;
+
+	/*
+	 * This is only performed if the channel settings have
+	 * actually changed.
+	 *
+	 * To switch channels clear any pending DMA operations;
+	 * wait long enough for the RX fifo to drain, reset the
+	 * hardware at the new frequency, and then re-enable
+	 * the relevant bits of the h/w.
+	 */
+	ath9k_hw_disable_interrupts(ah);
+	stopped = ath_drain_all_txq(sc, 0);
+
+	if (!ath_stoprecv(sc))
+		stopped = 0;
+
+	if (!ath9k_hw_check_alive(ah))
+		stopped = 0;
+
+	/* XXX: do not flush receive queue here. We don't want
+	 * to flush data frames already in queue because of
+	 * changing channel. */
+
+	if (!(sc->sc_flags & SC_OP_OFFCHANNEL))
+		caldata = &sc->caldata;
+
+	DBG2("ath9k: "
+		"(%d MHz) -> (%d MHz)\n",
+		sc->sc_ah->curchan->channel,
+		channel->center_freq);
+
+	r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
+	if (r) {
+		DBG("ath9k: "
+			"Unable to reset channel (%d MHz), reset status %d\n",
+			channel->center_freq, r);
+		goto ps_restore;
+	}
+
+	if (ath_startrecv(sc) != 0) {
+		DBG("ath9k: Unable to restart recv logic\n");
+		r = -EIO;
+		goto ps_restore;
+	}
+
+	ath9k_cmn_update_txpow(ah, sc->curtxpow,
+			       sc->config.txpowlimit, &sc->curtxpow);
+	ath9k_hw_set_interrupts(ah, ah->imask);
+
+	if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
+		sc->tx_complete_work(sc);
+		sc->hw_pll_work_timer = (currticks() * 1000 ) / TICKS_PER_SEC + 500;
+		ath_start_ani(common);
+	}
+
+ ps_restore:
+	return r;
+}
+
+/*
+ *  This routine performs the periodic noise floor calibration function
+ *  that is used to adjust and optimize the chip performance.  This
+ *  takes environmental changes (location, temperature) into account.
+ *  When the task is complete, it reschedules itself depending on the
+ *  appropriate interval that was calculated.
+ */
+void ath_ani_calibrate(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	int longcal = 0;
+	int shortcal = 0;
+	int aniflag = 0;
+	unsigned int timestamp = (currticks() * 1000 ) / TICKS_PER_SEC;
+	u32 cal_interval, short_cal_interval, long_cal_interval;
+
+	if (ah->caldata && ah->caldata->nfcal_interference)
+		long_cal_interval = ATH_LONG_CALINTERVAL_INT;
+	else
+		long_cal_interval = ATH_LONG_CALINTERVAL;
+
+	short_cal_interval = ATH_STA_SHORT_CALINTERVAL;
+
+	/* Only calibrate if awake */
+	if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE)
+		goto set_timer;
+
+	/* Long calibration runs independently of short calibration. */
+	if ((timestamp - common->ani.longcal_timer) >= long_cal_interval) {
+		longcal = 1;
+		DBG2("ath9k: longcal @%d\n", timestamp);
+		common->ani.longcal_timer = timestamp;
+	}
+
+	/* Short calibration applies only while caldone is false */
+	if (!common->ani.caldone) {
+		if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) {
+			shortcal = 1;
+			DBG2("ath9k: "
+				"shortcal @%d\n", timestamp);
+			common->ani.shortcal_timer = timestamp;
+			common->ani.resetcal_timer = timestamp;
+		}
+	} else {
+		if ((timestamp - common->ani.resetcal_timer) >=
+		    ATH_RESTART_CALINTERVAL) {
+			common->ani.caldone = ath9k_hw_reset_calvalid(ah);
+			if (common->ani.caldone)
+				common->ani.resetcal_timer = timestamp;
+		}
+	}
+
+	/* Verify whether we must check ANI */
+	if ((timestamp - common->ani.checkani_timer) >=
+	     ah->config.ani_poll_interval) {
+		aniflag = 1;
+		common->ani.checkani_timer = timestamp;
+	}
+
+	/* Skip all processing if there's nothing to do. */
+	if (longcal || shortcal || aniflag) {
+		/* Call ANI routine if necessary */
+		if (aniflag) {
+			ath9k_hw_ani_monitor(ah, ah->curchan);
+			ath_update_survey_stats(sc);
+		}
+
+		/* Perform calibration if necessary */
+		if (longcal || shortcal) {
+			common->ani.caldone =
+				ath9k_hw_calibrate(ah,
+						   ah->curchan,
+						   common->rx_chainmask,
+						   longcal);
+		}
+	}
+
+set_timer:
+	/*
+	* Set timer interval based on previous results.
+	* The interval must be the shortest necessary to satisfy ANI,
+	* short calibration and long calibration.
+	*/
+	cal_interval = ATH_LONG_CALINTERVAL;
+	if (sc->sc_ah->config.enable_ani)
+		cal_interval = min(cal_interval,
+				   (u32)ah->config.ani_poll_interval);
+	if (!common->ani.caldone)
+		cal_interval = min(cal_interval, (u32)short_cal_interval);
+
+	common->ani.timer = timestamp + cal_interval;
+}
+
+void ath_hw_check(struct ath_softc *sc)
+{
+	int busy;
+
+	if (ath9k_hw_check_alive(sc->sc_ah))
+		goto out;
+
+	busy = ath_update_survey_stats(sc);
+
+	DBG("ath9k: Possible baseband hang, "
+		"busy=%d (try %d)\n", busy, sc->hw_busy_count + 1);
+	if (busy >= 99) {
+		if (++sc->hw_busy_count >= 3)
+			ath_reset(sc, 1);
+	} else if (busy >= 0)
+		sc->hw_busy_count = 0;
+
+out:
+	return;
+}
+
+static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
+{
+	static int count;
+
+	if (pll_sqsum >= 0x40000) {
+		count++;
+		if (count == 3) {
+			/* Rx is hung for more than 500ms. Reset it */
+			DBG("ath9k: "
+				"Possible RX hang, resetting");
+			ath_reset(sc, 1);
+			count = 0;
+		}
+	} else
+		count = 0;
+}
+
+void ath_hw_pll_work(struct ath_softc *sc)
+{
+	u32 pll_sqsum;
+
+	if (AR_SREV_9485(sc->sc_ah)) {
+		pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
+
+		ath_hw_pll_rx_hang_check(sc, pll_sqsum);
+
+		sc->hw_pll_work_timer = (currticks() * 1000 ) / TICKS_PER_SEC + 200;
+	}
+}
+
+
+void ath9k_tasklet(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+
+	u32 status = sc->intrstatus;
+	u32 rxmask;
+
+	if ((status & ATH9K_INT_FATAL) ||
+	    (status & ATH9K_INT_BB_WATCHDOG)) {
+		ath_reset(sc, 1);
+		return;
+	}
+
+	rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
+
+	if (status & rxmask) {
+		ath_rx_tasklet(sc, 0, 0);
+	}
+
+	if (status & ATH9K_INT_TX) {
+		ath_tx_tasklet(sc);
+	}
+
+	/* re-enable hardware interrupt */
+	ath9k_hw_enable_interrupts(ah);
+}
+
+void ath_isr(struct net80211_device *dev)
+{
+#define SCHED_INTR (				\
+		ATH9K_INT_FATAL |		\
+		ATH9K_INT_BB_WATCHDOG |		\
+		ATH9K_INT_RXORN |		\
+		ATH9K_INT_RXEOL |		\
+		ATH9K_INT_RX |			\
+		ATH9K_INT_RXLP |		\
+		ATH9K_INT_RXHP |		\
+		ATH9K_INT_TX |			\
+		ATH9K_INT_BMISS |		\
+		ATH9K_INT_CST |			\
+		ATH9K_INT_TSFOOR |		\
+		ATH9K_INT_GENTIMER)
+
+	struct ath_softc *sc = dev->priv;
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	enum ath9k_int status;
+	unsigned long timestamp = (currticks() * 1000 ) / TICKS_PER_SEC;
+	int sched = 0;
+
+	/*
+	 * The hardware is not ready/present, don't
+	 * touch anything. Note this can happen early
+	 * on if the IRQ is shared.
+	 */
+	if (sc->sc_flags & SC_OP_INVALID)
+		return;
+
+
+	/* Check calibration */
+	if(timestamp >= (unsigned int)common->ani.timer && common->ani.timer)
+		ath_ani_calibrate(sc);
+
+	/* Check tx_complete_work */
+	if(timestamp >= (unsigned int)sc->tx_complete_work_timer && sc->tx_complete_work_timer)
+		sc->tx_complete_work(sc);
+
+	/* Check hw_pll_work */
+	if(timestamp >= (unsigned int)sc->hw_pll_work_timer && sc->hw_pll_work_timer)
+		sc->hw_pll_work(sc);
+
+	/* shared irq, not for us */
+
+	if (!ath9k_hw_intrpend(ah))
+		return;
+
+	/*
+	 * Figure out the reason(s) for the interrupt.  Note
+	 * that the hal returns a pseudo-ISR that may include
+	 * bits we haven't explicitly enabled so we mask the
+	 * value to insure we only process bits we requested.
+	 */
+	ath9k_hw_getisr(ah, &status);	/* NB: clears ISR too */
+	status &= ah->imask;	/* discard unasked-for bits */
+
+	/*
+	 * If there are no status bits set, then this interrupt was not
+	 * for me (should have been caught above).
+	 */
+	if (!status)
+		return;
+
+	/* Cache the status */
+	sc->intrstatus = status;
+
+	if (status & SCHED_INTR)
+		sched = 1;
+
+	/*
+	 * If a FATAL or RXORN interrupt is received, we have to reset the
+	 * chip immediately.
+	 */
+	if ((status & ATH9K_INT_FATAL) || (status & ATH9K_INT_RXORN))
+		goto chip_reset;
+
+	if (status & ATH9K_INT_TXURN)
+		ath9k_hw_updatetxtriglevel(ah, 1);
+
+	if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+		if (status & ATH9K_INT_TIM_TIMER) {
+			if (sc->ps_idle)
+				goto chip_reset;
+			/* Clear RxAbort bit so that we can
+			 * receive frames */
+			ath9k_setpower(sc, ATH9K_PM_AWAKE);
+			ath9k_hw_setrxabort(sc->sc_ah, 0);
+			sc->ps_flags |= PS_WAIT_FOR_BEACON;
+		}
+
+chip_reset:
+
+	if (sched) {
+		/* turn off every interrupt */
+		ath9k_hw_disable_interrupts(ah);
+		sc->intr_tq(sc);
+	}
+
+	return;
+
+#undef SCHED_INTR
+}
+
+void ath_radio_disable(struct ath_softc *sc, struct net80211_device *dev)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct net80211_channel *channel = dev->channels + dev->channel;
+	int r;
+
+	sc->hw_pll_work_timer = 0;
+
+	/*
+	 * Keep the LED on when the radio is disabled
+	 * during idle unassociated state.
+	 */
+	if (!sc->ps_idle) {
+		ath9k_hw_set_gpio(ah, ah->led_pin, 1);
+		ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
+	}
+
+	/* Disable interrupts */
+	ath9k_hw_disable_interrupts(ah);
+
+	ath_drain_all_txq(sc, 0);	/* clear pending tx frames */
+
+	ath_stoprecv(sc);		/* turn off frame recv */
+	ath_flushrecv(sc);		/* flush recv queue */
+
+	if (!ah->curchan)
+		ah->curchan = ath9k_cmn_get_curchannel(dev, ah);
+
+	r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, 0);
+	if (r) {
+		DBG("ath9k: "
+			"Unable to reset channel (%d MHz), reset status %d\n",
+			channel->center_freq, r);
+	}
+
+	ath9k_hw_phy_disable(ah);
+
+	ath9k_hw_configpcipowersave(ah, 1, 1);
+}
+
+int ath_reset(struct ath_softc *sc, int retry_tx)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	int r;
+
+	sc->hw_busy_count = 0;
+
+	/* Stop ANI */
+	common->ani.timer = 0;
+
+	ath9k_hw_disable_interrupts(ah);
+	ath_drain_all_txq(sc, retry_tx);
+
+	ath_stoprecv(sc);
+	ath_flushrecv(sc);
+
+	r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, 0);
+	if (r)
+		DBG("ath9k: "
+			"Unable to reset hardware; reset status %d\n", r);
+
+	if (ath_startrecv(sc) != 0)
+		DBG("ath9k: Unable to start recv logic\n");
+
+	/*
+	 * We may be doing a reset in response to a request
+	 * that changes the channel so update any state that
+	 * might change as a result.
+	 */
+	ath9k_cmn_update_txpow(ah, sc->curtxpow,
+			       sc->config.txpowlimit, &sc->curtxpow);
+
+	ath9k_hw_set_interrupts(ah, ah->imask);
+
+	if (retry_tx) {
+		int i;
+		for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+			if (ATH_TXQ_SETUP(sc, i)) {
+				ath_txq_schedule(sc, &sc->tx.txq[i]);
+			}
+		}
+	}
+
+	/* Start ANI */
+	ath_start_ani(common);
+
+	return r;
+}
+
+/**********************/
+/* mac80211 callbacks */
+/**********************/
+
+static int ath9k_start(struct net80211_device *dev)
+{
+	struct ath_softc *sc = dev->priv;
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct net80211_channel *curchan = dev->channels + dev->channel;
+	struct ath9k_channel *init_channel;
+	int r;
+
+	DBG("ath9k: "
+		"Starting driver with initial channel: %d MHz\n",
+		curchan->center_freq);
+
+	/* setup initial channel */
+	sc->chan_idx = curchan->hw_value;
+
+	init_channel = ath9k_cmn_get_curchannel(dev, ah);
+
+	/* Reset SERDES registers */
+	ath9k_hw_configpcipowersave(ah, 0, 0);
+
+	/*
+	 * The basic interface to setting the hardware in a good
+	 * state is ``reset''.  On return the hardware is known to
+	 * be powered up and with interrupts disabled.  This must
+	 * be followed by initialization of the appropriate bits
+	 * and then setup of the interrupt mask.
+	 */
+	r = ath9k_hw_reset(ah, init_channel, ah->caldata, 0);
+	if (r) {
+		DBG("ath9k: "
+			"Unable to reset hardware; reset status %d (freq %d MHz)\n",
+			r, curchan->center_freq);
+		goto mutex_unlock;
+	}
+
+	/*
+	 * This is needed only to setup initial state
+	 * but it's best done after a reset.
+	 */
+	ath9k_cmn_update_txpow(ah, sc->curtxpow,
+			sc->config.txpowlimit, &sc->curtxpow);
+
+	/*
+	 * Setup the hardware after reset:
+	 * The receive engine is set going.
+	 * Frame transmit is handled entirely
+	 * in the frame output path; there's nothing to do
+	 * here except setup the interrupt mask.
+	 */
+	if (ath_startrecv(sc) != 0) {
+		DBG("ath9k: Unable to start recv logic\n");
+		r = -EIO;
+		goto mutex_unlock;
+	}
+
+	/* Setup our intr mask. */
+	ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL |
+		    ATH9K_INT_RXORN | ATH9K_INT_FATAL |
+		    ATH9K_INT_GLOBAL;
+
+	ah->imask |= ATH9K_INT_RX;
+
+	sc->sc_flags &= ~SC_OP_INVALID;
+	sc->sc_ah->is_monitoring = 0;
+
+	ath9k_hw_set_interrupts(ah, ah->imask);
+
+	sc->tx_complete_work(sc);
+
+	if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en)
+		common->bus_ops->extn_synch_en(common);
+
+mutex_unlock:
+	return r;
+}
+
+static int ath9k_tx(struct net80211_device *dev, struct io_buffer *iob)
+{
+	struct ath_softc *sc = dev->priv;
+	struct ath_tx_control txctl;
+	int ret = 0;
+
+	memset(&txctl, 0, sizeof(struct ath_tx_control));
+	txctl.txq = sc->tx.txq_map[0];
+
+	DBGIO("ath9k: transmitting packet, iob: %p\n", iob);
+
+	ret = ath_tx_start(dev, iob, &txctl);
+	if (ret) {
+		DBG("ath9k: TX failed\n");
+		goto exit;
+	}
+
+	return ret;
+exit:
+	free_iob(iob);
+	return ret;
+}
+
+static void ath9k_stop(struct net80211_device *dev)
+{
+	struct ath_softc *sc = dev->priv;
+	struct ath_hw *ah = sc->sc_ah;
+
+	sc->tx_complete_work_timer = 0;
+	sc->hw_pll_work_timer = 0;
+
+	if (sc->sc_flags & SC_OP_INVALID) {
+		DBG("ath9k: Device not present\n");
+		return;
+	}
+
+	/* prevent tasklets to enable interrupts once we disable them */
+	ah->imask &= ~ATH9K_INT_GLOBAL;
+
+	/* make sure h/w will not generate any interrupt
+	 * before setting the invalid flag. */
+	ath9k_hw_disable_interrupts(ah);
+
+	if (!(sc->sc_flags & SC_OP_INVALID)) {
+		ath_drain_all_txq(sc, 0);
+		ath_stoprecv(sc);
+		ath9k_hw_phy_disable(ah);
+	} else
+		sc->rx.rxlink = NULL;
+
+	if (sc->rx.frag) {
+		free_iob(sc->rx.frag);
+		sc->rx.frag = NULL;
+	}
+
+	/* disable HAL and put h/w to sleep */
+	ath9k_hw_disable(ah);
+	ath9k_hw_configpcipowersave(ah, 1, 1);
+
+	ath_radio_disable(sc, dev);
+
+	sc->sc_flags |= SC_OP_INVALID;
+
+	DBG("ath9k: Driver halt\n");
+}
+
+static int ath9k_config(struct net80211_device *dev, int changed)
+{
+	struct ath_softc *sc = dev->priv;
+	struct ath_hw *ah = sc->sc_ah;
+
+	if ((changed & NET80211_CFG_RATE) ||
+			(changed & NET80211_CFG_PHY_PARAMS)) {
+		int spmbl = (sc->sc_flags & SC_OP_PREAMBLE_SHORT) ? IEEE80211_TX_RC_USE_SHORT_PREAMBLE : 0;
+		u16 rate = dev->rates[dev->rate];
+		u16 slowrate = dev->rates[dev->rtscts_rate];
+		int i;
+
+		for (i = 0; i < NET80211_MAX_RATES; i++) {
+			if (sc->rates[i].bitrate == rate &&
+			    (sc->rates[i].flags & spmbl))
+				sc->hw_rix = i;
+
+			if (sc->rates[i].bitrate == slowrate &&
+			    (sc->rates[i].flags & spmbl))
+				sc->hw_rix = i;
+		}
+	}
+
+	ath9k_bss_info_changed(dev, changed);
+
+	if (changed & NET80211_CFG_CHANNEL) {
+		struct net80211_channel *curchan = dev->channels + dev->channel;
+		int pos = curchan->hw_value;
+		int old_pos = -1;
+
+		if (ah->curchan)
+			old_pos = ah->curchan - &ah->channels[0];
+
+		sc->sc_flags &= ~SC_OP_OFFCHANNEL;
+
+		DBG2("ath9k: "
+			"Set channel: %d MHz\n",
+			curchan->center_freq);
+
+		ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
+					  curchan);
+
+		/* update survey stats for the old channel before switching */
+		ath_update_survey_stats(sc);
+
+		/*
+		 * If the operating channel changes, change the survey in-use flags
+		 * along with it.
+		 * Reset the survey data for the new channel, unless we're switching
+		 * back to the operating channel from an off-channel operation.
+		 */
+		if (sc->cur_survey != &sc->survey[pos]) {
+
+			if (sc->cur_survey)
+				sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE;
+
+			sc->cur_survey = &sc->survey[pos];
+
+			memset(sc->cur_survey, 0, sizeof(struct survey_info));
+			sc->cur_survey->filled |= SURVEY_INFO_IN_USE;
+		} else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) {
+			memset(&sc->survey[pos], 0, sizeof(struct survey_info));
+		}
+
+		if (ath_set_channel(sc, dev, &sc->sc_ah->channels[pos]) < 0) {
+			DBG("ath9k: Unable to set channel\n");
+			return -EINVAL;
+		}
+
+		/*
+		 * The most recent snapshot of channel->noisefloor for the old
+		 * channel is only available after the hardware reset. Copy it to
+		 * the survey stats now.
+		 */
+		if (old_pos >= 0)
+			ath_update_survey_nf(sc, old_pos);
+	}
+
+	if (changed & NET80211_CFG_CHANNEL) {
+		DBG2("ath9k: "
+			"Set power: %d\n", (dev->channels + dev->channel)->maxpower);
+		sc->config.txpowlimit = 2 * (dev->channels + dev->channel)->maxpower;
+		ath9k_cmn_update_txpow(ah, sc->curtxpow,
+				       sc->config.txpowlimit, &sc->curtxpow);
+	}
+
+	return 0;
+}
+
+static void ath9k_bss_iter(struct ath_softc *sc)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+	if (common->dev->state & NET80211_ASSOCIATED) {
+		sc->sc_flags |= SC_OP_PRIM_STA_VIF;
+		memcpy(common->curbssid, common->dev->bssid, ETH_ALEN);
+		common->curaid = common->dev->aid;
+		ath9k_hw_write_associd(sc->sc_ah);
+		DBG("ath9k: "
+			"Bss Info ASSOC %d, bssid: %pM\n",
+			common->dev->aid, common->curbssid);
+
+		/*
+		 * Request a re-configuration of Beacon related timers
+		 * on the receipt of the first Beacon frame (i.e.,
+		 * after time sync with the AP).
+		 */
+		sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+		/* Reset rssi stats */
+		sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
+		sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
+
+		sc->sc_flags |= SC_OP_ANI_RUN;
+		ath_start_ani(common);
+	}
+}
+
+static void ath9k_config_bss(struct ath_softc *sc)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct net80211_device *dev = common->dev;
+
+	/* Reconfigure bss info */
+	if (!(dev->state & NET80211_ASSOCIATED)) {
+		DBG2("ath9k: "
+			"ath9k: Bss Info DISASSOC %d, bssid %pM\n",
+			common->curaid, common->curbssid);
+		sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS);
+		memset(common->curbssid, 0, ETH_ALEN);
+		common->curaid = 0;
+	}
+
+	ath9k_bss_iter(sc);
+
+	/*
+	 * None of station vifs are associated.
+	 * Clear bssid & aid
+	 */
+	if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF)) {
+		ath9k_hw_write_associd(sc->sc_ah);
+		/* Stop ANI */
+		sc->sc_flags &= ~SC_OP_ANI_RUN;
+		common->ani.timer = 0;
+	}
+}
+
+static void ath9k_bss_info_changed(struct net80211_device *dev,
+				   u32 changed)
+{
+	struct ath_softc *sc = dev->priv;
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	int slottime;
+
+	if (changed & NET80211_CFG_ASSOC) {
+		ath9k_config_bss(sc);
+
+		DBG2("ath9k: BSSID: %pM aid: 0x%x\n",
+			common->curbssid, common->curaid);
+	}
+
+	if (changed & NET80211_CFG_PHY_PARAMS) {
+		if (dev->phy_flags & NET80211_PHY_USE_PROTECTION)
+			slottime = 9;
+		else
+			slottime = 20;
+		ah->slottime = slottime;
+		ath9k_hw_init_global_settings(ah);
+
+		DBG2("ath9k: BSS Changed PREAMBLE %d\n",
+				!!(dev->phy_flags & NET80211_PHY_USE_SHORT_PREAMBLE));
+		if (dev->phy_flags & NET80211_PHY_USE_SHORT_PREAMBLE)
+			sc->sc_flags |= SC_OP_PREAMBLE_SHORT;
+		else
+			sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT;
+
+		DBG2("ath9k: BSS Changed CTS PROT %d\n",
+			!!(dev->phy_flags & NET80211_PHY_USE_PROTECTION));
+		if ((dev->phy_flags & NET80211_PHY_USE_PROTECTION) &&
+		    (dev->channels + dev->channel)->band != NET80211_BAND_5GHZ)
+			sc->sc_flags |= SC_OP_PROTECT_ENABLE;
+		else
+			sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
+	}
+}
+
+static void ath9k_poll(struct net80211_device *dev)
+{
+	ath_isr(dev);
+}
+
+static void ath9k_irq(struct net80211_device *dev, int enable)
+{
+	struct ath_softc *sc = dev->priv;
+	struct ath_hw *ah = sc->sc_ah;
+
+	ah->ah_ier = enable ? AR_IER_ENABLE : AR_IER_DISABLE;
+
+	ath9k_hw_set_interrupts(ah, ah->imask);
+}
+
+struct net80211_device_operations ath9k_ops = {
+	.transmit	= ath9k_tx,
+	.open		= ath9k_start,
+	.close		= ath9k_stop,
+	.config		= ath9k_config,
+	.poll		= ath9k_poll,
+	.irq		= ath9k_irq,
+};
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_recv.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_recv.c
new file mode 100644
index 0000000000000000000000000000000000000000..ba363c676565ffc2f644bfe0d81450bf54e45b2a
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_recv.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/io.h>
+
+#include "ath9k.h"
+#include "ar9003_mac.h"
+
+/*
+ * Setup and link descriptors.
+ *
+ * 11N: we can no longer afford to self link the last descriptor.
+ * MAC acknowledges BA status as long as it copies frames to host
+ * buffer (or rx fifo). This can incorrectly acknowledge packets
+ * to a sender if last desc is self-linked.
+ */
+static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	struct ath_desc *ds;
+//	struct io_buffer *iob;
+
+	ATH_RXBUF_RESET(bf);
+
+	ds = bf->bf_desc;
+	ds->ds_link = 0; /* link to null */
+	ds->ds_data = bf->bf_buf_addr;
+
+//	/* virtual addr of the beginning of the buffer. */
+//	iob = bf->bf_mpdu;
+//	ds->ds_vdata = iob->data;
+
+	/*
+	 * setup rx descriptors. The rx_bufsize here tells the hardware
+	 * how much data it can DMA to us and that we are prepared
+	 * to process
+	 */
+	ath9k_hw_setuprxdesc(ah, ds,
+			     common->rx_bufsize,
+			     0);
+
+	if (sc->rx.rxlink == NULL)
+		ath9k_hw_putrxbuf(ah, bf->bf_daddr);
+	else
+		*sc->rx.rxlink = bf->bf_daddr;
+
+	sc->rx.rxlink = &ds->ds_link;
+}
+
+static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
+{
+	/* XXX block beacon interrupts */
+	ath9k_hw_setantenna(sc->sc_ah, antenna);
+	sc->rx.defant = antenna;
+	sc->rx.rxotherant = 0;
+}
+
+static void ath_opmode_init(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+
+	u32 rfilt, mfilt[2];
+
+	/* configure rx filter */
+	rfilt = ath_calcrxfilter(sc);
+	ath9k_hw_setrxfilter(ah, rfilt);
+
+	/* configure bssid mask */
+	ath_hw_setbssidmask(common);
+
+	/* configure operational mode */
+	ath9k_hw_setopmode(ah);
+
+	/* calculate and install multicast filter */
+	mfilt[0] = mfilt[1] = ~0;
+	ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
+}
+
+int ath_rx_init(struct ath_softc *sc, int nbufs)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct io_buffer *iob;
+	u32 *iob_addr = NULL;
+	struct ath_buf *bf;
+	int error = 0;
+
+	sc->sc_flags &= ~SC_OP_RXFLUSH;
+
+	common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
+			     sc->sc_ah->caps.rx_status_len;
+
+	DBG2("ath9k: cachelsz %d rxbufsize %d\n",
+		common->cachelsz, common->rx_bufsize);
+
+	/* Initialize rx descriptors */
+
+	error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
+			"rx", nbufs, 1, 0);
+	if (error != 0) {
+		DBG("ath9k: "
+			"failed to allocate rx descriptors: %d\n",
+			error);
+		goto err;
+	}
+
+	list_for_each_entry(bf, &sc->rx.rxbuf, list) {
+		iob = ath_rxbuf_alloc(common, common->rx_bufsize,
+				      iob_addr);
+		if (iob == NULL) {
+			error = -ENOMEM;
+			goto err;
+		}
+
+		bf->bf_mpdu = iob;
+		bf->bf_buf_addr = *iob_addr;
+	}
+	sc->rx.rxlink = NULL;
+
+err:
+	if (error)
+		ath_rx_cleanup(sc);
+
+	return error;
+}
+
+void ath_rx_cleanup(struct ath_softc *sc)
+{
+	struct io_buffer *iob;
+	struct ath_buf *bf;
+
+	list_for_each_entry(bf, &sc->rx.rxbuf, list) {
+		iob = bf->bf_mpdu;
+		if (iob) {
+			free_iob(iob);
+			bf->bf_buf_addr = 0;
+			bf->bf_mpdu = NULL;
+		}
+	}
+
+	if (sc->rx.rxdma.dd_desc_len != 0)
+		ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf);
+}
+
+/*
+ * Calculate the receive filter according to the
+ * operating mode and state:
+ *
+ * o always accept unicast, broadcast, and multicast traffic
+ * o maintain current state of phy error reception (the hal
+ *   may enable phy error frames for noise immunity work)
+ * o probe request frames are accepted only when operating in
+ *   hostap, adhoc, or monitor modes
+ * o enable promiscuous mode according to the interface state
+ * o accept beacons:
+ *   - when operating in adhoc mode so the 802.11 layer creates
+ *     node table entries for peers,
+ *   - when operating in station mode for collecting rssi data when
+ *     the station is otherwise quiet, or
+ *   - when operating as a repeater so we see repeater-sta beacons
+ *   - when scanning
+ */
+
+u32 ath_calcrxfilter(struct ath_softc *sc)
+{
+#define	RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR)
+
+	u32 rfilt;
+
+	rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE)
+		| ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
+		| ATH9K_RX_FILTER_MCAST | ATH9K_RX_FILTER_BEACON;
+
+	return rfilt;
+
+#undef RX_FILTER_PRESERVE
+}
+
+int ath_startrecv(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_buf *bf, *tbf;
+
+	if (list_empty(&sc->rx.rxbuf))
+		goto start_recv;
+
+	sc->rx.rxlink = NULL;
+	list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) {
+		ath_rx_buf_link(sc, bf);
+	}
+
+	/* We could have deleted elements so the list may be empty now */
+	if (list_empty(&sc->rx.rxbuf))
+		goto start_recv;
+
+	bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list);
+	ath9k_hw_putrxbuf(ah, bf->bf_daddr);
+	ath9k_hw_rxena(ah);
+
+start_recv:
+	ath_opmode_init(sc);
+	ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL));
+
+	return 0;
+}
+
+int ath_stoprecv(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	int stopped, reset = 0;
+
+	ath9k_hw_abortpcurecv(ah);
+	ath9k_hw_setrxfilter(ah, 0);
+	stopped = ath9k_hw_stopdmarecv(ah, &reset);
+
+	sc->rx.rxlink = NULL;
+
+	if (!(ah->ah_flags & AH_UNPLUGGED) &&
+	    !stopped) {
+		DBG("ath9k: "
+			"Could not stop RX, we could be "
+			"confusing the DMA engine when we start RX up\n");
+	}
+	return stopped && !reset;
+}
+
+void ath_flushrecv(struct ath_softc *sc)
+{
+	sc->sc_flags |= SC_OP_RXFLUSH;
+	ath_rx_tasklet(sc, 1, 0);
+	sc->sc_flags &= ~SC_OP_RXFLUSH;
+}
+
+static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
+					   struct ath_rx_status *rs)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_desc *ds;
+	struct ath_buf *bf;
+	int ret;
+
+	if (list_empty(&sc->rx.rxbuf)) {
+		sc->rx.rxlink = NULL;
+		return NULL;
+	}
+
+	bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list);
+	ds = bf->bf_desc;
+
+	/*
+	 * Must provide the virtual address of the current
+	 * descriptor, the physical address, and the virtual
+	 * address of the next descriptor in the h/w chain.
+	 * This allows the HAL to look ahead to see if the
+	 * hardware is done with a descriptor by checking the
+	 * done bit in the following descriptor and the address
+	 * of the current descriptor the DMA engine is working
+	 * on.  All this is necessary because of our use of
+	 * a self-linked list to avoid rx overruns.
+	 */
+	ret = ath9k_hw_rxprocdesc(ah, ds, rs, 0);
+	if (ret == -EINPROGRESS) {
+		struct ath_rx_status trs;
+		struct ath_buf *tbf;
+		struct ath_desc *tds;
+
+		memset(&trs, 0, sizeof(trs));
+		if ((&bf->list)->next == &sc->rx.rxbuf) {
+			sc->rx.rxlink = NULL;
+			return NULL;
+		}
+
+		tbf = list_entry(bf->list.next, struct ath_buf, list);
+
+		/*
+		 * On some hardware the descriptor status words could
+		 * get corrupted, including the done bit. Because of
+		 * this, check if the next descriptor's done bit is
+		 * set or not.
+		 *
+		 * If the next descriptor's done bit is set, the current
+		 * descriptor has been corrupted. Force s/w to discard
+		 * this descriptor and continue...
+		 */
+
+		tds = tbf->bf_desc;
+		ret = ath9k_hw_rxprocdesc(ah, tds, &trs, 0);
+		if (ret == -EINPROGRESS)
+			return NULL;
+	}
+
+	if (!bf->bf_mpdu)
+		return bf;
+
+	return bf;
+}
+
+/* Assumes you've already done the endian to CPU conversion */
+static int ath9k_rx_accept(struct ath_common *common,
+			    struct ath_rx_status *rx_stats,
+			    int *decrypt_error)
+{
+	struct ath_hw *ah = common->ah;
+	u8 rx_status_len = ah->caps.rx_status_len;
+
+
+	if (!rx_stats->rs_datalen)
+		return 0;
+        /*
+         * rs_status follows rs_datalen so if rs_datalen is too large
+         * we can take a hint that hardware corrupted it, so ignore
+         * those frames.
+         */
+	if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len))
+		return 0;
+
+	/* Only use error bits from the last fragment */
+	if (rx_stats->rs_more)
+		return 1;
+
+	/*
+	 * The rx_stats->rs_status will not be set until the end of the
+	 * chained descriptors so it can be ignored if rs_more is set. The
+	 * rs_more will be false at the last element of the chained
+	 * descriptors.
+	 */
+	if (rx_stats->rs_status != 0) {
+		if (rx_stats->rs_status & ATH9K_RXERR_PHY)
+			return 0;
+
+		if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
+			*decrypt_error = 1;
+		}
+		/*
+		 * Reject error frames with the exception of
+		 * decryption and MIC failures. For monitor mode,
+		 * we also ignore the CRC error.
+		 */
+		if (ah->is_monitoring) {
+			if (rx_stats->rs_status &
+			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
+			      ATH9K_RXERR_CRC))
+				return 0;
+		} else {
+			if (rx_stats->rs_status &
+			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
+				return 0;
+			}
+		}
+	}
+	return 1;
+}
+
+static int ath9k_process_rate(struct ath_common *common __unused,
+			      struct net80211_device *dev,
+			      struct ath_rx_status *rx_stats,
+			      int *rix)
+{
+	struct ath_softc *sc = (struct ath_softc *)dev->priv;
+	int band;
+	int i = 0;
+
+	band = (dev->channels + sc->dev->channel)->band;
+
+	for (i = 0; i < sc->hwinfo->nr_rates[band]; i++) {
+		if (sc->rates[i].hw_value == rx_stats->rs_rate) {
+			*rix = i;
+			return 0;
+		}
+		if (sc->rates[i].hw_value_short == rx_stats->rs_rate) {
+			*rix = i;
+			return 0;
+		}
+	}
+
+	/*
+	 * No valid hardware bitrate found -- we should not get here
+	 * because hardware has already validated this frame as OK.
+	 */
+	DBG("ath9k: "
+		"unsupported hw bitrate detected 0x%02x using 1 Mbit\n",
+		rx_stats->rs_rate);
+
+	return -EINVAL;
+}
+
+/*
+ * For Decrypt or Demic errors, we only mark packet status here and always push
+ * up the frame up to let mac80211 handle the actual error case, be it no
+ * decryption key or real decryption error. This let us keep statistics there.
+ */
+static int ath9k_rx_iob_preprocess(struct ath_common *common,
+				   struct net80211_device *dev,
+				   struct ath_rx_status *rx_stats,
+				   int *rix,
+				   int *decrypt_error)
+{
+	/*
+	 * everything but the rate is checked here, the rate check is done
+	 * separately to avoid doing two lookups for a rate for each frame.
+	 */
+	if (!ath9k_rx_accept(common, rx_stats, decrypt_error))
+		return -EINVAL;
+
+	/* Only use status info from the last fragment */
+	if (rx_stats->rs_more)
+		return 0;
+
+	if (ath9k_process_rate(common, dev, rx_stats, rix))
+		return -EINVAL;
+
+	return 0;
+}
+
+int ath_rx_tasklet(struct ath_softc *sc, int flush, int hp __unused)
+{
+	struct ath_buf *bf;
+	struct io_buffer *iob = NULL, *requeue_iob;
+	u32 *requeue_iob_addr = NULL;
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
+	/*
+	 * The hw can technically differ from common->hw when using ath9k
+	 * virtual wiphy so to account for that we iterate over the active
+	 * wiphys and find the appropriate wiphy and therefore hw.
+	 */
+	struct net80211_device *dev = sc->dev;
+	int retval;
+	int decrypt_error = 0;
+	struct ath_rx_status rs;
+	int rix = 0;
+
+	do {
+		/* If handling rx interrupt and flush is in progress => exit */
+		if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0))
+			break;
+
+		memset(&rs, 0, sizeof(rs));
+		bf = ath_get_next_rx_buf(sc, &rs);
+
+		if (!bf)
+			break;
+
+		iob = bf->bf_mpdu;
+		if (!iob)
+			continue;
+
+		/*
+		 * If we're asked to flush receive queue, directly
+		 * chain it back at the queue without processing it.
+		 */
+		if (flush)
+			goto requeue_drop_frag;
+
+		retval = ath9k_rx_iob_preprocess(common, dev, &rs,
+						 &rix, &decrypt_error);
+		if (retval)
+			goto requeue_drop_frag;
+
+		/* Ensure we always have an iob to requeue once we are done
+		 * processing the current buffer's iob */
+		requeue_iob = ath_rxbuf_alloc(common, common->rx_bufsize, requeue_iob_addr);
+
+		/* If there is no memory we ignore the current RX'd frame,
+		 * tell hardware it can give us a new frame using the old
+		 * iob and put it at the tail of the sc->rx.rxbuf list for
+		 * processing. */
+		if (!requeue_iob)
+			goto requeue_drop_frag;
+
+		iob_put(iob, rs.rs_datalen + ah->caps.rx_status_len);
+		if (ah->caps.rx_status_len)
+			iob_pull(iob, ah->caps.rx_status_len);
+
+		/* We will now give hardware our shiny new allocated iob */
+		bf->bf_mpdu = requeue_iob;
+		bf->bf_buf_addr = *requeue_iob_addr;
+
+		/*
+		 * change the default rx antenna if rx diversity chooses the
+		 * other antenna 3 times in a row.
+		 */
+		if (sc->rx.defant != rs.rs_antenna) {
+			if (++sc->rx.rxotherant >= 3)
+				ath_setdefantenna(sc, rs.rs_antenna);
+		} else {
+			sc->rx.rxotherant = 0;
+		}
+
+		DBGIO("ath9k: rx %d bytes, signal %d, bitrate %d, hw_value %d\n", rs.rs_datalen,
+		                                rs.rs_rssi, sc->rates[rix].bitrate, rs.rs_rate);
+
+		net80211_rx(dev, iob, rs.rs_rssi,
+				sc->rates[rix].bitrate);
+
+requeue_drop_frag:
+		list_del(&bf->list);
+		list_add_tail(&bf->list, &sc->rx.rxbuf);
+		ath_rx_buf_link(sc, bf);
+		ath9k_hw_rxena(ah);
+	} while (1);
+
+	return 0;
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_xmit.c b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_xmit.c
new file mode 100644
index 0000000000000000000000000000000000000000..7f4f28ab8b0c5a27ac15989fad50dfd1f3b36c6d
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/ath9k_xmit.c
@@ -0,0 +1,813 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/io.h>
+
+#include "ath9k.h"
+#include "ar9003_mac.h"
+
+#define BITS_PER_BYTE           8
+#define OFDM_PLCP_BITS          22
+#define HT_RC_2_STREAMS(_rc)    ((((_rc) & 0x78) >> 3) + 1)
+#define L_STF                   8
+#define L_LTF                   8
+#define L_SIG                   4
+#define HT_SIG                  8
+#define HT_STF                  4
+#define HT_LTF(_ns)             (4 * (_ns))
+#define SYMBOL_TIME(_ns)        ((_ns) << 2) /* ns * 4 us */
+#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5)  /* ns * 3.6 us */
+#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2)
+#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18)
+
+
+#define IS_HT_RATE(_rate)     ((_rate) & 0x80)
+
+static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
+			       struct ath_atx_tid *tid,
+			       struct list_head *bf_head);
+static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
+				struct ath_txq *txq, struct list_head *bf_q,
+				struct ath_tx_status *ts, int txok, int sendbar);
+static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
+			     struct list_head *head);
+static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
+
+enum {
+	MCS_HT20,
+	MCS_HT20_SGI,
+	MCS_HT40,
+	MCS_HT40_SGI,
+};
+
+/*********************/
+/* Aggregation logic */
+/*********************/
+
+static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
+{
+	struct ath_atx_ac *ac = tid->ac;
+
+	if (tid->paused)
+		return;
+
+	if (tid->sched)
+		return;
+
+	tid->sched = 1;
+	list_add_tail(&tid->list, &ac->tid_q);
+
+	if (ac->sched)
+		return;
+
+	ac->sched = 1;
+	list_add_tail(&ac->list, &txq->axq_acq);
+}
+
+static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
+{
+	struct ath_buf *bf = NULL;
+
+	if (list_empty(&sc->tx.txbuf)) {
+		return NULL;
+	}
+
+	bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
+	list_del(&bf->list);
+
+	return bf;
+}
+
+static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
+{
+	list_add_tail(&bf->list, &sc->tx.txbuf);
+}
+
+/********************/
+/* Queue Management */
+/********************/
+
+struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath9k_tx_queue_info qi;
+	static const int subtype_txq_to_hwq[] = {
+		[WME_AC_BE] = ATH_TXQ_AC_BE,
+	};
+	int axq_qnum, i;
+
+	memset(&qi, 0, sizeof(qi));
+	qi.tqi_subtype = subtype_txq_to_hwq[subtype];
+	qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
+	qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
+	qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
+	qi.tqi_physCompBuf = 0;
+
+	/*
+	 * Enable interrupts only for EOL and DESC conditions.
+	 * We mark tx descriptors to receive a DESC interrupt
+	 * when a tx queue gets deep; otherwise waiting for the
+	 * EOL to reap descriptors.  Note that this is done to
+	 * reduce interrupt load and this only defers reaping
+	 * descriptors, never transmitting frames.  Aside from
+	 * reducing interrupts this also permits more concurrency.
+	 * The only potential downside is if the tx queue backs
+	 * up in which case the top half of the kernel may backup
+	 * due to a lack of tx descriptors.
+	 *
+	 * The UAPSD queue is an exception, since we take a desc-
+	 * based intr on the EOSP frames.
+	 */
+	qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
+			TXQ_FLAG_TXDESCINT_ENABLE;
+
+	axq_qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
+	if (axq_qnum == -1) {
+		/*
+		 * NB: don't print a message, this happens
+		 * normally on parts with too few tx queues
+		 */
+		return NULL;
+	}
+	if ((unsigned int)axq_qnum >= ARRAY_SIZE(sc->tx.txq)) {
+		DBG("ath9k: qnum %d out of range, max %zd!\n",
+			axq_qnum, ARRAY_SIZE(sc->tx.txq));
+		ath9k_hw_releasetxqueue(ah, axq_qnum);
+		return NULL;
+	}
+	if (!ATH_TXQ_SETUP(sc, axq_qnum)) {
+		struct ath_txq *txq = &sc->tx.txq[axq_qnum];
+
+		txq->axq_qnum = axq_qnum;
+		txq->mac80211_qnum = -1;
+		txq->axq_link = NULL;
+		INIT_LIST_HEAD(&txq->axq_q);
+		INIT_LIST_HEAD(&txq->axq_acq);
+		txq->axq_depth = 0;
+		txq->axq_ampdu_depth = 0;
+		txq->axq_tx_inprogress = 0;
+		sc->tx.txqsetup |= 1<<axq_qnum;
+
+		txq->txq_headidx = txq->txq_tailidx = 0;
+		for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
+			INIT_LIST_HEAD(&txq->txq_fifo[i]);
+		INIT_LIST_HEAD(&txq->txq_fifo_pending);
+	}
+	return &sc->tx.txq[axq_qnum];
+}
+
+/*
+ * Drain a given TX queue (could be Beacon or Data)
+ *
+ * This assumes output has been stopped and
+ * we do not need to block ath_tx_tasklet.
+ */
+void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, int retry_tx __unused)
+{
+	struct ath_buf *bf, *lastbf __unused;
+	struct list_head bf_head;
+	struct ath_tx_status ts;
+
+	memset(&ts, 0, sizeof(ts));
+	INIT_LIST_HEAD(&bf_head);
+
+	for (;;) {
+		if (list_empty(&txq->axq_q)) {
+			txq->axq_link = NULL;
+			break;
+		}
+		bf = list_first_entry(&txq->axq_q, struct ath_buf,
+				      list);
+
+		if (bf->bf_stale) {
+			list_del(&bf->list);
+
+			ath_tx_return_buffer(sc, bf);
+			continue;
+		}
+
+		lastbf = bf->bf_lastbf;
+
+		list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
+
+		txq->axq_depth--;
+		ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
+	}
+
+	txq->axq_tx_inprogress = 0;
+}
+
+int ath_drain_all_txq(struct ath_softc *sc, int retry_tx)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_txq *txq;
+	int i, npend = 0;
+
+	if (sc->sc_flags & SC_OP_INVALID)
+		return 1;
+
+	ath9k_hw_abort_tx_dma(ah);
+
+	/* Check if any queue remains active */
+	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+		if (!ATH_TXQ_SETUP(sc, i))
+			continue;
+
+		npend += ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum);
+	}
+
+	if (npend)
+		DBG("ath9k: Failed to stop TX DMA!\n");
+
+	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+		if (!ATH_TXQ_SETUP(sc, i))
+			continue;
+
+		/*
+		 * The caller will resume queues with ieee80211_wake_queues.
+		 * Mark the queue as not stopped to prevent ath_tx_complete
+		 * from waking the queue too early.
+		 */
+		txq = &sc->tx.txq[i];
+		txq->stopped = 0;
+		ath_draintxq(sc, txq, retry_tx);
+	}
+
+	return !npend;
+}
+
+void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
+{
+	ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
+	sc->tx.txqsetup &= ~(1<<txq->axq_qnum);
+}
+
+/* For each axq_acq entry, for each tid, try to schedule packets
+ * for transmit until ampdu_depth has reached min Q depth.
+ */
+void ath_txq_schedule(struct ath_softc *sc __unused, struct ath_txq *txq)
+{
+	struct ath_atx_ac *ac, *ac_tmp, *last_ac;
+	struct ath_atx_tid *tid, *last_tid;
+
+	if (list_empty(&txq->axq_acq) ||
+	    txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
+		return;
+
+	ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
+	last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list);
+
+	list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
+		last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list);
+		list_del(&ac->list);
+		ac->sched = 0;
+
+		while (!list_empty(&ac->tid_q)) {
+			tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
+					       list);
+			list_del(&tid->list);
+			tid->sched = 0;
+
+			if (tid->paused)
+				continue;
+
+			/*
+			 * add tid to round-robin queue if more frames
+			 * are pending for the tid
+			 */
+			if (!list_empty(&tid->buf_q))
+				ath_tx_queue_tid(txq, tid);
+
+			if (tid == last_tid ||
+			    txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
+				break;
+		}
+
+		if (!list_empty(&ac->tid_q)) {
+			if (!ac->sched) {
+				ac->sched = 1;
+				list_add_tail(&ac->list, &txq->axq_acq);
+			}
+		}
+
+		if (ac == last_ac ||
+		    txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
+			return;
+	}
+}
+
+/***********/
+/* TX, DMA */
+/***********/
+
+/*
+ * Insert a chain of ath_buf (descriptors) on a txq and
+ * assume the descriptors are already chained together by caller.
+ */
+static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
+			     struct list_head *head)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_buf *bf;
+
+	/*
+	 * Insert the frame on the outbound list and
+	 * pass it on to the hardware.
+	 */
+
+	if (list_empty(head))
+		return;
+
+	bf = list_first_entry(head, struct ath_buf, list);
+
+	DBGIO("ath9k: "
+		"qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
+
+	list_splice_tail_init(head, &txq->axq_q);
+
+	if (txq->axq_link == NULL) {
+		ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
+		DBGIO("ath9k: TXDP[%d] = %llx (%p)\n",
+			txq->axq_qnum, ito64(bf->bf_daddr),
+			bf->bf_desc);
+	} else {
+		*txq->axq_link = bf->bf_daddr;
+		DBGIO("ath9k: "
+			"link[%d] (%p)=%llx (%p)\n",
+			txq->axq_qnum, txq->axq_link,
+			ito64(bf->bf_daddr), bf->bf_desc);
+	}
+	ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
+			       &txq->axq_link);
+	ath9k_hw_txstart(ah, txq->axq_qnum);
+
+	txq->axq_depth++;
+}
+
+static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
+			       struct ath_atx_tid *tid,
+			       struct list_head *bf_head)
+{
+	struct ath_buf *bf;
+
+	bf = list_first_entry(bf_head, struct ath_buf, list);
+	bf->bf_state.bf_type &= ~BUF_AMPDU;
+
+	/* update starting sequence number for subsequent ADDBA request */
+	if (tid)
+		INCR(tid->seq_start, IEEE80211_SEQ_MAX);
+
+	bf->bf_lastbf = bf;
+	ath_buf_set_rate(sc, bf, iob_len(bf->bf_mpdu) + FCS_LEN);
+	ath_tx_txqaddbuf(sc, txq, bf_head);
+}
+
+static enum ath9k_pkt_type get_hw_packet_type(struct io_buffer *iob)
+{
+	struct ieee80211_frame *hdr;
+	enum ath9k_pkt_type htype;
+	u16 fc;
+
+	hdr = (struct ieee80211_frame *)iob->data;
+	fc = hdr->fc;
+
+	if ((fc & (IEEE80211_FC_TYPE | IEEE80211_FC_SUBTYPE)) == (IEEE80211_TYPE_MGMT | IEEE80211_STYPE_BEACON))
+		htype = ATH9K_PKT_TYPE_BEACON;
+	else if ((fc & (IEEE80211_FC_TYPE | IEEE80211_FC_SUBTYPE)) == (IEEE80211_TYPE_MGMT | IEEE80211_STYPE_PROBE_RESP))
+		htype = ATH9K_PKT_TYPE_PROBE_RESP;
+	else
+		htype = ATH9K_PKT_TYPE_NORMAL;
+
+	return htype;
+}
+
+static int setup_tx_flags(struct io_buffer *iob __unused)
+{
+	int flags = 0;
+
+	flags |= ATH9K_TXDESC_INTREQ;
+
+	return flags;
+}
+
+u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath9k_channel *curchan = ah->curchan;
+	if ((sc->sc_flags & SC_OP_ENABLE_APM) &&
+			(curchan->channelFlags & CHANNEL_5GHZ) &&
+			(chainmask == 0x7) && (rate < 0x90))
+		return 0x3;
+	else
+		return chainmask;
+}
+
+static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
+{
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+	struct ath9k_11n_rate_series series[4];
+	const struct ath9k_legacy_rate *rate;
+	int i, flags = 0;
+	u8 rix = 0, ctsrate = 0;
+	int is_pspoll;
+
+	memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
+
+	is_pspoll = 0;
+
+	/*
+	 * We check if Short Preamble is needed for the CTS rate by
+	 * checking the BSS's global flag.
+	 * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
+	 */
+	rate = &sc->rates[sc->hw_rix];
+	ctsrate = rate->hw_value;
+	if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
+		ctsrate |= rate->hw_value_short;
+
+	for (i = 0; i < 4; i++) {
+		int is_40 __unused, is_sgi __unused, is_sp;
+		int phy;
+
+		rix = sc->hw_rix;
+		series[i].Tries = ATH_TXMAXTRY;
+
+		if (sc->sc_flags & SC_OP_PROTECT_ENABLE) {
+			series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+			flags |= ATH9K_TXDESC_CTSENA;
+		}
+
+		is_sp = !!(rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
+
+		/* legacy rates */
+		if ((sc->dev->channels + sc->dev->channel)->band == NET80211_BAND_2GHZ)
+			phy = CHANNEL_CCK;
+		else
+			phy = CHANNEL_OFDM;
+
+		series[i].Rate = rate->hw_value;
+		if (rate->hw_value_short && (sc->sc_flags & SC_OP_PREAMBLE_SHORT)) {
+			if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+				series[i].Rate |= rate->hw_value_short;
+		} else {
+			is_sp = 0;
+		}
+
+		if (bf->bf_state.bfs_paprd)
+			series[i].ChSel = common->tx_chainmask;
+		else
+			series[i].ChSel = ath_txchainmask_reduction(sc,
+					common->tx_chainmask, series[i].Rate);
+
+		series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
+			phy, rate->bitrate * 100, len, rix, is_sp);
+	}
+
+	/* For AR5416 - RTS cannot be followed by a frame larger than 8K */
+	if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
+		flags &= ~ATH9K_TXDESC_RTSENA;
+
+	/* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
+	if (flags & ATH9K_TXDESC_RTSENA)
+		flags &= ~ATH9K_TXDESC_CTSENA;
+
+	/* set dur_update_en for l-sig computation except for PS-Poll frames */
+	ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
+				     bf->bf_lastbf->bf_desc,
+				     !is_pspoll, ctsrate,
+				     0, series, 4, flags);
+
+}
+
+static struct ath_buf *ath_tx_setup_buffer(struct net80211_device *dev,
+					   struct ath_txq *txq,
+					   struct io_buffer *iob)
+{
+	struct ath_softc *sc = dev->priv;
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_buf *bf;
+	struct ath_desc *ds;
+	int frm_type;
+	static const enum ath9k_key_type net80211_keytype_to_ath[] = {
+			[NET80211_CRYPT_NONE] = ATH9K_KEY_TYPE_CLEAR,
+			[NET80211_CRYPT_WEP] = ATH9K_KEY_TYPE_WEP,
+			[NET80211_CRYPT_TKIP] = ATH9K_KEY_TYPE_TKIP,
+			[NET80211_CRYPT_CCMP] = ATH9K_KEY_TYPE_AES,
+			[NET80211_CRYPT_UNKNOWN] = ATH9K_KEY_TYPE_CLEAR,
+	};
+
+	bf = ath_tx_get_buffer(sc);
+	if (!bf) {
+		DBG("ath9k: TX buffers are full\n");
+		return NULL;
+	}
+
+	ATH_TXBUF_RESET(bf);
+
+	bf->bf_flags = setup_tx_flags(iob);
+	bf->bf_mpdu = iob;
+
+	bf->bf_buf_addr = virt_to_bus(iob->data);
+
+	frm_type = get_hw_packet_type(iob);
+
+	ds = bf->bf_desc;
+	ath9k_hw_set_desc_link(ah, ds, 0);
+
+	ath9k_hw_set11n_txdesc(ah, ds, iob_len(iob) + FCS_LEN, frm_type, MAX_RATE_POWER,
+			       ATH9K_TXKEYIX_INVALID, net80211_keytype_to_ath[dev->crypto->algorithm], bf->bf_flags);
+
+	ath9k_hw_filltxdesc(ah, ds,
+			    iob_len(iob),	/* segment length */
+			    1,		/* first segment */
+			    1,		/* last segment */
+			    ds,		/* first descriptor */
+			    bf->bf_buf_addr,
+			    txq->axq_qnum);
+
+
+	return bf;
+}
+
+/* FIXME: tx power */
+static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
+			     struct ath_tx_control *txctl)
+{
+	struct list_head bf_head;
+	struct ath_atx_tid *tid = NULL;
+
+	INIT_LIST_HEAD(&bf_head);
+	list_add_tail(&bf->list, &bf_head);
+
+	bf->bf_state.bfs_paprd = txctl->paprd;
+
+	if (txctl->paprd)
+		bf->bf_state.bfs_paprd_timestamp = ( currticks() * 1000 ) / TICKS_PER_SEC;
+
+	ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, 1);
+
+	ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
+}
+
+/* Upon failure caller should free iob */
+int ath_tx_start(struct net80211_device *dev, struct io_buffer *iob,
+		 struct ath_tx_control *txctl)
+{
+	struct ath_softc *sc = dev->priv;
+	struct ath_txq *txq = txctl->txq;
+	struct ath_buf *bf;
+	int q;
+
+	/*
+	 * At this point, the vif, hw_key and sta pointers in the tx control
+	 * info are no longer valid (overwritten by the ath_frame_info data.
+	 */
+
+	bf = ath_tx_setup_buffer(dev, txctl->txq, iob);
+	if (!bf)
+		return -ENOMEM;
+
+	q = 0;
+	if (txq == sc->tx.txq_map[q] &&
+	    ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
+		txq->stopped = 1;
+	}
+
+	ath_tx_start_dma(sc, bf, txctl);
+
+	return 0;
+}
+
+/*****************/
+/* TX Completion */
+/*****************/
+
+static void ath_tx_complete(struct ath_softc *sc, struct io_buffer *iob,
+			    int tx_flags __unused, struct ath_tx_status *ts, struct ath_txq *txq)
+{
+	struct net80211_device *dev = sc->dev;
+	int q, padpos __unused, padsize __unused;
+
+	DBGIO("ath9k: TX complete: iob: %p\n", iob);
+
+	q = 0;
+	if (txq == sc->tx.txq_map[q]) {
+		if (--txq->pending_frames < 0)
+			txq->pending_frames = 0;
+
+		if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
+			txq->stopped = 0;
+		}
+	}
+
+	net80211_tx_complete(dev, iob, ts->ts_longretry,
+			(ts->ts_status & ATH9K_TXERR_MASK) ? EIO : 0);
+}
+
+static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
+				struct ath_txq *txq, struct list_head *bf_q,
+				struct ath_tx_status *ts, int txok, int sendbar)
+{
+	struct io_buffer *iob = bf->bf_mpdu;
+	int tx_flags = 0;
+
+	if (sendbar)
+		tx_flags = ATH_TX_BAR;
+
+	if (!txok) {
+		tx_flags |= ATH_TX_ERROR;
+
+		if (bf_isxretried(bf))
+			tx_flags |= ATH_TX_XRETRY;
+	}
+
+	bf->bf_buf_addr = 0;
+
+	ath_tx_complete(sc, iob, tx_flags,
+			ts, txq);
+
+	/* At this point, iob (bf->bf_mpdu) is consumed...make sure we don't
+	 * accidentally reference it later.
+	 */
+	bf->bf_mpdu = NULL;
+
+	/*
+	 * Return the list of ath_buf of this mpdu to free queue
+	 */
+	list_splice_tail_init(bf_q, &sc->tx.txbuf);
+}
+
+static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_buf *bf, *lastbf, *bf_held = NULL;
+	struct list_head bf_head;
+	struct ath_desc *ds;
+	struct ath_tx_status ts;
+	int txok;
+	int status;
+
+	DBGIO("ath9k: tx queue %d (%x), link %p\n",
+		txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
+		txq->axq_link);
+
+	for (;;) {
+		if (list_empty(&txq->axq_q)) {
+			txq->axq_link = NULL;
+			if (sc->sc_flags & SC_OP_TXAGGR)
+				ath_txq_schedule(sc, txq);
+			break;
+		}
+		bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
+
+		/*
+		 * There is a race condition that a BH gets scheduled
+		 * after sw writes TxE and before hw re-load the last
+		 * descriptor to get the newly chained one.
+		 * Software must keep the last DONE descriptor as a
+		 * holding descriptor - software does so by marking
+		 * it with the STALE flag.
+		 */
+		bf_held = NULL;
+		if (bf->bf_stale) {
+			bf_held = bf;
+			if (list_is_last(&bf_held->list, &txq->axq_q)) {
+				break;
+			} else {
+				bf = list_entry(bf_held->list.next,
+						struct ath_buf, list);
+			}
+		}
+
+		lastbf = bf->bf_lastbf;
+		ds = lastbf->bf_desc;
+
+		memset(&ts, 0, sizeof(ts));
+		status = ath9k_hw_txprocdesc(ah, ds, &ts);
+		if (status == -EINPROGRESS) {
+			break;
+		}
+
+		/*
+		 * Remove ath_buf's of the same transmit unit from txq,
+		 * however leave the last descriptor back as the holding
+		 * descriptor for hw.
+		 */
+		lastbf->bf_stale = 1;
+		INIT_LIST_HEAD(&bf_head);
+		if (!list_is_singular(&lastbf->list))
+			list_cut_position(&bf_head,
+				&txq->axq_q, lastbf->list.prev);
+
+		txq->axq_depth--;
+		txok = !(ts.ts_status & ATH9K_TXERR_MASK);
+		txq->axq_tx_inprogress = 0;
+		if (bf_held)
+			list_del(&bf_held->list);
+
+		if (bf_held)
+			ath_tx_return_buffer(sc, bf_held);
+
+		/*
+		 * This frame is sent out as a single frame.
+		 * Use hardware retry status for this frame.
+		 */
+		if (ts.ts_status & ATH9K_TXERR_XRETRY)
+			bf->bf_state.bf_type |= BUF_XRETRY;
+
+		ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
+
+		if (sc->sc_flags & SC_OP_TXAGGR)
+			ath_txq_schedule(sc, txq);
+	}
+}
+
+static void ath_tx_complete_poll_work(struct ath_softc *sc)
+{
+	struct ath_txq *txq;
+	int i;
+	int needreset = 0;
+
+	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+		if (ATH_TXQ_SETUP(sc, i)) {
+			txq = &sc->tx.txq[i];
+			if (txq->axq_depth) {
+				if (txq->axq_tx_inprogress) {
+					needreset = 1;
+					break;
+				} else {
+					txq->axq_tx_inprogress = 1;
+				}
+			}
+		}
+
+	if (needreset) {
+		DBG("ath9k: "
+			"tx hung, resetting the chip\n");
+		ath_reset(sc, 1);
+	}
+
+	sc->tx_complete_work_timer = ( currticks() * 1000 ) / TICKS_PER_SEC + ATH_TX_COMPLETE_POLL_INT;
+}
+
+
+
+void ath_tx_tasklet(struct ath_softc *sc)
+{
+	int i;
+	u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
+
+	ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
+
+	for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+		if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
+			ath_tx_processq(sc, &sc->tx.txq[i]);
+	}
+}
+
+/*****************/
+/* Init, Cleanup */
+/*****************/
+
+int ath_tx_init(struct ath_softc *sc, int nbufs)
+{
+	int error = 0;
+
+	error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
+				  "tx", nbufs, 1, 1);
+	if (error != 0) {
+		DBG("ath9k: "
+			"Failed to allocate tx descriptors: %d\n", error);
+		goto err;
+	}
+
+	sc->tx_complete_work = ath_tx_complete_poll_work;
+
+err:
+	if (error != 0)
+		ath_tx_cleanup(sc);
+
+	return error;
+}
+
+void ath_tx_cleanup(struct ath_softc *sc)
+{
+	if (sc->tx.txdma.dd_desc_len != 0)
+		ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/calib.h b/roms/ipxe/src/drivers/net/ath/ath9k/calib.h
new file mode 100644
index 0000000000000000000000000000000000000000..5bf50f4a6a50cf78338bc7be234f0461cd588d19
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/calib.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef CALIB_H
+#define CALIB_H
+
+#include "hw.h"
+
+#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT     3
+#define AR_PHY_CCA_FILTERWINDOW_LENGTH          5
+
+#define NUM_NF_READINGS       6
+#define ATH9K_NF_CAL_HIST_MAX 5
+
+struct ar5416IniArray {
+	u32 *ia_array;
+	u32 ia_rows;
+	u32 ia_columns;
+};
+
+#define INIT_INI_ARRAY(iniarray, array, rows, columns) do {	\
+		(iniarray)->ia_array = (u32 *)(array);		\
+		(iniarray)->ia_rows = (rows);			\
+		(iniarray)->ia_columns = (columns);		\
+	} while (0)
+
+#define INI_RA(iniarray, row, column) \
+	(((iniarray)->ia_array)[(row) *	((iniarray)->ia_columns) + (column)])
+
+#define INIT_CAL(_perCal) do {				\
+		(_perCal)->calState = CAL_WAITING;	\
+		(_perCal)->calNext = NULL;		\
+	} while (0)
+
+#define INSERT_CAL(_ahp, _perCal)					\
+	do {								\
+		if ((_ahp)->cal_list_last == NULL) {			\
+			(_ahp)->cal_list =				\
+				(_ahp)->cal_list_last = (_perCal);	\
+			((_ahp)->cal_list_last)->calNext = (_perCal); \
+		} else {						\
+			((_ahp)->cal_list_last)->calNext = (_perCal); \
+			(_ahp)->cal_list_last = (_perCal);		\
+			(_perCal)->calNext = (_ahp)->cal_list;	\
+		}							\
+	} while (0)
+
+enum ath9k_cal_state {
+	CAL_INACTIVE,
+	CAL_WAITING,
+	CAL_RUNNING,
+	CAL_DONE
+};
+
+#define MIN_CAL_SAMPLES     1
+#define MAX_CAL_SAMPLES    64
+#define INIT_LOG_COUNT      5
+#define PER_MIN_LOG_COUNT   2
+#define PER_MAX_LOG_COUNT  10
+
+struct ath9k_percal_data {
+	u32 calType;
+	u32 calNumSamples;
+	u32 calCountMax;
+	void (*calCollect) (struct ath_hw *);
+	void (*calPostProc) (struct ath_hw *, u8);
+};
+
+struct ath9k_cal_list {
+	const struct ath9k_percal_data *calData;
+	enum ath9k_cal_state calState;
+	struct ath9k_cal_list *calNext;
+};
+
+struct ath9k_nfcal_hist {
+	int16_t nfCalBuffer[ATH9K_NF_CAL_HIST_MAX];
+	u8 currIndex;
+	int16_t privNF;
+	u8 invalidNFcount;
+};
+
+#define MAX_PACAL_SKIPCOUNT 8
+struct ath9k_pacal_info{
+	int32_t prev_offset;	/* Previous value of PA offset value */
+	int8_t max_skipcount;	/* Max No. of times PACAL can be skipped */
+	int8_t skipcount;	/* No. of times the PACAL to be skipped */
+};
+
+int ath9k_hw_reset_calvalid(struct ath_hw *ah);
+void ath9k_hw_start_nfcal(struct ath_hw *ah, int update);
+void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
+int ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan);
+void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
+				  struct ath9k_channel *chan);
+void ath9k_hw_reset_calibration(struct ath_hw *ah,
+				struct ath9k_cal_list *currCal);
+
+
+#endif /* CALIB_H */
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/common.h b/roms/ipxe/src/drivers/net/ath/ath9k/common.h
new file mode 100644
index 0000000000000000000000000000000000000000..009f8036dc2a50c106f760dc0348acf3531f3689
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/common.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2009-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "../ath.h"
+
+#include "hw.h"
+#include "hw-ops.h"
+
+/* Common header for Atheros 802.11n base driver cores */
+
+#define WME_NUM_TID             16
+#define WME_BA_BMP_SIZE         64
+#define WME_MAX_BA              WME_BA_BMP_SIZE
+#define ATH_TID_MAX_BUFS        (2 * WME_MAX_BA)
+
+#define WME_AC_BE   2
+#define WME_NUM_AC  1
+
+#define ATH_RSSI_DUMMY_MARKER   0x127
+#define ATH_RSSI_LPF_LEN 		10
+#define RSSI_LPF_THRESHOLD		-20
+#define ATH_RSSI_EP_MULTIPLIER     (1<<7)
+#define ATH_EP_MUL(x, mul)         ((x) * (mul))
+#define ATH_RSSI_IN(x)             (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
+#define ATH_LPF_RSSI(x, y, len) \
+    ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y))
+#define ATH_RSSI_LPF(x, y) do {                     			\
+    if ((y) >= RSSI_LPF_THRESHOLD)                         		\
+	x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN);  	\
+} while (0)
+#define ATH_EP_RND(x, mul) 						\
+	((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+
+
+void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
+			       struct net80211_channel *chan);
+struct ath9k_channel *ath9k_cmn_get_curchannel(struct net80211_device *dev,
+					       struct ath_hw *ah);
+void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow,
+			    u16 new_txpow, u16 *txpower);
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/eeprom.h b/roms/ipxe/src/drivers/net/ath/ath9k/eeprom.h
new file mode 100644
index 0000000000000000000000000000000000000000..b451ebd70f6dbb48201ea4ad8e84b40918d75fae
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/eeprom.h
@@ -0,0 +1,714 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef EEPROM_H
+#define EEPROM_H
+
+#define AR_EEPROM_MODAL_SPURS   5
+
+#include "../ath.h"
+#include "ar9003_eeprom.h"
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define AR5416_EEPROM_MAGIC 0x5aa5
+#else
+#define AR5416_EEPROM_MAGIC 0xa55a
+#endif
+
+#define CTRY_DEBUG   0x1ff
+#define	CTRY_DEFAULT 0
+
+#define AR_EEPROM_EEPCAP_COMPRESS_DIS   0x0001
+#define AR_EEPROM_EEPCAP_AES_DIS        0x0002
+#define AR_EEPROM_EEPCAP_FASTFRAME_DIS  0x0004
+#define AR_EEPROM_EEPCAP_BURST_DIS      0x0008
+#define AR_EEPROM_EEPCAP_MAXQCU         0x01F0
+#define AR_EEPROM_EEPCAP_MAXQCU_S       4
+#define AR_EEPROM_EEPCAP_HEAVY_CLIP_EN  0x0200
+#define AR_EEPROM_EEPCAP_KC_ENTRIES     0xF000
+#define AR_EEPROM_EEPCAP_KC_ENTRIES_S   12
+
+#define AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND   0x0040
+#define AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN    0x0080
+#define AR_EEPROM_EEREGCAP_EN_KK_U2         0x0100
+#define AR_EEPROM_EEREGCAP_EN_KK_MIDBAND    0x0200
+#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD     0x0400
+#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A    0x0800
+
+#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD_PRE4_0  0x4000
+#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0 0x8000
+
+#define AR5416_EEPROM_MAGIC_OFFSET  0x0
+#define AR5416_EEPROM_S             2
+#define AR5416_EEPROM_OFFSET        0x2000
+#define AR5416_EEPROM_MAX           0xae0
+
+#define AR5416_EEPROM_START_ADDR \
+	(AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200
+
+#define SD_NO_CTL               0xE0
+#define NO_CTL                  0xff
+#define CTL_MODE_M              0xf
+#define CTL_11A                 0
+#define CTL_11B                 1
+#define CTL_11G                 2
+#define CTL_2GHT20              5
+#define CTL_5GHT20              6
+#define CTL_2GHT40              7
+#define CTL_5GHT40              8
+
+#define EXT_ADDITIVE (0x8000)
+#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE)
+#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE)
+#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE)
+
+#define SUB_NUM_CTL_MODES_AT_5G_40 2
+#define SUB_NUM_CTL_MODES_AT_2G_40 3
+
+#define INCREASE_MAXPOW_BY_TWO_CHAIN     6  /* 10*log10(2)*2 */
+#define INCREASE_MAXPOW_BY_THREE_CHAIN   10 /* 10*log10(3)*2 */
+
+/*
+ * For AR9285 and later chipsets, the following bits are not being programmed
+ * in EEPROM and so need to be enabled always.
+ *
+ * Bit 0: en_fcc_mid
+ * Bit 1: en_jap_mid
+ * Bit 2: en_fcc_dfs_ht40
+ * Bit 3: en_jap_ht40
+ * Bit 4: en_jap_dfs_ht40
+ */
+#define AR9285_RDEXT_DEFAULT    0x1F
+
+#define ATH9K_POW_SM(_r, _s)	(((_r) & 0x3f) << (_s))
+#define FREQ2FBIN(x, y)		((y) ? ((x) - 2300) : (((x) - 4800) / 5))
+#define ath9k_hw_use_flash(_ah)	(!(_ah->ah_flags & AH_USE_EEPROM))
+
+#define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK)
+#define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \
+				 ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
+#define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_11_OR_LATER(ah) && \
+				 ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
+
+#define AR_EEPROM_RFSILENT_GPIO_SEL     0x001c
+#define AR_EEPROM_RFSILENT_GPIO_SEL_S   2
+#define AR_EEPROM_RFSILENT_POLARITY     0x0002
+#define AR_EEPROM_RFSILENT_POLARITY_S   1
+
+#define EEP_RFSILENT_ENABLED        0x0001
+#define EEP_RFSILENT_ENABLED_S      0
+#define EEP_RFSILENT_POLARITY       0x0002
+#define EEP_RFSILENT_POLARITY_S     1
+#define EEP_RFSILENT_GPIO_SEL       0x001c
+#define EEP_RFSILENT_GPIO_SEL_S     2
+
+#define AR5416_OPFLAGS_11A           0x01
+#define AR5416_OPFLAGS_11G           0x02
+#define AR5416_OPFLAGS_N_5G_HT40     0x04
+#define AR5416_OPFLAGS_N_2G_HT40     0x08
+#define AR5416_OPFLAGS_N_5G_HT20     0x10
+#define AR5416_OPFLAGS_N_2G_HT20     0x20
+
+#define AR5416_EEP_NO_BACK_VER       0x1
+#define AR5416_EEP_VER               0xE
+#define AR5416_EEP_VER_MINOR_MASK    0x0FFF
+#define AR5416_EEP_MINOR_VER_2       0x2
+#define AR5416_EEP_MINOR_VER_3       0x3
+#define AR5416_EEP_MINOR_VER_7       0x7
+#define AR5416_EEP_MINOR_VER_9       0x9
+#define AR5416_EEP_MINOR_VER_16      0x10
+#define AR5416_EEP_MINOR_VER_17      0x11
+#define AR5416_EEP_MINOR_VER_19      0x13
+#define AR5416_EEP_MINOR_VER_20      0x14
+#define AR5416_EEP_MINOR_VER_21      0x15
+#define AR5416_EEP_MINOR_VER_22      0x16
+
+#define AR5416_NUM_5G_CAL_PIERS         8
+#define AR5416_NUM_2G_CAL_PIERS         4
+#define AR5416_NUM_5G_20_TARGET_POWERS  8
+#define AR5416_NUM_5G_40_TARGET_POWERS  8
+#define AR5416_NUM_2G_CCK_TARGET_POWERS 3
+#define AR5416_NUM_2G_20_TARGET_POWERS  4
+#define AR5416_NUM_2G_40_TARGET_POWERS  4
+#define AR5416_NUM_CTLS                 24
+#define AR5416_NUM_BAND_EDGES           8
+#define AR5416_NUM_PD_GAINS             4
+#define AR5416_PD_GAINS_IN_MASK         4
+#define AR5416_PD_GAIN_ICEPTS           5
+#define AR5416_NUM_PDADC_VALUES         128
+#define AR5416_BCHAN_UNUSED             0xFF
+#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64
+#define AR5416_MAX_CHAINS               3
+#define AR9300_MAX_CHAINS		3
+#define AR5416_PWR_TABLE_OFFSET_DB     -5
+
+/* Rx gain type values */
+#define AR5416_EEP_RXGAIN_23DB_BACKOFF     0
+#define AR5416_EEP_RXGAIN_13DB_BACKOFF     1
+#define AR5416_EEP_RXGAIN_ORIG             2
+
+/* Tx gain type values */
+#define AR5416_EEP_TXGAIN_ORIGINAL         0
+#define AR5416_EEP_TXGAIN_HIGH_POWER       1
+
+#define AR5416_EEP4K_START_LOC                64
+#define AR5416_EEP4K_NUM_2G_CAL_PIERS         3
+#define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3
+#define AR5416_EEP4K_NUM_2G_20_TARGET_POWERS  3
+#define AR5416_EEP4K_NUM_2G_40_TARGET_POWERS  3
+#define AR5416_EEP4K_NUM_CTLS                 12
+#define AR5416_EEP4K_NUM_BAND_EDGES           4
+#define AR5416_EEP4K_NUM_PD_GAINS             2
+#define AR5416_EEP4K_MAX_CHAINS               1
+
+#define AR9280_TX_GAIN_TABLE_SIZE 22
+
+#define AR9287_EEP_VER               0xE
+#define AR9287_EEP_VER_MINOR_MASK    0xFFF
+#define AR9287_EEP_MINOR_VER_1       0x1
+#define AR9287_EEP_MINOR_VER_2       0x2
+#define AR9287_EEP_MINOR_VER_3       0x3
+#define AR9287_EEP_MINOR_VER         AR9287_EEP_MINOR_VER_3
+#define AR9287_EEP_MINOR_VER_b       AR9287_EEP_MINOR_VER
+#define AR9287_EEP_NO_BACK_VER       AR9287_EEP_MINOR_VER_1
+
+#define AR9287_EEP_START_LOC            128
+#define AR9287_HTC_EEP_START_LOC        256
+#define AR9287_NUM_2G_CAL_PIERS         3
+#define AR9287_NUM_2G_CCK_TARGET_POWERS 3
+#define AR9287_NUM_2G_20_TARGET_POWERS  3
+#define AR9287_NUM_2G_40_TARGET_POWERS  3
+#define AR9287_NUM_CTLS              	12
+#define AR9287_NUM_BAND_EDGES        	4
+#define AR9287_PD_GAIN_ICEPTS           1
+#define AR9287_EEPMISC_BIG_ENDIAN       0x01
+#define AR9287_EEPMISC_WOW              0x02
+#define AR9287_MAX_CHAINS               2
+#define AR9287_ANT_16S                  32
+
+#define AR9287_DATA_SZ                  32
+
+#define AR9287_PWR_TABLE_OFFSET_DB  -5
+
+#define AR9287_CHECKSUM_LOCATION (AR9287_EEP_START_LOC + 1)
+
+#define CTL_EDGE_TPOWER(_ctl) ((_ctl) & 0x3f)
+#define CTL_EDGE_FLAGS(_ctl) (((_ctl) >> 6) & 0x03)
+
+#define LNA_CTL_BUF_MODE	BIT(0)
+#define LNA_CTL_ISEL_LO		BIT(1)
+#define LNA_CTL_ISEL_HI		BIT(2)
+#define LNA_CTL_BUF_IN		BIT(3)
+#define LNA_CTL_FEM_BAND	BIT(4)
+#define LNA_CTL_LOCAL_BIAS	BIT(5)
+#define LNA_CTL_FORCE_XPA	BIT(6)
+#define LNA_CTL_USE_ANT1	BIT(7)
+
+enum eeprom_param {
+	EEP_NFTHRESH_5,
+	EEP_NFTHRESH_2,
+	EEP_MAC_MSW,
+	EEP_MAC_MID,
+	EEP_MAC_LSW,
+	EEP_REG_0,
+	EEP_REG_1,
+	EEP_OP_CAP,
+	EEP_OP_MODE,
+	EEP_RF_SILENT,
+	EEP_OB_5,
+	EEP_DB_5,
+	EEP_OB_2,
+	EEP_DB_2,
+	EEP_MINOR_REV,
+	EEP_TX_MASK,
+	EEP_RX_MASK,
+	EEP_FSTCLK_5G,
+	EEP_RXGAIN_TYPE,
+	EEP_OL_PWRCTRL,
+	EEP_TXGAIN_TYPE,
+	EEP_RC_CHAIN_MASK,
+	EEP_DAC_HPWR_5G,
+	EEP_FRAC_N_5G,
+	EEP_DEV_TYPE,
+	EEP_TEMPSENSE_SLOPE,
+	EEP_TEMPSENSE_SLOPE_PAL_ON,
+	EEP_PWR_TABLE_OFFSET,
+	EEP_DRIVE_STRENGTH,
+	EEP_INTERNAL_REGULATOR,
+	EEP_SWREG,
+	EEP_PAPRD,
+	EEP_MODAL_VER,
+	EEP_ANT_DIV_CTL1,
+	EEP_CHAIN_MASK_REDUCE
+};
+
+enum ar5416_rates {
+	rate6mb, rate9mb, rate12mb, rate18mb,
+	rate24mb, rate36mb, rate48mb, rate54mb,
+	rate1l, rate2l, rate2s, rate5_5l,
+	rate5_5s, rate11l, rate11s, rateXr,
+	rateHt20_0, rateHt20_1, rateHt20_2, rateHt20_3,
+	rateHt20_4, rateHt20_5, rateHt20_6, rateHt20_7,
+	rateHt40_0, rateHt40_1, rateHt40_2, rateHt40_3,
+	rateHt40_4, rateHt40_5, rateHt40_6, rateHt40_7,
+	rateDupCck, rateDupOfdm, rateExtCck, rateExtOfdm,
+	Ar5416RateSize
+};
+
+enum ath9k_hal_freq_band {
+	ATH9K_HAL_FREQ_BAND_5GHZ = 0,
+	ATH9K_HAL_FREQ_BAND_2GHZ = 1
+};
+
+struct base_eep_header {
+	u16 length;
+	u16 checksum;
+	u16 version;
+	u8 opCapFlags;
+	u8 eepMisc;
+	u16 regDmn[2];
+	u8 macAddr[6];
+	u8 rxMask;
+	u8 txMask;
+	u16 rfSilent;
+	u16 blueToothOptions;
+	u16 deviceCap;
+	u32 binBuildNumber;
+	u8 deviceType;
+	u8 pwdclkind;
+	u8 fastClk5g;
+	u8 divChain;
+	u8 rxGainType;
+	u8 dacHiPwrMode_5G;
+	u8 openLoopPwrCntl;
+	u8 dacLpMode;
+	u8 txGainType;
+	u8 rcChainMask;
+	u8 desiredScaleCCK;
+	u8 pwr_table_offset;
+	u8 frac_n_5g;
+	u8 futureBase_3[21];
+} __attribute__((packed));
+
+struct base_eep_header_4k {
+	u16 length;
+	u16 checksum;
+	u16 version;
+	u8 opCapFlags;
+	u8 eepMisc;
+	u16 regDmn[2];
+	u8 macAddr[6];
+	u8 rxMask;
+	u8 txMask;
+	u16 rfSilent;
+	u16 blueToothOptions;
+	u16 deviceCap;
+	u32 binBuildNumber;
+	u8 deviceType;
+	u8 txGainType;
+} __attribute__((packed));
+
+
+struct spur_chan {
+	u16 spurChan;
+	u8 spurRangeLow;
+	u8 spurRangeHigh;
+} __attribute__((packed));
+
+struct modal_eep_header {
+	u32 antCtrlChain[AR5416_MAX_CHAINS];
+	u32 antCtrlCommon;
+	u8 antennaGainCh[AR5416_MAX_CHAINS];
+	u8 switchSettling;
+	u8 txRxAttenCh[AR5416_MAX_CHAINS];
+	u8 rxTxMarginCh[AR5416_MAX_CHAINS];
+	u8 adcDesiredSize;
+	u8 pgaDesiredSize;
+	u8 xlnaGainCh[AR5416_MAX_CHAINS];
+	u8 txEndToXpaOff;
+	u8 txEndToRxOn;
+	u8 txFrameToXpaOn;
+	u8 thresh62;
+	u8 noiseFloorThreshCh[AR5416_MAX_CHAINS];
+	u8 xpdGain;
+	u8 xpd;
+	u8 iqCalICh[AR5416_MAX_CHAINS];
+	u8 iqCalQCh[AR5416_MAX_CHAINS];
+	u8 pdGainOverlap;
+	u8 ob;
+	u8 db;
+	u8 xpaBiasLvl;
+	u8 pwrDecreaseFor2Chain;
+	u8 pwrDecreaseFor3Chain;
+	u8 txFrameToDataStart;
+	u8 txFrameToPaOn;
+	u8 ht40PowerIncForPdadc;
+	u8 bswAtten[AR5416_MAX_CHAINS];
+	u8 bswMargin[AR5416_MAX_CHAINS];
+	u8 swSettleHt40;
+	u8 xatten2Db[AR5416_MAX_CHAINS];
+	u8 xatten2Margin[AR5416_MAX_CHAINS];
+	u8 ob_ch1;
+	u8 db_ch1;
+	u8 lna_ctl;
+	u8 miscBits;
+	u16 xpaBiasLvlFreq[3];
+	u8 futureModal[6];
+
+	struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS];
+} __attribute__((packed));
+
+struct calDataPerFreqOpLoop {
+	u8 pwrPdg[2][5];
+	u8 vpdPdg[2][5];
+	u8 pcdac[2][5];
+	u8 empty[2][5];
+} __attribute__((packed));
+
+struct modal_eep_4k_header {
+	u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS];
+	u32 antCtrlCommon;
+	u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS];
+	u8 switchSettling;
+	u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS];
+	u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS];
+	u8 adcDesiredSize;
+	u8 pgaDesiredSize;
+	u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS];
+	u8 txEndToXpaOff;
+	u8 txEndToRxOn;
+	u8 txFrameToXpaOn;
+	u8 thresh62;
+	u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS];
+	u8 xpdGain;
+	u8 xpd;
+	u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS];
+	u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS];
+	u8 pdGainOverlap;
+#ifdef __BIG_ENDIAN_BITFIELD
+	u8 ob_1:4, ob_0:4;
+	u8 db1_1:4, db1_0:4;
+#else
+	u8 ob_0:4, ob_1:4;
+	u8 db1_0:4, db1_1:4;
+#endif
+	u8 xpaBiasLvl;
+	u8 txFrameToDataStart;
+	u8 txFrameToPaOn;
+	u8 ht40PowerIncForPdadc;
+	u8 bswAtten[AR5416_EEP4K_MAX_CHAINS];
+	u8 bswMargin[AR5416_EEP4K_MAX_CHAINS];
+	u8 swSettleHt40;
+	u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS];
+	u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS];
+#ifdef __BIG_ENDIAN_BITFIELD
+	u8 db2_1:4, db2_0:4;
+#else
+	u8 db2_0:4, db2_1:4;
+#endif
+	u8 version;
+#ifdef __BIG_ENDIAN_BITFIELD
+	u8 ob_3:4, ob_2:4;
+	u8 antdiv_ctl1:4, ob_4:4;
+	u8 db1_3:4, db1_2:4;
+	u8 antdiv_ctl2:4, db1_4:4;
+	u8 db2_2:4, db2_3:4;
+	u8 reserved:4, db2_4:4;
+#else
+	u8 ob_2:4, ob_3:4;
+	u8 ob_4:4, antdiv_ctl1:4;
+	u8 db1_2:4, db1_3:4;
+	u8 db1_4:4, antdiv_ctl2:4;
+	u8 db2_2:4, db2_3:4;
+	u8 db2_4:4, reserved:4;
+#endif
+	u8 tx_diversity;
+	u8 flc_pwr_thresh;
+	u8 bb_scale_smrt_antenna;
+#define EEP_4K_BB_DESIRED_SCALE_MASK	0x1f
+	u8 futureModal[1];
+	struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS];
+} __attribute__((packed));
+
+struct base_eep_ar9287_header {
+	u16 length;
+	u16 checksum;
+	u16 version;
+	u8 opCapFlags;
+	u8 eepMisc;
+	u16 regDmn[2];
+	u8 macAddr[6];
+	u8 rxMask;
+	u8 txMask;
+	u16 rfSilent;
+	u16 blueToothOptions;
+	u16 deviceCap;
+	u32 binBuildNumber;
+	u8 deviceType;
+	u8 openLoopPwrCntl;
+	int8_t pwrTableOffset;
+	int8_t tempSensSlope;
+	int8_t tempSensSlopePalOn;
+	u8 futureBase[29];
+} __attribute__((packed));
+
+struct modal_eep_ar9287_header {
+	u32 antCtrlChain[AR9287_MAX_CHAINS];
+	u32 antCtrlCommon;
+	int8_t antennaGainCh[AR9287_MAX_CHAINS];
+	u8 switchSettling;
+	u8 txRxAttenCh[AR9287_MAX_CHAINS];
+	u8 rxTxMarginCh[AR9287_MAX_CHAINS];
+	int8_t adcDesiredSize;
+	u8 txEndToXpaOff;
+	u8 txEndToRxOn;
+	u8 txFrameToXpaOn;
+	u8 thresh62;
+	int8_t noiseFloorThreshCh[AR9287_MAX_CHAINS];
+	u8 xpdGain;
+	u8 xpd;
+	int8_t iqCalICh[AR9287_MAX_CHAINS];
+	int8_t iqCalQCh[AR9287_MAX_CHAINS];
+	u8 pdGainOverlap;
+	u8 xpaBiasLvl;
+	u8 txFrameToDataStart;
+	u8 txFrameToPaOn;
+	u8 ht40PowerIncForPdadc;
+	u8 bswAtten[AR9287_MAX_CHAINS];
+	u8 bswMargin[AR9287_MAX_CHAINS];
+	u8 swSettleHt40;
+	u8 version;
+	u8 db1;
+	u8 db2;
+	u8 ob_cck;
+	u8 ob_psk;
+	u8 ob_qam;
+	u8 ob_pal_off;
+	u8 futureModal[30];
+	struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS];
+} __attribute__((packed));
+
+struct cal_data_per_freq {
+	u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
+	u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
+} __attribute__((packed));
+
+struct cal_data_per_freq_4k {
+	u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
+	u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
+} __attribute__((packed));
+
+struct cal_target_power_leg {
+	u8 bChannel;
+	u8 tPow2x[4];
+} __attribute__((packed));
+
+struct cal_target_power_ht {
+	u8 bChannel;
+	u8 tPow2x[8];
+} __attribute__((packed));
+
+struct cal_ctl_edges {
+	u8 bChannel;
+	u8 ctl;
+} __attribute__((packed));
+
+struct cal_data_op_loop_ar9287 {
+	u8 pwrPdg[2][5];
+	u8 vpdPdg[2][5];
+	u8 pcdac[2][5];
+	u8 empty[2][5];
+} __attribute__((packed));
+
+struct cal_data_per_freq_ar9287 {
+	u8 pwrPdg[AR5416_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS];
+	u8 vpdPdg[AR5416_NUM_PD_GAINS][AR9287_PD_GAIN_ICEPTS];
+} __attribute__((packed));
+
+union cal_data_per_freq_ar9287_u {
+	struct cal_data_op_loop_ar9287 calDataOpen;
+	struct cal_data_per_freq_ar9287 calDataClose;
+} __attribute__((packed));
+
+struct cal_ctl_data_ar9287 {
+	struct cal_ctl_edges
+	ctlEdges[AR9287_MAX_CHAINS][AR9287_NUM_BAND_EDGES];
+} __attribute__((packed));
+
+struct cal_ctl_data {
+	struct cal_ctl_edges
+	ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
+} __attribute__((packed));
+
+struct cal_ctl_data_4k {
+	struct cal_ctl_edges
+	ctlEdges[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_BAND_EDGES];
+} __attribute__((packed));
+
+struct ar5416_eeprom_def {
+	struct base_eep_header baseEepHeader;
+	u8 custData[64];
+	struct modal_eep_header modalHeader[2];
+	u8 calFreqPier5G[AR5416_NUM_5G_CAL_PIERS];
+	u8 calFreqPier2G[AR5416_NUM_2G_CAL_PIERS];
+	struct cal_data_per_freq
+	 calPierData5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS];
+	struct cal_data_per_freq
+	 calPierData2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS];
+	struct cal_target_power_leg
+	 calTargetPower5G[AR5416_NUM_5G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	 calTargetPower5GHT20[AR5416_NUM_5G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	 calTargetPower5GHT40[AR5416_NUM_5G_40_TARGET_POWERS];
+	struct cal_target_power_leg
+	 calTargetPowerCck[AR5416_NUM_2G_CCK_TARGET_POWERS];
+	struct cal_target_power_leg
+	 calTargetPower2G[AR5416_NUM_2G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	 calTargetPower2GHT20[AR5416_NUM_2G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	 calTargetPower2GHT40[AR5416_NUM_2G_40_TARGET_POWERS];
+	u8 ctlIndex[AR5416_NUM_CTLS];
+	struct cal_ctl_data ctlData[AR5416_NUM_CTLS];
+	u8 padding;
+} __attribute__((packed));
+
+struct ar5416_eeprom_4k {
+	struct base_eep_header_4k baseEepHeader;
+	u8 custData[20];
+	struct modal_eep_4k_header modalHeader;
+	u8 calFreqPier2G[AR5416_EEP4K_NUM_2G_CAL_PIERS];
+	struct cal_data_per_freq_4k
+	calPierData2G[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_2G_CAL_PIERS];
+	struct cal_target_power_leg
+	calTargetPowerCck[AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS];
+	struct cal_target_power_leg
+	calTargetPower2G[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	calTargetPower2GHT20[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	calTargetPower2GHT40[AR5416_EEP4K_NUM_2G_40_TARGET_POWERS];
+	u8 ctlIndex[AR5416_EEP4K_NUM_CTLS];
+	struct cal_ctl_data_4k ctlData[AR5416_EEP4K_NUM_CTLS];
+	u8 padding;
+} __attribute__((packed));
+
+struct ar9287_eeprom {
+	struct base_eep_ar9287_header baseEepHeader;
+	u8 custData[AR9287_DATA_SZ];
+	struct modal_eep_ar9287_header modalHeader;
+	u8 calFreqPier2G[AR9287_NUM_2G_CAL_PIERS];
+	union cal_data_per_freq_ar9287_u
+	calPierData2G[AR9287_MAX_CHAINS][AR9287_NUM_2G_CAL_PIERS];
+	struct cal_target_power_leg
+	calTargetPowerCck[AR9287_NUM_2G_CCK_TARGET_POWERS];
+	struct cal_target_power_leg
+	calTargetPower2G[AR9287_NUM_2G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	calTargetPower2GHT20[AR9287_NUM_2G_20_TARGET_POWERS];
+	struct cal_target_power_ht
+	calTargetPower2GHT40[AR9287_NUM_2G_40_TARGET_POWERS];
+	u8 ctlIndex[AR9287_NUM_CTLS];
+	struct cal_ctl_data_ar9287 ctlData[AR9287_NUM_CTLS];
+	u8 padding;
+} __attribute__((packed));
+
+enum reg_ext_bitmap {
+	REG_EXT_FCC_MIDBAND = 0,
+	REG_EXT_JAPAN_MIDBAND = 1,
+	REG_EXT_FCC_DFS_HT40 = 2,
+	REG_EXT_JAPAN_NONDFS_HT40 = 3,
+	REG_EXT_JAPAN_DFS_HT40 = 4
+};
+
+struct ath9k_country_entry {
+	u16 countryCode;
+	u16 regDmnEnum;
+	u16 regDmn5G;
+	u16 regDmn2G;
+	u8 isMultidomain;
+	u8 iso[3];
+};
+
+struct eeprom_ops {
+	int (*check_eeprom)(struct ath_hw *hw);
+	u32 (*get_eeprom)(struct ath_hw *hw, enum eeprom_param param);
+	int (*fill_eeprom)(struct ath_hw *hw);
+	int (*get_eeprom_ver)(struct ath_hw *hw);
+	int (*get_eeprom_rev)(struct ath_hw *hw);
+	void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan);
+	void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan);
+	void (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan,
+			   u16 cfgCtl, u8 twiceAntennaReduction,
+			   u8 twiceMaxRegulatoryPower, u8 powerLimit,
+			   int test);
+	u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, int is2GHz);
+};
+
+void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val);
+void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
+			       u32 shift, u32 val);
+int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
+			     int16_t targetLeft,
+			     int16_t targetRight);
+int ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
+				    u16 *indexL, u16 *indexR);
+int ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data);
+void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
+				  int eep_start_loc, int size);
+void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
+			     u8 *pVpdList, u16 numIntercepts,
+			     u8 *pRetVpdList);
+void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
+				       struct ath9k_channel *chan,
+				       struct cal_target_power_leg *powInfo,
+				       u16 numChannels,
+				       struct cal_target_power_leg *pNewPower,
+				       u16 numRates, int isExtTarget);
+void ath9k_hw_get_target_powers(struct ath_hw *ah,
+				struct ath9k_channel *chan,
+				struct cal_target_power_ht *powInfo,
+				u16 numChannels,
+				struct cal_target_power_ht *pNewPower,
+				u16 numRates, int isHt40Target);
+u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
+				int is2GHz, int num_band_edges);
+void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah);
+int ath9k_hw_eeprom_init(struct ath_hw *ah);
+
+void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
+				struct ath9k_channel *chan,
+				void *pRawDataSet,
+				u8 *bChans, u16 availPiers,
+				u16 tPdGainOverlap,
+				u16 *pPdGainBoundaries, u8 *pPDADCValues,
+				u16 numXpdGains);
+
+#define ar5416_get_ntxchains(_txchainmask)			\
+	(((_txchainmask >> 2) & 1) +                            \
+	 ((_txchainmask >> 1) & 1) + (_txchainmask & 1))
+
+extern const struct eeprom_ops eep_def_ops;
+extern const struct eeprom_ops eep_4k_ops;
+extern const struct eeprom_ops eep_ar9287_ops;
+extern const struct eeprom_ops eep_ar9287_ops;
+extern const struct eeprom_ops eep_ar9300_ops;
+
+#endif /* EEPROM_H */
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/hw-ops.h b/roms/ipxe/src/drivers/net/ath/ath9k/hw-ops.h
new file mode 100644
index 0000000000000000000000000000000000000000..65cff3b08f9e71f8ad2515670b824f15061fe932
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/hw-ops.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ATH9K_HW_OPS_H
+#define ATH9K_HW_OPS_H
+
+#include "hw.h"
+
+/* Hardware core and driver accessible callbacks */
+
+static inline void ath9k_hw_configpcipowersave(struct ath_hw *ah,
+					       int restore,
+					       int power_off)
+{
+	ath9k_hw_ops(ah)->config_pci_powersave(ah, restore, power_off);
+}
+
+static inline void ath9k_hw_rxena(struct ath_hw *ah)
+{
+	ath9k_hw_ops(ah)->rx_enable(ah);
+}
+
+static inline void ath9k_hw_set_desc_link(struct ath_hw *ah, void *ds,
+					  u32 link)
+{
+	ath9k_hw_ops(ah)->set_desc_link(ds, link);
+}
+
+static inline void ath9k_hw_get_desc_link(struct ath_hw *ah, void *ds,
+					  u32 **link)
+{
+	ath9k_hw_ops(ah)->get_desc_link(ds, link);
+}
+static inline int ath9k_hw_calibrate(struct ath_hw *ah,
+				      struct ath9k_channel *chan,
+				      u8 rxchainmask,
+				      int longcal)
+{
+	return ath9k_hw_ops(ah)->calibrate(ah, chan, rxchainmask, longcal);
+}
+
+static inline int ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
+{
+	return ath9k_hw_ops(ah)->get_isr(ah, masked);
+}
+
+static inline void ath9k_hw_filltxdesc(struct ath_hw *ah, void *ds, u32 seglen,
+				  int is_firstseg, int is_lastseg,
+				  const void *ds0, u32 buf_addr,
+				  unsigned int qcu)
+{
+	ath9k_hw_ops(ah)->fill_txdesc(ah, ds, seglen, is_firstseg, is_lastseg,
+				      ds0, buf_addr, qcu);
+}
+
+static inline int ath9k_hw_txprocdesc(struct ath_hw *ah, void *ds,
+				      struct ath_tx_status *ts)
+{
+	return ath9k_hw_ops(ah)->proc_txdesc(ah, ds, ts);
+}
+
+static inline void ath9k_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
+					  u32 pktLen, enum ath9k_pkt_type type,
+					  u32 txPower, u32 keyIx,
+					  enum ath9k_key_type keyType,
+					  u32 flags)
+{
+	ath9k_hw_ops(ah)->set11n_txdesc(ah, ds, pktLen, type, txPower, keyIx,
+				      keyType, flags);
+}
+
+static inline void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
+					void *lastds,
+					u32 durUpdateEn, u32 rtsctsRate,
+					u32 rtsctsDuration,
+					struct ath9k_11n_rate_series series[],
+					u32 nseries, u32 flags)
+{
+	ath9k_hw_ops(ah)->set11n_ratescenario(ah, ds, lastds, durUpdateEn,
+					    rtsctsRate, rtsctsDuration, series,
+					    nseries, flags);
+}
+
+static inline void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, void *ds,
+					u32 aggrLen)
+{
+	ath9k_hw_ops(ah)->set11n_aggr_first(ah, ds, aggrLen);
+}
+
+static inline void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds,
+					       u32 numDelims)
+{
+	ath9k_hw_ops(ah)->set11n_aggr_middle(ah, ds, numDelims);
+}
+
+static inline void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, void *ds)
+{
+	ath9k_hw_ops(ah)->set11n_aggr_last(ah, ds);
+}
+
+static inline void ath9k_hw_clr11n_aggr(struct ath_hw *ah, void *ds)
+{
+	ath9k_hw_ops(ah)->clr11n_aggr(ah, ds);
+}
+
+static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, int val)
+{
+	ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val);
+}
+
+static inline void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
+		struct ath_hw_antcomb_conf *antconf)
+{
+	ath9k_hw_ops(ah)->antdiv_comb_conf_get(ah, antconf);
+}
+
+static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
+		struct ath_hw_antcomb_conf *antconf)
+{
+	ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf);
+}
+
+/* Private hardware call ops */
+
+/* PHY ops */
+
+static inline int ath9k_hw_rf_set_freq(struct ath_hw *ah,
+				       struct ath9k_channel *chan)
+{
+	return ath9k_hw_private_ops(ah)->rf_set_freq(ah, chan);
+}
+
+static inline void ath9k_hw_spur_mitigate_freq(struct ath_hw *ah,
+					       struct ath9k_channel *chan)
+{
+	ath9k_hw_private_ops(ah)->spur_mitigate_freq(ah, chan);
+}
+
+static inline int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah)
+{
+	if (!ath9k_hw_private_ops(ah)->rf_alloc_ext_banks)
+		return 0;
+
+	return ath9k_hw_private_ops(ah)->rf_alloc_ext_banks(ah);
+}
+
+static inline void ath9k_hw_rf_free_ext_banks(struct ath_hw *ah)
+{
+	if (!ath9k_hw_private_ops(ah)->rf_free_ext_banks)
+		return;
+
+	ath9k_hw_private_ops(ah)->rf_free_ext_banks(ah);
+}
+
+static inline int ath9k_hw_set_rf_regs(struct ath_hw *ah,
+					struct ath9k_channel *chan,
+					u16 modesIndex)
+{
+	if (!ath9k_hw_private_ops(ah)->set_rf_regs)
+		return 1;
+
+	return ath9k_hw_private_ops(ah)->set_rf_regs(ah, chan, modesIndex);
+}
+
+static inline void ath9k_hw_init_bb(struct ath_hw *ah,
+				    struct ath9k_channel *chan)
+{
+	return ath9k_hw_private_ops(ah)->init_bb(ah, chan);
+}
+
+static inline void ath9k_hw_set_channel_regs(struct ath_hw *ah,
+					     struct ath9k_channel *chan)
+{
+	return ath9k_hw_private_ops(ah)->set_channel_regs(ah, chan);
+}
+
+static inline int ath9k_hw_process_ini(struct ath_hw *ah,
+					struct ath9k_channel *chan)
+{
+	return ath9k_hw_private_ops(ah)->process_ini(ah, chan);
+}
+
+static inline void ath9k_olc_init(struct ath_hw *ah)
+{
+	if (!ath9k_hw_private_ops(ah)->olc_init)
+		return;
+
+	return ath9k_hw_private_ops(ah)->olc_init(ah);
+}
+
+static inline void ath9k_hw_set_rfmode(struct ath_hw *ah,
+				       struct ath9k_channel *chan)
+{
+	return ath9k_hw_private_ops(ah)->set_rfmode(ah, chan);
+}
+
+static inline void ath9k_hw_mark_phy_inactive(struct ath_hw *ah)
+{
+	return ath9k_hw_private_ops(ah)->mark_phy_inactive(ah);
+}
+
+static inline void ath9k_hw_set_delta_slope(struct ath_hw *ah,
+					    struct ath9k_channel *chan)
+{
+	return ath9k_hw_private_ops(ah)->set_delta_slope(ah, chan);
+}
+
+static inline int ath9k_hw_rfbus_req(struct ath_hw *ah)
+{
+	return ath9k_hw_private_ops(ah)->rfbus_req(ah);
+}
+
+static inline void ath9k_hw_rfbus_done(struct ath_hw *ah)
+{
+	return ath9k_hw_private_ops(ah)->rfbus_done(ah);
+}
+
+static inline void ath9k_hw_restore_chainmask(struct ath_hw *ah)
+{
+	if (!ath9k_hw_private_ops(ah)->restore_chainmask)
+		return;
+
+	return ath9k_hw_private_ops(ah)->restore_chainmask(ah);
+}
+
+static inline void ath9k_hw_set_diversity(struct ath_hw *ah, int value)
+{
+	return ath9k_hw_private_ops(ah)->set_diversity(ah, value);
+}
+
+static inline int ath9k_hw_ani_control(struct ath_hw *ah,
+					enum ath9k_ani_cmd cmd, int param)
+{
+	return ath9k_hw_private_ops(ah)->ani_control(ah, cmd, param);
+}
+
+static inline void ath9k_hw_do_getnf(struct ath_hw *ah,
+				     int16_t nfarray[NUM_NF_READINGS])
+{
+	ath9k_hw_private_ops(ah)->do_getnf(ah, nfarray);
+}
+
+static inline int ath9k_hw_init_cal(struct ath_hw *ah,
+				     struct ath9k_channel *chan)
+{
+	return ath9k_hw_private_ops(ah)->init_cal(ah, chan);
+}
+
+static inline void ath9k_hw_setup_calibration(struct ath_hw *ah,
+					      struct ath9k_cal_list *currCal)
+{
+	ath9k_hw_private_ops(ah)->setup_calibration(ah, currCal);
+}
+
+#endif /* ATH9K_HW_OPS_H */
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/hw.h b/roms/ipxe/src/drivers/net/ath/ath9k/hw.h
new file mode 100644
index 0000000000000000000000000000000000000000..c10df3883487f6ae3d7fd0bb080b0a61047ae17b
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/hw.h
@@ -0,0 +1,995 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HW_H
+#define HW_H
+
+#include <errno.h>
+
+#include "mac.h"
+#include "ani.h"
+#include "eeprom.h"
+#include "calib.h"
+#include "reg.h"
+#include "phy.h"
+
+#include "../regd.h"
+
+/* Keep all ath9k files under one errfile ID */
+#undef ERRFILE
+#define ERRFILE ERRFILE_ath9k
+
+#define ATHEROS_VENDOR_ID	0x168c
+
+#define AR5416_DEVID_PCI	0x0023
+#define AR5416_DEVID_PCIE	0x0024
+#define AR9160_DEVID_PCI	0x0027
+#define AR9280_DEVID_PCI	0x0029
+#define AR9280_DEVID_PCIE	0x002a
+#define AR9285_DEVID_PCIE	0x002b
+#define AR2427_DEVID_PCIE	0x002c
+#define AR9287_DEVID_PCI	0x002d
+#define AR9287_DEVID_PCIE	0x002e
+#define AR9300_DEVID_PCIE	0x0030
+#define AR9300_DEVID_AR9340	0x0031
+#define AR9300_DEVID_AR9485_PCIE 0x0032
+
+#define AR5416_AR9100_DEVID	0x000b
+
+#define	AR_SUBVENDOR_ID_NOG	0x0e11
+#define AR_SUBVENDOR_ID_NEW_A	0x7065
+#define AR5416_MAGIC		0x19641014
+
+#define AR9280_COEX2WIRE_SUBSYSID	0x309b
+#define AT9285_COEX3WIRE_SA_SUBSYSID	0x30aa
+#define AT9285_COEX3WIRE_DA_SUBSYSID	0x30ab
+
+#define AR9300_NUM_BT_WEIGHTS   4
+#define AR9300_NUM_WLAN_WEIGHTS 4
+
+#define ATH_AMPDU_LIMIT_MAX        (64 * 1024 - 1)
+
+#define	ATH_DEFAULT_NOISE_FLOOR -95
+
+#define ATH9K_RSSI_BAD			-128
+
+#define ATH9K_NUM_CHANNELS	38
+
+/* Register read/write primitives */
+#define REG_WRITE(_ah, _reg, _val) \
+	(_ah)->reg_ops.write((_ah), (_val), (_reg))
+
+#define REG_READ(_ah, _reg) \
+	(_ah)->reg_ops.read((_ah), (_reg))
+
+#define REG_READ_MULTI(_ah, _addr, _val, _cnt)		\
+	(_ah)->reg_ops.multi_read((_ah), (_addr), (_val), (_cnt))
+
+#define REG_RMW(_ah, _reg, _set, _clr) \
+	(_ah)->reg_ops.rmw((_ah), (_reg), (_set), (_clr))
+
+#define ENABLE_REGWRITE_BUFFER(_ah)					\
+	do {								\
+		if ((_ah)->reg_ops.enable_write_buffer)	\
+			(_ah)->reg_ops.enable_write_buffer((_ah)); \
+	} while (0)
+
+#define REGWRITE_BUFFER_FLUSH(_ah)					\
+	do {								\
+		if ((_ah)->reg_ops.write_flush)		\
+			(_ah)->reg_ops.write_flush((_ah));	\
+	} while (0)
+
+#define SM(_v, _f)  (((_v) << _f##_S) & _f)
+#define MS(_v, _f)  (((_v) & _f) >> _f##_S)
+#define REG_RMW_FIELD(_a, _r, _f, _v) \
+	REG_RMW(_a, _r, (((_v) << _f##_S) & _f), (_f))
+#define REG_READ_FIELD(_a, _r, _f) \
+	(((REG_READ(_a, _r) & _f) >> _f##_S))
+#define REG_SET_BIT(_a, _r, _f) \
+	REG_RMW(_a, _r, (_f), 0)
+#define REG_CLR_BIT(_a, _r, _f) \
+	REG_RMW(_a, _r, 0, (_f))
+
+#define DO_DELAY(x) do {					\
+		if (((++(x) % 64) == 0) &&			\
+		    (ath9k_hw_common(ah)->bus_ops->ath_bus_type	\
+			!= ATH_USB))				\
+			udelay(1);				\
+	} while (0)
+
+#define REG_WRITE_ARRAY(iniarray, column, regWr) \
+	ath9k_hw_write_array(ah, iniarray, column, &(regWr))
+
+#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT             0
+#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
+#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED     2
+#define AR_GPIO_OUTPUT_MUX_AS_TX_FRAME           3
+#define AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL  4
+#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED    5
+#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED      6
+
+#define AR_GPIOD_MASK               0x00001FFF
+#define AR_GPIO_BIT(_gpio)          (1 << (_gpio))
+
+#define BASE_ACTIVATE_DELAY         100
+#define RTC_PLL_SETTLE_DELAY        (AR_SREV_9340(ah) ? 1000 : 100)
+#define COEF_SCALE_S                24
+#define HT40_CHANNEL_CENTER_SHIFT   10
+
+#define ATH9K_ANTENNA0_CHAINMASK    0x1
+#define ATH9K_ANTENNA1_CHAINMASK    0x2
+
+#define ATH9K_NUM_DMA_DEBUG_REGS    8
+#define ATH9K_NUM_QUEUES            10
+
+#define MAX_RATE_POWER              63
+#define AH_WAIT_TIMEOUT             100000 /* (us) */
+#define AH_TSF_WRITE_TIMEOUT        100    /* (us) */
+#define AH_TIME_QUANTUM             10
+#define AR_KEYTABLE_SIZE            128
+#define POWER_UP_TIME               10000
+#define SPUR_RSSI_THRESH            40
+
+#define CAB_TIMEOUT_VAL             10
+#define BEACON_TIMEOUT_VAL          10
+#define MIN_BEACON_TIMEOUT_VAL      1
+#define SLEEP_SLOP                  3
+
+#define INIT_CONFIG_STATUS          0x00000000
+#define INIT_RSSI_THR               0x00000700
+#define INIT_BCON_CNTRL_REG         0x00000000
+
+#define TU_TO_USEC(_tu)             ((_tu) << 10)
+
+#define ATH9K_HW_RX_HP_QDEPTH	16
+#define ATH9K_HW_RX_LP_QDEPTH	128
+
+#define PAPRD_GAIN_TABLE_ENTRIES    32
+#define PAPRD_TABLE_SZ              24
+
+enum ath_hw_txq_subtype {
+	ATH_TXQ_AC_BE = 0,
+};
+
+enum ath_ini_subsys {
+	ATH_INI_PRE = 0,
+	ATH_INI_CORE,
+	ATH_INI_POST,
+	ATH_INI_NUM_SPLIT,
+};
+
+enum ath9k_hw_caps {
+	ATH9K_HW_CAP_HT                         = BIT(0),
+	ATH9K_HW_CAP_RFSILENT                   = BIT(1),
+	ATH9K_HW_CAP_CST                        = BIT(2),
+	ATH9K_HW_CAP_AUTOSLEEP                  = BIT(4),
+	ATH9K_HW_CAP_4KB_SPLITTRANS             = BIT(5),
+	ATH9K_HW_CAP_EDMA			= BIT(6),
+	ATH9K_HW_CAP_RAC_SUPPORTED		= BIT(7),
+	ATH9K_HW_CAP_LDPC			= BIT(8),
+	ATH9K_HW_CAP_FASTCLOCK			= BIT(9),
+	ATH9K_HW_CAP_SGI_20			= BIT(10),
+	ATH9K_HW_CAP_PAPRD			= BIT(11),
+	ATH9K_HW_CAP_ANT_DIV_COMB		= BIT(12),
+	ATH9K_HW_CAP_2GHZ			= BIT(13),
+	ATH9K_HW_CAP_5GHZ			= BIT(14),
+	ATH9K_HW_CAP_APM			= BIT(15),
+};
+
+struct ath9k_hw_capabilities {
+	u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */
+	u16 rts_aggr_limit;
+	u8 tx_chainmask;
+	u8 rx_chainmask;
+	u8 max_txchains;
+	u8 max_rxchains;
+	u8 num_gpio_pins;
+	u8 rx_hp_qdepth;
+	u8 rx_lp_qdepth;
+	u8 rx_status_len;
+	u8 tx_desc_len;
+	u8 txs_len;
+	u16 pcie_lcr_offset;
+	int pcie_lcr_extsync_en;
+};
+
+struct ath9k_ops_config {
+	int dma_beacon_response_time;
+	int sw_beacon_response_time;
+	int additional_swba_backoff;
+	int ack_6mb;
+	u32 cwm_ignore_extcca;
+	u8 pcie_powersave_enable;
+	int pcieSerDesWrite;
+	u8 pcie_clock_req;
+	u32 pcie_waen;
+	u8 analog_shiftreg;
+	u8 paprd_disable;
+	u32 ofdm_trig_low;
+	u32 ofdm_trig_high;
+	u32 cck_trig_high;
+	u32 cck_trig_low;
+	u32 enable_ani;
+	int serialize_regmode;
+	int rx_intr_mitigation;
+	int tx_intr_mitigation;
+#define SPUR_DISABLE        	0
+#define SPUR_ENABLE_IOCTL   	1
+#define SPUR_ENABLE_EEPROM  	2
+#define AR_SPUR_5413_1      	1640
+#define AR_SPUR_5413_2      	1200
+#define AR_NO_SPUR      	0x8000
+#define AR_BASE_FREQ_2GHZ   	2300
+#define AR_BASE_FREQ_5GHZ   	4900
+#define AR_SPUR_FEEQ_BOUND_HT40 19
+#define AR_SPUR_FEEQ_BOUND_HT20 10
+	int spurmode;
+	u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
+	u8 max_txtrig_level;
+	u16 ani_poll_interval; /* ANI poll interval in ms */
+};
+
+enum ath9k_int {
+	ATH9K_INT_RX = 0x00000001,
+	ATH9K_INT_RXDESC = 0x00000002,
+	ATH9K_INT_RXHP = 0x00000001,
+	ATH9K_INT_RXLP = 0x00000002,
+	ATH9K_INT_RXNOFRM = 0x00000008,
+	ATH9K_INT_RXEOL = 0x00000010,
+	ATH9K_INT_RXORN = 0x00000020,
+	ATH9K_INT_TX = 0x00000040,
+	ATH9K_INT_TXDESC = 0x00000080,
+	ATH9K_INT_TIM_TIMER = 0x00000100,
+	ATH9K_INT_BB_WATCHDOG = 0x00000400,
+	ATH9K_INT_TXURN = 0x00000800,
+	ATH9K_INT_MIB = 0x00001000,
+	ATH9K_INT_RXPHY = 0x00004000,
+	ATH9K_INT_RXKCM = 0x00008000,
+	ATH9K_INT_SWBA = 0x00010000,
+	ATH9K_INT_BMISS = 0x00040000,
+	ATH9K_INT_BNR = 0x00100000,
+	ATH9K_INT_TIM = 0x00200000,
+	ATH9K_INT_DTIM = 0x00400000,
+	ATH9K_INT_DTIMSYNC = 0x00800000,
+	ATH9K_INT_GPIO = 0x01000000,
+	ATH9K_INT_CABEND = 0x02000000,
+	ATH9K_INT_TSFOOR = 0x04000000,
+	ATH9K_INT_GENTIMER = 0x08000000,
+	ATH9K_INT_CST = 0x10000000,
+	ATH9K_INT_GTT = 0x20000000,
+	ATH9K_INT_FATAL = 0x40000000,
+	ATH9K_INT_GLOBAL = 0x80000000,
+	ATH9K_INT_BMISC = ATH9K_INT_TIM |
+		ATH9K_INT_DTIM |
+		ATH9K_INT_DTIMSYNC |
+		ATH9K_INT_TSFOOR |
+		ATH9K_INT_CABEND,
+	ATH9K_INT_COMMON = ATH9K_INT_RXNOFRM |
+		ATH9K_INT_RXDESC |
+		ATH9K_INT_RXEOL |
+		ATH9K_INT_RXORN |
+		ATH9K_INT_TXURN |
+		ATH9K_INT_TXDESC |
+		ATH9K_INT_MIB |
+		ATH9K_INT_RXPHY |
+		ATH9K_INT_RXKCM |
+		ATH9K_INT_SWBA |
+		ATH9K_INT_BMISS |
+		ATH9K_INT_GPIO,
+	ATH9K_INT_NOCARD = 0xffffffff
+};
+
+#define CHANNEL_CW_INT    0x00002
+#define CHANNEL_CCK       0x00020
+#define CHANNEL_OFDM      0x00040
+#define CHANNEL_2GHZ      0x00080
+#define CHANNEL_5GHZ      0x00100
+#define CHANNEL_PASSIVE   0x00200
+#define CHANNEL_DYN       0x00400
+#define CHANNEL_HALF      0x04000
+#define CHANNEL_QUARTER   0x08000
+#define CHANNEL_HT20      0x10000
+#define CHANNEL_HT40PLUS  0x20000
+#define CHANNEL_HT40MINUS 0x40000
+
+#define CHANNEL_A           (CHANNEL_5GHZ|CHANNEL_OFDM)
+#define CHANNEL_B           (CHANNEL_2GHZ|CHANNEL_CCK)
+#define CHANNEL_G           (CHANNEL_2GHZ|CHANNEL_OFDM)
+#define CHANNEL_G_HT20      (CHANNEL_2GHZ|CHANNEL_HT20)
+#define CHANNEL_A_HT20      (CHANNEL_5GHZ|CHANNEL_HT20)
+#define CHANNEL_G_HT40PLUS  (CHANNEL_2GHZ|CHANNEL_HT40PLUS)
+#define CHANNEL_G_HT40MINUS (CHANNEL_2GHZ|CHANNEL_HT40MINUS)
+#define CHANNEL_A_HT40PLUS  (CHANNEL_5GHZ|CHANNEL_HT40PLUS)
+#define CHANNEL_A_HT40MINUS (CHANNEL_5GHZ|CHANNEL_HT40MINUS)
+#define CHANNEL_ALL				\
+	(CHANNEL_OFDM|				\
+	 CHANNEL_CCK|				\
+	 CHANNEL_2GHZ |				\
+	 CHANNEL_5GHZ |				\
+	 CHANNEL_HT20 |				\
+	 CHANNEL_HT40PLUS |			\
+	 CHANNEL_HT40MINUS)
+
+struct ath9k_hw_cal_data {
+	u16 channel;
+	u32 channelFlags;
+	int32_t CalValid;
+	int8_t iCoff;
+	int8_t qCoff;
+	int paprd_done;
+	int nfcal_pending;
+	int nfcal_interference;
+	u16 small_signal_gain[AR9300_MAX_CHAINS];
+	u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];
+	struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
+};
+
+struct ath9k_channel {
+	struct net80211_channel *chan;
+	struct ar5416AniState ani;
+	u16 channel;
+	u32 channelFlags;
+	u32 chanmode;
+	s16 noisefloor;
+};
+
+#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
+       (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \
+       (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \
+       (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS))
+#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0)
+#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0)
+#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0)
+#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0)
+#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0)
+#define IS_CHAN_A_FAST_CLOCK(_ah, _c)			\
+	((((_c)->channelFlags & CHANNEL_5GHZ) != 0) &&	\
+	 ((_ah)->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK))
+
+/* These macros check chanmode and not channelFlags */
+#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B)
+#define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) ||	\
+			  ((_c)->chanmode == CHANNEL_G_HT20))
+#define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) ||	\
+			  ((_c)->chanmode == CHANNEL_A_HT40MINUS) ||	\
+			  ((_c)->chanmode == CHANNEL_G_HT40PLUS) ||	\
+			  ((_c)->chanmode == CHANNEL_G_HT40MINUS))
+#define IS_CHAN_HT(_c) (IS_CHAN_HT20((_c)) || IS_CHAN_HT40((_c)))
+
+enum ath9k_power_mode {
+	ATH9K_PM_AWAKE = 0,
+	ATH9K_PM_FULL_SLEEP,
+	ATH9K_PM_NETWORK_SLEEP,
+	ATH9K_PM_UNDEFINED
+};
+
+enum ath9k_tp_scale {
+	ATH9K_TP_SCALE_MAX = 0,
+	ATH9K_TP_SCALE_50,
+	ATH9K_TP_SCALE_25,
+	ATH9K_TP_SCALE_12,
+	ATH9K_TP_SCALE_MIN
+};
+
+enum ser_reg_mode {
+	SER_REG_MODE_OFF = 0,
+	SER_REG_MODE_ON = 1,
+	SER_REG_MODE_AUTO = 2,
+};
+
+enum ath9k_rx_qtype {
+	ATH9K_RX_QUEUE_HP,
+	ATH9K_RX_QUEUE_LP,
+	ATH9K_RX_QUEUE_MAX,
+};
+
+struct ath9k_beacon_state {
+	u32 bs_nexttbtt;
+	u32 bs_nextdtim;
+	u32 bs_intval;
+#define ATH9K_BEACON_PERIOD       0x0000ffff
+#define ATH9K_TSFOOR_THRESHOLD    0x00004240 /* 16k us */
+	u32 bs_dtimperiod;
+	u16 bs_cfpperiod;
+	u16 bs_cfpmaxduration;
+	u32 bs_cfpnext;
+	u16 bs_timoffset;
+	u16 bs_bmissthreshold;
+	u32 bs_sleepduration;
+	u32 bs_tsfoor_threshold;
+};
+
+struct chan_centers {
+	u16 synth_center;
+	u16 ctl_center;
+	u16 ext_center;
+};
+
+enum {
+	ATH9K_RESET_POWER_ON,
+	ATH9K_RESET_WARM,
+	ATH9K_RESET_COLD,
+};
+
+struct ath9k_hw_version {
+	u32 magic;
+	u16 devid;
+	u16 subvendorid;
+	u32 macVersion;
+	u16 macRev;
+	u16 phyRev;
+	u16 analog5GhzRev;
+	u16 analog2GhzRev;
+	u16 subsysid;
+	enum ath_usb_dev usbdev;
+};
+
+/* Generic TSF timer definitions */
+
+#define ATH_MAX_GEN_TIMER	16
+
+#define AR_GENTMR_BIT(_index)	(1 << (_index))
+
+/*
+ * Using de Bruijin sequence to look up 1's index in a 32 bit number
+ * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001
+ */
+#define debruijn32 0x077CB531U
+
+struct ath_gen_timer_configuration {
+	u32 next_addr;
+	u32 period_addr;
+	u32 mode_addr;
+	u32 mode_mask;
+};
+
+struct ath_gen_timer {
+	void (*trigger)(void *arg);
+	void (*overflow)(void *arg);
+	void *arg;
+	u8 index;
+};
+
+struct ath_gen_timer_table {
+	u32 gen_timer_index[32];
+	struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER];
+	union {
+		unsigned long timer_bits;
+		u16 val;
+	} timer_mask;
+};
+
+struct ath_hw_antcomb_conf {
+	u8 main_lna_conf;
+	u8 alt_lna_conf;
+	u8 fast_div_bias;
+	u8 main_gaintb;
+	u8 alt_gaintb;
+	int lna1_lna2_delta;
+	u8 div_group;
+};
+
+/**
+ * struct ath_hw_radar_conf - radar detection initialization parameters
+ *
+ * @pulse_inband: threshold for checking the ratio of in-band power
+ *	to total power for short radar pulses (half dB steps)
+ * @pulse_inband_step: threshold for checking an in-band power to total
+ *	power ratio increase for short radar pulses (half dB steps)
+ * @pulse_height: threshold for detecting the beginning of a short
+ *	radar pulse (dB step)
+ * @pulse_rssi: threshold for detecting if a short radar pulse is
+ *	gone (dB step)
+ * @pulse_maxlen: maximum pulse length (0.8 us steps)
+ *
+ * @radar_rssi: RSSI threshold for starting long radar detection (dB steps)
+ * @radar_inband: threshold for checking the ratio of in-band power
+ *	to total power for long radar pulses (half dB steps)
+ * @fir_power: threshold for detecting the end of a long radar pulse (dB)
+ *
+ * @ext_channel: enable extension channel radar detection
+ */
+struct ath_hw_radar_conf {
+	unsigned int pulse_inband;
+	unsigned int pulse_inband_step;
+	unsigned int pulse_height;
+	unsigned int pulse_rssi;
+	unsigned int pulse_maxlen;
+
+	unsigned int radar_rssi;
+	unsigned int radar_inband;
+	int fir_power;
+
+	int ext_channel;
+};
+
+/**
+ * struct ath_hw_private_ops - callbacks used internally by hardware code
+ *
+ * This structure contains private callbacks designed to only be used internally
+ * by the hardware core.
+ *
+ * @init_cal_settings: setup types of calibrations supported
+ * @init_cal: starts actual calibration
+ *
+ * @init_mode_regs: Initializes mode registers
+ * @init_mode_gain_regs: Initialize TX/RX gain registers
+ *
+ * @rf_set_freq: change frequency
+ * @spur_mitigate_freq: spur mitigation
+ * @rf_alloc_ext_banks:
+ * @rf_free_ext_banks:
+ * @set_rf_regs:
+ * @compute_pll_control: compute the PLL control value to use for
+ *	AR_RTC_PLL_CONTROL for a given channel
+ * @setup_calibration: set up calibration
+ * @iscal_supported: used to query if a type of calibration is supported
+ *
+ * @ani_cache_ini_regs: cache the values for ANI from the initial
+ *	register settings through the register initialization.
+ */
+struct ath_hw_private_ops {
+	/* Calibration ops */
+	void (*init_cal_settings)(struct ath_hw *ah);
+	int (*init_cal)(struct ath_hw *ah, struct ath9k_channel *chan);
+
+	void (*init_mode_regs)(struct ath_hw *ah);
+	void (*init_mode_gain_regs)(struct ath_hw *ah);
+	void (*setup_calibration)(struct ath_hw *ah,
+				  struct ath9k_cal_list *currCal);
+
+	/* PHY ops */
+	int (*rf_set_freq)(struct ath_hw *ah,
+			   struct ath9k_channel *chan);
+	void (*spur_mitigate_freq)(struct ath_hw *ah,
+				   struct ath9k_channel *chan);
+	int (*rf_alloc_ext_banks)(struct ath_hw *ah);
+	void (*rf_free_ext_banks)(struct ath_hw *ah);
+	int (*set_rf_regs)(struct ath_hw *ah,
+			    struct ath9k_channel *chan,
+			    u16 modesIndex);
+	void (*set_channel_regs)(struct ath_hw *ah, struct ath9k_channel *chan);
+	void (*init_bb)(struct ath_hw *ah,
+			struct ath9k_channel *chan);
+	int (*process_ini)(struct ath_hw *ah, struct ath9k_channel *chan);
+	void (*olc_init)(struct ath_hw *ah);
+	void (*set_rfmode)(struct ath_hw *ah, struct ath9k_channel *chan);
+	void (*mark_phy_inactive)(struct ath_hw *ah);
+	void (*set_delta_slope)(struct ath_hw *ah, struct ath9k_channel *chan);
+	int (*rfbus_req)(struct ath_hw *ah);
+	void (*rfbus_done)(struct ath_hw *ah);
+	void (*restore_chainmask)(struct ath_hw *ah);
+	void (*set_diversity)(struct ath_hw *ah, int value);
+	u32 (*compute_pll_control)(struct ath_hw *ah,
+				   struct ath9k_channel *chan);
+	int (*ani_control)(struct ath_hw *ah, enum ath9k_ani_cmd cmd,
+			    int param);
+	void (*do_getnf)(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]);
+	void (*set_radar_params)(struct ath_hw *ah,
+				 struct ath_hw_radar_conf *conf);
+
+	/* ANI */
+	void (*ani_cache_ini_regs)(struct ath_hw *ah);
+};
+
+/**
+ * struct ath_hw_ops - callbacks used by hardware code and driver code
+ *
+ * This structure contains callbacks designed to to be used internally by
+ * hardware code and also by the lower level driver.
+ *
+ * @config_pci_powersave:
+ * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
+ */
+struct ath_hw_ops {
+	void (*config_pci_powersave)(struct ath_hw *ah,
+				     int restore,
+				     int power_off);
+	void (*rx_enable)(struct ath_hw *ah);
+	void (*set_desc_link)(void *ds, u32 link);
+	void (*get_desc_link)(void *ds, u32 **link);
+	int (*calibrate)(struct ath_hw *ah,
+			  struct ath9k_channel *chan,
+			  u8 rxchainmask,
+			  int longcal);
+	int (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked);
+	void (*fill_txdesc)(struct ath_hw *ah, void *ds, u32 seglen,
+			    int is_firstseg, int is_is_lastseg,
+			    const void *ds0, u32 buf_addr,
+			    unsigned int qcu);
+	int (*proc_txdesc)(struct ath_hw *ah, void *ds,
+			   struct ath_tx_status *ts);
+	void (*set11n_txdesc)(struct ath_hw *ah, void *ds,
+			      u32 pktLen, enum ath9k_pkt_type type,
+			      u32 txPower, u32 keyIx,
+			      enum ath9k_key_type keyType,
+			      u32 flags);
+	void (*set11n_ratescenario)(struct ath_hw *ah, void *ds,
+				void *lastds,
+				u32 durUpdateEn, u32 rtsctsRate,
+				u32 rtsctsDuration,
+				struct ath9k_11n_rate_series series[],
+				u32 nseries, u32 flags);
+	void (*set11n_aggr_first)(struct ath_hw *ah, void *ds,
+				  u32 aggrLen);
+	void (*set11n_aggr_middle)(struct ath_hw *ah, void *ds,
+				   u32 numDelims);
+	void (*set11n_aggr_last)(struct ath_hw *ah, void *ds);
+	void (*clr11n_aggr)(struct ath_hw *ah, void *ds);
+	void (*set_clrdmask)(struct ath_hw *ah, void *ds, int val);
+	void (*antdiv_comb_conf_get)(struct ath_hw *ah,
+			struct ath_hw_antcomb_conf *antconf);
+	void (*antdiv_comb_conf_set)(struct ath_hw *ah,
+			struct ath_hw_antcomb_conf *antconf);
+
+};
+
+struct ath_nf_limits {
+	s16 max;
+	s16 min;
+	s16 nominal;
+};
+
+/* ah_flags */
+#define AH_USE_EEPROM   0x1
+#define AH_UNPLUGGED    0x2 /* The card has been physically removed. */
+
+struct ath_hw {
+	struct ath_ops reg_ops;
+
+	struct net80211_device *dev;
+	struct ath_common common;
+	struct ath9k_hw_version hw_version;
+	struct ath9k_ops_config config;
+	struct ath9k_hw_capabilities caps;
+	struct ath9k_channel channels[ATH9K_NUM_CHANNELS];
+	struct ath9k_channel *curchan;
+
+	union {
+		struct ar5416_eeprom_def def;
+		struct ar5416_eeprom_4k map4k;
+		struct ar9287_eeprom map9287;
+		struct ar9300_eeprom ar9300_eep;
+	} eeprom;
+	const struct eeprom_ops *eep_ops;
+
+	int sw_mgmt_crypto;
+	int is_pciexpress;
+	int is_monitoring;
+	int need_an_top2_fixup;
+	u16 tx_trig_level;
+
+	u32 nf_regs[6];
+	struct ath_nf_limits nf_2g;
+	struct ath_nf_limits nf_5g;
+	u16 rfsilent;
+	u32 rfkill_gpio;
+	u32 rfkill_polarity;
+	u32 ah_flags;
+
+	int htc_reset_init;
+
+	enum ath9k_power_mode power_mode;
+
+	struct ath9k_hw_cal_data *caldata;
+	struct ath9k_pacal_info pacal_info;
+	struct ar5416Stats stats;
+	struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
+
+	int16_t curchan_rad_index;
+	int ah_ier;
+	enum ath9k_int imask;
+	u32 imrs2_reg;
+	u32 txok_interrupt_mask;
+	u32 txerr_interrupt_mask;
+	u32 txdesc_interrupt_mask;
+	u32 txeol_interrupt_mask;
+	u32 txurn_interrupt_mask;
+	int chip_fullsleep;
+	u32 atim_window;
+
+	/* Calibration */
+	u32 supp_cals;
+	struct ath9k_cal_list iq_caldata;
+	struct ath9k_cal_list adcgain_caldata;
+	struct ath9k_cal_list adcdc_caldata;
+	struct ath9k_cal_list tempCompCalData;
+	struct ath9k_cal_list *cal_list;
+	struct ath9k_cal_list *cal_list_last;
+	struct ath9k_cal_list *cal_list_curr;
+#define totalPowerMeasI meas0.unsign
+#define totalPowerMeasQ meas1.unsign
+#define totalIqCorrMeas meas2.sign
+#define totalAdcIOddPhase  meas0.unsign
+#define totalAdcIEvenPhase meas1.unsign
+#define totalAdcQOddPhase  meas2.unsign
+#define totalAdcQEvenPhase meas3.unsign
+#define totalAdcDcOffsetIOddPhase  meas0.sign
+#define totalAdcDcOffsetIEvenPhase meas1.sign
+#define totalAdcDcOffsetQOddPhase  meas2.sign
+#define totalAdcDcOffsetQEvenPhase meas3.sign
+	union {
+		u32 unsign[AR5416_MAX_CHAINS];
+		int32_t sign[AR5416_MAX_CHAINS];
+	} meas0;
+	union {
+		u32 unsign[AR5416_MAX_CHAINS];
+		int32_t sign[AR5416_MAX_CHAINS];
+	} meas1;
+	union {
+		u32 unsign[AR5416_MAX_CHAINS];
+		int32_t sign[AR5416_MAX_CHAINS];
+	} meas2;
+	union {
+		u32 unsign[AR5416_MAX_CHAINS];
+		int32_t sign[AR5416_MAX_CHAINS];
+	} meas3;
+	u16 cal_samples;
+
+	u32 sta_id1_defaults;
+	u32 misc_mode;
+	enum {
+		AUTO_32KHZ,
+		USE_32KHZ,
+		DONT_USE_32KHZ,
+	} enable_32kHz_clock;
+
+	/* Private to hardware code */
+	struct ath_hw_private_ops private_ops;
+	/* Accessed by the lower level driver */
+	struct ath_hw_ops ops;
+
+	/* Used to program the radio on non single-chip devices */
+	u32 *analogBank0Data;
+	u32 *analogBank1Data;
+	u32 *analogBank2Data;
+	u32 *analogBank3Data;
+	u32 *analogBank6Data;
+	u32 *analogBank6TPCData;
+	u32 *analogBank7Data;
+	u32 *addac5416_21;
+	u32 *bank6Temp;
+
+	u8 txpower_limit;
+	int coverage_class;
+	u32 slottime;
+	u32 globaltxtimeout;
+
+	/* ANI */
+	u32 proc_phyerr;
+	u32 aniperiod;
+	int totalSizeDesired[5];
+	int coarse_high[5];
+	int coarse_low[5];
+	int firpwr[5];
+	enum ath9k_ani_cmd ani_function;
+
+	u32 intr_txqs;
+	u8 txchainmask;
+	u8 rxchainmask;
+
+	struct ath_hw_radar_conf radar_conf;
+
+	u32 originalGain[22];
+	int initPDADC;
+	int PDADCdelta;
+	int led_pin;
+	u32 gpio_mask;
+	u32 gpio_val;
+
+	struct ar5416IniArray iniModes;
+	struct ar5416IniArray iniCommon;
+	struct ar5416IniArray iniBank0;
+	struct ar5416IniArray iniBB_RfGain;
+	struct ar5416IniArray iniBank1;
+	struct ar5416IniArray iniBank2;
+	struct ar5416IniArray iniBank3;
+	struct ar5416IniArray iniBank6;
+	struct ar5416IniArray iniBank6TPC;
+	struct ar5416IniArray iniBank7;
+	struct ar5416IniArray iniAddac;
+	struct ar5416IniArray iniPcieSerdes;
+	struct ar5416IniArray iniPcieSerdesLowPower;
+	struct ar5416IniArray iniModesAdditional;
+	struct ar5416IniArray iniModesAdditional_40M;
+	struct ar5416IniArray iniModesRxGain;
+	struct ar5416IniArray iniModesTxGain;
+	struct ar5416IniArray iniModes_9271_1_0_only;
+	struct ar5416IniArray iniCckfirNormal;
+	struct ar5416IniArray iniCckfirJapan2484;
+	struct ar5416IniArray iniCommon_normal_cck_fir_coeff_9271;
+	struct ar5416IniArray iniCommon_japan_2484_cck_fir_coeff_9271;
+	struct ar5416IniArray iniModes_9271_ANI_reg;
+	struct ar5416IniArray iniModes_high_power_tx_gain_9271;
+	struct ar5416IniArray iniModes_normal_power_tx_gain_9271;
+
+	struct ar5416IniArray iniMac[ATH_INI_NUM_SPLIT];
+	struct ar5416IniArray iniBB[ATH_INI_NUM_SPLIT];
+	struct ar5416IniArray iniRadio[ATH_INI_NUM_SPLIT];
+	struct ar5416IniArray iniSOC[ATH_INI_NUM_SPLIT];
+
+	u32 intr_gen_timer_trigger;
+	u32 intr_gen_timer_thresh;
+	struct ath_gen_timer_table hw_gen_timers;
+
+	struct ar9003_txs *ts_ring;
+	void *ts_start;
+	u32 ts_paddr_start;
+	u32 ts_paddr_end;
+	u16 ts_tail;
+	u8 ts_size;
+
+	unsigned int paprd_target_power;
+	unsigned int paprd_training_power;
+	unsigned int paprd_ratemask;
+	unsigned int paprd_ratemask_ht40;
+	int paprd_table_write_done;
+	u32 paprd_gain_table_entries[PAPRD_GAIN_TABLE_ENTRIES];
+	u8 paprd_gain_table_index[PAPRD_GAIN_TABLE_ENTRIES];
+	/*
+	 * Store the permanent value of Reg 0x4004in WARegVal
+	 * so we dont have to R/M/W. We should not be reading
+	 * this register when in sleep states.
+	 */
+	u32 WARegVal;
+
+	/* Enterprise mode cap */
+	u32 ent_mode;
+
+	int is_clk_25mhz;
+};
+
+struct ath_bus_ops {
+	enum ath_bus_type ath_bus_type;
+	void (*read_cachesize)(struct ath_common *common, int *csz);
+	int (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
+	void (*bt_coex_prep)(struct ath_common *common);
+	void (*extn_synch_en)(struct ath_common *common);
+};
+
+static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
+{
+	return &ah->common;
+}
+
+static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah)
+{
+	return &(ath9k_hw_common(ah)->regulatory);
+}
+
+static inline struct ath_hw_private_ops *ath9k_hw_private_ops(struct ath_hw *ah)
+{
+	return &ah->private_ops;
+}
+
+static inline struct ath_hw_ops *ath9k_hw_ops(struct ath_hw *ah)
+{
+	return &ah->ops;
+}
+
+static inline u8 get_streams(int mask)
+{
+	return !!(mask & BIT(0)) + !!(mask & BIT(1)) + !!(mask & BIT(2));
+}
+
+/* Initialization, Detach, Reset */
+const char *ath9k_hw_probe(u16 vendorid, u16 devid);
+void ath9k_hw_deinit(struct ath_hw *ah);
+int ath9k_hw_init(struct ath_hw *ah);
+int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
+		   struct ath9k_hw_cal_data *caldata, int bChannelChange);
+int ath9k_hw_fill_cap_info(struct ath_hw *ah);
+u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan);
+
+/* GPIO / RFKILL / Antennae */
+void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio);
+u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio);
+void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
+			 u32 ah_signal_type);
+void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val);
+u32 ath9k_hw_getdefantenna(struct ath_hw *ah);
+void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
+
+/* General Operation */
+int ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
+void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
+			  int column, unsigned int *writecnt);
+u32 ath9k_hw_reverse_bits(u32 val, u32 n);
+u16 ath9k_hw_computetxtime(struct ath_hw *ah,
+			   u8 phy, int kbps,
+			   u32 frameLen, u16 rateix, int shortPreamble);
+void ath9k_hw_get_channel_centers(struct ath_hw *ah,
+				  struct ath9k_channel *chan,
+				  struct chan_centers *centers);
+u32 ath9k_hw_getrxfilter(struct ath_hw *ah);
+void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits);
+int ath9k_hw_phy_disable(struct ath_hw *ah);
+int ath9k_hw_disable(struct ath_hw *ah);
+void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, int test);
+void ath9k_hw_setopmode(struct ath_hw *ah);
+void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1);
+void ath9k_hw_setbssidmask(struct ath_hw *ah);
+void ath9k_hw_write_associd(struct ath_hw *ah);
+void ath9k_hw_init_global_settings(struct ath_hw *ah);
+u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah);
+void ath9k_hw_set11nmac2040(struct ath_hw *ah);
+int ath9k_hw_check_alive(struct ath_hw *ah);
+
+int ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
+
+void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len);
+
+/* HTC */
+void ath9k_hw_htc_resetinit(struct ath_hw *ah);
+
+/* PHY */
+void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
+				   u32 *coef_mantissa, u32 *coef_exponent);
+
+/*
+ * Code Specific to AR5008, AR9001 or AR9002,
+ * we stuff these here to avoid callbacks for AR9003.
+ */
+void ar9002_hw_cck_chan14_spread(struct ath_hw *ah);
+int ar9002_hw_rf_claim(struct ath_hw *ah);
+void ar9002_hw_enable_async_fifo(struct ath_hw *ah);
+void ar9002_hw_update_async_fifo(struct ath_hw *ah);
+void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah);
+
+/*
+ * Code specific to AR9003, we stuff these here to avoid callbacks
+ * for older families
+ */
+void ar9003_hw_disable_phy_restart(struct ath_hw *ah);
+
+/* Hardware family op attach helpers */
+void ar5008_hw_attach_phy_ops(struct ath_hw *ah);
+void ar9002_hw_attach_phy_ops(struct ath_hw *ah);
+void ar9003_hw_attach_phy_ops(struct ath_hw *ah);
+
+void ar9002_hw_attach_calib_ops(struct ath_hw *ah);
+void ar9003_hw_attach_calib_ops(struct ath_hw *ah);
+
+void ar9002_hw_attach_ops(struct ath_hw *ah);
+void ar9003_hw_attach_ops(struct ath_hw *ah);
+
+void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan);
+/*
+ * ANI work can be shared between all families but a next
+ * generation implementation of ANI will be used only for AR9003 only
+ * for now as the other families still need to be tested with the same
+ * next generation ANI. Feel free to start testing it though for the
+ * older families (AR5008, AR9001, AR9002) by using modparam_force_new_ani.
+ */
+extern int modparam_force_new_ani;
+void ath9k_ani_reset(struct ath_hw *ah, int is_scanning);
+void ath9k_hw_proc_mib_event(struct ath_hw *ah);
+void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan);
+
+#define ATH_PCIE_CAP_LINK_CTRL	0x70
+#define ATH_PCIE_CAP_LINK_L0S	1
+#define ATH_PCIE_CAP_LINK_L1	2
+
+#define ATH9K_CLOCK_RATE_CCK		22
+#define ATH9K_CLOCK_RATE_5GHZ_OFDM	40
+#define ATH9K_CLOCK_RATE_2GHZ_OFDM	44
+#define ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM 44
+
+#endif
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/mac.h b/roms/ipxe/src/drivers/net/ath/ath9k/mac.h
new file mode 100644
index 0000000000000000000000000000000000000000..5899230e03b158afa3154e731dbefe3e10e4044b
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/mac.h
@@ -0,0 +1,707 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MAC_H
+#define MAC_H
+
+#include <unistd.h>
+
+#define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_20_OR_LATER(ah) ?		\
+				MS(ads->ds_rxstatus0, AR_RxRate) :	\
+				(ads->ds_rxstatus3 >> 2) & 0xFF)
+
+#define set11nTries(_series, _index) \
+	(SM((_series)[_index].Tries, AR_XmitDataTries##_index))
+
+#define set11nRate(_series, _index) \
+	(SM((_series)[_index].Rate, AR_XmitRate##_index))
+
+#define set11nPktDurRTSCTS(_series, _index)				\
+	(SM((_series)[_index].PktDuration, AR_PacketDur##_index) |	\
+	 ((_series)[_index].RateFlags & ATH9K_RATESERIES_RTS_CTS   ?	\
+	  AR_RTSCTSQual##_index : 0))
+
+#define set11nRateFlags(_series, _index)				\
+	(((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ?		\
+	  AR_2040_##_index : 0)						\
+	 |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ?	\
+	   AR_GI##_index : 0)						\
+	 |((_series)[_index].RateFlags & ATH9K_RATESERIES_STBC ?	\
+	   AR_STBC##_index : 0)						\
+	 |SM((_series)[_index].ChSel, AR_ChainSel##_index))
+
+#define CCK_SIFS_TIME        10
+#define CCK_PREAMBLE_BITS   144
+#define CCK_PLCP_BITS        48
+
+#define OFDM_SIFS_TIME        16
+#define OFDM_PREAMBLE_TIME    20
+#define OFDM_PLCP_BITS        22
+#define OFDM_SYMBOL_TIME      4
+
+#define OFDM_SIFS_TIME_HALF     32
+#define OFDM_PREAMBLE_TIME_HALF 40
+#define OFDM_PLCP_BITS_HALF     22
+#define OFDM_SYMBOL_TIME_HALF   8
+
+#define OFDM_SIFS_TIME_QUARTER      64
+#define OFDM_PREAMBLE_TIME_QUARTER  80
+#define OFDM_PLCP_BITS_QUARTER      22
+#define OFDM_SYMBOL_TIME_QUARTER    16
+
+#define INIT_AIFS       2
+#define INIT_CWMIN      15
+#define INIT_CWMIN_11B  31
+#define INIT_CWMAX      1023
+#define INIT_SH_RETRY   10
+#define INIT_LG_RETRY   10
+#define INIT_SSH_RETRY  32
+#define INIT_SLG_RETRY  32
+
+#define ATH9K_SLOT_TIME_6 6
+#define ATH9K_SLOT_TIME_9 9
+#define ATH9K_SLOT_TIME_20 20
+
+#define ATH9K_TXERR_XRETRY         0x01
+#define ATH9K_TXERR_FILT           0x02
+#define ATH9K_TXERR_FIFO           0x04
+#define ATH9K_TXERR_XTXOP          0x08
+#define ATH9K_TXERR_TIMER_EXPIRED  0x10
+#define ATH9K_TX_ACKED		   0x20
+#define ATH9K_TXERR_MASK						\
+	(ATH9K_TXERR_XRETRY | ATH9K_TXERR_FILT | ATH9K_TXERR_FIFO |	\
+	 ATH9K_TXERR_XTXOP | ATH9K_TXERR_TIMER_EXPIRED)
+
+#define ATH9K_TX_BA                0x01
+#define ATH9K_TX_PWRMGMT           0x02
+#define ATH9K_TX_DESC_CFG_ERR      0x04
+#define ATH9K_TX_DATA_UNDERRUN     0x08
+#define ATH9K_TX_DELIM_UNDERRUN    0x10
+#define ATH9K_TX_SW_FILTERED       0x80
+
+/* 64 bytes */
+#define MIN_TX_FIFO_THRESHOLD   0x1
+
+/*
+ * Single stream device AR9285 and AR9271 require 2 KB
+ * to work around a hardware issue, all other devices
+ * have can use the max 4 KB limit.
+ */
+#define MAX_TX_FIFO_THRESHOLD   ((4096 / 64) - 1)
+
+struct ath_tx_status {
+	u32 ts_tstamp;
+	u16 ts_seqnum;
+	u8 ts_status;
+	u8 ts_rateindex;
+	int8_t ts_rssi;
+	u8 ts_shortretry;
+	u8 ts_longretry;
+	u8 ts_virtcol;
+	u8 ts_flags;
+	int8_t ts_rssi_ctl0;
+	int8_t ts_rssi_ctl1;
+	int8_t ts_rssi_ctl2;
+	int8_t ts_rssi_ext0;
+	int8_t ts_rssi_ext1;
+	int8_t ts_rssi_ext2;
+	u8 qid;
+	u16 desc_id;
+	u8 tid;
+	u32 ba_low;
+	u32 ba_high;
+	u32 evm0;
+	u32 evm1;
+	u32 evm2;
+};
+
+struct ath_rx_status {
+	u32 rs_tstamp;
+	u16 rs_datalen;
+	u8 rs_status;
+	u8 rs_phyerr;
+	int8_t rs_rssi;
+	u8 rs_keyix;
+	u8 rs_rate;
+	u8 rs_antenna;
+	u8 rs_more;
+	int8_t rs_rssi_ctl0;
+	int8_t rs_rssi_ctl1;
+	int8_t rs_rssi_ctl2;
+	int8_t rs_rssi_ext0;
+	int8_t rs_rssi_ext1;
+	int8_t rs_rssi_ext2;
+	u8 rs_isaggr;
+	u8 rs_moreaggr;
+	u8 rs_num_delims;
+	u8 rs_flags;
+	u32 evm0;
+	u32 evm1;
+	u32 evm2;
+	u32 evm3;
+	u32 evm4;
+};
+
+struct ath_htc_rx_status {
+	uint64_t rs_tstamp;
+	uint16_t rs_datalen;
+	u8 rs_status;
+	u8 rs_phyerr;
+	int8_t rs_rssi;
+	int8_t rs_rssi_ctl0;
+	int8_t rs_rssi_ctl1;
+	int8_t rs_rssi_ctl2;
+	int8_t rs_rssi_ext0;
+	int8_t rs_rssi_ext1;
+	int8_t rs_rssi_ext2;
+	u8 rs_keyix;
+	u8 rs_rate;
+	u8 rs_antenna;
+	u8 rs_more;
+	u8 rs_isaggr;
+	u8 rs_moreaggr;
+	u8 rs_num_delims;
+	u8 rs_flags;
+	u8 rs_dummy;
+	uint32_t evm0;
+	uint32_t evm1;
+	uint32_t evm2;
+};
+
+#define ATH9K_RXERR_CRC           0x01
+#define ATH9K_RXERR_PHY           0x02
+#define ATH9K_RXERR_FIFO          0x04
+#define ATH9K_RXERR_DECRYPT       0x08
+#define ATH9K_RXERR_MIC           0x10
+
+#define ATH9K_RX_MORE             0x01
+#define ATH9K_RX_MORE_AGGR        0x02
+#define ATH9K_RX_GI               0x04
+#define ATH9K_RX_2040             0x08
+#define ATH9K_RX_DELIM_CRC_PRE    0x10
+#define ATH9K_RX_DELIM_CRC_POST   0x20
+#define ATH9K_RX_DECRYPT_BUSY     0x40
+
+#define ATH9K_RXKEYIX_INVALID	((u8)-1)
+#define ATH9K_TXKEYIX_INVALID	((u32)-1)
+
+enum ath9k_phyerr {
+	ATH9K_PHYERR_UNDERRUN             = 0,  /* Transmit underrun */
+	ATH9K_PHYERR_TIMING               = 1,  /* Timing error */
+	ATH9K_PHYERR_PARITY               = 2,  /* Illegal parity */
+	ATH9K_PHYERR_RATE                 = 3,  /* Illegal rate */
+	ATH9K_PHYERR_LENGTH               = 4,  /* Illegal length */
+	ATH9K_PHYERR_RADAR                = 5,  /* Radar detect */
+	ATH9K_PHYERR_SERVICE              = 6,  /* Illegal service */
+	ATH9K_PHYERR_TOR                  = 7,  /* Transmit override receive */
+
+	ATH9K_PHYERR_OFDM_TIMING          = 17,
+	ATH9K_PHYERR_OFDM_SIGNAL_PARITY   = 18,
+	ATH9K_PHYERR_OFDM_RATE_ILLEGAL    = 19,
+	ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL  = 20,
+	ATH9K_PHYERR_OFDM_POWER_DROP      = 21,
+	ATH9K_PHYERR_OFDM_SERVICE         = 22,
+	ATH9K_PHYERR_OFDM_RESTART         = 23,
+	ATH9K_PHYERR_FALSE_RADAR_EXT      = 24,
+
+	ATH9K_PHYERR_CCK_TIMING           = 25,
+	ATH9K_PHYERR_CCK_HEADER_CRC       = 26,
+	ATH9K_PHYERR_CCK_RATE_ILLEGAL     = 27,
+	ATH9K_PHYERR_CCK_SERVICE          = 30,
+	ATH9K_PHYERR_CCK_RESTART          = 31,
+	ATH9K_PHYERR_CCK_LENGTH_ILLEGAL   = 32,
+	ATH9K_PHYERR_CCK_POWER_DROP       = 33,
+
+	ATH9K_PHYERR_HT_CRC_ERROR         = 34,
+	ATH9K_PHYERR_HT_LENGTH_ILLEGAL    = 35,
+	ATH9K_PHYERR_HT_RATE_ILLEGAL      = 36,
+
+	ATH9K_PHYERR_MAX                  = 37,
+};
+
+struct ath_desc {
+	u32 ds_link;
+	u32 ds_data;
+	u32 ds_ctl0;
+	u32 ds_ctl1;
+	u32 ds_hw[20];
+//	void *ds_vdata;
+} __attribute__((packed, aligned(4)));
+
+#define ATH9K_TXDESC_NOACK		0x0002
+#define ATH9K_TXDESC_RTSENA		0x0004
+#define ATH9K_TXDESC_CTSENA		0x0008
+/* ATH9K_TXDESC_INTREQ forces a tx interrupt to be generated for
+ * the descriptor its marked on.  We take a tx interrupt to reap
+ * descriptors when the h/w hits an EOL condition or
+ * when the descriptor is specifically marked to generate
+ * an interrupt with this flag. Descriptors should be
+ * marked periodically to insure timely replenishing of the
+ * supply needed for sending frames. Defering interrupts
+ * reduces system load and potentially allows more concurrent
+ * work to be done but if done to aggressively can cause
+ * senders to backup. When the hardware queue is left too
+ * large rate control information may also be too out of
+ * date. An Alternative for this is TX interrupt mitigation
+ * but this needs more testing. */
+#define ATH9K_TXDESC_INTREQ		0x0010
+#define ATH9K_TXDESC_VEOL		0x0020
+#define ATH9K_TXDESC_EXT_ONLY		0x0040
+#define ATH9K_TXDESC_EXT_AND_CTL	0x0080
+#define ATH9K_TXDESC_VMF		0x0100
+#define ATH9K_TXDESC_FRAG_IS_ON 	0x0200
+#define ATH9K_TXDESC_LOWRXCHAIN		0x0400
+#define ATH9K_TXDESC_LDPC		0x00010000
+
+#define ATH9K_RXDESC_INTREQ		0x0020
+
+struct ar5416_desc {
+	u32 ds_link;
+	u32 ds_data;
+	u32 ds_ctl0;
+	u32 ds_ctl1;
+	union {
+		struct {
+			u32 ctl2;
+			u32 ctl3;
+			u32 ctl4;
+			u32 ctl5;
+			u32 ctl6;
+			u32 ctl7;
+			u32 ctl8;
+			u32 ctl9;
+			u32 ctl10;
+			u32 ctl11;
+			u32 status0;
+			u32 status1;
+			u32 status2;
+			u32 status3;
+			u32 status4;
+			u32 status5;
+			u32 status6;
+			u32 status7;
+			u32 status8;
+			u32 status9;
+		} tx;
+		struct {
+			u32 status0;
+			u32 status1;
+			u32 status2;
+			u32 status3;
+			u32 status4;
+			u32 status5;
+			u32 status6;
+			u32 status7;
+			u32 status8;
+		} rx;
+	} u;
+} __attribute__((packed, aligned(4)));
+
+#define AR5416DESC(_ds)         ((struct ar5416_desc *)(_ds))
+#define AR5416DESC_CONST(_ds)   ((const struct ar5416_desc *)(_ds))
+
+#define ds_ctl2     u.tx.ctl2
+#define ds_ctl3     u.tx.ctl3
+#define ds_ctl4     u.tx.ctl4
+#define ds_ctl5     u.tx.ctl5
+#define ds_ctl6     u.tx.ctl6
+#define ds_ctl7     u.tx.ctl7
+#define ds_ctl8     u.tx.ctl8
+#define ds_ctl9     u.tx.ctl9
+#define ds_ctl10    u.tx.ctl10
+#define ds_ctl11    u.tx.ctl11
+
+#define ds_txstatus0    u.tx.status0
+#define ds_txstatus1    u.tx.status1
+#define ds_txstatus2    u.tx.status2
+#define ds_txstatus3    u.tx.status3
+#define ds_txstatus4    u.tx.status4
+#define ds_txstatus5    u.tx.status5
+#define ds_txstatus6    u.tx.status6
+#define ds_txstatus7    u.tx.status7
+#define ds_txstatus8    u.tx.status8
+#define ds_txstatus9    u.tx.status9
+
+#define ds_rxstatus0    u.rx.status0
+#define ds_rxstatus1    u.rx.status1
+#define ds_rxstatus2    u.rx.status2
+#define ds_rxstatus3    u.rx.status3
+#define ds_rxstatus4    u.rx.status4
+#define ds_rxstatus5    u.rx.status5
+#define ds_rxstatus6    u.rx.status6
+#define ds_rxstatus7    u.rx.status7
+#define ds_rxstatus8    u.rx.status8
+
+#define AR_FrameLen         0x00000fff
+#define AR_VirtMoreFrag     0x00001000
+#define AR_TxCtlRsvd00      0x0000e000
+#define AR_XmitPower        0x003f0000
+#define AR_XmitPower_S      16
+#define AR_RTSEnable        0x00400000
+#define AR_VEOL             0x00800000
+#define AR_ClrDestMask      0x01000000
+#define AR_TxCtlRsvd01      0x1e000000
+#define AR_TxIntrReq        0x20000000
+#define AR_DestIdxValid     0x40000000
+#define AR_CTSEnable        0x80000000
+
+#define AR_TxMore           0x00001000
+#define AR_DestIdx          0x000fe000
+#define AR_DestIdx_S        13
+#define AR_FrameType        0x00f00000
+#define AR_FrameType_S      20
+#define AR_NoAck            0x01000000
+#define AR_InsertTS         0x02000000
+#define AR_CorruptFCS       0x04000000
+#define AR_ExtOnly          0x08000000
+#define AR_ExtAndCtl        0x10000000
+#define AR_MoreAggr         0x20000000
+#define AR_IsAggr           0x40000000
+
+#define AR_BurstDur         0x00007fff
+#define AR_BurstDur_S       0
+#define AR_DurUpdateEna     0x00008000
+#define AR_XmitDataTries0   0x000f0000
+#define AR_XmitDataTries0_S 16
+#define AR_XmitDataTries1   0x00f00000
+#define AR_XmitDataTries1_S 20
+#define AR_XmitDataTries2   0x0f000000
+#define AR_XmitDataTries2_S 24
+#define AR_XmitDataTries3   0xf0000000
+#define AR_XmitDataTries3_S 28
+
+#define AR_XmitRate0        0x000000ff
+#define AR_XmitRate0_S      0
+#define AR_XmitRate1        0x0000ff00
+#define AR_XmitRate1_S      8
+#define AR_XmitRate2        0x00ff0000
+#define AR_XmitRate2_S      16
+#define AR_XmitRate3        0xff000000
+#define AR_XmitRate3_S      24
+
+#define AR_PacketDur0       0x00007fff
+#define AR_PacketDur0_S     0
+#define AR_RTSCTSQual0      0x00008000
+#define AR_PacketDur1       0x7fff0000
+#define AR_PacketDur1_S     16
+#define AR_RTSCTSQual1      0x80000000
+
+#define AR_PacketDur2       0x00007fff
+#define AR_PacketDur2_S     0
+#define AR_RTSCTSQual2      0x00008000
+#define AR_PacketDur3       0x7fff0000
+#define AR_PacketDur3_S     16
+#define AR_RTSCTSQual3      0x80000000
+
+#define AR_AggrLen          0x0000ffff
+#define AR_AggrLen_S        0
+#define AR_TxCtlRsvd60      0x00030000
+#define AR_PadDelim         0x03fc0000
+#define AR_PadDelim_S       18
+#define AR_EncrType         0x0c000000
+#define AR_EncrType_S       26
+#define AR_TxCtlRsvd61      0xf0000000
+#define AR_LDPC             0x80000000
+
+#define AR_2040_0           0x00000001
+#define AR_GI0              0x00000002
+#define AR_ChainSel0        0x0000001c
+#define AR_ChainSel0_S      2
+#define AR_2040_1           0x00000020
+#define AR_GI1              0x00000040
+#define AR_ChainSel1        0x00000380
+#define AR_ChainSel1_S      7
+#define AR_2040_2           0x00000400
+#define AR_GI2              0x00000800
+#define AR_ChainSel2        0x00007000
+#define AR_ChainSel2_S      12
+#define AR_2040_3           0x00008000
+#define AR_GI3              0x00010000
+#define AR_ChainSel3        0x000e0000
+#define AR_ChainSel3_S      17
+#define AR_RTSCTSRate       0x0ff00000
+#define AR_RTSCTSRate_S     20
+#define AR_STBC0            0x10000000
+#define AR_STBC1            0x20000000
+#define AR_STBC2            0x40000000
+#define AR_STBC3            0x80000000
+
+#define AR_TxRSSIAnt00      0x000000ff
+#define AR_TxRSSIAnt00_S    0
+#define AR_TxRSSIAnt01      0x0000ff00
+#define AR_TxRSSIAnt01_S    8
+#define AR_TxRSSIAnt02      0x00ff0000
+#define AR_TxRSSIAnt02_S    16
+#define AR_TxStatusRsvd00   0x3f000000
+#define AR_TxBaStatus       0x40000000
+#define AR_TxStatusRsvd01   0x80000000
+
+/*
+ * AR_FrmXmitOK - Frame transmission success flag. If set, the frame was
+ * transmitted successfully. If clear, no ACK or BA was received to indicate
+ * successful transmission when we were expecting an ACK or BA.
+ */
+#define AR_FrmXmitOK            0x00000001
+#define AR_ExcessiveRetries     0x00000002
+#define AR_FIFOUnderrun         0x00000004
+#define AR_Filtered             0x00000008
+#define AR_RTSFailCnt           0x000000f0
+#define AR_RTSFailCnt_S         4
+#define AR_DataFailCnt          0x00000f00
+#define AR_DataFailCnt_S        8
+#define AR_VirtRetryCnt         0x0000f000
+#define AR_VirtRetryCnt_S       12
+#define AR_TxDelimUnderrun      0x00010000
+#define AR_TxDataUnderrun       0x00020000
+#define AR_DescCfgErr           0x00040000
+#define AR_TxTimerExpired       0x00080000
+#define AR_TxStatusRsvd10       0xfff00000
+
+#define AR_SendTimestamp    ds_txstatus2
+#define AR_BaBitmapLow      ds_txstatus3
+#define AR_BaBitmapHigh     ds_txstatus4
+
+#define AR_TxRSSIAnt10      0x000000ff
+#define AR_TxRSSIAnt10_S    0
+#define AR_TxRSSIAnt11      0x0000ff00
+#define AR_TxRSSIAnt11_S    8
+#define AR_TxRSSIAnt12      0x00ff0000
+#define AR_TxRSSIAnt12_S    16
+#define AR_TxRSSICombined   0xff000000
+#define AR_TxRSSICombined_S 24
+
+#define AR_TxTid	0xf0000000
+#define AR_TxTid_S	28
+
+#define AR_TxEVM0           ds_txstatus5
+#define AR_TxEVM1           ds_txstatus6
+#define AR_TxEVM2           ds_txstatus7
+
+#define AR_TxDone           0x00000001
+#define AR_SeqNum           0x00001ffe
+#define AR_SeqNum_S         1
+#define AR_TxStatusRsvd80   0x0001e000
+#define AR_TxOpExceeded     0x00020000
+#define AR_TxStatusRsvd81   0x001c0000
+#define AR_FinalTxIdx       0x00600000
+#define AR_FinalTxIdx_S     21
+#define AR_TxStatusRsvd82   0x01800000
+#define AR_PowerMgmt        0x02000000
+#define AR_TxStatusRsvd83   0xfc000000
+
+#define AR_RxCTLRsvd00  0xffffffff
+
+#define AR_RxCtlRsvd00  0x00001000
+#define AR_RxIntrReq    0x00002000
+#define AR_RxCtlRsvd01  0xffffc000
+
+#define AR_RxRSSIAnt00      0x000000ff
+#define AR_RxRSSIAnt00_S    0
+#define AR_RxRSSIAnt01      0x0000ff00
+#define AR_RxRSSIAnt01_S    8
+#define AR_RxRSSIAnt02      0x00ff0000
+#define AR_RxRSSIAnt02_S    16
+#define AR_RxRate           0xff000000
+#define AR_RxRate_S         24
+#define AR_RxStatusRsvd00   0xff000000
+
+#define AR_DataLen          0x00000fff
+#define AR_RxMore           0x00001000
+#define AR_NumDelim         0x003fc000
+#define AR_NumDelim_S       14
+#define AR_RxStatusRsvd10   0xff800000
+
+#define AR_RcvTimestamp     ds_rxstatus2
+
+#define AR_GI               0x00000001
+#define AR_2040             0x00000002
+#define AR_Parallel40       0x00000004
+#define AR_Parallel40_S     2
+#define AR_RxStatusRsvd30   0x000000f8
+#define AR_RxAntenna	    0xffffff00
+#define AR_RxAntenna_S	    8
+
+#define AR_RxRSSIAnt10            0x000000ff
+#define AR_RxRSSIAnt10_S          0
+#define AR_RxRSSIAnt11            0x0000ff00
+#define AR_RxRSSIAnt11_S          8
+#define AR_RxRSSIAnt12            0x00ff0000
+#define AR_RxRSSIAnt12_S          16
+#define AR_RxRSSICombined         0xff000000
+#define AR_RxRSSICombined_S       24
+
+#define AR_RxEVM0           ds_rxstatus4
+#define AR_RxEVM1           ds_rxstatus5
+#define AR_RxEVM2           ds_rxstatus6
+
+#define AR_RxDone           0x00000001
+#define AR_RxFrameOK        0x00000002
+#define AR_CRCErr           0x00000004
+#define AR_DecryptCRCErr    0x00000008
+#define AR_PHYErr           0x00000010
+#define AR_MichaelErr       0x00000020
+#define AR_PreDelimCRCErr   0x00000040
+#define AR_RxStatusRsvd70   0x00000080
+#define AR_RxKeyIdxValid    0x00000100
+#define AR_KeyIdx           0x0000fe00
+#define AR_KeyIdx_S         9
+#define AR_PHYErrCode       0x0000ff00
+#define AR_PHYErrCode_S     8
+#define AR_RxMoreAggr       0x00010000
+#define AR_RxAggr           0x00020000
+#define AR_PostDelimCRCErr  0x00040000
+#define AR_RxStatusRsvd71   0x3ff80000
+#define AR_DecryptBusyErr   0x40000000
+#define AR_KeyMiss          0x80000000
+
+enum ath9k_tx_queue {
+	ATH9K_TX_QUEUE_INACTIVE = 0,
+	ATH9K_TX_QUEUE_DATA,
+};
+
+#define	ATH9K_NUM_TX_QUEUES 1
+
+/* Used as a queue subtype instead of a WMM AC */
+#define ATH9K_WME_UPSD	4
+
+enum ath9k_tx_queue_flags {
+	TXQ_FLAG_TXOKINT_ENABLE = 0x0001,
+	TXQ_FLAG_TXERRINT_ENABLE = 0x0001,
+	TXQ_FLAG_TXDESCINT_ENABLE = 0x0002,
+	TXQ_FLAG_TXEOLINT_ENABLE = 0x0004,
+	TXQ_FLAG_TXURNINT_ENABLE = 0x0008,
+	TXQ_FLAG_BACKOFF_DISABLE = 0x0010,
+	TXQ_FLAG_COMPRESSION_ENABLE = 0x0020,
+	TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE = 0x0040,
+	TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE = 0x0080,
+};
+
+#define ATH9K_TXQ_USEDEFAULT ((u32) -1)
+#define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001
+
+#define ATH9K_DECOMP_MASK_SIZE     128
+#define ATH9K_READY_TIME_LO_BOUND  50
+#define ATH9K_READY_TIME_HI_BOUND  96
+
+enum ath9k_pkt_type {
+	ATH9K_PKT_TYPE_NORMAL = 0,
+	ATH9K_PKT_TYPE_ATIM,
+	ATH9K_PKT_TYPE_PSPOLL,
+	ATH9K_PKT_TYPE_BEACON,
+	ATH9K_PKT_TYPE_PROBE_RESP,
+	ATH9K_PKT_TYPE_CHIRP,
+	ATH9K_PKT_TYPE_GRP_POLL,
+};
+
+struct ath9k_tx_queue_info {
+	u32 tqi_ver;
+	enum ath9k_tx_queue tqi_type;
+	int tqi_subtype;
+	enum ath9k_tx_queue_flags tqi_qflags;
+	u32 tqi_priority;
+	u32 tqi_aifs;
+	u32 tqi_cwmin;
+	u32 tqi_cwmax;
+	u16 tqi_shretry;
+	u16 tqi_lgretry;
+	u32 tqi_cbrPeriod;
+	u32 tqi_cbrOverflowLimit;
+	u32 tqi_burstTime;
+	u32 tqi_readyTime;
+	u32 tqi_physCompBuf;
+	u32 tqi_intFlags;
+};
+
+enum ath9k_rx_filter {
+	ATH9K_RX_FILTER_UCAST = 0x00000001,
+	ATH9K_RX_FILTER_MCAST = 0x00000002,
+	ATH9K_RX_FILTER_BCAST = 0x00000004,
+	ATH9K_RX_FILTER_CONTROL = 0x00000008,
+	ATH9K_RX_FILTER_BEACON = 0x00000010,
+	ATH9K_RX_FILTER_PROM = 0x00000020,
+	ATH9K_RX_FILTER_PROBEREQ = 0x00000080,
+	ATH9K_RX_FILTER_PHYERR = 0x00000100,
+	ATH9K_RX_FILTER_MYBEACON = 0x00000200,
+	ATH9K_RX_FILTER_COMP_BAR = 0x00000400,
+	ATH9K_RX_FILTER_COMP_BA = 0x00000800,
+	ATH9K_RX_FILTER_UNCOMP_BA_BAR = 0x00001000,
+	ATH9K_RX_FILTER_PSPOLL = 0x00004000,
+	ATH9K_RX_FILTER_PHYRADAR = 0x00002000,
+	ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000,
+};
+
+#define ATH9K_RATESERIES_RTS_CTS  0x0001
+#define ATH9K_RATESERIES_2040     0x0002
+#define ATH9K_RATESERIES_HALFGI   0x0004
+#define ATH9K_RATESERIES_STBC     0x0008
+
+struct ath9k_11n_rate_series {
+	u32 Tries;
+	u32 Rate;
+	u32 PktDuration;
+	u32 ChSel;
+	u32 RateFlags;
+};
+
+enum ath9k_key_type {
+	ATH9K_KEY_TYPE_CLEAR,
+	ATH9K_KEY_TYPE_WEP,
+	ATH9K_KEY_TYPE_AES,
+	ATH9K_KEY_TYPE_TKIP,
+};
+
+struct ath_hw;
+struct ath9k_channel;
+
+u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q);
+void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp);
+void ath9k_hw_txstart(struct ath_hw *ah, u32 q);
+void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds);
+u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q);
+int ath9k_hw_updatetxtriglevel(struct ath_hw *ah, int bIncTrigLevel);
+int ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q);
+void ath9k_hw_abort_tx_dma(struct ath_hw *ah);
+void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs);
+int ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
+			    const struct ath9k_tx_queue_info *qinfo);
+int ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
+			    struct ath9k_tx_queue_info *qinfo);
+int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
+			  const struct ath9k_tx_queue_info *qinfo);
+int ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q);
+int ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q);
+int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
+			struct ath_rx_status *rs, u64 tsf);
+void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
+			  u32 size, u32 flags);
+int ath9k_hw_setrxabort(struct ath_hw *ah, int set);
+void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp);
+void ath9k_hw_startpcureceive(struct ath_hw *ah, int is_scanning);
+void ath9k_hw_abortpcurecv(struct ath_hw *ah);
+int ath9k_hw_stopdmarecv(struct ath_hw *ah, int *reset);
+
+/* Interrupt Handling */
+int ath9k_hw_intrpend(struct ath_hw *ah);
+void ath9k_hw_set_interrupts(struct ath_hw *ah, unsigned int ints);
+void ath9k_hw_enable_interrupts(struct ath_hw *ah);
+void ath9k_hw_disable_interrupts(struct ath_hw *ah);
+
+void ar9002_hw_attach_mac_ops(struct ath_hw *ah);
+
+#endif /* MAC_H */
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/phy.h b/roms/ipxe/src/drivers/net/ath/ath9k/phy.h
new file mode 100644
index 0000000000000000000000000000000000000000..8b380305b0fc1acf8c2593acd474daa52f7eb6c9
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/phy.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef PHY_H
+#define PHY_H
+
+#define CHANSEL_DIV		15
+#define CHANSEL_2G(_freq)	(((_freq) * 0x10000) / CHANSEL_DIV)
+#define CHANSEL_5G(_freq)	(((_freq) * 0x8000) / CHANSEL_DIV)
+
+#define AR_PHY_BASE     0x9800
+#define AR_PHY(_n)      (AR_PHY_BASE + ((_n)<<2))
+
+#define AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX   0x0007E000
+#define AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX_S 13
+#define AR_PHY_TX_GAIN_CLC       0x0000001E
+#define AR_PHY_TX_GAIN_CLC_S     1
+#define AR_PHY_TX_GAIN           0x0007F000
+#define AR_PHY_TX_GAIN_S         12
+
+#define AR_PHY_CLC_TBL1      0xa35c
+#define AR_PHY_CLC_I0        0x07ff0000
+#define AR_PHY_CLC_I0_S      16
+#define AR_PHY_CLC_Q0        0x0000ffd0
+#define AR_PHY_CLC_Q0_S      5
+
+#define ANTSWAP_AB 0x0001
+#define REDUCE_CHAIN_0 0x00000050
+#define REDUCE_CHAIN_1 0x00000051
+#define AR_PHY_CHIP_ID 0x9818
+
+#define	AR_PHY_TIMING11_SPUR_FREQ_SD		0x3FF00000
+#define	AR_PHY_TIMING11_SPUR_FREQ_SD_S		20
+
+#define AR_PHY_PLL_CONTROL 0x16180
+#define AR_PHY_PLL_MODE 0x16184
+
+#endif
diff --git a/roms/ipxe/src/drivers/net/ath/ath9k/reg.h b/roms/ipxe/src/drivers/net/ath/ath9k/reg.h
new file mode 100644
index 0000000000000000000000000000000000000000..c18ee9921fb19ef9000122c21d1da887c5731094
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath9k/reg.h
@@ -0,0 +1,1919 @@
+/*
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef REG_H
+#define REG_H
+
+#include "../reg.h"
+
+#define AR_CR                0x0008
+#define AR_CR_RXE            (AR_SREV_9300_20_OR_LATER(ah) ? 0x0000000c : 0x00000004)
+#define AR_CR_RXD            0x00000020
+#define AR_CR_SWI            0x00000040
+
+#define AR_RXDP              0x000C
+
+#define AR_CFG               0x0014
+#define AR_CFG_SWTD          0x00000001
+#define AR_CFG_SWTB          0x00000002
+#define AR_CFG_SWRD          0x00000004
+#define AR_CFG_SWRB          0x00000008
+#define AR_CFG_SWRG          0x00000010
+#define AR_CFG_AP_ADHOC_INDICATION 0x00000020
+#define AR_CFG_PHOK          0x00000100
+#define AR_CFG_CLK_GATE_DIS  0x00000400
+#define AR_CFG_EEBS          0x00000200
+#define AR_CFG_PCI_MASTER_REQ_Q_THRESH         0x00060000
+#define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S       17
+
+#define AR_RXBP_THRESH       0x0018
+#define AR_RXBP_THRESH_HP    0x0000000f
+#define AR_RXBP_THRESH_HP_S  0
+#define AR_RXBP_THRESH_LP    0x00003f00
+#define AR_RXBP_THRESH_LP_S  8
+
+#define AR_MIRT              0x0020
+#define AR_MIRT_VAL          0x0000ffff
+#define AR_MIRT_VAL_S        16
+
+#define AR_IER               0x0024
+#define AR_IER_ENABLE        0x00000001
+#define AR_IER_DISABLE       0x00000000
+
+#define AR_TIMT              0x0028
+#define AR_TIMT_LAST         0x0000ffff
+#define AR_TIMT_LAST_S       0
+#define AR_TIMT_FIRST        0xffff0000
+#define AR_TIMT_FIRST_S      16
+
+#define AR_RIMT              0x002C
+#define AR_RIMT_LAST         0x0000ffff
+#define AR_RIMT_LAST_S       0
+#define AR_RIMT_FIRST        0xffff0000
+#define AR_RIMT_FIRST_S      16
+
+#define AR_DMASIZE_4B        0x00000000
+#define AR_DMASIZE_8B        0x00000001
+#define AR_DMASIZE_16B       0x00000002
+#define AR_DMASIZE_32B       0x00000003
+#define AR_DMASIZE_64B       0x00000004
+#define AR_DMASIZE_128B      0x00000005
+#define AR_DMASIZE_256B      0x00000006
+#define AR_DMASIZE_512B      0x00000007
+
+#define AR_TXCFG             0x0030
+#define AR_TXCFG_DMASZ_MASK  0x00000007
+#define AR_TXCFG_DMASZ_4B    0
+#define AR_TXCFG_DMASZ_8B    1
+#define AR_TXCFG_DMASZ_16B   2
+#define AR_TXCFG_DMASZ_32B   3
+#define AR_TXCFG_DMASZ_64B   4
+#define AR_TXCFG_DMASZ_128B  5
+#define AR_TXCFG_DMASZ_256B  6
+#define AR_TXCFG_DMASZ_512B  7
+#define AR_FTRIG             0x000003F0
+#define AR_FTRIG_S           4
+#define AR_FTRIG_IMMED       0x00000000
+#define AR_FTRIG_64B         0x00000010
+#define AR_FTRIG_128B        0x00000020
+#define AR_FTRIG_192B        0x00000030
+#define AR_FTRIG_256B        0x00000040
+#define AR_FTRIG_512B        0x00000080
+#define AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY 0x00000800
+
+#define AR_RXCFG             0x0034
+#define AR_RXCFG_CHIRP       0x00000008
+#define AR_RXCFG_ZLFDMA      0x00000010
+#define AR_RXCFG_DMASZ_MASK  0x00000007
+#define AR_RXCFG_DMASZ_4B    0
+#define AR_RXCFG_DMASZ_8B    1
+#define AR_RXCFG_DMASZ_16B   2
+#define AR_RXCFG_DMASZ_32B   3
+#define AR_RXCFG_DMASZ_64B   4
+#define AR_RXCFG_DMASZ_128B  5
+#define AR_RXCFG_DMASZ_256B  6
+#define AR_RXCFG_DMASZ_512B  7
+
+#define AR_TOPS              0x0044
+#define AR_TOPS_MASK         0x0000FFFF
+
+#define AR_RXNPTO            0x0048
+#define AR_RXNPTO_MASK       0x000003FF
+
+#define AR_TXNPTO            0x004C
+#define AR_TXNPTO_MASK       0x000003FF
+#define AR_TXNPTO_QCU_MASK   0x000FFC00
+
+#define AR_RPGTO             0x0050
+#define AR_RPGTO_MASK        0x000003FF
+
+#define AR_RPCNT             0x0054
+#define AR_RPCNT_MASK        0x0000001F
+
+#define AR_MACMISC           0x0058
+#define AR_MACMISC_PCI_EXT_FORCE        0x00000010
+#define AR_MACMISC_DMA_OBS              0x000001E0
+#define AR_MACMISC_DMA_OBS_S            5
+#define AR_MACMISC_DMA_OBS_LINE_0       0
+#define AR_MACMISC_DMA_OBS_LINE_1       1
+#define AR_MACMISC_DMA_OBS_LINE_2       2
+#define AR_MACMISC_DMA_OBS_LINE_3       3
+#define AR_MACMISC_DMA_OBS_LINE_4       4
+#define AR_MACMISC_DMA_OBS_LINE_5       5
+#define AR_MACMISC_DMA_OBS_LINE_6       6
+#define AR_MACMISC_DMA_OBS_LINE_7       7
+#define AR_MACMISC_DMA_OBS_LINE_8       8
+#define AR_MACMISC_MISC_OBS             0x00000E00
+#define AR_MACMISC_MISC_OBS_S           9
+#define AR_MACMISC_MISC_OBS_BUS_LSB     0x00007000
+#define AR_MACMISC_MISC_OBS_BUS_LSB_S   12
+#define AR_MACMISC_MISC_OBS_BUS_MSB     0x00038000
+#define AR_MACMISC_MISC_OBS_BUS_MSB_S   15
+#define AR_MACMISC_MISC_OBS_BUS_1       1
+
+#define AR_DATABUF_SIZE		0x0060
+#define AR_DATABUF_SIZE_MASK	0x00000FFF
+
+#define AR_GTXTO    0x0064
+#define AR_GTXTO_TIMEOUT_COUNTER    0x0000FFFF
+#define AR_GTXTO_TIMEOUT_LIMIT      0xFFFF0000
+#define AR_GTXTO_TIMEOUT_LIMIT_S    16
+
+#define AR_GTTM     0x0068
+#define AR_GTTM_USEC          0x00000001
+#define AR_GTTM_IGNORE_IDLE   0x00000002
+#define AR_GTTM_RESET_IDLE    0x00000004
+#define AR_GTTM_CST_USEC      0x00000008
+
+#define AR_CST         0x006C
+#define AR_CST_TIMEOUT_COUNTER    0x0000FFFF
+#define AR_CST_TIMEOUT_LIMIT      0xFFFF0000
+#define AR_CST_TIMEOUT_LIMIT_S    16
+
+#define AR_HP_RXDP 0x0074
+#define AR_LP_RXDP 0x0078
+
+#define AR_ISR               0x0080
+#define AR_ISR_RXOK          0x00000001
+#define AR_ISR_RXDESC        0x00000002
+#define AR_ISR_HP_RXOK	     0x00000001
+#define AR_ISR_LP_RXOK	     0x00000002
+#define AR_ISR_RXERR         0x00000004
+#define AR_ISR_RXNOPKT       0x00000008
+#define AR_ISR_RXEOL         0x00000010
+#define AR_ISR_RXORN         0x00000020
+#define AR_ISR_TXOK          0x00000040
+#define AR_ISR_TXDESC        0x00000080
+#define AR_ISR_TXERR         0x00000100
+#define AR_ISR_TXNOPKT       0x00000200
+#define AR_ISR_TXEOL         0x00000400
+#define AR_ISR_TXURN         0x00000800
+#define AR_ISR_MIB           0x00001000
+#define AR_ISR_SWI           0x00002000
+#define AR_ISR_RXPHY         0x00004000
+#define AR_ISR_RXKCM         0x00008000
+#define AR_ISR_SWBA          0x00010000
+#define AR_ISR_BRSSI         0x00020000
+#define AR_ISR_BMISS         0x00040000
+#define AR_ISR_BNR           0x00100000
+#define AR_ISR_RXCHIRP       0x00200000
+#define AR_ISR_BCNMISC       0x00800000
+#define AR_ISR_TIM           0x00800000
+#define AR_ISR_QCBROVF       0x02000000
+#define AR_ISR_QCBRURN       0x04000000
+#define AR_ISR_QTRIG         0x08000000
+#define AR_ISR_GENTMR        0x10000000
+
+#define AR_ISR_TXMINTR       0x00080000
+#define AR_ISR_RXMINTR       0x01000000
+#define AR_ISR_TXINTM        0x40000000
+#define AR_ISR_RXINTM        0x80000000
+
+#define AR_ISR_S0               0x0084
+#define AR_ISR_S0_QCU_TXOK      0x000003FF
+#define AR_ISR_S0_QCU_TXOK_S    0
+#define AR_ISR_S0_QCU_TXDESC    0x03FF0000
+#define AR_ISR_S0_QCU_TXDESC_S  16
+
+#define AR_ISR_S1              0x0088
+#define AR_ISR_S1_QCU_TXERR    0x000003FF
+#define AR_ISR_S1_QCU_TXERR_S  0
+#define AR_ISR_S1_QCU_TXEOL    0x03FF0000
+#define AR_ISR_S1_QCU_TXEOL_S  16
+
+#define AR_ISR_S2              0x008c
+#define AR_ISR_S2_QCU_TXURN    0x000003FF
+#define AR_ISR_S2_BB_WATCHDOG  0x00010000
+#define AR_ISR_S2_CST          0x00400000
+#define AR_ISR_S2_GTT          0x00800000
+#define AR_ISR_S2_TIM          0x01000000
+#define AR_ISR_S2_CABEND       0x02000000
+#define AR_ISR_S2_DTIMSYNC     0x04000000
+#define AR_ISR_S2_BCNTO        0x08000000
+#define AR_ISR_S2_CABTO        0x10000000
+#define AR_ISR_S2_DTIM         0x20000000
+#define AR_ISR_S2_TSFOOR       0x40000000
+#define AR_ISR_S2_TBTT_TIME    0x80000000
+
+#define AR_ISR_S3             0x0090
+#define AR_ISR_S3_QCU_QCBROVF    0x000003FF
+#define AR_ISR_S3_QCU_QCBRURN    0x03FF0000
+
+#define AR_ISR_S4              0x0094
+#define AR_ISR_S4_QCU_QTRIG    0x000003FF
+#define AR_ISR_S4_RESV0        0xFFFFFC00
+
+#define AR_ISR_S5                   0x0098
+#define AR_ISR_S5_TIMER_TRIG        0x000000FF
+#define AR_ISR_S5_TIMER_THRESH      0x0007FE00
+#define AR_ISR_S5_TIM_TIMER         0x00000010
+#define AR_ISR_S5_DTIM_TIMER        0x00000020
+#define AR_IMR_S5                   0x00b8
+#define AR_IMR_S5_TIM_TIMER         0x00000010
+#define AR_IMR_S5_DTIM_TIMER        0x00000020
+#define AR_ISR_S5_GENTIMER_TRIG     0x0000FF80
+#define AR_ISR_S5_GENTIMER_TRIG_S   0
+#define AR_ISR_S5_GENTIMER_THRESH   0xFF800000
+#define AR_ISR_S5_GENTIMER_THRESH_S 16
+#define AR_IMR_S5_GENTIMER_TRIG     0x0000FF80
+#define AR_IMR_S5_GENTIMER_TRIG_S   0
+#define AR_IMR_S5_GENTIMER_THRESH   0xFF800000
+#define AR_IMR_S5_GENTIMER_THRESH_S 16
+
+#define AR_IMR               0x00a0
+#define AR_IMR_RXOK          0x00000001
+#define AR_IMR_RXDESC        0x00000002
+#define AR_IMR_RXOK_HP	     0x00000001
+#define AR_IMR_RXOK_LP	     0x00000002
+#define AR_IMR_RXERR         0x00000004
+#define AR_IMR_RXNOPKT       0x00000008
+#define AR_IMR_RXEOL         0x00000010
+#define AR_IMR_RXORN         0x00000020
+#define AR_IMR_TXOK          0x00000040
+#define AR_IMR_TXDESC        0x00000080
+#define AR_IMR_TXERR         0x00000100
+#define AR_IMR_TXNOPKT       0x00000200
+#define AR_IMR_TXEOL         0x00000400
+#define AR_IMR_TXURN         0x00000800
+#define AR_IMR_MIB           0x00001000
+#define AR_IMR_SWI           0x00002000
+#define AR_IMR_RXPHY         0x00004000
+#define AR_IMR_RXKCM         0x00008000
+#define AR_IMR_SWBA          0x00010000
+#define AR_IMR_BRSSI         0x00020000
+#define AR_IMR_BMISS         0x00040000
+#define AR_IMR_BNR           0x00100000
+#define AR_IMR_RXCHIRP       0x00200000
+#define AR_IMR_BCNMISC       0x00800000
+#define AR_IMR_TIM           0x00800000
+#define AR_IMR_QCBROVF       0x02000000
+#define AR_IMR_QCBRURN       0x04000000
+#define AR_IMR_QTRIG         0x08000000
+#define AR_IMR_GENTMR        0x10000000
+
+#define AR_IMR_TXMINTR       0x00080000
+#define AR_IMR_RXMINTR       0x01000000
+#define AR_IMR_TXINTM        0x40000000
+#define AR_IMR_RXINTM        0x80000000
+
+#define AR_IMR_S0               0x00a4
+#define AR_IMR_S0_QCU_TXOK      0x000003FF
+#define AR_IMR_S0_QCU_TXOK_S    0
+#define AR_IMR_S0_QCU_TXDESC    0x03FF0000
+#define AR_IMR_S0_QCU_TXDESC_S  16
+
+#define AR_IMR_S1              0x00a8
+#define AR_IMR_S1_QCU_TXERR    0x000003FF
+#define AR_IMR_S1_QCU_TXERR_S  0
+#define AR_IMR_S1_QCU_TXEOL    0x03FF0000
+#define AR_IMR_S1_QCU_TXEOL_S  16
+
+#define AR_IMR_S2              0x00ac
+#define AR_IMR_S2_QCU_TXURN    0x000003FF
+#define AR_IMR_S2_QCU_TXURN_S  0
+#define AR_IMR_S2_CST          0x00400000
+#define AR_IMR_S2_GTT          0x00800000
+#define AR_IMR_S2_TIM          0x01000000
+#define AR_IMR_S2_CABEND       0x02000000
+#define AR_IMR_S2_DTIMSYNC     0x04000000
+#define AR_IMR_S2_BCNTO        0x08000000
+#define AR_IMR_S2_CABTO        0x10000000
+#define AR_IMR_S2_DTIM         0x20000000
+#define AR_IMR_S2_TSFOOR       0x40000000
+
+#define AR_IMR_S3                0x00b0
+#define AR_IMR_S3_QCU_QCBROVF    0x000003FF
+#define AR_IMR_S3_QCU_QCBRURN    0x03FF0000
+#define AR_IMR_S3_QCU_QCBRURN_S  16
+
+#define AR_IMR_S4              0x00b4
+#define AR_IMR_S4_QCU_QTRIG    0x000003FF
+#define AR_IMR_S4_RESV0        0xFFFFFC00
+
+#define AR_IMR_S5              0x00b8
+#define AR_IMR_S5_TIMER_TRIG        0x000000FF
+#define AR_IMR_S5_TIMER_THRESH      0x0000FF00
+
+
+#define AR_ISR_RAC            0x00c0
+#define AR_ISR_S0_S           0x00c4
+#define AR_ISR_S0_QCU_TXOK      0x000003FF
+#define AR_ISR_S0_QCU_TXOK_S    0
+#define AR_ISR_S0_QCU_TXDESC    0x03FF0000
+#define AR_ISR_S0_QCU_TXDESC_S  16
+
+#define AR_ISR_S1_S           0x00c8
+#define AR_ISR_S1_QCU_TXERR    0x000003FF
+#define AR_ISR_S1_QCU_TXERR_S  0
+#define AR_ISR_S1_QCU_TXEOL    0x03FF0000
+#define AR_ISR_S1_QCU_TXEOL_S  16
+
+#define AR_ISR_S2_S           (AR_SREV_9300_20_OR_LATER(ah) ? 0x00d0 : 0x00cc)
+#define AR_ISR_S3_S           (AR_SREV_9300_20_OR_LATER(ah) ? 0x00d4 : 0x00d0)
+#define AR_ISR_S4_S           (AR_SREV_9300_20_OR_LATER(ah) ? 0x00d8 : 0x00d4)
+#define AR_ISR_S5_S           (AR_SREV_9300_20_OR_LATER(ah) ? 0x00dc : 0x00d8)
+#define AR_DMADBG_0           0x00e0
+#define AR_DMADBG_1           0x00e4
+#define AR_DMADBG_2           0x00e8
+#define AR_DMADBG_3           0x00ec
+#define AR_DMADBG_4           0x00f0
+#define AR_DMADBG_5           0x00f4
+#define AR_DMADBG_6           0x00f8
+#define AR_DMADBG_7           0x00fc
+
+#define AR_NUM_QCU      10
+#define AR_QCU_0        0x0001
+#define AR_QCU_1        0x0002
+#define AR_QCU_2        0x0004
+#define AR_QCU_3        0x0008
+#define AR_QCU_4        0x0010
+#define AR_QCU_5        0x0020
+#define AR_QCU_6        0x0040
+#define AR_QCU_7        0x0080
+#define AR_QCU_8        0x0100
+#define AR_QCU_9        0x0200
+
+#define AR_Q0_TXDP           0x0800
+#define AR_Q1_TXDP           0x0804
+#define AR_Q2_TXDP           0x0808
+#define AR_Q3_TXDP           0x080c
+#define AR_Q4_TXDP           0x0810
+#define AR_Q5_TXDP           0x0814
+#define AR_Q6_TXDP           0x0818
+#define AR_Q7_TXDP           0x081c
+#define AR_Q8_TXDP           0x0820
+#define AR_Q9_TXDP           0x0824
+#define AR_QTXDP(_i)    (AR_Q0_TXDP + ((_i)<<2))
+
+#define AR_Q_STATUS_RING_START	0x830
+#define AR_Q_STATUS_RING_END	0x834
+
+#define AR_Q_TXE             0x0840
+#define AR_Q_TXE_M           0x000003FF
+
+#define AR_Q_TXD             0x0880
+#define AR_Q_TXD_M           0x000003FF
+
+#define AR_Q0_CBRCFG         0x08c0
+#define AR_Q1_CBRCFG         0x08c4
+#define AR_Q2_CBRCFG         0x08c8
+#define AR_Q3_CBRCFG         0x08cc
+#define AR_Q4_CBRCFG         0x08d0
+#define AR_Q5_CBRCFG         0x08d4
+#define AR_Q6_CBRCFG         0x08d8
+#define AR_Q7_CBRCFG         0x08dc
+#define AR_Q8_CBRCFG         0x08e0
+#define AR_Q9_CBRCFG         0x08e4
+#define AR_QCBRCFG(_i)      (AR_Q0_CBRCFG + ((_i)<<2))
+#define AR_Q_CBRCFG_INTERVAL     0x00FFFFFF
+#define AR_Q_CBRCFG_INTERVAL_S   0
+#define AR_Q_CBRCFG_OVF_THRESH   0xFF000000
+#define AR_Q_CBRCFG_OVF_THRESH_S 24
+
+#define AR_Q0_RDYTIMECFG         0x0900
+#define AR_Q1_RDYTIMECFG         0x0904
+#define AR_Q2_RDYTIMECFG         0x0908
+#define AR_Q3_RDYTIMECFG         0x090c
+#define AR_Q4_RDYTIMECFG         0x0910
+#define AR_Q5_RDYTIMECFG         0x0914
+#define AR_Q6_RDYTIMECFG         0x0918
+#define AR_Q7_RDYTIMECFG         0x091c
+#define AR_Q8_RDYTIMECFG         0x0920
+#define AR_Q9_RDYTIMECFG         0x0924
+#define AR_QRDYTIMECFG(_i)       (AR_Q0_RDYTIMECFG + ((_i)<<2))
+#define AR_Q_RDYTIMECFG_DURATION   0x00FFFFFF
+#define AR_Q_RDYTIMECFG_DURATION_S 0
+#define AR_Q_RDYTIMECFG_EN         0x01000000
+
+#define AR_Q_ONESHOTARM_SC       0x0940
+#define AR_Q_ONESHOTARM_SC_M     0x000003FF
+#define AR_Q_ONESHOTARM_SC_RESV0 0xFFFFFC00
+
+#define AR_Q_ONESHOTARM_CC       0x0980
+#define AR_Q_ONESHOTARM_CC_M     0x000003FF
+#define AR_Q_ONESHOTARM_CC_RESV0 0xFFFFFC00
+
+#define AR_Q0_MISC         0x09c0
+#define AR_Q1_MISC         0x09c4
+#define AR_Q2_MISC         0x09c8
+#define AR_Q3_MISC         0x09cc
+#define AR_Q4_MISC         0x09d0
+#define AR_Q5_MISC         0x09d4
+#define AR_Q6_MISC         0x09d8
+#define AR_Q7_MISC         0x09dc
+#define AR_Q8_MISC         0x09e0
+#define AR_Q9_MISC         0x09e4
+#define AR_QMISC(_i)       (AR_Q0_MISC + ((_i)<<2))
+#define AR_Q_MISC_FSP                     0x0000000F
+#define AR_Q_MISC_FSP_ASAP                0
+#define AR_Q_MISC_FSP_CBR                 1
+#define AR_Q_MISC_FSP_DBA_GATED           2
+#define AR_Q_MISC_FSP_TIM_GATED           3
+#define AR_Q_MISC_FSP_BEACON_SENT_GATED   4
+#define AR_Q_MISC_FSP_BEACON_RCVD_GATED   5
+#define AR_Q_MISC_ONE_SHOT_EN             0x00000010
+#define AR_Q_MISC_CBR_INCR_DIS1           0x00000020
+#define AR_Q_MISC_CBR_INCR_DIS0           0x00000040
+#define AR_Q_MISC_BEACON_USE              0x00000080
+#define AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN   0x00000100
+#define AR_Q_MISC_RDYTIME_EXP_POLICY      0x00000200
+#define AR_Q_MISC_RESET_CBR_EXP_CTR       0x00000400
+#define AR_Q_MISC_DCU_EARLY_TERM_REQ      0x00000800
+#define AR_Q_MISC_RESV0                   0xFFFFF000
+
+#define AR_Q0_STS         0x0a00
+#define AR_Q1_STS         0x0a04
+#define AR_Q2_STS         0x0a08
+#define AR_Q3_STS         0x0a0c
+#define AR_Q4_STS         0x0a10
+#define AR_Q5_STS         0x0a14
+#define AR_Q6_STS         0x0a18
+#define AR_Q7_STS         0x0a1c
+#define AR_Q8_STS         0x0a20
+#define AR_Q9_STS         0x0a24
+#define AR_QSTS(_i)       (AR_Q0_STS + ((_i)<<2))
+#define AR_Q_STS_PEND_FR_CNT          0x00000003
+#define AR_Q_STS_RESV0                0x000000FC
+#define AR_Q_STS_CBR_EXP_CNT          0x0000FF00
+#define AR_Q_STS_RESV1                0xFFFF0000
+
+#define AR_Q_RDYTIMESHDN    0x0a40
+#define AR_Q_RDYTIMESHDN_M  0x000003FF
+
+/* MAC Descriptor CRC check */
+#define AR_Q_DESC_CRCCHK    0xa44
+/* Enable CRC check on the descriptor fetched from host */
+#define AR_Q_DESC_CRCCHK_EN 1
+
+#define AR_NUM_DCU      10
+#define AR_DCU_0        0x0001
+#define AR_DCU_1        0x0002
+#define AR_DCU_2        0x0004
+#define AR_DCU_3        0x0008
+#define AR_DCU_4        0x0010
+#define AR_DCU_5        0x0020
+#define AR_DCU_6        0x0040
+#define AR_DCU_7        0x0080
+#define AR_DCU_8        0x0100
+#define AR_DCU_9        0x0200
+
+#define AR_D0_QCUMASK     0x1000
+#define AR_D1_QCUMASK     0x1004
+#define AR_D2_QCUMASK     0x1008
+#define AR_D3_QCUMASK     0x100c
+#define AR_D4_QCUMASK     0x1010
+#define AR_D5_QCUMASK     0x1014
+#define AR_D6_QCUMASK     0x1018
+#define AR_D7_QCUMASK     0x101c
+#define AR_D8_QCUMASK     0x1020
+#define AR_D9_QCUMASK     0x1024
+#define AR_DQCUMASK(_i)   (AR_D0_QCUMASK + ((_i)<<2))
+#define AR_D_QCUMASK         0x000003FF
+#define AR_D_QCUMASK_RESV0   0xFFFFFC00
+
+#define AR_D_TXBLK_CMD  0x1038
+#define AR_D_TXBLK_DATA(i) (AR_D_TXBLK_CMD+(i))
+
+#define AR_D0_LCL_IFS     0x1040
+#define AR_D1_LCL_IFS     0x1044
+#define AR_D2_LCL_IFS     0x1048
+#define AR_D3_LCL_IFS     0x104c
+#define AR_D4_LCL_IFS     0x1050
+#define AR_D5_LCL_IFS     0x1054
+#define AR_D6_LCL_IFS     0x1058
+#define AR_D7_LCL_IFS     0x105c
+#define AR_D8_LCL_IFS     0x1060
+#define AR_D9_LCL_IFS     0x1064
+#define AR_DLCL_IFS(_i)   (AR_D0_LCL_IFS + ((_i)<<2))
+#define AR_D_LCL_IFS_CWMIN       0x000003FF
+#define AR_D_LCL_IFS_CWMIN_S     0
+#define AR_D_LCL_IFS_CWMAX       0x000FFC00
+#define AR_D_LCL_IFS_CWMAX_S     10
+#define AR_D_LCL_IFS_AIFS        0x0FF00000
+#define AR_D_LCL_IFS_AIFS_S      20
+
+#define AR_D_LCL_IFS_RESV0    0xF0000000
+
+#define AR_D0_RETRY_LIMIT     0x1080
+#define AR_D1_RETRY_LIMIT     0x1084
+#define AR_D2_RETRY_LIMIT     0x1088
+#define AR_D3_RETRY_LIMIT     0x108c
+#define AR_D4_RETRY_LIMIT     0x1090
+#define AR_D5_RETRY_LIMIT     0x1094
+#define AR_D6_RETRY_LIMIT     0x1098
+#define AR_D7_RETRY_LIMIT     0x109c
+#define AR_D8_RETRY_LIMIT     0x10a0
+#define AR_D9_RETRY_LIMIT     0x10a4
+#define AR_DRETRY_LIMIT(_i)   (AR_D0_RETRY_LIMIT + ((_i)<<2))
+#define AR_D_RETRY_LIMIT_FR_SH       0x0000000F
+#define AR_D_RETRY_LIMIT_FR_SH_S     0
+#define AR_D_RETRY_LIMIT_STA_SH      0x00003F00
+#define AR_D_RETRY_LIMIT_STA_SH_S    8
+#define AR_D_RETRY_LIMIT_STA_LG      0x000FC000
+#define AR_D_RETRY_LIMIT_STA_LG_S    14
+#define AR_D_RETRY_LIMIT_RESV0       0xFFF00000
+
+#define AR_D0_CHNTIME     0x10c0
+#define AR_D1_CHNTIME     0x10c4
+#define AR_D2_CHNTIME     0x10c8
+#define AR_D3_CHNTIME     0x10cc
+#define AR_D4_CHNTIME     0x10d0
+#define AR_D5_CHNTIME     0x10d4
+#define AR_D6_CHNTIME     0x10d8
+#define AR_D7_CHNTIME     0x10dc
+#define AR_D8_CHNTIME     0x10e0
+#define AR_D9_CHNTIME     0x10e4
+#define AR_DCHNTIME(_i)   (AR_D0_CHNTIME + ((_i)<<2))
+#define AR_D_CHNTIME_DUR         0x000FFFFF
+#define AR_D_CHNTIME_DUR_S       0
+#define AR_D_CHNTIME_EN          0x00100000
+#define AR_D_CHNTIME_RESV0       0xFFE00000
+
+#define AR_D0_MISC        0x1100
+#define AR_D1_MISC        0x1104
+#define AR_D2_MISC        0x1108
+#define AR_D3_MISC        0x110c
+#define AR_D4_MISC        0x1110
+#define AR_D5_MISC        0x1114
+#define AR_D6_MISC        0x1118
+#define AR_D7_MISC        0x111c
+#define AR_D8_MISC        0x1120
+#define AR_D9_MISC        0x1124
+#define AR_DMISC(_i)      (AR_D0_MISC + ((_i)<<2))
+#define AR_D_MISC_BKOFF_THRESH        0x0000003F
+#define AR_D_MISC_RETRY_CNT_RESET_EN  0x00000040
+#define AR_D_MISC_CW_RESET_EN         0x00000080
+#define AR_D_MISC_FRAG_WAIT_EN        0x00000100
+#define AR_D_MISC_FRAG_BKOFF_EN       0x00000200
+#define AR_D_MISC_CW_BKOFF_EN         0x00001000
+#define AR_D_MISC_VIR_COL_HANDLING    0x0000C000
+#define AR_D_MISC_VIR_COL_HANDLING_S  14
+#define AR_D_MISC_VIR_COL_HANDLING_DEFAULT 0
+#define AR_D_MISC_VIR_COL_HANDLING_IGNORE  1
+#define AR_D_MISC_BEACON_USE          0x00010000
+#define AR_D_MISC_ARB_LOCKOUT_CNTRL   0x00060000
+#define AR_D_MISC_ARB_LOCKOUT_CNTRL_S 17
+#define AR_D_MISC_ARB_LOCKOUT_CNTRL_NONE     0
+#define AR_D_MISC_ARB_LOCKOUT_CNTRL_INTRA_FR 1
+#define AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL   2
+#define AR_D_MISC_ARB_LOCKOUT_IGNORE  0x00080000
+#define AR_D_MISC_SEQ_NUM_INCR_DIS    0x00100000
+#define AR_D_MISC_POST_FR_BKOFF_DIS   0x00200000
+#define AR_D_MISC_VIT_COL_CW_BKOFF_EN 0x00400000
+#define AR_D_MISC_BLOWN_IFS_RETRY_EN  0x00800000
+#define AR_D_MISC_RESV0               0xFF000000
+
+#define AR_D_SEQNUM      0x1140
+
+#define AR_D_GBL_IFS_SIFS         0x1030
+#define AR_D_GBL_IFS_SIFS_M       0x0000FFFF
+#define AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR 0x000003AB
+#define AR_D_GBL_IFS_SIFS_RESV0   0xFFFFFFFF
+
+#define AR_D_TXBLK_BASE            0x1038
+#define AR_D_TXBLK_WRITE_BITMASK    0x0000FFFF
+#define AR_D_TXBLK_WRITE_BITMASK_S  0
+#define AR_D_TXBLK_WRITE_SLICE      0x000F0000
+#define AR_D_TXBLK_WRITE_SLICE_S    16
+#define AR_D_TXBLK_WRITE_DCU        0x00F00000
+#define AR_D_TXBLK_WRITE_DCU_S      20
+#define AR_D_TXBLK_WRITE_COMMAND    0x0F000000
+#define AR_D_TXBLK_WRITE_COMMAND_S      24
+
+#define AR_D_GBL_IFS_SLOT         0x1070
+#define AR_D_GBL_IFS_SLOT_M       0x0000FFFF
+#define AR_D_GBL_IFS_SLOT_RESV0   0xFFFF0000
+#define AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR   0x00000420
+
+#define AR_D_GBL_IFS_EIFS         0x10b0
+#define AR_D_GBL_IFS_EIFS_M       0x0000FFFF
+#define AR_D_GBL_IFS_EIFS_RESV0   0xFFFF0000
+#define AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR   0x0000A5EB
+
+#define AR_D_GBL_IFS_MISC        0x10f0
+#define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL        0x00000007
+#define AR_D_GBL_IFS_MISC_TURBO_MODE            0x00000008
+#define AR_D_GBL_IFS_MISC_USEC_DURATION         0x000FFC00
+#define AR_D_GBL_IFS_MISC_DCU_ARBITER_DLY       0x00300000
+#define AR_D_GBL_IFS_MISC_RANDOM_LFSR_SLICE_DIS 0x01000000
+#define AR_D_GBL_IFS_MISC_SLOT_XMIT_WIND_LEN    0x06000000
+#define AR_D_GBL_IFS_MISC_FORCE_XMIT_SLOT_BOUND 0x08000000
+#define AR_D_GBL_IFS_MISC_IGNORE_BACKOFF        0x10000000
+
+#define AR_D_FPCTL                  0x1230
+#define AR_D_FPCTL_DCU              0x0000000F
+#define AR_D_FPCTL_DCU_S            0
+#define AR_D_FPCTL_PREFETCH_EN      0x00000010
+#define AR_D_FPCTL_BURST_PREFETCH   0x00007FE0
+#define AR_D_FPCTL_BURST_PREFETCH_S 5
+
+#define AR_D_TXPSE                 0x1270
+#define AR_D_TXPSE_CTRL            0x000003FF
+#define AR_D_TXPSE_RESV0           0x0000FC00
+#define AR_D_TXPSE_STATUS          0x00010000
+#define AR_D_TXPSE_RESV1           0xFFFE0000
+
+#define AR_D_TXSLOTMASK            0x12f0
+#define AR_D_TXSLOTMASK_NUM        0x0000000F
+
+#define AR_CFG_LED                     0x1f04
+#define AR_CFG_SCLK_RATE_IND           0x00000003
+#define AR_CFG_SCLK_RATE_IND_S         0
+#define AR_CFG_SCLK_32MHZ              0x00000000
+#define AR_CFG_SCLK_4MHZ               0x00000001
+#define AR_CFG_SCLK_1MHZ               0x00000002
+#define AR_CFG_SCLK_32KHZ              0x00000003
+#define AR_CFG_LED_BLINK_SLOW          0x00000008
+#define AR_CFG_LED_BLINK_THRESH_SEL    0x00000070
+#define AR_CFG_LED_MODE_SEL            0x00000380
+#define AR_CFG_LED_MODE_SEL_S          7
+#define AR_CFG_LED_POWER               0x00000280
+#define AR_CFG_LED_POWER_S             7
+#define AR_CFG_LED_NETWORK             0x00000300
+#define AR_CFG_LED_NETWORK_S           7
+#define AR_CFG_LED_MODE_PROP           0x0
+#define AR_CFG_LED_MODE_RPROP          0x1
+#define AR_CFG_LED_MODE_SPLIT          0x2
+#define AR_CFG_LED_MODE_RAND           0x3
+#define AR_CFG_LED_MODE_POWER_OFF      0x4
+#define AR_CFG_LED_MODE_POWER_ON       0x5
+#define AR_CFG_LED_MODE_NETWORK_OFF    0x4
+#define AR_CFG_LED_MODE_NETWORK_ON     0x6
+#define AR_CFG_LED_ASSOC_CTL           0x00000c00
+#define AR_CFG_LED_ASSOC_CTL_S         10
+#define AR_CFG_LED_ASSOC_NONE          0x0
+#define AR_CFG_LED_ASSOC_ACTIVE        0x1
+#define AR_CFG_LED_ASSOC_PENDING       0x2
+
+#define AR_CFG_LED_BLINK_SLOW          0x00000008
+#define AR_CFG_LED_BLINK_SLOW_S        3
+
+#define AR_CFG_LED_BLINK_THRESH_SEL    0x00000070
+#define AR_CFG_LED_BLINK_THRESH_SEL_S  4
+
+#define AR_MAC_SLEEP                0x1f00
+#define AR_MAC_SLEEP_MAC_AWAKE      0x00000000
+#define AR_MAC_SLEEP_MAC_ASLEEP     0x00000001
+
+#define AR_RC                0x4000
+#define AR_RC_AHB            0x00000001
+#define AR_RC_APB            0x00000002
+#define AR_RC_HOSTIF         0x00000100
+
+#define AR_WA			(AR_SREV_9340(ah) ? 0x40c4 : 0x4004)
+#define AR_WA_BIT6			(1 << 6)
+#define AR_WA_BIT7			(1 << 7)
+#define AR_WA_BIT23			(1 << 23)
+#define AR_WA_D3_L1_DISABLE		(1 << 14)
+#define AR_WA_D3_TO_L1_DISABLE_REAL     (1 << 16)
+#define AR_WA_ASPM_TIMER_BASED_DISABLE  (1 << 17)
+#define AR_WA_RESET_EN                  (1 << 18) /* Sw Control to enable PCI-Reset to POR (bit 15) */
+#define AR_WA_ANALOG_SHIFT              (1 << 20)
+#define AR_WA_POR_SHORT                 (1 << 21) /* PCI-E Phy reset control */
+#define AR_WA_BIT22			(1 << 22)
+#define AR9285_WA_DEFAULT		0x004a050b
+#define AR9280_WA_DEFAULT           	0x0040073b
+#define AR_WA_DEFAULT               	0x0000073f
+
+
+#define AR_PM_STATE                 0x4008
+#define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000
+
+#define AR_HOST_TIMEOUT             (AR_SREV_9340(ah) ? 0x4008 : 0x4018)
+#define AR_HOST_TIMEOUT_APB_CNTR    0x0000FFFF
+#define AR_HOST_TIMEOUT_APB_CNTR_S  0
+#define AR_HOST_TIMEOUT_LCL_CNTR    0xFFFF0000
+#define AR_HOST_TIMEOUT_LCL_CNTR_S  16
+
+#define AR_EEPROM                0x401c
+#define AR_EEPROM_ABSENT         0x00000100
+#define AR_EEPROM_CORRUPT        0x00000200
+#define AR_EEPROM_PROT_MASK      0x03FFFC00
+#define AR_EEPROM_PROT_MASK_S    10
+
+#define EEPROM_PROTECT_RP_0_31        0x0001
+#define EEPROM_PROTECT_WP_0_31        0x0002
+#define EEPROM_PROTECT_RP_32_63       0x0004
+#define EEPROM_PROTECT_WP_32_63       0x0008
+#define EEPROM_PROTECT_RP_64_127      0x0010
+#define EEPROM_PROTECT_WP_64_127      0x0020
+#define EEPROM_PROTECT_RP_128_191     0x0040
+#define EEPROM_PROTECT_WP_128_191     0x0080
+#define EEPROM_PROTECT_RP_192_255     0x0100
+#define EEPROM_PROTECT_WP_192_255     0x0200
+#define EEPROM_PROTECT_RP_256_511     0x0400
+#define EEPROM_PROTECT_WP_256_511     0x0800
+#define EEPROM_PROTECT_RP_512_1023    0x1000
+#define EEPROM_PROTECT_WP_512_1023    0x2000
+#define EEPROM_PROTECT_RP_1024_2047   0x4000
+#define EEPROM_PROTECT_WP_1024_2047   0x8000
+
+#define AR_SREV \
+	((AR_SREV_9100(ah)) ? 0x0600 : (AR_SREV_9340(ah) \
+					? 0x400c : 0x4020))
+
+#define AR_SREV_ID \
+	((AR_SREV_9100(ah)) ? 0x00000FFF : 0x000000FF)
+#define AR_SREV_VERSION                       0x000000F0
+#define AR_SREV_VERSION_S                     4
+#define AR_SREV_REVISION                      0x00000007
+
+#define AR_SREV_ID2                           0xFFFFFFFF
+#define AR_SREV_VERSION2        	      0xFFFC0000
+#define AR_SREV_VERSION2_S                    18
+#define AR_SREV_TYPE2        	      	      0x0003F000
+#define AR_SREV_TYPE2_S                       12
+#define AR_SREV_TYPE2_CHAIN		      0x00001000
+#define AR_SREV_TYPE2_HOST_MODE		      0x00002000
+#define AR_SREV_REVISION2        	      0x00000F00
+#define AR_SREV_REVISION2_S     	      8
+
+#define AR_SREV_VERSION_5416_PCI	0xD
+#define AR_SREV_VERSION_5416_PCIE	0xC
+#define AR_SREV_REVISION_5416_10	0
+#define AR_SREV_REVISION_5416_20	1
+#define AR_SREV_REVISION_5416_22	2
+#define AR_SREV_VERSION_9100		0x14
+#define AR_SREV_VERSION_9160		0x40
+#define AR_SREV_REVISION_9160_10	0
+#define AR_SREV_REVISION_9160_11	1
+#define AR_SREV_VERSION_9280		0x80
+#define AR_SREV_REVISION_9280_10	0
+#define AR_SREV_REVISION_9280_20	1
+#define AR_SREV_REVISION_9280_21	2
+#define AR_SREV_VERSION_9285		0xC0
+#define AR_SREV_REVISION_9285_10	0
+#define AR_SREV_REVISION_9285_11	1
+#define AR_SREV_REVISION_9285_12	2
+#define AR_SREV_VERSION_9287		0x180
+#define AR_SREV_REVISION_9287_10	0
+#define AR_SREV_REVISION_9287_11	1
+#define AR_SREV_REVISION_9287_12	2
+#define AR_SREV_REVISION_9287_13	3
+#define AR_SREV_VERSION_9271		0x140
+#define AR_SREV_REVISION_9271_10	0
+#define AR_SREV_REVISION_9271_11	1
+#define AR_SREV_VERSION_9300		0x1c0
+#define AR_SREV_REVISION_9300_20	2 /* 2.0 and 2.1 */
+#define AR_SREV_VERSION_9485		0x240
+#define AR_SREV_REVISION_9485_10	0
+#define AR_SREV_REVISION_9485_11        1
+#define AR_SREV_VERSION_9340		0x300
+
+#define AR_SREV_5416(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
+	 ((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE))
+#define AR_SREV_5416_20_OR_LATER(_ah) \
+	(((AR_SREV_5416(_ah)) && \
+	 ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_20)) || \
+	 ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100))
+#define AR_SREV_5416_22_OR_LATER(_ah) \
+	(((AR_SREV_5416(_ah)) && \
+	 ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_22)) || \
+	 ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100))
+
+#define AR_SREV_9100(ah) \
+	((ah->hw_version.macVersion) == AR_SREV_VERSION_9100)
+#define AR_SREV_9100_OR_LATER(_ah) \
+	(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100))
+
+#define AR_SREV_9160(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9160))
+#define AR_SREV_9160_10_OR_LATER(_ah) \
+	(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9160))
+#define AR_SREV_9160_11(_ah) \
+	(AR_SREV_9160(_ah) && \
+	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9160_11))
+#define AR_SREV_9280(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280))
+#define AR_SREV_9280_20_OR_LATER(_ah) \
+	(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9280))
+#define AR_SREV_9280_20(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9280))
+
+#define AR_SREV_9285(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9285))
+#define AR_SREV_9285_12_OR_LATER(_ah) \
+	(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9285))
+
+#define AR_SREV_9287(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287))
+#define AR_SREV_9287_11_OR_LATER(_ah) \
+	(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9287))
+#define AR_SREV_9287_11(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_11))
+#define AR_SREV_9287_12(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_12))
+#define AR_SREV_9287_12_OR_LATER(_ah) \
+	(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
+	 (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+	  ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_12)))
+#define AR_SREV_9287_13_OR_LATER(_ah) \
+	(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
+	 (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+	  ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_13)))
+
+#define AR_SREV_9271(_ah) \
+    (((_ah))->hw_version.macVersion == AR_SREV_VERSION_9271)
+#define AR_SREV_9271_10(_ah) \
+    (AR_SREV_9271(_ah) && \
+     ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_10))
+#define AR_SREV_9271_11(_ah) \
+    (AR_SREV_9271(_ah) && \
+     ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_11))
+
+#define AR_SREV_9300(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300))
+#define AR_SREV_9300_20_OR_LATER(_ah) \
+	((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9300)
+
+#define AR_SREV_9485(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
+#define AR_SREV_9485_10(_ah) \
+	(AR_SREV_9485(_ah) && \
+	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_10))
+#define AR_SREV_9485_11(_ah) \
+	(AR_SREV_9485(_ah) && \
+	 ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11))
+#define AR_SREV_9485_OR_LATER(_ah) \
+	(((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485))
+
+#define AR_SREV_9340(_ah) \
+	(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340))
+
+#define AR_SREV_9285E_20(_ah) \
+    (AR_SREV_9285_12_OR_LATER(_ah) && \
+     ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1))
+
+enum ath_usb_dev {
+	AR9280_USB = 1, /* AR7010 + AR9280, UB94 */
+	AR9287_USB = 2, /* AR7010 + AR9287, UB95 */
+	STORAGE_DEVICE = 3,
+};
+
+#define AR_DEVID_7010(_ah) \
+	(((_ah)->hw_version.usbdev == AR9280_USB) || \
+	 ((_ah)->hw_version.usbdev == AR9287_USB))
+
+#define AR_RADIO_SREV_MAJOR                   0xf0
+#define AR_RAD5133_SREV_MAJOR                 0xc0
+#define AR_RAD2133_SREV_MAJOR                 0xd0
+#define AR_RAD5122_SREV_MAJOR                 0xe0
+#define AR_RAD2122_SREV_MAJOR                 0xf0
+
+#define AR_AHB_MODE                           0x4024
+#define AR_AHB_EXACT_WR_EN                    0x00000000
+#define AR_AHB_BUF_WR_EN                      0x00000001
+#define AR_AHB_EXACT_RD_EN                    0x00000000
+#define AR_AHB_CACHELINE_RD_EN                0x00000002
+#define AR_AHB_PREFETCH_RD_EN                 0x00000004
+#define AR_AHB_PAGE_SIZE_1K                   0x00000000
+#define AR_AHB_PAGE_SIZE_2K                   0x00000008
+#define AR_AHB_PAGE_SIZE_4K                   0x00000010
+#define AR_AHB_CUSTOM_BURST_EN                0x000000C0
+#define AR_AHB_CUSTOM_BURST_EN_S              6
+#define AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL    3
+
+#define AR_INTR_RTC_IRQ                       0x00000001
+#define AR_INTR_MAC_IRQ                       0x00000002
+#define AR_INTR_EEP_PROT_ACCESS               0x00000004
+#define AR_INTR_MAC_AWAKE                     0x00020000
+#define AR_INTR_MAC_ASLEEP                    0x00040000
+#define AR_INTR_SPURIOUS                      0xFFFFFFFF
+
+
+#define AR_INTR_SYNC_CAUSE                    (AR_SREV_9340(ah) ? 0x4010 : 0x4028)
+#define AR_INTR_SYNC_CAUSE_CLR                (AR_SREV_9340(ah) ? 0x4010 : 0x4028)
+
+
+#define AR_INTR_SYNC_ENABLE                   (AR_SREV_9340(ah) ? 0x4014 : 0x402c)
+#define AR_INTR_SYNC_ENABLE_GPIO              0xFFFC0000
+#define AR_INTR_SYNC_ENABLE_GPIO_S            18
+
+enum {
+	AR_INTR_SYNC_RTC_IRQ = 0x00000001,
+	AR_INTR_SYNC_MAC_IRQ = 0x00000002,
+	AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS = 0x00000004,
+	AR_INTR_SYNC_APB_TIMEOUT = 0x00000008,
+	AR_INTR_SYNC_PCI_MODE_CONFLICT = 0x00000010,
+	AR_INTR_SYNC_HOST1_FATAL = 0x00000020,
+	AR_INTR_SYNC_HOST1_PERR = 0x00000040,
+	AR_INTR_SYNC_TRCV_FIFO_PERR = 0x00000080,
+	AR_INTR_SYNC_RADM_CPL_EP = 0x00000100,
+	AR_INTR_SYNC_RADM_CPL_DLLP_ABORT = 0x00000200,
+	AR_INTR_SYNC_RADM_CPL_TLP_ABORT = 0x00000400,
+	AR_INTR_SYNC_RADM_CPL_ECRC_ERR = 0x00000800,
+	AR_INTR_SYNC_RADM_CPL_TIMEOUT = 0x00001000,
+	AR_INTR_SYNC_LOCAL_TIMEOUT = 0x00002000,
+	AR_INTR_SYNC_PM_ACCESS = 0x00004000,
+	AR_INTR_SYNC_MAC_AWAKE = 0x00008000,
+	AR_INTR_SYNC_MAC_ASLEEP = 0x00010000,
+	AR_INTR_SYNC_MAC_SLEEP_ACCESS = 0x00020000,
+	AR_INTR_SYNC_ALL = 0x0003FFFF,
+
+
+	AR_INTR_SYNC_DEFAULT = (AR_INTR_SYNC_HOST1_FATAL |
+				AR_INTR_SYNC_HOST1_PERR |
+				AR_INTR_SYNC_RADM_CPL_EP |
+				AR_INTR_SYNC_RADM_CPL_DLLP_ABORT |
+				AR_INTR_SYNC_RADM_CPL_TLP_ABORT |
+				AR_INTR_SYNC_RADM_CPL_ECRC_ERR |
+				AR_INTR_SYNC_RADM_CPL_TIMEOUT |
+				AR_INTR_SYNC_LOCAL_TIMEOUT |
+				AR_INTR_SYNC_MAC_SLEEP_ACCESS),
+
+	AR_INTR_SYNC_SPURIOUS = 0xFFFFFFFF,
+
+};
+
+#define AR_INTR_ASYNC_MASK                       (AR_SREV_9340(ah) ? 0x4018 : 0x4030)
+#define AR_INTR_ASYNC_MASK_GPIO                  0xFFFC0000
+#define AR_INTR_ASYNC_MASK_GPIO_S                18
+
+#define AR_INTR_SYNC_MASK                        (AR_SREV_9340(ah) ? 0x401c : 0x4034)
+#define AR_INTR_SYNC_MASK_GPIO                   0xFFFC0000
+#define AR_INTR_SYNC_MASK_GPIO_S                 18
+
+#define AR_INTR_ASYNC_CAUSE_CLR                  (AR_SREV_9340(ah) ? 0x4020 : 0x4038)
+#define AR_INTR_ASYNC_CAUSE                      (AR_SREV_9340(ah) ? 0x4020 : 0x4038)
+
+#define AR_INTR_ASYNC_ENABLE                     (AR_SREV_9340(ah) ? 0x4024 : 0x403c)
+#define AR_INTR_ASYNC_ENABLE_GPIO                0xFFFC0000
+#define AR_INTR_ASYNC_ENABLE_GPIO_S              18
+
+#define AR_PCIE_SERDES                           0x4040
+#define AR_PCIE_SERDES2                          0x4044
+#define AR_PCIE_PM_CTRL                          (AR_SREV_9340(ah) ? 0x4004 : 0x4014)
+#define AR_PCIE_PM_CTRL_ENA                      0x00080000
+
+#define AR_NUM_GPIO                              14
+#define AR928X_NUM_GPIO                          10
+#define AR9285_NUM_GPIO                          12
+#define AR9287_NUM_GPIO                          11
+#define AR9271_NUM_GPIO                          16
+#define AR9300_NUM_GPIO                          17
+#define AR7010_NUM_GPIO                          16
+
+#define AR_GPIO_IN_OUT                           (AR_SREV_9340(ah) ? 0x4028 : 0x4048)
+#define AR_GPIO_IN_VAL                           0x0FFFC000
+#define AR_GPIO_IN_VAL_S                         14
+#define AR928X_GPIO_IN_VAL                       0x000FFC00
+#define AR928X_GPIO_IN_VAL_S                     10
+#define AR9285_GPIO_IN_VAL                       0x00FFF000
+#define AR9285_GPIO_IN_VAL_S                     12
+#define AR9287_GPIO_IN_VAL                       0x003FF800
+#define AR9287_GPIO_IN_VAL_S                     11
+#define AR9271_GPIO_IN_VAL                       0xFFFF0000
+#define AR9271_GPIO_IN_VAL_S                     16
+#define AR7010_GPIO_IN_VAL                       0x0000FFFF
+#define AR7010_GPIO_IN_VAL_S                     0
+
+#define AR_GPIO_IN				 (AR_SREV_9340(ah) ? 0x402c : 0x404c)
+#define AR9300_GPIO_IN_VAL                       0x0001FFFF
+#define AR9300_GPIO_IN_VAL_S                     0
+
+#define AR_GPIO_OE_OUT                           (AR_SREV_9340(ah) ? 0x4030 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c))
+#define AR_GPIO_OE_OUT_DRV                       0x3
+#define AR_GPIO_OE_OUT_DRV_NO                    0x0
+#define AR_GPIO_OE_OUT_DRV_LOW                   0x1
+#define AR_GPIO_OE_OUT_DRV_HI                    0x2
+#define AR_GPIO_OE_OUT_DRV_ALL                   0x3
+
+#define AR7010_GPIO_OE                           0x52000
+#define AR7010_GPIO_OE_MASK                      0x1
+#define AR7010_GPIO_OE_AS_OUTPUT                 0x0
+#define AR7010_GPIO_OE_AS_INPUT                  0x1
+#define AR7010_GPIO_IN                           0x52004
+#define AR7010_GPIO_OUT                          0x52008
+#define AR7010_GPIO_SET                          0x5200C
+#define AR7010_GPIO_CLEAR                        0x52010
+#define AR7010_GPIO_INT                          0x52014
+#define AR7010_GPIO_INT_TYPE                     0x52018
+#define AR7010_GPIO_INT_POLARITY                 0x5201C
+#define AR7010_GPIO_PENDING                      0x52020
+#define AR7010_GPIO_INT_MASK                     0x52024
+#define AR7010_GPIO_FUNCTION                     0x52028
+
+#define AR_GPIO_INTR_POL                         (AR_SREV_9340(ah) ? 0x4038 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050))
+#define AR_GPIO_INTR_POL_VAL                     0x0001FFFF
+#define AR_GPIO_INTR_POL_VAL_S                   0
+
+#define AR_GPIO_INPUT_EN_VAL                     (AR_SREV_9340(ah) ? 0x403c : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054))
+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF     0x00000004
+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_S       2
+#define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF    0x00000008
+#define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_S      3
+#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_DEF       0x00000010
+#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_S         4
+#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF        0x00000080
+#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S      7
+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB      0x00000400
+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S    10
+#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB        0x00001000
+#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S      12
+#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB         0x00008000
+#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S       15
+#define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE        0x00010000
+#define AR_GPIO_JTAG_DISABLE                     0x00020000
+
+#define AR_GPIO_INPUT_MUX1                       (AR_SREV_9340(ah) ? 0x4040 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058))
+#define AR_GPIO_INPUT_MUX1_BT_ACTIVE             0x000f0000
+#define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S           16
+#define AR_GPIO_INPUT_MUX1_BT_PRIORITY           0x00000f00
+#define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S         8
+
+#define AR_GPIO_INPUT_MUX2                       (AR_SREV_9340(ah) ? 0x4044 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c))
+#define AR_GPIO_INPUT_MUX2_CLK25                 0x0000000f
+#define AR_GPIO_INPUT_MUX2_CLK25_S               0
+#define AR_GPIO_INPUT_MUX2_RFSILENT              0x000000f0
+#define AR_GPIO_INPUT_MUX2_RFSILENT_S            4
+#define AR_GPIO_INPUT_MUX2_RTC_RESET             0x00000f00
+#define AR_GPIO_INPUT_MUX2_RTC_RESET_S           8
+
+#define AR_GPIO_OUTPUT_MUX1                      (AR_SREV_9340(ah) ? 0x4048 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060))
+#define AR_GPIO_OUTPUT_MUX2                      (AR_SREV_9340(ah) ? 0x404c : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064))
+#define AR_GPIO_OUTPUT_MUX3                      (AR_SREV_9340(ah) ? 0x4050 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068))
+
+#define AR_INPUT_STATE                           (AR_SREV_9340(ah) ? 0x4054 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c))
+
+#define AR_EEPROM_STATUS_DATA                    (AR_SREV_9340(ah) ? 0x40c8 : \
+						  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c))
+#define AR_EEPROM_STATUS_DATA_VAL                0x0000ffff
+#define AR_EEPROM_STATUS_DATA_VAL_S              0
+#define AR_EEPROM_STATUS_DATA_BUSY               0x00010000
+#define AR_EEPROM_STATUS_DATA_BUSY_ACCESS        0x00020000
+#define AR_EEPROM_STATUS_DATA_PROT_ACCESS        0x00040000
+#define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS      0x00080000
+
+#define AR_OBS                  (AR_SREV_9340(ah) ? 0x405c : \
+				 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080))
+
+#define AR_GPIO_PDPU                             (AR_SREV_9300_20_OR_LATER(ah) ? 0x4090 : 0x4088)
+
+#define AR_PCIE_MSI                             (AR_SREV_9340(ah) ? 0x40d8 : \
+						 (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094))
+#define AR_PCIE_MSI_ENABLE                       0x00000001
+
+#define AR_INTR_PRIO_SYNC_ENABLE  (AR_SREV_9340(ah) ? 0x4088 : 0x40c4)
+#define AR_INTR_PRIO_ASYNC_MASK   (AR_SREV_9340(ah) ? 0x408c : 0x40c8)
+#define AR_INTR_PRIO_SYNC_MASK    (AR_SREV_9340(ah) ? 0x4090 : 0x40cc)
+#define AR_INTR_PRIO_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4094 : 0x40d4)
+#define AR_ENT_OTP		  0x40d8
+#define AR_ENT_OTP_CHAIN2_DISABLE               0x00020000
+#define AR_ENT_OTP_MPSD		0x00800000
+
+#define AR_CH0_BB_DPLL1		 0x16180
+#define AR_CH0_BB_DPLL1_REFDIV	 0xF8000000
+#define AR_CH0_BB_DPLL1_REFDIV_S 27
+#define AR_CH0_BB_DPLL1_NINI	 0x07FC0000
+#define AR_CH0_BB_DPLL1_NINI_S	 18
+#define AR_CH0_BB_DPLL1_NFRAC	 0x0003FFFF
+#define AR_CH0_BB_DPLL1_NFRAC_S	 0
+
+#define AR_CH0_BB_DPLL2		     0x16184
+#define AR_CH0_BB_DPLL2_LOCAL_PLL       0x40000000
+#define AR_CH0_BB_DPLL2_LOCAL_PLL_S     30
+#define AR_CH0_DPLL2_KI              0x3C000000
+#define AR_CH0_DPLL2_KI_S            26
+#define AR_CH0_DPLL2_KD              0x03F80000
+#define AR_CH0_DPLL2_KD_S            19
+#define AR_CH0_BB_DPLL2_EN_NEGTRIG   0x00040000
+#define AR_CH0_BB_DPLL2_EN_NEGTRIG_S 18
+#define AR_CH0_BB_DPLL2_PLL_PWD	     0x00010000
+#define AR_CH0_BB_DPLL2_PLL_PWD_S    16
+#define AR_CH0_BB_DPLL2_OUTDIV	     0x0000E000
+#define AR_CH0_BB_DPLL2_OUTDIV_S     13
+
+#define AR_CH0_BB_DPLL3          0x16188
+#define AR_CH0_BB_DPLL3_PHASE_SHIFT	0x3F800000
+#define AR_CH0_BB_DPLL3_PHASE_SHIFT_S	23
+
+#define AR_CH0_DDR_DPLL2         0x16244
+#define AR_CH0_DDR_DPLL3         0x16248
+#define AR_CH0_DPLL3_PHASE_SHIFT     0x3F800000
+#define AR_CH0_DPLL3_PHASE_SHIFT_S   23
+#define AR_PHY_CCA_NOM_VAL_2GHZ      -118
+
+#define AR_RTC_9300_PLL_DIV          0x000003ff
+#define AR_RTC_9300_PLL_DIV_S        0
+#define AR_RTC_9300_PLL_REFDIV       0x00003C00
+#define AR_RTC_9300_PLL_REFDIV_S     10
+#define AR_RTC_9300_PLL_CLKSEL       0x0000C000
+#define AR_RTC_9300_PLL_CLKSEL_S     14
+
+#define AR_RTC_9160_PLL_DIV	0x000003ff
+#define AR_RTC_9160_PLL_DIV_S   0
+#define AR_RTC_9160_PLL_REFDIV  0x00003C00
+#define AR_RTC_9160_PLL_REFDIV_S 10
+#define AR_RTC_9160_PLL_CLKSEL	0x0000C000
+#define AR_RTC_9160_PLL_CLKSEL_S 14
+
+#define AR_RTC_BASE             0x00020000
+#define AR_RTC_RC \
+	((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0000) : 0x7000)
+#define AR_RTC_RC_M		0x00000003
+#define AR_RTC_RC_MAC_WARM      0x00000001
+#define AR_RTC_RC_MAC_COLD      0x00000002
+#define AR_RTC_RC_COLD_RESET    0x00000004
+#define AR_RTC_RC_WARM_RESET    0x00000008
+
+/* Crystal Control */
+#define AR_RTC_XTAL_CONTROL     0x7004
+
+/* Reg Control 0 */
+#define AR_RTC_REG_CONTROL0     0x7008
+
+/* Reg Control 1 */
+#define AR_RTC_REG_CONTROL1     0x700c
+#define AR_RTC_REG_CONTROL1_SWREG_PROGRAM       0x00000001
+
+#define AR_RTC_PLL_CONTROL \
+	((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0014) : 0x7014)
+
+#define AR_RTC_PLL_CONTROL2	0x703c
+
+#define AR_RTC_PLL_DIV          0x0000001f
+#define AR_RTC_PLL_DIV_S        0
+#define AR_RTC_PLL_DIV2         0x00000020
+#define AR_RTC_PLL_REFDIV_5     0x000000c0
+#define AR_RTC_PLL_CLKSEL       0x00000300
+#define AR_RTC_PLL_CLKSEL_S     8
+#define AR_RTC_PLL_BYPASS	0x00010000
+
+#define PLL3 0x16188
+#define PLL3_DO_MEAS_MASK 0x40000000
+#define PLL4 0x1618c
+#define PLL4_MEAS_DONE    0x8
+#define SQSUM_DVC_MASK 0x007ffff8
+
+#define AR_RTC_RESET \
+	((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0040) : 0x7040)
+#define AR_RTC_RESET_EN		(0x00000001)
+
+#define AR_RTC_STATUS \
+	((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0044) : 0x7044)
+
+#define AR_RTC_STATUS_M \
+	((AR_SREV_9100(ah)) ? 0x0000003f : 0x0000000f)
+
+#define AR_RTC_PM_STATUS_M      0x0000000f
+
+#define AR_RTC_STATUS_SHUTDOWN  0x00000001
+#define AR_RTC_STATUS_ON        0x00000002
+#define AR_RTC_STATUS_SLEEP     0x00000004
+#define AR_RTC_STATUS_WAKEUP    0x00000008
+
+#define AR_RTC_SLEEP_CLK \
+	((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0048) : 0x7048)
+#define AR_RTC_FORCE_DERIVED_CLK    0x2
+#define AR_RTC_FORCE_SWREG_PRD      0x00000004
+
+#define AR_RTC_FORCE_WAKE \
+	((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x004c) : 0x704c)
+#define AR_RTC_FORCE_WAKE_EN        0x00000001
+#define AR_RTC_FORCE_WAKE_ON_INT    0x00000002
+
+
+#define AR_RTC_INTR_CAUSE \
+	((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0050) : 0x7050)
+
+#define AR_RTC_INTR_ENABLE \
+	((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0054) : 0x7054)
+
+#define AR_RTC_INTR_MASK \
+	((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058)
+
+/* RTC_DERIVED_* - only for AR9100 */
+
+#define AR_RTC_DERIVED_CLK \
+	(AR_SREV_9100(ah) ? (AR_RTC_BASE + 0x0038) : 0x7038)
+#define AR_RTC_DERIVED_CLK_PERIOD    0x0000fffe
+#define AR_RTC_DERIVED_CLK_PERIOD_S  1
+
+#define	AR_SEQ_MASK	0x8060
+
+#define AR_AN_RF2G1_CH0         0x7810
+#define AR_AN_RF2G1_CH0_OB      0x03800000
+#define AR_AN_RF2G1_CH0_OB_S    23
+#define AR_AN_RF2G1_CH0_DB      0x1C000000
+#define AR_AN_RF2G1_CH0_DB_S    26
+
+#define AR_AN_RF5G1_CH0         0x7818
+#define AR_AN_RF5G1_CH0_OB5     0x00070000
+#define AR_AN_RF5G1_CH0_OB5_S   16
+#define AR_AN_RF5G1_CH0_DB5     0x00380000
+#define AR_AN_RF5G1_CH0_DB5_S   19
+
+#define AR_AN_RF2G1_CH1         0x7834
+#define AR_AN_RF2G1_CH1_OB      0x03800000
+#define AR_AN_RF2G1_CH1_OB_S    23
+#define AR_AN_RF2G1_CH1_DB      0x1C000000
+#define AR_AN_RF2G1_CH1_DB_S    26
+
+#define AR_AN_RF5G1_CH1         0x783C
+#define AR_AN_RF5G1_CH1_OB5     0x00070000
+#define AR_AN_RF5G1_CH1_OB5_S   16
+#define AR_AN_RF5G1_CH1_DB5     0x00380000
+#define AR_AN_RF5G1_CH1_DB5_S   19
+
+#define AR_AN_TOP1                  0x7890
+#define AR_AN_TOP1_DACIPMODE	    0x00040000
+#define AR_AN_TOP1_DACIPMODE_S	    18
+
+#define AR_AN_TOP2                  0x7894
+#define AR_AN_TOP2_XPABIAS_LVL      0xC0000000
+#define AR_AN_TOP2_XPABIAS_LVL_S    30
+#define AR_AN_TOP2_LOCALBIAS        0x00200000
+#define AR_AN_TOP2_LOCALBIAS_S      21
+#define AR_AN_TOP2_PWDCLKIND        0x00400000
+#define AR_AN_TOP2_PWDCLKIND_S      22
+
+#define AR_AN_SYNTH9            0x7868
+#define AR_AN_SYNTH9_REFDIVA    0xf8000000
+#define AR_AN_SYNTH9_REFDIVA_S  27
+
+#define AR9285_AN_RF2G1              0x7820
+#define AR9285_AN_RF2G1_ENPACAL      0x00000800
+#define AR9285_AN_RF2G1_ENPACAL_S    11
+#define AR9285_AN_RF2G1_PDPADRV1     0x02000000
+#define AR9285_AN_RF2G1_PDPADRV1_S   25
+#define AR9285_AN_RF2G1_PDPADRV2     0x01000000
+#define AR9285_AN_RF2G1_PDPADRV2_S   24
+#define AR9285_AN_RF2G1_PDPAOUT      0x00800000
+#define AR9285_AN_RF2G1_PDPAOUT_S    23
+
+
+#define AR9285_AN_RF2G2              0x7824
+#define AR9285_AN_RF2G2_OFFCAL       0x00001000
+#define AR9285_AN_RF2G2_OFFCAL_S     12
+
+#define AR9285_AN_RF2G3             0x7828
+#define AR9285_AN_RF2G3_PDVCCOMP    0x02000000
+#define AR9285_AN_RF2G3_PDVCCOMP_S  25
+#define AR9285_AN_RF2G3_OB_0    0x00E00000
+#define AR9285_AN_RF2G3_OB_0_S    21
+#define AR9285_AN_RF2G3_OB_1    0x001C0000
+#define AR9285_AN_RF2G3_OB_1_S    18
+#define AR9285_AN_RF2G3_OB_2    0x00038000
+#define AR9285_AN_RF2G3_OB_2_S    15
+#define AR9285_AN_RF2G3_OB_3    0x00007000
+#define AR9285_AN_RF2G3_OB_3_S    12
+#define AR9285_AN_RF2G3_OB_4    0x00000E00
+#define AR9285_AN_RF2G3_OB_4_S    9
+
+#define AR9285_AN_RF2G3_DB1_0    0x000001C0
+#define AR9285_AN_RF2G3_DB1_0_S    6
+#define AR9285_AN_RF2G3_DB1_1    0x00000038
+#define AR9285_AN_RF2G3_DB1_1_S    3
+#define AR9285_AN_RF2G3_DB1_2    0x00000007
+#define AR9285_AN_RF2G3_DB1_2_S    0
+#define AR9285_AN_RF2G4         0x782C
+#define AR9285_AN_RF2G4_DB1_3    0xE0000000
+#define AR9285_AN_RF2G4_DB1_3_S    29
+#define AR9285_AN_RF2G4_DB1_4    0x1C000000
+#define AR9285_AN_RF2G4_DB1_4_S    26
+
+#define AR9285_AN_RF2G4_DB2_0    0x03800000
+#define AR9285_AN_RF2G4_DB2_0_S    23
+#define AR9285_AN_RF2G4_DB2_1    0x00700000
+#define AR9285_AN_RF2G4_DB2_1_S    20
+#define AR9285_AN_RF2G4_DB2_2    0x000E0000
+#define AR9285_AN_RF2G4_DB2_2_S    17
+#define AR9285_AN_RF2G4_DB2_3    0x0001C000
+#define AR9285_AN_RF2G4_DB2_3_S    14
+#define AR9285_AN_RF2G4_DB2_4    0x00003800
+#define AR9285_AN_RF2G4_DB2_4_S    11
+
+#define AR9285_RF2G5			0x7830
+#define AR9285_RF2G5_IC50TX		0xfffff8ff
+#define AR9285_RF2G5_IC50TX_SET		0x00000400
+#define AR9285_RF2G5_IC50TX_XE_SET	0x00000500
+#define AR9285_RF2G5_IC50TX_CLEAR	0x00000700
+#define AR9285_RF2G5_IC50TX_CLEAR_S	8
+
+/* AR9271 : 0x7828, 0x782c different setting from AR9285 */
+#define AR9271_AN_RF2G3_OB_cck		0x001C0000
+#define AR9271_AN_RF2G3_OB_cck_S	18
+#define AR9271_AN_RF2G3_OB_psk		0x00038000
+#define AR9271_AN_RF2G3_OB_psk_S	15
+#define AR9271_AN_RF2G3_OB_qam		0x00007000
+#define AR9271_AN_RF2G3_OB_qam_S	12
+
+#define AR9271_AN_RF2G3_DB_1		0x00E00000
+#define AR9271_AN_RF2G3_DB_1_S		21
+
+#define AR9271_AN_RF2G3_CCOMP		0xFFF
+#define AR9271_AN_RF2G3_CCOMP_S		0
+
+#define AR9271_AN_RF2G4_DB_2		0xE0000000
+#define AR9271_AN_RF2G4_DB_2_S		29
+
+#define AR9285_AN_RF2G6                 0x7834
+#define AR9285_AN_RF2G6_CCOMP           0x00007800
+#define AR9285_AN_RF2G6_CCOMP_S         11
+#define AR9285_AN_RF2G6_OFFS            0x03f00000
+#define AR9285_AN_RF2G6_OFFS_S          20
+
+#define AR9271_AN_RF2G6_OFFS            0x07f00000
+#define AR9271_AN_RF2G6_OFFS_S            20
+
+#define AR9285_AN_RF2G7                 0x7838
+#define AR9285_AN_RF2G7_PWDDB           0x00000002
+#define AR9285_AN_RF2G7_PWDDB_S         1
+#define AR9285_AN_RF2G7_PADRVGN2TAB0    0xE0000000
+#define AR9285_AN_RF2G7_PADRVGN2TAB0_S  29
+
+#define AR9285_AN_RF2G8                  0x783C
+#define AR9285_AN_RF2G8_PADRVGN2TAB0     0x0001C000
+#define AR9285_AN_RF2G8_PADRVGN2TAB0_S   14
+
+
+#define AR9285_AN_RF2G9          0x7840
+#define AR9285_AN_RXTXBB1              0x7854
+#define AR9285_AN_RXTXBB1_PDRXTXBB1    0x00000020
+#define AR9285_AN_RXTXBB1_PDRXTXBB1_S  5
+#define AR9285_AN_RXTXBB1_PDV2I        0x00000080
+#define AR9285_AN_RXTXBB1_PDV2I_S      7
+#define AR9285_AN_RXTXBB1_PDDACIF      0x00000100
+#define AR9285_AN_RXTXBB1_PDDACIF_S    8
+#define AR9285_AN_RXTXBB1_SPARE9       0x00000001
+#define AR9285_AN_RXTXBB1_SPARE9_S     0
+
+#define AR9285_AN_TOP2           0x7868
+
+#define AR9285_AN_TOP3                  0x786c
+#define AR9285_AN_TOP3_XPABIAS_LVL      0x0000000C
+#define AR9285_AN_TOP3_XPABIAS_LVL_S    2
+#define AR9285_AN_TOP3_PWDDAC           0x00800000
+#define AR9285_AN_TOP3_PWDDAC_S    23
+
+#define AR9285_AN_TOP4           0x7870
+#define AR9285_AN_TOP4_DEFAULT   0x10142c00
+
+#define AR9287_AN_RF2G3_CH0             0x7808
+#define AR9287_AN_RF2G3_CH1             0x785c
+#define AR9287_AN_RF2G3_DB1             0xE0000000
+#define AR9287_AN_RF2G3_DB1_S           29
+#define AR9287_AN_RF2G3_DB2             0x1C000000
+#define AR9287_AN_RF2G3_DB2_S           26
+#define AR9287_AN_RF2G3_OB_CCK          0x03800000
+#define AR9287_AN_RF2G3_OB_CCK_S        23
+#define AR9287_AN_RF2G3_OB_PSK          0x00700000
+#define AR9287_AN_RF2G3_OB_PSK_S        20
+#define AR9287_AN_RF2G3_OB_QAM          0x000E0000
+#define AR9287_AN_RF2G3_OB_QAM_S        17
+#define AR9287_AN_RF2G3_OB_PAL_OFF      0x0001C000
+#define AR9287_AN_RF2G3_OB_PAL_OFF_S    14
+
+#define AR9287_AN_TXPC0                 0x7898
+#define AR9287_AN_TXPC0_TXPCMODE        0x0000C000
+#define AR9287_AN_TXPC0_TXPCMODE_S      14
+#define AR9287_AN_TXPC0_TXPCMODE_NORMAL    0
+#define AR9287_AN_TXPC0_TXPCMODE_TEST      1
+#define AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE 2
+#define AR9287_AN_TXPC0_TXPCMODE_ATBTEST   3
+
+#define AR9287_AN_TOP2                  0x78b4
+#define AR9287_AN_TOP2_XPABIAS_LVL      0xC0000000
+#define AR9287_AN_TOP2_XPABIAS_LVL_S    30
+
+/* AR9271 specific stuff */
+#define AR9271_RESET_POWER_DOWN_CONTROL		0x50044
+#define AR9271_RADIO_RF_RST			0x20
+#define AR9271_GATE_MAC_CTL			0x4000
+
+#define AR_STA_ID0                 0x8000
+#define AR_STA_ID1                 0x8004
+#define AR_STA_ID1_SADH_MASK       0x0000FFFF
+#define AR_STA_ID1_STA_AP          0x00010000
+#define AR_STA_ID1_ADHOC           0x00020000
+#define AR_STA_ID1_PWR_SAV         0x00040000
+#define AR_STA_ID1_KSRCHDIS        0x00080000
+#define AR_STA_ID1_PCF             0x00100000
+#define AR_STA_ID1_USE_DEFANT      0x00200000
+#define AR_STA_ID1_DEFANT_UPDATE   0x00400000
+#define AR_STA_ID1_AR9100_BA_FIX   0x00400000
+#define AR_STA_ID1_RTS_USE_DEF     0x00800000
+#define AR_STA_ID1_ACKCTS_6MB      0x01000000
+#define AR_STA_ID1_BASE_RATE_11B   0x02000000
+#define AR_STA_ID1_SECTOR_SELF_GEN 0x04000000
+#define AR_STA_ID1_CRPT_MIC_ENABLE 0x08000000
+#define AR_STA_ID1_KSRCH_MODE      0x10000000
+#define AR_STA_ID1_PRESERVE_SEQNUM 0x20000000
+#define AR_STA_ID1_CBCIV_ENDIAN    0x40000000
+#define AR_STA_ID1_MCAST_KSRCH     0x80000000
+
+#define AR_BSS_ID0          0x8008
+#define AR_BSS_ID1          0x800C
+#define AR_BSS_ID1_U16       0x0000FFFF
+#define AR_BSS_ID1_AID       0x07FF0000
+#define AR_BSS_ID1_AID_S     16
+
+#define AR_BCN_RSSI_AVE      0x8010
+#define AR_BCN_RSSI_AVE_MASK 0x00000FFF
+
+#define AR_TIME_OUT         0x8014
+#define AR_TIME_OUT_ACK      0x00003FFF
+#define AR_TIME_OUT_ACK_S    0
+#define AR_TIME_OUT_CTS      0x3FFF0000
+#define AR_TIME_OUT_CTS_S    16
+#define AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR    0x16001D56
+
+#define AR_RSSI_THR          0x8018
+#define AR_RSSI_THR_MASK     0x000000FF
+#define AR_RSSI_THR_BM_THR   0x0000FF00
+#define AR_RSSI_THR_BM_THR_S 8
+#define AR_RSSI_BCN_WEIGHT   0x1F000000
+#define AR_RSSI_BCN_WEIGHT_S 24
+#define AR_RSSI_BCN_RSSI_RST 0x20000000
+
+#define AR_USEC              0x801c
+#define AR_USEC_USEC         0x0000007F
+#define AR_USEC_TX_LAT       0x007FC000
+#define AR_USEC_TX_LAT_S     14
+#define AR_USEC_RX_LAT       0x1F800000
+#define AR_USEC_RX_LAT_S     23
+#define AR_USEC_ASYNC_FIFO_DUR    0x12e00074
+
+#define AR_RESET_TSF        0x8020
+#define AR_RESET_TSF_ONCE   0x01000000
+
+#define AR_MAX_CFP_DUR      0x8038
+#define AR_CFP_VAL          0x0000FFFF
+
+#define AR_RX_FILTER        0x803C
+
+#define AR_MCAST_FIL0       0x8040
+#define AR_MCAST_FIL1       0x8044
+
+/*
+ * AR_DIAG_SW - Register which can be used for diagnostics and testing purposes.
+ *
+ * The force RX abort (AR_DIAG_RX_ABORT, bit 25) can be used in conjunction with
+ * RX block (AR_DIAG_RX_DIS, bit 5) to help fast channel change to shut down
+ * receive. The force RX abort bit will kill any frame which is currently being
+ * transferred between the MAC and baseband. The RX block bit (AR_DIAG_RX_DIS)
+ * will prevent any new frames from getting started.
+ */
+#define AR_DIAG_SW                  0x8048
+#define AR_DIAG_CACHE_ACK           0x00000001
+#define AR_DIAG_ACK_DIS             0x00000002
+#define AR_DIAG_CTS_DIS             0x00000004
+#define AR_DIAG_ENCRYPT_DIS         0x00000008
+#define AR_DIAG_DECRYPT_DIS         0x00000010
+#define AR_DIAG_RX_DIS              0x00000020 /* RX block */
+#define AR_DIAG_LOOP_BACK           0x00000040
+#define AR_DIAG_CORR_FCS            0x00000080
+#define AR_DIAG_CHAN_INFO           0x00000100
+#define AR_DIAG_SCRAM_SEED          0x0001FE00
+#define AR_DIAG_SCRAM_SEED_S        8
+#define AR_DIAG_FRAME_NV0           0x00020000
+#define AR_DIAG_OBS_PT_SEL1         0x000C0000
+#define AR_DIAG_OBS_PT_SEL1_S       18
+#define AR_DIAG_FORCE_RX_CLEAR      0x00100000 /* force rx_clear high */
+#define AR_DIAG_IGNORE_VIRT_CS      0x00200000
+#define AR_DIAG_FORCE_CH_IDLE_HIGH  0x00400000
+#define AR_DIAG_EIFS_CTRL_ENA       0x00800000
+#define AR_DIAG_DUAL_CHAIN_INFO     0x01000000
+#define AR_DIAG_RX_ABORT            0x02000000 /* Force RX abort */
+#define AR_DIAG_SATURATE_CYCLE_CNT  0x04000000
+#define AR_DIAG_OBS_PT_SEL2         0x08000000
+#define AR_DIAG_RX_CLEAR_CTL_LOW    0x10000000
+#define AR_DIAG_RX_CLEAR_EXT_LOW    0x20000000
+
+#define AR_TSF_L32          0x804c
+#define AR_TSF_U32          0x8050
+
+#define AR_TST_ADDAC        0x8054
+#define AR_DEF_ANTENNA      0x8058
+
+#define AR_AES_MUTE_MASK0       0x805c
+#define AR_AES_MUTE_MASK0_FC    0x0000FFFF
+#define AR_AES_MUTE_MASK0_QOS   0xFFFF0000
+#define AR_AES_MUTE_MASK0_QOS_S 16
+
+#define AR_AES_MUTE_MASK1       0x8060
+#define AR_AES_MUTE_MASK1_SEQ   0x0000FFFF
+#define AR_AES_MUTE_MASK1_FC_MGMT 0xFFFF0000
+#define AR_AES_MUTE_MASK1_FC_MGMT_S 16
+
+#define AR_GATED_CLKS       0x8064
+#define AR_GATED_CLKS_TX    0x00000002
+#define AR_GATED_CLKS_RX    0x00000004
+#define AR_GATED_CLKS_REG   0x00000008
+
+#define AR_OBS_BUS_CTRL     0x8068
+#define AR_OBS_BUS_SEL_1    0x00040000
+#define AR_OBS_BUS_SEL_2    0x00080000
+#define AR_OBS_BUS_SEL_3    0x000C0000
+#define AR_OBS_BUS_SEL_4    0x08040000
+#define AR_OBS_BUS_SEL_5    0x08080000
+
+#define AR_OBS_BUS_1               0x806c
+#define AR_OBS_BUS_1_PCU           0x00000001
+#define AR_OBS_BUS_1_RX_END        0x00000002
+#define AR_OBS_BUS_1_RX_WEP        0x00000004
+#define AR_OBS_BUS_1_RX_BEACON     0x00000008
+#define AR_OBS_BUS_1_RX_FILTER     0x00000010
+#define AR_OBS_BUS_1_TX_HCF        0x00000020
+#define AR_OBS_BUS_1_QUIET_TIME    0x00000040
+#define AR_OBS_BUS_1_CHAN_IDLE     0x00000080
+#define AR_OBS_BUS_1_TX_HOLD       0x00000100
+#define AR_OBS_BUS_1_TX_FRAME      0x00000200
+#define AR_OBS_BUS_1_RX_FRAME      0x00000400
+#define AR_OBS_BUS_1_RX_CLEAR      0x00000800
+#define AR_OBS_BUS_1_WEP_STATE     0x0003F000
+#define AR_OBS_BUS_1_WEP_STATE_S   12
+#define AR_OBS_BUS_1_RX_STATE      0x01F00000
+#define AR_OBS_BUS_1_RX_STATE_S    20
+#define AR_OBS_BUS_1_TX_STATE      0x7E000000
+#define AR_OBS_BUS_1_TX_STATE_S    25
+
+#define AR_LAST_TSTP        0x8080
+#define AR_NAV              0x8084
+#define AR_RTS_OK           0x8088
+#define AR_RTS_FAIL         0x808c
+#define AR_ACK_FAIL         0x8090
+#define AR_FCS_FAIL         0x8094
+#define AR_BEACON_CNT       0x8098
+
+#define AR_SLEEP1               0x80d4
+#define AR_SLEEP1_ASSUME_DTIM   0x00080000
+#define AR_SLEEP1_CAB_TIMEOUT   0xFFE00000
+#define AR_SLEEP1_CAB_TIMEOUT_S 21
+
+#define AR_SLEEP2                   0x80d8
+#define AR_SLEEP2_BEACON_TIMEOUT    0xFFE00000
+#define AR_SLEEP2_BEACON_TIMEOUT_S  21
+
+#define AR_TPC                 0x80e8
+#define AR_TPC_ACK             0x0000003f
+#define AR_TPC_ACK_S           0x00
+#define AR_TPC_CTS             0x00003f00
+#define AR_TPC_CTS_S           0x08
+#define AR_TPC_CHIRP           0x003f0000
+#define AR_TPC_CHIRP_S         0x16
+
+#define AR_QUIET1          0x80fc
+#define AR_QUIET1_NEXT_QUIET_S         0
+#define AR_QUIET1_NEXT_QUIET_M         0x0000ffff
+#define AR_QUIET1_QUIET_ENABLE         0x00010000
+#define AR_QUIET1_QUIET_ACK_CTS_ENABLE 0x00020000
+#define AR_QUIET1_QUIET_ACK_CTS_ENABLE_S 17
+#define AR_QUIET2          0x8100
+#define AR_QUIET2_QUIET_PERIOD_S       0
+#define AR_QUIET2_QUIET_PERIOD_M       0x0000ffff
+#define AR_QUIET2_QUIET_DUR_S     16
+#define AR_QUIET2_QUIET_DUR       0xffff0000
+
+#define AR_TSF_PARM        0x8104
+#define AR_TSF_INCREMENT_M     0x000000ff
+#define AR_TSF_INCREMENT_S     0x00
+
+#define AR_QOS_NO_ACK              0x8108
+#define AR_QOS_NO_ACK_TWO_BIT      0x0000000f
+#define AR_QOS_NO_ACK_TWO_BIT_S    0
+#define AR_QOS_NO_ACK_BIT_OFF      0x00000070
+#define AR_QOS_NO_ACK_BIT_OFF_S    4
+#define AR_QOS_NO_ACK_BYTE_OFF     0x00000180
+#define AR_QOS_NO_ACK_BYTE_OFF_S   7
+
+#define AR_PHY_ERR         0x810c
+
+#define AR_PHY_ERR_DCHIRP      0x00000008
+#define AR_PHY_ERR_RADAR       0x00000020
+#define AR_PHY_ERR_OFDM_TIMING 0x00020000
+#define AR_PHY_ERR_CCK_TIMING  0x02000000
+
+#define AR_RXFIFO_CFG          0x8114
+
+
+#define AR_MIC_QOS_CONTROL 0x8118
+#define AR_MIC_QOS_SELECT  0x811c
+
+#define AR_PCU_MISC                0x8120
+#define AR_PCU_FORCE_BSSID_MATCH   0x00000001
+#define AR_PCU_MIC_NEW_LOC_ENA     0x00000004
+#define AR_PCU_TX_ADD_TSF          0x00000008
+#define AR_PCU_CCK_SIFS_MODE       0x00000010
+#define AR_PCU_RX_ANT_UPDT         0x00000800
+#define AR_PCU_TXOP_TBTT_LIMIT_ENA 0x00001000
+#define AR_PCU_MISS_BCN_IN_SLEEP   0x00004000
+#define AR_PCU_BUG_12306_FIX_ENA   0x00020000
+#define AR_PCU_FORCE_QUIET_COLL    0x00040000
+#define AR_PCU_TBTT_PROTECT        0x00200000
+#define AR_PCU_CLEAR_VMF           0x01000000
+#define AR_PCU_CLEAR_BA_VALID      0x04000000
+#define AR_PCU_ALWAYS_PERFORM_KEYSEARCH 0x10000000
+
+#define AR_PCU_BT_ANT_PREVENT_RX   0x00100000
+#define AR_PCU_BT_ANT_PREVENT_RX_S 20
+
+#define AR_FILT_OFDM           0x8124
+#define AR_FILT_OFDM_COUNT     0x00FFFFFF
+
+#define AR_FILT_CCK            0x8128
+#define AR_FILT_CCK_COUNT      0x00FFFFFF
+
+#define AR_PHY_ERR_1           0x812c
+#define AR_PHY_ERR_1_COUNT     0x00FFFFFF
+#define AR_PHY_ERR_MASK_1      0x8130
+
+#define AR_PHY_ERR_2           0x8134
+#define AR_PHY_ERR_2_COUNT     0x00FFFFFF
+#define AR_PHY_ERR_MASK_2      0x8138
+
+#define AR_PHY_COUNTMAX        (3 << 22)
+#define AR_MIBCNT_INTRMASK     (3 << 22)
+
+#define AR_TSFOOR_THRESHOLD       0x813c
+#define AR_TSFOOR_THRESHOLD_VAL   0x0000FFFF
+
+#define AR_PHY_ERR_EIFS_MASK   0x8144
+
+#define AR_PHY_ERR_3           0x8168
+#define AR_PHY_ERR_3_COUNT     0x00FFFFFF
+#define AR_PHY_ERR_MASK_3      0x816c
+
+#define AR_BT_COEX_MODE            0x8170
+#define AR_BT_TIME_EXTEND          0x000000ff
+#define AR_BT_TIME_EXTEND_S        0
+#define AR_BT_TXSTATE_EXTEND       0x00000100
+#define AR_BT_TXSTATE_EXTEND_S     8
+#define AR_BT_TX_FRAME_EXTEND      0x00000200
+#define AR_BT_TX_FRAME_EXTEND_S    9
+#define AR_BT_MODE                 0x00000c00
+#define AR_BT_MODE_S               10
+#define AR_BT_QUIET                0x00001000
+#define AR_BT_QUIET_S              12
+#define AR_BT_QCU_THRESH           0x0001e000
+#define AR_BT_QCU_THRESH_S         13
+#define AR_BT_RX_CLEAR_POLARITY    0x00020000
+#define AR_BT_RX_CLEAR_POLARITY_S  17
+#define AR_BT_PRIORITY_TIME        0x00fc0000
+#define AR_BT_PRIORITY_TIME_S      18
+#define AR_BT_FIRST_SLOT_TIME      0xff000000
+#define AR_BT_FIRST_SLOT_TIME_S    24
+
+#define AR_BT_COEX_WEIGHT          0x8174
+#define AR_BT_COEX_WGHT		   0xff55
+#define AR_STOMP_ALL_WLAN_WGHT	   0xfcfc
+#define AR_STOMP_LOW_WLAN_WGHT	   0xa8a8
+#define AR_STOMP_NONE_WLAN_WGHT	   0x0000
+#define AR_BTCOEX_BT_WGHT          0x0000ffff
+#define AR_BTCOEX_BT_WGHT_S        0
+#define AR_BTCOEX_WL_WGHT          0xffff0000
+#define AR_BTCOEX_WL_WGHT_S        16
+
+#define AR_BT_COEX_WL_WEIGHTS0     0x8174
+#define AR_BT_COEX_WL_WEIGHTS1     0x81c4
+
+#define AR_BT_COEX_BT_WEIGHTS0     0x83ac
+#define AR_BT_COEX_BT_WEIGHTS1     0x83b0
+#define AR_BT_COEX_BT_WEIGHTS2     0x83b4
+#define AR_BT_COEX_BT_WEIGHTS3     0x83b8
+
+#define AR9300_BT_WGHT                     0xcccc4444
+#define AR9300_STOMP_ALL_WLAN_WGHT0        0xfffffff0
+#define AR9300_STOMP_ALL_WLAN_WGHT1        0xfffffff0
+#define AR9300_STOMP_LOW_WLAN_WGHT0        0x88888880
+#define AR9300_STOMP_LOW_WLAN_WGHT1        0x88888880
+#define AR9300_STOMP_NONE_WLAN_WGHT0       0x00000000
+#define AR9300_STOMP_NONE_WLAN_WGHT1       0x00000000
+
+#define AR_BT_COEX_MODE2           0x817c
+#define AR_BT_BCN_MISS_THRESH      0x000000ff
+#define AR_BT_BCN_MISS_THRESH_S    0
+#define AR_BT_BCN_MISS_CNT         0x0000ff00
+#define AR_BT_BCN_MISS_CNT_S       8
+#define AR_BT_HOLD_RX_CLEAR        0x00010000
+#define AR_BT_HOLD_RX_CLEAR_S      16
+#define AR_BT_DISABLE_BT_ANT       0x00100000
+#define AR_BT_DISABLE_BT_ANT_S     20
+
+#define AR_TXSIFS              0x81d0
+#define AR_TXSIFS_TIME         0x000000FF
+#define AR_TXSIFS_TX_LATENCY   0x00000F00
+#define AR_TXSIFS_TX_LATENCY_S 8
+#define AR_TXSIFS_ACK_SHIFT    0x00007000
+#define AR_TXSIFS_ACK_SHIFT_S  12
+
+#define AR_TXOP_X          0x81ec
+#define AR_TXOP_X_VAL      0x000000FF
+
+
+#define AR_TXOP_0_3    0x81f0
+#define AR_TXOP_4_7    0x81f4
+#define AR_TXOP_8_11   0x81f8
+#define AR_TXOP_12_15  0x81fc
+
+#define AR_NEXT_NDP2_TIMER                  0x8180
+#define AR_FIRST_NDP_TIMER                  7
+#define AR_NDP2_PERIOD                      0x81a0
+#define AR_NDP2_TIMER_MODE                  0x81c0
+
+#define AR_GEN_TIMERS(_i)                   (0x8200 + ((_i) << 2))
+#define AR_NEXT_TBTT_TIMER                  AR_GEN_TIMERS(0)
+#define AR_NEXT_DMA_BEACON_ALERT            AR_GEN_TIMERS(1)
+#define AR_NEXT_SWBA                        AR_GEN_TIMERS(2)
+#define AR_NEXT_CFP                         AR_GEN_TIMERS(2)
+#define AR_NEXT_HCF                         AR_GEN_TIMERS(3)
+#define AR_NEXT_TIM                         AR_GEN_TIMERS(4)
+#define AR_NEXT_DTIM                        AR_GEN_TIMERS(5)
+#define AR_NEXT_QUIET_TIMER                 AR_GEN_TIMERS(6)
+#define AR_NEXT_NDP_TIMER                   AR_GEN_TIMERS(7)
+
+#define AR_BEACON_PERIOD                    AR_GEN_TIMERS(8)
+#define AR_DMA_BEACON_PERIOD                AR_GEN_TIMERS(9)
+#define AR_SWBA_PERIOD                      AR_GEN_TIMERS(10)
+#define AR_HCF_PERIOD                       AR_GEN_TIMERS(11)
+#define AR_TIM_PERIOD                       AR_GEN_TIMERS(12)
+#define AR_DTIM_PERIOD                      AR_GEN_TIMERS(13)
+#define AR_QUIET_PERIOD                     AR_GEN_TIMERS(14)
+#define AR_NDP_PERIOD                       AR_GEN_TIMERS(15)
+
+#define AR_TIMER_MODE                       0x8240
+#define AR_TBTT_TIMER_EN                    0x00000001
+#define AR_DBA_TIMER_EN                     0x00000002
+#define AR_SWBA_TIMER_EN                    0x00000004
+#define AR_HCF_TIMER_EN                     0x00000008
+#define AR_TIM_TIMER_EN                     0x00000010
+#define AR_DTIM_TIMER_EN                    0x00000020
+#define AR_QUIET_TIMER_EN                   0x00000040
+#define AR_NDP_TIMER_EN                     0x00000080
+#define AR_TIMER_OVERFLOW_INDEX             0x00000700
+#define AR_TIMER_OVERFLOW_INDEX_S           8
+#define AR_TIMER_THRESH                     0xFFFFF000
+#define AR_TIMER_THRESH_S                   12
+
+#define AR_SLP32_MODE                  0x8244
+#define AR_SLP32_HALF_CLK_LATENCY      0x000FFFFF
+#define AR_SLP32_ENA                   0x00100000
+#define AR_SLP32_TSF_WRITE_STATUS      0x00200000
+
+#define AR_SLP32_WAKE              0x8248
+#define AR_SLP32_WAKE_XTL_TIME     0x0000FFFF
+
+#define AR_SLP32_INC               0x824c
+#define AR_SLP32_TST_INC           0x000FFFFF
+
+#define AR_SLP_CNT         0x8250
+#define AR_SLP_CYCLE_CNT   0x8254
+
+#define AR_SLP_MIB_CTRL    0x8258
+#define AR_SLP_MIB_CLEAR   0x00000001
+#define AR_SLP_MIB_PENDING 0x00000002
+
+#define AR_MAC_PCU_LOGIC_ANALYZER               0x8264
+#define AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768   0x20000000
+
+
+#define AR_2040_MODE                0x8318
+#define AR_2040_JOINED_RX_CLEAR 0x00000001
+
+
+#define AR_EXTRCCNT         0x8328
+
+#define AR_SELFGEN_MASK         0x832c
+
+#define AR_PCU_TXBUF_CTRL               0x8340
+#define AR_PCU_TXBUF_CTRL_SIZE_MASK     0x7FF
+#define AR_PCU_TXBUF_CTRL_USABLE_SIZE   0x700
+#define AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE   0x380
+
+#define AR_PCU_MISC_MODE2               0x8344
+#define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE           0x00000002
+#define AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT   0x00000004
+
+#define AR_PCU_MISC_MODE2_RESERVED                     0x00000038
+#define AR_PCU_MISC_MODE2_ADHOC_MCAST_KEYID_ENABLE     0x00000040
+#define AR_PCU_MISC_MODE2_CFP_IGNORE                   0x00000080
+#define AR_PCU_MISC_MODE2_MGMT_QOS                     0x0000FF00
+#define AR_PCU_MISC_MODE2_MGMT_QOS_S                   8
+#define AR_PCU_MISC_MODE2_ENABLE_LOAD_NAV_BEACON_DURATION 0x00010000
+#define AR_PCU_MISC_MODE2_ENABLE_AGGWEP                0x00020000
+#define AR_PCU_MISC_MODE2_HWWAR1                       0x00100000
+#define AR_PCU_MISC_MODE2_HWWAR2                       0x02000000
+#define AR_PCU_MISC_MODE2_RESERVED2                    0xFFFE0000
+
+#define AR_MAC_PCU_ASYNC_FIFO_REG3                     0x8358
+#define AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL        0x00000400
+#define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET          0x80000000
+
+
+#define AR_AES_MUTE_MASK0       0x805c
+#define AR_AES_MUTE_MASK0_FC    0x0000FFFF
+#define AR_AES_MUTE_MASK0_QOS   0xFFFF0000
+#define AR_AES_MUTE_MASK0_QOS_S 16
+
+#define AR_AES_MUTE_MASK1              0x8060
+#define AR_AES_MUTE_MASK1_SEQ          0x0000FFFF
+#define AR_AES_MUTE_MASK1_SEQ_S        0
+#define AR_AES_MUTE_MASK1_FC_MGMT      0xFFFF0000
+#define AR_AES_MUTE_MASK1_FC_MGMT_S    16
+
+#define AR_RATE_DURATION_0      0x8700
+#define AR_RATE_DURATION_31     0x87CC
+#define AR_RATE_DURATION_32     0x8780
+#define AR_RATE_DURATION(_n)    (AR_RATE_DURATION_0 + ((_n)<<2))
+
+
+#define AR_KEYTABLE_0           0x8800
+#define AR_KEYTABLE(_n)         (AR_KEYTABLE_0 + ((_n)*32))
+#define AR_KEY_CACHE_SIZE       128
+#define AR_RSVD_KEYTABLE_ENTRIES 4
+#define AR_KEY_TYPE             0x00000007
+#define AR_KEYTABLE_TYPE_40     0x00000000
+#define AR_KEYTABLE_TYPE_104    0x00000001
+#define AR_KEYTABLE_TYPE_128    0x00000003
+#define AR_KEYTABLE_TYPE_TKIP   0x00000004
+#define AR_KEYTABLE_TYPE_AES    0x00000005
+#define AR_KEYTABLE_TYPE_CCM    0x00000006
+#define AR_KEYTABLE_TYPE_CLR    0x00000007
+#define AR_KEYTABLE_ANT         0x00000008
+#define AR_KEYTABLE_VALID       0x00008000
+#define AR_KEYTABLE_KEY0(_n)    (AR_KEYTABLE(_n) + 0)
+#define AR_KEYTABLE_KEY1(_n)    (AR_KEYTABLE(_n) + 4)
+#define AR_KEYTABLE_KEY2(_n)    (AR_KEYTABLE(_n) + 8)
+#define AR_KEYTABLE_KEY3(_n)    (AR_KEYTABLE(_n) + 12)
+#define AR_KEYTABLE_KEY4(_n)    (AR_KEYTABLE(_n) + 16)
+#define AR_KEYTABLE_TYPE(_n)    (AR_KEYTABLE(_n) + 20)
+#define AR_KEYTABLE_MAC0(_n)    (AR_KEYTABLE(_n) + 24)
+#define AR_KEYTABLE_MAC1(_n)    (AR_KEYTABLE(_n) + 28)
+
+#define AR9271_CORE_CLOCK	117   /* clock to 117Mhz */
+#define AR9271_TARGET_BAUD_RATE	19200 /* 115200 */
+
+#define AR_AGG_WEP_ENABLE_FIX		0x00000008  /* This allows the use of AR_AGG_WEP_ENABLE */
+#define AR_ADHOC_MCAST_KEYID_ENABLE     0x00000040  /* This bit enables the Multicast search
+						     * based on both MAC Address and Key ID.
+						     * If bit is 0, then Multicast search is
+						     * based on MAC address only.
+						     * For Merlin and above only.
+						     */
+#define AR_AGG_WEP_ENABLE               0x00020000  /* This field enables AGG_WEP feature,
+						     * when it is enable, AGG_WEP would takes
+						     * charge of the encryption interface of
+						     * pcu_txsm.
+						     */
+
+#define AR9300_SM_BASE				0xa200
+#define AR9002_PHY_AGC_CONTROL			0x9860
+#define AR9003_PHY_AGC_CONTROL			AR9300_SM_BASE + 0xc4
+#define AR_PHY_AGC_CONTROL			(AR_SREV_9300_20_OR_LATER(ah) ? AR9003_PHY_AGC_CONTROL : AR9002_PHY_AGC_CONTROL)
+#define AR_PHY_AGC_CONTROL_CAL			0x00000001  /* do internal calibration */
+#define AR_PHY_AGC_CONTROL_NF			0x00000002  /* do noise-floor calibration */
+#define AR_PHY_AGC_CONTROL_OFFSET_CAL		0x00000800  /* allow offset calibration */
+#define AR_PHY_AGC_CONTROL_ENABLE_NF		0x00008000  /* enable noise floor calibration to happen */
+#define AR_PHY_AGC_CONTROL_FLTR_CAL		0x00010000  /* allow tx filter calibration */
+#define AR_PHY_AGC_CONTROL_NO_UPDATE_NF		0x00020000  /* don't update noise floor automatically */
+#define AR_PHY_AGC_CONTROL_EXT_NF_PWR_MEAS	0x00040000  /* extend noise floor power measurement */
+#define AR_PHY_AGC_CONTROL_CLC_SUCCESS		0x00080000  /* carrier leak calibration done */
+#define AR_PHY_AGC_CONTROL_YCOK_MAX		0x000003c0
+#define AR_PHY_AGC_CONTROL_YCOK_MAX_S		6
+
+#endif
diff --git a/roms/ipxe/src/drivers/net/ath/ath_hw.c b/roms/ipxe/src/drivers/net/ath/ath_hw.c
new file mode 100644
index 0000000000000000000000000000000000000000..8e3128868040741a6c1594829f01acdcbcba6576
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath_hw.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2009 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/io.h>
+
+#include "ath.h"
+#include "reg.h"
+
+#define REG_READ	(common->ops->read)
+#define REG_WRITE	(common->ops->write)
+
+/**
+ * ath_hw_set_bssid_mask - filter out bssids we listen
+ *
+ * @common: the ath_common struct for the device.
+ *
+ * BSSID masking is a method used by AR5212 and newer hardware to inform PCU
+ * which bits of the interface's MAC address should be looked at when trying
+ * to decide which packets to ACK. In station mode and AP mode with a single
+ * BSS every bit matters since we lock to only one BSS. In AP mode with
+ * multiple BSSes (virtual interfaces) not every bit matters because hw must
+ * accept frames for all BSSes and so we tweak some bits of our mac address
+ * in order to have multiple BSSes.
+ *
+ * NOTE: This is a simple filter and does *not* filter out all
+ * relevant frames. Some frames that are not for us might get ACKed from us
+ * by PCU because they just match the mask.
+ *
+ * When handling multiple BSSes you can get the BSSID mask by computing the
+ * set of  ~ ( MAC XOR BSSID ) for all bssids we handle.
+ *
+ * When you do this you are essentially computing the common bits of all your
+ * BSSes. Later it is assumed the hardware will "and" (&) the BSSID mask with
+ * the MAC address to obtain the relevant bits and compare the result with
+ * (frame's BSSID & mask) to see if they match.
+ *
+ * Simple example: on your card you have have two BSSes you have created with
+ * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address.
+ * There is another BSSID-03 but you are not part of it. For simplicity's sake,
+ * assuming only 4 bits for a mac address and for BSSIDs you can then have:
+ *
+ *                  \
+ * MAC:        0001 |
+ * BSSID-01:   0100 | --> Belongs to us
+ * BSSID-02:   1001 |
+ *                  /
+ * -------------------
+ * BSSID-03:   0110  | --> External
+ * -------------------
+ *
+ * Our bssid_mask would then be:
+ *
+ *             On loop iteration for BSSID-01:
+ *             ~(0001 ^ 0100)  -> ~(0101)
+ *                             ->   1010
+ *             bssid_mask      =    1010
+ *
+ *             On loop iteration for BSSID-02:
+ *             bssid_mask &= ~(0001   ^   1001)
+ *             bssid_mask =   (1010)  & ~(0001 ^ 1001)
+ *             bssid_mask =   (1010)  & ~(1000)
+ *             bssid_mask =   (1010)  &  (0111)
+ *             bssid_mask =   0010
+ *
+ * A bssid_mask of 0010 means "only pay attention to the second least
+ * significant bit". This is because its the only bit common
+ * amongst the MAC and all BSSIDs we support. To findout what the real
+ * common bit is we can simply "&" the bssid_mask now with any BSSID we have
+ * or our MAC address (we assume the hardware uses the MAC address).
+ *
+ * Now, suppose there's an incoming frame for BSSID-03:
+ *
+ * IFRAME-01:  0110
+ *
+ * An easy eye-inspeciton of this already should tell you that this frame
+ * will not pass our check. This is because the bssid_mask tells the
+ * hardware to only look at the second least significant bit and the
+ * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB
+ * as 1, which does not match 0.
+ *
+ * So with IFRAME-01 we *assume* the hardware will do:
+ *
+ *     allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ *  --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0;
+ *  --> allow = (0010) == 0000 ? 1 : 0;
+ *  --> allow = 0
+ *
+ *  Lets now test a frame that should work:
+ *
+ * IFRAME-02:  0001 (we should allow)
+ *
+ *     allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ *  --> allow = (0001 & 0010) ==  (0010 & 0001) ? 1 :0;
+ *  --> allow = (0000) == (0000)
+ *  --> allow = 1
+ *
+ * Other examples:
+ *
+ * IFRAME-03:  0100 --> allowed
+ * IFRAME-04:  1001 --> allowed
+ * IFRAME-05:  1101 --> allowed but its not for us!!!
+ *
+ */
+void ath_hw_setbssidmask(struct ath_common *common)
+{
+	void *ah = common->ah;
+
+	REG_WRITE(ah, get_unaligned_le32(common->bssidmask), AR_BSSMSKL);
+	REG_WRITE(ah, get_unaligned_le16(common->bssidmask + 4), AR_BSSMSKU);
+}
+
+
+/**
+ * ath_hw_cycle_counters_update - common function to update cycle counters
+ *
+ * @common: the ath_common struct for the device.
+ *
+ * This function is used to update all cycle counters in one place.
+ * It has to be called while holding common->cc_lock!
+ */
+void ath_hw_cycle_counters_update(struct ath_common *common)
+{
+	u32 cycles, busy, rx, tx;
+	void *ah = common->ah;
+
+	/* freeze */
+	REG_WRITE(ah, AR_MIBC_FMC, AR_MIBC);
+
+	/* read */
+	cycles = REG_READ(ah, AR_CCCNT);
+	busy = REG_READ(ah, AR_RCCNT);
+	rx = REG_READ(ah, AR_RFCNT);
+	tx = REG_READ(ah, AR_TFCNT);
+
+	/* clear */
+	REG_WRITE(ah, 0, AR_CCCNT);
+	REG_WRITE(ah, 0, AR_RFCNT);
+	REG_WRITE(ah, 0, AR_RCCNT);
+	REG_WRITE(ah, 0, AR_TFCNT);
+
+	/* unfreeze */
+	REG_WRITE(ah, 0, AR_MIBC);
+
+	/* update all cycle counters here */
+	common->cc_ani.cycles += cycles;
+	common->cc_ani.rx_busy += busy;
+	common->cc_ani.rx_frame += rx;
+	common->cc_ani.tx_frame += tx;
+
+	common->cc_survey.cycles += cycles;
+	common->cc_survey.rx_busy += busy;
+	common->cc_survey.rx_frame += rx;
+	common->cc_survey.tx_frame += tx;
+}
+
+int32_t ath_hw_get_listen_time(struct ath_common *common)
+{
+	struct ath_cycle_counters *cc = &common->cc_ani;
+	int32_t listen_time;
+
+	listen_time = (cc->cycles - cc->rx_frame - cc->tx_frame) /
+		      (common->clockrate * 1000);
+
+	memset(cc, 0, sizeof(*cc));
+
+	return listen_time;
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath_key.c b/roms/ipxe/src/drivers/net/ath/ath_key.c
new file mode 100644
index 0000000000000000000000000000000000000000..d269a45aca0f9f74acc48c5a3aadf4f1ecdff757
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath_key.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2009 Atheros Communications Inc.
+ * Copyright (c) 2010 Bruno Randolf <br1@einfach.org>
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath.h"
+#include "reg.h"
+
+#define REG_READ			(common->ops->read)
+#define REG_WRITE(_ah, _reg, _val)	(common->ops->write)(_ah, _val, _reg)
+#define ENABLE_REGWRITE_BUFFER(_ah)			\
+	if (common->ops->enable_write_buffer)		\
+		common->ops->enable_write_buffer((_ah));
+
+#define REGWRITE_BUFFER_FLUSH(_ah)			\
+	if (common->ops->write_flush)			\
+		common->ops->write_flush((_ah));
+
+
+#define IEEE80211_WEP_NKID      4       /* number of key ids */
+
+/************************/
+/* Key Cache Management */
+/************************/
+
+int ath_hw_keyreset(struct ath_common *common, u16 entry)
+{
+	u32 keyType;
+	void *ah = common->ah;
+
+	if (entry >= common->keymax) {
+		DBG("ath: keycache entry %d out of range\n", entry);
+		return 0;
+	}
+
+	keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
+
+	ENABLE_REGWRITE_BUFFER(ah);
+
+	REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
+	REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
+	REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
+	REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
+	REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
+	REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
+	REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
+	REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
+
+	if (keyType == AR_KEYTABLE_TYPE_TKIP) {
+		u16 micentry = entry + 64;
+
+		REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
+		REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
+		REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
+		REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
+		if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) {
+			REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
+			REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
+				  AR_KEYTABLE_TYPE_CLR);
+		}
+
+	}
+
+	REGWRITE_BUFFER_FLUSH(ah);
+
+	return 1;
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath_main.c b/roms/ipxe/src/drivers/net/ath/ath_main.c
new file mode 100644
index 0000000000000000000000000000000000000000..85d159a36d3f1086d3edf4a7ed12b968ca7cbd33
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath_main.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2009 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ipxe/io.h>
+
+#include "ath.h"
+
+struct io_buffer *ath_rxbuf_alloc(struct ath_common *common,
+				u32 len,
+				u32 *iob_addr)
+{
+	struct io_buffer *iob;
+	u32 off;
+
+	/*
+	 * Cache-line-align.  This is important (for the
+	 * 5210 at least) as not doing so causes bogus data
+	 * in rx'd frames.
+	 */
+
+	/* Note: the kernel can allocate a value greater than
+	 * what we ask it to give us. We really only need 4 KB as that
+	 * is this hardware supports and in fact we need at least 3849
+	 * as that is the MAX AMSDU size this hardware supports.
+	 * Unfortunately this means we may get 8 KB here from the
+	 * kernel... and that is actually what is observed on some
+	 * systems :( */
+	iob = alloc_iob(len + common->cachelsz - 1);
+	if (iob != NULL) {
+		*iob_addr = virt_to_bus(iob->data);
+		off = ((unsigned long) iob->data) % common->cachelsz;
+		if (off != 0)
+		{
+			iob_reserve(iob, common->cachelsz - off);
+			*iob_addr += common->cachelsz - off;
+		}
+	} else {
+		DBG("ath: iobuffer alloc of size %d failed\n", len);
+		return NULL;
+	}
+
+	return iob;
+}
diff --git a/roms/ipxe/src/drivers/net/ath/ath_regd.c b/roms/ipxe/src/drivers/net/ath/ath_regd.c
new file mode 100644
index 0000000000000000000000000000000000000000..190b1f9f50bb4daf7977821e1f6cff78e6ddc528
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/ath_regd.c
@@ -0,0 +1,602 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "regd.h"
+#include "regd_common.h"
+
+/*
+ * This is a set of common rules used by our world regulatory domains.
+ * We have 12 world regulatory domains. To save space we consolidate
+ * the regulatory domains in 5 structures by frequency and change
+ * the flags on our reg_notifier() on a case by case basis.
+ */
+
+/* Only these channels all allow active scan on all world regulatory domains */
+#define ATH9K_2GHZ_CH01_11	REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
+
+/* We enable active scan on these a case by case basis by regulatory domain */
+#define ATH9K_2GHZ_CH12_13	REG_RULE(2467-10, 2472+10, 40, 0, 20,\
+					NL80211_RRF_PASSIVE_SCAN)
+#define ATH9K_2GHZ_CH14		REG_RULE(2484-10, 2484+10, 40, 0, 20,\
+				NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)
+
+/* We allow IBSS on these on a case by case basis by regulatory domain */
+#define ATH9K_5GHZ_5150_5350	REG_RULE(5150-10, 5350+10, 40, 0, 30,\
+				NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
+#define ATH9K_5GHZ_5470_5850	REG_RULE(5470-10, 5850+10, 40, 0, 30,\
+				NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
+#define ATH9K_5GHZ_5725_5850	REG_RULE(5725-10, 5850+10, 40, 0, 30,\
+				NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
+
+#define ATH9K_2GHZ_ALL		ATH9K_2GHZ_CH01_11, \
+				ATH9K_2GHZ_CH12_13, \
+				ATH9K_2GHZ_CH14
+
+#define ATH9K_5GHZ_ALL		ATH9K_5GHZ_5150_5350, \
+				ATH9K_5GHZ_5470_5850
+
+/* This one skips what we call "mid band" */
+#define ATH9K_5GHZ_NO_MIDBAND	ATH9K_5GHZ_5150_5350, \
+				ATH9K_5GHZ_5725_5850
+
+///* Can be used for:
+// * 0x60, 0x61, 0x62 */
+//static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = {
+//	.n_reg_rules = 5,
+//	.alpha2 =  "99",
+//	.reg_rules = {
+//		ATH9K_2GHZ_ALL,
+//		ATH9K_5GHZ_ALL,
+//	}
+//};
+//
+///* Can be used by 0x63 and 0x65 */
+//static const struct ieee80211_regdomain ath_world_regdom_63_65 = {
+//	.n_reg_rules = 4,
+//	.alpha2 =  "99",
+//	.reg_rules = {
+//		ATH9K_2GHZ_CH01_11,
+//		ATH9K_2GHZ_CH12_13,
+//		ATH9K_5GHZ_NO_MIDBAND,
+//	}
+//};
+//
+///* Can be used by 0x64 only */
+//static const struct ieee80211_regdomain ath_world_regdom_64 = {
+//	.n_reg_rules = 3,
+//	.alpha2 =  "99",
+//	.reg_rules = {
+//		ATH9K_2GHZ_CH01_11,
+//		ATH9K_5GHZ_NO_MIDBAND,
+//	}
+//};
+//
+///* Can be used by 0x66 and 0x69 */
+//static const struct ieee80211_regdomain ath_world_regdom_66_69 = {
+//	.n_reg_rules = 3,
+//	.alpha2 =  "99",
+//	.reg_rules = {
+//		ATH9K_2GHZ_CH01_11,
+//		ATH9K_5GHZ_ALL,
+//	}
+//};
+//
+///* Can be used by 0x67, 0x68, 0x6A and 0x6C */
+//static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = {
+//	.n_reg_rules = 4,
+//	.alpha2 =  "99",
+//	.reg_rules = {
+//		ATH9K_2GHZ_CH01_11,
+//		ATH9K_2GHZ_CH12_13,
+//		ATH9K_5GHZ_ALL,
+//	}
+//};
+//
+//static inline int is_wwr_sku(u16 regd)
+//{
+//	return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) &&
+//		(((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||
+//		(regd == WORLD));
+//}
+//
+//static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg)
+//{
+//	return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG;
+//}
+//
+//int ath_is_world_regd(struct ath_regulatory *reg)
+//{
+//	return is_wwr_sku(ath_regd_get_eepromRD(reg));
+//}
+//
+//static const struct ieee80211_regdomain *ath_default_world_regdomain(void)
+//{
+//	/* this is the most restrictive */
+//	return &ath_world_regdom_64;
+//}
+//
+//static const struct
+//ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
+//{
+//	switch (reg->regpair->regDmnEnum) {
+//	case 0x60:
+//	case 0x61:
+//	case 0x62:
+//		return &ath_world_regdom_60_61_62;
+//	case 0x63:
+//	case 0x65:
+//		return &ath_world_regdom_63_65;
+//	case 0x64:
+//		return &ath_world_regdom_64;
+//	case 0x66:
+//	case 0x69:
+//		return &ath_world_regdom_66_69;
+//	case 0x67:
+//	case 0x68:
+//	case 0x6A:
+//	case 0x6C:
+//		return &ath_world_regdom_67_68_6A_6C;
+//	default:
+//		WARN_ON(1);
+//		return ath_default_world_regdomain();
+//	}
+//}
+//
+//int ath_is_49ghz_allowed(u16 regdomain)
+//{
+//	/* possibly more */
+//	return regdomain == MKK9_MKKC;
+//}
+//
+///* Frequency is one where radar detection is required */
+//static int ath_is_radar_freq(u16 center_freq)
+//{
+//	return (center_freq >= 5260 && center_freq <= 5700);
+//}
+//
+///*
+// * N.B: These exception rules do not apply radar freqs.
+// *
+// * - We enable adhoc (or beaconing) if allowed by 11d
+// * - We enable active scan if the channel is allowed by 11d
+// * - If no country IE has been processed and a we determine we have
+// *   received a beacon on a channel we can enable active scan and
+// *   adhoc (or beaconing).
+// */
+//static void
+//ath_reg_apply_beaconing_flags(struct wiphy *wiphy,
+//			      enum nl80211_reg_initiator initiator)
+//{
+//	int band;
+//	struct ieee80211_supported_band *sband;
+//	const struct ieee80211_reg_rule *reg_rule;
+//	struct net80211_channel *ch;
+//	unsigned int i;
+//	u32 bandwidth = 0;
+//	int r;
+//
+//	for (band = 0; band < NET80211_NR_BANDS; band++) {
+//
+//		if (!wiphy->bands[band])
+//			continue;
+//
+//		sband = wiphy->bands[band];
+//
+//		for (i = 0; i < sband->n_channels; i++) {
+//
+//			ch = &sband->channels[i];
+//
+//			if (ath_is_radar_freq(ch->center_freq) ||
+//			    (ch->flags & IEEE80211_CHAN_RADAR))
+//				continue;
+//
+//			if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+//				r = freq_reg_info(wiphy,
+//						  ch->center_freq,
+//						  bandwidth,
+//						  &reg_rule);
+//				if (r)
+//					continue;
+//				/*
+//				 * If 11d had a rule for this channel ensure
+//				 * we enable adhoc/beaconing if it allows us to
+//				 * use it. Note that we would have disabled it
+//				 * by applying our static world regdomain by
+//				 * default during init, prior to calling our
+//				 * regulatory_hint().
+//				 */
+//				if (!(reg_rule->flags &
+//				    NL80211_RRF_NO_IBSS))
+//					ch->flags &=
+//					  ~IEEE80211_CHAN_NO_IBSS;
+//				if (!(reg_rule->flags &
+//				    NL80211_RRF_PASSIVE_SCAN))
+//					ch->flags &=
+//					  ~IEEE80211_CHAN_PASSIVE_SCAN;
+//			} else {
+//				if (ch->beacon_found)
+//					ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
+//					  IEEE80211_CHAN_PASSIVE_SCAN);
+//			}
+//		}
+//	}
+//
+//}
+//
+///* Allows active scan scan on Ch 12 and 13 */
+//static void
+//ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
+//				enum nl80211_reg_initiator initiator)
+//{
+//	struct ieee80211_supported_band *sband;
+//	struct net80211_channel *ch;
+//	const struct ieee80211_reg_rule *reg_rule;
+//	u32 bandwidth = 0;
+//	int r;
+//
+//	sband = wiphy->bands[NET80211_BAND_2GHZ];
+//
+//	/*
+//	 * If no country IE has been received always enable active scan
+//	 * on these channels. This is only done for specific regulatory SKUs
+//	 */
+//	if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+//		ch = &sband->channels[11]; /* CH 12 */
+//		if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+//			ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+//		ch = &sband->channels[12]; /* CH 13 */
+//		if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+//			ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+//		return;
+//	}
+//
+//	/*
+//	 * If a country IE has been received check its rule for this
+//	 * channel first before enabling active scan. The passive scan
+//	 * would have been enforced by the initial processing of our
+//	 * custom regulatory domain.
+//	 */
+//
+//	ch = &sband->channels[11]; /* CH 12 */
+//	r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
+//	if (!r) {
+//		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
+//			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+//				ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+//	}
+//
+//	ch = &sband->channels[12]; /* CH 13 */
+//	r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
+//	if (!r) {
+//		if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
+//			if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+//				ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+//	}
+//}
+//
+///* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */
+//static void ath_reg_apply_radar_flags(struct wiphy *wiphy)
+//{
+//	struct ieee80211_supported_band *sband;
+//	struct net80211_channel *ch;
+//	unsigned int i;
+//
+//	if (!wiphy->bands[NET80211_BAND_5GHZ])
+//		return;
+//
+//	sband = wiphy->bands[NET80211_BAND_5GHZ];
+//
+//	for (i = 0; i < sband->n_channels; i++) {
+//		ch = &sband->channels[i];
+//		if (!ath_is_radar_freq(ch->center_freq))
+//			continue;
+//		/* We always enable radar detection/DFS on this
+//		 * frequency range. Additionally we also apply on
+//		 * this frequency range:
+//		 * - If STA mode does not yet have DFS supports disable
+//		 *   active scanning
+//		 * - If adhoc mode does not support DFS yet then
+//		 *   disable adhoc in the frequency.
+//		 * - If AP mode does not yet support radar detection/DFS
+//		 *   do not allow AP mode
+//		 */
+//		if (!(ch->flags & IEEE80211_CHAN_DISABLED))
+//			ch->flags |= IEEE80211_CHAN_RADAR |
+//				     IEEE80211_CHAN_NO_IBSS |
+//				     IEEE80211_CHAN_PASSIVE_SCAN;
+//	}
+//}
+//
+//static void ath_reg_apply_world_flags(struct wiphy *wiphy,
+//				      enum nl80211_reg_initiator initiator,
+//				      struct ath_regulatory *reg)
+//{
+//	switch (reg->regpair->regDmnEnum) {
+//	case 0x60:
+//	case 0x63:
+//	case 0x66:
+//	case 0x67:
+//	case 0x6C:
+//		ath_reg_apply_beaconing_flags(wiphy, initiator);
+//		break;
+//	case 0x68:
+//		ath_reg_apply_beaconing_flags(wiphy, initiator);
+//		ath_reg_apply_active_scan_flags(wiphy, initiator);
+//		break;
+//	}
+//}
+//
+//int ath_reg_notifier_apply(struct wiphy *wiphy,
+//			   struct regulatory_request *request,
+//			   struct ath_regulatory *reg)
+//{
+//	/* We always apply this */
+//	ath_reg_apply_radar_flags(wiphy);
+//
+//	/*
+//	 * This would happen when we have sent a custom regulatory request
+//	 * a world regulatory domain and the scheduler hasn't yet processed
+//	 * any pending requests in the queue.
+//	 */
+//	if (!request)
+//		return 0;
+//
+//	switch (request->initiator) {
+//	case NL80211_REGDOM_SET_BY_DRIVER:
+//	case NL80211_REGDOM_SET_BY_CORE:
+//	case NL80211_REGDOM_SET_BY_USER:
+//		break;
+//	case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+//		if (ath_is_world_regd(reg))
+//			ath_reg_apply_world_flags(wiphy, request->initiator,
+//						  reg);
+//		break;
+//	}
+//
+//	return 0;
+//}
+//
+//static int ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
+//{
+//	u16 rd = ath_regd_get_eepromRD(reg);
+//	int i;
+//
+//	if (rd & COUNTRY_ERD_FLAG) {
+//		/* EEPROM value is a country code */
+//		u16 cc = rd & ~COUNTRY_ERD_FLAG;
+//		DBG2(
+//		       "ath: EEPROM indicates we should expect "
+//			"a country code\n");
+//		for (i = 0; i < ARRAY_SIZE(allCountries); i++)
+//			if (allCountries[i].countryCode == cc)
+//				return 1;
+//	} else {
+//		/* EEPROM value is a regpair value */
+//		if (rd != CTRY_DEFAULT)
+//			DBG2("ath: EEPROM indicates we "
+//			       "should expect a direct regpair map\n");
+//		for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
+//			if (regDomainPairs[i].regDmnEnum == rd)
+//				return 1;
+//	}
+//	DBG(
+//		 "ath: invalid regulatory domain/country code 0x%x\n", rd);
+//	return 0;
+//}
+//
+///* EEPROM country code to regpair mapping */
+//static struct country_code_to_enum_rd*
+//ath_regd_find_country(u16 countryCode)
+//{
+//	int i;
+//
+//	for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
+//		if (allCountries[i].countryCode == countryCode)
+//			return &allCountries[i];
+//	}
+//	return NULL;
+//}
+//
+///* EEPROM rd code to regpair mapping */
+//static struct country_code_to_enum_rd*
+//ath_regd_find_country_by_rd(int regdmn)
+//{
+//	int i;
+//
+//	for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
+//		if (allCountries[i].regDmnEnum == regdmn)
+//			return &allCountries[i];
+//	}
+//	return NULL;
+//}
+//
+///* Returns the map of the EEPROM set RD to a country code */
+//static u16 ath_regd_get_default_country(u16 rd)
+//{
+//	if (rd & COUNTRY_ERD_FLAG) {
+//		struct country_code_to_enum_rd *country = NULL;
+//		u16 cc = rd & ~COUNTRY_ERD_FLAG;
+//
+//		country = ath_regd_find_country(cc);
+//		if (country != NULL)
+//			return cc;
+//	}
+//
+//	return CTRY_DEFAULT;
+//}
+//
+//static struct reg_dmn_pair_mapping*
+//ath_get_regpair(int regdmn)
+//{
+//	int i;
+//
+//	if (regdmn == NO_ENUMRD)
+//		return NULL;
+//	for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
+//		if (regDomainPairs[i].regDmnEnum == regdmn)
+//			return &regDomainPairs[i];
+//	}
+//	return NULL;
+//}
+//
+//static int
+//ath_regd_init_wiphy(struct ath_regulatory *reg,
+//		    struct wiphy *wiphy,
+//		    int (*reg_notifier)(struct wiphy *wiphy,
+//					struct regulatory_request *request))
+//{
+//	const struct ieee80211_regdomain *regd;
+//
+//	wiphy->reg_notifier = reg_notifier;
+//	wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;
+//
+//	if (ath_is_world_regd(reg)) {
+//		/*
+//		 * Anything applied here (prior to wiphy registration) gets
+//		 * saved on the wiphy orig_* parameters
+//		 */
+//		regd = ath_world_regdomain(reg);
+//		wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+//	} else {
+//		/*
+//		 * This gets applied in the case of the absence of CRDA,
+//		 * it's our own custom world regulatory domain, similar to
+//		 * cfg80211's but we enable passive scanning.
+//		 */
+//		regd = ath_default_world_regdomain();
+//	}
+//	wiphy_apply_custom_regulatory(wiphy, regd);
+//	ath_reg_apply_radar_flags(wiphy);
+//	ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
+//	return 0;
+//}
+//
+///*
+// * Some users have reported their EEPROM programmed with
+// * 0x8000 set, this is not a supported regulatory domain
+// * but since we have more than one user with it we need
+// * a solution for them. We default to 0x64, which is the
+// * default Atheros world regulatory domain.
+// */
+//static void ath_regd_sanitize(struct ath_regulatory *reg)
+//{
+//	if (reg->current_rd != COUNTRY_ERD_FLAG)
+//		return;
+//	DBG2("ath: EEPROM regdomain sanitized\n");
+//	reg->current_rd = 0x64;
+//}
+//
+//int
+//ath_regd_init(struct ath_regulatory *reg,
+//	      struct wiphy *wiphy,
+//	      int (*reg_notifier)(struct wiphy *wiphy,
+//				  struct regulatory_request *request))
+//{
+//	struct country_code_to_enum_rd *country = NULL;
+//	u16 regdmn;
+//
+//	if (!reg)
+//		return -EINVAL;
+//
+//	ath_regd_sanitize(reg);
+//
+//	DBG2("ath: EEPROM regdomain: 0x%0x\n", reg->current_rd);
+//
+//	if (!ath_regd_is_eeprom_valid(reg)) {
+//		DBG("ath: Invalid EEPROM contents\n");
+//		return -EINVAL;
+//	}
+//
+//	regdmn = ath_regd_get_eepromRD(reg);
+//	reg->country_code = ath_regd_get_default_country(regdmn);
+//
+//	if (reg->country_code == CTRY_DEFAULT &&
+//	    regdmn == CTRY_DEFAULT) {
+//		DBG2("ath: EEPROM indicates default "
+//		       "country code should be used\n");
+//		reg->country_code = CTRY_UNITED_STATES;
+//	}
+//
+//	if (reg->country_code == CTRY_DEFAULT) {
+//		country = NULL;
+//	} else {
+//		DBG2("ath: doing EEPROM country->regdmn "
+//		       "map search\n");
+//		country = ath_regd_find_country(reg->country_code);
+//		if (country == NULL) {
+//			DBG(
+//				"ath: no valid country maps found for "
+//				"country code: 0x%0x\n",
+//				reg->country_code);
+//			return -EINVAL;
+//		} else {
+//			regdmn = country->regDmnEnum;
+//			DBG2("ath: country maps to "
+//			       "regdmn code: 0x%0x\n",
+//			       regdmn);
+//		}
+//	}
+//
+//	reg->regpair = ath_get_regpair(regdmn);
+//
+//	if (!reg->regpair) {
+//		DBG("ath: "
+//			"No regulatory domain pair found, cannot continue\n");
+//		return -EINVAL;
+//	}
+//
+//	if (!country)
+//		country = ath_regd_find_country_by_rd(regdmn);
+//
+//	if (country) {
+//		reg->alpha2[0] = country->isoName[0];
+//		reg->alpha2[1] = country->isoName[1];
+//	} else {
+//		reg->alpha2[0] = '0';
+//		reg->alpha2[1] = '0';
+//	}
+//
+//	DBG2("ath: Country alpha2 being used: %c%c\n",
+//		reg->alpha2[0], reg->alpha2[1]);
+//	DBG2("ath: Regpair used: 0x%0x\n",
+//		reg->regpair->regDmnEnum);
+//
+//	ath_regd_init_wiphy(reg, wiphy, reg_notifier);
+//	return 0;
+//}
+
+u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
+			  int band)
+{
+	/* TODO Cottsay: reg */
+//	if (!reg->regpair ||
+//	    (reg->country_code == CTRY_DEFAULT &&
+//	     is_wwr_sku(ath_regd_get_eepromRD(reg)))) {
+//		return SD_NO_CTL;
+//	}
+
+	switch (band) {
+	case NET80211_BAND_2GHZ:
+		return reg->regpair->reg_2ghz_ctl;
+	case NET80211_BAND_5GHZ:
+		return reg->regpair->reg_5ghz_ctl;
+	default:
+		return NO_CTL;
+	}
+}
diff --git a/roms/ipxe/src/drivers/net/ath/reg.h b/roms/ipxe/src/drivers/net/ath/reg.h
new file mode 100644
index 0000000000000000000000000000000000000000..484a8f1cb147ee3ab07fd30e6119a65869516ff3
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/reg.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ATH_REGISTERS_H
+#define ATH_REGISTERS_H
+
+#define AR_MIBC			0x0040
+#define AR_MIBC_COW		0x00000001
+#define AR_MIBC_FMC		0x00000002
+#define AR_MIBC_CMC		0x00000004
+#define AR_MIBC_MCS		0x00000008
+
+/*
+ * BSSID mask registers. See ath_hw_set_bssid_mask()
+ * for detailed documentation about these registers.
+ */
+#define AR_BSSMSKL		0x80e0
+#define AR_BSSMSKU		0x80e4
+
+#define AR_TFCNT		0x80ec
+#define AR_RFCNT		0x80f0
+#define AR_RCCNT		0x80f4
+#define AR_CCCNT		0x80f8
+
+#define AR_KEYTABLE_0           0x8800
+#define AR_KEYTABLE(_n)         (AR_KEYTABLE_0 + ((_n)*32))
+#define AR_KEY_CACHE_SIZE       128
+#define AR_RSVD_KEYTABLE_ENTRIES 4
+#define AR_KEY_TYPE             0x00000007
+#define AR_KEYTABLE_TYPE_40     0x00000000
+#define AR_KEYTABLE_TYPE_104    0x00000001
+#define AR_KEYTABLE_TYPE_128    0x00000003
+#define AR_KEYTABLE_TYPE_TKIP   0x00000004
+#define AR_KEYTABLE_TYPE_AES    0x00000005
+#define AR_KEYTABLE_TYPE_CCM    0x00000006
+#define AR_KEYTABLE_TYPE_CLR    0x00000007
+#define AR_KEYTABLE_ANT         0x00000008
+#define AR_KEYTABLE_VALID       0x00008000
+#define AR_KEYTABLE_KEY0(_n)    (AR_KEYTABLE(_n) + 0)
+#define AR_KEYTABLE_KEY1(_n)    (AR_KEYTABLE(_n) + 4)
+#define AR_KEYTABLE_KEY2(_n)    (AR_KEYTABLE(_n) + 8)
+#define AR_KEYTABLE_KEY3(_n)    (AR_KEYTABLE(_n) + 12)
+#define AR_KEYTABLE_KEY4(_n)    (AR_KEYTABLE(_n) + 16)
+#define AR_KEYTABLE_TYPE(_n)    (AR_KEYTABLE(_n) + 20)
+#define AR_KEYTABLE_MAC0(_n)    (AR_KEYTABLE(_n) + 24)
+#define AR_KEYTABLE_MAC1(_n)    (AR_KEYTABLE(_n) + 28)
+
+#endif /* ATH_REGISTERS_H */
diff --git a/roms/ipxe/src/drivers/net/ath/regd.h b/roms/ipxe/src/drivers/net/ath/regd.h
new file mode 100644
index 0000000000000000000000000000000000000000..6954c5f3646751b9d9a59969539127784e84c7e1
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/regd.h
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef REGD_H
+#define REGD_H
+
+#include "ath.h"
+
+enum ctl_group {
+	CTL_FCC = 0x10,
+	CTL_MKK = 0x40,
+	CTL_ETSI = 0x30,
+};
+
+#define NO_CTL 0xff
+#define SD_NO_CTL               0xE0
+#define NO_CTL                  0xff
+#define CTL_11A                 0
+#define CTL_11B                 1
+#define CTL_11G                 2
+#define CTL_2GHT20              5
+#define CTL_5GHT20              6
+#define CTL_2GHT40              7
+#define CTL_5GHT40              8
+
+#define CTRY_DEBUG 0x1ff
+#define CTRY_DEFAULT 0
+
+#define COUNTRY_ERD_FLAG        0x8000
+#define WORLDWIDE_ROAMING_FLAG  0x4000
+
+#define MULTI_DOMAIN_MASK 0xFF00
+
+#define WORLD_SKU_MASK          0x00F0
+#define WORLD_SKU_PREFIX        0x0060
+
+#define CHANNEL_HALF_BW         10
+#define CHANNEL_QUARTER_BW      5
+
+struct country_code_to_enum_rd {
+	u16 countryCode;
+	u16 regDmnEnum;
+	const char *isoName;
+};
+
+enum CountryCode {
+	CTRY_ALBANIA = 8,
+	CTRY_ALGERIA = 12,
+	CTRY_ARGENTINA = 32,
+	CTRY_ARMENIA = 51,
+	CTRY_ARUBA = 533,
+	CTRY_AUSTRALIA = 36,
+	CTRY_AUSTRIA = 40,
+	CTRY_AZERBAIJAN = 31,
+	CTRY_BAHRAIN = 48,
+	CTRY_BANGLADESH = 50,
+	CTRY_BARBADOS = 52,
+	CTRY_BELARUS = 112,
+	CTRY_BELGIUM = 56,
+	CTRY_BELIZE = 84,
+	CTRY_BOLIVIA = 68,
+	CTRY_BOSNIA_HERZ = 70,
+	CTRY_BRAZIL = 76,
+	CTRY_BRUNEI_DARUSSALAM = 96,
+	CTRY_BULGARIA = 100,
+	CTRY_CAMBODIA = 116,
+	CTRY_CANADA = 124,
+	CTRY_CHILE = 152,
+	CTRY_CHINA = 156,
+	CTRY_COLOMBIA = 170,
+	CTRY_COSTA_RICA = 188,
+	CTRY_CROATIA = 191,
+	CTRY_CYPRUS = 196,
+	CTRY_CZECH = 203,
+	CTRY_DENMARK = 208,
+	CTRY_DOMINICAN_REPUBLIC = 214,
+	CTRY_ECUADOR = 218,
+	CTRY_EGYPT = 818,
+	CTRY_EL_SALVADOR = 222,
+	CTRY_ESTONIA = 233,
+	CTRY_FAEROE_ISLANDS = 234,
+	CTRY_FINLAND = 246,
+	CTRY_FRANCE = 250,
+	CTRY_GEORGIA = 268,
+	CTRY_GERMANY = 276,
+	CTRY_GREECE = 300,
+	CTRY_GREENLAND = 304,
+	CTRY_GRENEDA = 308,
+	CTRY_GUAM = 316,
+	CTRY_GUATEMALA = 320,
+	CTRY_HAITI = 332,
+	CTRY_HONDURAS = 340,
+	CTRY_HONG_KONG = 344,
+	CTRY_HUNGARY = 348,
+	CTRY_ICELAND = 352,
+	CTRY_INDIA = 356,
+	CTRY_INDONESIA = 360,
+	CTRY_IRAN = 364,
+	CTRY_IRAQ = 368,
+	CTRY_IRELAND = 372,
+	CTRY_ISRAEL = 376,
+	CTRY_ITALY = 380,
+	CTRY_JAMAICA = 388,
+	CTRY_JAPAN = 392,
+	CTRY_JORDAN = 400,
+	CTRY_KAZAKHSTAN = 398,
+	CTRY_KENYA = 404,
+	CTRY_KOREA_NORTH = 408,
+	CTRY_KOREA_ROC = 410,
+	CTRY_KOREA_ROC2 = 411,
+	CTRY_KOREA_ROC3 = 412,
+	CTRY_KUWAIT = 414,
+	CTRY_LATVIA = 428,
+	CTRY_LEBANON = 422,
+	CTRY_LIBYA = 434,
+	CTRY_LIECHTENSTEIN = 438,
+	CTRY_LITHUANIA = 440,
+	CTRY_LUXEMBOURG = 442,
+	CTRY_MACAU = 446,
+	CTRY_MACEDONIA = 807,
+	CTRY_MALAYSIA = 458,
+	CTRY_MALTA = 470,
+	CTRY_MEXICO = 484,
+	CTRY_MONACO = 492,
+	CTRY_MOROCCO = 504,
+	CTRY_NEPAL = 524,
+	CTRY_NETHERLANDS = 528,
+	CTRY_NETHERLANDS_ANTILLES = 530,
+	CTRY_NEW_ZEALAND = 554,
+	CTRY_NICARAGUA = 558,
+	CTRY_NORWAY = 578,
+	CTRY_OMAN = 512,
+	CTRY_PAKISTAN = 586,
+	CTRY_PANAMA = 591,
+	CTRY_PAPUA_NEW_GUINEA = 598,
+	CTRY_PARAGUAY = 600,
+	CTRY_PERU = 604,
+	CTRY_PHILIPPINES = 608,
+	CTRY_POLAND = 616,
+	CTRY_PORTUGAL = 620,
+	CTRY_PUERTO_RICO = 630,
+	CTRY_QATAR = 634,
+	CTRY_ROMANIA = 642,
+	CTRY_RUSSIA = 643,
+	CTRY_SAUDI_ARABIA = 682,
+	CTRY_SERBIA_MONTENEGRO = 891,
+	CTRY_SINGAPORE = 702,
+	CTRY_SLOVAKIA = 703,
+	CTRY_SLOVENIA = 705,
+	CTRY_SOUTH_AFRICA = 710,
+	CTRY_SPAIN = 724,
+	CTRY_SRI_LANKA = 144,
+	CTRY_SWEDEN = 752,
+	CTRY_SWITZERLAND = 756,
+	CTRY_SYRIA = 760,
+	CTRY_TAIWAN = 158,
+	CTRY_THAILAND = 764,
+	CTRY_TRINIDAD_Y_TOBAGO = 780,
+	CTRY_TUNISIA = 788,
+	CTRY_TURKEY = 792,
+	CTRY_UAE = 784,
+	CTRY_UKRAINE = 804,
+	CTRY_UNITED_KINGDOM = 826,
+	CTRY_UNITED_STATES = 840,
+	CTRY_UNITED_STATES_FCC49 = 842,
+	CTRY_URUGUAY = 858,
+	CTRY_UZBEKISTAN = 860,
+	CTRY_VENEZUELA = 862,
+	CTRY_VIET_NAM = 704,
+	CTRY_YEMEN = 887,
+	CTRY_ZIMBABWE = 716,
+	CTRY_JAPAN1 = 393,
+	CTRY_JAPAN2 = 394,
+	CTRY_JAPAN3 = 395,
+	CTRY_JAPAN4 = 396,
+	CTRY_JAPAN5 = 397,
+	CTRY_JAPAN6 = 4006,
+	CTRY_JAPAN7 = 4007,
+	CTRY_JAPAN8 = 4008,
+	CTRY_JAPAN9 = 4009,
+	CTRY_JAPAN10 = 4010,
+	CTRY_JAPAN11 = 4011,
+	CTRY_JAPAN12 = 4012,
+	CTRY_JAPAN13 = 4013,
+	CTRY_JAPAN14 = 4014,
+	CTRY_JAPAN15 = 4015,
+	CTRY_JAPAN16 = 4016,
+	CTRY_JAPAN17 = 4017,
+	CTRY_JAPAN18 = 4018,
+	CTRY_JAPAN19 = 4019,
+	CTRY_JAPAN20 = 4020,
+	CTRY_JAPAN21 = 4021,
+	CTRY_JAPAN22 = 4022,
+	CTRY_JAPAN23 = 4023,
+	CTRY_JAPAN24 = 4024,
+	CTRY_JAPAN25 = 4025,
+	CTRY_JAPAN26 = 4026,
+	CTRY_JAPAN27 = 4027,
+	CTRY_JAPAN28 = 4028,
+	CTRY_JAPAN29 = 4029,
+	CTRY_JAPAN30 = 4030,
+	CTRY_JAPAN31 = 4031,
+	CTRY_JAPAN32 = 4032,
+	CTRY_JAPAN33 = 4033,
+	CTRY_JAPAN34 = 4034,
+	CTRY_JAPAN35 = 4035,
+	CTRY_JAPAN36 = 4036,
+	CTRY_JAPAN37 = 4037,
+	CTRY_JAPAN38 = 4038,
+	CTRY_JAPAN39 = 4039,
+	CTRY_JAPAN40 = 4040,
+	CTRY_JAPAN41 = 4041,
+	CTRY_JAPAN42 = 4042,
+	CTRY_JAPAN43 = 4043,
+	CTRY_JAPAN44 = 4044,
+	CTRY_JAPAN45 = 4045,
+	CTRY_JAPAN46 = 4046,
+	CTRY_JAPAN47 = 4047,
+	CTRY_JAPAN48 = 4048,
+	CTRY_JAPAN49 = 4049,
+	CTRY_JAPAN50 = 4050,
+	CTRY_JAPAN51 = 4051,
+	CTRY_JAPAN52 = 4052,
+	CTRY_JAPAN53 = 4053,
+	CTRY_JAPAN54 = 4054,
+	CTRY_JAPAN55 = 4055,
+	CTRY_JAPAN56 = 4056,
+	CTRY_JAPAN57 = 4057,
+	CTRY_JAPAN58 = 4058,
+	CTRY_JAPAN59 = 4059,
+	CTRY_AUSTRALIA2 = 5000,
+	CTRY_CANADA2 = 5001,
+	CTRY_BELGIUM2 = 5002
+};
+
+int ath_is_world_regd(struct ath_regulatory *reg);
+int ath_is_49ghz_allowed(u16 redomain);
+//int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy,
+//		  int (*reg_notifier)(struct wiphy *wiphy,
+//		  struct regulatory_request *request));
+u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
+			  int band);
+//int ath_reg_notifier_apply(struct wiphy *wiphy,
+//			   struct regulatory_request *request,
+//			   struct ath_regulatory *reg);
+
+#endif
diff --git a/roms/ipxe/src/drivers/net/ath/regd_common.h b/roms/ipxe/src/drivers/net/ath/regd_common.h
new file mode 100644
index 0000000000000000000000000000000000000000..ee1ac3f409ebc5110800b16e67de86f9252dd3ec
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/ath/regd_common.h
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
+ * Original from Linux kernel 3.0.1
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef REGD_COMMON_H
+#define REGD_COMMON_H
+
+enum EnumRd {
+	NO_ENUMRD = 0x00,
+	NULL1_WORLD = 0x03,
+	NULL1_ETSIB = 0x07,
+	NULL1_ETSIC = 0x08,
+	FCC1_FCCA = 0x10,
+	FCC1_WORLD = 0x11,
+	FCC4_FCCA = 0x12,
+	FCC5_FCCA = 0x13,
+	FCC6_FCCA = 0x14,
+
+	FCC2_FCCA = 0x20,
+	FCC2_WORLD = 0x21,
+	FCC2_ETSIC = 0x22,
+	FCC6_WORLD = 0x23,
+	FRANCE_RES = 0x31,
+	FCC3_FCCA = 0x3A,
+	FCC3_WORLD = 0x3B,
+
+	ETSI1_WORLD = 0x37,
+	ETSI3_ETSIA = 0x32,
+	ETSI2_WORLD = 0x35,
+	ETSI3_WORLD = 0x36,
+	ETSI4_WORLD = 0x30,
+	ETSI4_ETSIC = 0x38,
+	ETSI5_WORLD = 0x39,
+	ETSI6_WORLD = 0x34,
+	ETSI_RESERVED = 0x33,
+
+	MKK1_MKKA = 0x40,
+	MKK1_MKKB = 0x41,
+	APL4_WORLD = 0x42,
+	MKK2_MKKA = 0x43,
+	APL_RESERVED = 0x44,
+	APL2_WORLD = 0x45,
+	APL2_APLC = 0x46,
+	APL3_WORLD = 0x47,
+	MKK1_FCCA = 0x48,
+	APL2_APLD = 0x49,
+	MKK1_MKKA1 = 0x4A,
+	MKK1_MKKA2 = 0x4B,
+	MKK1_MKKC = 0x4C,
+
+	APL3_FCCA = 0x50,
+	APL1_WORLD = 0x52,
+	APL1_FCCA = 0x53,
+	APL1_APLA = 0x54,
+	APL1_ETSIC = 0x55,
+	APL2_ETSIC = 0x56,
+	APL5_WORLD = 0x58,
+	APL6_WORLD = 0x5B,
+	APL7_FCCA = 0x5C,
+	APL8_WORLD = 0x5D,
+	APL9_WORLD = 0x5E,
+
+	WOR0_WORLD = 0x60,
+	WOR1_WORLD = 0x61,
+	WOR2_WORLD = 0x62,
+	WOR3_WORLD = 0x63,
+	WOR4_WORLD = 0x64,
+	WOR5_ETSIC = 0x65,
+
+	WOR01_WORLD = 0x66,
+	WOR02_WORLD = 0x67,
+	EU1_WORLD = 0x68,
+
+	WOR9_WORLD = 0x69,
+	WORA_WORLD = 0x6A,
+	WORB_WORLD = 0x6B,
+	WORC_WORLD = 0x6C,
+
+	MKK3_MKKB = 0x80,
+	MKK3_MKKA2 = 0x81,
+	MKK3_MKKC = 0x82,
+
+	MKK4_MKKB = 0x83,
+	MKK4_MKKA2 = 0x84,
+	MKK4_MKKC = 0x85,
+
+	MKK5_MKKB = 0x86,
+	MKK5_MKKA2 = 0x87,
+	MKK5_MKKC = 0x88,
+
+	MKK6_MKKB = 0x89,
+	MKK6_MKKA2 = 0x8A,
+	MKK6_MKKC = 0x8B,
+
+	MKK7_MKKB = 0x8C,
+	MKK7_MKKA2 = 0x8D,
+	MKK7_MKKC = 0x8E,
+
+	MKK8_MKKB = 0x8F,
+	MKK8_MKKA2 = 0x90,
+	MKK8_MKKC = 0x91,
+
+	MKK14_MKKA1 = 0x92,
+	MKK15_MKKA1 = 0x93,
+
+	MKK10_FCCA = 0xD0,
+	MKK10_MKKA1 = 0xD1,
+	MKK10_MKKC = 0xD2,
+	MKK10_MKKA2 = 0xD3,
+
+	MKK11_MKKA = 0xD4,
+	MKK11_FCCA = 0xD5,
+	MKK11_MKKA1 = 0xD6,
+	MKK11_MKKC = 0xD7,
+	MKK11_MKKA2 = 0xD8,
+
+	MKK12_MKKA = 0xD9,
+	MKK12_FCCA = 0xDA,
+	MKK12_MKKA1 = 0xDB,
+	MKK12_MKKC = 0xDC,
+	MKK12_MKKA2 = 0xDD,
+
+	MKK13_MKKB = 0xDE,
+
+	MKK3_MKKA = 0xF0,
+	MKK3_MKKA1 = 0xF1,
+	MKK3_FCCA = 0xF2,
+	MKK4_MKKA = 0xF3,
+	MKK4_MKKA1 = 0xF4,
+	MKK4_FCCA = 0xF5,
+	MKK9_MKKA = 0xF6,
+	MKK10_MKKA = 0xF7,
+	MKK6_MKKA1 = 0xF8,
+	MKK6_FCCA = 0xF9,
+	MKK7_MKKA1 = 0xFA,
+	MKK7_FCCA = 0xFB,
+	MKK9_FCCA = 0xFC,
+	MKK9_MKKA1 = 0xFD,
+	MKK9_MKKC = 0xFE,
+	MKK9_MKKA2 = 0xFF,
+
+	WORLD = 0x0199,
+	DEBUG_REG_DMN = 0x01ff,
+};
+
+///* Regpair to CTL band mapping */
+//static struct reg_dmn_pair_mapping regDomainPairs[] = {
+//	/* regpair, 5 GHz CTL, 2 GHz CTL */
+//	{NO_ENUMRD, DEBUG_REG_DMN, DEBUG_REG_DMN},
+//	{NULL1_WORLD, NO_CTL, CTL_ETSI},
+//	{NULL1_ETSIB, NO_CTL, CTL_ETSI},
+//	{NULL1_ETSIC, NO_CTL, CTL_ETSI},
+//
+//	{FCC2_FCCA, CTL_FCC, CTL_FCC},
+//	{FCC2_WORLD, CTL_FCC, CTL_ETSI},
+//	{FCC2_ETSIC, CTL_FCC, CTL_ETSI},
+//	{FCC3_FCCA, CTL_FCC, CTL_FCC},
+//	{FCC3_WORLD, CTL_FCC, CTL_ETSI},
+//	{FCC4_FCCA, CTL_FCC, CTL_FCC},
+//	{FCC5_FCCA, CTL_FCC, CTL_FCC},
+//	{FCC6_FCCA, CTL_FCC, CTL_FCC},
+//	{FCC6_WORLD, CTL_FCC, CTL_ETSI},
+//
+//	{ETSI1_WORLD, CTL_ETSI, CTL_ETSI},
+//	{ETSI2_WORLD, CTL_ETSI, CTL_ETSI},
+//	{ETSI3_WORLD, CTL_ETSI, CTL_ETSI},
+//	{ETSI4_WORLD, CTL_ETSI, CTL_ETSI},
+//	{ETSI5_WORLD, CTL_ETSI, CTL_ETSI},
+//	{ETSI6_WORLD, CTL_ETSI, CTL_ETSI},
+//
+//	/* XXX: For ETSI3_ETSIA, Was NO_CTL meant for the 2 GHz band ? */
+//	{ETSI3_ETSIA, CTL_ETSI, CTL_ETSI},
+//	{FRANCE_RES, CTL_ETSI, CTL_ETSI},
+//
+//	{FCC1_WORLD, CTL_FCC, CTL_ETSI},
+//	{FCC1_FCCA, CTL_FCC, CTL_FCC},
+//	{APL1_WORLD, CTL_FCC, CTL_ETSI},
+//	{APL2_WORLD, CTL_FCC, CTL_ETSI},
+//	{APL3_WORLD, CTL_FCC, CTL_ETSI},
+//	{APL4_WORLD, CTL_FCC, CTL_ETSI},
+//	{APL5_WORLD, CTL_FCC, CTL_ETSI},
+//	{APL6_WORLD, CTL_ETSI, CTL_ETSI},
+//	{APL8_WORLD, CTL_ETSI, CTL_ETSI},
+//	{APL9_WORLD, CTL_ETSI, CTL_ETSI},
+//
+//	{APL3_FCCA, CTL_FCC, CTL_FCC},
+//	{APL7_FCCA, CTL_FCC, CTL_FCC},
+//	{APL1_ETSIC, CTL_FCC, CTL_ETSI},
+//	{APL2_ETSIC, CTL_FCC, CTL_ETSI},
+//	{APL2_APLD, CTL_FCC, NO_CTL},
+//
+//	{MKK1_MKKA, CTL_MKK, CTL_MKK},
+//	{MKK1_MKKB, CTL_MKK, CTL_MKK},
+//	{MKK1_FCCA, CTL_MKK, CTL_FCC},
+//	{MKK1_MKKA1, CTL_MKK, CTL_MKK},
+//	{MKK1_MKKA2, CTL_MKK, CTL_MKK},
+//	{MKK1_MKKC, CTL_MKK, CTL_MKK},
+//
+//	{MKK2_MKKA, CTL_MKK, CTL_MKK},
+//	{MKK3_MKKA, CTL_MKK, CTL_MKK},
+//	{MKK3_MKKB, CTL_MKK, CTL_MKK},
+//	{MKK3_MKKA1, CTL_MKK, CTL_MKK},
+//	{MKK3_MKKA2, CTL_MKK, CTL_MKK},
+//	{MKK3_MKKC, CTL_MKK, CTL_MKK},
+//	{MKK3_FCCA, CTL_MKK, CTL_FCC},
+//
+//	{MKK4_MKKA, CTL_MKK, CTL_MKK},
+//	{MKK4_MKKB, CTL_MKK, CTL_MKK},
+//	{MKK4_MKKA1, CTL_MKK, CTL_MKK},
+//	{MKK4_MKKA2, CTL_MKK, CTL_MKK},
+//	{MKK4_MKKC, CTL_MKK, CTL_MKK},
+//	{MKK4_FCCA, CTL_MKK, CTL_FCC},
+//
+//	{MKK5_MKKB, CTL_MKK, CTL_MKK},
+//	{MKK5_MKKA2, CTL_MKK, CTL_MKK},
+//	{MKK5_MKKC, CTL_MKK, CTL_MKK},
+//
+//	{MKK6_MKKB, CTL_MKK, CTL_MKK},
+//	{MKK6_MKKA1, CTL_MKK, CTL_MKK},
+//	{MKK6_MKKA2, CTL_MKK, CTL_MKK},
+//	{MKK6_MKKC, CTL_MKK, CTL_MKK},
+//	{MKK6_FCCA, CTL_MKK, CTL_FCC},
+//
+//	{MKK7_MKKB, CTL_MKK, CTL_MKK},
+//	{MKK7_MKKA1, CTL_MKK, CTL_MKK},
+//	{MKK7_MKKA2, CTL_MKK, CTL_MKK},
+//	{MKK7_MKKC, CTL_MKK, CTL_MKK},
+//	{MKK7_FCCA, CTL_MKK, CTL_FCC},
+//
+//	{MKK8_MKKB, CTL_MKK, CTL_MKK},
+//	{MKK8_MKKA2, CTL_MKK, CTL_MKK},
+//	{MKK8_MKKC, CTL_MKK, CTL_MKK},
+//
+//	{MKK9_MKKA, CTL_MKK, CTL_MKK},
+//	{MKK9_FCCA, CTL_MKK, CTL_FCC},
+//	{MKK9_MKKA1, CTL_MKK, CTL_MKK},
+//	{MKK9_MKKA2, CTL_MKK, CTL_MKK},
+//	{MKK9_MKKC, CTL_MKK, CTL_MKK},
+//
+//	{MKK10_MKKA, CTL_MKK, CTL_MKK},
+//	{MKK10_FCCA, CTL_MKK, CTL_FCC},
+//	{MKK10_MKKA1, CTL_MKK, CTL_MKK},
+//	{MKK10_MKKA2, CTL_MKK, CTL_MKK},
+//	{MKK10_MKKC, CTL_MKK, CTL_MKK},
+//
+//	{MKK11_MKKA, CTL_MKK, CTL_MKK},
+//	{MKK11_FCCA, CTL_MKK, CTL_FCC},
+//	{MKK11_MKKA1, CTL_MKK, CTL_MKK},
+//	{MKK11_MKKA2, CTL_MKK, CTL_MKK},
+//	{MKK11_MKKC, CTL_MKK, CTL_MKK},
+//
+//	{MKK12_MKKA, CTL_MKK, CTL_MKK},
+//	{MKK12_FCCA, CTL_MKK, CTL_FCC},
+//	{MKK12_MKKA1, CTL_MKK, CTL_MKK},
+//	{MKK12_MKKA2, CTL_MKK, CTL_MKK},
+//	{MKK12_MKKC, CTL_MKK, CTL_MKK},
+//
+//	{MKK13_MKKB, CTL_MKK, CTL_MKK},
+//	{MKK14_MKKA1, CTL_MKK, CTL_MKK},
+//	{MKK15_MKKA1, CTL_MKK, CTL_MKK},
+//
+//	{WOR0_WORLD, NO_CTL, NO_CTL},
+//	{WOR1_WORLD, NO_CTL, NO_CTL},
+//	{WOR2_WORLD, NO_CTL, NO_CTL},
+//	{WOR3_WORLD, NO_CTL, NO_CTL},
+//	{WOR4_WORLD, NO_CTL, NO_CTL},
+//	{WOR5_ETSIC, NO_CTL, NO_CTL},
+//	{WOR01_WORLD, NO_CTL, NO_CTL},
+//	{WOR02_WORLD, NO_CTL, NO_CTL},
+//	{EU1_WORLD, NO_CTL, NO_CTL},
+//	{WOR9_WORLD, NO_CTL, NO_CTL},
+//	{WORA_WORLD, NO_CTL, NO_CTL},
+//	{WORB_WORLD, NO_CTL, NO_CTL},
+//	{WORC_WORLD, NO_CTL, NO_CTL},
+//};
+//
+//static struct country_code_to_enum_rd allCountries[] = {
+//	{CTRY_DEBUG, NO_ENUMRD, "DB"},
+//	{CTRY_DEFAULT, FCC1_FCCA, "CO"},
+//	{CTRY_ALBANIA, NULL1_WORLD, "AL"},
+//	{CTRY_ALGERIA, NULL1_WORLD, "DZ"},
+//	{CTRY_ARGENTINA, FCC3_WORLD, "AR"},
+//	{CTRY_ARMENIA, ETSI4_WORLD, "AM"},
+//	{CTRY_ARUBA, ETSI1_WORLD, "AW"},
+//	{CTRY_AUSTRALIA, FCC2_WORLD, "AU"},
+//	{CTRY_AUSTRALIA2, FCC6_WORLD, "AU"},
+//	{CTRY_AUSTRIA, ETSI1_WORLD, "AT"},
+//	{CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ"},
+//	{CTRY_BAHRAIN, APL6_WORLD, "BH"},
+//	{CTRY_BANGLADESH, NULL1_WORLD, "BD"},
+//	{CTRY_BARBADOS, FCC2_WORLD, "BB"},
+//	{CTRY_BELARUS, ETSI1_WORLD, "BY"},
+//	{CTRY_BELGIUM, ETSI1_WORLD, "BE"},
+//	{CTRY_BELGIUM2, ETSI4_WORLD, "BL"},
+//	{CTRY_BELIZE, APL1_ETSIC, "BZ"},
+//	{CTRY_BOLIVIA, APL1_ETSIC, "BO"},
+//	{CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA"},
+//	{CTRY_BRAZIL, FCC3_WORLD, "BR"},
+//	{CTRY_BRUNEI_DARUSSALAM, APL1_WORLD, "BN"},
+//	{CTRY_BULGARIA, ETSI6_WORLD, "BG"},
+//	{CTRY_CAMBODIA, ETSI1_WORLD, "KH"},
+//	{CTRY_CANADA, FCC3_FCCA, "CA"},
+//	{CTRY_CANADA2, FCC6_FCCA, "CA"},
+//	{CTRY_CHILE, APL6_WORLD, "CL"},
+//	{CTRY_CHINA, APL1_WORLD, "CN"},
+//	{CTRY_COLOMBIA, FCC1_FCCA, "CO"},
+//	{CTRY_COSTA_RICA, FCC1_WORLD, "CR"},
+//	{CTRY_CROATIA, ETSI1_WORLD, "HR"},
+//	{CTRY_CYPRUS, ETSI1_WORLD, "CY"},
+//	{CTRY_CZECH, ETSI3_WORLD, "CZ"},
+//	{CTRY_DENMARK, ETSI1_WORLD, "DK"},
+//	{CTRY_DOMINICAN_REPUBLIC, FCC1_FCCA, "DO"},
+//	{CTRY_ECUADOR, FCC1_WORLD, "EC"},
+//	{CTRY_EGYPT, ETSI3_WORLD, "EG"},
+//	{CTRY_EL_SALVADOR, FCC1_WORLD, "SV"},
+//	{CTRY_ESTONIA, ETSI1_WORLD, "EE"},
+//	{CTRY_FINLAND, ETSI1_WORLD, "FI"},
+//	{CTRY_FRANCE, ETSI1_WORLD, "FR"},
+//	{CTRY_GEORGIA, ETSI4_WORLD, "GE"},
+//	{CTRY_GERMANY, ETSI1_WORLD, "DE"},
+//	{CTRY_GREECE, ETSI1_WORLD, "GR"},
+//	{CTRY_GREENLAND, ETSI1_WORLD, "GL"},
+//	{CTRY_GRENEDA, FCC3_FCCA, "GD"},
+//	{CTRY_GUAM, FCC1_FCCA, "GU"},
+//	{CTRY_GUATEMALA, FCC1_FCCA, "GT"},
+//	{CTRY_HAITI, ETSI1_WORLD, "HT"},
+//	{CTRY_HONDURAS, NULL1_WORLD, "HN"},
+//	{CTRY_HONG_KONG, FCC3_WORLD, "HK"},
+//	{CTRY_HUNGARY, ETSI1_WORLD, "HU"},
+//	{CTRY_ICELAND, ETSI1_WORLD, "IS"},
+//	{CTRY_INDIA, APL6_WORLD, "IN"},
+//	{CTRY_INDONESIA, NULL1_WORLD, "ID"},
+//	{CTRY_IRAN, APL1_WORLD, "IR"},
+//	{CTRY_IRELAND, ETSI1_WORLD, "IE"},
+//	{CTRY_ISRAEL, NULL1_WORLD, "IL"},
+//	{CTRY_ITALY, ETSI1_WORLD, "IT"},
+//	{CTRY_JAMAICA, FCC3_WORLD, "JM"},
+//
+//	{CTRY_JAPAN, MKK1_MKKA, "JP"},
+//	{CTRY_JAPAN1, MKK1_MKKB, "JP"},
+//	{CTRY_JAPAN2, MKK1_FCCA, "JP"},
+//	{CTRY_JAPAN3, MKK2_MKKA, "JP"},
+//	{CTRY_JAPAN4, MKK1_MKKA1, "JP"},
+//	{CTRY_JAPAN5, MKK1_MKKA2, "JP"},
+//	{CTRY_JAPAN6, MKK1_MKKC, "JP"},
+//	{CTRY_JAPAN7, MKK3_MKKB, "JP"},
+//	{CTRY_JAPAN8, MKK3_MKKA2, "JP"},
+//	{CTRY_JAPAN9, MKK3_MKKC, "JP"},
+//	{CTRY_JAPAN10, MKK4_MKKB, "JP"},
+//	{CTRY_JAPAN11, MKK4_MKKA2, "JP"},
+//	{CTRY_JAPAN12, MKK4_MKKC, "JP"},
+//	{CTRY_JAPAN13, MKK5_MKKB, "JP"},
+//	{CTRY_JAPAN14, MKK5_MKKA2, "JP"},
+//	{CTRY_JAPAN15, MKK5_MKKC, "JP"},
+//	{CTRY_JAPAN16, MKK6_MKKB, "JP"},
+//	{CTRY_JAPAN17, MKK6_MKKA2, "JP"},
+//	{CTRY_JAPAN18, MKK6_MKKC, "JP"},
+//	{CTRY_JAPAN19, MKK7_MKKB, "JP"},
+//	{CTRY_JAPAN20, MKK7_MKKA2, "JP"},
+//	{CTRY_JAPAN21, MKK7_MKKC, "JP"},
+//	{CTRY_JAPAN22, MKK8_MKKB, "JP"},
+//	{CTRY_JAPAN23, MKK8_MKKA2, "JP"},
+//	{CTRY_JAPAN24, MKK8_MKKC, "JP"},
+//	{CTRY_JAPAN25, MKK3_MKKA, "JP"},
+//	{CTRY_JAPAN26, MKK3_MKKA1, "JP"},
+//	{CTRY_JAPAN27, MKK3_FCCA, "JP"},
+//	{CTRY_JAPAN28, MKK4_MKKA1, "JP"},
+//	{CTRY_JAPAN29, MKK4_FCCA, "JP"},
+//	{CTRY_JAPAN30, MKK6_MKKA1, "JP"},
+//	{CTRY_JAPAN31, MKK6_FCCA, "JP"},
+//	{CTRY_JAPAN32, MKK7_MKKA1, "JP"},
+//	{CTRY_JAPAN33, MKK7_FCCA, "JP"},
+//	{CTRY_JAPAN34, MKK9_MKKA, "JP"},
+//	{CTRY_JAPAN35, MKK10_MKKA, "JP"},
+//	{CTRY_JAPAN36, MKK4_MKKA, "JP"},
+//	{CTRY_JAPAN37, MKK9_FCCA, "JP"},
+//	{CTRY_JAPAN38, MKK9_MKKA1, "JP"},
+//	{CTRY_JAPAN39, MKK9_MKKC, "JP"},
+//	{CTRY_JAPAN40, MKK9_MKKA2, "JP"},
+//	{CTRY_JAPAN41, MKK10_FCCA, "JP"},
+//	{CTRY_JAPAN42, MKK10_MKKA1, "JP"},
+//	{CTRY_JAPAN43, MKK10_MKKC, "JP"},
+//	{CTRY_JAPAN44, MKK10_MKKA2, "JP"},
+//	{CTRY_JAPAN45, MKK11_MKKA, "JP"},
+//	{CTRY_JAPAN46, MKK11_FCCA, "JP"},
+//	{CTRY_JAPAN47, MKK11_MKKA1, "JP"},
+//	{CTRY_JAPAN48, MKK11_MKKC, "JP"},
+//	{CTRY_JAPAN49, MKK11_MKKA2, "JP"},
+//	{CTRY_JAPAN50, MKK12_MKKA, "JP"},
+//	{CTRY_JAPAN51, MKK12_FCCA, "JP"},
+//	{CTRY_JAPAN52, MKK12_MKKA1, "JP"},
+//	{CTRY_JAPAN53, MKK12_MKKC, "JP"},
+//	{CTRY_JAPAN54, MKK12_MKKA2, "JP"},
+//	{CTRY_JAPAN57, MKK13_MKKB, "JP"},
+//	{CTRY_JAPAN58, MKK14_MKKA1, "JP"},
+//	{CTRY_JAPAN59, MKK15_MKKA1, "JP"},
+//
+//	{CTRY_JORDAN, ETSI2_WORLD, "JO"},
+//	{CTRY_KAZAKHSTAN, NULL1_WORLD, "KZ"},
+//	{CTRY_KOREA_NORTH, APL9_WORLD, "KP"},
+//	{CTRY_KOREA_ROC, APL9_WORLD, "KR"},
+//	{CTRY_KOREA_ROC2, APL2_WORLD, "K2"},
+//	{CTRY_KOREA_ROC3, APL9_WORLD, "K3"},
+//	{CTRY_KUWAIT, ETSI3_WORLD, "KW"},
+//	{CTRY_LATVIA, ETSI1_WORLD, "LV"},
+//	{CTRY_LEBANON, NULL1_WORLD, "LB"},
+//	{CTRY_LIECHTENSTEIN, ETSI1_WORLD, "LI"},
+//	{CTRY_LITHUANIA, ETSI1_WORLD, "LT"},
+//	{CTRY_LUXEMBOURG, ETSI1_WORLD, "LU"},
+//	{CTRY_MACAU, FCC2_WORLD, "MO"},
+//	{CTRY_MACEDONIA, NULL1_WORLD, "MK"},
+//	{CTRY_MALAYSIA, APL8_WORLD, "MY"},
+//	{CTRY_MALTA, ETSI1_WORLD, "MT"},
+//	{CTRY_MEXICO, FCC1_FCCA, "MX"},
+//	{CTRY_MONACO, ETSI4_WORLD, "MC"},
+//	{CTRY_MOROCCO, APL4_WORLD, "MA"},
+//	{CTRY_NEPAL, APL1_WORLD, "NP"},
+//	{CTRY_NETHERLANDS, ETSI1_WORLD, "NL"},
+//	{CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN"},
+//	{CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ"},
+//	{CTRY_NORWAY, ETSI1_WORLD, "NO"},
+//	{CTRY_OMAN, FCC3_WORLD, "OM"},
+//	{CTRY_PAKISTAN, NULL1_WORLD, "PK"},
+//	{CTRY_PANAMA, FCC1_FCCA, "PA"},
+//	{CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG"},
+//	{CTRY_PERU, APL1_WORLD, "PE"},
+//	{CTRY_PHILIPPINES, APL1_WORLD, "PH"},
+//	{CTRY_POLAND, ETSI1_WORLD, "PL"},
+//	{CTRY_PORTUGAL, ETSI1_WORLD, "PT"},
+//	{CTRY_PUERTO_RICO, FCC1_FCCA, "PR"},
+//	{CTRY_QATAR, APL1_WORLD, "QA"},
+//	{CTRY_ROMANIA, NULL1_WORLD, "RO"},
+//	{CTRY_RUSSIA, NULL1_WORLD, "RU"},
+//	{CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA"},
+//	{CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS"},
+//	{CTRY_SINGAPORE, APL6_WORLD, "SG"},
+//	{CTRY_SLOVAKIA, ETSI1_WORLD, "SK"},
+//	{CTRY_SLOVENIA, ETSI1_WORLD, "SI"},
+//	{CTRY_SOUTH_AFRICA, FCC3_WORLD, "ZA"},
+//	{CTRY_SPAIN, ETSI1_WORLD, "ES"},
+//	{CTRY_SRI_LANKA, FCC3_WORLD, "LK"},
+//	{CTRY_SWEDEN, ETSI1_WORLD, "SE"},
+//	{CTRY_SWITZERLAND, ETSI1_WORLD, "CH"},
+//	{CTRY_SYRIA, NULL1_WORLD, "SY"},
+//	{CTRY_TAIWAN, APL3_FCCA, "TW"},
+//	{CTRY_THAILAND, FCC3_WORLD, "TH"},
+//	{CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT"},
+//	{CTRY_TUNISIA, ETSI3_WORLD, "TN"},
+//	{CTRY_TURKEY, ETSI3_WORLD, "TR"},
+//	{CTRY_UKRAINE, NULL1_WORLD, "UA"},
+//	{CTRY_UAE, NULL1_WORLD, "AE"},
+//	{CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"},
+//	{CTRY_UNITED_STATES, FCC3_FCCA, "US"},
+//	/* This "PS" is for US public safety actually... to support this we
+//	 * would need to assign new special alpha2 to CRDA db as with the world
+//	 * regdomain and use another alpha2 */
+//	{CTRY_UNITED_STATES_FCC49, FCC4_FCCA, "PS"},
+//	{CTRY_URUGUAY, FCC3_WORLD, "UY"},
+//	{CTRY_UZBEKISTAN, FCC3_FCCA, "UZ"},
+//	{CTRY_VENEZUELA, APL2_ETSIC, "VE"},
+//	{CTRY_VIET_NAM, NULL1_WORLD, "VN"},
+//	{CTRY_YEMEN, NULL1_WORLD, "YE"},
+//	{CTRY_ZIMBABWE, NULL1_WORLD, "ZW"},
+//};
+
+#endif
diff --git a/roms/ipxe/src/drivers/net/ath5k/ath5k.c b/roms/ipxe/src/drivers/net/ath5k/ath5k.c
deleted file mode 100644
index 92c4ffdf410bb49906a45d618080e44a3740fea8..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/ath5k.c
+++ /dev/null
@@ -1,1698 +0,0 @@
-/*
- * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
- * Copyright (c) 2004-2005 Atheros Communications, Inc.
- * Copyright (c) 2006 Devicescape Software, Inc.
- * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
- * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
- *
- * Modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>
- * Original from Linux kernel 2.6.30.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
- *    redistribution must be conditioned upon including a substantially
- *    similar Disclaimer requirement for further binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * 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 NONINFRINGEMENT, MERCHANTIBILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- *
- */
-
-FILE_LICENCE ( BSD3 );
-
-#include <stdlib.h>
-#include <ipxe/malloc.h>
-#include <ipxe/timer.h>
-#include <ipxe/netdevice.h>
-#include <ipxe/pci.h>
-#include <ipxe/pci_io.h>
-
-#include "base.h"
-#include "reg.h"
-
-#define ATH5K_CALIB_INTERVAL	10 /* Calibrate PHY every 10 seconds */
-#define ATH5K_RETRIES		4  /* Number of times to retry packet sends */
-#define ATH5K_DESC_ALIGN	16 /* Alignment for TX/RX descriptors */
-
-/******************\
-* Internal defines *
-\******************/
-
-/* Known PCI ids */
-static struct pci_device_id ath5k_nics[] = {
-	PCI_ROM(0x168c, 0x0207, "ath5210e", "Atheros 5210 early", AR5K_AR5210),
-	PCI_ROM(0x168c, 0x0007, "ath5210", "Atheros 5210", AR5K_AR5210),
-	PCI_ROM(0x168c, 0x0011, "ath5311", "Atheros 5311 (AHB)", AR5K_AR5211),
-	PCI_ROM(0x168c, 0x0012, "ath5211", "Atheros 5211", AR5K_AR5211),
-	PCI_ROM(0x168c, 0x0013, "ath5212", "Atheros 5212", AR5K_AR5212),
-	PCI_ROM(0xa727, 0x0013, "ath5212c","3com Ath 5212", AR5K_AR5212),
-	PCI_ROM(0x10b7, 0x0013, "rdag675", "3com 3CRDAG675", AR5K_AR5212),
-	PCI_ROM(0x168c, 0x1014, "ath5212m", "Ath 5212 miniPCI", AR5K_AR5212),
-	PCI_ROM(0x168c, 0x0014, "ath5212x14", "Atheros 5212 x14", AR5K_AR5212),
-	PCI_ROM(0x168c, 0x0015, "ath5212x15", "Atheros 5212 x15", AR5K_AR5212),
-	PCI_ROM(0x168c, 0x0016, "ath5212x16", "Atheros 5212 x16", AR5K_AR5212),
-	PCI_ROM(0x168c, 0x0017, "ath5212x17", "Atheros 5212 x17", AR5K_AR5212),
-	PCI_ROM(0x168c, 0x0018, "ath5212x18", "Atheros 5212 x18", AR5K_AR5212),
-	PCI_ROM(0x168c, 0x0019, "ath5212x19", "Atheros 5212 x19", AR5K_AR5212),
-	PCI_ROM(0x168c, 0x001a, "ath2413", "Atheros 2413 Griffin", AR5K_AR5212),
-	PCI_ROM(0x168c, 0x001b, "ath5413", "Atheros 5413 Eagle", AR5K_AR5212),
-	PCI_ROM(0x168c, 0x001c, "ath5212e", "Atheros 5212 PCI-E", AR5K_AR5212),
-	PCI_ROM(0x168c, 0x001d, "ath2417", "Atheros 2417 Nala", AR5K_AR5212),
-};
-
-/* Known SREVs */
-static const struct ath5k_srev_name srev_names[] = {
-	{ "5210",	AR5K_VERSION_MAC,	AR5K_SREV_AR5210 },
-	{ "5311",	AR5K_VERSION_MAC,	AR5K_SREV_AR5311 },
-	{ "5311A",	AR5K_VERSION_MAC,	AR5K_SREV_AR5311A },
-	{ "5311B",	AR5K_VERSION_MAC,	AR5K_SREV_AR5311B },
-	{ "5211",	AR5K_VERSION_MAC,	AR5K_SREV_AR5211 },
-	{ "5212",	AR5K_VERSION_MAC,	AR5K_SREV_AR5212 },
-	{ "5213",	AR5K_VERSION_MAC,	AR5K_SREV_AR5213 },
-	{ "5213A",	AR5K_VERSION_MAC,	AR5K_SREV_AR5213A },
-	{ "2413",	AR5K_VERSION_MAC,	AR5K_SREV_AR2413 },
-	{ "2414",	AR5K_VERSION_MAC,	AR5K_SREV_AR2414 },
-	{ "5424",	AR5K_VERSION_MAC,	AR5K_SREV_AR5424 },
-	{ "5413",	AR5K_VERSION_MAC,	AR5K_SREV_AR5413 },
-	{ "5414",	AR5K_VERSION_MAC,	AR5K_SREV_AR5414 },
-	{ "2415",	AR5K_VERSION_MAC,	AR5K_SREV_AR2415 },
-	{ "5416",	AR5K_VERSION_MAC,	AR5K_SREV_AR5416 },
-	{ "5418",	AR5K_VERSION_MAC,	AR5K_SREV_AR5418 },
-	{ "2425",	AR5K_VERSION_MAC,	AR5K_SREV_AR2425 },
-	{ "2417",	AR5K_VERSION_MAC,	AR5K_SREV_AR2417 },
-	{ "xxxxx",	AR5K_VERSION_MAC,	AR5K_SREV_UNKNOWN },
-	{ "5110",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5110 },
-	{ "5111",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5111 },
-	{ "5111A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5111A },
-	{ "2111",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2111 },
-	{ "5112",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112 },
-	{ "5112A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112A },
-	{ "5112B",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112B },
-	{ "2112",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112 },
-	{ "2112A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112A },
-	{ "2112B",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112B },
-	{ "2413",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2413 },
-	{ "5413",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5413 },
-	{ "2316",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2316 },
-	{ "2317",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2317 },
-	{ "5424",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5424 },
-	{ "5133",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5133 },
-	{ "xxxxx",	AR5K_VERSION_RAD,	AR5K_SREV_UNKNOWN },
-};
-
-#define ATH5K_SPMBL_NO   1
-#define ATH5K_SPMBL_YES  2
-#define ATH5K_SPMBL_BOTH 3
-
-static const struct {
-	u16 bitrate;
-	u8 short_pmbl;
-	u8 hw_code;
-} ath5k_rates[] = {
-	{ 10, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_1M },
-	{ 20, ATH5K_SPMBL_NO, ATH5K_RATE_CODE_2M },
-	{ 55, ATH5K_SPMBL_NO, ATH5K_RATE_CODE_5_5M },
-	{ 110, ATH5K_SPMBL_NO, ATH5K_RATE_CODE_11M },
-	{ 60, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_6M },
-	{ 90, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_9M },
-	{ 120, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_12M },
-	{ 180, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_18M },
-	{ 240, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_24M },
-	{ 360, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_36M },
-	{ 480, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_48M },
-	{ 540, ATH5K_SPMBL_BOTH, ATH5K_RATE_CODE_54M },
-	{ 20, ATH5K_SPMBL_YES, ATH5K_RATE_CODE_2M | AR5K_SET_SHORT_PREAMBLE },
-	{ 55, ATH5K_SPMBL_YES, ATH5K_RATE_CODE_5_5M | AR5K_SET_SHORT_PREAMBLE },
-	{ 110, ATH5K_SPMBL_YES, ATH5K_RATE_CODE_11M | AR5K_SET_SHORT_PREAMBLE },
-	{ 0, 0, 0 },
-};
-
-#define ATH5K_NR_RATES 15
-
-/*
- * Prototypes - PCI stack related functions
- */
-static int 		ath5k_probe(struct pci_device *pdev);
-static void		ath5k_remove(struct pci_device *pdev);
-
-struct pci_driver ath5k_pci_driver __pci_driver = {
-	.ids		= ath5k_nics,
-	.id_count	= sizeof(ath5k_nics) / sizeof(ath5k_nics[0]),
-	.probe		= ath5k_probe,
-	.remove		= ath5k_remove,
-};
-
-
-
-/*
- * Prototypes - MAC 802.11 stack related functions
- */
-static int ath5k_tx(struct net80211_device *dev, struct io_buffer *skb);
-static int ath5k_reset(struct ath5k_softc *sc, struct net80211_channel *chan);
-static int ath5k_reset_wake(struct ath5k_softc *sc);
-static int ath5k_start(struct net80211_device *dev);
-static void ath5k_stop(struct net80211_device *dev);
-static int ath5k_config(struct net80211_device *dev, int changed);
-static void ath5k_poll(struct net80211_device *dev);
-static void ath5k_irq(struct net80211_device *dev, int enable);
-
-static struct net80211_device_operations ath5k_ops = {
-	.open		= ath5k_start,
-	.close		= ath5k_stop,
-	.transmit	= ath5k_tx,
-	.poll		= ath5k_poll,
-	.irq		= ath5k_irq,
-	.config		= ath5k_config,
-};
-
-/*
- * Prototypes - Internal functions
- */
-/* Attach detach */
-static int 	ath5k_attach(struct net80211_device *dev);
-static void 	ath5k_detach(struct net80211_device *dev);
-/* Channel/mode setup */
-static unsigned int ath5k_copy_channels(struct ath5k_hw *ah,
-				struct net80211_channel *channels,
-				unsigned int mode,
-				unsigned int max);
-static int 	ath5k_setup_bands(struct net80211_device *dev);
-static int 	ath5k_chan_set(struct ath5k_softc *sc,
-				struct net80211_channel *chan);
-static void	ath5k_setcurmode(struct ath5k_softc *sc,
-				unsigned int mode);
-static void	ath5k_mode_setup(struct ath5k_softc *sc);
-
-/* Descriptor setup */
-static int	ath5k_desc_alloc(struct ath5k_softc *sc);
-static void	ath5k_desc_free(struct ath5k_softc *sc);
-/* Buffers setup */
-static int 	ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf);
-static int 	ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf);
-
-static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
-				    struct ath5k_buf *bf)
-{
-	if (!bf->iob)
-		return;
-
-	net80211_tx_complete(sc->dev, bf->iob, 0, ECANCELED);
-	bf->iob = NULL;
-}
-
-static inline void ath5k_rxbuf_free(struct ath5k_softc *sc __unused,
-				    struct ath5k_buf *bf)
-{
-	free_iob(bf->iob);
-	bf->iob = NULL;
-}
-
-/* Queues setup */
-static int 	ath5k_txq_setup(struct ath5k_softc *sc,
-					   int qtype, int subtype);
-static void 	ath5k_txq_drainq(struct ath5k_softc *sc,
-				 struct ath5k_txq *txq);
-static void 	ath5k_txq_cleanup(struct ath5k_softc *sc);
-static void 	ath5k_txq_release(struct ath5k_softc *sc);
-/* Rx handling */
-static int 	ath5k_rx_start(struct ath5k_softc *sc);
-static void 	ath5k_rx_stop(struct ath5k_softc *sc);
-/* Tx handling */
-static void 	ath5k_tx_processq(struct ath5k_softc *sc,
-				  struct ath5k_txq *txq);
-
-/* Interrupt handling */
-static int 	ath5k_init(struct ath5k_softc *sc);
-static int 	ath5k_stop_hw(struct ath5k_softc *sc);
-
-static void 	ath5k_calibrate(struct ath5k_softc *sc);
-
-/* Filter */
-static void	ath5k_configure_filter(struct ath5k_softc *sc);
-
-/********************\
-* PCI Initialization *
-\********************/
-
-#if DBGLVL_MAX
-static const char *
-ath5k_chip_name(enum ath5k_srev_type type, u16 val)
-{
-	const char *name = "xxxxx";
-	unsigned int i;
-
-	for (i = 0; i < ARRAY_SIZE(srev_names); i++) {
-		if (srev_names[i].sr_type != type)
-			continue;
-
-		if ((val & 0xf0) == srev_names[i].sr_val)
-			name = srev_names[i].sr_name;
-
-		if ((val & 0xff) == srev_names[i].sr_val) {
-			name = srev_names[i].sr_name;
-			break;
-		}
-	}
-
-	return name;
-}
-#endif
-
-static int ath5k_probe(struct pci_device *pdev)
-{
-	void *mem;
-	struct ath5k_softc *sc;
-	struct net80211_device *dev;
-	int ret;
-	u8 csz;
-
-	adjust_pci_device(pdev);
-
-	/*
-	 * Cache line size is used to size and align various
-	 * structures used to communicate with the hardware.
-	 */
-	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
-	if (csz == 0) {
-		/*
-		 * We must have this setup properly for rx buffer
-		 * DMA to work so force a reasonable value here if it
-		 * comes up zero.
-		 */
-		csz = 16;
-		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
-	}
-	/*
-	 * The default setting of latency timer yields poor results,
-	 * set it to the value used by other systems.  It may be worth
-	 * tweaking this setting more.
-	 */
-	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
-
-	/*
-	 * Disable the RETRY_TIMEOUT register (0x41) to keep
-	 * PCI Tx retries from interfering with C3 CPU state.
-	 */
-	pci_write_config_byte(pdev, 0x41, 0);
-
-	mem = ioremap(pdev->membase, 0x10000);
-	if (!mem) {
-		DBG("ath5k: cannot remap PCI memory region\n");
-		ret = -EIO;
-		goto err;
-	}
-
-	/*
-	 * Allocate dev (net80211 main struct)
-	 * and dev->priv (driver private data)
-	 */
-	dev = net80211_alloc(sizeof(*sc));
-	if (!dev) {
-		DBG("ath5k: cannot allocate 802.11 device\n");
-		ret = -ENOMEM;
-		goto err_map;
-	}
-
-	/* Initialize driver private data */
-	sc = dev->priv;
-	sc->dev = dev;
-	sc->pdev = pdev;
-
-	sc->hwinfo = zalloc(sizeof(*sc->hwinfo));
-	if (!sc->hwinfo) {
-		DBG("ath5k: cannot allocate 802.11 hardware info structure\n");
-		ret = -ENOMEM;
-		goto err_free;
-	}
-
-	sc->hwinfo->flags = NET80211_HW_RX_HAS_FCS;
-	sc->hwinfo->signal_type = NET80211_SIGNAL_DB;
-	sc->hwinfo->signal_max = 40; /* 35dB should give perfect 54Mbps */
-	sc->hwinfo->channel_change_time = 5000;
-
-	/* Avoid working with the device until setup is complete */
-	sc->status |= ATH_STAT_INVALID;
-
-	sc->iobase = mem;
-	sc->cachelsz = csz * 4; /* convert to bytes */
-
-	DBG("ath5k: register base at %p (%08lx)\n", sc->iobase, pdev->membase);
-	DBG("ath5k: cache line size %d\n", sc->cachelsz);
-
-	/* Set private data */
-	pci_set_drvdata(pdev, dev);
-	dev->netdev->dev = (struct device *)pdev;
-
-	/* Initialize device */
-	ret = ath5k_hw_attach(sc, pdev->id->driver_data, &sc->ah);
-	if (ret)
-		goto err_free_hwinfo;
-
-	/* Finish private driver data initialization */
-	ret = ath5k_attach(dev);
-	if (ret)
-		goto err_ah;
-
-#if DBGLVL_MAX
-	DBG("Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
-	    ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev),
-	    sc->ah->ah_mac_srev, sc->ah->ah_phy_revision);
-
-	if (!sc->ah->ah_single_chip) {
-		/* Single chip radio (!RF5111) */
-		if (sc->ah->ah_radio_5ghz_revision &&
-		    !sc->ah->ah_radio_2ghz_revision) {
-			/* No 5GHz support -> report 2GHz radio */
-			if (!(sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11A)) {
-				DBG("RF%s 2GHz radio found (0x%x)\n",
-				    ath5k_chip_name(AR5K_VERSION_RAD,
-						    sc->ah->ah_radio_5ghz_revision),
-				    sc->ah->ah_radio_5ghz_revision);
-			/* No 2GHz support (5110 and some
-			 * 5Ghz only cards) -> report 5Ghz radio */
-			} else if (!(sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11B)) {
-				DBG("RF%s 5GHz radio found (0x%x)\n",
-				    ath5k_chip_name(AR5K_VERSION_RAD,
-						    sc->ah->ah_radio_5ghz_revision),
-				    sc->ah->ah_radio_5ghz_revision);
-			/* Multiband radio */
-			} else {
-				DBG("RF%s multiband radio found (0x%x)\n",
-				    ath5k_chip_name(AR5K_VERSION_RAD,
-						    sc->ah->ah_radio_5ghz_revision),
-				    sc->ah->ah_radio_5ghz_revision);
-			}
-		}
-		/* Multi chip radio (RF5111 - RF2111) ->
-		 * report both 2GHz/5GHz radios */
-		else if (sc->ah->ah_radio_5ghz_revision &&
-			 sc->ah->ah_radio_2ghz_revision) {
-			DBG("RF%s 5GHz radio found (0x%x)\n",
-			    ath5k_chip_name(AR5K_VERSION_RAD,
-					    sc->ah->ah_radio_5ghz_revision),
-			    sc->ah->ah_radio_5ghz_revision);
-			DBG("RF%s 2GHz radio found (0x%x)\n",
-			    ath5k_chip_name(AR5K_VERSION_RAD,
-					    sc->ah->ah_radio_2ghz_revision),
-			    sc->ah->ah_radio_2ghz_revision);
-		}
-	}
-#endif
-
-	/* Ready to go */
-	sc->status &= ~ATH_STAT_INVALID;
-
-	return 0;
-err_ah:
-	ath5k_hw_detach(sc->ah);
-err_free_hwinfo:
-	free(sc->hwinfo);
-err_free:
-	net80211_free(dev);
-err_map:
-	iounmap(mem);
-err:
-	return ret;
-}
-
-static void ath5k_remove(struct pci_device *pdev)
-{
-	struct net80211_device *dev = pci_get_drvdata(pdev);
-	struct ath5k_softc *sc = dev->priv;
-
-	ath5k_detach(dev);
-	ath5k_hw_detach(sc->ah);
-	iounmap(sc->iobase);
-	free(sc->hwinfo);
-	net80211_free(dev);
-}
-
-
-/***********************\
-* Driver Initialization *
-\***********************/
-
-static int
-ath5k_attach(struct net80211_device *dev)
-{
-	struct ath5k_softc *sc = dev->priv;
-	struct ath5k_hw *ah = sc->ah;
-	int ret;
-
-	/*
-	 * Collect the channel list.  The 802.11 layer
-	 * is resposible for filtering this list based
-	 * on settings like the phy mode and regulatory
-	 * domain restrictions.
-	 */
-	ret = ath5k_setup_bands(dev);
-	if (ret) {
-		DBG("ath5k: can't get channels\n");
-		goto err;
-	}
-
-	/* NB: setup here so ath5k_rate_update is happy */
-	if (ah->ah_modes & AR5K_MODE_BIT_11A)
-		ath5k_setcurmode(sc, AR5K_MODE_11A);
-	else
-		ath5k_setcurmode(sc, AR5K_MODE_11B);
-
-	/*
-	 * Allocate tx+rx descriptors and populate the lists.
-	 */
-	ret = ath5k_desc_alloc(sc);
-	if (ret) {
-		DBG("ath5k: can't allocate descriptors\n");
-		goto err;
-	}
-
-	/*
-	 * Allocate hardware transmit queues. Note that hw functions
-	 * handle reseting these queues at the needed time.
-	 */
-	ret = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BE);
-	if (ret) {
-		DBG("ath5k: can't setup xmit queue\n");
-		goto err_desc;
-	}
-
-	sc->last_calib_ticks = currticks();
-
-	ret = ath5k_eeprom_read_mac(ah, sc->hwinfo->hwaddr);
-	if (ret) {
-		DBG("ath5k: unable to read address from EEPROM: 0x%04x\n",
-		    sc->pdev->device);
-		goto err_queues;
-	}
-
-	memset(sc->bssidmask, 0xff, ETH_ALEN);
-	ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
-
-	ret = net80211_register(sc->dev, &ath5k_ops, sc->hwinfo);
-	if (ret) {
-		DBG("ath5k: can't register ieee80211 hw\n");
-		goto err_queues;
-	}
-
-	return 0;
-err_queues:
-	ath5k_txq_release(sc);
-err_desc:
-	ath5k_desc_free(sc);
-err:
-	return ret;
-}
-
-static void
-ath5k_detach(struct net80211_device *dev)
-{
-	struct ath5k_softc *sc = dev->priv;
-
-	net80211_unregister(dev);
-	ath5k_desc_free(sc);
-	ath5k_txq_release(sc);
-}
-
-
-
-
-/********************\
-* Channel/mode setup *
-\********************/
-
-/*
- * Convert IEEE channel number to MHz frequency.
- */
-static inline short
-ath5k_ieee2mhz(short chan)
-{
-	if (chan < 14)
-		return 2407 + 5 * chan;
-	if (chan == 14)
-		return 2484;
-	if (chan < 27)
-		return 2212 + 20 * chan;
-	return 5000 + 5 * chan;
-}
-
-static unsigned int
-ath5k_copy_channels(struct ath5k_hw *ah,
-		    struct net80211_channel *channels,
-		    unsigned int mode, unsigned int max)
-{
-	unsigned int i, count, size, chfreq, freq, ch;
-
-	if (!(ah->ah_modes & (1 << mode)))
-		return 0;
-
-	switch (mode) {
-	case AR5K_MODE_11A:
-	case AR5K_MODE_11A_TURBO:
-		/* 1..220, but 2GHz frequencies are filtered by check_channel */
-		size = 220;
-		chfreq = CHANNEL_5GHZ;
-		break;
-	case AR5K_MODE_11B:
-	case AR5K_MODE_11G:
-	case AR5K_MODE_11G_TURBO:
-		size = 26;
-		chfreq = CHANNEL_2GHZ;
-		break;
-	default:
-		return 0;
-	}
-
-	for (i = 0, count = 0; i < size && max > 0; i++) {
-		ch = i + 1 ;
-		freq = ath5k_ieee2mhz(ch);
-
-		/* Check if channel is supported by the chipset */
-		if (!ath5k_channel_ok(ah, freq, chfreq))
-			continue;
-
-		/* Write channel info and increment counter */
-		channels[count].center_freq = freq;
-		channels[count].maxpower = 0; /* use regulatory */
-		channels[count].band = (chfreq == CHANNEL_2GHZ) ?
-			NET80211_BAND_2GHZ : NET80211_BAND_5GHZ;
-		switch (mode) {
-		case AR5K_MODE_11A:
-		case AR5K_MODE_11G:
-			channels[count].hw_value = chfreq | CHANNEL_OFDM;
-			break;
-		case AR5K_MODE_11A_TURBO:
-		case AR5K_MODE_11G_TURBO:
-			channels[count].hw_value = chfreq |
-				CHANNEL_OFDM | CHANNEL_TURBO;
-			break;
-		case AR5K_MODE_11B:
-			channels[count].hw_value = CHANNEL_B;
-		}
-
-		count++;
-		max--;
-	}
-
-	return count;
-}
-
-static int
-ath5k_setup_bands(struct net80211_device *dev)
-{
-	struct ath5k_softc *sc = dev->priv;
-	struct ath5k_hw *ah = sc->ah;
-	int max_c, count_c = 0;
-	int i;
-	int band;
-
-	max_c = sizeof(sc->hwinfo->channels) / sizeof(sc->hwinfo->channels[0]);
-
-	/* 2GHz band */
-	if (sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11G) {
-		/* G mode */
-		band = NET80211_BAND_2GHZ;
-		sc->hwinfo->bands = NET80211_BAND_BIT_2GHZ;
-		sc->hwinfo->modes = (NET80211_MODE_G | NET80211_MODE_B);
-
-		for (i = 0; i < 12; i++)
-			sc->hwinfo->rates[band][i] = ath5k_rates[i].bitrate;
-		sc->hwinfo->nr_rates[band] = 12;
-
-		sc->hwinfo->nr_channels =
-			ath5k_copy_channels(ah, sc->hwinfo->channels,
-					    AR5K_MODE_11G, max_c);
-		count_c = sc->hwinfo->nr_channels;
-		max_c -= count_c;
-	} else if (sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11B) {
-		/* B mode */
-		band = NET80211_BAND_2GHZ;
-		sc->hwinfo->bands = NET80211_BAND_BIT_2GHZ;
-		sc->hwinfo->modes = NET80211_MODE_B;
-
-		for (i = 0; i < 4; i++)
-			sc->hwinfo->rates[band][i] = ath5k_rates[i].bitrate;
-		sc->hwinfo->nr_rates[band] = 4;
-
-		sc->hwinfo->nr_channels =
-			ath5k_copy_channels(ah, sc->hwinfo->channels,
-					    AR5K_MODE_11B, max_c);
-		count_c = sc->hwinfo->nr_channels;
-		max_c -= count_c;
-	}
-
-	/* 5GHz band, A mode */
-	if (sc->ah->ah_capabilities.cap_mode & AR5K_MODE_BIT_11A) {
-		band = NET80211_BAND_5GHZ;
-		sc->hwinfo->bands |= NET80211_BAND_BIT_5GHZ;
-		sc->hwinfo->modes |= NET80211_MODE_A;
-
-		for (i = 0; i < 8; i++)
-			sc->hwinfo->rates[band][i] = ath5k_rates[i+4].bitrate;
-		sc->hwinfo->nr_rates[band] = 8;
-
-		sc->hwinfo->nr_channels =
-			ath5k_copy_channels(ah, sc->hwinfo->channels,
-					    AR5K_MODE_11B, max_c);
-		count_c = sc->hwinfo->nr_channels;
-		max_c -= count_c;
-	}
-
-	return 0;
-}
-
-/*
- * Set/change channels.  If the channel is really being changed,
- * it's done by reseting the chip.  To accomplish this we must
- * first cleanup any pending DMA, then restart stuff after a la
- * ath5k_init.
- */
-static int
-ath5k_chan_set(struct ath5k_softc *sc, struct net80211_channel *chan)
-{
-	if (chan->center_freq != sc->curchan->center_freq ||
-	    chan->hw_value != sc->curchan->hw_value) {
-		/*
-		 * To switch channels clear any pending DMA operations;
-		 * wait long enough for the RX fifo to drain, reset the
-		 * hardware at the new frequency, and then re-enable
-		 * the relevant bits of the h/w.
-		 */
-		DBG2("ath5k: resetting for channel change (%d -> %d MHz)\n",
-		     sc->curchan->center_freq, chan->center_freq);
-		return ath5k_reset(sc, chan);
-	}
-
-	return 0;
-}
-
-static void
-ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
-{
-	sc->curmode = mode;
-
-	if (mode == AR5K_MODE_11A) {
-		sc->curband = NET80211_BAND_5GHZ;
-	} else {
-		sc->curband = NET80211_BAND_2GHZ;
-	}
-}
-
-static void
-ath5k_mode_setup(struct ath5k_softc *sc)
-{
-	struct ath5k_hw *ah = sc->ah;
-	u32 rfilt;
-
-	/* configure rx filter */
-	rfilt = sc->filter_flags;
-	ath5k_hw_set_rx_filter(ah, rfilt);
-
-	if (ath5k_hw_hasbssidmask(ah))
-		ath5k_hw_set_bssid_mask(ah, sc->bssidmask);
-
-	/* configure operational mode */
-	ath5k_hw_set_opmode(ah);
-
-	ath5k_hw_set_mcast_filter(ah, 0, 0);
-}
-
-static inline int
-ath5k_hw_rix_to_bitrate(int hw_rix)
-{
-	int i;
-
-	for (i = 0; i < ATH5K_NR_RATES; i++) {
-		if (ath5k_rates[i].hw_code == hw_rix)
-			return ath5k_rates[i].bitrate;
-	}
-
-	DBG("ath5k: invalid rix %02x\n", hw_rix);
-	return 10;		/* use lowest rate */
-}
-
-int ath5k_bitrate_to_hw_rix(int bitrate)
-{
-	int i;
-
-	for (i = 0; i < ATH5K_NR_RATES; i++) {
-		if (ath5k_rates[i].bitrate == bitrate)
-			return ath5k_rates[i].hw_code;
-	}
-
-	DBG("ath5k: invalid bitrate %d\n", bitrate);
-	return ATH5K_RATE_CODE_1M; /* use lowest rate */
-}
-
-/***************\
-* Buffers setup *
-\***************/
-
-static struct io_buffer *
-ath5k_rx_iob_alloc(struct ath5k_softc *sc, u32 *iob_addr)
-{
-	struct io_buffer *iob;
-	unsigned int off;
-
-	/*
-	 * Allocate buffer with headroom_needed space for the
-	 * fake physical layer header at the start.
-	 */
-	iob = alloc_iob(sc->rxbufsize + sc->cachelsz - 1);
-
-	if (!iob) {
-		DBG("ath5k: can't alloc iobuf of size %d\n",
-		    sc->rxbufsize + sc->cachelsz - 1);
-		return NULL;
-	}
-
-	*iob_addr = virt_to_bus(iob->data);
-
-	/*
-	 * Cache-line-align.  This is important (for the
-	 * 5210 at least) as not doing so causes bogus data
-	 * in rx'd frames.
-	 */
-	off = *iob_addr % sc->cachelsz;
-	if (off != 0) {
-		iob_reserve(iob, sc->cachelsz - off);
-		*iob_addr += sc->cachelsz - off;
-	}
-
-	return iob;
-}
-
-static int
-ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
-{
-	struct ath5k_hw *ah = sc->ah;
-	struct io_buffer *iob = bf->iob;
-	struct ath5k_desc *ds;
-
-	if (!iob) {
-		iob = ath5k_rx_iob_alloc(sc, &bf->iobaddr);
-		if (!iob)
-			return -ENOMEM;
-		bf->iob = iob;
-	}
-
-	/*
-	 * Setup descriptors.  For receive we always terminate
-	 * the descriptor list with a self-linked entry so we'll
-	 * not get overrun under high load (as can happen with a
-	 * 5212 when ANI processing enables PHY error frames).
-	 *
-	 * To insure the last descriptor is self-linked we create
-	 * each descriptor as self-linked and add it to the end.  As
-	 * each additional descriptor is added the previous self-linked
-	 * entry is ``fixed'' naturally.  This should be safe even
-	 * if DMA is happening.  When processing RX interrupts we
-	 * never remove/process the last, self-linked, entry on the
-	 * descriptor list.  This insures the hardware always has
-	 * someplace to write a new frame.
-	 */
-	ds = bf->desc;
-	ds->ds_link = bf->daddr;	/* link to self */
-	ds->ds_data = bf->iobaddr;
-	if (ah->ah_setup_rx_desc(ah, ds,
-				 iob_tailroom(iob),	/* buffer size */
-				 0) != 0) {
-		DBG("ath5k: error setting up RX descriptor for %zd bytes\n", iob_tailroom(iob));
-		return -EINVAL;
-	}
-
-	if (sc->rxlink != NULL)
-		*sc->rxlink = bf->daddr;
-	sc->rxlink = &ds->ds_link;
-	return 0;
-}
-
-static int
-ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
-{
-	struct ath5k_hw *ah = sc->ah;
-	struct ath5k_txq *txq = &sc->txq;
-	struct ath5k_desc *ds = bf->desc;
-	struct io_buffer *iob = bf->iob;
-	unsigned int pktlen, flags;
-	int ret;
-	u16 duration = 0;
-	u16 cts_rate = 0;
-
-	flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
-	bf->iobaddr = virt_to_bus(iob->data);
-	pktlen = iob_len(iob);
-
-	/* FIXME: If we are in g mode and rate is a CCK rate
-	 * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta
-	 * from tx power (value is in dB units already) */
-	if (sc->dev->phy_flags & NET80211_PHY_USE_PROTECTION) {
-		struct net80211_device *dev = sc->dev;
-
-		flags |= AR5K_TXDESC_CTSENA;
-		cts_rate = sc->hw_rtscts_rate;
-		duration = net80211_cts_duration(dev, pktlen);
-	}
-	ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
-				   IEEE80211_TYP_FRAME_HEADER_LEN,
-				   AR5K_PKT_TYPE_NORMAL, sc->power_level * 2,
-				   sc->hw_rate, ATH5K_RETRIES,
-				   AR5K_TXKEYIX_INVALID, 0, flags,
-				   cts_rate, duration);
-	if (ret)
-		return ret;
-
-	ds->ds_link = 0;
-	ds->ds_data = bf->iobaddr;
-
-	list_add_tail(&bf->list, &txq->q);
-	if (txq->link == NULL) /* is this first packet? */
-		ath5k_hw_set_txdp(ah, txq->qnum, bf->daddr);
-	else /* no, so only link it */
-		*txq->link = bf->daddr;
-
-	txq->link = &ds->ds_link;
-	ath5k_hw_start_tx_dma(ah, txq->qnum);
-	mb();
-
-	return 0;
-}
-
-/*******************\
-* Descriptors setup *
-\*******************/
-
-static int
-ath5k_desc_alloc(struct ath5k_softc *sc)
-{
-	struct ath5k_desc *ds;
-	struct ath5k_buf *bf;
-	u32 da;
-	unsigned int i;
-	int ret;
-
-	/* allocate descriptors */
-	sc->desc_len = sizeof(struct ath5k_desc) * (ATH_TXBUF + ATH_RXBUF + 1);
-	sc->desc = malloc_dma(sc->desc_len, ATH5K_DESC_ALIGN);
-	if (sc->desc == NULL) {
-		DBG("ath5k: can't allocate descriptors\n");
-		ret = -ENOMEM;
-		goto err;
-	}
-	memset(sc->desc, 0, sc->desc_len);
-	sc->desc_daddr = virt_to_bus(sc->desc);
-
-	ds = sc->desc;
-	da = sc->desc_daddr;
-
-	bf = calloc(ATH_TXBUF + ATH_RXBUF + 1, sizeof(struct ath5k_buf));
-	if (bf == NULL) {
-		DBG("ath5k: can't allocate buffer pointers\n");
-		ret = -ENOMEM;
-		goto err_free;
-	}
-	sc->bufptr = bf;
-
-	INIT_LIST_HEAD(&sc->rxbuf);
-	for (i = 0; i < ATH_RXBUF; i++, bf++, ds++, da += sizeof(*ds)) {
-		bf->desc = ds;
-		bf->daddr = da;
-		list_add_tail(&bf->list, &sc->rxbuf);
-	}
-
-	INIT_LIST_HEAD(&sc->txbuf);
-	sc->txbuf_len = ATH_TXBUF;
-	for (i = 0; i < ATH_TXBUF; i++, bf++, ds++, da += sizeof(*ds)) {
-		bf->desc = ds;
-		bf->daddr = da;
-		list_add_tail(&bf->list, &sc->txbuf);
-	}
-
-	return 0;
-
-err_free:
-	free_dma(sc->desc, sc->desc_len);
-err:
-	sc->desc = NULL;
-	return ret;
-}
-
-static void
-ath5k_desc_free(struct ath5k_softc *sc)
-{
-	struct ath5k_buf *bf;
-
-	list_for_each_entry(bf, &sc->txbuf, list)
-		ath5k_txbuf_free(sc, bf);
-	list_for_each_entry(bf, &sc->rxbuf, list)
-		ath5k_rxbuf_free(sc, bf);
-
-	/* Free memory associated with all descriptors */
-	free_dma(sc->desc, sc->desc_len);
-
-	free(sc->bufptr);
-	sc->bufptr = NULL;
-}
-
-
-
-
-
-/**************\
-* Queues setup *
-\**************/
-
-static int
-ath5k_txq_setup(struct ath5k_softc *sc, int qtype, int subtype)
-{
-	struct ath5k_hw *ah = sc->ah;
-	struct ath5k_txq *txq;
-	struct ath5k_txq_info qi = {
-		.tqi_subtype = subtype,
-		.tqi_aifs = AR5K_TXQ_USEDEFAULT,
-		.tqi_cw_min = AR5K_TXQ_USEDEFAULT,
-		.tqi_cw_max = AR5K_TXQ_USEDEFAULT
-	};
-	int qnum;
-
-	/*
-	 * Enable interrupts only for EOL and DESC conditions.
-	 * We mark tx descriptors to receive a DESC interrupt
-	 * when a tx queue gets deep; otherwise waiting for the
-	 * EOL to reap descriptors.  Note that this is done to
-	 * reduce interrupt load and this only defers reaping
-	 * descriptors, never transmitting frames.  Aside from
-	 * reducing interrupts this also permits more concurrency.
-	 * The only potential downside is if the tx queue backs
-	 * up in which case the top half of the kernel may backup
-	 * due to a lack of tx descriptors.
-	 */
-	qi.tqi_flags = AR5K_TXQ_FLAG_TXEOLINT_ENABLE |
-				AR5K_TXQ_FLAG_TXDESCINT_ENABLE;
-	qnum = ath5k_hw_setup_tx_queue(ah, qtype, &qi);
-	if (qnum < 0) {
-		DBG("ath5k: can't set up a TX queue\n");
-		return -EIO;
-	}
-
-	txq = &sc->txq;
-	if (!txq->setup) {
-		txq->qnum = qnum;
-		txq->link = NULL;
-		INIT_LIST_HEAD(&txq->q);
-		txq->setup = 1;
-	}
-	return 0;
-}
-
-static void
-ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
-{
-	struct ath5k_buf *bf, *bf0;
-
-	list_for_each_entry_safe(bf, bf0, &txq->q, list) {
-		ath5k_txbuf_free(sc, bf);
-
-		list_del(&bf->list);
-		list_add_tail(&bf->list, &sc->txbuf);
-		sc->txbuf_len++;
-	}
-	txq->link = NULL;
-}
-
-/*
- * Drain the transmit queues and reclaim resources.
- */
-static void
-ath5k_txq_cleanup(struct ath5k_softc *sc)
-{
-	struct ath5k_hw *ah = sc->ah;
-
-	if (!(sc->status & ATH_STAT_INVALID)) {
-		/* don't touch the hardware if marked invalid */
-		if (sc->txq.setup) {
-			ath5k_hw_stop_tx_dma(ah, sc->txq.qnum);
-			DBG("ath5k: txq [%d] %x, link %p\n",
-			    sc->txq.qnum,
-			    ath5k_hw_get_txdp(ah, sc->txq.qnum),
-			    sc->txq.link);
-		}
-	}
-
-	if (sc->txq.setup)
-		ath5k_txq_drainq(sc, &sc->txq);
-}
-
-static void
-ath5k_txq_release(struct ath5k_softc *sc)
-{
-	if (sc->txq.setup) {
-		ath5k_hw_release_tx_queue(sc->ah);
-		sc->txq.setup = 0;
-	}
-}
-
-
-
-
-/*************\
-* RX Handling *
-\*************/
-
-/*
- * Enable the receive h/w following a reset.
- */
-static int
-ath5k_rx_start(struct ath5k_softc *sc)
-{
-	struct ath5k_hw *ah = sc->ah;
-	struct ath5k_buf *bf;
-	int ret;
-
-	sc->rxbufsize = IEEE80211_MAX_LEN;
-	if (sc->rxbufsize % sc->cachelsz != 0)
-		sc->rxbufsize += sc->cachelsz - (sc->rxbufsize % sc->cachelsz);
-
-	sc->rxlink = NULL;
-
-	list_for_each_entry(bf, &sc->rxbuf, list) {
-		ret = ath5k_rxbuf_setup(sc, bf);
-		if (ret != 0)
-			return ret;
-	}
-
-	bf = list_entry(sc->rxbuf.next, struct ath5k_buf, list);
-
-	ath5k_hw_set_rxdp(ah, bf->daddr);
-	ath5k_hw_start_rx_dma(ah);	/* enable recv descriptors */
-	ath5k_mode_setup(sc);		/* set filters, etc. */
-	ath5k_hw_start_rx_pcu(ah);	/* re-enable PCU/DMA engine */
-
-	return 0;
-}
-
-/*
- * Disable the receive h/w in preparation for a reset.
- */
-static void
-ath5k_rx_stop(struct ath5k_softc *sc)
-{
-	struct ath5k_hw *ah = sc->ah;
-
-	ath5k_hw_stop_rx_pcu(ah);	/* disable PCU */
-	ath5k_hw_set_rx_filter(ah, 0);	/* clear recv filter */
-	ath5k_hw_stop_rx_dma(ah);	/* disable DMA engine */
-
-	sc->rxlink = NULL;		/* just in case */
-}
-
-static void
-ath5k_handle_rx(struct ath5k_softc *sc)
-{
-	struct ath5k_rx_status rs;
-	struct io_buffer *iob, *next_iob;
-	u32 next_iob_addr;
-	struct ath5k_buf *bf, *bf_last;
-	struct ath5k_desc *ds;
-	int ret;
-
-	memset(&rs, 0, sizeof(rs));
-
-	if (list_empty(&sc->rxbuf)) {
-		DBG("ath5k: empty rx buf pool\n");
-		return;
-	}
-
-	bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list);
-
-	do {
-		bf = list_entry(sc->rxbuf.next, struct ath5k_buf, list);
-		assert(bf->iob != NULL);
-		iob = bf->iob;
-		ds = bf->desc;
-
-		/*
-		 * last buffer must not be freed to ensure proper hardware
-		 * function. When the hardware finishes also a packet next to
-		 * it, we are sure, it doesn't use it anymore and we can go on.
-		 */
-		if (bf_last == bf)
-			bf->flags |= 1;
-		if (bf->flags) {
-			struct ath5k_buf *bf_next = list_entry(bf->list.next,
-					struct ath5k_buf, list);
-			ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc,
-					&rs);
-			if (ret)
-				break;
-			bf->flags &= ~1;
-			/* skip the overwritten one (even status is martian) */
-			goto next;
-		}
-
-		ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs);
-		if (ret) {
-			if (ret != -EINPROGRESS) {
-				DBG("ath5k: error in processing rx desc: %s\n",
-				    strerror(ret));
-				net80211_rx_err(sc->dev, NULL, -ret);
-			} else {
-				/* normal return, reached end of
-				   available descriptors */
-			}
-			return;
-		}
-
-		if (rs.rs_more) {
-			DBG("ath5k: unsupported fragmented rx\n");
-			goto next;
-		}
-
-		if (rs.rs_status) {
-			if (rs.rs_status & AR5K_RXERR_PHY) {
-				/* These are uncommon, and may indicate a real problem. */
-				net80211_rx_err(sc->dev, NULL, EIO);
-				goto next;
-			}
-			if (rs.rs_status & AR5K_RXERR_CRC) {
-				/* These occur *all the time*. */
-				goto next;
-			}
-			if (rs.rs_status & AR5K_RXERR_DECRYPT) {
-				/*
-				 * Decrypt error.  If the error occurred
-				 * because there was no hardware key, then
-				 * let the frame through so the upper layers
-				 * can process it.  This is necessary for 5210
-				 * parts which have no way to setup a ``clear''
-				 * key cache entry.
-				 *
-				 * XXX do key cache faulting
-				 */
-				if (rs.rs_keyix == AR5K_RXKEYIX_INVALID &&
-				    !(rs.rs_status & AR5K_RXERR_CRC))
-					goto accept;
-			}
-
-			/* any other error, unhandled */
-			DBG("ath5k: packet rx status %x\n", rs.rs_status);
-			goto next;
-		}
-accept:
-		next_iob = ath5k_rx_iob_alloc(sc, &next_iob_addr);
-
-		/*
-		 * If we can't replace bf->iob with a new iob under memory
-		 * pressure, just skip this packet
-		 */
-		if (!next_iob) {
-			DBG("ath5k: dropping packet under memory pressure\n");
-			goto next;
-		}
-
-		iob_put(iob, rs.rs_datalen);
-
-		/* The MAC header is padded to have 32-bit boundary if the
-		 * packet payload is non-zero. However, iPXE only
-		 * supports standard 802.11 packets with 24-byte
-		 * header, so no padding correction should be needed.
-		 */
-
-		DBG2("ath5k: rx %d bytes, signal %d\n", rs.rs_datalen,
-		     rs.rs_rssi);
-
-		net80211_rx(sc->dev, iob, rs.rs_rssi,
-			    ath5k_hw_rix_to_bitrate(rs.rs_rate));
-
-		bf->iob = next_iob;
-		bf->iobaddr = next_iob_addr;
-next:
-		list_del(&bf->list);
-		list_add_tail(&bf->list, &sc->rxbuf);
-	} while (ath5k_rxbuf_setup(sc, bf) == 0);
-}
-
-
-
-
-/*************\
-* TX Handling *
-\*************/
-
-static void
-ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
-{
-	struct ath5k_tx_status ts;
-	struct ath5k_buf *bf, *bf0;
-	struct ath5k_desc *ds;
-	struct io_buffer *iob;
-	int ret;
-
-	memset(&ts, 0, sizeof(ts));
-
-	list_for_each_entry_safe(bf, bf0, &txq->q, list) {
-		ds = bf->desc;
-
-		ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts);
-		if (ret) {
-			if (ret != -EINPROGRESS) {
-				DBG("ath5k: error in processing tx desc: %s\n",
-				    strerror(ret));
-			} else {
-				/* normal return, reached end of tx completions */
-			}
-			break;
-		}
-
-		iob = bf->iob;
-		bf->iob = NULL;
-
-		DBG2("ath5k: tx %zd bytes complete, %d retries\n",
-		     iob_len(iob), ts.ts_retry[0]);
-
-		net80211_tx_complete(sc->dev, iob, ts.ts_retry[0],
-				     ts.ts_status ? EIO : 0);
-
-		list_del(&bf->list);
-		list_add_tail(&bf->list, &sc->txbuf);
-		sc->txbuf_len++;
-	}
-
-	if (list_empty(&txq->q))
-		txq->link = NULL;
-}
-
-static void
-ath5k_handle_tx(struct ath5k_softc *sc)
-{
-	ath5k_tx_processq(sc, &sc->txq);
-}
-
-
-/********************\
-* Interrupt handling *
-\********************/
-
-static void
-ath5k_irq(struct net80211_device *dev, int enable)
-{
-	struct ath5k_softc *sc = dev->priv;
-	struct ath5k_hw *ah = sc->ah;
-
-	sc->irq_ena = enable;
-	ah->ah_ier = enable ? AR5K_IER_ENABLE : AR5K_IER_DISABLE;
-
-	ath5k_hw_reg_write(ah, ah->ah_ier, AR5K_IER);
-	ath5k_hw_set_imr(ah, sc->imask);
-}
-
-static int
-ath5k_init(struct ath5k_softc *sc)
-{
-	struct ath5k_hw *ah = sc->ah;
-	int ret, i;
-
-	/*
-	 * Stop anything previously setup.  This is safe
-	 * no matter this is the first time through or not.
-	 */
-	ath5k_stop_hw(sc);
-
-	/*
-	 * The basic interface to setting the hardware in a good
-	 * state is ``reset''.  On return the hardware is known to
-	 * be powered up and with interrupts disabled.  This must
-	 * be followed by initialization of the appropriate bits
-	 * and then setup of the interrupt mask.
-	 */
-	sc->curchan = sc->dev->channels + sc->dev->channel;
-	sc->curband = sc->curchan->band;
-	sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
-		AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
-		AR5K_INT_FATAL | AR5K_INT_GLOBAL;
-	ret = ath5k_reset(sc, NULL);
-	if (ret)
-		goto done;
-
-	ath5k_rfkill_hw_start(ah);
-
-	/*
-	 * Reset the key cache since some parts do not reset the
-	 * contents on initial power up or resume from suspend.
-	 */
-	for (i = 0; i < AR5K_KEYTABLE_SIZE; i++)
-		ath5k_hw_reset_key(ah, i);
-
-	/* Set ack to be sent at low bit-rates */
-	ath5k_hw_set_ack_bitrate_high(ah, 0);
-
-	ret = 0;
-done:
-	mb();
-	return ret;
-}
-
-static int
-ath5k_stop_hw(struct ath5k_softc *sc)
-{
-	struct ath5k_hw *ah = sc->ah;
-
-	/*
-	 * Shutdown the hardware and driver:
-	 *    stop output from above
-	 *    disable interrupts
-	 *    turn off timers
-	 *    turn off the radio
-	 *    clear transmit machinery
-	 *    clear receive machinery
-	 *    drain and release tx queues
-	 *    reclaim beacon resources
-	 *    power down hardware
-	 *
-	 * Note that some of this work is not possible if the
-	 * hardware is gone (invalid).
-	 */
-
-	if (!(sc->status & ATH_STAT_INVALID)) {
-		ath5k_hw_set_imr(ah, 0);
-	}
-	ath5k_txq_cleanup(sc);
-	if (!(sc->status & ATH_STAT_INVALID)) {
-		ath5k_rx_stop(sc);
-		ath5k_hw_phy_disable(ah);
-	} else
-		sc->rxlink = NULL;
-
-	ath5k_rfkill_hw_stop(sc->ah);
-
-	return 0;
-}
-
-static void
-ath5k_poll(struct net80211_device *dev)
-{
-	struct ath5k_softc *sc = dev->priv;
-	struct ath5k_hw *ah = sc->ah;
-	enum ath5k_int status;
-	unsigned int counter = 1000;
-
-	if (currticks() - sc->last_calib_ticks >
-	    ATH5K_CALIB_INTERVAL * ticks_per_sec()) {
-		ath5k_calibrate(sc);
-		sc->last_calib_ticks = currticks();
-	}
-
-	if ((sc->status & ATH_STAT_INVALID) ||
-	    (sc->irq_ena && !ath5k_hw_is_intr_pending(ah)))
-		return;
-
-	do {
-		ath5k_hw_get_isr(ah, &status);		/* NB: clears IRQ too */
-		DBGP("ath5k: status %#x/%#x\n", status, sc->imask);
-		if (status & AR5K_INT_FATAL) {
-			/*
-			 * Fatal errors are unrecoverable.
-			 * Typically these are caused by DMA errors.
-			 */
-			DBG("ath5k: fatal error, resetting\n");
-			ath5k_reset_wake(sc);
-		} else if (status & AR5K_INT_RXORN) {
-			DBG("ath5k: rx overrun, resetting\n");
-			ath5k_reset_wake(sc);
-		} else {
-			if (status & AR5K_INT_RXEOL) {
-				/*
-				 * NB: the hardware should re-read the link when
-				 *     RXE bit is written, but it doesn't work at
-				 *     least on older hardware revs.
-				 */
-				DBG("ath5k: rx EOL\n");
-				sc->rxlink = NULL;
-			}
-			if (status & AR5K_INT_TXURN) {
-				/* bump tx trigger level */
-				DBG("ath5k: tx underrun\n");
-				ath5k_hw_update_tx_triglevel(ah, 1);
-			}
-			if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
-				ath5k_handle_rx(sc);
-			if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
-				      | AR5K_INT_TXERR | AR5K_INT_TXEOL))
-				ath5k_handle_tx(sc);
-		}
-	} while (ath5k_hw_is_intr_pending(ah) && counter-- > 0);
-
-	if (!counter)
-		DBG("ath5k: too many interrupts, giving up for now\n");
-}
-
-/*
- * Periodically recalibrate the PHY to account
- * for temperature/environment changes.
- */
-static void
-ath5k_calibrate(struct ath5k_softc *sc)
-{
-	struct ath5k_hw *ah = sc->ah;
-
-	if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
-		/*
-		 * Rfgain is out of bounds, reset the chip
-		 * to load new gain values.
-		 */
-		DBG("ath5k: resetting for calibration\n");
-		ath5k_reset_wake(sc);
-	}
-	if (ath5k_hw_phy_calibrate(ah, sc->curchan))
-		DBG("ath5k: calibration of channel %d failed\n",
-		    sc->curchan->channel_nr);
-}
-
-
-/********************\
-* Net80211 functions *
-\********************/
-
-static int
-ath5k_tx(struct net80211_device *dev, struct io_buffer *iob)
-{
-	struct ath5k_softc *sc = dev->priv;
-	struct ath5k_buf *bf;
-	int rc;
-
-	/*
-	 * The hardware expects the header padded to 4 byte boundaries.
-	 * iPXE only ever sends 24-byte headers, so no action necessary.
-	 */
-
-	if (list_empty(&sc->txbuf)) {
-		DBG("ath5k: dropping packet because no tx bufs available\n");
-		return -ENOBUFS;
-	}
-
-	bf = list_entry(sc->txbuf.next, struct ath5k_buf, list);
-	list_del(&bf->list);
-	sc->txbuf_len--;
-
-	bf->iob = iob;
-
-	if ((rc = ath5k_txbuf_setup(sc, bf)) != 0) {
-		bf->iob = NULL;
-		list_add_tail(&bf->list, &sc->txbuf);
-		sc->txbuf_len++;
-		return rc;
-	}
-	return 0;
-}
-
-/*
- * Reset the hardware.  If chan is not NULL, then also pause rx/tx
- * and change to the given channel.
- */
-static int
-ath5k_reset(struct ath5k_softc *sc, struct net80211_channel *chan)
-{
-	struct ath5k_hw *ah = sc->ah;
-	int ret;
-
-	if (chan) {
-		ath5k_hw_set_imr(ah, 0);
-		ath5k_txq_cleanup(sc);
-		ath5k_rx_stop(sc);
-
-		sc->curchan = chan;
-		sc->curband = chan->band;
-	}
-
-	ret = ath5k_hw_reset(ah, sc->curchan, 1);
-	if (ret) {
-		DBG("ath5k: can't reset hardware: %s\n", strerror(ret));
-		return ret;
-	}
-
-	ret = ath5k_rx_start(sc);
-	if (ret) {
-		DBG("ath5k: can't start rx logic: %s\n", strerror(ret));
-		return ret;
-	}
-
-	/*
-	 * Change channels and update the h/w rate map if we're switching;
-	 * e.g. 11a to 11b/g.
-	 *
-	 * We may be doing a reset in response to an ioctl that changes the
-	 * channel so update any state that might change as a result.
-	 *
-	 * XXX needed?
-	 */
-/*	ath5k_chan_change(sc, c); */
-
-	/* Reenable interrupts if necessary */
-	ath5k_irq(sc->dev, sc->irq_ena);
-
-	return 0;
-}
-
-static int ath5k_reset_wake(struct ath5k_softc *sc)
-{
-	return ath5k_reset(sc, sc->curchan);
-}
-
-static int ath5k_start(struct net80211_device *dev)
-{
-	struct ath5k_softc *sc = dev->priv;
-	int ret;
-
-	if ((ret = ath5k_init(sc)) != 0)
-		return ret;
-
-	sc->assoc = 0;
-	ath5k_configure_filter(sc);
-	ath5k_hw_set_lladdr(sc->ah, dev->netdev->ll_addr);
-
-	return 0;
-}
-
-static void ath5k_stop(struct net80211_device *dev)
-{
-	struct ath5k_softc *sc = dev->priv;
-	u8 mac[ETH_ALEN] = {};
-
-	ath5k_hw_set_lladdr(sc->ah, mac);
-
-	ath5k_stop_hw(sc);
-}
-
-static int
-ath5k_config(struct net80211_device *dev, int changed)
-{
-	struct ath5k_softc *sc = dev->priv;
-	struct ath5k_hw *ah = sc->ah;
-	struct net80211_channel *chan = &dev->channels[dev->channel];
-	int ret;
-
-	if (changed & NET80211_CFG_CHANNEL) {
-		sc->power_level = chan->maxpower;
-		if ((ret = ath5k_chan_set(sc, chan)) != 0)
-			return ret;
-	}
-
-	if ((changed & NET80211_CFG_RATE) ||
-	    (changed & NET80211_CFG_PHY_PARAMS)) {
-		int spmbl = ATH5K_SPMBL_NO;
-		u16 rate = dev->rates[dev->rate];
-		u16 slowrate = dev->rates[dev->rtscts_rate];
-		int i;
-
-		if (dev->phy_flags & NET80211_PHY_USE_SHORT_PREAMBLE)
-			spmbl = ATH5K_SPMBL_YES;
-
-		for (i = 0; i < ATH5K_NR_RATES; i++) {
-			if (ath5k_rates[i].bitrate == rate &&
-			    (ath5k_rates[i].short_pmbl & spmbl))
-				sc->hw_rate = ath5k_rates[i].hw_code;
-
-			if (ath5k_rates[i].bitrate == slowrate &&
-			    (ath5k_rates[i].short_pmbl & spmbl))
-				sc->hw_rtscts_rate = ath5k_rates[i].hw_code;
-		}
-	}
-
-	if (changed & NET80211_CFG_ASSOC) {
-		sc->assoc = !!(dev->state & NET80211_ASSOCIATED);
-		if (sc->assoc) {
-			memcpy(ah->ah_bssid, dev->bssid, ETH_ALEN);
-		} else {
-			memset(ah->ah_bssid, 0xff, ETH_ALEN);
-		}
-		ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
-	}
-
-	return 0;
-}
-
-/*
- * o always accept unicast, broadcast, and multicast traffic
- * o multicast traffic for all BSSIDs will be enabled if mac80211
- *   says it should be
- * o maintain current state of phy ofdm or phy cck error reception.
- *   If the hardware detects any of these type of errors then
- *   ath5k_hw_get_rx_filter() will pass to us the respective
- *   hardware filters to be able to receive these type of frames.
- * o probe request frames are accepted only when operating in
- *   hostap, adhoc, or monitor modes
- * o enable promiscuous mode according to the interface state
- * o accept beacons:
- *   - when operating in adhoc mode so the 802.11 layer creates
- *     node table entries for peers,
- *   - when operating in station mode for collecting rssi data when
- *     the station is otherwise quiet, or
- *   - when scanning
- */
-static void ath5k_configure_filter(struct ath5k_softc *sc)
-{
-	struct ath5k_hw *ah = sc->ah;
-	u32 mfilt[2], rfilt;
-
-	/* Enable all multicast */
-	mfilt[0] = ~0;
-	mfilt[1] = ~0;
-
-	/* Enable data frames and beacons */
-	rfilt = (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
-		 AR5K_RX_FILTER_MCAST | AR5K_RX_FILTER_BEACON);
-
-	/* Set filters */
-	ath5k_hw_set_rx_filter(ah, rfilt);
-
-	/* Set multicast bits */
-	ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
-
-	/* Set the cached hw filter flags, this will alter actually
-	 * be set in HW */
-	sc->filter_flags = rfilt;
-}
diff --git a/roms/ipxe/src/drivers/net/ath5k/ath5k.h b/roms/ipxe/src/drivers/net/ath5k/ath5k.h
deleted file mode 100644
index 30e2024c60307b27d531563c8f7849249760e9a8..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/ath5k.h
+++ /dev/null
@@ -1,1279 +0,0 @@
-/*
- * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
- *
- * Modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>
- * Original from Linux kernel 2.6.30.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _ATH5K_H
-#define _ATH5K_H
-
-FILE_LICENCE ( MIT );
-
-#include <stddef.h>
-#include <byteswap.h>
-#include <ipxe/io.h>
-#include <ipxe/netdevice.h>
-#include <ipxe/net80211.h>
-#include <errno.h>
-
-/* Keep all ath5k files under one errfile ID */
-#undef ERRFILE
-#define ERRFILE ERRFILE_ath5k
-
-#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
-
-/* RX/TX descriptor hw structs */
-#include "desc.h"
-
-/* EEPROM structs/offsets */
-#include "eeprom.h"
-
-/* PCI IDs */
-#define PCI_DEVICE_ID_ATHEROS_AR5210 		0x0007 /* AR5210 */
-#define PCI_DEVICE_ID_ATHEROS_AR5311 		0x0011 /* AR5311 */
-#define PCI_DEVICE_ID_ATHEROS_AR5211 		0x0012 /* AR5211 */
-#define PCI_DEVICE_ID_ATHEROS_AR5212 		0x0013 /* AR5212 */
-#define PCI_DEVICE_ID_3COM_3CRDAG675 		0x0013 /* 3CRDAG675 (Atheros AR5212) */
-#define PCI_DEVICE_ID_3COM_2_3CRPAG175 		0x0013 /* 3CRPAG175 (Atheros AR5212) */
-#define PCI_DEVICE_ID_ATHEROS_AR5210_AP 	0x0207 /* AR5210 (Early) */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_IBM	0x1014 /* AR5212 (IBM MiniPCI) */
-#define PCI_DEVICE_ID_ATHEROS_AR5210_DEFAULT 	0x1107 /* AR5210 (no eeprom) */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_DEFAULT 	0x1113 /* AR5212 (no eeprom) */
-#define PCI_DEVICE_ID_ATHEROS_AR5211_DEFAULT 	0x1112 /* AR5211 (no eeprom) */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_FPGA 	0xf013 /* AR5212 (emulation board) */
-#define PCI_DEVICE_ID_ATHEROS_AR5211_LEGACY 	0xff12 /* AR5211 (emulation board) */
-#define PCI_DEVICE_ID_ATHEROS_AR5211_FPGA11B 	0xf11b /* AR5211 (emulation board) */
-#define PCI_DEVICE_ID_ATHEROS_AR5312_REV2 	0x0052 /* AR5312 WMAC (AP31) */
-#define PCI_DEVICE_ID_ATHEROS_AR5312_REV7 	0x0057 /* AR5312 WMAC (AP30-040) */
-#define PCI_DEVICE_ID_ATHEROS_AR5312_REV8 	0x0058 /* AR5312 WMAC (AP43-030) */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_0014 	0x0014 /* AR5212 compatible */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_0015 	0x0015 /* AR5212 compatible */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_0016 	0x0016 /* AR5212 compatible */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_0017 	0x0017 /* AR5212 compatible */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_0018 	0x0018 /* AR5212 compatible */
-#define PCI_DEVICE_ID_ATHEROS_AR5212_0019 	0x0019 /* AR5212 compatible */
-#define PCI_DEVICE_ID_ATHEROS_AR2413 		0x001a /* AR2413 (Griffin-lite) */
-#define PCI_DEVICE_ID_ATHEROS_AR5413 		0x001b /* AR5413 (Eagle) */
-#define PCI_DEVICE_ID_ATHEROS_AR5424 		0x001c /* AR5424 (Condor PCI-E) */
-#define PCI_DEVICE_ID_ATHEROS_AR5416 		0x0023 /* AR5416 */
-#define PCI_DEVICE_ID_ATHEROS_AR5418 		0x0024 /* AR5418 */
-
-/****************************\
-  GENERIC DRIVER DEFINITIONS
-\****************************/
-
-/*
- * AR5K REGISTER ACCESS
- */
-
-/* Some macros to read/write fields */
-
-/* First shift, then mask */
-#define AR5K_REG_SM(_val, _flags)					\
-	(((_val) << _flags##_S) & (_flags))
-
-/* First mask, then shift */
-#define AR5K_REG_MS(_val, _flags)					\
-	(((_val) & (_flags)) >> _flags##_S)
-
-/* Some registers can hold multiple values of interest. For this
- * reason when we want to write to these registers we must first
- * retrieve the values which we do not want to clear (lets call this
- * old_data) and then set the register with this and our new_value:
- * ( old_data | new_value) */
-#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val)			\
-	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \
-	    (((_val) << _flags##_S) & (_flags)), _reg)
-
-#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask)			\
-	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) &		\
-			(_mask)) | (_flags), _reg)
-
-#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags)				\
-	ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg)
-
-#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags)			\
-	ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg)
-
-/* Access to PHY registers */
-#define AR5K_PHY_READ(ah, _reg)					\
-	ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2))
-
-#define AR5K_PHY_WRITE(ah, _reg, _val)					\
-	ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2))
-
-/* Access QCU registers per queue */
-#define AR5K_REG_READ_Q(ah, _reg, _queue)				\
-	(ath5k_hw_reg_read(ah, _reg) & (1 << _queue))			\
-
-#define AR5K_REG_WRITE_Q(ah, _reg, _queue)				\
-	ath5k_hw_reg_write(ah, (1 << _queue), _reg)
-
-#define AR5K_Q_ENABLE_BITS(_reg, _queue) do {				\
-	_reg |= 1 << _queue;						\
-} while (0)
-
-#define AR5K_Q_DISABLE_BITS(_reg, _queue) do {				\
-	_reg &= ~(1 << _queue);						\
-} while (0)
-
-/* Used while writing initvals */
-#define AR5K_REG_WAIT(_i) do {						\
-	if (_i % 64)							\
-		udelay(1);						\
-} while (0)
-
-/* Register dumps are done per operation mode */
-#define AR5K_INI_RFGAIN_5GHZ		0
-#define AR5K_INI_RFGAIN_2GHZ		1
-
-/* TODO: Clean this up */
-#define AR5K_INI_VAL_11A		0
-#define AR5K_INI_VAL_11A_TURBO		1
-#define AR5K_INI_VAL_11B		2
-#define AR5K_INI_VAL_11G		3
-#define AR5K_INI_VAL_11G_TURBO		4
-#define AR5K_INI_VAL_XR			0
-#define AR5K_INI_VAL_MAX		5
-
-/* Used for BSSID etc manipulation */
-#define AR5K_LOW_ID(_a)(				\
-(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24	\
-)
-
-#define AR5K_HIGH_ID(_a)	((_a)[4] | (_a)[5] << 8)
-
-#define IEEE80211_MAX_LEN	2352
-
-/*
- * Some tuneable values (these should be changeable by the user)
- */
-#define AR5K_TUNE_DMA_BEACON_RESP		2
-#define AR5K_TUNE_SW_BEACON_RESP		10
-#define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF	0
-#define AR5K_TUNE_RADAR_ALERT			0
-#define AR5K_TUNE_MIN_TX_FIFO_THRES		1
-#define AR5K_TUNE_MAX_TX_FIFO_THRES		((IEEE80211_MAX_LEN / 64) + 1)
-#define AR5K_TUNE_REGISTER_TIMEOUT		20000
-/* Register for RSSI threshold has a mask of 0xff, so 255 seems to
- * be the max value. */
-#define AR5K_TUNE_RSSI_THRES			129
-/* This must be set when setting the RSSI threshold otherwise it can
- * prevent a reset. If AR5K_RSSI_THR is read after writing to it
- * the BMISS_THRES will be seen as 0, seems harware doesn't keep
- * track of it. Max value depends on harware. For AR5210 this is just 7.
- * For AR5211+ this seems to be up to 255. */
-#define AR5K_TUNE_BMISS_THRES			7
-#define AR5K_TUNE_REGISTER_DWELL_TIME		20000
-#define AR5K_TUNE_BEACON_INTERVAL		100
-#define AR5K_TUNE_AIFS				2
-#define AR5K_TUNE_AIFS_11B			2
-#define AR5K_TUNE_AIFS_XR			0
-#define AR5K_TUNE_CWMIN				15
-#define AR5K_TUNE_CWMIN_11B			31
-#define AR5K_TUNE_CWMIN_XR			3
-#define AR5K_TUNE_CWMAX				1023
-#define AR5K_TUNE_CWMAX_11B			1023
-#define AR5K_TUNE_CWMAX_XR			7
-#define AR5K_TUNE_NOISE_FLOOR			-72
-#define AR5K_TUNE_MAX_TXPOWER			63
-#define AR5K_TUNE_DEFAULT_TXPOWER		25
-#define AR5K_TUNE_TPC_TXPOWER			0
-#define AR5K_TUNE_ANT_DIVERSITY			1
-#define AR5K_TUNE_HWTXTRIES			4
-
-#define AR5K_INIT_CARR_SENSE_EN			1
-
-/*Swap RX/TX Descriptor for big endian archs*/
-#if __BYTE_ORDER == __BIG_ENDIAN
-#define AR5K_INIT_CFG	(		\
-	AR5K_CFG_SWTD | AR5K_CFG_SWRD	\
-)
-#else
-#define AR5K_INIT_CFG	0x00000000
-#endif
-
-/* Initial values */
-#define	AR5K_INIT_CYCRSSI_THR1			2
-#define AR5K_INIT_TX_LATENCY			502
-#define AR5K_INIT_USEC				39
-#define AR5K_INIT_USEC_TURBO			79
-#define AR5K_INIT_USEC_32			31
-#define AR5K_INIT_SLOT_TIME			396
-#define AR5K_INIT_SLOT_TIME_TURBO		480
-#define AR5K_INIT_ACK_CTS_TIMEOUT		1024
-#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO		0x08000800
-#define AR5K_INIT_PROG_IFS			920
-#define AR5K_INIT_PROG_IFS_TURBO		960
-#define AR5K_INIT_EIFS				3440
-#define AR5K_INIT_EIFS_TURBO			6880
-#define AR5K_INIT_SIFS				560
-#define AR5K_INIT_SIFS_TURBO			480
-#define AR5K_INIT_SH_RETRY			10
-#define AR5K_INIT_LG_RETRY			AR5K_INIT_SH_RETRY
-#define AR5K_INIT_SSH_RETRY			32
-#define AR5K_INIT_SLG_RETRY			AR5K_INIT_SSH_RETRY
-#define AR5K_INIT_TX_RETRY			10
-
-#define AR5K_INIT_TRANSMIT_LATENCY		(			\
-	(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |	\
-	(AR5K_INIT_USEC)						\
-)
-#define AR5K_INIT_TRANSMIT_LATENCY_TURBO	(			\
-	(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |	\
-	(AR5K_INIT_USEC_TURBO)						\
-)
-#define AR5K_INIT_PROTO_TIME_CNTRL		(			\
-	(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) |	\
-	(AR5K_INIT_PROG_IFS)						\
-)
-#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO	(			\
-	(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \
-	(AR5K_INIT_PROG_IFS_TURBO)					\
-)
-
-/* token to use for aifs, cwmin, cwmax in MadWiFi */
-#define	AR5K_TXQ_USEDEFAULT	((u32) -1)
-
-/* GENERIC CHIPSET DEFINITIONS */
-
-/* MAC Chips */
-enum ath5k_version {
-	AR5K_AR5210	= 0,
-	AR5K_AR5211	= 1,
-	AR5K_AR5212	= 2,
-};
-
-/* PHY Chips */
-enum ath5k_radio {
-	AR5K_RF5110	= 0,
-	AR5K_RF5111	= 1,
-	AR5K_RF5112	= 2,
-	AR5K_RF2413	= 3,
-	AR5K_RF5413	= 4,
-	AR5K_RF2316	= 5,
-	AR5K_RF2317	= 6,
-	AR5K_RF2425	= 7,
-};
-
-/*
- * Common silicon revision/version values
- */
-
-enum ath5k_srev_type {
-	AR5K_VERSION_MAC,
-	AR5K_VERSION_RAD,
-};
-
-struct ath5k_srev_name {
-	const char		*sr_name;
-	enum ath5k_srev_type	sr_type;
-	unsigned		sr_val;
-};
-
-#define AR5K_SREV_UNKNOWN	0xffff
-
-#define AR5K_SREV_AR5210	0x00 /* Crete */
-#define AR5K_SREV_AR5311	0x10 /* Maui 1 */
-#define AR5K_SREV_AR5311A	0x20 /* Maui 2 */
-#define AR5K_SREV_AR5311B	0x30 /* Spirit */
-#define AR5K_SREV_AR5211	0x40 /* Oahu */
-#define AR5K_SREV_AR5212	0x50 /* Venice */
-#define AR5K_SREV_AR5213	0x55 /* ??? */
-#define AR5K_SREV_AR5213A	0x59 /* Hainan */
-#define AR5K_SREV_AR2413	0x78 /* Griffin lite */
-#define AR5K_SREV_AR2414	0x70 /* Griffin */
-#define AR5K_SREV_AR5424	0x90 /* Condor */
-#define AR5K_SREV_AR5413	0xa4 /* Eagle lite */
-#define AR5K_SREV_AR5414	0xa0 /* Eagle */
-#define AR5K_SREV_AR2415	0xb0 /* Talon */
-#define AR5K_SREV_AR5416	0xc0 /* PCI-E */
-#define AR5K_SREV_AR5418	0xca /* PCI-E */
-#define AR5K_SREV_AR2425	0xe0 /* Swan */
-#define AR5K_SREV_AR2417	0xf0 /* Nala */
-
-#define AR5K_SREV_RAD_5110	0x00
-#define AR5K_SREV_RAD_5111	0x10
-#define AR5K_SREV_RAD_5111A	0x15
-#define AR5K_SREV_RAD_2111	0x20
-#define AR5K_SREV_RAD_5112	0x30
-#define AR5K_SREV_RAD_5112A	0x35
-#define	AR5K_SREV_RAD_5112B	0x36
-#define AR5K_SREV_RAD_2112	0x40
-#define AR5K_SREV_RAD_2112A	0x45
-#define	AR5K_SREV_RAD_2112B	0x46
-#define AR5K_SREV_RAD_2413	0x50
-#define AR5K_SREV_RAD_5413	0x60
-#define AR5K_SREV_RAD_2316	0x70 /* Cobra SoC */
-#define AR5K_SREV_RAD_2317	0x80
-#define AR5K_SREV_RAD_5424	0xa0 /* Mostly same as 5413 */
-#define AR5K_SREV_RAD_2425	0xa2
-#define AR5K_SREV_RAD_5133	0xc0
-
-#define AR5K_SREV_PHY_5211	0x30
-#define AR5K_SREV_PHY_5212	0x41
-#define	AR5K_SREV_PHY_5212A	0x42
-#define AR5K_SREV_PHY_5212B	0x43
-#define AR5K_SREV_PHY_2413	0x45
-#define AR5K_SREV_PHY_5413	0x61
-#define AR5K_SREV_PHY_2425	0x70
-
-/*
- * Some of this information is based on Documentation from:
- *
- * http://madwifi.org/wiki/ChipsetFeatures/SuperAG
- *
- * Modulation for Atheros' eXtended Range - range enhancing extension that is
- * supposed to double the distance an Atheros client device can keep a
- * connection with an Atheros access point. This is achieved by increasing
- * the receiver sensitivity up to, -105dBm, which is about 20dB above what
- * the 802.11 specifications demand. In addition, new (proprietary) data rates
- * are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s.
- *
- * Please note that can you either use XR or TURBO but you cannot use both,
- * they are exclusive.
- *
- */
-#define MODULATION_XR 		0x00000200
-
-/*
- * Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a
- * throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s
- * signaling rate achieved through the bonding of two 54Mbit/s 802.11g
- * channels. To use this feature your Access Point must also suport it.
- * There is also a distinction between "static" and "dynamic" turbo modes:
- *
- * - Static: is the dumb version: devices set to this mode stick to it until
- *     the mode is turned off.
- * - Dynamic: is the intelligent version, the network decides itself if it
- *     is ok to use turbo. As soon as traffic is detected on adjacent channels
- *     (which would get used in turbo mode), or when a non-turbo station joins
- *     the network, turbo mode won't be used until the situation changes again.
- *     Dynamic mode is achieved by Atheros' Adaptive Radio (AR) feature which
- *     monitors the used radio band in order to decide whether turbo mode may
- *     be used or not.
- *
- * This article claims Super G sticks to bonding of channels 5 and 6 for
- * USA:
- *
- * http://www.pcworld.com/article/id,113428-page,1/article.html
- *
- * The channel bonding seems to be driver specific though. In addition to
- * deciding what channels will be used, these "Turbo" modes are accomplished
- * by also enabling the following features:
- *
- * - Bursting: allows multiple frames to be sent at once, rather than pausing
- *     after each frame. Bursting is a standards-compliant feature that can be
- *     used with any Access Point.
- * - Fast frames: increases the amount of information that can be sent per
- *     frame, also resulting in a reduction of transmission overhead. It is a
- *     proprietary feature that needs to be supported by the Access Point.
- * - Compression: data frames are compressed in real time using a Lempel Ziv
- *     algorithm. This is done transparently. Once this feature is enabled,
- *     compression and decompression takes place inside the chipset, without
- *     putting additional load on the host CPU.
- *
- */
-#define MODULATION_TURBO	0x00000080
-
-enum ath5k_driver_mode {
-	AR5K_MODE_11A		= 0,
-	AR5K_MODE_11A_TURBO	= 1,
-	AR5K_MODE_11B		= 2,
-	AR5K_MODE_11G		= 3,
-	AR5K_MODE_11G_TURBO	= 4,
-	AR5K_MODE_XR		= 5,
-};
-
-enum {
-	AR5K_MODE_BIT_11A	= (1 << AR5K_MODE_11A),
-	AR5K_MODE_BIT_11A_TURBO	= (1 << AR5K_MODE_11A_TURBO),
-	AR5K_MODE_BIT_11B	= (1 << AR5K_MODE_11B),
-	AR5K_MODE_BIT_11G	= (1 << AR5K_MODE_11G),
-	AR5K_MODE_BIT_11G_TURBO	= (1 << AR5K_MODE_11G_TURBO),
-	AR5K_MODE_BIT_XR	= (1 << AR5K_MODE_XR),
-};
-
-/****************\
-  TX DEFINITIONS
-\****************/
-
-/*
- * TX Status descriptor
- */
-struct ath5k_tx_status {
-	u16	ts_seqnum;
-	u16	ts_tstamp;
-	u8	ts_status;
-	u8	ts_rate[4];
-	u8	ts_retry[4];
-	u8	ts_final_idx;
-	s8	ts_rssi;
-	u8	ts_shortretry;
-	u8	ts_longretry;
-	u8	ts_virtcol;
-	u8	ts_antenna;
-} __attribute__ ((packed));
-
-#define AR5K_TXSTAT_ALTRATE	0x80
-#define AR5K_TXERR_XRETRY	0x01
-#define AR5K_TXERR_FILT		0x02
-#define AR5K_TXERR_FIFO		0x04
-
-/**
- * enum ath5k_tx_queue - Queue types used to classify tx queues.
- * @AR5K_TX_QUEUE_INACTIVE: q is unused -- see ath5k_hw_release_tx_queue
- * @AR5K_TX_QUEUE_DATA: A normal data queue
- * @AR5K_TX_QUEUE_XR_DATA: An XR-data queue
- * @AR5K_TX_QUEUE_BEACON: The beacon queue
- * @AR5K_TX_QUEUE_CAB: The after-beacon queue
- * @AR5K_TX_QUEUE_UAPSD: Unscheduled Automatic Power Save Delivery queue
- */
-enum ath5k_tx_queue {
-	AR5K_TX_QUEUE_INACTIVE = 0,
-	AR5K_TX_QUEUE_DATA,
-	AR5K_TX_QUEUE_XR_DATA,
-	AR5K_TX_QUEUE_BEACON,
-	AR5K_TX_QUEUE_CAB,
-	AR5K_TX_QUEUE_UAPSD,
-};
-
-/*
- * Queue syb-types to classify normal data queues.
- * These are the 4 Access Categories as defined in
- * WME spec. 0 is the lowest priority and 4 is the
- * highest. Normal data that hasn't been classified
- * goes to the Best Effort AC.
- */
-enum ath5k_tx_queue_subtype {
-	AR5K_WME_AC_BK = 0,	/*Background traffic*/
-	AR5K_WME_AC_BE, 	/*Best-effort (normal) traffic)*/
-	AR5K_WME_AC_VI, 	/*Video traffic*/
-	AR5K_WME_AC_VO, 	/*Voice traffic*/
-};
-
-/*
- * Queue ID numbers as returned by the hw functions, each number
- * represents a hw queue. If hw does not support hw queues
- * (eg 5210) all data goes in one queue. These match
- * d80211 definitions (net80211/MadWiFi don't use them).
- */
-enum ath5k_tx_queue_id {
-	AR5K_TX_QUEUE_ID_NOQCU_DATA	= 0,
-	AR5K_TX_QUEUE_ID_NOQCU_BEACON	= 1,
-	AR5K_TX_QUEUE_ID_DATA_MIN	= 0, /*IEEE80211_TX_QUEUE_DATA0*/
-	AR5K_TX_QUEUE_ID_DATA_MAX	= 4, /*IEEE80211_TX_QUEUE_DATA4*/
-	AR5K_TX_QUEUE_ID_DATA_SVP	= 5, /*IEEE80211_TX_QUEUE_SVP - Spectralink Voice Protocol*/
-	AR5K_TX_QUEUE_ID_CAB		= 6, /*IEEE80211_TX_QUEUE_AFTER_BEACON*/
-	AR5K_TX_QUEUE_ID_BEACON		= 7, /*IEEE80211_TX_QUEUE_BEACON*/
-	AR5K_TX_QUEUE_ID_UAPSD		= 8,
-	AR5K_TX_QUEUE_ID_XR_DATA	= 9,
-};
-
-/*
- * Flags to set hw queue's parameters...
- */
-#define AR5K_TXQ_FLAG_TXOKINT_ENABLE		0x0001	/* Enable TXOK interrupt */
-#define AR5K_TXQ_FLAG_TXERRINT_ENABLE		0x0002	/* Enable TXERR interrupt */
-#define AR5K_TXQ_FLAG_TXEOLINT_ENABLE		0x0004	/* Enable TXEOL interrupt -not used- */
-#define AR5K_TXQ_FLAG_TXDESCINT_ENABLE		0x0008	/* Enable TXDESC interrupt -not used- */
-#define AR5K_TXQ_FLAG_TXURNINT_ENABLE		0x0010	/* Enable TXURN interrupt */
-#define AR5K_TXQ_FLAG_CBRORNINT_ENABLE		0x0020	/* Enable CBRORN interrupt */
-#define AR5K_TXQ_FLAG_CBRURNINT_ENABLE		0x0040	/* Enable CBRURN interrupt */
-#define AR5K_TXQ_FLAG_QTRIGINT_ENABLE		0x0080	/* Enable QTRIG interrupt */
-#define AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE		0x0100	/* Enable TXNOFRM interrupt */
-#define AR5K_TXQ_FLAG_BACKOFF_DISABLE		0x0200	/* Disable random post-backoff */
-#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE	0x0300	/* Enable ready time expiry policy (?)*/
-#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE	0x0800	/* Enable backoff while bursting */
-#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS		0x1000	/* Disable backoff while bursting */
-#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE	0x2000	/* Enable hw compression -not implemented-*/
-
-/*
- * A struct to hold tx queue's parameters
- */
-struct ath5k_txq_info {
-	enum ath5k_tx_queue tqi_type;
-	enum ath5k_tx_queue_subtype tqi_subtype;
-	u16	tqi_flags;	/* Tx queue flags (see above) */
-	u32	tqi_aifs;	/* Arbitrated Interframe Space */
-	s32	tqi_cw_min;	/* Minimum Contention Window */
-	s32	tqi_cw_max;	/* Maximum Contention Window */
-	u32	tqi_cbr_period; /* Constant bit rate period */
-	u32	tqi_cbr_overflow_limit;
-	u32	tqi_burst_time;
-	u32	tqi_ready_time; /* Not used */
-};
-
-/*
- * Transmit packet types.
- * used on tx control descriptor
- * TODO: Use them inside base.c corectly
- */
-enum ath5k_pkt_type {
-	AR5K_PKT_TYPE_NORMAL		= 0,
-	AR5K_PKT_TYPE_ATIM		= 1,
-	AR5K_PKT_TYPE_PSPOLL		= 2,
-	AR5K_PKT_TYPE_BEACON		= 3,
-	AR5K_PKT_TYPE_PROBE_RESP	= 4,
-	AR5K_PKT_TYPE_PIFS		= 5,
-};
-
-/*
- * TX power and TPC settings
- */
-#define AR5K_TXPOWER_OFDM(_r, _v)	(			\
-	((0 & 1) << ((_v) + 6)) |				\
-	(((ah->ah_txpower.txp_rates_power_table[(_r)]) & 0x3f) << (_v))	\
-)
-
-#define AR5K_TXPOWER_CCK(_r, _v)	(			\
-	(ah->ah_txpower.txp_rates_power_table[(_r)] & 0x3f) << (_v)	\
-)
-
-/*
- * DMA size definitions (2^n+2)
- */
-enum ath5k_dmasize {
-	AR5K_DMASIZE_4B	= 0,
-	AR5K_DMASIZE_8B,
-	AR5K_DMASIZE_16B,
-	AR5K_DMASIZE_32B,
-	AR5K_DMASIZE_64B,
-	AR5K_DMASIZE_128B,
-	AR5K_DMASIZE_256B,
-	AR5K_DMASIZE_512B
-};
-
-
-/****************\
-  RX DEFINITIONS
-\****************/
-
-/*
- * RX Status descriptor
- */
-struct ath5k_rx_status {
-	u16	rs_datalen;
-	u16	rs_tstamp;
-	u8	rs_status;
-	u8	rs_phyerr;
-	s8	rs_rssi;
-	u8	rs_keyix;
-	u8	rs_rate;
-	u8	rs_antenna;
-	u8	rs_more;
-};
-
-#define AR5K_RXERR_CRC		0x01
-#define AR5K_RXERR_PHY		0x02
-#define AR5K_RXERR_FIFO		0x04
-#define AR5K_RXERR_DECRYPT	0x08
-#define AR5K_RXERR_MIC		0x10
-#define AR5K_RXKEYIX_INVALID	((u8) - 1)
-#define AR5K_TXKEYIX_INVALID	((u32) - 1)
-
-
-/*
- * TSF to TU conversion:
- *
- * TSF is a 64bit value in usec (microseconds).
- * TU is a 32bit value and defined by IEEE802.11 (page 6) as "A measurement of
- * time equal to 1024 usec", so it's roughly milliseconds (usec / 1024).
- */
-#define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10)
-
-
-/*******************************\
-  GAIN OPTIMIZATION DEFINITIONS
-\*******************************/
-
-enum ath5k_rfgain {
-	AR5K_RFGAIN_INACTIVE = 0,
-	AR5K_RFGAIN_ACTIVE,
-	AR5K_RFGAIN_READ_REQUESTED,
-	AR5K_RFGAIN_NEED_CHANGE,
-};
-
-struct ath5k_gain {
-	u8			g_step_idx;
-	u8			g_current;
-	u8			g_target;
-	u8			g_low;
-	u8			g_high;
-	u8			g_f_corr;
-	u8			g_state;
-};
-
-/********************\
-  COMMON DEFINITIONS
-\********************/
-
-#define AR5K_SLOT_TIME_9	396
-#define AR5K_SLOT_TIME_20	880
-#define AR5K_SLOT_TIME_MAX	0xffff
-
-/* channel_flags */
-#define	CHANNEL_CW_INT	0x0008	/* Contention Window interference detected */
-#define	CHANNEL_TURBO	0x0010	/* Turbo Channel */
-#define	CHANNEL_CCK	0x0020	/* CCK channel */
-#define	CHANNEL_OFDM	0x0040	/* OFDM channel */
-#define	CHANNEL_2GHZ	0x0080	/* 2GHz channel. */
-#define	CHANNEL_5GHZ	0x0100	/* 5GHz channel */
-#define	CHANNEL_PASSIVE	0x0200	/* Only passive scan allowed */
-#define	CHANNEL_DYN	0x0400	/* Dynamic CCK-OFDM channel (for g operation) */
-#define	CHANNEL_XR	0x0800	/* XR channel */
-
-#define	CHANNEL_A	(CHANNEL_5GHZ|CHANNEL_OFDM)
-#define	CHANNEL_B	(CHANNEL_2GHZ|CHANNEL_CCK)
-#define	CHANNEL_G	(CHANNEL_2GHZ|CHANNEL_OFDM)
-#define	CHANNEL_T	(CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
-#define	CHANNEL_TG	(CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
-#define	CHANNEL_108A	CHANNEL_T
-#define	CHANNEL_108G	CHANNEL_TG
-#define	CHANNEL_X	(CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR)
-
-#define	CHANNEL_ALL 	(CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_2GHZ|CHANNEL_5GHZ| \
-		CHANNEL_TURBO)
-
-#define	CHANNEL_ALL_NOTURBO 	(CHANNEL_ALL & ~CHANNEL_TURBO)
-#define CHANNEL_MODES		CHANNEL_ALL
-
-/*
- * Used internaly for reset_tx_queue).
- * Also see struct struct net80211_channel.
- */
-#define IS_CHAN_XR(_c)	((_c->hw_value & CHANNEL_XR) != 0)
-#define IS_CHAN_B(_c)	((_c->hw_value & CHANNEL_B) != 0)
-
-/*
- * The following structure is used to map 2GHz channels to
- * 5GHz Atheros channels.
- * TODO: Clean up
- */
-struct ath5k_athchan_2ghz {
-	u32	a2_flags;
-	u16	a2_athchan;
-};
-
-
-/******************\
-  RATE DEFINITIONS
-\******************/
-
-/**
- * Seems the ar5xxx harware supports up to 32 rates, indexed by 1-32.
- *
- * The rate code is used to get the RX rate or set the TX rate on the
- * hardware descriptors. It is also used for internal modulation control
- * and settings.
- *
- * This is the hardware rate map we are aware of:
- *
- * rate_code   0x01    0x02    0x03    0x04    0x05    0x06    0x07    0x08
- * rate_kbps   3000    1000    ?       ?       ?       2000    500     48000
- *
- * rate_code   0x09    0x0A    0x0B    0x0C    0x0D    0x0E    0x0F    0x10
- * rate_kbps   24000   12000   6000    54000   36000   18000   9000    ?
- *
- * rate_code   17      18      19      20      21      22      23      24
- * rate_kbps   ?       ?       ?       ?       ?       ?       ?       11000
- *
- * rate_code   25      26      27      28      29      30      31      32
- * rate_kbps   5500    2000    1000    11000S  5500S   2000S   ?       ?
- *
- * "S" indicates CCK rates with short preamble.
- *
- * AR5211 has different rate codes for CCK (802.11B) rates. It only uses the
- * lowest 4 bits, so they are the same as below with a 0xF mask.
- * (0xB, 0xA, 0x9 and 0x8 for 1M, 2M, 5.5M and 11M).
- * We handle this in ath5k_setup_bands().
- */
-#define AR5K_MAX_RATES 32
-
-/* B */
-#define ATH5K_RATE_CODE_1M	0x1B
-#define ATH5K_RATE_CODE_2M	0x1A
-#define ATH5K_RATE_CODE_5_5M	0x19
-#define ATH5K_RATE_CODE_11M	0x18
-/* A and G */
-#define ATH5K_RATE_CODE_6M	0x0B
-#define ATH5K_RATE_CODE_9M	0x0F
-#define ATH5K_RATE_CODE_12M	0x0A
-#define ATH5K_RATE_CODE_18M	0x0E
-#define ATH5K_RATE_CODE_24M	0x09
-#define ATH5K_RATE_CODE_36M	0x0D
-#define ATH5K_RATE_CODE_48M	0x08
-#define ATH5K_RATE_CODE_54M	0x0C
-/* XR */
-#define ATH5K_RATE_CODE_XR_500K	0x07
-#define ATH5K_RATE_CODE_XR_1M	0x02
-#define ATH5K_RATE_CODE_XR_2M	0x06
-#define ATH5K_RATE_CODE_XR_3M	0x01
-
-/* adding this flag to rate_code enables short preamble */
-#define AR5K_SET_SHORT_PREAMBLE 0x04
-
-/*
- * Crypto definitions
- */
-
-#define AR5K_KEYCACHE_SIZE	8
-
-/***********************\
- HW RELATED DEFINITIONS
-\***********************/
-
-/*
- * Misc definitions
- */
-#define	AR5K_RSSI_EP_MULTIPLIER	(1<<7)
-
-#define AR5K_ASSERT_ENTRY(_e, _s) do {		\
-	if (_e >= _s)				\
-		return 0;			\
-} while (0)
-
-/*
- * Hardware interrupt abstraction
- */
-
-/**
- * enum ath5k_int - Hardware interrupt masks helpers
- *
- * @AR5K_INT_RX: mask to identify received frame interrupts, of type
- * 	AR5K_ISR_RXOK or AR5K_ISR_RXERR
- * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?)
- * @AR5K_INT_RXNOFRM: No frame received (?)
- * @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The
- * 	Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's
- * 	LinkPtr is NULL. For more details, refer to:
- * 	http://www.freepatentsonline.com/20030225739.html
- * @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors).
- * 	Note that Rx overrun is not always fatal, on some chips we can continue
- * 	operation without reseting the card, that's why int_fatal is not
- * 	common for all chips.
- * @AR5K_INT_TX: mask to identify received frame interrupts, of type
- * 	AR5K_ISR_TXOK or AR5K_ISR_TXERR
- * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?)
- * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold
- * 	We currently do increments on interrupt by
- * 	(AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2
- * @AR5K_INT_MIB: Indicates the Management Information Base counters should be
- * 	checked. We should do this with ath5k_hw_update_mib_counters() but
- * 	it seems we should also then do some noise immunity work.
- * @AR5K_INT_RXPHY: RX PHY Error
- * @AR5K_INT_RXKCM: RX Key cache miss
- * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a
- * 	beacon that must be handled in software. The alternative is if you
- * 	have VEOL support, in that case you let the hardware deal with things.
- * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing
- * 	beacons from the AP have associated with, we should probably try to
- * 	reassociate. When in IBSS mode this might mean we have not received
- * 	any beacons from any local stations. Note that every station in an
- * 	IBSS schedules to send beacons at the Target Beacon Transmission Time
- * 	(TBTT) with a random backoff.
- * @AR5K_INT_BNR: Beacon Not Ready interrupt - ??
- * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now
- * 	until properly handled
- * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA
- * 	errors. These types of errors we can enable seem to be of type
- * 	AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR.
- * @AR5K_INT_GLOBAL: Used to clear and set the IER
- * @AR5K_INT_NOCARD: signals the card has been removed
- * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same
- * 	bit value
- *
- * These are mapped to take advantage of some common bits
- * between the MACs, to be able to set intr properties
- * easier. Some of them are not used yet inside hw.c. Most map
- * to the respective hw interrupt value as they are common amogst different
- * MACs.
- */
-enum ath5k_int {
-	AR5K_INT_RXOK	= 0x00000001,
-	AR5K_INT_RXDESC	= 0x00000002,
-	AR5K_INT_RXERR	= 0x00000004,
-	AR5K_INT_RXNOFRM = 0x00000008,
-	AR5K_INT_RXEOL	= 0x00000010,
-	AR5K_INT_RXORN	= 0x00000020,
-	AR5K_INT_TXOK	= 0x00000040,
-	AR5K_INT_TXDESC	= 0x00000080,
-	AR5K_INT_TXERR	= 0x00000100,
-	AR5K_INT_TXNOFRM = 0x00000200,
-	AR5K_INT_TXEOL	= 0x00000400,
-	AR5K_INT_TXURN	= 0x00000800,
-	AR5K_INT_MIB	= 0x00001000,
-	AR5K_INT_SWI	= 0x00002000,
-	AR5K_INT_RXPHY	= 0x00004000,
-	AR5K_INT_RXKCM	= 0x00008000,
-	AR5K_INT_SWBA	= 0x00010000,
-	AR5K_INT_BRSSI	= 0x00020000,
-	AR5K_INT_BMISS	= 0x00040000,
-	AR5K_INT_FATAL	= 0x00080000, /* Non common */
-	AR5K_INT_BNR	= 0x00100000, /* Non common */
-	AR5K_INT_TIM	= 0x00200000, /* Non common */
-	AR5K_INT_DTIM	= 0x00400000, /* Non common */
-	AR5K_INT_DTIM_SYNC =	0x00800000, /* Non common */
-	AR5K_INT_GPIO	=	0x01000000,
-	AR5K_INT_BCN_TIMEOUT =	0x02000000, /* Non common */
-	AR5K_INT_CAB_TIMEOUT =	0x04000000, /* Non common */
-	AR5K_INT_RX_DOPPLER =	0x08000000, /* Non common */
-	AR5K_INT_QCBRORN =	0x10000000, /* Non common */
-	AR5K_INT_QCBRURN =	0x20000000, /* Non common */
-	AR5K_INT_QTRIG	=	0x40000000, /* Non common */
-	AR5K_INT_GLOBAL =	0x80000000,
-
-	AR5K_INT_COMMON  = AR5K_INT_RXOK
-		| AR5K_INT_RXDESC
-		| AR5K_INT_RXERR
-		| AR5K_INT_RXNOFRM
-		| AR5K_INT_RXEOL
-		| AR5K_INT_RXORN
-		| AR5K_INT_TXOK
-		| AR5K_INT_TXDESC
-		| AR5K_INT_TXERR
-		| AR5K_INT_TXNOFRM
-		| AR5K_INT_TXEOL
-		| AR5K_INT_TXURN
-		| AR5K_INT_MIB
-		| AR5K_INT_SWI
-		| AR5K_INT_RXPHY
-		| AR5K_INT_RXKCM
-		| AR5K_INT_SWBA
-		| AR5K_INT_BRSSI
-		| AR5K_INT_BMISS
-		| AR5K_INT_GPIO
-		| AR5K_INT_GLOBAL,
-
-	AR5K_INT_NOCARD	= 0xffffffff
-};
-
-/*
- * Power management
- */
-enum ath5k_power_mode {
-	AR5K_PM_UNDEFINED = 0,
-	AR5K_PM_AUTO,
-	AR5K_PM_AWAKE,
-	AR5K_PM_FULL_SLEEP,
-	AR5K_PM_NETWORK_SLEEP,
-};
-
-/* GPIO-controlled software LED */
-#define AR5K_SOFTLED_PIN	0
-#define AR5K_SOFTLED_ON		0
-#define AR5K_SOFTLED_OFF	1
-
-/*
- * Chipset capabilities -see ath5k_hw_get_capability-
- * get_capability function is not yet fully implemented
- * in ath5k so most of these don't work yet...
- * TODO: Implement these & merge with _TUNE_ stuff above
- */
-enum ath5k_capability_type {
-	AR5K_CAP_REG_DMN		= 0,	/* Used to get current reg. domain id */
-	AR5K_CAP_TKIP_MIC		= 2,	/* Can handle TKIP MIC in hardware */
-	AR5K_CAP_TKIP_SPLIT		= 3,	/* TKIP uses split keys */
-	AR5K_CAP_PHYCOUNTERS		= 4,	/* PHY error counters */
-	AR5K_CAP_DIVERSITY		= 5,	/* Supports fast diversity */
-	AR5K_CAP_NUM_TXQUEUES		= 6,	/* Used to get max number of hw txqueues */
-	AR5K_CAP_VEOL			= 7,	/* Supports virtual EOL */
-	AR5K_CAP_COMPRESSION		= 8,	/* Supports compression */
-	AR5K_CAP_BURST			= 9,	/* Supports packet bursting */
-	AR5K_CAP_FASTFRAME		= 10,	/* Supports fast frames */
-	AR5K_CAP_TXPOW			= 11,	/* Used to get global tx power limit */
-	AR5K_CAP_TPC			= 12,	/* Can do per-packet tx power control (needed for 802.11a) */
-	AR5K_CAP_BSSIDMASK		= 13,	/* Supports bssid mask */
-	AR5K_CAP_MCAST_KEYSRCH		= 14,	/* Supports multicast key search */
-	AR5K_CAP_TSF_ADJUST		= 15,	/* Supports beacon tsf adjust */
-	AR5K_CAP_XR			= 16,	/* Supports XR mode */
-	AR5K_CAP_WME_TKIPMIC 		= 17,	/* Supports TKIP MIC when using WMM */
-	AR5K_CAP_CHAN_HALFRATE 		= 18,	/* Supports half rate channels */
-	AR5K_CAP_CHAN_QUARTERRATE 	= 19,	/* Supports quarter rate channels */
-	AR5K_CAP_RFSILENT		= 20,	/* Supports RFsilent */
-};
-
-
-/* XXX: we *may* move cap_range stuff to struct wiphy */
-struct ath5k_capabilities {
-	/*
-	 * Supported PHY modes
-	 * (ie. CHANNEL_A, CHANNEL_B, ...)
-	 */
-	u16 cap_mode;
-
-	/*
-	 * Frequency range (without regulation restrictions)
-	 */
-	struct {
-		u16	range_2ghz_min;
-		u16	range_2ghz_max;
-		u16	range_5ghz_min;
-		u16	range_5ghz_max;
-	} cap_range;
-
-	/*
-	 * Values stored in the EEPROM (some of them...)
-	 */
-	struct ath5k_eeprom_info	cap_eeprom;
-
-	/*
-	 * Queue information
-	 */
-	struct {
-		u8	q_tx_num;
-	} cap_queues;
-};
-
-
-/***************************************\
-  HARDWARE ABSTRACTION LAYER STRUCTURE
-\***************************************/
-
-/*
- * Misc defines
- */
-
-#define AR5K_MAX_GPIO		10
-#define AR5K_MAX_RF_BANKS	8
-
-/* TODO: Clean up and merge with ath5k_softc */
-struct ath5k_hw {
-	struct ath5k_softc	*ah_sc;
-	void			*ah_iobase;
-
-	enum ath5k_int		ah_imr;
-	int			ah_ier;
-
-	struct net80211_channel	*ah_current_channel;
-	int			ah_turbo;
-	int			ah_calibration;
-	int			ah_running;
-	int			ah_single_chip;
-	int			ah_combined_mic;
-
-	u32			ah_mac_srev;
-	u16			ah_mac_version;
-	u16			ah_mac_revision;
-	u16			ah_phy_revision;
-	u16			ah_radio_5ghz_revision;
-	u16			ah_radio_2ghz_revision;
-
-	enum ath5k_version	ah_version;
-	enum ath5k_radio	ah_radio;
-	u32			ah_phy;
-
-	int			ah_5ghz;
-	int			ah_2ghz;
-
-#define ah_regdomain		ah_capabilities.cap_regdomain.reg_current
-#define ah_regdomain_hw		ah_capabilities.cap_regdomain.reg_hw
-#define ah_modes		ah_capabilities.cap_mode
-#define ah_ee_version		ah_capabilities.cap_eeprom.ee_version
-
-	u32			ah_atim_window;
-	u32			ah_aifs;
-	u32			ah_cw_min;
-	u32			ah_cw_max;
-	int			ah_software_retry;
-	u32			ah_limit_tx_retries;
-
-	u32			ah_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
-	int			ah_ant_diversity;
-
-	u8			ah_sta_id[ETH_ALEN];
-
-	/* Current BSSID we are trying to assoc to / create.
-	 * This is passed by mac80211 on config_interface() and cached here for
-	 * use in resets */
-	u8			ah_bssid[ETH_ALEN];
-	u8			ah_bssid_mask[ETH_ALEN];
-
-	u32			ah_gpio[AR5K_MAX_GPIO];
-	int			ah_gpio_npins;
-
-	struct ath5k_capabilities ah_capabilities;
-
-	struct ath5k_txq_info	ah_txq;
-	u32			ah_txq_status;
-	u32			ah_txq_imr_txok;
-	u32			ah_txq_imr_txerr;
-	u32			ah_txq_imr_txurn;
-	u32			ah_txq_imr_txdesc;
-	u32			ah_txq_imr_txeol;
-	u32			ah_txq_imr_cbrorn;
-	u32			ah_txq_imr_cbrurn;
-	u32			ah_txq_imr_qtrig;
-	u32			ah_txq_imr_nofrm;
-	u32			ah_txq_isr;
-	u32			*ah_rf_banks;
-	size_t			ah_rf_banks_size;
-	size_t			ah_rf_regs_count;
-	struct ath5k_gain	ah_gain;
-	u8			ah_offset[AR5K_MAX_RF_BANKS];
-
-
-	struct {
-		/* Temporary tables used for interpolation */
-		u8		tmpL[AR5K_EEPROM_N_PD_GAINS]
-					[AR5K_EEPROM_POWER_TABLE_SIZE];
-		u8		tmpR[AR5K_EEPROM_N_PD_GAINS]
-					[AR5K_EEPROM_POWER_TABLE_SIZE];
-		u8		txp_pd_table[AR5K_EEPROM_POWER_TABLE_SIZE * 2];
-		u16		txp_rates_power_table[AR5K_MAX_RATES];
-		u8		txp_min_idx;
-		int		txp_tpc;
-		/* Values in 0.25dB units */
-		s16		txp_min_pwr;
-		s16		txp_max_pwr;
-		s16		txp_offset;
-		s16		txp_ofdm;
-		/* Values in dB units */
-		s16		txp_cck_ofdm_pwr_delta;
-		s16		txp_cck_ofdm_gainf_delta;
-	} ah_txpower;
-
-	/* noise floor from last periodic calibration */
-	s32			ah_noise_floor;
-
-	/*
-	 * Function pointers
-	 */
-	int (*ah_setup_rx_desc)(struct ath5k_hw *ah, struct ath5k_desc *desc,
-				u32 size, unsigned int flags);
-	int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
-		unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
-		unsigned int, unsigned int, unsigned int, unsigned int,
-		unsigned int, unsigned int, unsigned int);
-	int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
-		struct ath5k_tx_status *);
-	int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *,
-		struct ath5k_rx_status *);
-};
-
-/*
- * Prototypes
- */
-
-extern int ath5k_bitrate_to_hw_rix(int bitrate);
-
-/* Attach/Detach Functions */
-extern int ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version, struct ath5k_hw **ah);
-extern void ath5k_hw_detach(struct ath5k_hw *ah);
-
-/* LED functions */
-extern int ath5k_init_leds(struct ath5k_softc *sc);
-extern void ath5k_led_enable(struct ath5k_softc *sc);
-extern void ath5k_led_off(struct ath5k_softc *sc);
-extern void ath5k_unregister_leds(struct ath5k_softc *sc);
-
-/* Reset Functions */
-extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, int initial);
-extern int ath5k_hw_reset(struct ath5k_hw *ah, struct net80211_channel *channel, int change_channel);
-/* Power management functions */
-extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, int set_chip, u16 sleep_duration);
-
-/* DMA Related Functions */
-extern void ath5k_hw_start_rx_dma(struct ath5k_hw *ah);
-extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah);
-extern u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah);
-extern void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr);
-extern int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue);
-extern int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue);
-extern u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue);
-extern int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue,
-				u32 phys_addr);
-extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, int increase);
-/* Interrupt handling */
-extern int ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
-extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
-extern enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask);
-
-/* EEPROM access functions */
-extern int ath5k_eeprom_init(struct ath5k_hw *ah);
-extern void ath5k_eeprom_detach(struct ath5k_hw *ah);
-extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
-extern int ath5k_eeprom_is_hb63(struct ath5k_hw *ah);
-
-/* Protocol Control Unit Functions */
-extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
-/* BSSID Functions */
-extern void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac);
-extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
-extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id);
-extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
-/* Receive start/stop functions */
-extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
-extern void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah);
-/* RX Filter functions */
-extern void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1);
-extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah);
-extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter);
-/* ACK bit rate */
-void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, int high);
-/* ACK/CTS Timeouts */
-extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout);
-extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah);
-extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout);
-extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah);
-/* Key table (WEP) functions */
-extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry);
-
-/* Queue Control Unit, DFS Control Unit Functions */
-extern int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, const struct ath5k_txq_info *queue_info);
-extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah,
-				enum ath5k_tx_queue queue_type,
-				struct ath5k_txq_info *queue_info);
-extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah);
-extern void ath5k_hw_release_tx_queue(struct ath5k_hw *ah);
-extern int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah);
-extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
-
-/* Hardware Descriptor Functions */
-extern int ath5k_hw_init_desc_functions(struct ath5k_hw *ah);
-
-/* GPIO Functions */
-extern int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio);
-extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio);
-extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio);
-extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val);
-extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level);
-
-/* rfkill Functions */
-extern void ath5k_rfkill_hw_start(struct ath5k_hw *ah);
-extern void ath5k_rfkill_hw_stop(struct ath5k_hw *ah);
-
-/* Misc functions */
-int ath5k_hw_set_capabilities(struct ath5k_hw *ah);
-extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result);
-extern int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, u16 assoc_id);
-extern int ath5k_hw_disable_pspoll(struct ath5k_hw *ah);
-
-/* Initial register settings functions */
-extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, int change_channel);
-
-/* Initialize RF */
-extern int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
-				struct net80211_channel *channel,
-				unsigned int mode);
-extern int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq);
-extern enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah);
-extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
-/* PHY/RF channel functions */
-extern int ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
-extern int ath5k_hw_channel(struct ath5k_hw *ah, struct net80211_channel *channel);
-/* PHY calibration */
-extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct net80211_channel *channel);
-extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
-/* Misc PHY functions */
-extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
-extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant);
-extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah);
-extern int ath5k_hw_phy_disable(struct ath5k_hw *ah);
-/* TX power setup */
-extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct net80211_channel *channel, u8 ee_mode, u8 txpower);
-extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 ee_mode, u8 txpower);
-
-/*
- * Functions used internaly
- */
-
-/*
- * Translate usec to hw clock units
- * TODO: Half/quarter rate
- */
-static inline unsigned int ath5k_hw_htoclock(unsigned int usec, int turbo)
-{
-	return turbo ? (usec * 80) : (usec * 40);
-}
-
-/*
- * Translate hw clock units to usec
- * TODO: Half/quarter rate
- */
-static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, int turbo)
-{
-	return turbo ? (clock / 80) : (clock / 40);
-}
-
-/*
- * Read from a register
- */
-static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
-{
-	return readl(ah->ah_iobase + reg);
-}
-
-/*
- * Write to a register
- */
-static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
-{
-	writel(val, ah->ah_iobase + reg);
-}
-
-#if defined(_ATH5K_RESET) || defined(_ATH5K_PHY)
-/*
- * Check if a register write has been completed
- */
-static int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag,
-		u32 val, int is_set)
-{
-	int i;
-	u32 data;
-
-	for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
-		data = ath5k_hw_reg_read(ah, reg);
-		if (is_set && (data & flag))
-			break;
-		else if ((data & flag) == val)
-			break;
-		udelay(15);
-	}
-
-	return (i <= 0) ? -EAGAIN : 0;
-}
-
-/*
- * Convert channel frequency to channel number
- */
-static inline int ath5k_freq_to_channel(int freq)
-{
-	if (freq == 2484)
-		return 14;
-
-	if (freq < 2484)
-		return (freq - 2407) / 5;
-
-	return freq/5 - 1000;
-}
-
-#endif
-
-static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
-{
-	u32 retval = 0, bit, i;
-
-	for (i = 0; i < bits; i++) {
-		bit = (val >> i) & 1;
-		retval = (retval << 1) | bit;
-	}
-
-	return retval;
-}
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/ath5k/ath5k_attach.c b/roms/ipxe/src/drivers/net/ath5k/ath5k_attach.c
deleted file mode 100644
index 302536dbd093ef218e20d20ca86da33af0b4a9a5..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/ath5k_attach.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
- *
- * Modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>
- * Original from Linux kernel 2.6.30.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-FILE_LICENCE ( MIT );
-
-/*************************************\
-* Attach/Detach Functions and helpers *
-\*************************************/
-
-#include <ipxe/pci.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "ath5k.h"
-#include "reg.h"
-#include "base.h"
-
-/**
- * ath5k_hw_post - Power On Self Test helper function
- *
- * @ah: The &struct ath5k_hw
- */
-static int ath5k_hw_post(struct ath5k_hw *ah)
-{
-
-	static const u32 static_pattern[4] = {
-		0x55555555,	0xaaaaaaaa,
-		0x66666666,	0x99999999
-	};
-	static const u16 regs[2] = { AR5K_STA_ID0, AR5K_PHY(8) };
-	int i, c;
-	u16 cur_reg;
-	u32 var_pattern;
-	u32 init_val;
-	u32 cur_val;
-
-	for (c = 0; c < 2; c++) {
-
-		cur_reg = regs[c];
-
-		/* Save previous value */
-		init_val = ath5k_hw_reg_read(ah, cur_reg);
-
-		for (i = 0; i < 256; i++) {
-			var_pattern = i << 16 | i;
-			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
-			cur_val = ath5k_hw_reg_read(ah, cur_reg);
-
-			if (cur_val != var_pattern) {
-				DBG("ath5k: POST failed!\n");
-				return -EAGAIN;
-			}
-
-			/* Found on ndiswrapper dumps */
-			var_pattern = 0x0039080f;
-			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
-		}
-
-		for (i = 0; i < 4; i++) {
-			var_pattern = static_pattern[i];
-			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
-			cur_val = ath5k_hw_reg_read(ah, cur_reg);
-
-			if (cur_val != var_pattern) {
-				DBG("ath5k: POST failed!\n");
-				return -EAGAIN;
-			}
-
-			/* Found on ndiswrapper dumps */
-			var_pattern = 0x003b080f;
-			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
-		}
-
-		/* Restore previous value */
-		ath5k_hw_reg_write(ah, init_val, cur_reg);
-
-	}
-
-	return 0;
-
-}
-
-/**
- * ath5k_hw_attach - Check if hw is supported and init the needed structs
- *
- * @sc: The &struct ath5k_softc we got from the driver's attach function
- * @mac_version: The mac version id (check out ath5k.h) based on pci id
- * @hw: Returned newly allocated hardware structure, on success
- *
- * Check if the device is supported, perform a POST and initialize the needed
- * structs. Returns -ENOMEM if we don't have memory for the needed structs,
- * -ENODEV if the device is not supported or prints an error msg if something
- * else went wrong.
- */
-int ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version,
-		    struct ath5k_hw **hw)
-{
-	struct ath5k_hw *ah;
-	struct pci_device *pdev = sc->pdev;
-	int ret;
-	u32 srev;
-
-	ah = zalloc(sizeof(struct ath5k_hw));
-	if (ah == NULL) {
-		ret = -ENOMEM;
-		DBG("ath5k: out of memory\n");
-		goto err;
-	}
-
-	ah->ah_sc = sc;
-	ah->ah_iobase = sc->iobase;
-
-	/*
-	 * HW information
-	 */
-	ah->ah_turbo = 0;
-	ah->ah_txpower.txp_tpc = 0;
-	ah->ah_imr = 0;
-	ah->ah_atim_window = 0;
-	ah->ah_aifs = AR5K_TUNE_AIFS;
-	ah->ah_cw_min = AR5K_TUNE_CWMIN;
-	ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
-	ah->ah_software_retry = 0;
-	ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY;
-
-	/*
-	 * Set the mac version based on the pci id
-	 */
-	ah->ah_version = mac_version;
-
-	/*Fill the ath5k_hw struct with the needed functions*/
-	ret = ath5k_hw_init_desc_functions(ah);
-	if (ret)
-		goto err_free;
-
-	/* Bring device out of sleep and reset it's units */
-	ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, 1);
-	if (ret)
-		goto err_free;
-
-	/* Get MAC, PHY and RADIO revisions */
-	srev = ath5k_hw_reg_read(ah, AR5K_SREV);
-	ah->ah_mac_srev = srev;
-	ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
-	ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
-	ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID);
-	ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, CHANNEL_5GHZ);
-	ah->ah_phy = AR5K_PHY(0);
-
-	/* Try to identify radio chip based on it's srev */
-	switch (ah->ah_radio_5ghz_revision & 0xf0) {
-	case AR5K_SREV_RAD_5111:
-		ah->ah_radio = AR5K_RF5111;
-		ah->ah_single_chip = 0;
-		ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
-							CHANNEL_2GHZ);
-		break;
-	case AR5K_SREV_RAD_5112:
-	case AR5K_SREV_RAD_2112:
-		ah->ah_radio = AR5K_RF5112;
-		ah->ah_single_chip = 0;
-		ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
-							CHANNEL_2GHZ);
-		break;
-	case AR5K_SREV_RAD_2413:
-		ah->ah_radio = AR5K_RF2413;
-		ah->ah_single_chip = 1;
-		break;
-	case AR5K_SREV_RAD_5413:
-		ah->ah_radio = AR5K_RF5413;
-		ah->ah_single_chip = 1;
-		break;
-	case AR5K_SREV_RAD_2316:
-		ah->ah_radio = AR5K_RF2316;
-		ah->ah_single_chip = 1;
-		break;
-	case AR5K_SREV_RAD_2317:
-		ah->ah_radio = AR5K_RF2317;
-		ah->ah_single_chip = 1;
-		break;
-	case AR5K_SREV_RAD_5424:
-		if (ah->ah_mac_version == AR5K_SREV_AR2425 ||
-		    ah->ah_mac_version == AR5K_SREV_AR2417) {
-			ah->ah_radio = AR5K_RF2425;
-		} else {
-			ah->ah_radio = AR5K_RF5413;
-		}
-		ah->ah_single_chip = 1;
-		break;
-	default:
-		/* Identify radio based on mac/phy srev */
-		if (ah->ah_version == AR5K_AR5210) {
-			ah->ah_radio = AR5K_RF5110;
-			ah->ah_single_chip = 0;
-		} else if (ah->ah_version == AR5K_AR5211) {
-			ah->ah_radio = AR5K_RF5111;
-			ah->ah_single_chip = 0;
-			ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
-								CHANNEL_2GHZ);
-		} else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) ||
-			   ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) ||
-			   ah->ah_phy_revision == AR5K_SREV_PHY_2425) {
-			ah->ah_radio = AR5K_RF2425;
-			ah->ah_single_chip = 1;
-			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2425;
-		} else if (srev == AR5K_SREV_AR5213A &&
-			   ah->ah_phy_revision == AR5K_SREV_PHY_5212B) {
-			ah->ah_radio = AR5K_RF5112;
-			ah->ah_single_chip = 0;
-			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5112B;
-		} else if (ah->ah_mac_version == (AR5K_SREV_AR2415 >> 4)) {
-			ah->ah_radio = AR5K_RF2316;
-			ah->ah_single_chip = 1;
-			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2316;
-		} else if (ah->ah_mac_version == (AR5K_SREV_AR5414 >> 4) ||
-			   ah->ah_phy_revision == AR5K_SREV_PHY_5413) {
-			ah->ah_radio = AR5K_RF5413;
-			ah->ah_single_chip = 1;
-			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_5413;
-		} else if (ah->ah_mac_version == (AR5K_SREV_AR2414 >> 4) ||
-			   ah->ah_phy_revision == AR5K_SREV_PHY_2413) {
-			ah->ah_radio = AR5K_RF2413;
-			ah->ah_single_chip = 1;
-			ah->ah_radio_5ghz_revision = AR5K_SREV_RAD_2413;
-		} else {
-			DBG("ath5k: Couldn't identify radio revision.\n");
-			ret = -ENOTSUP;
-			goto err_free;
-		}
-	}
-
-	/* Return on unsuported chips (unsupported eeprom etc) */
-	if ((srev >= AR5K_SREV_AR5416) &&
-	    (srev < AR5K_SREV_AR2425)) {
-		DBG("ath5k: Device not yet supported.\n");
-		ret = -ENOTSUP;
-		goto err_free;
-	}
-
-	/*
-	 * Write PCI-E power save settings
-	 */
-	if ((ah->ah_version == AR5K_AR5212) &&
-	    pci_find_capability(pdev, PCI_CAP_ID_EXP)) {
-		ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
-		ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
-		/* Shut off RX when elecidle is asserted */
-		ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES);
-		ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES);
-		/* TODO: EEPROM work */
-		ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES);
-		/* Shut off PLL and CLKREQ active in L1 */
-		ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES);
-		/* Preserce other settings */
-		ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES);
-		ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES);
-		ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES);
-		/* Reset SERDES to load new settings */
-		ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET);
-		mdelay(1);
-	}
-
-	/*
-	 * POST
-	 */
-	ret = ath5k_hw_post(ah);
-	if (ret)
-		goto err_free;
-
-	/* Enable pci core retry fix on Hainan (5213A) and later chips */
-	if (srev >= AR5K_SREV_AR5213A)
-		ath5k_hw_reg_write(ah, AR5K_PCICFG_RETRY_FIX, AR5K_PCICFG);
-
-	/*
-	 * Get card capabilities, calibration values etc
-	 * TODO: EEPROM work
-	 */
-	ret = ath5k_eeprom_init(ah);
-	if (ret) {
-		DBG("ath5k: unable to init EEPROM\n");
-		goto err_free;
-	}
-
-	/* Get misc capabilities */
-	ret = ath5k_hw_set_capabilities(ah);
-	if (ret) {
-		DBG("ath5k: unable to get device capabilities: 0x%04x\n",
-		    sc->pdev->device);
-		goto err_free;
-	}
-
-	if (srev >= AR5K_SREV_AR2414) {
-		ah->ah_combined_mic = 1;
-		AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE,
-				     AR5K_MISC_MODE_COMBINED_MIC);
-	}
-
-	/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
-	memset(ah->ah_bssid, 0xff, ETH_ALEN);
-	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
-	ath5k_hw_set_opmode(ah);
-
-	ath5k_hw_rfgain_opt_init(ah);
-
-	*hw = ah;
-	return 0;
-err_free:
-	free(ah);
-err:
-	return ret;
-}
-
-/**
- * ath5k_hw_detach - Free the ath5k_hw struct
- *
- * @ah: The &struct ath5k_hw
- */
-void ath5k_hw_detach(struct ath5k_hw *ah)
-{
-	free(ah->ah_rf_banks);
-	ath5k_eeprom_detach(ah);
-	free(ah);
-}
diff --git a/roms/ipxe/src/drivers/net/ath5k/ath5k_caps.c b/roms/ipxe/src/drivers/net/ath5k/ath5k_caps.c
deleted file mode 100644
index 9c00d15d771b166f587b365305aed2ecb6a33171..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/ath5k_caps.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
- * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
- *
- * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-FILE_LICENCE ( MIT );
-
-/**************\
-* Capabilities *
-\**************/
-
-#include "ath5k.h"
-#include "reg.h"
-#include "base.h"
-
-/*
- * Fill the capabilities struct
- * TODO: Merge this with EEPROM code when we are done with it
- */
-int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
-{
-	u16 ee_header;
-
-	/* Capabilities stored in the EEPROM */
-	ee_header = ah->ah_capabilities.cap_eeprom.ee_header;
-
-	if (ah->ah_version == AR5K_AR5210) {
-		/*
-		 * Set radio capabilities
-		 * (The AR5110 only supports the middle 5GHz band)
-		 */
-		ah->ah_capabilities.cap_range.range_5ghz_min = 5120;
-		ah->ah_capabilities.cap_range.range_5ghz_max = 5430;
-		ah->ah_capabilities.cap_range.range_2ghz_min = 0;
-		ah->ah_capabilities.cap_range.range_2ghz_max = 0;
-
-		/* Set supported modes */
-		ah->ah_capabilities.cap_mode |= AR5K_MODE_BIT_11A;
-		ah->ah_capabilities.cap_mode |= AR5K_MODE_BIT_11A_TURBO;
-	} else {
-		/*
-		 * XXX The tranceiver supports frequencies from 4920 to 6100GHz
-		 * XXX and from 2312 to 2732GHz. There are problems with the
-		 * XXX current ieee80211 implementation because the IEEE
-		 * XXX channel mapping does not support negative channel
-		 * XXX numbers (2312MHz is channel -19). Of course, this
-		 * XXX doesn't matter because these channels are out of range
-		 * XXX but some regulation domains like MKK (Japan) will
-		 * XXX support frequencies somewhere around 4.8GHz.
-		 */
-
-		/*
-		 * Set radio capabilities
-		 */
-
-		if (AR5K_EEPROM_HDR_11A(ee_header)) {
-			/* 4920 */
-			ah->ah_capabilities.cap_range.range_5ghz_min = 5005;
-			ah->ah_capabilities.cap_range.range_5ghz_max = 6100;
-
-			/* Set supported modes */
-			ah->ah_capabilities.cap_mode |= AR5K_MODE_BIT_11A;
-			ah->ah_capabilities.cap_mode |= AR5K_MODE_BIT_11A_TURBO;
-			if (ah->ah_version == AR5K_AR5212)
-				ah->ah_capabilities.cap_mode |=
-					AR5K_MODE_BIT_11G_TURBO;
-		}
-
-		/* Enable  802.11b if a 2GHz capable radio (2111/5112) is
-		 * connected */
-		if (AR5K_EEPROM_HDR_11B(ee_header) ||
-		    (AR5K_EEPROM_HDR_11G(ee_header) &&
-		     ah->ah_version != AR5K_AR5211)) {
-			/* 2312 */
-			ah->ah_capabilities.cap_range.range_2ghz_min = 2412;
-			ah->ah_capabilities.cap_range.range_2ghz_max = 2732;
-
-			if (AR5K_EEPROM_HDR_11B(ee_header))
-				ah->ah_capabilities.cap_mode |=
-					AR5K_MODE_BIT_11B;
-
-			if (AR5K_EEPROM_HDR_11G(ee_header) &&
-			    ah->ah_version != AR5K_AR5211)
-				ah->ah_capabilities.cap_mode |=
-					AR5K_MODE_BIT_11G;
-		}
-	}
-
-	/* GPIO */
-	ah->ah_gpio_npins = AR5K_NUM_GPIO;
-
-	/* Set number of supported TX queues */
-	ah->ah_capabilities.cap_queues.q_tx_num = 1;
-
-	return 0;
-}
-
-/* Main function used by the driver part to check caps */
-int ath5k_hw_get_capability(struct ath5k_hw *ah,
-		enum ath5k_capability_type cap_type,
-		u32 capability __unused, u32 *result)
-{
-	switch (cap_type) {
-	case AR5K_CAP_NUM_TXQUEUES:
-		if (result) {
-			*result = 1;
-			goto yes;
-		}
-	case AR5K_CAP_VEOL:
-		goto yes;
-	case AR5K_CAP_COMPRESSION:
-		if (ah->ah_version == AR5K_AR5212)
-			goto yes;
-		else
-			goto no;
-	case AR5K_CAP_BURST:
-		goto yes;
-	case AR5K_CAP_TPC:
-		goto yes;
-	case AR5K_CAP_BSSIDMASK:
-		if (ah->ah_version == AR5K_AR5212)
-			goto yes;
-		else
-			goto no;
-	case AR5K_CAP_XR:
-		if (ah->ah_version == AR5K_AR5212)
-			goto yes;
-		else
-			goto no;
-	default:
-		goto no;
-	}
-
-no:
-	return -EINVAL;
-yes:
-	return 0;
-}
diff --git a/roms/ipxe/src/drivers/net/ath5k/ath5k_desc.c b/roms/ipxe/src/drivers/net/ath5k/ath5k_desc.c
deleted file mode 100644
index 30fe1c77704a7988f69190b327ea488fda349f29..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/ath5k_desc.c
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
- * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
- *
- * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-FILE_LICENCE ( MIT );
-
-/******************************\
- Hardware Descriptor Functions
-\******************************/
-
-#include "ath5k.h"
-#include "reg.h"
-#include "base.h"
-
-/*
- * TX Descriptors
- */
-
-#define FCS_LEN	4
-
-/*
- * Initialize the 2-word tx control descriptor on 5210/5211
- */
-static int
-ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
-	unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type,
-	unsigned int tx_power __unused, unsigned int tx_rate0, unsigned int tx_tries0,
-	unsigned int key_index __unused, unsigned int antenna_mode, unsigned int flags,
-	unsigned int rtscts_rate __unused, unsigned int rtscts_duration)
-{
-	u32 frame_type;
-	struct ath5k_hw_2w_tx_ctl *tx_ctl;
-	unsigned int frame_len;
-
-	tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
-
-	/*
-	 * Validate input
-	 * - Zero retries don't make sense.
-	 * - A zero rate will put the HW into a mode where it continously sends
-	 *   noise on the channel, so it is important to avoid this.
-	 */
-	if (tx_tries0 == 0) {
-		DBG("ath5k: zero retries\n");
-		return -EINVAL;
-	}
-	if (tx_rate0 == 0) {
-		DBG("ath5k: zero rate\n");
-		return -EINVAL;
-	}
-
-	/* Clear descriptor */
-	memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc));
-
-	/* Setup control descriptor */
-
-	/* Verify and set frame length */
-
-	frame_len = pkt_len + FCS_LEN;
-
-	if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
-		return -EINVAL;
-
-	tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
-
-	/* Verify and set buffer length */
-
-	if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
-		return -EINVAL;
-
-	tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
-
-	/*
-	 * Verify and set header length
-	 * XXX: I only found that on 5210 code, does it work on 5211 ?
-	 */
-	if (ah->ah_version == AR5K_AR5210) {
-		if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN)
-			return -EINVAL;
-		tx_ctl->tx_control_0 |=
-			AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN);
-	}
-
-	/*Diferences between 5210-5211*/
-	if (ah->ah_version == AR5K_AR5210) {
-		switch (type) {
-		case AR5K_PKT_TYPE_BEACON:
-		case AR5K_PKT_TYPE_PROBE_RESP:
-			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY;
-		case AR5K_PKT_TYPE_PIFS:
-			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS;
-		default:
-			frame_type = type /*<< 2 ?*/;
-		}
-
-		tx_ctl->tx_control_0 |=
-		AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) |
-		AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
-
-	} else {
-		tx_ctl->tx_control_0 |=
-			AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) |
-			AR5K_REG_SM(antenna_mode,
-				AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT);
-		tx_ctl->tx_control_1 |=
-			AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE);
-	}
-#define _TX_FLAGS(_c, _flag)					\
-	if (flags & AR5K_TXDESC_##_flag) {			\
-		tx_ctl->tx_control_##_c |=			\
-			AR5K_2W_TX_DESC_CTL##_c##_##_flag;	\
-	}
-
-	_TX_FLAGS(0, CLRDMASK);
-	_TX_FLAGS(0, VEOL);
-	_TX_FLAGS(0, INTREQ);
-	_TX_FLAGS(0, RTSENA);
-	_TX_FLAGS(1, NOACK);
-
-#undef _TX_FLAGS
-
-	/*
-	 * RTS/CTS Duration [5210 ?]
-	 */
-	if ((ah->ah_version == AR5K_AR5210) &&
-			(flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)))
-		tx_ctl->tx_control_1 |= rtscts_duration &
-				AR5K_2W_TX_DESC_CTL1_RTS_DURATION;
-
-	return 0;
-}
-
-/*
- * Initialize the 4-word tx control descriptor on 5212
- */
-static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
-	struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len __unused,
-	enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0,
-	unsigned int tx_tries0, unsigned int key_index __unused,
-	unsigned int antenna_mode, unsigned int flags,
-	unsigned int rtscts_rate,
-	unsigned int rtscts_duration)
-{
-	struct ath5k_hw_4w_tx_ctl *tx_ctl;
-	unsigned int frame_len;
-
-	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
-
-	/*
-	 * Validate input
-	 * - Zero retries don't make sense.
-	 * - A zero rate will put the HW into a mode where it continously sends
-	 *   noise on the channel, so it is important to avoid this.
-	 */
-	if (tx_tries0 == 0) {
-		DBG("ath5k: zero retries\n");
-		return -EINVAL;
-	}
-	if (tx_rate0 == 0) {
-		DBG("ath5k: zero rate\n");
-		return -EINVAL;
-	}
-
-	tx_power += ah->ah_txpower.txp_offset;
-	if (tx_power > AR5K_TUNE_MAX_TXPOWER)
-		tx_power = AR5K_TUNE_MAX_TXPOWER;
-
-	/* Clear descriptor */
-	memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc));
-
-	/* Setup control descriptor */
-
-	/* Verify and set frame length */
-
-	frame_len = pkt_len + FCS_LEN;
-
-	if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
-		return -EINVAL;
-
-	tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
-
-	/* Verify and set buffer length */
-
-	if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
-		return -EINVAL;
-
-	tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
-
-	tx_ctl->tx_control_0 |=
-		AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
-		AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
-	tx_ctl->tx_control_1 |= AR5K_REG_SM(type,
-					AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
-	tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES,
-					AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
-	tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
-
-#define _TX_FLAGS(_c, _flag)					\
-	if (flags & AR5K_TXDESC_##_flag) {			\
-		tx_ctl->tx_control_##_c |=			\
-			AR5K_4W_TX_DESC_CTL##_c##_##_flag;	\
-	}
-
-	_TX_FLAGS(0, CLRDMASK);
-	_TX_FLAGS(0, VEOL);
-	_TX_FLAGS(0, INTREQ);
-	_TX_FLAGS(0, RTSENA);
-	_TX_FLAGS(0, CTSENA);
-	_TX_FLAGS(1, NOACK);
-
-#undef _TX_FLAGS
-
-	/*
-	 * RTS/CTS
-	 */
-	if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) {
-		if ((flags & AR5K_TXDESC_RTSENA) &&
-				(flags & AR5K_TXDESC_CTSENA))
-			return -EINVAL;
-		tx_ctl->tx_control_2 |= rtscts_duration &
-				AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
-		tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
-				AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
-	}
-
-	return 0;
-}
-
-/*
- * Proccess the tx status descriptor on 5210/5211
- */
-static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah __unused,
-		struct ath5k_desc *desc, struct ath5k_tx_status *ts)
-{
-	struct ath5k_hw_2w_tx_ctl *tx_ctl;
-	struct ath5k_hw_tx_status *tx_status;
-
-	tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
-	tx_status = &desc->ud.ds_tx5210.tx_stat;
-
-	/* No frame has been send or error */
-	if ((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)
-		return -EINPROGRESS;
-
-	/*
-	 * Get descriptor status
-	 */
-	ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
-		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
-	ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
-		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
-	ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
-		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
-	/*TODO: ts->ts_virtcol + test*/
-	ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
-		AR5K_DESC_TX_STATUS1_SEQ_NUM);
-	ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
-		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
-	ts->ts_antenna = 1;
-	ts->ts_status = 0;
-	ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0,
-		AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
-	ts->ts_retry[0] = ts->ts_longretry;
-	ts->ts_final_idx = 0;
-
-	if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
-		if (tx_status->tx_status_0 &
-				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
-			ts->ts_status |= AR5K_TXERR_XRETRY;
-
-		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
-			ts->ts_status |= AR5K_TXERR_FIFO;
-
-		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
-			ts->ts_status |= AR5K_TXERR_FILT;
-	}
-
-	return 0;
-}
-
-/*
- * Proccess a tx status descriptor on 5212
- */
-static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah __unused,
-		struct ath5k_desc *desc, struct ath5k_tx_status *ts)
-{
-	struct ath5k_hw_4w_tx_ctl *tx_ctl;
-	struct ath5k_hw_tx_status *tx_status;
-
-	tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
-	tx_status = &desc->ud.ds_tx5212.tx_stat;
-
-	/* No frame has been send or error */
-	if (!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE))
-		return -EINPROGRESS;
-
-	/*
-	 * Get descriptor status
-	 */
-	ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
-		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
-	ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
-		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
-	ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
-		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
-	ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
-		AR5K_DESC_TX_STATUS1_SEQ_NUM);
-	ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
-		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
-	ts->ts_antenna = (tx_status->tx_status_1 &
-		AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
-	ts->ts_status = 0;
-
-	ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1,
-			AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX);
-
-	ts->ts_retry[0] = ts->ts_longretry;
-	ts->ts_rate[0] = tx_ctl->tx_control_3 &
-		AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
-
-	/* TX error */
-	if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
-		if (tx_status->tx_status_0 &
-				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
-			ts->ts_status |= AR5K_TXERR_XRETRY;
-
-		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
-			ts->ts_status |= AR5K_TXERR_FIFO;
-
-		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
-			ts->ts_status |= AR5K_TXERR_FILT;
-	}
-
-	return 0;
-}
-
-/*
- * RX Descriptors
- */
-
-/*
- * Initialize an rx control descriptor
- */
-static int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah __unused,
-				  struct ath5k_desc *desc,
-				  u32 size, unsigned int flags)
-{
-	struct ath5k_hw_rx_ctl *rx_ctl;
-
-	rx_ctl = &desc->ud.ds_rx.rx_ctl;
-
-	/*
-	 * Clear the descriptor
-	 * If we don't clean the status descriptor,
-	 * while scanning we get too many results,
-	 * most of them virtual, after some secs
-	 * of scanning system hangs. M.F.
-	*/
-	memset(&desc->ud.ds_rx, 0, sizeof(struct ath5k_hw_all_rx_desc));
-
-	/* Setup descriptor */
-	rx_ctl->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
-	if (rx_ctl->rx_control_1 != size)
-		return -EINVAL;
-
-	if (flags & AR5K_RXDESC_INTREQ)
-		rx_ctl->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
-
-	return 0;
-}
-
-/*
- * Proccess the rx status descriptor on 5210/5211
- */
-static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah __unused,
-		struct ath5k_desc *desc, struct ath5k_rx_status *rs)
-{
-	struct ath5k_hw_rx_status *rx_status;
-
-	rx_status = &desc->ud.ds_rx.u.rx_stat;
-
-	/* No frame received / not ready */
-	if (!(rx_status->rx_status_1 & AR5K_5210_RX_DESC_STATUS1_DONE))
-		return -EINPROGRESS;
-
-	/*
-	 * Frame receive status
-	 */
-	rs->rs_datalen = rx_status->rx_status_0 &
-		AR5K_5210_RX_DESC_STATUS0_DATA_LEN;
-	rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
-		AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL);
-	rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
-		AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE);
-	rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
-		AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA);
-	rs->rs_more = !!(rx_status->rx_status_0 &
-		AR5K_5210_RX_DESC_STATUS0_MORE);
-	/* TODO: this timestamp is 13 bit, later on we assume 15 bit */
-	rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
-		AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
-	rs->rs_status = 0;
-	rs->rs_phyerr = 0;
-	rs->rs_keyix = AR5K_RXKEYIX_INVALID;
-
-	/*
-	 * Receive/descriptor errors
-	 */
-	if (!(rx_status->rx_status_1 &
-	      AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
-		if (rx_status->rx_status_1 &
-				AR5K_5210_RX_DESC_STATUS1_CRC_ERROR)
-			rs->rs_status |= AR5K_RXERR_CRC;
-
-		if (rx_status->rx_status_1 &
-				AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN)
-			rs->rs_status |= AR5K_RXERR_FIFO;
-
-		if (rx_status->rx_status_1 &
-				AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) {
-			rs->rs_status |= AR5K_RXERR_PHY;
-			rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1,
-				AR5K_5210_RX_DESC_STATUS1_PHY_ERROR);
-		}
-
-		if (rx_status->rx_status_1 &
-				AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
-			rs->rs_status |= AR5K_RXERR_DECRYPT;
-	}
-
-	return 0;
-}
-
-/*
- * Proccess the rx status descriptor on 5212
- */
-static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah __unused,
-		struct ath5k_desc *desc, struct ath5k_rx_status *rs)
-{
-	struct ath5k_hw_rx_status *rx_status;
-	struct ath5k_hw_rx_error *rx_err;
-
-	rx_status = &desc->ud.ds_rx.u.rx_stat;
-
-	/* Overlay on error */
-	rx_err = &desc->ud.ds_rx.u.rx_err;
-
-	/* No frame received / not ready */
-	if (!(rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_DONE))
-		return -EINPROGRESS;
-
-	/*
-	 * Frame receive status
-	 */
-	rs->rs_datalen = rx_status->rx_status_0 &
-		AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
-	rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
-		AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL);
-	rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
-		AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE);
-	rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
-		AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA);
-	rs->rs_more = !!(rx_status->rx_status_0 &
-		AR5K_5212_RX_DESC_STATUS0_MORE);
-	rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
-		AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
-	rs->rs_status = 0;
-	rs->rs_phyerr = 0;
-	rs->rs_keyix = AR5K_RXKEYIX_INVALID;
-
-	/*
-	 * Receive/descriptor errors
-	 */
-	if (!(rx_status->rx_status_1 &
-	      AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
-		if (rx_status->rx_status_1 &
-				AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
-			rs->rs_status |= AR5K_RXERR_CRC;
-
-		if (rx_status->rx_status_1 &
-				AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
-			rs->rs_status |= AR5K_RXERR_PHY;
-			rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1,
-					   AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
-		}
-
-		if (rx_status->rx_status_1 &
-				AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
-			rs->rs_status |= AR5K_RXERR_DECRYPT;
-
-		if (rx_status->rx_status_1 &
-				AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
-			rs->rs_status |= AR5K_RXERR_MIC;
-	}
-
-	return 0;
-}
-
-/*
- * Init function pointers inside ath5k_hw struct
- */
-int ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
-{
-
-	if (ah->ah_version != AR5K_AR5210 &&
-	    ah->ah_version != AR5K_AR5211 &&
-	    ah->ah_version != AR5K_AR5212)
-		return -ENOTSUP;
-
-	if (ah->ah_version == AR5K_AR5212) {
-		ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
-		ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;
-		ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status;
-	} else {
-		ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
-		ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
-		ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
-	}
-
-	if (ah->ah_version == AR5K_AR5212)
-		ah->ah_proc_rx_desc = ath5k_hw_proc_5212_rx_status;
-	else if (ah->ah_version <= AR5K_AR5211)
-		ah->ah_proc_rx_desc = ath5k_hw_proc_5210_rx_status;
-
-	return 0;
-}
-
diff --git a/roms/ipxe/src/drivers/net/ath5k/ath5k_dma.c b/roms/ipxe/src/drivers/net/ath5k/ath5k_dma.c
deleted file mode 100644
index fa1e0d013469da663cdeed269191fe3e1689b02c..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/ath5k_dma.c
+++ /dev/null
@@ -1,631 +0,0 @@
-/*
- * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
- *
- * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-FILE_LICENCE ( MIT );
-
-/*************************************\
-* DMA and interrupt masking functions *
-\*************************************/
-
-/*
- * dma.c - DMA and interrupt masking functions
- *
- * Here we setup descriptor pointers (rxdp/txdp) start/stop dma engine and
- * handle queue setup for 5210 chipset (rest are handled on qcu.c).
- * Also we setup interrupt mask register (IMR) and read the various iterrupt
- * status registers (ISR).
- *
- * TODO: Handle SISR on 5211+ and introduce a function to return the queue
- * number that resulted the interrupt.
- */
-
-#include <unistd.h>
-
-#include "ath5k.h"
-#include "reg.h"
-#include "base.h"
-
-/*********\
-* Receive *
-\*********/
-
-/**
- * ath5k_hw_start_rx_dma - Start DMA receive
- *
- * @ah:	The &struct ath5k_hw
- */
-void ath5k_hw_start_rx_dma(struct ath5k_hw *ah)
-{
-	ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
-	ath5k_hw_reg_read(ah, AR5K_CR);
-}
-
-/**
- * ath5k_hw_stop_rx_dma - Stop DMA receive
- *
- * @ah:	The &struct ath5k_hw
- */
-int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
-{
-	unsigned int i;
-
-	ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR);
-
-	/*
-	 * It may take some time to disable the DMA receive unit
-	 */
-	for (i = 1000; i > 0 &&
-			(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0;
-			i--)
-		udelay(10);
-
-	return i ? 0 : -EBUSY;
-}
-
-/**
- * ath5k_hw_get_rxdp - Get RX Descriptor's address
- *
- * @ah: The &struct ath5k_hw
- *
- * XXX: Is RXDP read and clear ?
- */
-u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah)
-{
-	return ath5k_hw_reg_read(ah, AR5K_RXDP);
-}
-
-/**
- * ath5k_hw_set_rxdp - Set RX Descriptor's address
- *
- * @ah: The &struct ath5k_hw
- * @phys_addr: RX descriptor address
- *
- * XXX: Should we check if rx is enabled before setting rxdp ?
- */
-void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
-{
-	ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
-}
-
-
-/**********\
-* Transmit *
-\**********/
-
-/**
- * ath5k_hw_start_tx_dma - Start DMA transmit for a specific queue
- *
- * @ah: The &struct ath5k_hw
- * @queue: The hw queue number
- *
- * Start DMA transmit for a specific queue and since 5210 doesn't have
- * QCU/DCU, set up queue parameters for 5210 here based on queue type (one
- * queue for normal data and one queue for beacons). For queue setup
- * on newer chips check out qcu.c. Returns -EINVAL if queue number is out
- * of range or if queue is already disabled.
- *
- * NOTE: Must be called after setting up tx control descriptor for that
- * queue (see below).
- */
-int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
-{
-	u32 tx_queue;
-
-	/* Return if queue is declared inactive */
-	if (ah->ah_txq.tqi_type == AR5K_TX_QUEUE_INACTIVE)
-		return -EIO;
-
-	if (ah->ah_version == AR5K_AR5210) {
-		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
-
-		/* Assume always a data queue */
-		tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0;
-
-		/* Start queue */
-		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
-		ath5k_hw_reg_read(ah, AR5K_CR);
-	} else {
-		/* Return if queue is disabled */
-		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue))
-			return -EIO;
-
-		/* Start queue */
-		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue);
-	}
-
-	return 0;
-}
-
-/**
- * ath5k_hw_stop_tx_dma - Stop DMA transmit on a specific queue
- *
- * @ah: The &struct ath5k_hw
- * @queue: The hw queue number
- *
- * Stop DMA transmit on a specific hw queue and drain queue so we don't
- * have any pending frames. Returns -EBUSY if we still have pending frames,
- * -EINVAL if queue number is out of range.
- *
- */
-int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
-{
-	unsigned int i = 40;
-	u32 tx_queue, pending;
-
-	/* Return if queue is declared inactive */
-	if (ah->ah_txq.tqi_type == AR5K_TX_QUEUE_INACTIVE)
-		return -EIO;
-
-	if (ah->ah_version == AR5K_AR5210) {
-		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
-
-		/* Assume a data queue */
-		tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0;
-
-		/* Stop queue */
-		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
-		ath5k_hw_reg_read(ah, AR5K_CR);
-	} else {
-		/*
-		 * Schedule TX disable and wait until queue is empty
-		 */
-		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue);
-
-		/*Check for pending frames*/
-		do {
-			pending = ath5k_hw_reg_read(ah,
-				AR5K_QUEUE_STATUS(queue)) &
-				AR5K_QCU_STS_FRMPENDCNT;
-			udelay(100);
-		} while (--i && pending);
-
-		/* For 2413+ order PCU to drop packets using
-		 * QUIET mechanism */
-		if (ah->ah_mac_version >= (AR5K_SREV_AR2414 >> 4) && pending) {
-			/* Set periodicity and duration */
-			ath5k_hw_reg_write(ah,
-				AR5K_REG_SM(100, AR5K_QUIET_CTL2_QT_PER)|
-				AR5K_REG_SM(10, AR5K_QUIET_CTL2_QT_DUR),
-				AR5K_QUIET_CTL2);
-
-			/* Enable quiet period for current TSF */
-			ath5k_hw_reg_write(ah,
-				AR5K_QUIET_CTL1_QT_EN |
-				AR5K_REG_SM(ath5k_hw_reg_read(ah,
-						AR5K_TSF_L32_5211) >> 10,
-						AR5K_QUIET_CTL1_NEXT_QT_TSF),
-				AR5K_QUIET_CTL1);
-
-			/* Force channel idle high */
-			AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
-					AR5K_DIAG_SW_CHANEL_IDLE_HIGH);
-
-			/* Wait a while and disable mechanism */
-			udelay(200);
-			AR5K_REG_DISABLE_BITS(ah, AR5K_QUIET_CTL1,
-						AR5K_QUIET_CTL1_QT_EN);
-
-			/* Re-check for pending frames */
-			i = 40;
-			do {
-				pending = ath5k_hw_reg_read(ah,
-					AR5K_QUEUE_STATUS(queue)) &
-					AR5K_QCU_STS_FRMPENDCNT;
-				udelay(100);
-			} while (--i && pending);
-
-			AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211,
-					AR5K_DIAG_SW_CHANEL_IDLE_HIGH);
-		}
-
-		/* Clear register */
-		ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
-		if (pending)
-			return -EBUSY;
-	}
-
-	/* TODO: Check for success on 5210 else return error */
-	return 0;
-}
-
-/**
- * ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue
- *
- * @ah: The &struct ath5k_hw
- * @queue: The hw queue number
- *
- * Get TX descriptor's address for a specific queue. For 5210 we ignore
- * the queue number and use tx queue type since we only have 2 queues.
- * We use TXDP0 for normal data queue and TXDP1 for beacon queue.
- * For newer chips with QCU/DCU we just read the corresponding TXDP register.
- *
- * XXX: Is TXDP read and clear ?
- */
-u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
-{
-	u16 tx_reg;
-
-	/*
-	 * Get the transmit queue descriptor pointer from the selected queue
-	 */
-	/*5210 doesn't have QCU*/
-	if (ah->ah_version == AR5K_AR5210) {
-		/* Assume a data queue */
-		tx_reg = AR5K_NOQCU_TXDP0;
-	} else {
-		tx_reg = AR5K_QUEUE_TXDP(queue);
-	}
-
-	return ath5k_hw_reg_read(ah, tx_reg);
-}
-
-/**
- * ath5k_hw_set_txdp - Set TX Descriptor's address for a specific queue
- *
- * @ah: The &struct ath5k_hw
- * @queue: The hw queue number
- *
- * Set TX descriptor's address for a specific queue. For 5210 we ignore
- * the queue number and we use tx queue type since we only have 2 queues
- * so as above we use TXDP0 for normal data queue and TXDP1 for beacon queue.
- * For newer chips with QCU/DCU we just set the corresponding TXDP register.
- * Returns -EINVAL if queue type is invalid for 5210 and -EIO if queue is still
- * active.
- */
-int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
-{
-	u16 tx_reg;
-
-	/*
-	 * Set the transmit queue descriptor pointer register by type
-	 * on 5210
-	 */
-	if (ah->ah_version == AR5K_AR5210) {
-		/* Assume a data queue */
-		tx_reg = AR5K_NOQCU_TXDP0;
-	} else {
-		/*
-		 * Set the transmit queue descriptor pointer for
-		 * the selected queue on QCU for 5211+
-		 * (this won't work if the queue is still active)
-		 */
-		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
-			return -EIO;
-
-		tx_reg = AR5K_QUEUE_TXDP(queue);
-	}
-
-	/* Set descriptor pointer */
-	ath5k_hw_reg_write(ah, phys_addr, tx_reg);
-
-	return 0;
-}
-
-/**
- * ath5k_hw_update_tx_triglevel - Update tx trigger level
- *
- * @ah: The &struct ath5k_hw
- * @increase: Flag to force increase of trigger level
- *
- * This function increases/decreases the tx trigger level for the tx fifo
- * buffer (aka FIFO threshold) that is used to indicate when PCU flushes
- * the buffer and transmits it's data. Lowering this results sending small
- * frames more quickly but can lead to tx underruns, raising it a lot can
- * result other problems (i think bmiss is related). Right now we start with
- * the lowest possible (64Bytes) and if we get tx underrun we increase it using
- * the increase flag. Returns -EIO if we have have reached maximum/minimum.
- *
- * XXX: Link this with tx DMA size ?
- * XXX: Use it to save interrupts ?
- * TODO: Needs testing, i think it's related to bmiss...
- */
-int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, int increase)
-{
-	u32 trigger_level, imr;
-	int ret = -EIO;
-
-	/*
-	 * Disable interrupts by setting the mask
-	 */
-	imr = ath5k_hw_set_imr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL);
-
-	trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG),
-			AR5K_TXCFG_TXFULL);
-
-	if (!increase) {
-		if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES)
-			goto done;
-	} else
-		trigger_level +=
-			((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2);
-
-	/*
-	 * Update trigger level on success
-	 */
-	if (ah->ah_version == AR5K_AR5210)
-		ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL);
-	else
-		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
-				AR5K_TXCFG_TXFULL, trigger_level);
-
-	ret = 0;
-
-done:
-	/*
-	 * Restore interrupt mask
-	 */
-	ath5k_hw_set_imr(ah, imr);
-
-	return ret;
-}
-
-/*******************\
-* Interrupt masking *
-\*******************/
-
-/**
- * ath5k_hw_is_intr_pending - Check if we have pending interrupts
- *
- * @ah: The &struct ath5k_hw
- *
- * Check if we have pending interrupts to process. Returns 1 if we
- * have pending interrupts and 0 if we haven't.
- */
-int ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
-{
-	return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0;
-}
-
-/**
- * ath5k_hw_get_isr - Get interrupt status
- *
- * @ah: The @struct ath5k_hw
- * @interrupt_mask: Driver's interrupt mask used to filter out
- * interrupts in sw.
- *
- * This function is used inside our interrupt handler to determine the reason
- * for the interrupt by reading Primary Interrupt Status Register. Returns an
- * abstract interrupt status mask which is mostly ISR with some uncommon bits
- * being mapped on some standard non hw-specific positions
- * (check out &ath5k_int).
- *
- * NOTE: We use read-and-clear register, so after this function is called ISR
- * is zeroed.
- */
-int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
-{
-	u32 data;
-
-	/*
-	 * Read interrupt status from the Interrupt Status register
-	 * on 5210
-	 */
-	if (ah->ah_version == AR5K_AR5210) {
-		data = ath5k_hw_reg_read(ah, AR5K_ISR);
-		if (data == AR5K_INT_NOCARD) {
-			*interrupt_mask = data;
-			return -ENODEV;
-		}
-	} else {
-		/*
-		 * Read interrupt status from Interrupt
-		 * Status Register shadow copy (Read And Clear)
-		 *
-		 * Note: PISR/SISR Not available on 5210
-		 */
-		data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR);
-		if (data == AR5K_INT_NOCARD) {
-			*interrupt_mask = data;
-			return -ENODEV;
-		}
-	}
-
-	/*
-	 * Get abstract interrupt mask (driver-compatible)
-	 */
-	*interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr;
-
-	if (ah->ah_version != AR5K_AR5210) {
-		u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2);
-
-		/*HIU = Host Interface Unit (PCI etc)*/
-		if (data & (AR5K_ISR_HIUERR))
-			*interrupt_mask |= AR5K_INT_FATAL;
-
-		/*Beacon Not Ready*/
-		if (data & (AR5K_ISR_BNR))
-			*interrupt_mask |= AR5K_INT_BNR;
-
-		if (sisr2 & (AR5K_SISR2_SSERR | AR5K_SISR2_DPERR |
-			     AR5K_SISR2_MCABT))
-			*interrupt_mask |= AR5K_INT_FATAL;
-
-		if (data & AR5K_ISR_TIM)
-			*interrupt_mask |= AR5K_INT_TIM;
-
-		if (data & AR5K_ISR_BCNMISC) {
-			if (sisr2 & AR5K_SISR2_TIM)
-				*interrupt_mask |= AR5K_INT_TIM;
-			if (sisr2 & AR5K_SISR2_DTIM)
-				*interrupt_mask |= AR5K_INT_DTIM;
-			if (sisr2 & AR5K_SISR2_DTIM_SYNC)
-				*interrupt_mask |= AR5K_INT_DTIM_SYNC;
-			if (sisr2 & AR5K_SISR2_BCN_TIMEOUT)
-				*interrupt_mask |= AR5K_INT_BCN_TIMEOUT;
-			if (sisr2 & AR5K_SISR2_CAB_TIMEOUT)
-				*interrupt_mask |= AR5K_INT_CAB_TIMEOUT;
-		}
-
-		if (data & AR5K_ISR_RXDOPPLER)
-			*interrupt_mask |= AR5K_INT_RX_DOPPLER;
-		if (data & AR5K_ISR_QCBRORN) {
-			*interrupt_mask |= AR5K_INT_QCBRORN;
-			ah->ah_txq_isr |= AR5K_REG_MS(
-					ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
-					AR5K_SISR3_QCBRORN);
-		}
-		if (data & AR5K_ISR_QCBRURN) {
-			*interrupt_mask |= AR5K_INT_QCBRURN;
-			ah->ah_txq_isr |= AR5K_REG_MS(
-					ath5k_hw_reg_read(ah, AR5K_RAC_SISR3),
-					AR5K_SISR3_QCBRURN);
-		}
-		if (data & AR5K_ISR_QTRIG) {
-			*interrupt_mask |= AR5K_INT_QTRIG;
-			ah->ah_txq_isr |= AR5K_REG_MS(
-					ath5k_hw_reg_read(ah, AR5K_RAC_SISR4),
-					AR5K_SISR4_QTRIG);
-		}
-
-		if (data & AR5K_ISR_TXOK)
-			ah->ah_txq_isr |= AR5K_REG_MS(
-					ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
-					AR5K_SISR0_QCU_TXOK);
-
-		if (data & AR5K_ISR_TXDESC)
-			ah->ah_txq_isr |= AR5K_REG_MS(
-					ath5k_hw_reg_read(ah, AR5K_RAC_SISR0),
-					AR5K_SISR0_QCU_TXDESC);
-
-		if (data & AR5K_ISR_TXERR)
-			ah->ah_txq_isr |= AR5K_REG_MS(
-					ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
-					AR5K_SISR1_QCU_TXERR);
-
-		if (data & AR5K_ISR_TXEOL)
-			ah->ah_txq_isr |= AR5K_REG_MS(
-					ath5k_hw_reg_read(ah, AR5K_RAC_SISR1),
-					AR5K_SISR1_QCU_TXEOL);
-
-		if (data & AR5K_ISR_TXURN)
-			ah->ah_txq_isr |= AR5K_REG_MS(
-					ath5k_hw_reg_read(ah, AR5K_RAC_SISR2),
-					AR5K_SISR2_QCU_TXURN);
-	} else {
-		if (data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT |
-			    AR5K_ISR_HIUERR | AR5K_ISR_DPERR))
-			*interrupt_mask |= AR5K_INT_FATAL;
-
-		/*
-		 * XXX: BMISS interrupts may occur after association.
-		 * I found this on 5210 code but it needs testing. If this is
-		 * true we should disable them before assoc and re-enable them
-		 * after a successful assoc + some jiffies.
-			interrupt_mask &= ~AR5K_INT_BMISS;
-		 */
-	}
-
-	return 0;
-}
-
-/**
- * ath5k_hw_set_imr - Set interrupt mask
- *
- * @ah: The &struct ath5k_hw
- * @new_mask: The new interrupt mask to be set
- *
- * Set the interrupt mask in hw to save interrupts. We do that by mapping
- * ath5k_int bits to hw-specific bits to remove abstraction and writing
- * Interrupt Mask Register.
- */
-enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
-{
-	enum ath5k_int old_mask, int_mask;
-
-	old_mask = ah->ah_imr;
-
-	/*
-	 * Disable card interrupts to prevent any race conditions
-	 * (they will be re-enabled afterwards if AR5K_INT GLOBAL
-	 * is set again on the new mask).
-	 */
-	if (old_mask & AR5K_INT_GLOBAL) {
-		ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
-		ath5k_hw_reg_read(ah, AR5K_IER);
-	}
-
-	/*
-	 * Add additional, chipset-dependent interrupt mask flags
-	 * and write them to the IMR (interrupt mask register).
-	 */
-	int_mask = new_mask & AR5K_INT_COMMON;
-
-	if (ah->ah_version != AR5K_AR5210) {
-		/* Preserve per queue TXURN interrupt mask */
-		u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2)
-				& AR5K_SIMR2_QCU_TXURN;
-
-		if (new_mask & AR5K_INT_FATAL) {
-			int_mask |= AR5K_IMR_HIUERR;
-			simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR
-				| AR5K_SIMR2_DPERR);
-		}
-
-		/*Beacon Not Ready*/
-		if (new_mask & AR5K_INT_BNR)
-			int_mask |= AR5K_INT_BNR;
-
-		if (new_mask & AR5K_INT_TIM)
-			int_mask |= AR5K_IMR_TIM;
-
-		if (new_mask & AR5K_INT_TIM)
-			simr2 |= AR5K_SISR2_TIM;
-		if (new_mask & AR5K_INT_DTIM)
-			simr2 |= AR5K_SISR2_DTIM;
-		if (new_mask & AR5K_INT_DTIM_SYNC)
-			simr2 |= AR5K_SISR2_DTIM_SYNC;
-		if (new_mask & AR5K_INT_BCN_TIMEOUT)
-			simr2 |= AR5K_SISR2_BCN_TIMEOUT;
-		if (new_mask & AR5K_INT_CAB_TIMEOUT)
-			simr2 |= AR5K_SISR2_CAB_TIMEOUT;
-
-		if (new_mask & AR5K_INT_RX_DOPPLER)
-			int_mask |= AR5K_IMR_RXDOPPLER;
-
-		/* Note: Per queue interrupt masks
-		 * are set via reset_tx_queue (qcu.c) */
-		ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
-		ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2);
-
-	} else {
-		if (new_mask & AR5K_INT_FATAL)
-			int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT
-				| AR5K_IMR_HIUERR | AR5K_IMR_DPERR);
-
-		ath5k_hw_reg_write(ah, int_mask, AR5K_IMR);
-	}
-
-	/* If RXNOFRM interrupt is masked disable it
-	 * by setting AR5K_RXNOFRM to zero */
-	if (!(new_mask & AR5K_INT_RXNOFRM))
-		ath5k_hw_reg_write(ah, 0, AR5K_RXNOFRM);
-
-	/* Store new interrupt mask */
-	ah->ah_imr = new_mask;
-
-	/* ..re-enable interrupts if AR5K_INT_GLOBAL is set */
-	if (new_mask & AR5K_INT_GLOBAL) {
-		ath5k_hw_reg_write(ah, ah->ah_ier, AR5K_IER);
-		ath5k_hw_reg_read(ah, AR5K_IER);
-	}
-
-	return old_mask;
-}
-
diff --git a/roms/ipxe/src/drivers/net/ath5k/ath5k_eeprom.c b/roms/ipxe/src/drivers/net/ath5k/ath5k_eeprom.c
deleted file mode 100644
index 983d206b7e36cc4981ecbb760a418c04c848e286..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/ath5k_eeprom.c
+++ /dev/null
@@ -1,1760 +0,0 @@
-/*
- * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>
- * Copyright (c) 2008-2009 Felix Fietkau <nbd@openwrt.org>
- *
- * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-FILE_LICENCE ( MIT );
-
-/*************************************\
-* EEPROM access functions and helpers *
-\*************************************/
-
-#include <unistd.h>
-#include <stdlib.h>
-
-#include "ath5k.h"
-#include "reg.h"
-#include "base.h"
-
-/*
- * Read from eeprom
- */
-static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
-{
-	u32 status, timeout;
-
-	/*
-	 * Initialize EEPROM access
-	 */
-	if (ah->ah_version == AR5K_AR5210) {
-		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
-		(void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset));
-	} else {
-		ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
-		AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
-				AR5K_EEPROM_CMD_READ);
-	}
-
-	for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
-		status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
-		if (status & AR5K_EEPROM_STAT_RDDONE) {
-			if (status & AR5K_EEPROM_STAT_RDERR)
-				return -EIO;
-			*data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
-					0xffff);
-			return 0;
-		}
-		udelay(15);
-	}
-
-	return -ETIMEDOUT;
-}
-
-/*
- * Translate binary channel representation in EEPROM to frequency
- */
-static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin,
-                                 unsigned int mode)
-{
-	u16 val;
-
-	if (bin == AR5K_EEPROM_CHANNEL_DIS)
-		return bin;
-
-	if (mode == AR5K_EEPROM_MODE_11A) {
-		if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
-			val = (5 * bin) + 4800;
-		else
-			val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
-				(bin * 10) + 5100;
-	} else {
-		if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)
-			val = bin + 2300;
-		else
-			val = bin + 2400;
-	}
-
-	return val;
-}
-
-/*
- * Initialize eeprom & capabilities structs
- */
-static int
-ath5k_eeprom_init_header(struct ath5k_hw *ah)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	int ret;
-	u16 val;
-
-	/*
-	 * Read values from EEPROM and store them in the capability structure
-	 */
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
-
-	/* Return if we have an old EEPROM */
-	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
-		return 0;
-
-	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
-	    ee_ant_gain);
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
-		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
-		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
-
-		/* XXX: Don't know which versions include these two */
-		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2);
-
-		if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3)
-			AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC3, ee_misc3);
-
-		if (ee->ee_version >= AR5K_EEPROM_VERSION_5_0) {
-			AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC4, ee_misc4);
-			AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC5, ee_misc5);
-			AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC6, ee_misc6);
-		}
-	}
-
-	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
-		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
-		ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
-		ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
-
-		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
-		ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
-		ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
-	}
-
-	AR5K_EEPROM_READ(AR5K_EEPROM_IS_HB63, val);
-
-	if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && val)
-		ee->ee_is_hb63 = 1;
-	else
-		ee->ee_is_hb63 = 0;
-
-	AR5K_EEPROM_READ(AR5K_EEPROM_RFKILL, val);
-	ee->ee_rfkill_pin = (u8) AR5K_REG_MS(val, AR5K_EEPROM_RFKILL_GPIO_SEL);
-	ee->ee_rfkill_pol = val & AR5K_EEPROM_RFKILL_POLARITY ? 1 : 0;
-
-	return 0;
-}
-
-
-/*
- * Read antenna infos from eeprom
- */
-static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
-		unsigned int mode)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	u32 o = *offset;
-	u16 val;
-	int ret, i = 0;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_switch_settling[mode]	= (val >> 8) & 0x7f;
-	ee->ee_atn_tx_rx[mode]		= (val >> 2) & 0x3f;
-	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
-	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
-	ee->ee_ant_control[mode][i++]	= val & 0x3f;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_ant_control[mode][i++]	= (val >> 10) & 0x3f;
-	ee->ee_ant_control[mode][i++]	= (val >> 4) & 0x3f;
-	ee->ee_ant_control[mode][i]	= (val << 2) & 0x3f;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_ant_control[mode][i++]	|= (val >> 14) & 0x3;
-	ee->ee_ant_control[mode][i++]	= (val >> 8) & 0x3f;
-	ee->ee_ant_control[mode][i++]	= (val >> 2) & 0x3f;
-	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
-	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
-	ee->ee_ant_control[mode][i++]	= val & 0x3f;
-
-	/* Get antenna modes */
-	ah->ah_antenna[mode][0] =
-	    (ee->ee_ant_control[mode][0] << 4);
-	ah->ah_antenna[mode][AR5K_ANT_FIXED_A] =
-	     ee->ee_ant_control[mode][1] 	|
-	    (ee->ee_ant_control[mode][2] << 6) 	|
-	    (ee->ee_ant_control[mode][3] << 12) |
-	    (ee->ee_ant_control[mode][4] << 18) |
-	    (ee->ee_ant_control[mode][5] << 24);
-	ah->ah_antenna[mode][AR5K_ANT_FIXED_B] =
-	     ee->ee_ant_control[mode][6] 	|
-	    (ee->ee_ant_control[mode][7] << 6) 	|
-	    (ee->ee_ant_control[mode][8] << 12) |
-	    (ee->ee_ant_control[mode][9] << 18) |
-	    (ee->ee_ant_control[mode][10] << 24);
-
-	/* return new offset */
-	*offset = o;
-
-	return 0;
-}
-
-/*
- * Read supported modes and some mode-specific calibration data
- * from eeprom
- */
-static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
-		unsigned int mode)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	u32 o = *offset;
-	u16 val;
-	int ret;
-
-	ee->ee_n_piers[mode] = 0;
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
-	switch(mode) {
-	case AR5K_EEPROM_MODE_11A:
-		ee->ee_ob[mode][3]	= (val >> 5) & 0x7;
-		ee->ee_db[mode][3]	= (val >> 2) & 0x7;
-		ee->ee_ob[mode][2]	= (val << 1) & 0x7;
-
-		AR5K_EEPROM_READ(o++, val);
-		ee->ee_ob[mode][2]	|= (val >> 15) & 0x1;
-		ee->ee_db[mode][2]	= (val >> 12) & 0x7;
-		ee->ee_ob[mode][1]	= (val >> 9) & 0x7;
-		ee->ee_db[mode][1]	= (val >> 6) & 0x7;
-		ee->ee_ob[mode][0]	= (val >> 3) & 0x7;
-		ee->ee_db[mode][0]	= val & 0x7;
-		break;
-	case AR5K_EEPROM_MODE_11G:
-	case AR5K_EEPROM_MODE_11B:
-		ee->ee_ob[mode][1]	= (val >> 4) & 0x7;
-		ee->ee_db[mode][1]	= val & 0x7;
-		break;
-	}
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_tx_end2xlna_enable[mode]	= (val >> 8) & 0xff;
-	ee->ee_thr_62[mode]		= val & 0xff;
-
-	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
-		ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_tx_end2xpa_disable[mode]	= (val >> 8) & 0xff;
-	ee->ee_tx_frm2xpa_enable[mode]	= val & 0xff;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_pga_desired_size[mode]	= (val >> 8) & 0xff;
-
-	if ((val & 0xff) & 0x80)
-		ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);
-	else
-		ee->ee_noise_floor_thr[mode] = val & 0xff;
-
-	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
-		ee->ee_noise_floor_thr[mode] =
-		    mode == AR5K_EEPROM_MODE_11A ? -54 : -1;
-
-	AR5K_EEPROM_READ(o++, val);
-	ee->ee_xlna_gain[mode]		= (val >> 5) & 0xff;
-	ee->ee_x_gain[mode]		= (val >> 1) & 0xf;
-	ee->ee_xpd[mode]		= val & 0x1;
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0)
-		ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) {
-		AR5K_EEPROM_READ(o++, val);
-		ee->ee_false_detect[mode] = (val >> 6) & 0x7f;
-
-		if (mode == AR5K_EEPROM_MODE_11A)
-			ee->ee_xr_power[mode] = val & 0x3f;
-		else {
-			ee->ee_ob[mode][0] = val & 0x7;
-			ee->ee_db[mode][0] = (val >> 3) & 0x7;
-		}
-	}
-
-	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) {
-		ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;
-		ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;
-	} else {
-		ee->ee_i_gain[mode] = (val >> 13) & 0x7;
-
-		AR5K_EEPROM_READ(o++, val);
-		ee->ee_i_gain[mode] |= (val << 3) & 0x38;
-
-		if (mode == AR5K_EEPROM_MODE_11G) {
-			ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
-			if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6)
-				ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
-		}
-	}
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
-			mode == AR5K_EEPROM_MODE_11A) {
-		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
-		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
-	}
-
-	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0)
-		goto done;
-
-	/* Note: >= v5 have bg freq piers on another location
-	 * so these freq piers are ignored for >= v5 (should be 0xff
-	 * anyway) */
-	switch(mode) {
-	case AR5K_EEPROM_MODE_11A:
-		if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1)
-			break;
-
-		AR5K_EEPROM_READ(o++, val);
-		ee->ee_margin_tx_rx[mode] = val & 0x3f;
-		break;
-	case AR5K_EEPROM_MODE_11B:
-		AR5K_EEPROM_READ(o++, val);
-
-		ee->ee_pwr_cal_b[0].freq =
-			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
-		if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS)
-			ee->ee_n_piers[mode]++;
-
-		ee->ee_pwr_cal_b[1].freq =
-			ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
-		if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS)
-			ee->ee_n_piers[mode]++;
-
-		AR5K_EEPROM_READ(o++, val);
-		ee->ee_pwr_cal_b[2].freq =
-			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
-		if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS)
-			ee->ee_n_piers[mode]++;
-
-		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
-			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
-		break;
-	case AR5K_EEPROM_MODE_11G:
-		AR5K_EEPROM_READ(o++, val);
-
-		ee->ee_pwr_cal_g[0].freq =
-			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
-		if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS)
-			ee->ee_n_piers[mode]++;
-
-		ee->ee_pwr_cal_g[1].freq =
-			ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
-		if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS)
-			ee->ee_n_piers[mode]++;
-
-		AR5K_EEPROM_READ(o++, val);
-		ee->ee_turbo_max_power[mode] = val & 0x7f;
-		ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
-
-		AR5K_EEPROM_READ(o++, val);
-		ee->ee_pwr_cal_g[2].freq =
-			ath5k_eeprom_bin2freq(ee, val & 0xff, mode);
-		if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS)
-			ee->ee_n_piers[mode]++;
-
-		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
-			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
-
-		AR5K_EEPROM_READ(o++, val);
-		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
-		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
-
-		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
-			AR5K_EEPROM_READ(o++, val);
-			ee->ee_cck_ofdm_gain_delta = val & 0xff;
-		}
-		break;
-	}
-
-done:
-	/* return new offset */
-	*offset = o;
-
-	return 0;
-}
-
-/*
- * Read turbo mode information on newer EEPROM versions
- */
-static int
-ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
-			      u32 *offset, unsigned int mode)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	u32 o = *offset;
-	u16 val;
-	int ret;
-
-	if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)
-		return 0;
-
-	switch (mode){
-	case AR5K_EEPROM_MODE_11A:
-		ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f;
-
-		ee->ee_atn_tx_rx_turbo[mode] = (val >> 13) & 0x7;
-		AR5K_EEPROM_READ(o++, val);
-		ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x7) << 3;
-		ee->ee_margin_tx_rx_turbo[mode] = (val >> 3) & 0x3f;
-
-		ee->ee_adc_desired_size_turbo[mode] = (val >> 9) & 0x7f;
-		AR5K_EEPROM_READ(o++, val);
-		ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7;
-		ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff;
-
-		if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2)
-			ee->ee_pd_gain_overlap = (val >> 9) & 0xf;
-		break;
-	case AR5K_EEPROM_MODE_11G:
-		ee->ee_switch_settling_turbo[mode] = (val >> 8) & 0x7f;
-
-		ee->ee_atn_tx_rx_turbo[mode] = (val >> 15) & 0x7;
-		AR5K_EEPROM_READ(o++, val);
-		ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x1f) << 1;
-		ee->ee_margin_tx_rx_turbo[mode] = (val >> 5) & 0x3f;
-
-		ee->ee_adc_desired_size_turbo[mode] = (val >> 11) & 0x7f;
-		AR5K_EEPROM_READ(o++, val);
-		ee->ee_adc_desired_size_turbo[mode] |= (val & 0x7) << 5;
-		ee->ee_pga_desired_size_turbo[mode] = (val >> 3) & 0xff;
-		break;
-	}
-
-	/* return new offset */
-	*offset = o;
-
-	return 0;
-}
-
-/* Read mode-specific data (except power calibration data) */
-static int
-ath5k_eeprom_init_modes(struct ath5k_hw *ah)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	u32 mode_offset[3];
-	unsigned int mode;
-	u32 offset;
-	int ret;
-
-	/*
-	 * Get values for all modes
-	 */
-	mode_offset[AR5K_EEPROM_MODE_11A] = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
-	mode_offset[AR5K_EEPROM_MODE_11B] = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
-	mode_offset[AR5K_EEPROM_MODE_11G] = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
-
-	ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A] =
-		AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
-
-	for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) {
-		offset = mode_offset[mode];
-
-		ret = ath5k_eeprom_read_ants(ah, &offset, mode);
-		if (ret)
-			return ret;
-
-		ret = ath5k_eeprom_read_modes(ah, &offset, mode);
-		if (ret)
-			return ret;
-
-		ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode);
-		if (ret)
-			return ret;
-	}
-
-	/* override for older eeprom versions for better performance */
-	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) {
-		ee->ee_thr_62[AR5K_EEPROM_MODE_11A] = 15;
-		ee->ee_thr_62[AR5K_EEPROM_MODE_11B] = 28;
-		ee->ee_thr_62[AR5K_EEPROM_MODE_11G] = 28;
-	}
-
-	return 0;
-}
-
-/* Read the frequency piers for each mode (mostly used on newer eeproms with 0xff
- * frequency mask) */
-static inline int
-ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max,
-			struct ath5k_chan_pcal_info *pc, unsigned int mode)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	int o = *offset;
-	int i = 0;
-	u8 freq1, freq2;
-	int ret;
-	u16 val;
-
-	ee->ee_n_piers[mode] = 0;
-	while(i < max) {
-		AR5K_EEPROM_READ(o++, val);
-
-		freq1 = val & 0xff;
-		if (!freq1)
-			break;
-
-		pc[i++].freq = ath5k_eeprom_bin2freq(ee,
-				freq1, mode);
-		ee->ee_n_piers[mode]++;
-
-		freq2 = (val >> 8) & 0xff;
-		if (!freq2)
-			break;
-
-		pc[i++].freq = ath5k_eeprom_bin2freq(ee,
-				freq2, mode);
-		ee->ee_n_piers[mode]++;
-	}
-
-	/* return new offset */
-	*offset = o;
-
-	return 0;
-}
-
-/* Read frequency piers for 802.11a */
-static int
-ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a;
-	int i, ret;
-	u16 val;
-	u8 mask;
-
-	if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
-		ath5k_eeprom_read_freq_list(ah, &offset,
-			AR5K_EEPROM_N_5GHZ_CHAN, pcal,
-			AR5K_EEPROM_MODE_11A);
-	} else {
-		mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version);
-
-		AR5K_EEPROM_READ(offset++, val);
-		pcal[0].freq  = (val >> 9) & mask;
-		pcal[1].freq  = (val >> 2) & mask;
-		pcal[2].freq  = (val << 5) & mask;
-
-		AR5K_EEPROM_READ(offset++, val);
-		pcal[2].freq |= (val >> 11) & 0x1f;
-		pcal[3].freq  = (val >> 4) & mask;
-		pcal[4].freq  = (val << 3) & mask;
-
-		AR5K_EEPROM_READ(offset++, val);
-		pcal[4].freq |= (val >> 13) & 0x7;
-		pcal[5].freq  = (val >> 6) & mask;
-		pcal[6].freq  = (val << 1) & mask;
-
-		AR5K_EEPROM_READ(offset++, val);
-		pcal[6].freq |= (val >> 15) & 0x1;
-		pcal[7].freq  = (val >> 8) & mask;
-		pcal[8].freq  = (val >> 1) & mask;
-		pcal[9].freq  = (val << 6) & mask;
-
-		AR5K_EEPROM_READ(offset++, val);
-		pcal[9].freq |= (val >> 10) & 0x3f;
-
-		/* Fixed number of piers */
-		ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10;
-
-		for (i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i++) {
-			pcal[i].freq = ath5k_eeprom_bin2freq(ee,
-				pcal[i].freq, AR5K_EEPROM_MODE_11A);
-		}
-	}
-
-	return 0;
-}
-
-/* Read frequency piers for 802.11bg on eeprom versions >= 5 and eemap >= 2 */
-static inline int
-ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct ath5k_chan_pcal_info *pcal;
-
-	switch(mode) {
-	case AR5K_EEPROM_MODE_11B:
-		pcal = ee->ee_pwr_cal_b;
-		break;
-	case AR5K_EEPROM_MODE_11G:
-		pcal = ee->ee_pwr_cal_g;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	ath5k_eeprom_read_freq_list(ah, &offset,
-		AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal,
-		mode);
-
-	return 0;
-}
-
-/*
- * Read power calibration for RF5111 chips
- *
- * For RF5111 we have an XPD -eXternal Power Detector- curve
- * for each calibrated channel. Each curve has 0,5dB Power steps
- * on x axis and PCDAC steps (offsets) on y axis and looks like an
- * exponential function. To recreate the curve we read 11 points
- * here and interpolate later.
- */
-
-/* Used to match PCDAC steps with power values on RF5111 chips
- * (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC
- * steps that match with the power values we read from eeprom. On
- * older eeprom versions (< 3.2) these steps are equaly spaced at
- * 10% of the pcdac curve -until the curve reaches it's maximum-
- * (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2)
- * these 11 steps are spaced in a different way. This function returns
- * the pcdac steps based on eeprom version and curve min/max so that we
- * can have pcdac/pwr points.
- */
-static inline void
-ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
-{
-	static const u16 intercepts3[] =
-		{ 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 };
-	static const u16 intercepts3_2[] =
-		{ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
-	const u16 *ip;
-	unsigned i;
-
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2)
-		ip = intercepts3_2;
-	else
-		ip = intercepts3;
-
-	for (i = 0; i < ARRAY_SIZE(intercepts3); i++)
-		vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100;
-}
-
-/* Convert RF5111 specific data to generic raw data
- * used by interpolation code */
-static int
-ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
-				struct ath5k_chan_pcal_info *chinfo)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct ath5k_chan_pcal_info_rf5111 *pcinfo;
-	struct ath5k_pdgain_info *pd;
-	u8 pier, point, idx;
-	u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
-
-	/* Fill raw data for each calibration pier */
-	for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
-
-		pcinfo = &chinfo[pier].rf5111_info;
-
-		/* Allocate pd_curves for this cal pier */
-		chinfo[pier].pd_curves =
-			calloc(AR5K_EEPROM_N_PD_CURVES,
-			       sizeof(struct ath5k_pdgain_info));
-
-		if (!chinfo[pier].pd_curves)
-			return -ENOMEM;
-
-		/* Only one curve for RF5111
-		 * find out which one and place
-		 * in in pd_curves.
-		 * Note: ee_x_gain is reversed here */
-		for (idx = 0; idx < AR5K_EEPROM_N_PD_CURVES; idx++) {
-
-			if (!((ee->ee_x_gain[mode] >> idx) & 0x1)) {
-				pdgain_idx[0] = idx;
-				break;
-			}
-		}
-
-		ee->ee_pd_gains[mode] = 1;
-
-		pd = &chinfo[pier].pd_curves[idx];
-
-		pd->pd_points = AR5K_EEPROM_N_PWR_POINTS_5111;
-
-		/* Allocate pd points for this curve */
-		pd->pd_step = calloc(AR5K_EEPROM_N_PWR_POINTS_5111, sizeof(u8));
-		if (!pd->pd_step)
-			return -ENOMEM;
-
-		pd->pd_pwr = calloc(AR5K_EEPROM_N_PWR_POINTS_5111, sizeof(s16));
-		if (!pd->pd_pwr)
-			return -ENOMEM;
-
-		/* Fill raw dataset
-		 * (convert power to 0.25dB units
-		 * for RF5112 combatibility) */
-		for (point = 0; point < pd->pd_points; point++) {
-
-			/* Absolute values */
-			pd->pd_pwr[point] = 2 * pcinfo->pwr[point];
-
-			/* Already sorted */
-			pd->pd_step[point] = pcinfo->pcdac[point];
-		}
-
-		/* Set min/max pwr */
-		chinfo[pier].min_pwr = pd->pd_pwr[0];
-		chinfo[pier].max_pwr = pd->pd_pwr[10];
-
-	}
-
-	return 0;
-}
-
-/* Parse EEPROM data */
-static int
-ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct ath5k_chan_pcal_info *pcal;
-	int offset, ret;
-	int i;
-	u16 val;
-
-	offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
-	switch(mode) {
-	case AR5K_EEPROM_MODE_11A:
-		if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
-			return 0;
-
-		ret = ath5k_eeprom_init_11a_pcal_freq(ah,
-			offset + AR5K_EEPROM_GROUP1_OFFSET);
-		if (ret < 0)
-			return ret;
-
-		offset += AR5K_EEPROM_GROUP2_OFFSET;
-		pcal = ee->ee_pwr_cal_a;
-		break;
-	case AR5K_EEPROM_MODE_11B:
-		if (!AR5K_EEPROM_HDR_11B(ee->ee_header) &&
-		    !AR5K_EEPROM_HDR_11G(ee->ee_header))
-			return 0;
-
-		pcal = ee->ee_pwr_cal_b;
-		offset += AR5K_EEPROM_GROUP3_OFFSET;
-
-		/* fixed piers */
-		pcal[0].freq = 2412;
-		pcal[1].freq = 2447;
-		pcal[2].freq = 2484;
-		ee->ee_n_piers[mode] = 3;
-		break;
-	case AR5K_EEPROM_MODE_11G:
-		if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
-			return 0;
-
-		pcal = ee->ee_pwr_cal_g;
-		offset += AR5K_EEPROM_GROUP4_OFFSET;
-
-		/* fixed piers */
-		pcal[0].freq = 2312;
-		pcal[1].freq = 2412;
-		pcal[2].freq = 2484;
-		ee->ee_n_piers[mode] = 3;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	for (i = 0; i < ee->ee_n_piers[mode]; i++) {
-		struct ath5k_chan_pcal_info_rf5111 *cdata =
-			&pcal[i].rf5111_info;
-
-		AR5K_EEPROM_READ(offset++, val);
-		cdata->pcdac_max = ((val >> 10) & AR5K_EEPROM_PCDAC_M);
-		cdata->pcdac_min = ((val >> 4) & AR5K_EEPROM_PCDAC_M);
-		cdata->pwr[0] = ((val << 2) & AR5K_EEPROM_POWER_M);
-
-		AR5K_EEPROM_READ(offset++, val);
-		cdata->pwr[0] |= ((val >> 14) & 0x3);
-		cdata->pwr[1] = ((val >> 8) & AR5K_EEPROM_POWER_M);
-		cdata->pwr[2] = ((val >> 2) & AR5K_EEPROM_POWER_M);
-		cdata->pwr[3] = ((val << 4) & AR5K_EEPROM_POWER_M);
-
-		AR5K_EEPROM_READ(offset++, val);
-		cdata->pwr[3] |= ((val >> 12) & 0xf);
-		cdata->pwr[4] = ((val >> 6) & AR5K_EEPROM_POWER_M);
-		cdata->pwr[5] = (val  & AR5K_EEPROM_POWER_M);
-
-		AR5K_EEPROM_READ(offset++, val);
-		cdata->pwr[6] = ((val >> 10) & AR5K_EEPROM_POWER_M);
-		cdata->pwr[7] = ((val >> 4) & AR5K_EEPROM_POWER_M);
-		cdata->pwr[8] = ((val << 2) & AR5K_EEPROM_POWER_M);
-
-		AR5K_EEPROM_READ(offset++, val);
-		cdata->pwr[8] |= ((val >> 14) & 0x3);
-		cdata->pwr[9] = ((val >> 8) & AR5K_EEPROM_POWER_M);
-		cdata->pwr[10] = ((val >> 2) & AR5K_EEPROM_POWER_M);
-
-		ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min,
-			cdata->pcdac_max, cdata->pcdac);
-	}
-
-	return ath5k_eeprom_convert_pcal_info_5111(ah, mode, pcal);
-}
-
-
-/*
- * Read power calibration for RF5112 chips
- *
- * For RF5112 we have 4 XPD -eXternal Power Detector- curves
- * for each calibrated channel on 0, -6, -12 and -18dbm but we only
- * use the higher (3) and the lower (0) curves. Each curve has 0.5dB
- * power steps on x axis and PCDAC steps on y axis and looks like a
- * linear function. To recreate the curve and pass the power values
- * on hw, we read 4 points for xpd 0 (lower gain -> max power)
- * and 3 points for xpd 3 (higher gain -> lower power) here and
- * interpolate later.
- *
- * Note: Many vendors just use xpd 0 so xpd 3 is zeroed.
- */
-
-/* Convert RF5112 specific data to generic raw data
- * used by interpolation code */
-static int
-ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
-				struct ath5k_chan_pcal_info *chinfo)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct ath5k_chan_pcal_info_rf5112 *pcinfo;
-	u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
-	unsigned int pier, pdg, point;
-
-	/* Fill raw data for each calibration pier */
-	for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
-
-		pcinfo = &chinfo[pier].rf5112_info;
-
-		/* Allocate pd_curves for this cal pier */
-		chinfo[pier].pd_curves =
-				calloc(AR5K_EEPROM_N_PD_CURVES,
-				       sizeof(struct ath5k_pdgain_info));
-
-		if (!chinfo[pier].pd_curves)
-			return -ENOMEM;
-
-		/* Fill pd_curves */
-		for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
-
-			u8 idx = pdgain_idx[pdg];
-			struct ath5k_pdgain_info *pd =
-					&chinfo[pier].pd_curves[idx];
-
-			/* Lowest gain curve (max power) */
-			if (pdg == 0) {
-				/* One more point for better accuracy */
-				pd->pd_points = AR5K_EEPROM_N_XPD0_POINTS;
-
-				/* Allocate pd points for this curve */
-				pd->pd_step = calloc(pd->pd_points, sizeof(u8));
-
-				if (!pd->pd_step)
-					return -ENOMEM;
-
-				pd->pd_pwr = calloc(pd->pd_points, sizeof(s16));
-
-				if (!pd->pd_pwr)
-					return -ENOMEM;
-
-
-				/* Fill raw dataset
-				 * (all power levels are in 0.25dB units) */
-				pd->pd_step[0] = pcinfo->pcdac_x0[0];
-				pd->pd_pwr[0] = pcinfo->pwr_x0[0];
-
-				for (point = 1; point < pd->pd_points;
-				point++) {
-					/* Absolute values */
-					pd->pd_pwr[point] =
-						pcinfo->pwr_x0[point];
-
-					/* Deltas */
-					pd->pd_step[point] =
-						pd->pd_step[point - 1] +
-						pcinfo->pcdac_x0[point];
-				}
-
-				/* Set min power for this frequency */
-				chinfo[pier].min_pwr = pd->pd_pwr[0];
-
-			/* Highest gain curve (min power) */
-			} else if (pdg == 1) {
-
-				pd->pd_points = AR5K_EEPROM_N_XPD3_POINTS;
-
-				/* Allocate pd points for this curve */
-				pd->pd_step = calloc(pd->pd_points, sizeof(u8));
-
-				if (!pd->pd_step)
-					return -ENOMEM;
-
-				pd->pd_pwr = calloc(pd->pd_points, sizeof(s16));
-
-				if (!pd->pd_pwr)
-					return -ENOMEM;
-
-				/* Fill raw dataset
-				 * (all power levels are in 0.25dB units) */
-				for (point = 0; point < pd->pd_points;
-				point++) {
-					/* Absolute values */
-					pd->pd_pwr[point] =
-						pcinfo->pwr_x3[point];
-
-					/* Fixed points */
-					pd->pd_step[point] =
-						pcinfo->pcdac_x3[point];
-				}
-
-				/* Since we have a higher gain curve
-				 * override min power */
-				chinfo[pier].min_pwr = pd->pd_pwr[0];
-			}
-		}
-	}
-
-	return 0;
-}
-
-/* Parse EEPROM data */
-static int
-ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info;
-	struct ath5k_chan_pcal_info *gen_chan_info;
-	u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
-	u32 offset;
-	u8 i, c;
-	u16 val;
-	int ret;
-	u8 pd_gains = 0;
-
-	/* Count how many curves we have and
-	 * identify them (which one of the 4
-	 * available curves we have on each count).
-	 * Curves are stored from lower (x0) to
-	 * higher (x3) gain */
-	for (i = 0; i < AR5K_EEPROM_N_PD_CURVES; i++) {
-		/* ee_x_gain[mode] is x gain mask */
-		if ((ee->ee_x_gain[mode] >> i) & 0x1)
-			pdgain_idx[pd_gains++] = i;
-	}
-	ee->ee_pd_gains[mode] = pd_gains;
-
-	if (pd_gains == 0 || pd_gains > 2)
-		return -EINVAL;
-
-	switch (mode) {
-	case AR5K_EEPROM_MODE_11A:
-		/*
-		 * Read 5GHz EEPROM channels
-		 */
-		offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
-		ath5k_eeprom_init_11a_pcal_freq(ah, offset);
-
-		offset += AR5K_EEPROM_GROUP2_OFFSET;
-		gen_chan_info = ee->ee_pwr_cal_a;
-		break;
-	case AR5K_EEPROM_MODE_11B:
-		offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
-		if (AR5K_EEPROM_HDR_11A(ee->ee_header))
-			offset += AR5K_EEPROM_GROUP3_OFFSET;
-
-		/* NB: frequency piers parsed during mode init */
-		gen_chan_info = ee->ee_pwr_cal_b;
-		break;
-	case AR5K_EEPROM_MODE_11G:
-		offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);
-		if (AR5K_EEPROM_HDR_11A(ee->ee_header))
-			offset += AR5K_EEPROM_GROUP4_OFFSET;
-		else if (AR5K_EEPROM_HDR_11B(ee->ee_header))
-			offset += AR5K_EEPROM_GROUP2_OFFSET;
-
-		/* NB: frequency piers parsed during mode init */
-		gen_chan_info = ee->ee_pwr_cal_g;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	for (i = 0; i < ee->ee_n_piers[mode]; i++) {
-		chan_pcal_info = &gen_chan_info[i].rf5112_info;
-
-		/* Power values in quarter dB
-		 * for the lower xpd gain curve
-		 * (0 dBm -> higher output power) */
-		for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {
-			AR5K_EEPROM_READ(offset++, val);
-			chan_pcal_info->pwr_x0[c] = (s8) (val & 0xff);
-			chan_pcal_info->pwr_x0[++c] = (s8) ((val >> 8) & 0xff);
-		}
-
-		/* PCDAC steps
-		 * corresponding to the above power
-		 * measurements */
-		AR5K_EEPROM_READ(offset++, val);
-		chan_pcal_info->pcdac_x0[1] = (val & 0x1f);
-		chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f);
-		chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f);
-
-		/* Power values in quarter dB
-		 * for the higher xpd gain curve
-		 * (18 dBm -> lower output power) */
-		AR5K_EEPROM_READ(offset++, val);
-		chan_pcal_info->pwr_x3[0] = (s8) (val & 0xff);
-		chan_pcal_info->pwr_x3[1] = (s8) ((val >> 8) & 0xff);
-
-		AR5K_EEPROM_READ(offset++, val);
-		chan_pcal_info->pwr_x3[2] = (val & 0xff);
-
-		/* PCDAC steps
-		 * corresponding to the above power
-		 * measurements (fixed) */
-		chan_pcal_info->pcdac_x3[0] = 20;
-		chan_pcal_info->pcdac_x3[1] = 35;
-		chan_pcal_info->pcdac_x3[2] = 63;
-
-		if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) {
-			chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0x3f);
-
-			/* Last xpd0 power level is also channel maximum */
-			gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3];
-		} else {
-			chan_pcal_info->pcdac_x0[0] = 1;
-			gen_chan_info[i].max_pwr = (s8) ((val >> 8) & 0xff);
-		}
-
-	}
-
-	return ath5k_eeprom_convert_pcal_info_5112(ah, mode, gen_chan_info);
-}
-
-
-/*
- * Read power calibration for RF2413 chips
- *
- * For RF2413 we have a Power to PDDAC table (Power Detector)
- * instead of a PCDAC and 4 pd gain curves for each calibrated channel.
- * Each curve has power on x axis in 0.5 db steps and PDDADC steps on y
- * axis and looks like an exponential function like the RF5111 curve.
- *
- * To recreate the curves we read here the points and interpolate
- * later. Note that in most cases only 2 (higher and lower) curves are
- * used (like RF5112) but vendors have the oportunity to include all
- * 4 curves on eeprom. The final curve (higher power) has an extra
- * point for better accuracy like RF5112.
- */
-
-/* For RF2413 power calibration data doesn't start on a fixed location and
- * if a mode is not supported, it's section is missing -not zeroed-.
- * So we need to calculate the starting offset for each section by using
- * these two functions */
-
-/* Return the size of each section based on the mode and the number of pd
- * gains available (maximum 4). */
-static inline unsigned int
-ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode)
-{
-	static const unsigned int pdgains_size[] = { 4, 6, 9, 12 };
-	unsigned int sz;
-
-	sz = pdgains_size[ee->ee_pd_gains[mode] - 1];
-	sz *= ee->ee_n_piers[mode];
-
-	return sz;
-}
-
-/* Return the starting offset for a section based on the modes supported
- * and each section's size. */
-static unsigned int
-ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode)
-{
-	u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4);
-
-	switch(mode) {
-	case AR5K_EEPROM_MODE_11G:
-		if (AR5K_EEPROM_HDR_11B(ee->ee_header))
-			offset += ath5k_pdgains_size_2413(ee,
-					AR5K_EEPROM_MODE_11B) +
-					AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
-		/* fall through */
-	case AR5K_EEPROM_MODE_11B:
-		if (AR5K_EEPROM_HDR_11A(ee->ee_header))
-			offset += ath5k_pdgains_size_2413(ee,
-					AR5K_EEPROM_MODE_11A) +
-					AR5K_EEPROM_N_5GHZ_CHAN / 2;
-		/* fall through */
-	case AR5K_EEPROM_MODE_11A:
-		break;
-	default:
-		break;
-	}
-
-	return offset;
-}
-
-/* Convert RF2413 specific data to generic raw data
- * used by interpolation code */
-static int
-ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
-				struct ath5k_chan_pcal_info *chinfo)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct ath5k_chan_pcal_info_rf2413 *pcinfo;
-	u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
-	unsigned int pier, point;
-	int pdg;
-
-	/* Fill raw data for each calibration pier */
-	for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
-
-		pcinfo = &chinfo[pier].rf2413_info;
-
-		/* Allocate pd_curves for this cal pier */
-		chinfo[pier].pd_curves =
-				calloc(AR5K_EEPROM_N_PD_CURVES,
-				       sizeof(struct ath5k_pdgain_info));
-
-		if (!chinfo[pier].pd_curves)
-			return -ENOMEM;
-
-		/* Fill pd_curves */
-		for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
-
-			u8 idx = pdgain_idx[pdg];
-			struct ath5k_pdgain_info *pd =
-					&chinfo[pier].pd_curves[idx];
-
-			/* One more point for the highest power
-			 * curve (lowest gain) */
-			if (pdg == ee->ee_pd_gains[mode] - 1)
-				pd->pd_points = AR5K_EEPROM_N_PD_POINTS;
-			else
-				pd->pd_points = AR5K_EEPROM_N_PD_POINTS - 1;
-
-			/* Allocate pd points for this curve */
-			pd->pd_step = calloc(pd->pd_points, sizeof(u8));
-
-			if (!pd->pd_step)
-				return -ENOMEM;
-
-			pd->pd_pwr = calloc(pd->pd_points, sizeof(s16));
-
-			if (!pd->pd_pwr)
-				return -ENOMEM;
-
-			/* Fill raw dataset
-			 * convert all pwr levels to
-			 * quarter dB for RF5112 combatibility */
-			pd->pd_step[0] = pcinfo->pddac_i[pdg];
-			pd->pd_pwr[0] = 4 * pcinfo->pwr_i[pdg];
-
-			for (point = 1; point < pd->pd_points; point++) {
-
-				pd->pd_pwr[point] = pd->pd_pwr[point - 1] +
-					2 * pcinfo->pwr[pdg][point - 1];
-
-				pd->pd_step[point] = pd->pd_step[point - 1] +
-						pcinfo->pddac[pdg][point - 1];
-
-			}
-
-			/* Highest gain curve -> min power */
-			if (pdg == 0)
-				chinfo[pier].min_pwr = pd->pd_pwr[0];
-
-			/* Lowest gain curve -> max power */
-			if (pdg == ee->ee_pd_gains[mode] - 1)
-				chinfo[pier].max_pwr =
-					pd->pd_pwr[pd->pd_points - 1];
-		}
-	}
-
-	return 0;
-}
-
-/* Parse EEPROM data */
-static int
-ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct ath5k_chan_pcal_info_rf2413 *pcinfo;
-	struct ath5k_chan_pcal_info *chinfo;
-	u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];
-	u32 offset;
-	int idx, i, ret;
-	u16 val;
-	u8 pd_gains = 0;
-
-	/* Count how many curves we have and
-	 * identify them (which one of the 4
-	 * available curves we have on each count).
-	 * Curves are stored from higher to
-	 * lower gain so we go backwards */
-	for (idx = AR5K_EEPROM_N_PD_CURVES - 1; idx >= 0; idx--) {
-		/* ee_x_gain[mode] is x gain mask */
-		if ((ee->ee_x_gain[mode] >> idx) & 0x1)
-			pdgain_idx[pd_gains++] = idx;
-
-	}
-	ee->ee_pd_gains[mode] = pd_gains;
-
-	if (pd_gains == 0)
-		return -EINVAL;
-
-	offset = ath5k_cal_data_offset_2413(ee, mode);
-	switch (mode) {
-	case AR5K_EEPROM_MODE_11A:
-		if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
-			return 0;
-
-		ath5k_eeprom_init_11a_pcal_freq(ah, offset);
-		offset += AR5K_EEPROM_N_5GHZ_CHAN / 2;
-		chinfo = ee->ee_pwr_cal_a;
-		break;
-	case AR5K_EEPROM_MODE_11B:
-		if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
-			return 0;
-
-		ath5k_eeprom_init_11bg_2413(ah, mode, offset);
-		offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
-		chinfo = ee->ee_pwr_cal_b;
-		break;
-	case AR5K_EEPROM_MODE_11G:
-		if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
-			return 0;
-
-		ath5k_eeprom_init_11bg_2413(ah, mode, offset);
-		offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;
-		chinfo = ee->ee_pwr_cal_g;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	for (i = 0; i < ee->ee_n_piers[mode]; i++) {
-		pcinfo = &chinfo[i].rf2413_info;
-
-		/*
-		 * Read pwr_i, pddac_i and the first
-		 * 2 pd points (pwr, pddac)
-		 */
-		AR5K_EEPROM_READ(offset++, val);
-		pcinfo->pwr_i[0] = val & 0x1f;
-		pcinfo->pddac_i[0] = (val >> 5) & 0x7f;
-		pcinfo->pwr[0][0] = (val >> 12) & 0xf;
-
-		AR5K_EEPROM_READ(offset++, val);
-		pcinfo->pddac[0][0] = val & 0x3f;
-		pcinfo->pwr[0][1] = (val >> 6) & 0xf;
-		pcinfo->pddac[0][1] = (val >> 10) & 0x3f;
-
-		AR5K_EEPROM_READ(offset++, val);
-		pcinfo->pwr[0][2] = val & 0xf;
-		pcinfo->pddac[0][2] = (val >> 4) & 0x3f;
-
-		pcinfo->pwr[0][3] = 0;
-		pcinfo->pddac[0][3] = 0;
-
-		if (pd_gains > 1) {
-			/*
-			 * Pd gain 0 is not the last pd gain
-			 * so it only has 2 pd points.
-			 * Continue wih pd gain 1.
-			 */
-			pcinfo->pwr_i[1] = (val >> 10) & 0x1f;
-
-			pcinfo->pddac_i[1] = (val >> 15) & 0x1;
-			AR5K_EEPROM_READ(offset++, val);
-			pcinfo->pddac_i[1] |= (val & 0x3F) << 1;
-
-			pcinfo->pwr[1][0] = (val >> 6) & 0xf;
-			pcinfo->pddac[1][0] = (val >> 10) & 0x3f;
-
-			AR5K_EEPROM_READ(offset++, val);
-			pcinfo->pwr[1][1] = val & 0xf;
-			pcinfo->pddac[1][1] = (val >> 4) & 0x3f;
-			pcinfo->pwr[1][2] = (val >> 10) & 0xf;
-
-			pcinfo->pddac[1][2] = (val >> 14) & 0x3;
-			AR5K_EEPROM_READ(offset++, val);
-			pcinfo->pddac[1][2] |= (val & 0xF) << 2;
-
-			pcinfo->pwr[1][3] = 0;
-			pcinfo->pddac[1][3] = 0;
-		} else if (pd_gains == 1) {
-			/*
-			 * Pd gain 0 is the last one so
-			 * read the extra point.
-			 */
-			pcinfo->pwr[0][3] = (val >> 10) & 0xf;
-
-			pcinfo->pddac[0][3] = (val >> 14) & 0x3;
-			AR5K_EEPROM_READ(offset++, val);
-			pcinfo->pddac[0][3] |= (val & 0xF) << 2;
-		}
-
-		/*
-		 * Proceed with the other pd_gains
-		 * as above.
-		 */
-		if (pd_gains > 2) {
-			pcinfo->pwr_i[2] = (val >> 4) & 0x1f;
-			pcinfo->pddac_i[2] = (val >> 9) & 0x7f;
-
-			AR5K_EEPROM_READ(offset++, val);
-			pcinfo->pwr[2][0] = (val >> 0) & 0xf;
-			pcinfo->pddac[2][0] = (val >> 4) & 0x3f;
-			pcinfo->pwr[2][1] = (val >> 10) & 0xf;
-
-			pcinfo->pddac[2][1] = (val >> 14) & 0x3;
-			AR5K_EEPROM_READ(offset++, val);
-			pcinfo->pddac[2][1] |= (val & 0xF) << 2;
-
-			pcinfo->pwr[2][2] = (val >> 4) & 0xf;
-			pcinfo->pddac[2][2] = (val >> 8) & 0x3f;
-
-			pcinfo->pwr[2][3] = 0;
-			pcinfo->pddac[2][3] = 0;
-		} else if (pd_gains == 2) {
-			pcinfo->pwr[1][3] = (val >> 4) & 0xf;
-			pcinfo->pddac[1][3] = (val >> 8) & 0x3f;
-		}
-
-		if (pd_gains > 3) {
-			pcinfo->pwr_i[3] = (val >> 14) & 0x3;
-			AR5K_EEPROM_READ(offset++, val);
-			pcinfo->pwr_i[3] |= ((val >> 0) & 0x7) << 2;
-
-			pcinfo->pddac_i[3] = (val >> 3) & 0x7f;
-			pcinfo->pwr[3][0] = (val >> 10) & 0xf;
-			pcinfo->pddac[3][0] = (val >> 14) & 0x3;
-
-			AR5K_EEPROM_READ(offset++, val);
-			pcinfo->pddac[3][0] |= (val & 0xF) << 2;
-			pcinfo->pwr[3][1] = (val >> 4) & 0xf;
-			pcinfo->pddac[3][1] = (val >> 8) & 0x3f;
-
-			pcinfo->pwr[3][2] = (val >> 14) & 0x3;
-			AR5K_EEPROM_READ(offset++, val);
-			pcinfo->pwr[3][2] |= ((val >> 0) & 0x3) << 2;
-
-			pcinfo->pddac[3][2] = (val >> 2) & 0x3f;
-			pcinfo->pwr[3][3] = (val >> 8) & 0xf;
-
-			pcinfo->pddac[3][3] = (val >> 12) & 0xF;
-			AR5K_EEPROM_READ(offset++, val);
-			pcinfo->pddac[3][3] |= ((val >> 0) & 0x3) << 4;
-		} else if (pd_gains == 3) {
-			pcinfo->pwr[2][3] = (val >> 14) & 0x3;
-			AR5K_EEPROM_READ(offset++, val);
-			pcinfo->pwr[2][3] |= ((val >> 0) & 0x3) << 2;
-
-			pcinfo->pddac[2][3] = (val >> 2) & 0x3f;
-		}
-	}
-
-	return ath5k_eeprom_convert_pcal_info_2413(ah, mode, chinfo);
-}
-
-
-/*
- * Read per rate target power (this is the maximum tx power
- * supported by the card). This info is used when setting
- * tx power, no matter the channel.
- *
- * This also works for v5 EEPROMs.
- */
-static int
-ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct ath5k_rate_pcal_info *rate_pcal_info;
-	u8 *rate_target_pwr_num;
-	u32 offset;
-	u16 val;
-	int ret, i;
-
-	offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1);
-	rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode];
-	switch (mode) {
-	case AR5K_EEPROM_MODE_11A:
-		offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version);
-		rate_pcal_info = ee->ee_rate_tpwr_a;
-		ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN;
-		break;
-	case AR5K_EEPROM_MODE_11B:
-		offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version);
-		rate_pcal_info = ee->ee_rate_tpwr_b;
-		ee->ee_rate_target_pwr_num[mode] = 2; /* 3rd is g mode's 1st */
-		break;
-	case AR5K_EEPROM_MODE_11G:
-		offset += AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version);
-		rate_pcal_info = ee->ee_rate_tpwr_g;
-		ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_2GHZ_CHAN;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* Different freq mask for older eeproms (<= v3.2) */
-	if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) {
-		for (i = 0; i < (*rate_target_pwr_num); i++) {
-			AR5K_EEPROM_READ(offset++, val);
-			rate_pcal_info[i].freq =
-			    ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode);
-
-			rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f);
-			rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f;
-
-			AR5K_EEPROM_READ(offset++, val);
-
-			if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
-			    val == 0) {
-				(*rate_target_pwr_num) = i;
-				break;
-			}
-
-			rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7);
-			rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f);
-			rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f);
-		}
-	} else {
-		for (i = 0; i < (*rate_target_pwr_num); i++) {
-			AR5K_EEPROM_READ(offset++, val);
-			rate_pcal_info[i].freq =
-			    ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);
-
-			rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f);
-			rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f;
-
-			AR5K_EEPROM_READ(offset++, val);
-
-			if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||
-			    val == 0) {
-				(*rate_target_pwr_num) = i;
-				break;
-			}
-
-			rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf;
-			rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f);
-			rate_pcal_info[i].target_power_54 = (val & 0x3f);
-		}
-	}
-
-	return 0;
-}
-
-/*
- * Read per channel calibration info from EEPROM
- *
- * This info is used to calibrate the baseband power table. Imagine
- * that for each channel there is a power curve that's hw specific
- * (depends on amplifier etc) and we try to "correct" this curve using
- * offests we pass on to phy chip (baseband -> before amplifier) so that
- * it can use accurate power values when setting tx power (takes amplifier's
- * performance on each channel into account).
- *
- * EEPROM provides us with the offsets for some pre-calibrated channels
- * and we have to interpolate to create the full table for these channels and
- * also the table for any channel.
- */
-static int
-ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	int (*read_pcal)(struct ath5k_hw *hw, int mode);
-	int mode;
-	int err;
-
-	if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) &&
-			(AR5K_EEPROM_EEMAP(ee->ee_misc0) == 1))
-		read_pcal = ath5k_eeprom_read_pcal_info_5112;
-	else if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0) &&
-			(AR5K_EEPROM_EEMAP(ee->ee_misc0) == 2))
-		read_pcal = ath5k_eeprom_read_pcal_info_2413;
-	else
-		read_pcal = ath5k_eeprom_read_pcal_info_5111;
-
-
-	for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G;
-	mode++) {
-		err = read_pcal(ah, mode);
-		if (err)
-			return err;
-
-		err = ath5k_eeprom_read_target_rate_pwr_info(ah, mode);
-		if (err < 0)
-			return err;
-	}
-
-	return 0;
-}
-
-static int
-ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct ath5k_chan_pcal_info *chinfo;
-	u8 pier, pdg;
-
-	switch (mode) {
-	case AR5K_EEPROM_MODE_11A:
-		if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
-			return 0;
-		chinfo = ee->ee_pwr_cal_a;
-		break;
-	case AR5K_EEPROM_MODE_11B:
-		if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
-			return 0;
-		chinfo = ee->ee_pwr_cal_b;
-		break;
-	case AR5K_EEPROM_MODE_11G:
-		if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
-			return 0;
-		chinfo = ee->ee_pwr_cal_g;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
-		if (!chinfo[pier].pd_curves)
-			continue;
-
-		for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
-			struct ath5k_pdgain_info *pd =
-					&chinfo[pier].pd_curves[pdg];
-
-			if (pd != NULL) {
-				free(pd->pd_step);
-				free(pd->pd_pwr);
-			}
-		}
-
-		free(chinfo[pier].pd_curves);
-	}
-
-	return 0;
-}
-
-void
-ath5k_eeprom_detach(struct ath5k_hw *ah)
-{
-	u8 mode;
-
-	for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++)
-		ath5k_eeprom_free_pcal_info(ah, mode);
-}
-
-/* Read conformance test limits used for regulatory control */
-static int
-ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct ath5k_edge_power *rep;
-	unsigned int fmask, pmask;
-	unsigned int ctl_mode;
-	int ret, i, j;
-	u32 offset;
-	u16 val;
-
-	pmask = AR5K_EEPROM_POWER_M;
-	fmask = AR5K_EEPROM_FREQ_M(ee->ee_version);
-	offset = AR5K_EEPROM_CTL(ee->ee_version);
-	ee->ee_ctls = AR5K_EEPROM_N_CTLS(ee->ee_version);
-	for (i = 0; i < ee->ee_ctls; i += 2) {
-		AR5K_EEPROM_READ(offset++, val);
-		ee->ee_ctl[i] = (val >> 8) & 0xff;
-		ee->ee_ctl[i + 1] = val & 0xff;
-	}
-
-	offset = AR5K_EEPROM_GROUP8_OFFSET;
-	if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0)
-		offset += AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) -
-			AR5K_EEPROM_GROUP5_OFFSET;
-	else
-		offset += AR5K_EEPROM_GROUPS_START(ee->ee_version);
-
-	rep = ee->ee_ctl_pwr;
-	for(i = 0; i < ee->ee_ctls; i++) {
-		switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) {
-		case AR5K_CTL_11A:
-		case AR5K_CTL_TURBO:
-			ctl_mode = AR5K_EEPROM_MODE_11A;
-			break;
-		default:
-			ctl_mode = AR5K_EEPROM_MODE_11G;
-			break;
-		}
-		if (ee->ee_ctl[i] == 0) {
-			if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3)
-				offset += 8;
-			else
-				offset += 7;
-			rep += AR5K_EEPROM_N_EDGES;
-			continue;
-		}
-		if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {
-			for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
-				AR5K_EEPROM_READ(offset++, val);
-				rep[j].freq = (val >> 8) & fmask;
-				rep[j + 1].freq = val & fmask;
-			}
-			for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {
-				AR5K_EEPROM_READ(offset++, val);
-				rep[j].edge = (val >> 8) & pmask;
-				rep[j].flag = (val >> 14) & 1;
-				rep[j + 1].edge = val & pmask;
-				rep[j + 1].flag = (val >> 6) & 1;
-			}
-		} else {
-			AR5K_EEPROM_READ(offset++, val);
-			rep[0].freq = (val >> 9) & fmask;
-			rep[1].freq = (val >> 2) & fmask;
-			rep[2].freq = (val << 5) & fmask;
-
-			AR5K_EEPROM_READ(offset++, val);
-			rep[2].freq |= (val >> 11) & 0x1f;
-			rep[3].freq = (val >> 4) & fmask;
-			rep[4].freq = (val << 3) & fmask;
-
-			AR5K_EEPROM_READ(offset++, val);
-			rep[4].freq |= (val >> 13) & 0x7;
-			rep[5].freq = (val >> 6) & fmask;
-			rep[6].freq = (val << 1) & fmask;
-
-			AR5K_EEPROM_READ(offset++, val);
-			rep[6].freq |= (val >> 15) & 0x1;
-			rep[7].freq = (val >> 8) & fmask;
-
-			rep[0].edge = (val >> 2) & pmask;
-			rep[1].edge = (val << 4) & pmask;
-
-			AR5K_EEPROM_READ(offset++, val);
-			rep[1].edge |= (val >> 12) & 0xf;
-			rep[2].edge = (val >> 6) & pmask;
-			rep[3].edge = val & pmask;
-
-			AR5K_EEPROM_READ(offset++, val);
-			rep[4].edge = (val >> 10) & pmask;
-			rep[5].edge = (val >> 4) & pmask;
-			rep[6].edge = (val << 2) & pmask;
-
-			AR5K_EEPROM_READ(offset++, val);
-			rep[6].edge |= (val >> 14) & 0x3;
-			rep[7].edge = (val >> 8) & pmask;
-		}
-		for (j = 0; j < AR5K_EEPROM_N_EDGES; j++) {
-			rep[j].freq = ath5k_eeprom_bin2freq(ee,
-				rep[j].freq, ctl_mode);
-		}
-		rep += AR5K_EEPROM_N_EDGES;
-	}
-
-	return 0;
-}
-
-
-/*
- * Initialize eeprom power tables
- */
-int
-ath5k_eeprom_init(struct ath5k_hw *ah)
-{
-	int err;
-
-	err = ath5k_eeprom_init_header(ah);
-	if (err < 0)
-		return err;
-
-	err = ath5k_eeprom_init_modes(ah);
-	if (err < 0)
-		return err;
-
-	err = ath5k_eeprom_read_pcal_info(ah);
-	if (err < 0)
-		return err;
-
-	err = ath5k_eeprom_read_ctl_info(ah);
-	if (err < 0)
-		return err;
-
-	return 0;
-}
-
-/*
- * Read the MAC address from eeprom
- */
-int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
-{
-	u8 mac_d[ETH_ALEN] = {};
-	u32 total, offset;
-	u16 data;
-	int octet, ret;
-
-	ret = ath5k_hw_eeprom_read(ah, 0x20, &data);
-	if (ret)
-		return ret;
-
-	for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
-		ret = ath5k_hw_eeprom_read(ah, offset, &data);
-		if (ret)
-			return ret;
-
-		total += data;
-		mac_d[octet + 1] = data & 0xff;
-		mac_d[octet] = data >> 8;
-		octet += 2;
-	}
-
-	if (!total || total == 3 * 0xffff)
-		return -EINVAL;
-
-	memcpy(mac, mac_d, ETH_ALEN);
-
-	return 0;
-}
-
-int ath5k_eeprom_is_hb63(struct ath5k_hw *ah)
-{
-	u16 data;
-
-	ath5k_hw_eeprom_read(ah, AR5K_EEPROM_IS_HB63, &data);
-
-	if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && data)
-		return 1;
-	else
-		return 0;
-}
-
diff --git a/roms/ipxe/src/drivers/net/ath5k/ath5k_gpio.c b/roms/ipxe/src/drivers/net/ath5k/ath5k_gpio.c
deleted file mode 100644
index 2301ec70b40dbc75e55ee350cf28b8bcd7c48b0c..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/ath5k_gpio.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
- *
- * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-FILE_LICENCE ( MIT );
-
-/****************\
-  GPIO Functions
-\****************/
-
-#include "ath5k.h"
-#include "reg.h"
-#include "base.h"
-
-/*
- * Set GPIO inputs
- */
-int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
-{
-	if (gpio >= AR5K_NUM_GPIO)
-		return -EINVAL;
-
-	ath5k_hw_reg_write(ah,
-		(ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio))
-		| AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR);
-
-	return 0;
-}
-
-/*
- * Set GPIO outputs
- */
-int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
-{
-	if (gpio >= AR5K_NUM_GPIO)
-		return -EINVAL;
-
-	ath5k_hw_reg_write(ah,
-		(ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio))
-		| AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR);
-
-	return 0;
-}
-
-/*
- * Get GPIO state
- */
-u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
-{
-	if (gpio >= AR5K_NUM_GPIO)
-		return 0xffffffff;
-
-	/* GPIO input magic */
-	return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) &
-		0x1;
-}
-
-/*
- * Set GPIO state
- */
-int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
-{
-	u32 data;
-
-	if (gpio >= AR5K_NUM_GPIO)
-		return -EINVAL;
-
-	/* GPIO output magic */
-	data = ath5k_hw_reg_read(ah, AR5K_GPIODO);
-
-	data &= ~(1 << gpio);
-	data |= (val & 1) << gpio;
-
-	ath5k_hw_reg_write(ah, data, AR5K_GPIODO);
-
-	return 0;
-}
-
-/*
- * Initialize the GPIO interrupt (RFKill switch)
- */
-void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
-		u32 interrupt_level)
-{
-	u32 data;
-
-	if (gpio >= AR5K_NUM_GPIO)
-		return;
-
-	/*
-	 * Set the GPIO interrupt
-	 */
-	data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &
-		~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH |
-		AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) |
-		(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA);
-
-	ath5k_hw_reg_write(ah, interrupt_level ? data :
-		(data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR);
-
-	ah->ah_imr |= AR5K_IMR_GPIO;
-
-	/* Enable GPIO interrupts */
-	AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO);
-}
-
diff --git a/roms/ipxe/src/drivers/net/ath5k/ath5k_initvals.c b/roms/ipxe/src/drivers/net/ath5k/ath5k_initvals.c
deleted file mode 100644
index 8f3bd20345e870e2152001a5d3af2e4de2de9cf3..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/ath5k_initvals.c
+++ /dev/null
@@ -1,1560 +0,0 @@
-/*
- * Initial register settings functions
- *
- * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>
- * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
- *
- * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-FILE_LICENCE ( MIT );
-
-#include <unistd.h>
-
-#include "ath5k.h"
-#include "reg.h"
-#include "base.h"
-
-/*
- * Mode-independent initial register writes
- */
-
-struct ath5k_ini {
-	u16	ini_register;
-	u32	ini_value;
-
-	enum {
-		AR5K_INI_WRITE = 0,	/* Default */
-		AR5K_INI_READ = 1,	/* Cleared on read */
-	} ini_mode;
-};
-
-/*
- * Mode specific initial register values
- */
-
-struct ath5k_ini_mode {
-	u16	mode_register;
-	u32	mode_value[5];
-};
-
-/* Initial register settings for AR5210 */
-static const struct ath5k_ini ar5210_ini[] = {
-	/* PCU and MAC registers */
-	{ AR5K_NOQCU_TXDP0,	0, AR5K_INI_WRITE },
-	{ AR5K_NOQCU_TXDP1,	0, AR5K_INI_WRITE },
-	{ AR5K_RXDP,		0, AR5K_INI_WRITE },
-	{ AR5K_CR,		0, AR5K_INI_WRITE },
-	{ AR5K_ISR,		0, AR5K_INI_READ },
-	{ AR5K_IMR,		0, AR5K_INI_WRITE },
-	{ AR5K_IER,		AR5K_IER_DISABLE, AR5K_INI_WRITE },
-	{ AR5K_BSR,		0, AR5K_INI_READ },
-	{ AR5K_TXCFG,		AR5K_DMASIZE_128B, AR5K_INI_WRITE },
-	{ AR5K_RXCFG,		AR5K_DMASIZE_128B, AR5K_INI_WRITE },
-	{ AR5K_CFG,		AR5K_INIT_CFG, AR5K_INI_WRITE },
-	{ AR5K_TOPS,		8, AR5K_INI_WRITE },
-	{ AR5K_RXNOFRM,		8, AR5K_INI_WRITE },
-	{ AR5K_RPGTO,		0, AR5K_INI_WRITE },
-	{ AR5K_TXNOFRM,		0, AR5K_INI_WRITE },
-	{ AR5K_SFR,		0, AR5K_INI_WRITE },
-	{ AR5K_MIBC,		0, AR5K_INI_WRITE },
-	{ AR5K_MISC,		0, AR5K_INI_WRITE },
-	{ AR5K_RX_FILTER_5210,	0, AR5K_INI_WRITE },
-	{ AR5K_MCAST_FILTER0_5210, 0, AR5K_INI_WRITE },
-	{ AR5K_MCAST_FILTER1_5210, 0, AR5K_INI_WRITE },
-	{ AR5K_TX_MASK0,	0, AR5K_INI_WRITE },
-	{ AR5K_TX_MASK1,	0, AR5K_INI_WRITE },
-	{ AR5K_CLR_TMASK,	0, AR5K_INI_WRITE },
-	{ AR5K_TRIG_LVL,	AR5K_TUNE_MIN_TX_FIFO_THRES, AR5K_INI_WRITE },
-	{ AR5K_DIAG_SW_5210,	0, AR5K_INI_WRITE },
-	{ AR5K_RSSI_THR,	AR5K_TUNE_RSSI_THRES, AR5K_INI_WRITE },
-	{ AR5K_TSF_L32_5210,	0, AR5K_INI_WRITE },
-	{ AR5K_TIMER0_5210,	0, AR5K_INI_WRITE },
-	{ AR5K_TIMER1_5210,	0xffffffff, AR5K_INI_WRITE },
-	{ AR5K_TIMER2_5210,	0xffffffff, AR5K_INI_WRITE },
-	{ AR5K_TIMER3_5210,	1, AR5K_INI_WRITE },
-	{ AR5K_CFP_DUR_5210,	0, AR5K_INI_WRITE },
-	{ AR5K_CFP_PERIOD_5210,	0, AR5K_INI_WRITE },
-	/* PHY registers */
-	{ AR5K_PHY(0),	0x00000047, AR5K_INI_WRITE },
-	{ AR5K_PHY_AGC,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(3),	0x09848ea6, AR5K_INI_WRITE },
-	{ AR5K_PHY(4),	0x3d32e000, AR5K_INI_WRITE },
-	{ AR5K_PHY(5),	0x0000076b, AR5K_INI_WRITE },
-	{ AR5K_PHY_ACT,	AR5K_PHY_ACT_DISABLE, AR5K_INI_WRITE },
-	{ AR5K_PHY(8),	0x02020200, AR5K_INI_WRITE },
-	{ AR5K_PHY(9),	0x00000e0e, AR5K_INI_WRITE },
-	{ AR5K_PHY(10),	0x0a020201, AR5K_INI_WRITE },
-	{ AR5K_PHY(11),	0x00036ffc, AR5K_INI_WRITE },
-	{ AR5K_PHY(12),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(13),	0x00000e0e, AR5K_INI_WRITE },
-	{ AR5K_PHY(14),	0x00000007, AR5K_INI_WRITE },
-	{ AR5K_PHY(15),	0x00020100, AR5K_INI_WRITE },
-	{ AR5K_PHY(16),	0x89630000, AR5K_INI_WRITE },
-	{ AR5K_PHY(17),	0x1372169c, AR5K_INI_WRITE },
-	{ AR5K_PHY(18),	0x0018b633, AR5K_INI_WRITE },
-	{ AR5K_PHY(19),	0x1284613c, AR5K_INI_WRITE },
-	{ AR5K_PHY(20),	0x0de8b8e0, AR5K_INI_WRITE },
-	{ AR5K_PHY(21),	0x00074859, AR5K_INI_WRITE },
-	{ AR5K_PHY(22),	0x7e80beba, AR5K_INI_WRITE },
-	{ AR5K_PHY(23),	0x313a665e, AR5K_INI_WRITE },
-	{ AR5K_PHY_AGCCTL, 0x00001d08, AR5K_INI_WRITE },
-	{ AR5K_PHY(25),	0x0001ce00, AR5K_INI_WRITE },
-	{ AR5K_PHY(26),	0x409a4190, AR5K_INI_WRITE },
-	{ AR5K_PHY(28),	0x0000000f, AR5K_INI_WRITE },
-	{ AR5K_PHY(29),	0x00000080, AR5K_INI_WRITE },
-	{ AR5K_PHY(30),	0x00000004, AR5K_INI_WRITE },
-	{ AR5K_PHY(31),	0x00000018, AR5K_INI_WRITE }, 	/* 0x987c */
-	{ AR5K_PHY(64),	0x00000000, AR5K_INI_WRITE }, 	/* 0x9900 */
-	{ AR5K_PHY(65),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(66),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(67),	0x00800000, AR5K_INI_WRITE },
-	{ AR5K_PHY(68),	0x00000003, AR5K_INI_WRITE },
-	/* BB gain table (64bytes) */
-	{ AR5K_BB_GAIN(0), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(1), 0x00000020, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(2), 0x00000010, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(3), 0x00000030, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(4), 0x00000008, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(5), 0x00000028, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(6), 0x00000028, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(7), 0x00000004, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(8), 0x00000024, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(9), 0x00000014, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(10), 0x00000034, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(11), 0x0000000c, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(12), 0x0000002c, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(13), 0x00000002, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(14), 0x00000022, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(15), 0x00000012, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(16), 0x00000032, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(17), 0x0000000a, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(18), 0x0000002a, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(19), 0x00000001, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(20), 0x00000021, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(21), 0x00000011, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(22), 0x00000031, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(23), 0x00000009, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(24), 0x00000029, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(25), 0x00000005, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(26), 0x00000025, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(27), 0x00000015, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(28), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(29), 0x0000000d, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(30), 0x0000002d, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(31), 0x00000003, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(32), 0x00000023, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(33), 0x00000013, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(34), 0x00000033, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(35), 0x0000000b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(36), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(37), 0x00000007, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(38), 0x00000027, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(39), 0x00000017, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(40), 0x00000037, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(41), 0x0000000f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(42), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(43), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(44), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(45), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(46), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(47), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(48), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(49), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(50), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(51), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(52), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(53), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(54), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(55), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(56), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(57), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(58), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(59), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(60), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(61), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(62), 0x0000002f, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(63), 0x0000002f, AR5K_INI_WRITE },
-	/* 5110 RF gain table (64btes) */
-	{ AR5K_RF_GAIN(0), 0x0000001d, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(1), 0x0000005d, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(2), 0x0000009d, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(3), 0x000000dd, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(4), 0x0000011d, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(5), 0x00000021, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(6), 0x00000061, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(7), 0x000000a1, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(8), 0x000000e1, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(9), 0x00000031, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(10), 0x00000071, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(11), 0x000000b1, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(12), 0x0000001c, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(13), 0x0000005c, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(14), 0x00000029, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(15), 0x00000069, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(16), 0x000000a9, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(17), 0x00000020, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(18), 0x00000019, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(19), 0x00000059, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(20), 0x00000099, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(21), 0x00000030, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(22), 0x00000005, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(23), 0x00000025, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(24), 0x00000065, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(25), 0x000000a5, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(26), 0x00000028, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(27), 0x00000068, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(28), 0x0000001f, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(29), 0x0000001e, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(30), 0x00000018, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(31), 0x00000058, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(32), 0x00000098, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(33), 0x00000003, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(34), 0x00000004, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(35), 0x00000044, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(36), 0x00000084, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(37), 0x00000013, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(38), 0x00000012, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(39), 0x00000052, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(40), 0x00000092, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(41), 0x000000d2, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(42), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(43), 0x0000002a, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(44), 0x0000006a, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(45), 0x000000aa, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(46), 0x0000001b, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(47), 0x0000001a, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(48), 0x0000005a, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(49), 0x0000009a, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(50), 0x000000da, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(51), 0x00000006, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(52), 0x00000006, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(53), 0x00000006, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(54), 0x00000006, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(55), 0x00000006, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(56), 0x00000006, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(57), 0x00000006, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(58), 0x00000006, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(59), 0x00000006, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(60), 0x00000006, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(61), 0x00000006, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(62), 0x00000006, AR5K_INI_WRITE },
-	{ AR5K_RF_GAIN(63), 0x00000006, AR5K_INI_WRITE },
-	/* PHY activation */
-	{ AR5K_PHY(53), 0x00000020, AR5K_INI_WRITE },
-	{ AR5K_PHY(51), 0x00000004, AR5K_INI_WRITE },
-	{ AR5K_PHY(50), 0x00060106, AR5K_INI_WRITE },
-	{ AR5K_PHY(39), 0x0000006d, AR5K_INI_WRITE },
-	{ AR5K_PHY(48), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(52), 0x00000014, AR5K_INI_WRITE },
-	{ AR5K_PHY_ACT, AR5K_PHY_ACT_ENABLE, AR5K_INI_WRITE },
-};
-
-/* Initial register settings for AR5211 */
-static const struct ath5k_ini ar5211_ini[] = {
-	{ AR5K_RXDP,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RTSD0,		0x84849c9c, AR5K_INI_WRITE },
-	{ AR5K_RTSD1,		0x7c7c7c7c, AR5K_INI_WRITE },
-	{ AR5K_RXCFG,		0x00000005, AR5K_INI_WRITE },
-	{ AR5K_MIBC,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_TOPS,		0x00000008, AR5K_INI_WRITE },
-	{ AR5K_RXNOFRM,		0x00000008, AR5K_INI_WRITE },
-	{ AR5K_TXNOFRM,		0x00000010, AR5K_INI_WRITE },
-	{ AR5K_RPGTO,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RFCNT,		0x0000001f, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(0),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(1),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(2),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(3),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(4),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(5),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(6),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(7),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(8),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(9),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_FP,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_STA_ID1,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_BSS_ID0,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_BSS_ID1,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RSSI_THR,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_CFP_PERIOD_5211,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_TIMER0_5211,	0x00000030, AR5K_INI_WRITE },
-	{ AR5K_TIMER1_5211,	0x0007ffff, AR5K_INI_WRITE },
-	{ AR5K_TIMER2_5211,	0x01ffffff, AR5K_INI_WRITE },
-	{ AR5K_TIMER3_5211,	0x00000031, AR5K_INI_WRITE },
-	{ AR5K_CFP_DUR_5211,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RX_FILTER_5211,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_MCAST_FILTER0_5211, 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_MCAST_FILTER1_5211, 0x00000002, AR5K_INI_WRITE },
-	{ AR5K_DIAG_SW_5211,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_ADDAC_TEST,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DEFAULT_ANTENNA,	0x00000000, AR5K_INI_WRITE },
-	/* PHY registers */
-	{ AR5K_PHY_AGC,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(3),	0x2d849093, AR5K_INI_WRITE },
-	{ AR5K_PHY(4),	0x7d32e000, AR5K_INI_WRITE },
-	{ AR5K_PHY(5),	0x00000f6b, AR5K_INI_WRITE },
-	{ AR5K_PHY_ACT,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(11),	0x00026ffe, AR5K_INI_WRITE },
-	{ AR5K_PHY(12),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(15),	0x00020100, AR5K_INI_WRITE },
-	{ AR5K_PHY(16),	0x206a017a, AR5K_INI_WRITE },
-	{ AR5K_PHY(19),	0x1284613c, AR5K_INI_WRITE },
-	{ AR5K_PHY(21),	0x00000859, AR5K_INI_WRITE },
-	{ AR5K_PHY(26),	0x409a4190, AR5K_INI_WRITE },	/* 0x9868 */
-	{ AR5K_PHY(27),	0x050cb081, AR5K_INI_WRITE },
-	{ AR5K_PHY(28),	0x0000000f, AR5K_INI_WRITE },
-	{ AR5K_PHY(29),	0x00000080, AR5K_INI_WRITE },
-	{ AR5K_PHY(30),	0x0000000c, AR5K_INI_WRITE },
-	{ AR5K_PHY(64),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(65),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(66),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(67),	0x00800000, AR5K_INI_WRITE },
-	{ AR5K_PHY(68),	0x00000001, AR5K_INI_WRITE },
-	{ AR5K_PHY(71),	0x0000092a, AR5K_INI_WRITE },
-	{ AR5K_PHY_IQ,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(73),	0x00058a05, AR5K_INI_WRITE },
-	{ AR5K_PHY(74),	0x00000001, AR5K_INI_WRITE },
-	{ AR5K_PHY(75),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_PAPD_PROBE, 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(77),	0x00000000, AR5K_INI_WRITE },	/* 0x9934 */
-	{ AR5K_PHY(78),	0x00000000, AR5K_INI_WRITE },	/* 0x9938 */
-	{ AR5K_PHY(79),	0x0000003f, AR5K_INI_WRITE },	/* 0x993c */
-	{ AR5K_PHY(80),	0x00000004, AR5K_INI_WRITE },
-	{ AR5K_PHY(82),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(83),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(84),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_RADAR, 0x5d50f14c, AR5K_INI_WRITE },
-	{ AR5K_PHY(86),	0x00000018, AR5K_INI_WRITE },
-	{ AR5K_PHY(87),	0x004b6a8e, AR5K_INI_WRITE },
-	/* Initial Power table (32bytes)
-	 * common on all cards/modes.
-	 * Note: Table is rewritten during
-	 * txpower setup later using calibration
-	 * data etc. so next write is non-common */
-	{ AR5K_PHY_PCDAC_TXPOWER(1), 0x06ff05ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(2), 0x07ff07ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(3), 0x08ff08ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(4), 0x09ff09ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(5), 0x0aff0aff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(6), 0x0bff0bff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(7), 0x0cff0cff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(8), 0x0dff0dff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(9), 0x0fff0eff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(10), 0x12ff12ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(11), 0x14ff13ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(12), 0x16ff15ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(13), 0x19ff17ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(14), 0x1bff1aff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(15), 0x1eff1dff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(16), 0x23ff20ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(17), 0x27ff25ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(18), 0x2cff29ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(19), 0x31ff2fff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(20), 0x37ff34ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(21), 0x3aff3aff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(22), 0x3aff3aff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(23), 0x3aff3aff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(24), 0x3aff3aff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(25), 0x3aff3aff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(26), 0x3aff3aff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(27), 0x3aff3aff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(28), 0x3aff3aff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(29), 0x3aff3aff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(30), 0x3aff3aff, AR5K_INI_WRITE },
-	{ AR5K_PHY_PCDAC_TXPOWER(31), 0x3aff3aff, AR5K_INI_WRITE },
-	{ AR5K_PHY_CCKTXCTL, 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(642), 0x503e4646, AR5K_INI_WRITE },
-	{ AR5K_PHY_GAIN_2GHZ, 0x6480416c, AR5K_INI_WRITE },
-	{ AR5K_PHY(644), 0x0199a003, AR5K_INI_WRITE },
-	{ AR5K_PHY(645), 0x044cd610, AR5K_INI_WRITE },
-	{ AR5K_PHY(646), 0x13800040, AR5K_INI_WRITE },
-	{ AR5K_PHY(647), 0x1be00060, AR5K_INI_WRITE },
-	{ AR5K_PHY(648), 0x0c53800a, AR5K_INI_WRITE },
-	{ AR5K_PHY(649), 0x0014df3b, AR5K_INI_WRITE },
-	{ AR5K_PHY(650), 0x000001b5, AR5K_INI_WRITE },
-	{ AR5K_PHY(651), 0x00000020, AR5K_INI_WRITE },
-};
-
-/* Initial mode-specific settings for AR5211
- * 5211 supports OFDM-only g (draft g) but we
- * need to test it !
- */
-static const struct ath5k_ini_mode ar5211_ini_mode[] = {
-	{ AR5K_TXCFG,
-	/*	  a	    aTurbo	  b	  g (OFDM)    */
-	   { 0x00000015, 0x00000015, 0x0000001d, 0x00000015 } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(0),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(1),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(2),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(3),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(4),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(5),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(6),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(7),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(8),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(9),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
-	{ AR5K_DCU_GBL_IFS_SLOT,
-	   { 0x00000168, 0x000001e0, 0x000001b8, 0x00000168 } },
-	{ AR5K_DCU_GBL_IFS_SIFS,
-	   { 0x00000230, 0x000001e0, 0x000000b0, 0x00000230 } },
-	{ AR5K_DCU_GBL_IFS_EIFS,
-	   { 0x00000d98, 0x00001180, 0x00001f48, 0x00000d98 } },
-	{ AR5K_DCU_GBL_IFS_MISC,
-	   { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000a0e0 } },
-	{ AR5K_TIME_OUT,
-	   { 0x04000400, 0x08000800, 0x20003000, 0x04000400 } },
-	{ AR5K_USEC_5211,
-	   { 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95, 0x0e8d8fa7 } },
-	{ AR5K_PHY_TURBO,
-	   { 0x00000000, 0x00000003, 0x00000000, 0x00000000 } },
-	{ AR5K_PHY(8),
-	   { 0x02020200, 0x02020200, 0x02010200, 0x02020200 } },
-	{ AR5K_PHY(9),
-	   { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e } },
-	{ AR5K_PHY(10),
-	   { 0x0a020001, 0x0a020001, 0x05010000, 0x0a020001 } },
-	{ AR5K_PHY(13),
-	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
-	{ AR5K_PHY(14),
-	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b } },
-	{ AR5K_PHY(17),
-	   { 0x1372169c, 0x137216a5, 0x137216a8, 0x1372169c } },
-	{ AR5K_PHY(18),
-	   { 0x0018ba67, 0x0018ba67, 0x0018ba69, 0x0018ba69 } },
-	{ AR5K_PHY(20),
-	   { 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } },
-	{ AR5K_PHY_SIG,
-	   { 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e, 0x7e800d2e } },
-	{ AR5K_PHY_AGCCOARSE,
-	   { 0x31375d5e, 0x31375d5e, 0x313a5d5e, 0x31375d5e } },
-	{ AR5K_PHY_AGCCTL,
-	   { 0x0000bd10, 0x0000bd10, 0x0000bd38, 0x0000bd10 } },
-	{ AR5K_PHY_NF,
-	   { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
-	{ AR5K_PHY_RX_DELAY,
-	   { 0x00002710, 0x00002710, 0x0000157c, 0x00002710 } },
-	{ AR5K_PHY(70),
-	   { 0x00000190, 0x00000190, 0x00000084, 0x00000190 } },
-	{ AR5K_PHY_FRAME_CTL_5211,
-	   { 0x6fe01020, 0x6fe01020, 0x6fe00920, 0x6fe01020 } },
-	{ AR5K_PHY_PCDAC_TXPOWER_BASE,
-	   { 0x05ff14ff, 0x05ff14ff, 0x05ff14ff, 0x05ff19ff } },
-	{ AR5K_RF_BUFFER_CONTROL_4,
-	   { 0x00000010, 0x00000014, 0x00000010, 0x00000010 } },
-};
-
-/* Initial register settings for AR5212 */
-static const struct ath5k_ini ar5212_ini_common_start[] = {
-	{ AR5K_RXDP,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RXCFG,		0x00000005, AR5K_INI_WRITE },
-	{ AR5K_MIBC,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_TOPS,		0x00000008, AR5K_INI_WRITE },
-	{ AR5K_RXNOFRM,		0x00000008, AR5K_INI_WRITE },
-	{ AR5K_TXNOFRM,		0x00000010, AR5K_INI_WRITE },
-	{ AR5K_RPGTO,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RFCNT,		0x0000001f, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(0),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(1),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(2),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(3),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(4),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(5),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(6),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(7),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(8),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUEUE_TXDP(9),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_FP,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TXP,		0x00000000, AR5K_INI_WRITE },
-	/* Tx filter table 0 (32 entries) */
-	{ AR5K_DCU_TX_FILTER_0(0),  0x00000000, AR5K_INI_WRITE }, /* DCU 0 */
-	{ AR5K_DCU_TX_FILTER_0(1),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(2),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(3),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(4),  0x00000000, AR5K_INI_WRITE }, /* DCU 1 */
-	{ AR5K_DCU_TX_FILTER_0(5),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(6),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(7),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(8),  0x00000000, AR5K_INI_WRITE }, /* DCU 2 */
-	{ AR5K_DCU_TX_FILTER_0(9),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(10), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(11), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(12), 0x00000000, AR5K_INI_WRITE }, /* DCU 3 */
-	{ AR5K_DCU_TX_FILTER_0(13), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(14), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(15), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(16), 0x00000000, AR5K_INI_WRITE }, /* DCU 4 */
-	{ AR5K_DCU_TX_FILTER_0(17), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(18), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(19), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(20), 0x00000000, AR5K_INI_WRITE }, /* DCU 5 */
-	{ AR5K_DCU_TX_FILTER_0(21), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(22), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(23), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(24), 0x00000000, AR5K_INI_WRITE }, /* DCU 6 */
-	{ AR5K_DCU_TX_FILTER_0(25), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(26), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(27), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(28), 0x00000000, AR5K_INI_WRITE }, /* DCU 7 */
-	{ AR5K_DCU_TX_FILTER_0(29), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(30), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_0(31), 0x00000000, AR5K_INI_WRITE },
-	/* Tx filter table 1 (16 entries) */
-	{ AR5K_DCU_TX_FILTER_1(0),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_1(1),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_1(2),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_1(3),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_1(4),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_1(5),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_1(6),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_1(7),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_1(8),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_1(9),  0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_1(10), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_1(11), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_1(12), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_1(13), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_1(14), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_1(15), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_CLR, 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_SET, 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_CLR, 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DCU_TX_FILTER_SET, 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_STA_ID1,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_BSS_ID0,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_BSS_ID1,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_BEACON_5211,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_CFP_PERIOD_5211, 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_TIMER0_5211,	0x00000030, AR5K_INI_WRITE },
-	{ AR5K_TIMER1_5211,	0x0007ffff, AR5K_INI_WRITE },
-	{ AR5K_TIMER2_5211,	0x01ffffff, AR5K_INI_WRITE },
-	{ AR5K_TIMER3_5211,	0x00000031, AR5K_INI_WRITE },
-	{ AR5K_CFP_DUR_5211,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RX_FILTER_5211,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DIAG_SW_5211,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_ADDAC_TEST,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_DEFAULT_ANTENNA,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_FRAME_CTL_QOSM, 	0x000fc78f, AR5K_INI_WRITE },
-	{ AR5K_XRMODE,		0x2a82301a, AR5K_INI_WRITE },
-	{ AR5K_XRDELAY,		0x05dc01e0, AR5K_INI_WRITE },
-	{ AR5K_XRTIMEOUT,	0x1f402710, AR5K_INI_WRITE },
-	{ AR5K_XRCHIRP,		0x01f40000, AR5K_INI_WRITE },
-	{ AR5K_XRSTOMP,		0x00001e1c, AR5K_INI_WRITE },
-	{ AR5K_SLEEP0,		0x0002aaaa, AR5K_INI_WRITE },
-	{ AR5K_SLEEP1,		0x02005555, AR5K_INI_WRITE },
-	{ AR5K_SLEEP2,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_BSS_IDM0,	0xffffffff, AR5K_INI_WRITE },
-	{ AR5K_BSS_IDM1,	0x0000ffff, AR5K_INI_WRITE },
-	{ AR5K_TXPC,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PROFCNT_TX,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PROFCNT_RX,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PROFCNT_RXCLR,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PROFCNT_CYCLE,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUIET_CTL1,	0x00000088, AR5K_INI_WRITE },
-	/* Initial rate duration table (32 entries )*/
-	{ AR5K_RATE_DUR(0),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(1),	0x0000008c, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(2),	0x000000e4, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(3),	0x000002d5, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(4),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(5),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(6),	0x000000a0, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(7),	0x000001c9, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(8),	0x0000002c, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(9),	0x0000002c, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(10),	0x00000030, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(11),	0x0000003c, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(12),	0x0000002c, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(13),	0x0000002c, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(14),	0x00000030, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(15),	0x0000003c, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(16),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(17),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(18),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(19),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(20),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(21),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(22),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(23),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(24),	0x000000d5, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(25),	0x000000df, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(26),	0x00000102, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(27),	0x0000013a, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(28),	0x00000075, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(29),	0x0000007f, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(30),	0x000000a2, AR5K_INI_WRITE },
-	{ AR5K_RATE_DUR(31),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_QUIET_CTL2,	0x00010002, AR5K_INI_WRITE },
-	{ AR5K_TSF_PARM,	0x00000001, AR5K_INI_WRITE },
-	{ AR5K_QOS_NOACK,	0x000000c0, AR5K_INI_WRITE },
-	{ AR5K_PHY_ERR_FIL,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_XRLAT_TX,	0x00000168, AR5K_INI_WRITE },
-	{ AR5K_ACKSIFS,		0x00000000, AR5K_INI_WRITE },
-	/* Rate -> db table
-	 * notice ...03<-02<-01<-00 ! */
-	{ AR5K_RATE2DB(0),	0x03020100, AR5K_INI_WRITE },
-	{ AR5K_RATE2DB(1),	0x07060504, AR5K_INI_WRITE },
-	{ AR5K_RATE2DB(2),	0x0b0a0908, AR5K_INI_WRITE },
-	{ AR5K_RATE2DB(3),	0x0f0e0d0c, AR5K_INI_WRITE },
-	{ AR5K_RATE2DB(4),	0x13121110, AR5K_INI_WRITE },
-	{ AR5K_RATE2DB(5),	0x17161514, AR5K_INI_WRITE },
-	{ AR5K_RATE2DB(6),	0x1b1a1918, AR5K_INI_WRITE },
-	{ AR5K_RATE2DB(7),	0x1f1e1d1c, AR5K_INI_WRITE },
-	/* Db -> Rate table */
-	{ AR5K_DB2RATE(0),	0x03020100, AR5K_INI_WRITE },
-	{ AR5K_DB2RATE(1),	0x07060504, AR5K_INI_WRITE },
-	{ AR5K_DB2RATE(2),	0x0b0a0908, AR5K_INI_WRITE },
-	{ AR5K_DB2RATE(3),	0x0f0e0d0c, AR5K_INI_WRITE },
-	{ AR5K_DB2RATE(4),	0x13121110, AR5K_INI_WRITE },
-	{ AR5K_DB2RATE(5),	0x17161514, AR5K_INI_WRITE },
-	{ AR5K_DB2RATE(6),	0x1b1a1918, AR5K_INI_WRITE },
-	{ AR5K_DB2RATE(7),	0x1f1e1d1c, AR5K_INI_WRITE },
-	/* PHY registers (Common settings
-	 * for all chips/modes) */
-	{ AR5K_PHY(3),		0xad848e19, AR5K_INI_WRITE },
-	{ AR5K_PHY(4),		0x7d28e000, AR5K_INI_WRITE },
-	{ AR5K_PHY_TIMING_3,	0x9c0a9f6b, AR5K_INI_WRITE },
-	{ AR5K_PHY_ACT,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY(16),		0x206a017a, AR5K_INI_WRITE },
-	{ AR5K_PHY(21),		0x00000859, AR5K_INI_WRITE },
-	{ AR5K_PHY_BIN_MASK_1,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_BIN_MASK_2,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_BIN_MASK_3,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_BIN_MASK_CTL, 0x00800000, AR5K_INI_WRITE },
-	{ AR5K_PHY_ANT_CTL,	0x00000001, AR5K_INI_WRITE },
-	/*{ AR5K_PHY(71), 0x0000092a, AR5K_INI_WRITE },*/ /* Old value */
-	{ AR5K_PHY_MAX_RX_LEN,	0x00000c80, AR5K_INI_WRITE },
-	{ AR5K_PHY_IQ,		0x05100000, AR5K_INI_WRITE },
-	{ AR5K_PHY_WARM_RESET,	0x00000001, AR5K_INI_WRITE },
-	{ AR5K_PHY_CTL,		0x00000004, AR5K_INI_WRITE },
-	{ AR5K_PHY_TXPOWER_RATE1, 0x1e1f2022, AR5K_INI_WRITE },
-	{ AR5K_PHY_TXPOWER_RATE2, 0x0a0b0c0d, AR5K_INI_WRITE },
-	{ AR5K_PHY_TXPOWER_RATE_MAX, 0x0000003f, AR5K_INI_WRITE },
-	{ AR5K_PHY(82),		0x9280b212, AR5K_INI_WRITE },
-	{ AR5K_PHY_RADAR,	0x5d50e188, AR5K_INI_WRITE },
-	/*{ AR5K_PHY(86), 0x000000ff, AR5K_INI_WRITE },*/
-	{ AR5K_PHY(87),		0x004b6a8e, AR5K_INI_WRITE },
-	{ AR5K_PHY_NFTHRES,	0x000003ce, AR5K_INI_WRITE },
-	{ AR5K_PHY_RESTART,	0x192fb515, AR5K_INI_WRITE },
-	{ AR5K_PHY(94),		0x00000001, AR5K_INI_WRITE },
-	{ AR5K_PHY_RFBUS_REQ,	0x00000000, AR5K_INI_WRITE },
-	/*{ AR5K_PHY(644), 0x0080a333, AR5K_INI_WRITE },*/ /* Old value */
-	/*{ AR5K_PHY(645), 0x00206c10, AR5K_INI_WRITE },*/ /* Old value */
-	{ AR5K_PHY(644),	0x00806333, AR5K_INI_WRITE },
-	{ AR5K_PHY(645),	0x00106c10, AR5K_INI_WRITE },
-	{ AR5K_PHY(646),	0x009c4060, AR5K_INI_WRITE },
-	/* { AR5K_PHY(647), 0x1483800a, AR5K_INI_WRITE }, */
-	/* { AR5K_PHY(648), 0x01831061, AR5K_INI_WRITE }, */ /* Old value */
-	{ AR5K_PHY(648),	0x018830c6, AR5K_INI_WRITE },
-	{ AR5K_PHY(649),	0x00000400, AR5K_INI_WRITE },
-	/*{ AR5K_PHY(650), 0x000001b5, AR5K_INI_WRITE },*/
-	{ AR5K_PHY(651),	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_TXPOWER_RATE3, 0x20202020, AR5K_INI_WRITE },
-	{ AR5K_PHY_TXPOWER_RATE2, 0x20202020, AR5K_INI_WRITE },
-	/*{ AR5K_PHY(655), 0x13c889af, AR5K_INI_WRITE },*/
-	{ AR5K_PHY(656),	0x38490a20, AR5K_INI_WRITE },
-	{ AR5K_PHY(657),	0x00007bb6, AR5K_INI_WRITE },
-	{ AR5K_PHY(658),	0x0fff3ffc, AR5K_INI_WRITE },
-};
-
-/* Initial mode-specific settings for AR5212 (Written before ar5212_ini) */
-static const struct ath5k_ini_mode ar5212_ini_mode_start[] = {
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(0),
-	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(1),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(2),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(3),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(4),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(5),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(6),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(7),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(8),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
-	{ AR5K_QUEUE_DFS_LOCAL_IFS(9),
-	   { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
-	{ AR5K_DCU_GBL_IFS_SIFS,
-	   { 0x00000230, 0x000001e0, 0x000000b0, 0x00000160, 0x000001e0 } },
-	{ AR5K_DCU_GBL_IFS_SLOT,
-	   { 0x00000168, 0x000001e0, 0x000001b8, 0x0000018c, 0x000001e0 } },
-	{ AR5K_DCU_GBL_IFS_EIFS,
-	   { 0x00000e60, 0x00001180, 0x00001f1c, 0x00003e38, 0x00001180 } },
-	{ AR5K_DCU_GBL_IFS_MISC,
-	   { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000b0e0, 0x00014068 } },
-	{ AR5K_TIME_OUT,
-	   { 0x03e803e8, 0x06e006e0, 0x04200420, 0x08400840, 0x06e006e0 } },
-	{ AR5K_PHY_TURBO,
-	   { 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000003 } },
-	{ AR5K_PHY(8),
-	   { 0x02020200, 0x02020200, 0x02010200, 0x02020200, 0x02020200 } },
-	{ AR5K_PHY_RF_CTL2,
-	   { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e, 0x00000e0e } },
-	{ AR5K_PHY_SETTLING,
-	   { 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } },
-	{ AR5K_PHY_AGCCTL,
-	   { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d10 } },
-	{ AR5K_PHY_NF,
-	   { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
-	{ AR5K_PHY_WEAK_OFDM_HIGH_THR,
-	   { 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 } },
-	{ AR5K_PHY(70),
-	   { 0x000001b8, 0x000001b8, 0x00000084, 0x00000108, 0x000001b8 } },
-	{ AR5K_PHY_OFDM_SELFCORR,
-	   { 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05 } },
-	{ 0xa230,
-	   { 0x00000000, 0x00000000, 0x00000000, 0x00000108, 0x00000000 } },
-};
-
-/* Initial mode-specific settings for AR5212 + RF5111 (Written after ar5212_ini) */
-static const struct ath5k_ini_mode rf5111_ini_mode_end[] = {
-	{ AR5K_TXCFG,
-	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
-	   { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
-	{ AR5K_USEC_5211,
-	   { 0x128d8fa7, 0x09880fcf, 0x04e00f95, 0x12e00fab, 0x09880fcf } },
-	{ AR5K_PHY_RF_CTL3,
-	   { 0x0a020001, 0x0a020001, 0x05010100, 0x0a020001, 0x0a020001 } },
-	{ AR5K_PHY_RF_CTL4,
-	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
-	{ AR5K_PHY_PA_CTL,
-	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
-	{ AR5K_PHY_GAIN,
-	   { 0x0018da5a, 0x0018da5a, 0x0018ca69, 0x0018ca69, 0x0018ca69 } },
-	{ AR5K_PHY_DESIRED_SIZE,
-	   { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
-	{ AR5K_PHY_SIG,
-	   { 0x7e800d2e, 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e, 0x7e800d2e } },
-	{ AR5K_PHY_AGCCOARSE,
-	   { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137615e } },
-	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
-	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb080, 0x050cb080 } },
-	{ AR5K_PHY_RX_DELAY,
-	   { 0x00002710, 0x00002710, 0x0000157c, 0x00002af8, 0x00002710 } },
-	{ AR5K_PHY_FRAME_CTL_5211,
-	   { 0xf7b81020, 0xf7b81020, 0xf7b80d20, 0xf7b81020, 0xf7b81020 } },
-	{ AR5K_PHY_GAIN_2GHZ,
-	   { 0x642c416a, 0x642c416a, 0x6440416a, 0x6440416a, 0x6440416a } },
-	{ AR5K_PHY_CCK_RX_CTL_4,
-	   { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
-};
-
-static const struct ath5k_ini rf5111_ini_common_end[] = {
-	{ AR5K_DCU_FP,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_AGC, 	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_ADC_CTL, 	0x00022ffe, AR5K_INI_WRITE },
-	{ 0x983c, 		0x00020100, AR5K_INI_WRITE },
-	{ AR5K_PHY_GAIN_OFFSET,	0x1284613c, AR5K_INI_WRITE },
-	{ AR5K_PHY_PAPD_PROBE,	0x00004883, AR5K_INI_WRITE },
-	{ 0x9940,		0x00000004, AR5K_INI_WRITE },
-	{ 0x9958,		0x000000ff, AR5K_INI_WRITE },
-	{ 0x9974,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_SPENDING,	0x00000018, AR5K_INI_WRITE },
-	{ AR5K_PHY_CCKTXCTL,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_CCK_CROSSCORR, 0xd03e6788, AR5K_INI_WRITE },
-	{ AR5K_PHY_DAG_CCK_CTL,	0x000001b5, AR5K_INI_WRITE },
-	{ 0xa23c,		0x13c889af, AR5K_INI_WRITE },
-};
-
-/* Initial mode-specific settings for AR5212 + RF5112 (Written after ar5212_ini) */
-static const struct ath5k_ini_mode rf5112_ini_mode_end[] = {
-	{ AR5K_TXCFG,
-	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
-	   { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
-	{ AR5K_USEC_5211,
-	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
-	{ AR5K_PHY_RF_CTL3,
-	   { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
-	{ AR5K_PHY_RF_CTL4,
-	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
-	{ AR5K_PHY_PA_CTL,
-	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
-	{ AR5K_PHY_GAIN,
-	   { 0x0018da6d, 0x0018da6d, 0x0018ca75, 0x0018ca75, 0x0018ca75 } },
-	{ AR5K_PHY_DESIRED_SIZE,
-	   { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
-	{ AR5K_PHY_SIG,
-	   { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7e800d2e } },
-	{ AR5K_PHY_AGCCOARSE,
-	   { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } },
-	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
-	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
-	{ AR5K_PHY_RX_DELAY,
-	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
-	{ AR5K_PHY_FRAME_CTL_5211,
-	   { 0xf7b81020, 0xf7b81020, 0xf7b80d10, 0xf7b81010, 0xf7b81010 } },
-	{ AR5K_PHY_CCKTXCTL,
-	   { 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008 } },
-	{ AR5K_PHY_CCK_CROSSCORR,
-	   { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
-	{ AR5K_PHY_GAIN_2GHZ,
-	   { 0x642c0140, 0x642c0140, 0x6442c160, 0x6442c160, 0x6442c160 } },
-	{ AR5K_PHY_CCK_RX_CTL_4,
-	   { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
-};
-
-static const struct ath5k_ini rf5112_ini_common_end[] = {
-	{ AR5K_DCU_FP,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_AGC,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_ADC_CTL,	0x00022ffe, AR5K_INI_WRITE },
-	{ 0x983c,		0x00020100, AR5K_INI_WRITE },
-	{ AR5K_PHY_GAIN_OFFSET,	0x1284613c, AR5K_INI_WRITE },
-	{ AR5K_PHY_PAPD_PROBE,	0x00004882, AR5K_INI_WRITE },
-	{ 0x9940,		0x00000004, AR5K_INI_WRITE },
-	{ 0x9958,		0x000000ff, AR5K_INI_WRITE },
-	{ 0x9974,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_DAG_CCK_CTL,	0x000001b5, AR5K_INI_WRITE },
-	{ 0xa23c,		0x13c889af, AR5K_INI_WRITE },
-};
-
-/* Initial mode-specific settings for RF5413/5414 (Written after ar5212_ini) */
-static const struct ath5k_ini_mode rf5413_ini_mode_end[] = {
-	{ AR5K_TXCFG,
-	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
-	   { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
-	{ AR5K_USEC_5211,
-	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
-	{ AR5K_PHY_RF_CTL3,
-	   { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
-	{ AR5K_PHY_RF_CTL4,
-	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
-	{ AR5K_PHY_PA_CTL,
-	   { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
-	{ AR5K_PHY_GAIN,
-	   { 0x0018fa61, 0x0018fa61, 0x001a1a63, 0x001a1a63, 0x001a1a63 } },
-	{ AR5K_PHY_DESIRED_SIZE,
-	   { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } },
-	{ AR5K_PHY_SIG,
-	   { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
-	{ AR5K_PHY_AGCCOARSE,
-	   { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
-	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
-	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
-	{ AR5K_PHY_RX_DELAY,
-	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
-	{ AR5K_PHY_FRAME_CTL_5211,
-	   { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
-	{ AR5K_PHY_CCKTXCTL,
-	   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ AR5K_PHY_CCK_CROSSCORR,
-	   { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
-	{ AR5K_PHY_GAIN_2GHZ,
-	   { 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 } },
-	{ AR5K_PHY_CCK_RX_CTL_4,
-	   { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
-	{ 0xa300,
-	   { 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 } },
-	{ 0xa304,
-	   { 0x30032602, 0x30032602, 0x30032602, 0x30032602, 0x30032602 } },
-	{ 0xa308,
-	   { 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06 } },
-	{ 0xa30c,
-	   { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } },
-	{ 0xa310,
-	   { 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f } },
-	{ 0xa314,
-	   { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } },
-	{ 0xa318,
-	   { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } },
-	{ 0xa31c,
-	   { 0x90cf865b, 0x90cf865b, 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } },
-	{ 0xa320,
-	   { 0x9d4f970f, 0x9d4f970f, 0x9b4f970f, 0x9b4f970f, 0x9b4f970f } },
-	{ 0xa324,
-	   { 0xa7cfa38f, 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f, 0xa3cf9f8f } },
-	{ 0xa328,
-	   { 0xb55faf1f, 0xb55faf1f, 0xb35faf1f, 0xb35faf1f, 0xb35faf1f } },
-	{ 0xa32c,
-	   { 0xbddfb99f, 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f, 0xbbdfb99f } },
-	{ 0xa330,
-	   { 0xcb7fc53f, 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f, 0xcb7fc73f } },
-	{ 0xa334,
-	   { 0xd5ffd1bf, 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf } },
-};
-
-static const struct ath5k_ini rf5413_ini_common_end[] = {
-	{ AR5K_DCU_FP,		0x000003e0, AR5K_INI_WRITE },
-	{ AR5K_5414_CBCFG,	0x00000010, AR5K_INI_WRITE },
-	{ AR5K_SEQ_MASK,	0x0000000f, AR5K_INI_WRITE },
-	{ 0x809c,		0x00000000, AR5K_INI_WRITE },
-	{ 0x80a0,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_MIC_QOS_CTL,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_MIC_QOS_SEL,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_MISC_MODE,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_OFDM_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_CCK_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHYERR_CNT1,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHYERR_CNT1_MASK, 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHYERR_CNT2,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHYERR_CNT2_MASK, 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_TSF_THRES,	0x00000000, AR5K_INI_WRITE },
-	{ 0x8140,		0x800003f9, AR5K_INI_WRITE },
-	{ 0x8144,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_AGC,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_ADC_CTL,	0x0000a000, AR5K_INI_WRITE },
-	{ 0x983c,		0x00200400, AR5K_INI_WRITE },
-	{ AR5K_PHY_GAIN_OFFSET, 0x1284233c, AR5K_INI_WRITE },
-	{ AR5K_PHY_SCR,		0x0000001f, AR5K_INI_WRITE },
-	{ AR5K_PHY_SLMT,	0x00000080, AR5K_INI_WRITE },
-	{ AR5K_PHY_SCAL,	0x0000000e, AR5K_INI_WRITE },
-	{ 0x9958,		0x00081fff, AR5K_INI_WRITE },
-	{ AR5K_PHY_TIMING_7,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_TIMING_8,	0x02800000, AR5K_INI_WRITE },
-	{ AR5K_PHY_TIMING_11,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000, AR5K_INI_WRITE },
-	{ 0x99e4,		0xaaaaaaaa, AR5K_INI_WRITE },
-	{ 0x99e8,		0x3c466478, AR5K_INI_WRITE },
-	{ 0x99ec,		0x000000aa, AR5K_INI_WRITE },
-	{ AR5K_PHY_SCLOCK,	0x0000000c, AR5K_INI_WRITE },
-	{ AR5K_PHY_SDELAY,	0x000000ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_SPENDING,	0x00000014, AR5K_INI_WRITE },
-	{ AR5K_PHY_DAG_CCK_CTL, 0x000009b5, AR5K_INI_WRITE },
-	{ 0xa23c,		0x93c889af, AR5K_INI_WRITE },
-	{ AR5K_PHY_FAST_ADC,	0x00000001, AR5K_INI_WRITE },
-	{ 0xa250,		0x0000a000, AR5K_INI_WRITE },
-	{ AR5K_PHY_BLUETOOTH,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_TPC_RG1,	0x0cc75380, AR5K_INI_WRITE },
-	{ 0xa25c,		0x0f0f0f01, AR5K_INI_WRITE },
-	{ 0xa260,		0x5f690f01, AR5K_INI_WRITE },
-	{ 0xa264,		0x00418a11, AR5K_INI_WRITE },
-	{ 0xa268,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_TPC_RG5,	0x0c30c16a, AR5K_INI_WRITE },
-	{ 0xa270, 0x00820820, AR5K_INI_WRITE },
-	{ 0xa274, 0x081b7caa, AR5K_INI_WRITE },
-	{ 0xa278, 0x1ce739ce, AR5K_INI_WRITE },
-	{ 0xa27c, 0x051701ce, AR5K_INI_WRITE },
-	{ 0xa338, 0x00000000, AR5K_INI_WRITE },
-	{ 0xa33c, 0x00000000, AR5K_INI_WRITE },
-	{ 0xa340, 0x00000000, AR5K_INI_WRITE },
-	{ 0xa344, 0x00000000, AR5K_INI_WRITE },
-	{ 0xa348, 0x3fffffff, AR5K_INI_WRITE },
-	{ 0xa34c, 0x3fffffff, AR5K_INI_WRITE },
-	{ 0xa350, 0x3fffffff, AR5K_INI_WRITE },
-	{ 0xa354, 0x0003ffff, AR5K_INI_WRITE },
-	{ 0xa358, 0x79a8aa1f, AR5K_INI_WRITE },
-	{ 0xa35c, 0x066c420f, AR5K_INI_WRITE },
-	{ 0xa360, 0x0f282207, AR5K_INI_WRITE },
-	{ 0xa364, 0x17601685, AR5K_INI_WRITE },
-	{ 0xa368, 0x1f801104, AR5K_INI_WRITE },
-	{ 0xa36c, 0x37a00c03, AR5K_INI_WRITE },
-	{ 0xa370, 0x3fc40883, AR5K_INI_WRITE },
-	{ 0xa374, 0x57c00803, AR5K_INI_WRITE },
-	{ 0xa378, 0x5fd80682, AR5K_INI_WRITE },
-	{ 0xa37c, 0x7fe00482, AR5K_INI_WRITE },
-	{ 0xa380, 0x7f3c7bba, AR5K_INI_WRITE },
-	{ 0xa384, 0xf3307ff0, AR5K_INI_WRITE },
-};
-
-/* Initial mode-specific settings for RF2413/2414 (Written after ar5212_ini) */
-/* XXX: a mode ? */
-static const struct ath5k_ini_mode rf2413_ini_mode_end[] = {
-	{ AR5K_TXCFG,
-	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
-	   { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
-	{ AR5K_USEC_5211,
-	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
-	{ AR5K_PHY_RF_CTL3,
-	   { 0x0a020001, 0x0a020001, 0x05020000, 0x0a020001, 0x0a020001 } },
-	{ AR5K_PHY_RF_CTL4,
-	   { 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00 } },
-	{ AR5K_PHY_PA_CTL,
-	   { 0x00000002, 0x00000002, 0x0000000a, 0x0000000a, 0x0000000a } },
-	{ AR5K_PHY_GAIN,
-	   { 0x0018da6d, 0x0018da6d, 0x001a6a64, 0x001a6a64, 0x001a6a64 } },
-	{ AR5K_PHY_DESIRED_SIZE,
-	   { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b0da, 0x0c98b0da, 0x0de8b0da } },
-	{ AR5K_PHY_SIG,
-	   { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ec80d2e, 0x7e800d2e } },
-	{ AR5K_PHY_AGCCOARSE,
-	   { 0x3137665e, 0x3137665e, 0x3137665e, 0x3139605e, 0x3137665e } },
-	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
-	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
-	{ AR5K_PHY_RX_DELAY,
-	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
-	{ AR5K_PHY_FRAME_CTL_5211,
-	   { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
-	{ AR5K_PHY_CCKTXCTL,
-	   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ AR5K_PHY_CCK_CROSSCORR,
-	   { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
-	{ AR5K_PHY_GAIN_2GHZ,
-	   { 0x002c0140, 0x002c0140, 0x0042c140, 0x0042c140, 0x0042c140 } },
-	{ AR5K_PHY_CCK_RX_CTL_4,
-	   { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
-};
-
-static const struct ath5k_ini rf2413_ini_common_end[] = {
-	{ AR5K_DCU_FP,		0x000003e0, AR5K_INI_WRITE },
-	{ AR5K_SEQ_MASK,	0x0000000f, AR5K_INI_WRITE },
-	{ AR5K_MIC_QOS_CTL,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_MIC_QOS_SEL,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_MISC_MODE,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_OFDM_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_CCK_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHYERR_CNT1,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHYERR_CNT1_MASK, 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHYERR_CNT2,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHYERR_CNT2_MASK, 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_TSF_THRES,	0x00000000, AR5K_INI_WRITE },
-	{ 0x8140,		0x800000a8, AR5K_INI_WRITE },
-	{ 0x8144,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_AGC,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_ADC_CTL,	0x0000a000, AR5K_INI_WRITE },
-	{ 0x983c,		0x00200400, AR5K_INI_WRITE },
-	{ AR5K_PHY_GAIN_OFFSET,	0x1284233c, AR5K_INI_WRITE },
-	{ AR5K_PHY_SCR,		0x0000001f, AR5K_INI_WRITE },
-	{ AR5K_PHY_SLMT,	0x00000080, AR5K_INI_WRITE },
-	{ AR5K_PHY_SCAL,	0x0000000e, AR5K_INI_WRITE },
-	{ 0x9958,		0x000000ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_TIMING_7,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_TIMING_8,	0x02800000, AR5K_INI_WRITE },
-	{ AR5K_PHY_TIMING_11,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000, AR5K_INI_WRITE },
-	{ 0x99e4,		0xaaaaaaaa, AR5K_INI_WRITE },
-	{ 0x99e8,		0x3c466478, AR5K_INI_WRITE },
-	{ 0x99ec,		0x000000aa, AR5K_INI_WRITE },
-	{ AR5K_PHY_SCLOCK,	0x0000000c, AR5K_INI_WRITE },
-	{ AR5K_PHY_SDELAY,	0x000000ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_SPENDING,	0x00000014, AR5K_INI_WRITE },
-	{ AR5K_PHY_DAG_CCK_CTL,	0x000009b5, AR5K_INI_WRITE },
-	{ 0xa23c,		0x93c889af, AR5K_INI_WRITE },
-	{ AR5K_PHY_FAST_ADC,	0x00000001, AR5K_INI_WRITE },
-	{ 0xa250,		0x0000a000, AR5K_INI_WRITE },
-	{ AR5K_PHY_BLUETOOTH,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_TPC_RG1,	0x0cc75380, AR5K_INI_WRITE },
-	{ 0xa25c,		0x0f0f0f01, AR5K_INI_WRITE },
-	{ 0xa260,		0x5f690f01, AR5K_INI_WRITE },
-	{ 0xa264,		0x00418a11, AR5K_INI_WRITE },
-	{ 0xa268,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_TPC_RG5,	0x0c30c16a, AR5K_INI_WRITE },
-	{ 0xa270, 0x00820820, AR5K_INI_WRITE },
-	{ 0xa274, 0x001b7caa, AR5K_INI_WRITE },
-	{ 0xa278, 0x1ce739ce, AR5K_INI_WRITE },
-	{ 0xa27c, 0x051701ce, AR5K_INI_WRITE },
-	{ 0xa300, 0x18010000, AR5K_INI_WRITE },
-	{ 0xa304, 0x30032602, AR5K_INI_WRITE },
-	{ 0xa308, 0x48073e06, AR5K_INI_WRITE },
-	{ 0xa30c, 0x560b4c0a, AR5K_INI_WRITE },
-	{ 0xa310, 0x641a600f, AR5K_INI_WRITE },
-	{ 0xa314, 0x784f6e1b, AR5K_INI_WRITE },
-	{ 0xa318, 0x868f7c5a, AR5K_INI_WRITE },
-	{ 0xa31c, 0x8ecf865b, AR5K_INI_WRITE },
-	{ 0xa320, 0x9d4f970f, AR5K_INI_WRITE },
-	{ 0xa324, 0xa5cfa18f, AR5K_INI_WRITE },
-	{ 0xa328, 0xb55faf1f, AR5K_INI_WRITE },
-	{ 0xa32c, 0xbddfb99f, AR5K_INI_WRITE },
-	{ 0xa330, 0xcd7fc73f, AR5K_INI_WRITE },
-	{ 0xa334, 0xd5ffd1bf, AR5K_INI_WRITE },
-	{ 0xa338, 0x00000000, AR5K_INI_WRITE },
-	{ 0xa33c, 0x00000000, AR5K_INI_WRITE },
-	{ 0xa340, 0x00000000, AR5K_INI_WRITE },
-	{ 0xa344, 0x00000000, AR5K_INI_WRITE },
-	{ 0xa348, 0x3fffffff, AR5K_INI_WRITE },
-	{ 0xa34c, 0x3fffffff, AR5K_INI_WRITE },
-	{ 0xa350, 0x3fffffff, AR5K_INI_WRITE },
-	{ 0xa354, 0x0003ffff, AR5K_INI_WRITE },
-	{ 0xa358, 0x79a8aa1f, AR5K_INI_WRITE },
-	{ 0xa35c, 0x066c420f, AR5K_INI_WRITE },
-	{ 0xa360, 0x0f282207, AR5K_INI_WRITE },
-	{ 0xa364, 0x17601685, AR5K_INI_WRITE },
-	{ 0xa368, 0x1f801104, AR5K_INI_WRITE },
-	{ 0xa36c, 0x37a00c03, AR5K_INI_WRITE },
-	{ 0xa370, 0x3fc40883, AR5K_INI_WRITE },
-	{ 0xa374, 0x57c00803, AR5K_INI_WRITE },
-	{ 0xa378, 0x5fd80682, AR5K_INI_WRITE },
-	{ 0xa37c, 0x7fe00482, AR5K_INI_WRITE },
-	{ 0xa380, 0x7f3c7bba, AR5K_INI_WRITE },
-	{ 0xa384, 0xf3307ff0, AR5K_INI_WRITE },
-};
-
-/* Initial mode-specific settings for RF2425 (Written after ar5212_ini) */
-/* XXX: a mode ? */
-static const struct ath5k_ini_mode rf2425_ini_mode_end[] = {
-	{ AR5K_TXCFG,
-	/*	a/XR	   aTurbo	  b	   g (DYN)     gTurbo     */
-	   { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
-	{ AR5K_USEC_5211,
-	   { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
-	{ AR5K_PHY_TURBO,
-	   { 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001 } },
-	{ AR5K_PHY_RF_CTL3,
-	   { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
-	{ AR5K_PHY_RF_CTL4,
-	   { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
-	{ AR5K_PHY_PA_CTL,
-	   { 0x00000003, 0x00000003, 0x0000000b, 0x0000000b, 0x0000000b } },
-	{ AR5K_PHY_SETTLING,
-	   { 0x1372161c, 0x13721c25, 0x13721722, 0x13721422, 0x13721c25 } },
-	{ AR5K_PHY_GAIN,
-	   { 0x0018fa61, 0x0018fa61, 0x00199a65, 0x00199a65, 0x00199a65 } },
-	{ AR5K_PHY_DESIRED_SIZE,
-	   { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } },
-	{ AR5K_PHY_SIG,
-	   { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
-	{ AR5K_PHY_AGCCOARSE,
-	   { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
-	{ AR5K_PHY_WEAK_OFDM_LOW_THR,
-	   { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
-	{ AR5K_PHY_RX_DELAY,
-	   { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
-	{ AR5K_PHY_FRAME_CTL_5211,
-	   { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
-	{ AR5K_PHY_CCKTXCTL,
-	   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ AR5K_PHY_CCK_CROSSCORR,
-	   { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
-	{ AR5K_PHY_GAIN_2GHZ,
-	   { 0x00000140, 0x00000140, 0x0052c140, 0x0052c140, 0x0052c140 } },
-	{ AR5K_PHY_CCK_RX_CTL_4,
-	   { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
-	{ 0xa324,
-	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
-	{ 0xa328,
-	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
-	{ 0xa32c,
-	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
-	{ 0xa330,
-	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
-	{ 0xa334,
-	   { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
-};
-
-static const struct ath5k_ini rf2425_ini_common_end[] = {
-	{ AR5K_DCU_FP,		0x000003e0, AR5K_INI_WRITE },
-	{ AR5K_SEQ_MASK,	0x0000000f, AR5K_INI_WRITE },
-	{ 0x809c,		0x00000000, AR5K_INI_WRITE },
-	{ 0x80a0,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_MIC_QOS_CTL,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_MIC_QOS_SEL,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_MISC_MODE,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_OFDM_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_CCK_FIL_CNT,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHYERR_CNT1,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHYERR_CNT1_MASK, 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHYERR_CNT2,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHYERR_CNT2_MASK, 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_TSF_THRES,	0x00000000, AR5K_INI_WRITE },
-	{ 0x8140,		0x800003f9, AR5K_INI_WRITE },
-	{ 0x8144,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_AGC,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_ADC_CTL,	0x0000a000, AR5K_INI_WRITE },
-	{ 0x983c,		0x00200400, AR5K_INI_WRITE },
-	{ AR5K_PHY_GAIN_OFFSET, 0x1284233c, AR5K_INI_WRITE },
-	{ AR5K_PHY_SCR,		0x0000001f, AR5K_INI_WRITE },
-	{ AR5K_PHY_SLMT,	0x00000080, AR5K_INI_WRITE },
-	{ AR5K_PHY_SCAL,	0x0000000e, AR5K_INI_WRITE },
-	{ 0x9958,		0x00081fff, AR5K_INI_WRITE },
-	{ AR5K_PHY_TIMING_7,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_TIMING_8,	0x02800000, AR5K_INI_WRITE },
-	{ AR5K_PHY_TIMING_11,	0x00000000, AR5K_INI_WRITE },
-	{ 0x99dc,		0xfebadbe8, AR5K_INI_WRITE },
-	{ AR5K_PHY_HEAVY_CLIP_ENABLE, 0x00000000, AR5K_INI_WRITE },
-	{ 0x99e4,		0xaaaaaaaa, AR5K_INI_WRITE },
-	{ 0x99e8,		0x3c466478, AR5K_INI_WRITE },
-	{ 0x99ec,		0x000000aa, AR5K_INI_WRITE },
-	{ AR5K_PHY_SCLOCK,	0x0000000c, AR5K_INI_WRITE },
-	{ AR5K_PHY_SDELAY,	0x000000ff, AR5K_INI_WRITE },
-	{ AR5K_PHY_SPENDING,	0x00000014, AR5K_INI_WRITE },
-	{ AR5K_PHY_DAG_CCK_CTL,	0x000009b5, AR5K_INI_WRITE },
-	{ AR5K_PHY_TXPOWER_RATE3, 0x20202020, AR5K_INI_WRITE },
-	{ AR5K_PHY_TXPOWER_RATE4, 0x20202020, AR5K_INI_WRITE },
-	{ 0xa23c,		0x93c889af, AR5K_INI_WRITE },
-	{ AR5K_PHY_FAST_ADC,	0x00000001, AR5K_INI_WRITE },
-	{ 0xa250,		0x0000a000, AR5K_INI_WRITE },
-	{ AR5K_PHY_BLUETOOTH,	0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_TPC_RG1,	0x0cc75380, AR5K_INI_WRITE },
-	{ 0xa25c,		0x0f0f0f01, AR5K_INI_WRITE },
-	{ 0xa260,		0x5f690f01, AR5K_INI_WRITE },
-	{ 0xa264,		0x00418a11, AR5K_INI_WRITE },
-	{ 0xa268,		0x00000000, AR5K_INI_WRITE },
-	{ AR5K_PHY_TPC_RG5,	0x0c30c166, AR5K_INI_WRITE },
-	{ 0xa270, 0x00820820, AR5K_INI_WRITE },
-	{ 0xa274, 0x081a3caa, AR5K_INI_WRITE },
-	{ 0xa278, 0x1ce739ce, AR5K_INI_WRITE },
-	{ 0xa27c, 0x051701ce, AR5K_INI_WRITE },
-	{ 0xa300, 0x16010000, AR5K_INI_WRITE },
-	{ 0xa304, 0x2c032402, AR5K_INI_WRITE },
-	{ 0xa308, 0x48433e42, AR5K_INI_WRITE },
-	{ 0xa30c, 0x5a0f500b, AR5K_INI_WRITE },
-	{ 0xa310, 0x6c4b624a, AR5K_INI_WRITE },
-	{ 0xa314, 0x7e8b748a, AR5K_INI_WRITE },
-	{ 0xa318, 0x96cf8ccb, AR5K_INI_WRITE },
-	{ 0xa31c, 0xa34f9d0f, AR5K_INI_WRITE },
-	{ 0xa320, 0xa7cfa58f, AR5K_INI_WRITE },
-	{ 0xa348, 0x3fffffff, AR5K_INI_WRITE },
-	{ 0xa34c, 0x3fffffff, AR5K_INI_WRITE },
-	{ 0xa350, 0x3fffffff, AR5K_INI_WRITE },
-	{ 0xa354, 0x0003ffff, AR5K_INI_WRITE },
-	{ 0xa358, 0x79a8aa1f, AR5K_INI_WRITE },
-	{ 0xa35c, 0x066c420f, AR5K_INI_WRITE },
-	{ 0xa360, 0x0f282207, AR5K_INI_WRITE },
-	{ 0xa364, 0x17601685, AR5K_INI_WRITE },
-	{ 0xa368, 0x1f801104, AR5K_INI_WRITE },
-	{ 0xa36c, 0x37a00c03, AR5K_INI_WRITE },
-	{ 0xa370, 0x3fc40883, AR5K_INI_WRITE },
-	{ 0xa374, 0x57c00803, AR5K_INI_WRITE },
-	{ 0xa378, 0x5fd80682, AR5K_INI_WRITE },
-	{ 0xa37c, 0x7fe00482, AR5K_INI_WRITE },
-	{ 0xa380, 0x7f3c7bba, AR5K_INI_WRITE },
-	{ 0xa384, 0xf3307ff0, AR5K_INI_WRITE },
-};
-
-/*
- * Initial BaseBand Gain settings for RF5111/5112 (AR5210 comes with
- * RF5110 only so initial BB Gain settings are included in AR5K_AR5210_INI)
- */
-
-/* RF5111 Initial BaseBand Gain settings */
-static const struct ath5k_ini rf5111_ini_bbgain[] = {
-	{ AR5K_BB_GAIN(0), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(1), 0x00000020, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(2), 0x00000010, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(3), 0x00000030, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(4), 0x00000008, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(5), 0x00000028, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(6), 0x00000004, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(7), 0x00000024, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(8), 0x00000014, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(9), 0x00000034, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(10), 0x0000000c, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(11), 0x0000002c, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(12), 0x00000002, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(13), 0x00000022, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(14), 0x00000012, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(15), 0x00000032, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(16), 0x0000000a, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(17), 0x0000002a, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(18), 0x00000006, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(19), 0x00000026, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(20), 0x00000016, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(21), 0x00000036, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(22), 0x0000000e, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(23), 0x0000002e, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(24), 0x00000001, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(25), 0x00000021, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(26), 0x00000011, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(27), 0x00000031, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(28), 0x00000009, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(29), 0x00000029, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(30), 0x00000005, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(31), 0x00000025, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(32), 0x00000015, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(33), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(34), 0x0000000d, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(35), 0x0000002d, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(36), 0x00000003, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(37), 0x00000023, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(38), 0x00000013, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(39), 0x00000033, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(40), 0x0000000b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(41), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(42), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(43), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(44), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(45), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(46), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(47), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(48), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(49), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(50), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(51), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(52), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(53), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(54), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(55), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(56), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(57), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(58), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(59), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(60), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(61), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(62), 0x00000002, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(63), 0x00000016, AR5K_INI_WRITE },
-};
-
-/* RF5112 Initial BaseBand Gain settings (Same for RF5413/5414+) */
-static const struct ath5k_ini rf5112_ini_bbgain[] = {
-	{ AR5K_BB_GAIN(0), 0x00000000, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(1), 0x00000001, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(2), 0x00000002, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(3), 0x00000003, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(4), 0x00000004, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(5), 0x00000005, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(6), 0x00000008, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(7), 0x00000009, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(8), 0x0000000a, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(9), 0x0000000b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(10), 0x0000000c, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(11), 0x0000000d, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(12), 0x00000010, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(13), 0x00000011, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(14), 0x00000012, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(15), 0x00000013, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(16), 0x00000014, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(17), 0x00000015, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(18), 0x00000018, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(19), 0x00000019, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(20), 0x0000001a, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(21), 0x0000001b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(22), 0x0000001c, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(23), 0x0000001d, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(24), 0x00000020, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(25), 0x00000021, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(26), 0x00000022, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(27), 0x00000023, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(28), 0x00000024, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(29), 0x00000025, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(30), 0x00000028, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(31), 0x00000029, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(32), 0x0000002a, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(33), 0x0000002b, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(34), 0x0000002c, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(35), 0x0000002d, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(36), 0x00000030, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(37), 0x00000031, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(38), 0x00000032, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(39), 0x00000033, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(40), 0x00000034, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(41), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(42), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(43), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(44), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(45), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(46), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(47), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(48), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(49), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(50), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(51), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(52), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(53), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(54), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(55), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(56), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(57), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(58), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(59), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(60), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(61), 0x00000035, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(62), 0x00000010, AR5K_INI_WRITE },
-	{ AR5K_BB_GAIN(63), 0x0000001a, AR5K_INI_WRITE },
-};
-
-
-/*
- * Write initial register dump
- */
-static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size,
-		const struct ath5k_ini *ini_regs, int change_channel)
-{
-	unsigned int i;
-
-	/* Write initial registers */
-	for (i = 0; i < size; i++) {
-		/* On channel change there is
-		 * no need to mess with PCU */
-		if (change_channel &&
-				ini_regs[i].ini_register >= AR5K_PCU_MIN &&
-				ini_regs[i].ini_register <= AR5K_PCU_MAX)
-			continue;
-
-		switch (ini_regs[i].ini_mode) {
-		case AR5K_INI_READ:
-			/* Cleared on read */
-			ath5k_hw_reg_read(ah, ini_regs[i].ini_register);
-			break;
-		case AR5K_INI_WRITE:
-		default:
-			AR5K_REG_WAIT(i);
-			ath5k_hw_reg_write(ah, ini_regs[i].ini_value,
-					ini_regs[i].ini_register);
-		}
-	}
-}
-
-static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah,
-		unsigned int size, const struct ath5k_ini_mode *ini_mode,
-		u8 mode)
-{
-	unsigned int i;
-
-	for (i = 0; i < size; i++) {
-		AR5K_REG_WAIT(i);
-		ath5k_hw_reg_write(ah, ini_mode[i].mode_value[mode],
-			(u32)ini_mode[i].mode_register);
-	}
-}
-
-int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, int change_channel)
-{
-	/*
-	 * Write initial register settings
-	 */
-
-	/* For AR5212 and combatible */
-	if (ah->ah_version == AR5K_AR5212) {
-
-		/* First set of mode-specific settings */
-		ath5k_hw_ini_mode_registers(ah,
-			ARRAY_SIZE(ar5212_ini_mode_start),
-			ar5212_ini_mode_start, mode);
-
-		/*
-		 * Write initial settings common for all modes
-		 */
-		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5212_ini_common_start),
-				ar5212_ini_common_start, change_channel);
-
-		/* Second set of mode-specific settings */
-		switch (ah->ah_radio) {
-		case AR5K_RF5111:
-
-			ath5k_hw_ini_mode_registers(ah,
-					ARRAY_SIZE(rf5111_ini_mode_end),
-					rf5111_ini_mode_end, mode);
-
-			ath5k_hw_ini_registers(ah,
-					ARRAY_SIZE(rf5111_ini_common_end),
-					rf5111_ini_common_end, change_channel);
-
-			/* Baseband gain table */
-			ath5k_hw_ini_registers(ah,
-					ARRAY_SIZE(rf5111_ini_bbgain),
-					rf5111_ini_bbgain, change_channel);
-
-			break;
-		case AR5K_RF5112:
-
-			ath5k_hw_ini_mode_registers(ah,
-					ARRAY_SIZE(rf5112_ini_mode_end),
-					rf5112_ini_mode_end, mode);
-
-			ath5k_hw_ini_registers(ah,
-					ARRAY_SIZE(rf5112_ini_common_end),
-					rf5112_ini_common_end, change_channel);
-
-			ath5k_hw_ini_registers(ah,
-					ARRAY_SIZE(rf5112_ini_bbgain),
-					rf5112_ini_bbgain, change_channel);
-
-			break;
-		case AR5K_RF5413:
-
-			ath5k_hw_ini_mode_registers(ah,
-					ARRAY_SIZE(rf5413_ini_mode_end),
-					rf5413_ini_mode_end, mode);
-
-			ath5k_hw_ini_registers(ah,
-					ARRAY_SIZE(rf5413_ini_common_end),
-					rf5413_ini_common_end, change_channel);
-
-			ath5k_hw_ini_registers(ah,
-					ARRAY_SIZE(rf5112_ini_bbgain),
-					rf5112_ini_bbgain, change_channel);
-
-			break;
-		case AR5K_RF2316:
-		case AR5K_RF2413:
-
-			ath5k_hw_ini_mode_registers(ah,
-					ARRAY_SIZE(rf2413_ini_mode_end),
-					rf2413_ini_mode_end, mode);
-
-			ath5k_hw_ini_registers(ah,
-					ARRAY_SIZE(rf2413_ini_common_end),
-					rf2413_ini_common_end, change_channel);
-
-			/* Override settings from rf2413_ini_common_end */
-			if (ah->ah_radio == AR5K_RF2316) {
-				ath5k_hw_reg_write(ah, 0x00004000,
-							AR5K_PHY_AGC);
-				ath5k_hw_reg_write(ah, 0x081b7caa,
-							0xa274);
-			}
-
-			ath5k_hw_ini_registers(ah,
-					ARRAY_SIZE(rf5112_ini_bbgain),
-					rf5112_ini_bbgain, change_channel);
-			break;
-		case AR5K_RF2317:
-		case AR5K_RF2425:
-
-			ath5k_hw_ini_mode_registers(ah,
-					ARRAY_SIZE(rf2425_ini_mode_end),
-					rf2425_ini_mode_end, mode);
-
-			ath5k_hw_ini_registers(ah,
-					ARRAY_SIZE(rf2425_ini_common_end),
-					rf2425_ini_common_end, change_channel);
-
-			ath5k_hw_ini_registers(ah,
-					ARRAY_SIZE(rf5112_ini_bbgain),
-					rf5112_ini_bbgain, change_channel);
-			break;
-		default:
-			return -EINVAL;
-
-		}
-
-	/* For AR5211 */
-	} else if (ah->ah_version == AR5K_AR5211) {
-
-		/* AR5K_MODE_11B */
-		if (mode > 2) {
-			DBG("ath5k: unsupported channel mode %d\n", mode);
-			return -EINVAL;
-		}
-
-		/* Mode-specific settings */
-		ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5211_ini_mode),
-				ar5211_ini_mode, mode);
-
-		/*
-		 * Write initial settings common for all modes
-		 */
-		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5211_ini),
-				ar5211_ini, change_channel);
-
-		/* AR5211 only comes with 5111 */
-
-		/* Baseband gain table */
-		ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_bbgain),
-				rf5111_ini_bbgain, change_channel);
-	/* For AR5210 (for mode settings check out ath5k_hw_reset_tx_queue) */
-	} else if (ah->ah_version == AR5K_AR5210) {
-		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5210_ini),
-				ar5210_ini, change_channel);
-	}
-
-	return 0;
-}
diff --git a/roms/ipxe/src/drivers/net/ath5k/ath5k_pcu.c b/roms/ipxe/src/drivers/net/ath5k/ath5k_pcu.c
deleted file mode 100644
index c8165da792e453b0dc6703fd6c054a2e33844b56..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/ath5k_pcu.c
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
- * Copyright (c) 2007-2008 Matthew W. S. Bell  <mentor@madwifi.org>
- * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
- * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
- * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
- *
- * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-FILE_LICENCE ( MIT );
-
-/*********************************\
-* Protocol Control Unit Functions *
-\*********************************/
-
-#include "ath5k.h"
-#include "reg.h"
-#include "base.h"
-
-/*******************\
-* Generic functions *
-\*******************/
-
-/**
- * ath5k_hw_set_opmode - Set PCU operating mode
- *
- * @ah: The &struct ath5k_hw
- *
- * Initialize PCU for the various operating modes (AP/STA etc)
- *
- * For iPXE we always assume STA mode.
- */
-int ath5k_hw_set_opmode(struct ath5k_hw *ah)
-{
-	u32 pcu_reg, beacon_reg, low_id, high_id;
-
-
-	/* Preserve rest settings */
-	pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
-	pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP
-			| AR5K_STA_ID1_KEYSRCH_MODE
-			| (ah->ah_version == AR5K_AR5210 ?
-			(AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0));
-
-	beacon_reg = 0;
-
-	pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
-		| (ah->ah_version == AR5K_AR5210 ?
-		   AR5K_STA_ID1_PWR_SV : 0);
-
-	/*
-	 * Set PCU registers
-	 */
-	low_id = AR5K_LOW_ID(ah->ah_sta_id);
-	high_id = AR5K_HIGH_ID(ah->ah_sta_id);
-	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
-	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
-
-	/*
-	 * Set Beacon Control Register on 5210
-	 */
-	if (ah->ah_version == AR5K_AR5210)
-		ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
-
-	return 0;
-}
-
-/**
- * ath5k_hw_set_ack_bitrate - set bitrate for ACKs
- *
- * @ah: The &struct ath5k_hw
- * @high: Flag to determine if we want to use high transmition rate
- * for ACKs or not
- *
- * If high flag is set, we tell hw to use a set of control rates based on
- * the current transmition rate (check out control_rates array inside reset.c).
- * If not hw just uses the lowest rate available for the current modulation
- * scheme being used (1Mbit for CCK and 6Mbits for OFDM).
- */
-void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, int high)
-{
-	if (ah->ah_version != AR5K_AR5212)
-		return;
-	else {
-		u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
-		if (high)
-			AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
-		else
-			AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
-	}
-}
-
-
-/******************\
-* ACK/CTS Timeouts *
-\******************/
-
-/**
- * ath5k_hw_het_ack_timeout - Get ACK timeout from PCU in usec
- *
- * @ah: The &struct ath5k_hw
- */
-unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
-{
-	return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
-			AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo);
-}
-
-/**
- * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU
- *
- * @ah: The &struct ath5k_hw
- * @timeout: Timeout in usec
- */
-int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
-{
-	if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK),
-			ah->ah_turbo) <= timeout)
-		return -EINVAL;
-
-	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
-		ath5k_hw_htoclock(timeout, ah->ah_turbo));
-
-	return 0;
-}
-
-/**
- * ath5k_hw_get_cts_timeout - Get CTS timeout from PCU in usec
- *
- * @ah: The &struct ath5k_hw
- */
-unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
-{
-	return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
-			AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo);
-}
-
-/**
- * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU
- *
- * @ah: The &struct ath5k_hw
- * @timeout: Timeout in usec
- */
-int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
-{
-	if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS),
-			ah->ah_turbo) <= timeout)
-		return -EINVAL;
-
-	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
-			ath5k_hw_htoclock(timeout, ah->ah_turbo));
-
-	return 0;
-}
-
-
-/****************\
-* BSSID handling *
-\****************/
-
-/**
- * ath5k_hw_get_lladdr - Get station id
- *
- * @ah: The &struct ath5k_hw
- * @mac: The card's mac address
- *
- * Initialize ah->ah_sta_id using the mac address provided
- * (just a memcpy).
- *
- * TODO: Remove it once we merge ath5k_softc and ath5k_hw
- */
-void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
-{
-	memcpy(mac, ah->ah_sta_id, ETH_ALEN);
-}
-
-/**
- * ath5k_hw_set_lladdr - Set station id
- *
- * @ah: The &struct ath5k_hw
- * @mac: The card's mac address
- *
- * Set station id on hw using the provided mac address
- */
-int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
-{
-	u32 low_id, high_id;
-	u32 pcu_reg;
-
-	/* Set new station ID */
-	memcpy(ah->ah_sta_id, mac, ETH_ALEN);
-
-	pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
-
-	low_id = AR5K_LOW_ID(mac);
-	high_id = AR5K_HIGH_ID(mac);
-
-	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
-	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
-
-	return 0;
-}
-
-/**
- * ath5k_hw_set_associd - Set BSSID for association
- *
- * @ah: The &struct ath5k_hw
- * @bssid: BSSID
- * @assoc_id: Assoc id
- *
- * Sets the BSSID which trigers the "SME Join" operation
- */
-void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
-{
-	u32 low_id, high_id;
-
-	/*
-	 * Set simple BSSID mask on 5212
-	 */
-	if (ah->ah_version == AR5K_AR5212) {
-		ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask),
-							AR5K_BSS_IDM0);
-		ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask),
-							AR5K_BSS_IDM1);
-	}
-
-	/*
-	 * Set BSSID which triggers the "SME Join" operation
-	 */
-	low_id = AR5K_LOW_ID(bssid);
-	high_id = AR5K_HIGH_ID(bssid);
-	ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0);
-	ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) <<
-				AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1);
-}
-
-/**
- * ath5k_hw_set_bssid_mask - filter out bssids we listen
- *
- * @ah: the &struct ath5k_hw
- * @mask: the bssid_mask, a u8 array of size ETH_ALEN
- *
- * BSSID masking is a method used by AR5212 and newer hardware to inform PCU
- * which bits of the interface's MAC address should be looked at when trying
- * to decide which packets to ACK. In station mode and AP mode with a single
- * BSS every bit matters since we lock to only one BSS. In AP mode with
- * multiple BSSes (virtual interfaces) not every bit matters because hw must
- * accept frames for all BSSes and so we tweak some bits of our mac address
- * in order to have multiple BSSes.
- *
- * NOTE: This is a simple filter and does *not* filter out all
- * relevant frames. Some frames that are not for us might get ACKed from us
- * by PCU because they just match the mask.
- *
- * When handling multiple BSSes you can get the BSSID mask by computing the
- * set of  ~ ( MAC XOR BSSID ) for all bssids we handle.
- *
- * When you do this you are essentially computing the common bits of all your
- * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with
- * the MAC address to obtain the relevant bits and compare the result with
- * (frame's BSSID & mask) to see if they match.
- */
-/*
- * Simple example: on your card you have have two BSSes you have created with
- * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address.
- * There is another BSSID-03 but you are not part of it. For simplicity's sake,
- * assuming only 4 bits for a mac address and for BSSIDs you can then have:
- *
- *                  \
- * MAC:                0001 |
- * BSSID-01:   0100 | --> Belongs to us
- * BSSID-02:   1001 |
- *                  /
- * -------------------
- * BSSID-03:   0110  | --> External
- * -------------------
- *
- * Our bssid_mask would then be:
- *
- *             On loop iteration for BSSID-01:
- *             ~(0001 ^ 0100)  -> ~(0101)
- *                             ->   1010
- *             bssid_mask      =    1010
- *
- *             On loop iteration for BSSID-02:
- *             bssid_mask &= ~(0001   ^   1001)
- *             bssid_mask =   (1010)  & ~(0001 ^ 1001)
- *             bssid_mask =   (1010)  & ~(1001)
- *             bssid_mask =   (1010)  &  (0110)
- *             bssid_mask =   0010
- *
- * A bssid_mask of 0010 means "only pay attention to the second least
- * significant bit". This is because its the only bit common
- * amongst the MAC and all BSSIDs we support. To findout what the real
- * common bit is we can simply "&" the bssid_mask now with any BSSID we have
- * or our MAC address (we assume the hardware uses the MAC address).
- *
- * Now, suppose there's an incoming frame for BSSID-03:
- *
- * IFRAME-01:  0110
- *
- * An easy eye-inspeciton of this already should tell you that this frame
- * will not pass our check. This is beacuse the bssid_mask tells the
- * hardware to only look at the second least significant bit and the
- * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB
- * as 1, which does not match 0.
- *
- * So with IFRAME-01 we *assume* the hardware will do:
- *
- *     allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
- *  --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0;
- *  --> allow = (0010) == 0000 ? 1 : 0;
- *  --> allow = 0
- *
- *  Lets now test a frame that should work:
- *
- * IFRAME-02:  0001 (we should allow)
- *
- *     allow = (0001 & 1010) == 1010
- *
- *     allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
- *  --> allow = (0001 & 0010) ==  (0010 & 0001) ? 1 :0;
- *  --> allow = (0010) == (0010)
- *  --> allow = 1
- *
- * Other examples:
- *
- * IFRAME-03:  0100 --> allowed
- * IFRAME-04:  1001 --> allowed
- * IFRAME-05:  1101 --> allowed but its not for us!!!
- *
- */
-int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
-{
-	u32 low_id, high_id;
-
-	/* Cache bssid mask so that we can restore it
-	 * on reset */
-	memcpy(ah->ah_bssid_mask, mask, ETH_ALEN);
-	if (ah->ah_version == AR5K_AR5212) {
-		low_id = AR5K_LOW_ID(mask);
-		high_id = AR5K_HIGH_ID(mask);
-
-		ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0);
-		ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1);
-
-		return 0;
-	}
-
-	return -EIO;
-}
-
-
-/************\
-* RX Control *
-\************/
-
-/**
- * ath5k_hw_start_rx_pcu - Start RX engine
- *
- * @ah: The &struct ath5k_hw
- *
- * Starts RX engine on PCU so that hw can process RXed frames
- * (ACK etc).
- *
- * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
- * TODO: Init ANI here
- */
-void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
-{
-	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
-}
-
-/**
- * at5k_hw_stop_rx_pcu - Stop RX engine
- *
- * @ah: The &struct ath5k_hw
- *
- * Stops RX engine on PCU
- *
- * TODO: Detach ANI here
- */
-void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
-{
-	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
-}
-
-/*
- * Set multicast filter
- */
-void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
-{
-	/* Set the multicat filter */
-	ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
-	ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
-}
-
-/**
- * ath5k_hw_get_rx_filter - Get current rx filter
- *
- * @ah: The &struct ath5k_hw
- *
- * Returns the RX filter by reading rx filter and
- * phy error filter registers. RX filter is used
- * to set the allowed frame types that PCU will accept
- * and pass to the driver. For a list of frame types
- * check out reg.h.
- */
-u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
-{
-	u32 data, filter = 0;
-
-	filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
-
-	/*Radar detection for 5212*/
-	if (ah->ah_version == AR5K_AR5212) {
-		data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL);
-
-		if (data & AR5K_PHY_ERR_FIL_RADAR)
-			filter |= AR5K_RX_FILTER_RADARERR;
-		if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK))
-			filter |= AR5K_RX_FILTER_PHYERR;
-	}
-
-	return filter;
-}
-
-/**
- * ath5k_hw_set_rx_filter - Set rx filter
- *
- * @ah: The &struct ath5k_hw
- * @filter: RX filter mask (see reg.h)
- *
- * Sets RX filter register and also handles PHY error filter
- * register on 5212 and newer chips so that we have proper PHY
- * error reporting.
- */
-void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
-{
-	u32 data = 0;
-
-	/* Set PHY error filter register on 5212*/
-	if (ah->ah_version == AR5K_AR5212) {
-		if (filter & AR5K_RX_FILTER_RADARERR)
-			data |= AR5K_PHY_ERR_FIL_RADAR;
-		if (filter & AR5K_RX_FILTER_PHYERR)
-			data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK;
-	}
-
-	/*
-	 * The AR5210 uses promiscous mode to detect radar activity
-	 */
-	if (ah->ah_version == AR5K_AR5210 &&
-			(filter & AR5K_RX_FILTER_RADARERR)) {
-		filter &= ~AR5K_RX_FILTER_RADARERR;
-		filter |= AR5K_RX_FILTER_PROM;
-	}
-
-	/*Zero length DMA (phy error reporting) */
-	if (data)
-		AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
-	else
-		AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
-
-	/*Write RX Filter register*/
-	ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER);
-
-	/*Write PHY error filter register on 5212*/
-	if (ah->ah_version == AR5K_AR5212)
-		ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL);
-
-}
-
-/*********************\
-* Key table functions *
-\*********************/
-
-/*
- * Reset a key entry on the table
- */
-int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
-{
-	unsigned int i, type;
-	u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
-
-	type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
-
-	for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
-		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
-
-	/* Reset associated MIC entry if TKIP
-	 * is enabled located at offset (entry + 64) */
-	if (type == AR5K_KEYTABLE_TYPE_TKIP) {
-		for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++)
-			ath5k_hw_reg_write(ah, 0,
-				AR5K_KEYTABLE_OFF(micentry, i));
-	}
-
-	/*
-	 * Set NULL encryption on AR5212+
-	 *
-	 * Note: AR5K_KEYTABLE_TYPE -> AR5K_KEYTABLE_OFF(entry, 5)
-	 *       AR5K_KEYTABLE_TYPE_NULL -> 0x00000007
-	 *
-	 * Note2: Windows driver (ndiswrapper) sets this to
-	 *        0x00000714 instead of 0x00000007
-	 */
-	if (ah->ah_version >= AR5K_AR5211) {
-		ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
-				AR5K_KEYTABLE_TYPE(entry));
-
-		if (type == AR5K_KEYTABLE_TYPE_TKIP) {
-			ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
-				AR5K_KEYTABLE_TYPE(micentry));
-		}
-	}
-
-	return 0;
-}
diff --git a/roms/ipxe/src/drivers/net/ath5k/ath5k_phy.c b/roms/ipxe/src/drivers/net/ath5k/ath5k_phy.c
deleted file mode 100644
index 7891d39eaad34ac858574862895f53e76ae70f9e..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/ath5k_phy.c
+++ /dev/null
@@ -1,2581 +0,0 @@
-/*
- * PHY functions
- *
- * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>
- * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
- * Copyright (c) 2008-2009 Felix Fietkau <nbd@openwrt.org>
- *
- * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-FILE_LICENCE ( MIT );
-
-#define _ATH5K_PHY
-
-#include <unistd.h>
-#include <stdlib.h>
-
-#include "ath5k.h"
-#include "reg.h"
-#include "base.h"
-#include "rfbuffer.h"
-#include "rfgain.h"
-
-static inline int min(int x, int y)
-{
-	return (x < y) ? x : y;
-}
-
-static inline int max(int x, int y)
-{
-	return (x > y) ? x : y;
-}
-
-/*
- * Used to modify RF Banks before writing them to AR5K_RF_BUFFER
- */
-static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
-					const struct ath5k_rf_reg *rf_regs,
-					u32 val, u8 reg_id, int set)
-{
-	const struct ath5k_rf_reg *rfreg = NULL;
-	u8 offset, bank, num_bits, col, position;
-	u16 entry;
-	u32 mask, data, last_bit, bits_shifted, first_bit;
-	u32 *rfb;
-	s32 bits_left;
-	unsigned i;
-
-	data = 0;
-	rfb = ah->ah_rf_banks;
-
-	for (i = 0; i < ah->ah_rf_regs_count; i++) {
-		if (rf_regs[i].index == reg_id) {
-			rfreg = &rf_regs[i];
-			break;
-		}
-	}
-
-	if (rfb == NULL || rfreg == NULL) {
-		DBG("ath5k: RF register not found!\n");
-		/* should not happen */
-		return 0;
-	}
-
-	bank = rfreg->bank;
-	num_bits = rfreg->field.len;
-	first_bit = rfreg->field.pos;
-	col = rfreg->field.col;
-
-	/* first_bit is an offset from bank's
-	 * start. Since we have all banks on
-	 * the same array, we use this offset
-	 * to mark each bank's start */
-	offset = ah->ah_offset[bank];
-
-	/* Boundary check */
-	if (!(col <= 3 && num_bits <= 32 && first_bit + num_bits <= 319)) {
-		DBG("ath5k: RF invalid values at offset %d\n", offset);
-		return 0;
-	}
-
-	entry = ((first_bit - 1) / 8) + offset;
-	position = (first_bit - 1) % 8;
-
-	if (set)
-		data = ath5k_hw_bitswap(val, num_bits);
-
-	for (bits_shifted = 0, bits_left = num_bits; bits_left > 0;
-	position = 0, entry++) {
-
-		last_bit = (position + bits_left > 8) ? 8 :
-					position + bits_left;
-
-		mask = (((1 << last_bit) - 1) ^ ((1 << position) - 1)) <<
-								(col * 8);
-
-		if (set) {
-			rfb[entry] &= ~mask;
-			rfb[entry] |= ((data << position) << (col * 8)) & mask;
-			data >>= (8 - position);
-		} else {
-			data |= (((rfb[entry] & mask) >> (col * 8)) >> position)
-				<< bits_shifted;
-			bits_shifted += last_bit - position;
-		}
-
-		bits_left -= 8 - position;
-	}
-
-	data = set ? 1 : ath5k_hw_bitswap(data, num_bits);
-
-	return data;
-}
-
-/**********************\
-* RF Gain optimization *
-\**********************/
-
-/*
- * This code is used to optimize rf gain on different environments
- * (temprature mostly) based on feedback from a power detector.
- *
- * It's only used on RF5111 and RF5112, later RF chips seem to have
- * auto adjustment on hw -notice they have a much smaller BANK 7 and
- * no gain optimization ladder-.
- *
- * For more infos check out this patent doc
- * http://www.freepatentsonline.com/7400691.html
- *
- * This paper describes power drops as seen on the receiver due to
- * probe packets
- * http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues
- * %20of%20Power%20Control.pdf
- *
- * And this is the MadWiFi bug entry related to the above
- * http://madwifi-project.org/ticket/1659
- * with various measurements and diagrams
- *
- * TODO: Deal with power drops due to probes by setting an apropriate
- * tx power on the probe packets ! Make this part of the calibration process.
- */
-
-/* Initialize ah_gain durring attach */
-int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah)
-{
-	/* Initialize the gain optimization values */
-	switch (ah->ah_radio) {
-	case AR5K_RF5111:
-		ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default;
-		ah->ah_gain.g_low = 20;
-		ah->ah_gain.g_high = 35;
-		ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
-		break;
-	case AR5K_RF5112:
-		ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
-		ah->ah_gain.g_low = 20;
-		ah->ah_gain.g_high = 85;
-		ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-/* Schedule a gain probe check on the next transmited packet.
- * That means our next packet is going to be sent with lower
- * tx power and a Peak to Average Power Detector (PAPD) will try
- * to measure the gain.
- *
- * TODO: Use propper tx power setting for the probe packet so
- * that we don't observe a serious power drop on the receiver
- *
- * XXX:  How about forcing a tx packet (bypassing PCU arbitrator etc)
- * just after we enable the probe so that we don't mess with
- * standard traffic ? Maybe it's time to use sw interrupts and
- * a probe tasklet !!!
- */
-static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah)
-{
-
-	/* Skip if gain calibration is inactive or
-	 * we already handle a probe request */
-	if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE)
-		return;
-
-	/* Send the packet with 2dB below max power as
-	 * patent doc suggest */
-	ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max_pwr - 4,
-			AR5K_PHY_PAPD_PROBE_TXPOWER) |
-			AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE);
-
-	ah->ah_gain.g_state = AR5K_RFGAIN_READ_REQUESTED;
-
-}
-
-/* Calculate gain_F measurement correction
- * based on the current step for RF5112 rev. 2 */
-static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah)
-{
-	u32 mix, step;
-	const struct ath5k_gain_opt *go;
-	const struct ath5k_gain_opt_step *g_step;
-	const struct ath5k_rf_reg *rf_regs;
-
-	/* Only RF5112 Rev. 2 supports it */
-	if ((ah->ah_radio != AR5K_RF5112) ||
-	(ah->ah_radio_5ghz_revision <= AR5K_SREV_RAD_5112A))
-		return 0;
-
-	go = &rfgain_opt_5112;
-	rf_regs = rf_regs_5112a;
-	ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a);
-
-	g_step = &go->go_step[ah->ah_gain.g_step_idx];
-
-	if (ah->ah_rf_banks == NULL)
-		return 0;
-
-	ah->ah_gain.g_f_corr = 0;
-
-	/* No VGA (Variable Gain Amplifier) override, skip */
-	if (ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR, 0) != 1)
-		return 0;
-
-	/* Mix gain stepping */
-	step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXGAIN_STEP, 0);
-
-	/* Mix gain override */
-	mix = g_step->gos_param[0];
-
-	switch (mix) {
-	case 3:
-		ah->ah_gain.g_f_corr = step * 2;
-		break;
-	case 2:
-		ah->ah_gain.g_f_corr = (step - 5) * 2;
-		break;
-	case 1:
-		ah->ah_gain.g_f_corr = step;
-		break;
-	default:
-		ah->ah_gain.g_f_corr = 0;
-		break;
-	}
-
-	return ah->ah_gain.g_f_corr;
-}
-
-/* Check if current gain_F measurement is in the range of our
- * power detector windows. If we get a measurement outside range
- * we know it's not accurate (detectors can't measure anything outside
- * their detection window) so we must ignore it */
-static int ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
-{
-	const struct ath5k_rf_reg *rf_regs;
-	u32 step, mix_ovr, level[4];
-
-	if (ah->ah_rf_banks == NULL)
-		return 0;
-
-	if (ah->ah_radio == AR5K_RF5111) {
-
-		rf_regs = rf_regs_5111;
-		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111);
-
-		step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_RFGAIN_STEP,
-			0);
-
-		level[0] = 0;
-		level[1] = (step == 63) ? 50 : step + 4;
-		level[2] = (step != 63) ? 64 : level[0];
-		level[3] = level[2] + 50 ;
-
-		ah->ah_gain.g_high = level[3] -
-			(step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
-		ah->ah_gain.g_low = level[0] +
-			(step == 63 ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
-	} else {
-
-		rf_regs = rf_regs_5112;
-		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112);
-
-		mix_ovr = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR,
-			0);
-
-		level[0] = level[2] = 0;
-
-		if (mix_ovr == 1) {
-			level[1] = level[3] = 83;
-		} else {
-			level[1] = level[3] = 107;
-			ah->ah_gain.g_high = 55;
-		}
-	}
-
-	return (ah->ah_gain.g_current >= level[0] &&
-			ah->ah_gain.g_current <= level[1]) ||
-		(ah->ah_gain.g_current >= level[2] &&
-			ah->ah_gain.g_current <= level[3]);
-}
-
-/* Perform gain_F adjustment by choosing the right set
- * of parameters from rf gain optimization ladder */
-static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah)
-{
-	const struct ath5k_gain_opt *go;
-	const struct ath5k_gain_opt_step *g_step;
-	int ret = 0;
-
-	switch (ah->ah_radio) {
-	case AR5K_RF5111:
-		go = &rfgain_opt_5111;
-		break;
-	case AR5K_RF5112:
-		go = &rfgain_opt_5112;
-		break;
-	default:
-		return 0;
-	}
-
-	g_step = &go->go_step[ah->ah_gain.g_step_idx];
-
-	if (ah->ah_gain.g_current >= ah->ah_gain.g_high) {
-
-		/* Reached maximum */
-		if (ah->ah_gain.g_step_idx == 0)
-			return -1;
-
-		for (ah->ah_gain.g_target = ah->ah_gain.g_current;
-				ah->ah_gain.g_target >=  ah->ah_gain.g_high &&
-				ah->ah_gain.g_step_idx > 0;
-				g_step = &go->go_step[ah->ah_gain.g_step_idx])
-			ah->ah_gain.g_target -= 2 *
-			    (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain -
-			    g_step->gos_gain);
-
-		ret = 1;
-		goto done;
-	}
-
-	if (ah->ah_gain.g_current <= ah->ah_gain.g_low) {
-
-		/* Reached minimum */
-		if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1))
-			return -2;
-
-		for (ah->ah_gain.g_target = ah->ah_gain.g_current;
-				ah->ah_gain.g_target <= ah->ah_gain.g_low &&
-				ah->ah_gain.g_step_idx < go->go_steps_count-1;
-				g_step = &go->go_step[ah->ah_gain.g_step_idx])
-			ah->ah_gain.g_target -= 2 *
-			    (go->go_step[++ah->ah_gain.g_step_idx].gos_gain -
-			    g_step->gos_gain);
-
-		ret = 2;
-		goto done;
-	}
-
-done:
-	DBG2("ath5k RF adjust: ret %d, gain step %d, current gain %d, "
-	     "target gain %d\n", ret, ah->ah_gain.g_step_idx,
-	     ah->ah_gain.g_current, ah->ah_gain.g_target);
-
-	return ret;
-}
-
-/* Main callback for thermal rf gain calibration engine
- * Check for a new gain reading and schedule an adjustment
- * if needed.
- *
- * TODO: Use sw interrupt to schedule reset if gain_F needs
- * adjustment */
-enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah)
-{
-	u32 data, type;
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-
-	if (ah->ah_rf_banks == NULL ||
-	ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE)
-		return AR5K_RFGAIN_INACTIVE;
-
-	/* No check requested, either engine is inactive
-	 * or an adjustment is already requested */
-	if (ah->ah_gain.g_state != AR5K_RFGAIN_READ_REQUESTED)
-		goto done;
-
-	/* Read the PAPD (Peak to Average Power Detector)
-	 * register */
-	data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE);
-
-	/* No probe is scheduled, read gain_F measurement */
-	if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) {
-		ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S;
-		type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE);
-
-		/* If tx packet is CCK correct the gain_F measurement
-		 * by cck ofdm gain delta */
-		if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) {
-			if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A)
-				ah->ah_gain.g_current +=
-					ee->ee_cck_ofdm_gain_delta;
-			else
-				ah->ah_gain.g_current +=
-					AR5K_GAIN_CCK_PROBE_CORR;
-		}
-
-		/* Further correct gain_F measurement for
-		 * RF5112A radios */
-		if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
-			ath5k_hw_rf_gainf_corr(ah);
-			ah->ah_gain.g_current =
-				ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ?
-				(ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
-				0;
-		}
-
-		/* Check if measurement is ok and if we need
-		 * to adjust gain, schedule a gain adjustment,
-		 * else switch back to the acive state */
-		if (ath5k_hw_rf_check_gainf_readback(ah) &&
-		AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
-		ath5k_hw_rf_gainf_adjust(ah)) {
-			ah->ah_gain.g_state = AR5K_RFGAIN_NEED_CHANGE;
-		} else {
-			ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
-		}
-	}
-
-done:
-	return ah->ah_gain.g_state;
-}
-
-/* Write initial rf gain table to set the RF sensitivity
- * this one works on all RF chips and has nothing to do
- * with gain_F calibration */
-int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
-{
-	const struct ath5k_ini_rfgain *ath5k_rfg;
-	unsigned int i, size;
-
-	switch (ah->ah_radio) {
-	case AR5K_RF5111:
-		ath5k_rfg = rfgain_5111;
-		size = ARRAY_SIZE(rfgain_5111);
-		break;
-	case AR5K_RF5112:
-		ath5k_rfg = rfgain_5112;
-		size = ARRAY_SIZE(rfgain_5112);
-		break;
-	case AR5K_RF2413:
-		ath5k_rfg = rfgain_2413;
-		size = ARRAY_SIZE(rfgain_2413);
-		break;
-	case AR5K_RF2316:
-		ath5k_rfg = rfgain_2316;
-		size = ARRAY_SIZE(rfgain_2316);
-		break;
-	case AR5K_RF5413:
-		ath5k_rfg = rfgain_5413;
-		size = ARRAY_SIZE(rfgain_5413);
-		break;
-	case AR5K_RF2317:
-	case AR5K_RF2425:
-		ath5k_rfg = rfgain_2425;
-		size = ARRAY_SIZE(rfgain_2425);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	switch (freq) {
-	case AR5K_INI_RFGAIN_2GHZ:
-	case AR5K_INI_RFGAIN_5GHZ:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	for (i = 0; i < size; i++) {
-		AR5K_REG_WAIT(i);
-		ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
-			(u32)ath5k_rfg[i].rfg_register);
-	}
-
-	return 0;
-}
-
-
-
-/********************\
-* RF Registers setup *
-\********************/
-
-
-/*
- * Setup RF registers by writing rf buffer on hw
- */
-int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct net80211_channel *channel,
-		unsigned int mode)
-{
-	const struct ath5k_rf_reg *rf_regs;
-	const struct ath5k_ini_rfbuffer *ini_rfb;
-	const struct ath5k_gain_opt *go = NULL;
-	const struct ath5k_gain_opt_step *g_step;
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	u8 ee_mode = 0;
-	u32 *rfb;
-	int obdb = -1, bank = -1;
-	unsigned i;
-
-	switch (ah->ah_radio) {
-	case AR5K_RF5111:
-		rf_regs = rf_regs_5111;
-		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111);
-		ini_rfb = rfb_5111;
-		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5111);
-		go = &rfgain_opt_5111;
-		break;
-	case AR5K_RF5112:
-		if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
-			rf_regs = rf_regs_5112a;
-			ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a);
-			ini_rfb = rfb_5112a;
-			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112a);
-		} else {
-			rf_regs = rf_regs_5112;
-			ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112);
-			ini_rfb = rfb_5112;
-			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112);
-		}
-		go = &rfgain_opt_5112;
-		break;
-	case AR5K_RF2413:
-		rf_regs = rf_regs_2413;
-		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2413);
-		ini_rfb = rfb_2413;
-		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2413);
-		break;
-	case AR5K_RF2316:
-		rf_regs = rf_regs_2316;
-		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2316);
-		ini_rfb = rfb_2316;
-		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2316);
-		break;
-	case AR5K_RF5413:
-		rf_regs = rf_regs_5413;
-		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5413);
-		ini_rfb = rfb_5413;
-		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5413);
-		break;
-	case AR5K_RF2317:
-		rf_regs = rf_regs_2425;
-		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425);
-		ini_rfb = rfb_2317;
-		ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2317);
-		break;
-	case AR5K_RF2425:
-		rf_regs = rf_regs_2425;
-		ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425);
-		if (ah->ah_mac_srev < AR5K_SREV_AR2417) {
-			ini_rfb = rfb_2425;
-			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2425);
-		} else {
-			ini_rfb = rfb_2417;
-			ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2417);
-		}
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* If it's the first time we set rf buffer, allocate
-	 * ah->ah_rf_banks based on ah->ah_rf_banks_size
-	 * we set above */
-	if (ah->ah_rf_banks == NULL) {
-		ah->ah_rf_banks = malloc(sizeof(u32) * ah->ah_rf_banks_size);
-		if (ah->ah_rf_banks == NULL) {
-			return -ENOMEM;
-		}
-	}
-
-	/* Copy values to modify them */
-	rfb = ah->ah_rf_banks;
-
-	for (i = 0; i < ah->ah_rf_banks_size; i++) {
-		if (ini_rfb[i].rfb_bank >= AR5K_MAX_RF_BANKS) {
-			DBG("ath5k: invalid RF register bank\n");
-			return -EINVAL;
-		}
-
-		/* Bank changed, write down the offset */
-		if (bank != ini_rfb[i].rfb_bank) {
-			bank = ini_rfb[i].rfb_bank;
-			ah->ah_offset[bank] = i;
-		}
-
-		rfb[i] = ini_rfb[i].rfb_mode_data[mode];
-	}
-
-	/* Set Output and Driver bias current (OB/DB) */
-	if (channel->hw_value & CHANNEL_2GHZ) {
-
-		if (channel->hw_value & CHANNEL_CCK)
-			ee_mode = AR5K_EEPROM_MODE_11B;
-		else
-			ee_mode = AR5K_EEPROM_MODE_11G;
-
-		/* For RF511X/RF211X combination we
-		 * use b_OB and b_DB parameters stored
-		 * in eeprom on ee->ee_ob[ee_mode][0]
-		 *
-		 * For all other chips we use OB/DB for 2Ghz
-		 * stored in the b/g modal section just like
-		 * 802.11a on ee->ee_ob[ee_mode][1] */
-		if ((ah->ah_radio == AR5K_RF5111) ||
-		(ah->ah_radio == AR5K_RF5112))
-			obdb = 0;
-		else
-			obdb = 1;
-
-		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb],
-						AR5K_RF_OB_2GHZ, 1);
-
-		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb],
-						AR5K_RF_DB_2GHZ, 1);
-
-	/* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */
-	} else if ((channel->hw_value & CHANNEL_5GHZ) ||
-			(ah->ah_radio == AR5K_RF5111)) {
-
-		/* For 11a, Turbo and XR we need to choose
-		 * OB/DB based on frequency range */
-		ee_mode = AR5K_EEPROM_MODE_11A;
-		obdb =	 channel->center_freq >= 5725 ? 3 :
-			(channel->center_freq >= 5500 ? 2 :
-			(channel->center_freq >= 5260 ? 1 :
-			 (channel->center_freq > 4000 ? 0 : -1)));
-
-		if (obdb < 0)
-			return -EINVAL;
-
-		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb],
-						AR5K_RF_OB_5GHZ, 1);
-
-		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb],
-						AR5K_RF_DB_5GHZ, 1);
-	}
-
-	g_step = &go->go_step[ah->ah_gain.g_step_idx];
-
-	/* Bank Modifications (chip-specific) */
-	if (ah->ah_radio == AR5K_RF5111) {
-
-		/* Set gain_F settings according to current step */
-		if (channel->hw_value & CHANNEL_OFDM) {
-
-			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
-					AR5K_PHY_FRAME_CTL_TX_CLIP,
-					g_step->gos_param[0]);
-
-			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1],
-							AR5K_RF_PWD_90, 1);
-
-			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2],
-							AR5K_RF_PWD_84, 1);
-
-			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3],
-						AR5K_RF_RFGAIN_SEL, 1);
-
-			/* We programmed gain_F parameters, switch back
-			 * to active state */
-			ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
-
-		}
-
-		/* Bank 6/7 setup */
-
-		ath5k_hw_rfb_op(ah, rf_regs, !ee->ee_xpd[ee_mode],
-						AR5K_RF_PWD_XPD, 1);
-
-		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_x_gain[ee_mode],
-						AR5K_RF_XPD_GAIN, 1);
-
-		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode],
-						AR5K_RF_GAIN_I, 1);
-
-		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode],
-						AR5K_RF_PLO_SEL, 1);
-
-		/* TODO: Half/quarter channel support */
-	}
-
-	if (ah->ah_radio == AR5K_RF5112) {
-
-		/* Set gain_F settings according to current step */
-		if (channel->hw_value & CHANNEL_OFDM) {
-
-			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0],
-						AR5K_RF_MIXGAIN_OVR, 1);
-
-			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1],
-						AR5K_RF_PWD_138, 1);
-
-			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2],
-						AR5K_RF_PWD_137, 1);
-
-			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3],
-						AR5K_RF_PWD_136, 1);
-
-			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[4],
-						AR5K_RF_PWD_132, 1);
-
-			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[5],
-						AR5K_RF_PWD_131, 1);
-
-			ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[6],
-						AR5K_RF_PWD_130, 1);
-
-			/* We programmed gain_F parameters, switch back
-			 * to active state */
-			ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
-		}
-
-		/* Bank 6/7 setup */
-
-		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode],
-						AR5K_RF_XPD_SEL, 1);
-
-		if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) {
-			/* Rev. 1 supports only one xpd */
-			ath5k_hw_rfb_op(ah, rf_regs,
-						ee->ee_x_gain[ee_mode],
-						AR5K_RF_XPD_GAIN, 1);
-
-		} else {
-			/* TODO: Set high and low gain bits */
-			ath5k_hw_rfb_op(ah, rf_regs,
-						ee->ee_x_gain[ee_mode],
-						AR5K_RF_PD_GAIN_LO, 1);
-			ath5k_hw_rfb_op(ah, rf_regs,
-						ee->ee_x_gain[ee_mode],
-						AR5K_RF_PD_GAIN_HI, 1);
-
-			/* Lower synth voltage on Rev 2 */
-			ath5k_hw_rfb_op(ah, rf_regs, 2,
-					AR5K_RF_HIGH_VC_CP, 1);
-
-			ath5k_hw_rfb_op(ah, rf_regs, 2,
-					AR5K_RF_MID_VC_CP, 1);
-
-			ath5k_hw_rfb_op(ah, rf_regs, 2,
-					AR5K_RF_LOW_VC_CP, 1);
-
-			ath5k_hw_rfb_op(ah, rf_regs, 2,
-					AR5K_RF_PUSH_UP, 1);
-
-			/* Decrease power consumption on 5213+ BaseBand */
-			if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
-				ath5k_hw_rfb_op(ah, rf_regs, 1,
-						AR5K_RF_PAD2GND, 1);
-
-				ath5k_hw_rfb_op(ah, rf_regs, 1,
-						AR5K_RF_XB2_LVL, 1);
-
-				ath5k_hw_rfb_op(ah, rf_regs, 1,
-						AR5K_RF_XB5_LVL, 1);
-
-				ath5k_hw_rfb_op(ah, rf_regs, 1,
-						AR5K_RF_PWD_167, 1);
-
-				ath5k_hw_rfb_op(ah, rf_regs, 1,
-						AR5K_RF_PWD_166, 1);
-			}
-		}
-
-		ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode],
-						AR5K_RF_GAIN_I, 1);
-
-		/* TODO: Half/quarter channel support */
-
-	}
-
-	if (ah->ah_radio == AR5K_RF5413 &&
-	channel->hw_value & CHANNEL_2GHZ) {
-
-		ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE,
-									1);
-
-		/* Set optimum value for early revisions (on pci-e chips) */
-		if (ah->ah_mac_srev >= AR5K_SREV_AR5424 &&
-		ah->ah_mac_srev < AR5K_SREV_AR5413)
-			ath5k_hw_rfb_op(ah, rf_regs, ath5k_hw_bitswap(6, 3),
-						AR5K_RF_PWD_ICLOBUF_2G, 1);
-
-	}
-
-	/* Write RF banks on hw */
-	for (i = 0; i < ah->ah_rf_banks_size; i++) {
-		AR5K_REG_WAIT(i);
-		ath5k_hw_reg_write(ah, rfb[i], ini_rfb[i].rfb_ctrl_register);
-	}
-
-	return 0;
-}
-
-
-/**************************\
-  PHY/RF channel functions
-\**************************/
-
-/*
- * Check if a channel is supported
- */
-int ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
-{
-	/* Check if the channel is in our supported range */
-	if (flags & CHANNEL_2GHZ) {
-		if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
-		    (freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
-			return 1;
-	} else if (flags & CHANNEL_5GHZ)
-		if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
-		    (freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
-			return 1;
-
-	return 0;
-}
-
-/*
- * Convertion needed for RF5110
- */
-static u32 ath5k_hw_rf5110_chan2athchan(struct net80211_channel *channel)
-{
-	u32 athchan;
-
-	/*
-	 * Convert IEEE channel/MHz to an internal channel value used
-	 * by the AR5210 chipset. This has not been verified with
-	 * newer chipsets like the AR5212A who have a completely
-	 * different RF/PHY part.
-	 */
-	athchan = (ath5k_hw_bitswap((ath5k_freq_to_channel(channel->center_freq)
-				     - 24) / 2, 5) << 1)
-		| (1 << 6) | 0x1;
-	return athchan;
-}
-
-/*
- * Set channel on RF5110
- */
-static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah,
-		struct net80211_channel *channel)
-{
-	u32 data;
-
-	/*
-	 * Set the channel and wait
-	 */
-	data = ath5k_hw_rf5110_chan2athchan(channel);
-	ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER);
-	ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0);
-	mdelay(1);
-
-	return 0;
-}
-
-/*
- * Convertion needed for 5111
- */
-static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee,
-		struct ath5k_athchan_2ghz *athchan)
-{
-	int channel;
-
-	/* Cast this value to catch negative channel numbers (>= -19) */
-	channel = (int)ieee;
-
-	/*
-	 * Map 2GHz IEEE channel to 5GHz Atheros channel
-	 */
-	if (channel <= 13) {
-		athchan->a2_athchan = 115 + channel;
-		athchan->a2_flags = 0x46;
-	} else if (channel == 14) {
-		athchan->a2_athchan = 124;
-		athchan->a2_flags = 0x44;
-	} else if (channel >= 15 && channel <= 26) {
-		athchan->a2_athchan = ((channel - 14) * 4) + 132;
-		athchan->a2_flags = 0x46;
-	} else
-		return -EINVAL;
-
-	return 0;
-}
-
-/*
- * Set channel on 5111
- */
-static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah,
-		struct net80211_channel *channel)
-{
-	struct ath5k_athchan_2ghz ath5k_channel_2ghz;
-	unsigned int ath5k_channel = ath5k_freq_to_channel(channel->center_freq);
-	u32 data0, data1, clock;
-	int ret;
-
-	/*
-	 * Set the channel on the RF5111 radio
-	 */
-	data0 = data1 = 0;
-
-	if (channel->hw_value & CHANNEL_2GHZ) {
-		/* Map 2GHz channel to 5GHz Atheros channel ID */
-		ret = ath5k_hw_rf5111_chan2athchan(ath5k_channel,
-						   &ath5k_channel_2ghz);
-		if (ret)
-			return ret;
-
-		ath5k_channel = ath5k_channel_2ghz.a2_athchan;
-		data0 = ((ath5k_hw_bitswap(ath5k_channel_2ghz.a2_flags, 8) & 0xff)
-		    << 5) | (1 << 4);
-	}
-
-	if (ath5k_channel < 145 || !(ath5k_channel & 1)) {
-		clock = 1;
-		data1 = ((ath5k_hw_bitswap(ath5k_channel - 24, 8) & 0xff) << 2) |
-			(clock << 1) | (1 << 10) | 1;
-	} else {
-		clock = 0;
-		data1 = ((ath5k_hw_bitswap((ath5k_channel - 24) / 2, 8) & 0xff)
-			<< 2) | (clock << 1) | (1 << 10) | 1;
-	}
-
-	ath5k_hw_reg_write(ah, (data1 & 0xff) | ((data0 & 0xff) << 8),
-			AR5K_RF_BUFFER);
-	ath5k_hw_reg_write(ah, ((data1 >> 8) & 0xff) | (data0 & 0xff00),
-			AR5K_RF_BUFFER_CONTROL_3);
-
-	return 0;
-}
-
-/*
- * Set channel on 5112 and newer
- */
-static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
-		struct net80211_channel *channel)
-{
-	u32 data, data0, data1, data2;
-	u16 c;
-
-	data = data0 = data1 = data2 = 0;
-	c = channel->center_freq;
-
-	if (c < 4800) {
-		if (!((c - 2224) % 5)) {
-			data0 = ((2 * (c - 704)) - 3040) / 10;
-			data1 = 1;
-		} else if (!((c - 2192) % 5)) {
-			data0 = ((2 * (c - 672)) - 3040) / 10;
-			data1 = 0;
-		} else
-			return -EINVAL;
-
-		data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8);
-	} else if ((c - (c % 5)) != 2 || c > 5435) {
-		if (!(c % 20) && c >= 5120) {
-			data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
-			data2 = ath5k_hw_bitswap(3, 2);
-		} else if (!(c % 10)) {
-			data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8);
-			data2 = ath5k_hw_bitswap(2, 2);
-		} else if (!(c % 5)) {
-			data0 = ath5k_hw_bitswap((c - 4800) / 5, 8);
-			data2 = ath5k_hw_bitswap(1, 2);
-		} else
-			return -EINVAL;
-	} else {
-		data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
-		data2 = ath5k_hw_bitswap(0, 2);
-	}
-
-	data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001;
-
-	ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER);
-	ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5);
-
-	return 0;
-}
-
-/*
- * Set the channel on the RF2425
- */
-static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
-		struct net80211_channel *channel)
-{
-	u32 data, data0, data2;
-	u16 c;
-
-	data = data0 = data2 = 0;
-	c = channel->center_freq;
-
-	if (c < 4800) {
-		data0 = ath5k_hw_bitswap((c - 2272), 8);
-		data2 = 0;
-	/* ? 5GHz ? */
-	} else if ((c - (c % 5)) != 2 || c > 5435) {
-		if (!(c % 20) && c < 5120)
-			data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
-		else if (!(c % 10))
-			data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8);
-		else if (!(c % 5))
-			data0 = ath5k_hw_bitswap((c - 4800) / 5, 8);
-		else
-			return -EINVAL;
-		data2 = ath5k_hw_bitswap(1, 2);
-	} else {
-		data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
-		data2 = ath5k_hw_bitswap(0, 2);
-	}
-
-	data = (data0 << 4) | data2 << 2 | 0x1001;
-
-	ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER);
-	ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5);
-
-	return 0;
-}
-
-/*
- * Set a channel on the radio chip
- */
-int ath5k_hw_channel(struct ath5k_hw *ah, struct net80211_channel *channel)
-{
-	int ret;
-	/*
-	 * Check bounds supported by the PHY (we don't care about regultory
-	 * restrictions at this point). Note: hw_value already has the band
-	 * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok()
-	 * of the band by that */
-	if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) {
-		DBG("ath5k: channel frequency (%d MHz) out of supported "
-		    "range\n", channel->center_freq);
-		return -EINVAL;
-	}
-
-	/*
-	 * Set the channel and wait
-	 */
-	switch (ah->ah_radio) {
-	case AR5K_RF5110:
-		ret = ath5k_hw_rf5110_channel(ah, channel);
-		break;
-	case AR5K_RF5111:
-		ret = ath5k_hw_rf5111_channel(ah, channel);
-		break;
-	case AR5K_RF2425:
-		ret = ath5k_hw_rf2425_channel(ah, channel);
-		break;
-	default:
-		ret = ath5k_hw_rf5112_channel(ah, channel);
-		break;
-	}
-
-	if (ret) {
-		DBG("ath5k: setting channel failed: %s\n", strerror(ret));
-		return ret;
-	}
-
-	/* Set JAPAN setting for channel 14 */
-	if (channel->center_freq == 2484) {
-		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL,
-				AR5K_PHY_CCKTXCTL_JAPAN);
-	} else {
-		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL,
-				AR5K_PHY_CCKTXCTL_WORLD);
-	}
-
-	ah->ah_current_channel = channel;
-	ah->ah_turbo = (channel->hw_value == CHANNEL_T ? 1 : 0);
-
-	return 0;
-}
-
-/*****************\
-  PHY calibration
-\*****************/
-
-/**
- * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration
- *
- * @ah: struct ath5k_hw pointer we are operating on
- * @freq: the channel frequency, just used for error logging
- *
- * This function performs a noise floor calibration of the PHY and waits for
- * it to complete. Then the noise floor value is compared to some maximum
- * noise floor we consider valid.
- *
- * Note that this is different from what the madwifi HAL does: it reads the
- * noise floor and afterwards initiates the calibration. Since the noise floor
- * calibration can take some time to finish, depending on the current channel
- * use, that avoids the occasional timeout warnings we are seeing now.
- *
- * See the following link for an Atheros patent on noise floor calibration:
- * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \
- * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7
- *
- * XXX: Since during noise floor calibration antennas are detached according to
- * the patent, we should stop tx queues here.
- */
-int
-ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
-{
-	int ret;
-	unsigned int i;
-	s32 noise_floor;
-
-	/*
-	 * Enable noise floor calibration
-	 */
-	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
-				AR5K_PHY_AGCCTL_NF);
-
-	ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
-			AR5K_PHY_AGCCTL_NF, 0, 0);
-
-	if (ret) {
-		DBG("ath5k: noise floor calibration timeout (%d MHz)\n", freq);
-		return -EAGAIN;
-	}
-
-	/* Wait until the noise floor is calibrated and read the value */
-	for (i = 20; i > 0; i--) {
-		mdelay(1);
-		noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
-		noise_floor = AR5K_PHY_NF_RVAL(noise_floor);
-		if (noise_floor & AR5K_PHY_NF_ACTIVE) {
-			noise_floor = AR5K_PHY_NF_AVAL(noise_floor);
-
-			if (noise_floor <= AR5K_TUNE_NOISE_FLOOR)
-				break;
-		}
-	}
-
-	DBG2("ath5k: noise floor %d\n", noise_floor);
-
-	if (noise_floor > AR5K_TUNE_NOISE_FLOOR) {
-		DBG("ath5k: noise floor calibration failed (%d MHz)\n", freq);
-		return -EAGAIN;
-	}
-
-	ah->ah_noise_floor = noise_floor;
-
-	return 0;
-}
-
-/*
- * Perform a PHY calibration on RF5110
- * -Fix BPSK/QAM Constellation (I/Q correction)
- * -Calculate Noise Floor
- */
-static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
-		struct net80211_channel *channel)
-{
-	u32 phy_sig, phy_agc, phy_sat, beacon;
-	int ret;
-
-	/*
-	 * Disable beacons and RX/TX queues, wait
-	 */
-	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210,
-		AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
-	beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210);
-	ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210);
-
-	mdelay(2);
-
-	/*
-	 * Set the channel (with AGC turned off)
-	 */
-	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
-	udelay(10);
-	ret = ath5k_hw_channel(ah, channel);
-
-	/*
-	 * Activate PHY and wait
-	 */
-	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
-	mdelay(1);
-
-	AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
-
-	if (ret)
-		return ret;
-
-	/*
-	 * Calibrate the radio chip
-	 */
-
-	/* Remember normal state */
-	phy_sig = ath5k_hw_reg_read(ah, AR5K_PHY_SIG);
-	phy_agc = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCOARSE);
-	phy_sat = ath5k_hw_reg_read(ah, AR5K_PHY_ADCSAT);
-
-	/* Update radio registers */
-	ath5k_hw_reg_write(ah, (phy_sig & ~(AR5K_PHY_SIG_FIRPWR)) |
-		AR5K_REG_SM(-1, AR5K_PHY_SIG_FIRPWR), AR5K_PHY_SIG);
-
-	ath5k_hw_reg_write(ah, (phy_agc & ~(AR5K_PHY_AGCCOARSE_HI |
-			AR5K_PHY_AGCCOARSE_LO)) |
-		AR5K_REG_SM(-1, AR5K_PHY_AGCCOARSE_HI) |
-		AR5K_REG_SM(-127, AR5K_PHY_AGCCOARSE_LO), AR5K_PHY_AGCCOARSE);
-
-	ath5k_hw_reg_write(ah, (phy_sat & ~(AR5K_PHY_ADCSAT_ICNT |
-			AR5K_PHY_ADCSAT_THR)) |
-		AR5K_REG_SM(2, AR5K_PHY_ADCSAT_ICNT) |
-		AR5K_REG_SM(12, AR5K_PHY_ADCSAT_THR), AR5K_PHY_ADCSAT);
-
-	udelay(20);
-
-	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
-	udelay(10);
-	ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG);
-	AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
-
-	mdelay(1);
-
-	/*
-	 * Enable calibration and wait until completion
-	 */
-	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL);
-
-	ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
-			AR5K_PHY_AGCCTL_CAL, 0, 0);
-
-	/* Reset to normal state */
-	ath5k_hw_reg_write(ah, phy_sig, AR5K_PHY_SIG);
-	ath5k_hw_reg_write(ah, phy_agc, AR5K_PHY_AGCCOARSE);
-	ath5k_hw_reg_write(ah, phy_sat, AR5K_PHY_ADCSAT);
-
-	if (ret) {
-		DBG("ath5k: calibration timeout (%d MHz)\n",
-		    channel->center_freq);
-		return ret;
-	}
-
-	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
-
-	/*
-	 * Re-enable RX/TX and beacons
-	 */
-	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210,
-		AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
-	ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210);
-
-	return 0;
-}
-
-/*
- * Perform a PHY calibration on RF5111/5112 and newer chips
- */
-static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
-		struct net80211_channel *channel)
-{
-	u32 i_pwr, q_pwr;
-	s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
-	int i;
-
-	if (!ah->ah_calibration ||
-		ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
-		goto done;
-
-	/* Calibration has finished, get the results and re-run */
-	for (i = 0; i <= 10; i++) {
-		iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
-		i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
-		q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q);
-	}
-
-	i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
-	q_coffd = q_pwr >> 7;
-
-	/* No correction */
-	if (i_coffd == 0 || q_coffd == 0)
-		goto done;
-
-	i_coff = ((-iq_corr) / i_coffd) & 0x3f;
-
-	/* Boundary check */
-	if (i_coff > 31)
-		i_coff = 31;
-	if (i_coff < -32)
-		i_coff = -32;
-
-	q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f;
-
-	/* Boundary check */
-	if (q_coff > 15)
-		q_coff = 15;
-	if (q_coff < -16)
-		q_coff = -16;
-
-	/* Commit new I/Q value */
-	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE |
-		((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S));
-
-	/* Re-enable calibration -if we don't we'll commit
-	 * the same values again and again */
-	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
-			AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
-	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_RUN);
-
-done:
-
-	/* TODO: Separate noise floor calibration from I/Q calibration
-	 * since noise floor calibration interrupts rx path while I/Q
-	 * calibration doesn't. We don't need to run noise floor calibration
-	 * as often as I/Q calibration.*/
-	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
-
-	/* Initiate a gain_F calibration */
-	ath5k_hw_request_rfgain_probe(ah);
-
-	return 0;
-}
-
-/*
- * Perform a PHY calibration
- */
-int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
-		struct net80211_channel *channel)
-{
-	int ret;
-
-	if (ah->ah_radio == AR5K_RF5110)
-		ret = ath5k_hw_rf5110_calibrate(ah, channel);
-	else
-		ret = ath5k_hw_rf511x_calibrate(ah, channel);
-
-	return ret;
-}
-
-int ath5k_hw_phy_disable(struct ath5k_hw *ah)
-{
-	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
-
-	return 0;
-}
-
-/********************\
-  Misc PHY functions
-\********************/
-
-/*
- * Get the PHY Chip revision
- */
-u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
-{
-	unsigned int i;
-	u32 srev;
-	u16 ret;
-
-	/*
-	 * Set the radio chip access register
-	 */
-	switch (chan) {
-	case CHANNEL_2GHZ:
-		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
-		break;
-	case CHANNEL_5GHZ:
-		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
-		break;
-	default:
-		return 0;
-	}
-
-	mdelay(2);
-
-	/* ...wait until PHY is ready and read the selected radio revision */
-	ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34));
-
-	for (i = 0; i < 8; i++)
-		ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
-
-	if (ah->ah_version == AR5K_AR5210) {
-		srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
-		ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
-	} else {
-		srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
-		ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) |
-				((srev & 0x0f) << 4), 8);
-	}
-
-	/* Reset to the 5GHz mode */
-	ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
-
-	return ret;
-}
-
-void /*TODO:Boundary check*/
-ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant)
-{
-	if (ah->ah_version != AR5K_AR5210)
-		ath5k_hw_reg_write(ah, ant, AR5K_DEFAULT_ANTENNA);
-}
-
-unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah)
-{
-	if (ah->ah_version != AR5K_AR5210)
-		return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
-
-	return 0; /*XXX: What do we return for 5210 ?*/
-}
-
-
-/****************\
-* TX power setup *
-\****************/
-
-/*
- * Helper functions
- */
-
-/*
- * Do linear interpolation between two given (x, y) points
- */
-static s16
-ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right,
-					s16 y_left, s16 y_right)
-{
-	s16 ratio, result;
-
-	/* Avoid divide by zero and skip interpolation
-	 * if we have the same point */
-	if ((x_left == x_right) || (y_left == y_right))
-		return y_left;
-
-	/*
-	 * Since we use ints and not fps, we need to scale up in
-	 * order to get a sane ratio value (or else we 'll eg. get
-	 * always 1 instead of 1.25, 1.75 etc). We scale up by 100
-	 * to have some accuracy both for 0.5 and 0.25 steps.
-	 */
-	ratio = ((100 * y_right - 100 * y_left)/(x_right - x_left));
-
-	/* Now scale down to be in range */
-	result = y_left + (ratio * (target - x_left) / 100);
-
-	return result;
-}
-
-/*
- * Find vertical boundary (min pwr) for the linear PCDAC curve.
- *
- * Since we have the top of the curve and we draw the line below
- * until we reach 1 (1 pcdac step) we need to know which point
- * (x value) that is so that we don't go below y axis and have negative
- * pcdac values when creating the curve, or fill the table with zeroes.
- */
-static s16
-ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR,
-				const s16 *pwrL, const s16 *pwrR)
-{
-	s8 tmp;
-	s16 min_pwrL, min_pwrR;
-	s16 pwr_i;
-
-	if (pwrL[0] == pwrL[1])
-		min_pwrL = pwrL[0];
-	else {
-		pwr_i = pwrL[0];
-		do {
-			pwr_i--;
-			tmp = (s8) ath5k_get_interpolated_value(pwr_i,
-							pwrL[0], pwrL[1],
-							stepL[0], stepL[1]);
-		} while (tmp > 1);
-
-		min_pwrL = pwr_i;
-	}
-
-	if (pwrR[0] == pwrR[1])
-		min_pwrR = pwrR[0];
-	else {
-		pwr_i = pwrR[0];
-		do {
-			pwr_i--;
-			tmp = (s8) ath5k_get_interpolated_value(pwr_i,
-							pwrR[0], pwrR[1],
-							stepR[0], stepR[1]);
-		} while (tmp > 1);
-
-		min_pwrR = pwr_i;
-	}
-
-	/* Keep the right boundary so that it works for both curves */
-	return max(min_pwrL, min_pwrR);
-}
-
-/*
- * Interpolate (pwr,vpd) points to create a Power to PDADC or a
- * Power to PCDAC curve.
- *
- * Each curve has power on x axis (in 0.5dB units) and PCDAC/PDADC
- * steps (offsets) on y axis. Power can go up to 31.5dB and max
- * PCDAC/PDADC step for each curve is 64 but we can write more than
- * one curves on hw so we can go up to 128 (which is the max step we
- * can write on the final table).
- *
- * We write y values (PCDAC/PDADC steps) on hw.
- */
-static void
-ath5k_create_power_curve(s16 pmin, s16 pmax,
-			const s16 *pwr, const u8 *vpd,
-			u8 num_points,
-			u8 *vpd_table, u8 type)
-{
-	u8 idx[2] = { 0, 1 };
-	s16 pwr_i = 2*pmin;
-	int i;
-
-	if (num_points < 2)
-		return;
-
-	/* We want the whole line, so adjust boundaries
-	 * to cover the entire power range. Note that
-	 * power values are already 0.25dB so no need
-	 * to multiply pwr_i by 2 */
-	if (type == AR5K_PWRTABLE_LINEAR_PCDAC) {
-		pwr_i = pmin;
-		pmin = 0;
-		pmax = 63;
-	}
-
-	/* Find surrounding turning points (TPs)
-	 * and interpolate between them */
-	for (i = 0; (i <= (u16) (pmax - pmin)) &&
-	(i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) {
-
-		/* We passed the right TP, move to the next set of TPs
-		 * if we pass the last TP, extrapolate above using the last
-		 * two TPs for ratio */
-		if ((pwr_i > pwr[idx[1]]) && (idx[1] < num_points - 1)) {
-			idx[0]++;
-			idx[1]++;
-		}
-
-		vpd_table[i] = (u8) ath5k_get_interpolated_value(pwr_i,
-						pwr[idx[0]], pwr[idx[1]],
-						vpd[idx[0]], vpd[idx[1]]);
-
-		/* Increase by 0.5dB
-		 * (0.25 dB units) */
-		pwr_i += 2;
-	}
-}
-
-/*
- * Get the surrounding per-channel power calibration piers
- * for a given frequency so that we can interpolate between
- * them and come up with an apropriate dataset for our current
- * channel.
- */
-static void
-ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah,
-			struct net80211_channel *channel,
-			struct ath5k_chan_pcal_info **pcinfo_l,
-			struct ath5k_chan_pcal_info **pcinfo_r)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct ath5k_chan_pcal_info *pcinfo;
-	u8 idx_l, idx_r;
-	u8 mode, max, i;
-	u32 target = channel->center_freq;
-
-	idx_l = 0;
-	idx_r = 0;
-
-	if (!(channel->hw_value & CHANNEL_OFDM)) {
-		pcinfo = ee->ee_pwr_cal_b;
-		mode = AR5K_EEPROM_MODE_11B;
-	} else if (channel->hw_value & CHANNEL_2GHZ) {
-		pcinfo = ee->ee_pwr_cal_g;
-		mode = AR5K_EEPROM_MODE_11G;
-	} else {
-		pcinfo = ee->ee_pwr_cal_a;
-		mode = AR5K_EEPROM_MODE_11A;
-	}
-	max = ee->ee_n_piers[mode] - 1;
-
-	/* Frequency is below our calibrated
-	 * range. Use the lowest power curve
-	 * we have */
-	if (target < pcinfo[0].freq) {
-		idx_l = idx_r = 0;
-		goto done;
-	}
-
-	/* Frequency is above our calibrated
-	 * range. Use the highest power curve
-	 * we have */
-	if (target > pcinfo[max].freq) {
-		idx_l = idx_r = max;
-		goto done;
-	}
-
-	/* Frequency is inside our calibrated
-	 * channel range. Pick the surrounding
-	 * calibration piers so that we can
-	 * interpolate */
-	for (i = 0; i <= max; i++) {
-
-		/* Frequency matches one of our calibration
-		 * piers, no need to interpolate, just use
-		 * that calibration pier */
-		if (pcinfo[i].freq == target) {
-			idx_l = idx_r = i;
-			goto done;
-		}
-
-		/* We found a calibration pier that's above
-		 * frequency, use this pier and the previous
-		 * one to interpolate */
-		if (target < pcinfo[i].freq) {
-			idx_r = i;
-			idx_l = idx_r - 1;
-			goto done;
-		}
-	}
-
-done:
-	*pcinfo_l = &pcinfo[idx_l];
-	*pcinfo_r = &pcinfo[idx_r];
-
-	return;
-}
-
-/*
- * Get the surrounding per-rate power calibration data
- * for a given frequency and interpolate between power
- * values to set max target power supported by hw for
- * each rate.
- */
-static void
-ath5k_get_rate_pcal_data(struct ath5k_hw *ah,
-			struct net80211_channel *channel,
-			struct ath5k_rate_pcal_info *rates)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct ath5k_rate_pcal_info *rpinfo;
-	u8 idx_l, idx_r;
-	u8 mode, max, i;
-	u32 target = channel->center_freq;
-
-	idx_l = 0;
-	idx_r = 0;
-
-	if (!(channel->hw_value & CHANNEL_OFDM)) {
-		rpinfo = ee->ee_rate_tpwr_b;
-		mode = AR5K_EEPROM_MODE_11B;
-	} else if (channel->hw_value & CHANNEL_2GHZ) {
-		rpinfo = ee->ee_rate_tpwr_g;
-		mode = AR5K_EEPROM_MODE_11G;
-	} else {
-		rpinfo = ee->ee_rate_tpwr_a;
-		mode = AR5K_EEPROM_MODE_11A;
-	}
-	max = ee->ee_rate_target_pwr_num[mode] - 1;
-
-	/* Get the surrounding calibration
-	 * piers - same as above */
-	if (target < rpinfo[0].freq) {
-		idx_l = idx_r = 0;
-		goto done;
-	}
-
-	if (target > rpinfo[max].freq) {
-		idx_l = idx_r = max;
-		goto done;
-	}
-
-	for (i = 0; i <= max; i++) {
-
-		if (rpinfo[i].freq == target) {
-			idx_l = idx_r = i;
-			goto done;
-		}
-
-		if (target < rpinfo[i].freq) {
-			idx_r = i;
-			idx_l = idx_r - 1;
-			goto done;
-		}
-	}
-
-done:
-	/* Now interpolate power value, based on the frequency */
-	rates->freq = target;
-
-	rates->target_power_6to24 =
-		ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
-					rpinfo[idx_r].freq,
-					rpinfo[idx_l].target_power_6to24,
-					rpinfo[idx_r].target_power_6to24);
-
-	rates->target_power_36 =
-		ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
-					rpinfo[idx_r].freq,
-					rpinfo[idx_l].target_power_36,
-					rpinfo[idx_r].target_power_36);
-
-	rates->target_power_48 =
-		ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
-					rpinfo[idx_r].freq,
-					rpinfo[idx_l].target_power_48,
-					rpinfo[idx_r].target_power_48);
-
-	rates->target_power_54 =
-		ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
-					rpinfo[idx_r].freq,
-					rpinfo[idx_l].target_power_54,
-					rpinfo[idx_r].target_power_54);
-}
-
-/*
- * Get the max edge power for this channel if
- * we have such data from EEPROM's Conformance Test
- * Limits (CTL), and limit max power if needed.
- *
- * FIXME: Only works for world regulatory domains
- */
-static void
-ath5k_get_max_ctl_power(struct ath5k_hw *ah,
-			struct net80211_channel *channel)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	struct ath5k_edge_power *rep = ee->ee_ctl_pwr;
-	u8 *ctl_val = ee->ee_ctl;
-	s16 max_chan_pwr = ah->ah_txpower.txp_max_pwr / 4;
-	s16 edge_pwr = 0;
-	u8 rep_idx;
-	u8 i, ctl_mode;
-	u8 ctl_idx = 0xFF;
-	u32 target = channel->center_freq;
-
-	/* Find out a CTL for our mode that's not mapped
-	 * on a specific reg domain.
-	 *
-	 * TODO: Map our current reg domain to one of the 3 available
-	 * reg domain ids so that we can support more CTLs. */
-	switch (channel->hw_value & CHANNEL_MODES) {
-	case CHANNEL_A:
-		ctl_mode = AR5K_CTL_11A | AR5K_CTL_NO_REGDOMAIN;
-		break;
-	case CHANNEL_G:
-		ctl_mode = AR5K_CTL_11G | AR5K_CTL_NO_REGDOMAIN;
-		break;
-	case CHANNEL_B:
-		ctl_mode = AR5K_CTL_11B | AR5K_CTL_NO_REGDOMAIN;
-		break;
-	case CHANNEL_T:
-		ctl_mode = AR5K_CTL_TURBO | AR5K_CTL_NO_REGDOMAIN;
-		break;
-	case CHANNEL_TG:
-		ctl_mode = AR5K_CTL_TURBOG | AR5K_CTL_NO_REGDOMAIN;
-		break;
-	case CHANNEL_XR:
-		/* Fall through */
-	default:
-		return;
-	}
-
-	for (i = 0; i < ee->ee_ctls; i++) {
-		if (ctl_val[i] == ctl_mode) {
-			ctl_idx = i;
-			break;
-		}
-	}
-
-	/* If we have a CTL dataset available grab it and find the
-	 * edge power for our frequency */
-	if (ctl_idx == 0xFF)
-		return;
-
-	/* Edge powers are sorted by frequency from lower
-	 * to higher. Each CTL corresponds to 8 edge power
-	 * measurements. */
-	rep_idx = ctl_idx * AR5K_EEPROM_N_EDGES;
-
-	/* Don't do boundaries check because we
-	 * might have more that one bands defined
-	 * for this mode */
-
-	/* Get the edge power that's closer to our
-	 * frequency */
-	for (i = 0; i < AR5K_EEPROM_N_EDGES; i++) {
-		rep_idx += i;
-		if (target <= rep[rep_idx].freq)
-			edge_pwr = (s16) rep[rep_idx].edge;
-	}
-
-	if (edge_pwr) {
-		ah->ah_txpower.txp_max_pwr = 4*min(edge_pwr, max_chan_pwr);
-	}
-}
-
-
-/*
- * Power to PCDAC table functions
- */
-
-/*
- * Fill Power to PCDAC table on RF5111
- *
- * No further processing is needed for RF5111, the only thing we have to
- * do is fill the values below and above calibration range since eeprom data
- * may not cover the entire PCDAC table.
- */
-static void
-ath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min,
-							s16 *table_max)
-{
-	u8 	*pcdac_out = ah->ah_txpower.txp_pd_table;
-	u8	*pcdac_tmp = ah->ah_txpower.tmpL[0];
-	u8	pcdac_0, pcdac_n, pcdac_i, pwr_idx, i;
-	s16	min_pwr, max_pwr;
-
-	/* Get table boundaries */
-	min_pwr = table_min[0];
-	pcdac_0 = pcdac_tmp[0];
-
-	max_pwr = table_max[0];
-	pcdac_n = pcdac_tmp[table_max[0] - table_min[0]];
-
-	/* Extrapolate below minimum using pcdac_0 */
-	pcdac_i = 0;
-	for (i = 0; i < min_pwr; i++)
-		pcdac_out[pcdac_i++] = pcdac_0;
-
-	/* Copy values from pcdac_tmp */
-	pwr_idx = min_pwr;
-	for (i = 0 ; pwr_idx <= max_pwr &&
-	pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE; i++) {
-		pcdac_out[pcdac_i++] = pcdac_tmp[i];
-		pwr_idx++;
-	}
-
-	/* Extrapolate above maximum */
-	while (pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE)
-		pcdac_out[pcdac_i++] = pcdac_n;
-
-}
-
-/*
- * Combine available XPD Curves and fill Linear Power to PCDAC table
- * on RF5112
- *
- * RFX112 can have up to 2 curves (one for low txpower range and one for
- * higher txpower range). We need to put them both on pcdac_out and place
- * them in the correct location. In case we only have one curve available
- * just fit it on pcdac_out (it's supposed to cover the entire range of
- * available pwr levels since it's always the higher power curve). Extrapolate
- * below and above final table if needed.
- */
-static void
-ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min,
-						s16 *table_max, u8 pdcurves)
-{
-	u8 	*pcdac_out = ah->ah_txpower.txp_pd_table;
-	u8	*pcdac_low_pwr;
-	u8	*pcdac_high_pwr;
-	u8	*pcdac_tmp;
-	u8	pwr;
-	s16	max_pwr_idx;
-	s16	min_pwr_idx;
-	s16	mid_pwr_idx = 0;
-	/* Edge flag turs on the 7nth bit on the PCDAC
-	 * to delcare the higher power curve (force values
-	 * to be greater than 64). If we only have one curve
-	 * we don't need to set this, if we have 2 curves and
-	 * fill the table backwards this can also be used to
-	 * switch from higher power curve to lower power curve */
-	u8	edge_flag;
-	int	i;
-
-	/* When we have only one curve available
-	 * that's the higher power curve. If we have
-	 * two curves the first is the high power curve
-	 * and the next is the low power curve. */
-	if (pdcurves > 1) {
-		pcdac_low_pwr = ah->ah_txpower.tmpL[1];
-		pcdac_high_pwr = ah->ah_txpower.tmpL[0];
-		mid_pwr_idx = table_max[1] - table_min[1] - 1;
-		max_pwr_idx = (table_max[0] - table_min[0]) / 2;
-
-		/* If table size goes beyond 31.5dB, keep the
-		 * upper 31.5dB range when setting tx power.
-		 * Note: 126 = 31.5 dB in quarter dB steps */
-		if (table_max[0] - table_min[1] > 126)
-			min_pwr_idx = table_max[0] - 126;
-		else
-			min_pwr_idx = table_min[1];
-
-		/* Since we fill table backwards
-		 * start from high power curve */
-		pcdac_tmp = pcdac_high_pwr;
-
-		edge_flag = 0x40;
-	} else {
-		pcdac_low_pwr = ah->ah_txpower.tmpL[1]; /* Zeroed */
-		pcdac_high_pwr = ah->ah_txpower.tmpL[0];
-		min_pwr_idx = table_min[0];
-		max_pwr_idx = (table_max[0] - table_min[0]) / 2;
-		pcdac_tmp = pcdac_high_pwr;
-		edge_flag = 0;
-	}
-
-	/* This is used when setting tx power*/
-	ah->ah_txpower.txp_min_idx = min_pwr_idx/2;
-
-	/* Fill Power to PCDAC table backwards */
-	pwr = max_pwr_idx;
-	for (i = 63; i >= 0; i--) {
-		/* Entering lower power range, reset
-		 * edge flag and set pcdac_tmp to lower
-		 * power curve.*/
-		if (edge_flag == 0x40 &&
-		(2*pwr <= (table_max[1] - table_min[0]) || pwr == 0)) {
-			edge_flag = 0x00;
-			pcdac_tmp = pcdac_low_pwr;
-			pwr = mid_pwr_idx/2;
-		}
-
-		/* Don't go below 1, extrapolate below if we have
-		 * already swithced to the lower power curve -or
-		 * we only have one curve and edge_flag is zero
-		 * anyway */
-		if (pcdac_tmp[pwr] < 1 && (edge_flag == 0x00)) {
-			while (i >= 0) {
-				pcdac_out[i] = pcdac_out[i + 1];
-				i--;
-			}
-			break;
-		}
-
-		pcdac_out[i] = pcdac_tmp[pwr] | edge_flag;
-
-		/* Extrapolate above if pcdac is greater than
-		 * 126 -this can happen because we OR pcdac_out
-		 * value with edge_flag on high power curve */
-		if (pcdac_out[i] > 126)
-			pcdac_out[i] = 126;
-
-		/* Decrease by a 0.5dB step */
-		pwr--;
-	}
-}
-
-/* Write PCDAC values on hw */
-static void
-ath5k_setup_pcdac_table(struct ath5k_hw *ah)
-{
-	u8 	*pcdac_out = ah->ah_txpower.txp_pd_table;
-	int	i;
-
-	/*
-	 * Write TX power values
-	 */
-	for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) {
-		ath5k_hw_reg_write(ah,
-			(((pcdac_out[2*i + 0] << 8 | 0xff) & 0xffff) << 0) |
-			(((pcdac_out[2*i + 1] << 8 | 0xff) & 0xffff) << 16),
-			AR5K_PHY_PCDAC_TXPOWER(i));
-	}
-}
-
-
-/*
- * Power to PDADC table functions
- */
-
-/*
- * Set the gain boundaries and create final Power to PDADC table
- *
- * We can have up to 4 pd curves, we need to do a simmilar process
- * as we do for RF5112. This time we don't have an edge_flag but we
- * set the gain boundaries on a separate register.
- */
-static void
-ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah,
-			s16 *pwr_min, s16 *pwr_max, u8 pdcurves)
-{
-	u8 gain_boundaries[AR5K_EEPROM_N_PD_GAINS];
-	u8 *pdadc_out = ah->ah_txpower.txp_pd_table;
-	u8 *pdadc_tmp;
-	s16 pdadc_0;
-	u8 pdadc_i, pdadc_n, pwr_step, pdg, max_idx, table_size;
-	u8 pd_gain_overlap;
-
-	/* Note: Register value is initialized on initvals
-	 * there is no feedback from hw.
-	 * XXX: What about pd_gain_overlap from EEPROM ? */
-	pd_gain_overlap = (u8) ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG5) &
-		AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP;
-
-	/* Create final PDADC table */
-	for (pdg = 0, pdadc_i = 0; pdg < pdcurves; pdg++) {
-		pdadc_tmp = ah->ah_txpower.tmpL[pdg];
-
-		if (pdg == pdcurves - 1)
-			/* 2 dB boundary stretch for last
-			 * (higher power) curve */
-			gain_boundaries[pdg] = pwr_max[pdg] + 4;
-		else
-			/* Set gain boundary in the middle
-			 * between this curve and the next one */
-			gain_boundaries[pdg] =
-				(pwr_max[pdg] + pwr_min[pdg + 1]) / 2;
-
-		/* Sanity check in case our 2 db stretch got out of
-		 * range. */
-		if (gain_boundaries[pdg] > AR5K_TUNE_MAX_TXPOWER)
-			gain_boundaries[pdg] = AR5K_TUNE_MAX_TXPOWER;
-
-		/* For the first curve (lower power)
-		 * start from 0 dB */
-		if (pdg == 0)
-			pdadc_0 = 0;
-		else
-			/* For the other curves use the gain overlap */
-			pdadc_0 = (gain_boundaries[pdg - 1] - pwr_min[pdg]) -
-							pd_gain_overlap;
-
-		/* Force each power step to be at least 0.5 dB */
-		if ((pdadc_tmp[1] - pdadc_tmp[0]) > 1)
-			pwr_step = pdadc_tmp[1] - pdadc_tmp[0];
-		else
-			pwr_step = 1;
-
-		/* If pdadc_0 is negative, we need to extrapolate
-		 * below this pdgain by a number of pwr_steps */
-		while ((pdadc_0 < 0) && (pdadc_i < 128)) {
-			s16 tmp = pdadc_tmp[0] + pdadc_0 * pwr_step;
-			pdadc_out[pdadc_i++] = (tmp < 0) ? 0 : (u8) tmp;
-			pdadc_0++;
-		}
-
-		/* Set last pwr level, using gain boundaries */
-		pdadc_n = gain_boundaries[pdg] + pd_gain_overlap - pwr_min[pdg];
-		/* Limit it to be inside pwr range */
-		table_size = pwr_max[pdg] - pwr_min[pdg];
-		max_idx = (pdadc_n < table_size) ? pdadc_n : table_size;
-
-		/* Fill pdadc_out table */
-		while (pdadc_0 < max_idx)
-			pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++];
-
-		/* Need to extrapolate above this pdgain? */
-		if (pdadc_n <= max_idx)
-			continue;
-
-		/* Force each power step to be at least 0.5 dB */
-		if ((pdadc_tmp[table_size - 1] - pdadc_tmp[table_size - 2]) > 1)
-			pwr_step = pdadc_tmp[table_size - 1] -
-						pdadc_tmp[table_size - 2];
-		else
-			pwr_step = 1;
-
-		/* Extrapolate above */
-		while ((pdadc_0 < (s16) pdadc_n) &&
-		(pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2)) {
-			s16 tmp = pdadc_tmp[table_size - 1] +
-					(pdadc_0 - max_idx) * pwr_step;
-			pdadc_out[pdadc_i++] = (tmp > 127) ? 127 : (u8) tmp;
-			pdadc_0++;
-		}
-	}
-
-	while (pdg < AR5K_EEPROM_N_PD_GAINS) {
-		gain_boundaries[pdg] = gain_boundaries[pdg - 1];
-		pdg++;
-	}
-
-	while (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2) {
-		pdadc_out[pdadc_i] = pdadc_out[pdadc_i - 1];
-		pdadc_i++;
-	}
-
-	/* Set gain boundaries */
-	ath5k_hw_reg_write(ah,
-		AR5K_REG_SM(pd_gain_overlap,
-			AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP) |
-		AR5K_REG_SM(gain_boundaries[0],
-			AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1) |
-		AR5K_REG_SM(gain_boundaries[1],
-			AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2) |
-		AR5K_REG_SM(gain_boundaries[2],
-			AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3) |
-		AR5K_REG_SM(gain_boundaries[3],
-			AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4),
-		AR5K_PHY_TPC_RG5);
-
-	/* Used for setting rate power table */
-	ah->ah_txpower.txp_min_idx = pwr_min[0];
-
-}
-
-/* Write PDADC values on hw */
-static void
-ath5k_setup_pwr_to_pdadc_table(struct ath5k_hw *ah,
-			u8 pdcurves, u8 *pdg_to_idx)
-{
-	u8 *pdadc_out = ah->ah_txpower.txp_pd_table;
-	u32 reg;
-	u8 i;
-
-	/* Select the right pdgain curves */
-
-	/* Clear current settings */
-	reg = ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG1);
-	reg &= ~(AR5K_PHY_TPC_RG1_PDGAIN_1 |
-		AR5K_PHY_TPC_RG1_PDGAIN_2 |
-		AR5K_PHY_TPC_RG1_PDGAIN_3 |
-		AR5K_PHY_TPC_RG1_NUM_PD_GAIN);
-
-	/*
-	 * Use pd_gains curve from eeprom
-	 *
-	 * This overrides the default setting from initvals
-	 * in case some vendors (e.g. Zcomax) don't use the default
-	 * curves. If we don't honor their settings we 'll get a
-	 * 5dB (1 * gain overlap ?) drop.
-	 */
-	reg |= AR5K_REG_SM(pdcurves, AR5K_PHY_TPC_RG1_NUM_PD_GAIN);
-
-	switch (pdcurves) {
-	case 3:
-		reg |= AR5K_REG_SM(pdg_to_idx[2], AR5K_PHY_TPC_RG1_PDGAIN_3);
-		/* Fall through */
-	case 2:
-		reg |= AR5K_REG_SM(pdg_to_idx[1], AR5K_PHY_TPC_RG1_PDGAIN_2);
-		/* Fall through */
-	case 1:
-		reg |= AR5K_REG_SM(pdg_to_idx[0], AR5K_PHY_TPC_RG1_PDGAIN_1);
-		break;
-	}
-	ath5k_hw_reg_write(ah, reg, AR5K_PHY_TPC_RG1);
-
-	/*
-	 * Write TX power values
-	 */
-	for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) {
-		ath5k_hw_reg_write(ah,
-			((pdadc_out[4*i + 0] & 0xff) << 0) |
-			((pdadc_out[4*i + 1] & 0xff) << 8) |
-			((pdadc_out[4*i + 2] & 0xff) << 16) |
-			((pdadc_out[4*i + 3] & 0xff) << 24),
-			AR5K_PHY_PDADC_TXPOWER(i));
-	}
-}
-
-
-/*
- * Common code for PCDAC/PDADC tables
- */
-
-/*
- * This is the main function that uses all of the above
- * to set PCDAC/PDADC table on hw for the current channel.
- * This table is used for tx power calibration on the basband,
- * without it we get weird tx power levels and in some cases
- * distorted spectral mask
- */
-static int
-ath5k_setup_channel_powertable(struct ath5k_hw *ah,
-			struct net80211_channel *channel,
-			u8 ee_mode, u8 type)
-{
-	struct ath5k_pdgain_info *pdg_L, *pdg_R;
-	struct ath5k_chan_pcal_info *pcinfo_L;
-	struct ath5k_chan_pcal_info *pcinfo_R;
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode];
-	s16 table_min[AR5K_EEPROM_N_PD_GAINS];
-	s16 table_max[AR5K_EEPROM_N_PD_GAINS];
-	u8 *tmpL;
-	u8 *tmpR;
-	u32 target = channel->center_freq;
-	int pdg, i;
-
-	/* Get surounding freq piers for this channel */
-	ath5k_get_chan_pcal_surrounding_piers(ah, channel,
-						&pcinfo_L,
-						&pcinfo_R);
-
-	/* Loop over pd gain curves on
-	 * surounding freq piers by index */
-	for (pdg = 0; pdg < ee->ee_pd_gains[ee_mode]; pdg++) {
-
-		/* Fill curves in reverse order
-		 * from lower power (max gain)
-		 * to higher power. Use curve -> idx
-		 * backmaping we did on eeprom init */
-		u8 idx = pdg_curve_to_idx[pdg];
-
-		/* Grab the needed curves by index */
-		pdg_L = &pcinfo_L->pd_curves[idx];
-		pdg_R = &pcinfo_R->pd_curves[idx];
-
-		/* Initialize the temp tables */
-		tmpL = ah->ah_txpower.tmpL[pdg];
-		tmpR = ah->ah_txpower.tmpR[pdg];
-
-		/* Set curve's x boundaries and create
-		 * curves so that they cover the same
-		 * range (if we don't do that one table
-		 * will have values on some range and the
-		 * other one won't have any so interpolation
-		 * will fail) */
-		table_min[pdg] = min(pdg_L->pd_pwr[0],
-					pdg_R->pd_pwr[0]) / 2;
-
-		table_max[pdg] = max(pdg_L->pd_pwr[pdg_L->pd_points - 1],
-				pdg_R->pd_pwr[pdg_R->pd_points - 1]) / 2;
-
-		/* Now create the curves on surrounding channels
-		 * and interpolate if needed to get the final
-		 * curve for this gain on this channel */
-		switch (type) {
-		case AR5K_PWRTABLE_LINEAR_PCDAC:
-			/* Override min/max so that we don't loose
-			 * accuracy (don't divide by 2) */
-			table_min[pdg] = min(pdg_L->pd_pwr[0],
-						pdg_R->pd_pwr[0]);
-
-			table_max[pdg] =
-				max(pdg_L->pd_pwr[pdg_L->pd_points - 1],
-					pdg_R->pd_pwr[pdg_R->pd_points - 1]);
-
-			/* Override minimum so that we don't get
-			 * out of bounds while extrapolating
-			 * below. Don't do this when we have 2
-			 * curves and we are on the high power curve
-			 * because table_min is ok in this case */
-			if (!(ee->ee_pd_gains[ee_mode] > 1 && pdg == 0)) {
-
-				table_min[pdg] =
-					ath5k_get_linear_pcdac_min(pdg_L->pd_step,
-								pdg_R->pd_step,
-								pdg_L->pd_pwr,
-								pdg_R->pd_pwr);
-
-				/* Don't go too low because we will
-				 * miss the upper part of the curve.
-				 * Note: 126 = 31.5dB (max power supported)
-				 * in 0.25dB units */
-				if (table_max[pdg] - table_min[pdg] > 126)
-					table_min[pdg] = table_max[pdg] - 126;
-			}
-
-			/* Fall through */
-		case AR5K_PWRTABLE_PWR_TO_PCDAC:
-		case AR5K_PWRTABLE_PWR_TO_PDADC:
-
-			ath5k_create_power_curve(table_min[pdg],
-						table_max[pdg],
-						pdg_L->pd_pwr,
-						pdg_L->pd_step,
-						pdg_L->pd_points, tmpL, type);
-
-			/* We are in a calibration
-			 * pier, no need to interpolate
-			 * between freq piers */
-			if (pcinfo_L == pcinfo_R)
-				continue;
-
-			ath5k_create_power_curve(table_min[pdg],
-						table_max[pdg],
-						pdg_R->pd_pwr,
-						pdg_R->pd_step,
-						pdg_R->pd_points, tmpR, type);
-			break;
-		default:
-			return -EINVAL;
-		}
-
-		/* Interpolate between curves
-		 * of surounding freq piers to
-		 * get the final curve for this
-		 * pd gain. Re-use tmpL for interpolation
-		 * output */
-		for (i = 0; (i < (u16) (table_max[pdg] - table_min[pdg])) &&
-		(i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) {
-			tmpL[i] = (u8) ath5k_get_interpolated_value(target,
-							(s16) pcinfo_L->freq,
-							(s16) pcinfo_R->freq,
-							(s16) tmpL[i],
-							(s16) tmpR[i]);
-		}
-	}
-
-	/* Now we have a set of curves for this
-	 * channel on tmpL (x range is table_max - table_min
-	 * and y values are tmpL[pdg][]) sorted in the same
-	 * order as EEPROM (because we've used the backmaping).
-	 * So for RF5112 it's from higher power to lower power
-	 * and for RF2413 it's from lower power to higher power.
-	 * For RF5111 we only have one curve. */
-
-	/* Fill min and max power levels for this
-	 * channel by interpolating the values on
-	 * surounding channels to complete the dataset */
-	ah->ah_txpower.txp_min_pwr = ath5k_get_interpolated_value(target,
-					(s16) pcinfo_L->freq,
-					(s16) pcinfo_R->freq,
-					pcinfo_L->min_pwr, pcinfo_R->min_pwr);
-
-	ah->ah_txpower.txp_max_pwr = ath5k_get_interpolated_value(target,
-					(s16) pcinfo_L->freq,
-					(s16) pcinfo_R->freq,
-					pcinfo_L->max_pwr, pcinfo_R->max_pwr);
-
-	/* We are ready to go, fill PCDAC/PDADC
-	 * table and write settings on hardware */
-	switch (type) {
-	case AR5K_PWRTABLE_LINEAR_PCDAC:
-		/* For RF5112 we can have one or two curves
-		 * and each curve covers a certain power lvl
-		 * range so we need to do some more processing */
-		ath5k_combine_linear_pcdac_curves(ah, table_min, table_max,
-						ee->ee_pd_gains[ee_mode]);
-
-		/* Set txp.offset so that we can
-		 * match max power value with max
-		 * table index */
-		ah->ah_txpower.txp_offset = 64 - (table_max[0] / 2);
-
-		/* Write settings on hw */
-		ath5k_setup_pcdac_table(ah);
-		break;
-	case AR5K_PWRTABLE_PWR_TO_PCDAC:
-		/* We are done for RF5111 since it has only
-		 * one curve, just fit the curve on the table */
-		ath5k_fill_pwr_to_pcdac_table(ah, table_min, table_max);
-
-		/* No rate powertable adjustment for RF5111 */
-		ah->ah_txpower.txp_min_idx = 0;
-		ah->ah_txpower.txp_offset = 0;
-
-		/* Write settings on hw */
-		ath5k_setup_pcdac_table(ah);
-		break;
-	case AR5K_PWRTABLE_PWR_TO_PDADC:
-		/* Set PDADC boundaries and fill
-		 * final PDADC table */
-		ath5k_combine_pwr_to_pdadc_curves(ah, table_min, table_max,
-						ee->ee_pd_gains[ee_mode]);
-
-		/* Write settings on hw */
-		ath5k_setup_pwr_to_pdadc_table(ah, pdg, pdg_curve_to_idx);
-
-		/* Set txp.offset, note that table_min
-		 * can be negative */
-		ah->ah_txpower.txp_offset = table_min[0];
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-
-/*
- * Per-rate tx power setting
- *
- * This is the code that sets the desired tx power (below
- * maximum) on hw for each rate (we also have TPC that sets
- * power per packet). We do that by providing an index on the
- * PCDAC/PDADC table we set up.
- */
-
-/*
- * Set rate power table
- *
- * For now we only limit txpower based on maximum tx power
- * supported by hw (what's inside rate_info). We need to limit
- * this even more, based on regulatory domain etc.
- *
- * Rate power table contains indices to PCDAC/PDADC table (0.5dB steps)
- * and is indexed as follows:
- * rates[0] - rates[7] -> OFDM rates
- * rates[8] - rates[14] -> CCK rates
- * rates[15] -> XR rates (they all have the same power)
- */
-static void
-ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
-			struct ath5k_rate_pcal_info *rate_info,
-			u8 ee_mode)
-{
-	unsigned int i;
-	u16 *rates;
-
-	/* max_pwr is power level we got from driver/user in 0.5dB
-	 * units, switch to 0.25dB units so we can compare */
-	max_pwr *= 2;
-	max_pwr = min(max_pwr, (u16) ah->ah_txpower.txp_max_pwr) / 2;
-
-	/* apply rate limits */
-	rates = ah->ah_txpower.txp_rates_power_table;
-
-	/* OFDM rates 6 to 24Mb/s */
-	for (i = 0; i < 5; i++)
-		rates[i] = min(max_pwr, rate_info->target_power_6to24);
-
-	/* Rest OFDM rates */
-	rates[5] = min(rates[0], rate_info->target_power_36);
-	rates[6] = min(rates[0], rate_info->target_power_48);
-	rates[7] = min(rates[0], rate_info->target_power_54);
-
-	/* CCK rates */
-	/* 1L */
-	rates[8] = min(rates[0], rate_info->target_power_6to24);
-	/* 2L */
-	rates[9] = min(rates[0], rate_info->target_power_36);
-	/* 2S */
-	rates[10] = min(rates[0], rate_info->target_power_36);
-	/* 5L */
-	rates[11] = min(rates[0], rate_info->target_power_48);
-	/* 5S */
-	rates[12] = min(rates[0], rate_info->target_power_48);
-	/* 11L */
-	rates[13] = min(rates[0], rate_info->target_power_54);
-	/* 11S */
-	rates[14] = min(rates[0], rate_info->target_power_54);
-
-	/* XR rates */
-	rates[15] = min(rates[0], rate_info->target_power_6to24);
-
-	/* CCK rates have different peak to average ratio
-	 * so we have to tweak their power so that gainf
-	 * correction works ok. For this we use OFDM to
-	 * CCK delta from eeprom */
-	if ((ee_mode == AR5K_EEPROM_MODE_11G) &&
-	(ah->ah_phy_revision < AR5K_SREV_PHY_5212A))
-		for (i = 8; i <= 15; i++)
-			rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta;
-
-	ah->ah_txpower.txp_min_pwr = rates[7];
-	ah->ah_txpower.txp_max_pwr = rates[0];
-	ah->ah_txpower.txp_ofdm = rates[7];
-}
-
-
-/*
- * Set transmition power
- */
-int
-ath5k_hw_txpower(struct ath5k_hw *ah, struct net80211_channel *channel,
-		u8 ee_mode, u8 txpower)
-{
-	struct ath5k_rate_pcal_info rate_info;
-	u8 type;
-	int ret;
-
-	if (txpower > AR5K_TUNE_MAX_TXPOWER) {
-		DBG("ath5k: invalid tx power %d\n", txpower);
-		return -EINVAL;
-	}
-	if (txpower == 0)
-		txpower = AR5K_TUNE_DEFAULT_TXPOWER;
-
-	/* Reset TX power values */
-	memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
-	ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
-	ah->ah_txpower.txp_min_pwr = 0;
-	ah->ah_txpower.txp_max_pwr = AR5K_TUNE_MAX_TXPOWER;
-
-	/* Initialize TX power table */
-	switch (ah->ah_radio) {
-	case AR5K_RF5111:
-		type = AR5K_PWRTABLE_PWR_TO_PCDAC;
-		break;
-	case AR5K_RF5112:
-		type = AR5K_PWRTABLE_LINEAR_PCDAC;
-		break;
-	case AR5K_RF2413:
-	case AR5K_RF5413:
-	case AR5K_RF2316:
-	case AR5K_RF2317:
-	case AR5K_RF2425:
-		type = AR5K_PWRTABLE_PWR_TO_PDADC;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* FIXME: Only on channel/mode change */
-	ret = ath5k_setup_channel_powertable(ah, channel, ee_mode, type);
-	if (ret)
-		return ret;
-
-	/* Limit max power if we have a CTL available */
-	ath5k_get_max_ctl_power(ah, channel);
-
-	/* FIXME: Tx power limit for this regdomain
-	 * XXX: Mac80211/CRDA will do that anyway ? */
-
-	/* FIXME: Antenna reduction stuff */
-
-	/* FIXME: Limit power on turbo modes */
-
-	/* FIXME: TPC scale reduction */
-
-	/* Get surounding channels for per-rate power table
-	 * calibration */
-	ath5k_get_rate_pcal_data(ah, channel, &rate_info);
-
-	/* Setup rate power table */
-	ath5k_setup_rate_powertable(ah, txpower, &rate_info, ee_mode);
-
-	/* Write rate power table on hw */
-	ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) |
-		AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) |
-		AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1);
-
-	ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(7, 24) |
-		AR5K_TXPOWER_OFDM(6, 16) | AR5K_TXPOWER_OFDM(5, 8) |
-		AR5K_TXPOWER_OFDM(4, 0), AR5K_PHY_TXPOWER_RATE2);
-
-	ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(10, 24) |
-		AR5K_TXPOWER_CCK(9, 16) | AR5K_TXPOWER_CCK(15, 8) |
-		AR5K_TXPOWER_CCK(8, 0), AR5K_PHY_TXPOWER_RATE3);
-
-	ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(14, 24) |
-		AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) |
-		AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4);
-
-	/* FIXME: TPC support */
-	if (ah->ah_txpower.txp_tpc) {
-		ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE |
-			AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
-
-		ath5k_hw_reg_write(ah,
-			AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_ACK) |
-			AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CTS) |
-			AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP),
-			AR5K_TPC);
-	} else {
-		ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX |
-			AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
-	}
-
-	return 0;
-}
-
-int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 mode, u8 txpower)
-{
-	struct net80211_channel *channel = ah->ah_current_channel;
-
-	DBG2("ath5k: changing txpower to %d\n", txpower);
-
-	return ath5k_hw_txpower(ah, channel, mode, txpower);
-}
-
-#undef _ATH5K_PHY
diff --git a/roms/ipxe/src/drivers/net/ath5k/ath5k_qcu.c b/roms/ipxe/src/drivers/net/ath5k/ath5k_qcu.c
deleted file mode 100644
index e38dba9e2f3db763cc4408e1badcca736d7d3d73..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/ath5k_qcu.c
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
- *
- * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-FILE_LICENCE ( MIT );
-
-/********************************************\
-Queue Control Unit, DFS Control Unit Functions
-\********************************************/
-
-#include "ath5k.h"
-#include "reg.h"
-#include "base.h"
-
-/*
- * Set properties for a transmit queue
- */
-int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah,
-				const struct ath5k_txq_info *queue_info)
-{
-	if (ah->ah_txq.tqi_type == AR5K_TX_QUEUE_INACTIVE)
-		return -EIO;
-
-	memcpy(&ah->ah_txq, queue_info, sizeof(struct ath5k_txq_info));
-
-	/*XXX: Is this supported on 5210 ?*/
-	if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA &&
-			((queue_info->tqi_subtype == AR5K_WME_AC_VI) ||
-			(queue_info->tqi_subtype == AR5K_WME_AC_VO))) ||
-			queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD)
-		ah->ah_txq.tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
-
-	return 0;
-}
-
-/*
- * Initialize a transmit queue
- */
-int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
-		struct ath5k_txq_info *queue_info)
-{
-	int ret;
-
-	/*
-	 * Setup internal queue structure
-	 */
-	memset(&ah->ah_txq, 0, sizeof(struct ath5k_txq_info));
-	ah->ah_txq.tqi_type = queue_type;
-
-	if (queue_info != NULL) {
-		queue_info->tqi_type = queue_type;
-		ret = ath5k_hw_set_tx_queueprops(ah, queue_info);
-		if (ret)
-			return ret;
-	}
-
-	/*
-	 * We use ah_txq_status to hold a temp value for
-	 * the Secondary interrupt mask registers on 5211+
-	 * check out ath5k_hw_reset_tx_queue
-	 */
-	AR5K_Q_ENABLE_BITS(ah->ah_txq_status, 0);
-
-	return 0;
-}
-
-/*
- * Set a transmit queue inactive
- */
-void ath5k_hw_release_tx_queue(struct ath5k_hw *ah)
-{
-	/* This queue will be skipped in further operations */
-	ah->ah_txq.tqi_type = AR5K_TX_QUEUE_INACTIVE;
-	/*For SIMR setup*/
-	AR5K_Q_DISABLE_BITS(ah->ah_txq_status, 0);
-}
-
-/*
- * Set DFS properties for a transmit queue on DCU
- */
-int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah)
-{
-	u32 cw_min, cw_max, retry_lg, retry_sh;
-	struct ath5k_txq_info *tq = &ah->ah_txq;
-	const int queue = 0;
-
-	tq = &ah->ah_txq;
-
-	if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
-		return 0;
-
-	if (ah->ah_version == AR5K_AR5210) {
-		/* Only handle data queues, others will be ignored */
-		if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
-			return 0;
-
-		/* Set Slot time */
-		ath5k_hw_reg_write(ah, ah->ah_turbo ?
-			AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
-			AR5K_SLOT_TIME);
-		/* Set ACK_CTS timeout */
-		ath5k_hw_reg_write(ah, ah->ah_turbo ?
-			AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
-			AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
-		/* Set Transmit Latency */
-		ath5k_hw_reg_write(ah, ah->ah_turbo ?
-			AR5K_INIT_TRANSMIT_LATENCY_TURBO :
-			AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
-
-		/* Set IFS0 */
-		if (ah->ah_turbo) {
-			 ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
-				(ah->ah_aifs + tq->tqi_aifs) *
-				AR5K_INIT_SLOT_TIME_TURBO) <<
-				AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
-				AR5K_IFS0);
-		} else {
-			ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
-				(ah->ah_aifs + tq->tqi_aifs) *
-				AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) |
-				AR5K_INIT_SIFS, AR5K_IFS0);
-		}
-
-		/* Set IFS1 */
-		ath5k_hw_reg_write(ah, ah->ah_turbo ?
-			AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
-			AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
-		/* Set AR5K_PHY_SETTLING */
-		ath5k_hw_reg_write(ah, ah->ah_turbo ?
-			(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
-			| 0x38 :
-			(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
-			| 0x1C,
-			AR5K_PHY_SETTLING);
-		/* Set Frame Control Register */
-		ath5k_hw_reg_write(ah, ah->ah_turbo ?
-			(AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
-			AR5K_PHY_TURBO_SHORT | 0x2020) :
-			(AR5K_PHY_FRAME_CTL_INI | 0x1020),
-			AR5K_PHY_FRAME_CTL_5210);
-	}
-
-	/*
-	 * Calculate cwmin/max by channel mode
-	 */
-	cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN;
-	cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX;
-	ah->ah_aifs = AR5K_TUNE_AIFS;
-	/*XR is only supported on 5212*/
-	if (IS_CHAN_XR(ah->ah_current_channel) &&
-			ah->ah_version == AR5K_AR5212) {
-		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR;
-		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR;
-		ah->ah_aifs = AR5K_TUNE_AIFS_XR;
-	/*B mode is not supported on 5210*/
-	} else if (IS_CHAN_B(ah->ah_current_channel) &&
-			ah->ah_version != AR5K_AR5210) {
-		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B;
-		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B;
-		ah->ah_aifs = AR5K_TUNE_AIFS_11B;
-	}
-
-	cw_min = 1;
-	while (cw_min < ah->ah_cw_min)
-		cw_min = (cw_min << 1) | 1;
-
-	cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) :
-		((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1);
-	cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) :
-		((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1);
-
-	/*
-	 * Calculate and set retry limits
-	 */
-	if (ah->ah_software_retry) {
-		/* XXX Need to test this */
-		retry_lg = ah->ah_limit_tx_retries;
-		retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
-			AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg;
-	} else {
-		retry_lg = AR5K_INIT_LG_RETRY;
-		retry_sh = AR5K_INIT_SH_RETRY;
-	}
-
-	/*No QCU/DCU [5210]*/
-	if (ah->ah_version == AR5K_AR5210) {
-		ath5k_hw_reg_write(ah,
-			(cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
-			| AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
-				AR5K_NODCU_RETRY_LMT_SLG_RETRY)
-			| AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
-				AR5K_NODCU_RETRY_LMT_SSH_RETRY)
-			| AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
-			| AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
-			AR5K_NODCU_RETRY_LMT);
-	} else {
-		/*QCU/DCU [5211+]*/
-		ath5k_hw_reg_write(ah,
-			AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
-				AR5K_DCU_RETRY_LMT_SLG_RETRY) |
-			AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
-				AR5K_DCU_RETRY_LMT_SSH_RETRY) |
-			AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
-			AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
-			AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
-
-	/*===Rest is also for QCU/DCU only [5211+]===*/
-
-		/*
-		 * Set initial content window (cw_min/cw_max)
-		 * and arbitrated interframe space (aifs)...
-		 */
-		ath5k_hw_reg_write(ah,
-			AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
-			AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
-			AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs,
-				AR5K_DCU_LCL_IFS_AIFS),
-			AR5K_QUEUE_DFS_LOCAL_IFS(queue));
-
-		/*
-		 * Set misc registers
-		 */
-		/* Enable DCU early termination for this queue */
-		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
-					AR5K_QCU_MISC_DCU_EARLY);
-
-		/* Enable DCU to wait for next fragment from QCU */
-		AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
-					AR5K_DCU_MISC_FRAG_WAIT);
-
-		/* On Maui and Spirit use the global seqnum on DCU */
-		if (ah->ah_mac_version < AR5K_SREV_AR5211)
-			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
-						AR5K_DCU_MISC_SEQNUM_CTL);
-
-		if (tq->tqi_cbr_period) {
-			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
-				AR5K_QCU_CBRCFG_INTVAL) |
-				AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
-				AR5K_QCU_CBRCFG_ORN_THRES),
-				AR5K_QUEUE_CBRCFG(queue));
-			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
-				AR5K_QCU_MISC_FRSHED_CBR);
-			if (tq->tqi_cbr_overflow_limit)
-				AR5K_REG_ENABLE_BITS(ah,
-					AR5K_QUEUE_MISC(queue),
-					AR5K_QCU_MISC_CBR_THRES_ENABLE);
-		}
-
-		if (tq->tqi_ready_time &&
-		(tq->tqi_type != AR5K_TX_QUEUE_CAB))
-			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
-				AR5K_QCU_RDYTIMECFG_INTVAL) |
-				AR5K_QCU_RDYTIMECFG_ENABLE,
-				AR5K_QUEUE_RDYTIMECFG(queue));
-
-		if (tq->tqi_burst_time) {
-			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
-				AR5K_DCU_CHAN_TIME_DUR) |
-				AR5K_DCU_CHAN_TIME_ENABLE,
-				AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
-
-			if (tq->tqi_flags
-			& AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
-				AR5K_REG_ENABLE_BITS(ah,
-					AR5K_QUEUE_MISC(queue),
-					AR5K_QCU_MISC_RDY_VEOL_POLICY);
-		}
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
-			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
-				AR5K_QUEUE_DFS_MISC(queue));
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
-			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
-				AR5K_QUEUE_DFS_MISC(queue));
-
-		/* TODO: Handle frame compression */
-
-		/*
-		 * Enable interrupts for this tx queue
-		 * in the secondary interrupt mask registers
-		 */
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
-			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
-			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
-			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
-			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
-			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE)
-			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue);
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE)
-			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue);
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE)
-			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue);
-
-		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE)
-			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue);
-
-		/* Update secondary interrupt mask registers */
-
-		/* Filter out inactive queues */
-		ah->ah_txq_imr_txok &= ah->ah_txq_status;
-		ah->ah_txq_imr_txerr &= ah->ah_txq_status;
-		ah->ah_txq_imr_txurn &= ah->ah_txq_status;
-		ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
-		ah->ah_txq_imr_txeol &= ah->ah_txq_status;
-		ah->ah_txq_imr_cbrorn &= ah->ah_txq_status;
-		ah->ah_txq_imr_cbrurn &= ah->ah_txq_status;
-		ah->ah_txq_imr_qtrig &= ah->ah_txq_status;
-		ah->ah_txq_imr_nofrm &= ah->ah_txq_status;
-
-		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
-			AR5K_SIMR0_QCU_TXOK) |
-			AR5K_REG_SM(ah->ah_txq_imr_txdesc,
-			AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
-		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
-			AR5K_SIMR1_QCU_TXERR) |
-			AR5K_REG_SM(ah->ah_txq_imr_txeol,
-			AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
-		/* Update simr2 but don't overwrite rest simr2 settings */
-		AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN);
-		AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2,
-			AR5K_REG_SM(ah->ah_txq_imr_txurn,
-			AR5K_SIMR2_QCU_TXURN));
-		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn,
-			AR5K_SIMR3_QCBRORN) |
-			AR5K_REG_SM(ah->ah_txq_imr_cbrurn,
-			AR5K_SIMR3_QCBRURN), AR5K_SIMR3);
-		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig,
-			AR5K_SIMR4_QTRIG), AR5K_SIMR4);
-		/* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */
-		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm,
-			AR5K_TXNOFRM_QCU), AR5K_TXNOFRM);
-		/* No queue has TXNOFRM enabled, disable the interrupt
-		 * by setting AR5K_TXNOFRM to zero */
-		if (ah->ah_txq_imr_nofrm == 0)
-			ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM);
-
-		/* Set QCU mask for this DCU to save power */
-		AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
-	}
-
-	return 0;
-}
-
-/*
- * Set slot time on DCU
- */
-int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
-{
-	if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX)
-		return -EINVAL;
-
-	if (ah->ah_version == AR5K_AR5210)
-		ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time,
-				ah->ah_turbo), AR5K_SLOT_TIME);
-	else
-		ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT);
-
-	return 0;
-}
-
diff --git a/roms/ipxe/src/drivers/net/ath5k/ath5k_reset.c b/roms/ipxe/src/drivers/net/ath5k/ath5k_reset.c
deleted file mode 100644
index 2f36a4e9a04871afdfd18e977c126d24191b2a77..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/ath5k_reset.c
+++ /dev/null
@@ -1,1174 +0,0 @@
-/*
- * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
- * Copyright (c) 2007-2008 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
- * Copyright (c) 2007-2008 Pavel Roskin <proski@gnu.org>
- * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com>
- *
- * Lightly modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-FILE_LICENCE ( MIT );
-
-#define _ATH5K_RESET
-
-/*****************************\
-  Reset functions and helpers
-\*****************************/
-
-#include <ipxe/pci.h> 		/* To determine if a card is pci-e */
-#include <unistd.h>
-
-#include "ath5k.h"
-#include "reg.h"
-#include "base.h"
-
-/* Find last set bit; fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32 */
-static int fls(int x)
-{
-        int r = 32;
-
-        if (!x)
-                return 0;
-        if (!(x & 0xffff0000u)) {
-                x <<= 16;
-                r -= 16;
-        }
-        if (!(x & 0xff000000u)) {
-                x <<= 8;
-                r -= 8;
-        }
-        if (!(x & 0xf0000000u)) {
-                x <<= 4;
-                r -= 4;
-        }
-        if (!(x & 0xc0000000u)) {
-                x <<= 2;
-                r -= 2;
-        }
-        if (!(x & 0x80000000u)) {
-                x <<= 1;
-                r -= 1;
-        }
-        return r;
-}
-
-
-/**
- * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
- *
- * @ah: the &struct ath5k_hw
- * @channel: the currently set channel upon reset
- *
- * Write the delta slope coefficient (used on pilot tracking ?) for OFDM
- * operation on the AR5212 upon reset. This is a helper for ath5k_hw_reset().
- *
- * Since delta slope is floating point we split it on its exponent and
- * mantissa and provide these values on hw.
- *
- * For more infos i think this patent is related
- * http://www.freepatentsonline.com/7184495.html
- */
-static int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
-	struct net80211_channel *channel)
-{
-	/* Get exponent and mantissa and set it */
-	u32 coef_scaled, coef_exp, coef_man,
-		ds_coef_exp, ds_coef_man, clock;
-
-	if (!(ah->ah_version == AR5K_AR5212) ||
-	    !(channel->hw_value & CHANNEL_OFDM)) {
-		DBG("ath5k: attempt to set OFDM timings on non-OFDM channel\n");
-		return -EFAULT;
-	}
-
-	/* Get coefficient
-	 * ALGO: coef = (5 * clock * carrier_freq) / 2)
-	 * we scale coef by shifting clock value by 24 for
-	 * better precision since we use integers */
-	/* TODO: Half/quarter rate */
-	clock =  ath5k_hw_htoclock(1, channel->hw_value & CHANNEL_TURBO);
-
-	coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq;
-
-	/* Get exponent
-	 * ALGO: coef_exp = 14 - highest set bit position */
-	coef_exp = fls(coef_scaled) - 1;
-
-	/* Doesn't make sense if it's zero*/
-	if (!coef_scaled || !coef_exp)
-		return -EINVAL;
-
-	/* Note: we've shifted coef_scaled by 24 */
-	coef_exp = 14 - (coef_exp - 24);
-
-
-	/* Get mantissa (significant digits)
-	 * ALGO: coef_mant = floor(coef_scaled* 2^coef_exp+0.5) */
-	coef_man = coef_scaled +
-		(1 << (24 - coef_exp - 1));
-
-	/* Calculate delta slope coefficient exponent
-	 * and mantissa (remove scaling) and set them on hw */
-	ds_coef_man = coef_man >> (24 - coef_exp);
-	ds_coef_exp = coef_exp - 16;
-
-	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
-		AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man);
-	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
-		AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp);
-
-	return 0;
-}
-
-
-/*
- * index into rates for control rates, we can set it up like this because
- * this is only used for AR5212 and we know it supports G mode
- */
-static const unsigned int control_rates[] =
-	{ 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 };
-
-/**
- * ath5k_hw_write_rate_duration - fill rate code to duration table
- *
- * @ah: the &struct ath5k_hw
- * @mode: one of enum ath5k_driver_mode
- *
- * Write the rate code to duration table upon hw reset. This is a helper for
- * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout on
- * the hardware, based on current mode, for each rate. The rates which are
- * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have
- * different rate code so we write their value twice (one for long preample
- * and one for short).
- *
- * Note: Band doesn't matter here, if we set the values for OFDM it works
- * on both a and g modes. So all we have to do is set values for all g rates
- * that include all OFDM and CCK rates. If we operate in turbo or xr/half/
- * quarter rate mode, we need to use another set of bitrates (that's why we
- * need the mode parameter) but we don't handle these proprietary modes yet.
- */
-static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
-       unsigned int mode __unused)
-{
-	struct ath5k_softc *sc = ah->ah_sc;
-	u16 rate;
-	int i;
-
-	/* Write rate duration table */
-	for (i = 0; i < sc->hwinfo->nr_rates[NET80211_BAND_2GHZ]; i++) {
-		u32 reg;
-		u16 tx_time;
-
-		rate = sc->hwinfo->rates[NET80211_BAND_2GHZ][i];
-
-		/* Set ACK timeout */
-		reg = AR5K_RATE_DUR(ath5k_bitrate_to_hw_rix(rate));
-
-		/* An ACK frame consists of 10 bytes. If you add the FCS,
-		 * it's 14 bytes. Note we use the control rate and not the
-		 * actual rate for this rate. See mac80211 tx.c
-		 * ieee80211_duration() for a brief description of
-		 * what rate we should choose to TX ACKs. */
-		tx_time = net80211_duration(sc->dev, 14, rate);
-
-		ath5k_hw_reg_write(ah, tx_time, reg);
-
-		if (rate != 20 && rate != 55 && rate != 110)
-			continue;
-
-		/*
-		 * We're not distinguishing short preamble here,
-		 * This is true, all we'll get is a longer value here
-		 * which is not necessarilly bad.
-		 */
-		ath5k_hw_reg_write(ah, tx_time,
-			reg + (AR5K_SET_SHORT_PREAMBLE << 2));
-	}
-}
-
-/*
- * Reset chipset
- */
-static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
-{
-	int ret;
-	u32 mask = val ? val : ~0U;
-
-	/* Read-and-clear RX Descriptor Pointer*/
-	ath5k_hw_reg_read(ah, AR5K_RXDP);
-
-	/*
-	 * Reset the device and wait until success
-	 */
-	ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL);
-
-	/* Wait at least 128 PCI clocks */
-	udelay(15);
-
-	if (ah->ah_version == AR5K_AR5210) {
-		val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
-			| AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY;
-		mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA
-			| AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY;
-	} else {
-		val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
-		mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
-	}
-
-	ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, 0);
-
-	/*
-	 * Reset configuration register (for hw byte-swap). Note that this
-	 * is only set for big endian. We do the necessary magic in
-	 * AR5K_INIT_CFG.
-	 */
-	if ((val & AR5K_RESET_CTL_PCU) == 0)
-		ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG);
-
-	return ret;
-}
-
-/*
- * Sleep control
- */
-int ath5k_hw_wake(struct ath5k_hw *ah)
-{
-	unsigned int i;
-	u32 staid, data;
-
-	staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
-	staid &= ~AR5K_STA_ID1_PWR_SV;
-
-	/* Preserve sleep duration */
-	data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
-	if (data & 0xffc00000)
-		data = 0;
-	else
-		data = data & 0xfffcffff;
-
-	ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
-	udelay(15);
-
-	for (i = 50; i > 0; i--) {
-		/* Check if the chip did wake up */
-		if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
-		     AR5K_PCICFG_SPWR_DN) == 0)
-			break;
-
-		/* Wait a bit and retry */
-		udelay(200);
-		ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
-	}
-
-	/* Fail if the chip didn't wake up */
-	if (i <= 0)
-		return -EIO;
-
-	ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
-
-	return 0;
-}
-
-/*
- * Bring up MAC + PHY Chips and program PLL
- * TODO: Half/Quarter rate support
- */
-int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, int initial __unused)
-{
-	struct pci_device *pdev = ah->ah_sc->pdev;
-	u32 turbo, mode, clock, bus_flags;
-	int ret;
-
-	turbo = 0;
-	mode = 0;
-	clock = 0;
-
-	/* Wakeup the device */
-	ret = ath5k_hw_wake(ah);
-	if (ret) {
-		DBG("ath5k: failed to wake up the MAC chip\n");
-		return ret;
-	}
-
-	if (ah->ah_version != AR5K_AR5210) {
-		/*
-		 * Get channel mode flags
-		 */
-
-		if (ah->ah_radio >= AR5K_RF5112) {
-			mode = AR5K_PHY_MODE_RAD_RF5112;
-			clock = AR5K_PHY_PLL_RF5112;
-		} else {
-			mode = AR5K_PHY_MODE_RAD_RF5111;	/*Zero*/
-			clock = AR5K_PHY_PLL_RF5111;		/*Zero*/
-		}
-
-		if (flags & CHANNEL_2GHZ) {
-			mode |= AR5K_PHY_MODE_FREQ_2GHZ;
-			clock |= AR5K_PHY_PLL_44MHZ;
-
-			if (flags & CHANNEL_CCK) {
-				mode |= AR5K_PHY_MODE_MOD_CCK;
-			} else if (flags & CHANNEL_OFDM) {
-				/* XXX Dynamic OFDM/CCK is not supported by the
-				 * AR5211 so we set MOD_OFDM for plain g (no
-				 * CCK headers) operation. We need to test
-				 * this, 5211 might support ofdm-only g after
-				 * all, there are also initial register values
-				 * in the code for g mode (see initvals.c). */
-				if (ah->ah_version == AR5K_AR5211)
-					mode |= AR5K_PHY_MODE_MOD_OFDM;
-				else
-					mode |= AR5K_PHY_MODE_MOD_DYN;
-			} else {
-				DBG("ath5k: invalid radio modulation mode\n");
-				return -EINVAL;
-			}
-		} else if (flags & CHANNEL_5GHZ) {
-			mode |= AR5K_PHY_MODE_FREQ_5GHZ;
-
-			if (ah->ah_radio == AR5K_RF5413)
-				clock = AR5K_PHY_PLL_40MHZ_5413;
-			else
-				clock |= AR5K_PHY_PLL_40MHZ;
-
-			if (flags & CHANNEL_OFDM)
-				mode |= AR5K_PHY_MODE_MOD_OFDM;
-			else {
-				DBG("ath5k: invalid radio modulation mode\n");
-				return -EINVAL;
-			}
-		} else {
-			DBG("ath5k: invalid radio frequency mode\n");
-			return -EINVAL;
-		}
-
-		if (flags & CHANNEL_TURBO)
-			turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT;
-	} else { /* Reset the device */
-
-		/* ...enable Atheros turbo mode if requested */
-		if (flags & CHANNEL_TURBO)
-			ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE,
-					AR5K_PHY_TURBO);
-	}
-
-	/* reseting PCI on PCI-E cards results card to hang
-	 * and always return 0xffff... so we ingore that flag
-	 * for PCI-E cards */
-	if (pci_find_capability(pdev, PCI_CAP_ID_EXP))
-		bus_flags = 0;
-	else
-		bus_flags = AR5K_RESET_CTL_PCI;
-
-	/* Reset chipset */
-	if (ah->ah_version == AR5K_AR5210) {
-		ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
-			AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
-			AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
-		mdelay(2);
-	} else {
-		ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
-			AR5K_RESET_CTL_BASEBAND | bus_flags);
-	}
-	if (ret) {
-		DBG("ath5k: failed to reset the MAC chip\n");
-		return -EIO;
-	}
-
-	/* ...wakeup again!*/
-	ret = ath5k_hw_wake(ah);
-	if (ret) {
-		DBG("ath5k: failed to resume the MAC chip\n");
-		return ret;
-	}
-
-	/* ...final warm reset */
-	if (ath5k_hw_nic_reset(ah, 0)) {
-		DBG("ath5k: failed to warm reset the MAC chip\n");
-		return -EIO;
-	}
-
-	if (ah->ah_version != AR5K_AR5210) {
-
-		/* ...update PLL if needed */
-		if (ath5k_hw_reg_read(ah, AR5K_PHY_PLL) != clock) {
-			ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
-			udelay(300);
-		}
-
-		/* ...set the PHY operating mode */
-		ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE);
-		ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO);
-	}
-
-	return 0;
-}
-
-static int ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
-				struct net80211_channel *channel)
-{
-	u8 refclk_freq;
-
-	if ((ah->ah_radio == AR5K_RF5112) ||
-	(ah->ah_radio == AR5K_RF5413) ||
-	(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
-		refclk_freq = 40;
-	else
-		refclk_freq = 32;
-
-	if ((channel->center_freq % refclk_freq != 0) &&
-	((channel->center_freq % refclk_freq < 10) ||
-	(channel->center_freq % refclk_freq > 22)))
-		return 1;
-	else
-		return 0;
-}
-
-/* TODO: Half/Quarter rate */
-static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
-				struct net80211_channel *channel)
-{
-	if (ah->ah_version == AR5K_AR5212 &&
-	    ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
-
-		/* Setup ADC control */
-		ath5k_hw_reg_write(ah,
-				(AR5K_REG_SM(2,
-				AR5K_PHY_ADC_CTL_INBUFGAIN_OFF) |
-				AR5K_REG_SM(2,
-				AR5K_PHY_ADC_CTL_INBUFGAIN_ON) |
-				AR5K_PHY_ADC_CTL_PWD_DAC_OFF |
-				AR5K_PHY_ADC_CTL_PWD_ADC_OFF),
-				AR5K_PHY_ADC_CTL);
-
-
-
-		/* Disable barker RSSI threshold */
-		AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_DAG_CCK_CTL,
-				AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR);
-
-		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DAG_CCK_CTL,
-			AR5K_PHY_DAG_CCK_CTL_RSSI_THR, 2);
-
-		/* Set the mute mask */
-		ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK);
-	}
-
-	/* Clear PHY_BLUETOOTH to allow RX_CLEAR line debug */
-	if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212B)
-		ath5k_hw_reg_write(ah, 0, AR5K_PHY_BLUETOOTH);
-
-	/* Enable DCU double buffering */
-	if (ah->ah_phy_revision > AR5K_SREV_PHY_5212B)
-		AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
-				AR5K_TXCFG_DCU_DBL_BUF_DIS);
-
-	/* Set DAC/ADC delays */
-	if (ah->ah_version == AR5K_AR5212) {
-		u32 scal;
-		if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
-			scal = AR5K_PHY_SCAL_32MHZ_2417;
-		else if (ath5k_eeprom_is_hb63(ah))
-			scal = AR5K_PHY_SCAL_32MHZ_HB63;
-		else
-			scal = AR5K_PHY_SCAL_32MHZ;
-		ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL);
-	}
-
-	/* Set fast ADC */
-	if ((ah->ah_radio == AR5K_RF5413) ||
-	(ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
-		u32 fast_adc = 1;
-
-		if (channel->center_freq == 2462 ||
-		channel->center_freq == 2467)
-			fast_adc = 0;
-
-		/* Only update if needed */
-		if (ath5k_hw_reg_read(ah, AR5K_PHY_FAST_ADC) != fast_adc)
-				ath5k_hw_reg_write(ah, fast_adc,
-						AR5K_PHY_FAST_ADC);
-	}
-
-	/* Fix for first revision of the RF5112 RF chipset */
-	if (ah->ah_radio == AR5K_RF5112 &&
-			ah->ah_radio_5ghz_revision <
-			AR5K_SREV_RAD_5112A) {
-		u32 data;
-		ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
-				AR5K_PHY_CCKTXCTL);
-		if (channel->hw_value & CHANNEL_5GHZ)
-			data = 0xffb81020;
-		else
-			data = 0xffb80d20;
-		ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
-	}
-
-	if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
-		u32 usec_reg;
-		/* 5311 has different tx/rx latency masks
-		 * from 5211, since we deal 5311 the same
-		 * as 5211 when setting initvals, shift
-		 * values here to their proper locations */
-		usec_reg = ath5k_hw_reg_read(ah, AR5K_USEC_5211);
-		ath5k_hw_reg_write(ah, usec_reg & (AR5K_USEC_1 |
-				AR5K_USEC_32 |
-				AR5K_USEC_TX_LATENCY_5211 |
-				AR5K_REG_SM(29,
-				AR5K_USEC_RX_LATENCY_5210)),
-				AR5K_USEC_5211);
-		/* Clear QCU/DCU clock gating register */
-		ath5k_hw_reg_write(ah, 0, AR5K_QCUDCU_CLKGT);
-		/* Set DAC/ADC delays */
-		ath5k_hw_reg_write(ah, 0x08, AR5K_PHY_SCAL);
-		/* Enable PCU FIFO corruption ECO */
-		AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
-					AR5K_DIAG_SW_ECO_ENABLE);
-	}
-}
-
-static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
-		struct net80211_channel *channel, u8 *ant, u8 ee_mode)
-{
-	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-	s16 cck_ofdm_pwr_delta;
-
-	/* Adjust power delta for channel 14 */
-	if (channel->center_freq == 2484)
-		cck_ofdm_pwr_delta =
-			((ee->ee_cck_ofdm_power_delta -
-			ee->ee_scaled_cck_delta) * 2) / 10;
-	else
-		cck_ofdm_pwr_delta =
-			(ee->ee_cck_ofdm_power_delta * 2) / 10;
-
-	/* Set CCK to OFDM power delta on tx power
-	 * adjustment register */
-	if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
-		if (channel->hw_value == CHANNEL_G)
-			ath5k_hw_reg_write(ah,
-			AR5K_REG_SM((ee->ee_cck_ofdm_gain_delta * -1),
-				AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) |
-			AR5K_REG_SM((cck_ofdm_pwr_delta * -1),
-				AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX),
-				AR5K_PHY_TX_PWR_ADJ);
-		else
-			ath5k_hw_reg_write(ah, 0, AR5K_PHY_TX_PWR_ADJ);
-	} else {
-		/* For older revs we scale power on sw during tx power
-		 * setup */
-		ah->ah_txpower.txp_cck_ofdm_pwr_delta = cck_ofdm_pwr_delta;
-		ah->ah_txpower.txp_cck_ofdm_gainf_delta =
-						ee->ee_cck_ofdm_gain_delta;
-	}
-
-	/* Set antenna idle switch table */
-	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_ANT_CTL,
-			AR5K_PHY_ANT_CTL_SWTABLE_IDLE,
-			(ah->ah_antenna[ee_mode][0] |
-			AR5K_PHY_ANT_CTL_TXRX_EN));
-
-	/* Set antenna switch table */
-	ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]],
-		AR5K_PHY_ANT_SWITCH_TABLE_0);
-	ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]],
-		AR5K_PHY_ANT_SWITCH_TABLE_1);
-
-	/* Noise floor threshold */
-	ath5k_hw_reg_write(ah,
-		AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
-		AR5K_PHY_NFTHRES);
-
-	if ((channel->hw_value & CHANNEL_TURBO) &&
-	(ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0)) {
-		/* Switch settling time (Turbo) */
-		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
-				AR5K_PHY_SETTLING_SWITCH,
-				ee->ee_switch_settling_turbo[ee_mode]);
-
-		/* Tx/Rx attenuation (Turbo) */
-		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN,
-				AR5K_PHY_GAIN_TXRX_ATTEN,
-				ee->ee_atn_tx_rx_turbo[ee_mode]);
-
-		/* ADC/PGA desired size (Turbo) */
-		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
-				AR5K_PHY_DESIRED_SIZE_ADC,
-				ee->ee_adc_desired_size_turbo[ee_mode]);
-
-		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
-				AR5K_PHY_DESIRED_SIZE_PGA,
-				ee->ee_pga_desired_size_turbo[ee_mode]);
-
-		/* Tx/Rx margin (Turbo) */
-		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
-				AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
-				ee->ee_margin_tx_rx_turbo[ee_mode]);
-
-	} else {
-		/* Switch settling time */
-		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
-				AR5K_PHY_SETTLING_SWITCH,
-				ee->ee_switch_settling[ee_mode]);
-
-		/* Tx/Rx attenuation */
-		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN,
-				AR5K_PHY_GAIN_TXRX_ATTEN,
-				ee->ee_atn_tx_rx[ee_mode]);
-
-		/* ADC/PGA desired size */
-		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
-				AR5K_PHY_DESIRED_SIZE_ADC,
-				ee->ee_adc_desired_size[ee_mode]);
-
-		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
-				AR5K_PHY_DESIRED_SIZE_PGA,
-				ee->ee_pga_desired_size[ee_mode]);
-
-		/* Tx/Rx margin */
-		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
-			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
-				AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
-				ee->ee_margin_tx_rx[ee_mode]);
-	}
-
-	/* XPA delays */
-	ath5k_hw_reg_write(ah,
-		(ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
-		(ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
-		(ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
-		(ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4);
-
-	/* XLNA delay */
-	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RF_CTL3,
-			AR5K_PHY_RF_CTL3_TXE2XLNA_ON,
-			ee->ee_tx_end2xlna_enable[ee_mode]);
-
-	/* Thresh64 (ANI) */
-	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_NF,
-			AR5K_PHY_NF_THRESH62,
-			ee->ee_thr_62[ee_mode]);
-
-
-	/* False detect backoff for channels
-	 * that have spur noise. Write the new
-	 * cyclic power RSSI threshold. */
-	if (ath5k_hw_chan_has_spur_noise(ah, channel))
-		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
-				AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
-				AR5K_INIT_CYCRSSI_THR1 +
-				ee->ee_false_detect[ee_mode]);
-	else
-		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
-				AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1,
-				AR5K_INIT_CYCRSSI_THR1);
-
-	/* I/Q correction
-	 * TODO: Per channel i/q infos ? */
-	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
-		AR5K_PHY_IQ_CORR_ENABLE |
-		(ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) |
-		ee->ee_q_cal[ee_mode]);
-
-	/* Heavy clipping -disable for now */
-	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_1)
-		ath5k_hw_reg_write(ah, 0, AR5K_PHY_HEAVY_CLIP_ENABLE);
-
-	return;
-}
-
-/*
- * Main reset function
- */
-int ath5k_hw_reset(struct ath5k_hw *ah,
-	struct net80211_channel *channel, int change_channel)
-{
-	u32 s_seq[10], s_ant, s_led[3], staid1_flags;
-	u32 phy_tst1;
-	u8 mode, freq, ee_mode, ant[2];
-	int i, ret;
-
-	s_ant = 0;
-	ee_mode = 0;
-	staid1_flags = 0;
-	freq = 0;
-	mode = 0;
-
-	/*
-	 * Save some registers before a reset
-	 */
-	/*DCU/Antenna selection not available on 5210*/
-	if (ah->ah_version != AR5K_AR5210) {
-
-		switch (channel->hw_value & CHANNEL_MODES) {
-		case CHANNEL_A:
-			mode = AR5K_MODE_11A;
-			freq = AR5K_INI_RFGAIN_5GHZ;
-			ee_mode = AR5K_EEPROM_MODE_11A;
-			break;
-		case CHANNEL_G:
-			mode = AR5K_MODE_11G;
-			freq = AR5K_INI_RFGAIN_2GHZ;
-			ee_mode = AR5K_EEPROM_MODE_11G;
-			break;
-		case CHANNEL_B:
-			mode = AR5K_MODE_11B;
-			freq = AR5K_INI_RFGAIN_2GHZ;
-			ee_mode = AR5K_EEPROM_MODE_11B;
-			break;
-		case CHANNEL_T:
-			mode = AR5K_MODE_11A_TURBO;
-			freq = AR5K_INI_RFGAIN_5GHZ;
-			ee_mode = AR5K_EEPROM_MODE_11A;
-			break;
-		case CHANNEL_TG:
-			if (ah->ah_version == AR5K_AR5211) {
-				DBG("ath5k: TurboG not available on 5211\n");
-				return -EINVAL;
-			}
-			mode = AR5K_MODE_11G_TURBO;
-			freq = AR5K_INI_RFGAIN_2GHZ;
-			ee_mode = AR5K_EEPROM_MODE_11G;
-			break;
-		case CHANNEL_XR:
-			if (ah->ah_version == AR5K_AR5211) {
-				DBG("ath5k: XR mode not available on 5211\n");
-				return -EINVAL;
-			}
-			mode = AR5K_MODE_XR;
-			freq = AR5K_INI_RFGAIN_5GHZ;
-			ee_mode = AR5K_EEPROM_MODE_11A;
-			break;
-		default:
-			DBG("ath5k: invalid channel (%d MHz)\n",
-			    channel->center_freq);
-			return -EINVAL;
-		}
-
-		if (change_channel) {
-			/*
-			 * Save frame sequence count
-			 * For revs. after Oahu, only save
-			 * seq num for DCU 0 (Global seq num)
-			 */
-			if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
-
-				for (i = 0; i < 10; i++)
-					s_seq[i] = ath5k_hw_reg_read(ah,
-						AR5K_QUEUE_DCU_SEQNUM(i));
-
-			} else {
-				s_seq[0] = ath5k_hw_reg_read(ah,
-						AR5K_QUEUE_DCU_SEQNUM(0));
-			}
-		}
-
-		/* Save default antenna */
-		s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
-
-		if (ah->ah_version == AR5K_AR5212) {
-			/* Since we are going to write rf buffer
-			 * check if we have any pending gain_F
-			 * optimization settings */
-			if (change_channel && ah->ah_rf_banks != NULL)
-				ath5k_hw_gainf_calibrate(ah);
-		}
-	}
-
-	/*GPIOs*/
-	s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) &
-					AR5K_PCICFG_LEDSTATE;
-	s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
-	s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
-
-	/* AR5K_STA_ID1 flags, only preserve antenna
-	 * settings and ack/cts rate mode */
-	staid1_flags = ath5k_hw_reg_read(ah, AR5K_STA_ID1) &
-			(AR5K_STA_ID1_DEFAULT_ANTENNA |
-			AR5K_STA_ID1_DESC_ANTENNA |
-			AR5K_STA_ID1_RTS_DEF_ANTENNA |
-			AR5K_STA_ID1_ACKCTS_6MB |
-			AR5K_STA_ID1_BASE_RATE_11B |
-			AR5K_STA_ID1_SELFGEN_DEF_ANT);
-
-	/* Wakeup the device */
-	ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, 0);
-	if (ret)
-		return ret;
-
-	/* PHY access enable */
-	if (ah->ah_mac_srev >= AR5K_SREV_AR5211)
-		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
-	else
-		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ | 0x40,
-							AR5K_PHY(0));
-
-	/* Write initial settings */
-	ret = ath5k_hw_write_initvals(ah, mode, change_channel);
-	if (ret)
-		return ret;
-
-	/*
-	 * 5211/5212 Specific
-	 */
-	if (ah->ah_version != AR5K_AR5210) {
-
-		/*
-		 * Write initial RF gain settings
-		 * This should work for both 5111/5112
-		 */
-		ret = ath5k_hw_rfgain_init(ah, freq);
-		if (ret)
-			return ret;
-
-		mdelay(1);
-
-		/*
-		 * Tweak initval settings for revised
-		 * chipsets and add some more config
-		 * bits
-		 */
-		ath5k_hw_tweak_initval_settings(ah, channel);
-
-		/*
-		 * Set TX power (FIXME)
-		 */
-		ret = ath5k_hw_txpower(ah, channel, ee_mode,
-					AR5K_TUNE_DEFAULT_TXPOWER);
-		if (ret)
-			return ret;
-
-		/* Write rate duration table only on AR5212 */
-		if (ah->ah_version == AR5K_AR5212)
-			ath5k_hw_write_rate_duration(ah, mode);
-
-		/*
-		 * Write RF buffer
-		 */
-		ret = ath5k_hw_rfregs_init(ah, channel, mode);
-		if (ret)
-			return ret;
-
-
-		/* Write OFDM timings on 5212*/
-		if (ah->ah_version == AR5K_AR5212 &&
-			channel->hw_value & CHANNEL_OFDM) {
-			ret = ath5k_hw_write_ofdm_timings(ah, channel);
-			if (ret)
-				return ret;
-		}
-
-		/*Enable/disable 802.11b mode on 5111
-		(enable 2111 frequency converter + CCK)*/
-		if (ah->ah_radio == AR5K_RF5111) {
-			if (mode == AR5K_MODE_11B)
-				AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
-				    AR5K_TXCFG_B_MODE);
-			else
-				AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
-				    AR5K_TXCFG_B_MODE);
-		}
-
-		/*
-		 * In case a fixed antenna was set as default
-		 * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE
-		 * registers.
-		 */
-		if (s_ant != 0) {
-			if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */
-				ant[0] = ant[1] = AR5K_ANT_FIXED_A;
-			else	/* 2 - Aux */
-				ant[0] = ant[1] = AR5K_ANT_FIXED_B;
-		} else {
-			ant[0] = AR5K_ANT_FIXED_A;
-			ant[1] = AR5K_ANT_FIXED_B;
-		}
-
-		/* Commit values from EEPROM */
-		ath5k_hw_commit_eeprom_settings(ah, channel, ant, ee_mode);
-
-	} else {
-		/*
-		 * For 5210 we do all initialization using
-		 * initvals, so we don't have to modify
-		 * any settings (5210 also only supports
-		 * a/aturbo modes)
-		 */
-		mdelay(1);
-		/* Disable phy and wait */
-		ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
-		mdelay(1);
-	}
-
-	/*
-	 * Restore saved values
-	 */
-
-	/*DCU/Antenna selection not available on 5210*/
-	if (ah->ah_version != AR5K_AR5210) {
-
-		if (change_channel) {
-			if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
-				for (i = 0; i < 10; i++)
-					ath5k_hw_reg_write(ah, s_seq[i],
-						AR5K_QUEUE_DCU_SEQNUM(i));
-			} else {
-				ath5k_hw_reg_write(ah, s_seq[0],
-					AR5K_QUEUE_DCU_SEQNUM(0));
-			}
-		}
-
-		ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA);
-	}
-
-	/* Ledstate */
-	AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]);
-
-	/* Gpio settings */
-	ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR);
-	ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
-
-	/* Restore sta_id flags and preserve our mac address*/
-	ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_sta_id),
-						AR5K_STA_ID0);
-	ath5k_hw_reg_write(ah, staid1_flags | AR5K_HIGH_ID(ah->ah_sta_id),
-						AR5K_STA_ID1);
-
-
-	/*
-	 * Configure PCU
-	 */
-
-	/* Restore bssid and bssid mask */
-	/* XXX: add ah->aid once mac80211 gives this to us */
-	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
-
-	/* Set PCU config */
-	ath5k_hw_set_opmode(ah);
-
-	/* Clear any pending interrupts
-	 * PISR/SISR Not available on 5210 */
-	if (ah->ah_version != AR5K_AR5210)
-		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
-
-	/* Set RSSI/BRSSI thresholds
-	 *
-	 * Note: If we decide to set this value
-	 * dynamicaly, have in mind that when AR5K_RSSI_THR
-	 * register is read it might return 0x40 if we haven't
-	 * wrote anything to it plus BMISS RSSI threshold is zeroed.
-	 * So doing a save/restore procedure here isn't the right
-	 * choice. Instead store it on ath5k_hw */
-	ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES |
-				AR5K_TUNE_BMISS_THRES <<
-				AR5K_RSSI_THR_BMISS_S),
-				AR5K_RSSI_THR);
-
-	/* MIC QoS support */
-	if (ah->ah_mac_srev >= AR5K_SREV_AR2413) {
-		ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL);
-		ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL);
-	}
-
-	/* QoS NOACK Policy */
-	if (ah->ah_version == AR5K_AR5212) {
-		ath5k_hw_reg_write(ah,
-			AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) |
-			AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET)  |
-			AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET),
-			AR5K_QOS_NOACK);
-	}
-
-
-	/*
-	 * Configure PHY
-	 */
-
-	/* Set channel on PHY */
-	ret = ath5k_hw_channel(ah, channel);
-	if (ret)
-		return ret;
-
-	/*
-	 * Enable the PHY and wait until completion
-	 * This includes BaseBand and Synthesizer
-	 * activation.
-	 */
-	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
-
-	/*
-	 * On 5211+ read activation -> rx delay
-	 * and use it.
-	 *
-	 * TODO: Half/quarter rate support
-	 */
-	if (ah->ah_version != AR5K_AR5210) {
-		u32 delay;
-		delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
-			AR5K_PHY_RX_DELAY_M;
-		delay = (channel->hw_value & CHANNEL_CCK) ?
-			((delay << 2) / 22) : (delay / 10);
-
-		udelay(100 + (2 * delay));
-	} else {
-		mdelay(1);
-	}
-
-	/*
-	 * Perform ADC test to see if baseband is ready
-	 * Set tx hold and check adc test register
-	 */
-	phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
-	ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
-	for (i = 0; i <= 20; i++) {
-		if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
-			break;
-		udelay(200);
-	}
-	ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
-
-	/*
-	 * Start automatic gain control calibration
-	 *
-	 * During AGC calibration RX path is re-routed to
-	 * a power detector so we don't receive anything.
-	 *
-	 * This method is used to calibrate some static offsets
-	 * used together with on-the fly I/Q calibration (the
-	 * one performed via ath5k_hw_phy_calibrate), that doesn't
-	 * interrupt rx path.
-	 *
-	 * While rx path is re-routed to the power detector we also
-	 * start a noise floor calibration, to measure the
-	 * card's noise floor (the noise we measure when we are not
-	 * transmiting or receiving anything).
-	 *
-	 * If we are in a noisy environment AGC calibration may time
-	 * out and/or noise floor calibration might timeout.
-	 */
-	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
-				AR5K_PHY_AGCCTL_CAL);
-
-	/* At the same time start I/Q calibration for QAM constellation
-	 * -no need for CCK- */
-	ah->ah_calibration = 0;
-	if (!(mode == AR5K_MODE_11B)) {
-		ah->ah_calibration = 1;
-		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
-				AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
-		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
-				AR5K_PHY_IQ_RUN);
-	}
-
-	/* Wait for gain calibration to finish (we check for I/Q calibration
-	 * during ath5k_phy_calibrate) */
-	if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
-			AR5K_PHY_AGCCTL_CAL, 0, 0)) {
-		DBG("ath5k: gain calibration timeout (%d MHz)\n",
-		    channel->center_freq);
-	}
-
-	/*
-	 * If we run NF calibration before AGC, it always times out.
-	 * Binary HAL starts NF and AGC calibration at the same time
-	 * and only waits for AGC to finish. Also if AGC or NF cal.
-	 * times out, reset doesn't fail on binary HAL. I believe
-	 * that's wrong because since rx path is routed to a detector,
-	 * if cal. doesn't finish we won't have RX. Sam's HAL for AR5210/5211
-	 * enables noise floor calibration after offset calibration and if noise
-	 * floor calibration fails, reset fails. I believe that's
-	 * a better approach, we just need to find a polling interval
-	 * that suits best, even if reset continues we need to make
-	 * sure that rx path is ready.
-	 */
-	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
-
-
-	/*
-	 * Configure QCUs/DCUs
-	 */
-
-	/* TODO: HW Compression support for data queues */
-	/* TODO: Burst prefetch for data queues */
-
-	/*
-	 * Reset queues and start beacon timers at the end of the reset routine
-	 * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping
-	 * Note: If we want we can assign multiple qcus on one dcu.
-	 */
-	ret = ath5k_hw_reset_tx_queue(ah);
-	if (ret) {
-		DBG("ath5k: failed to reset TX queue\n");
-		return ret;
-	}
-
-	/*
-	 * Configure DMA/Interrupts
-	 */
-
-	/*
-	 * Set Rx/Tx DMA Configuration
-	 *
-	 * Set standard DMA size (128). Note that
-	 * a DMA size of 512 causes rx overruns and tx errors
-	 * on pci-e cards (tested on 5424 but since rx overruns
-	 * also occur on 5416/5418 with madwifi we set 128
-	 * for all PCI-E cards to be safe).
-	 *
-	 * XXX: need to check 5210 for this
-	 * TODO: Check out tx triger level, it's always 64 on dumps but I
-	 * guess we can tweak it and see how it goes ;-)
-	 */
-	if (ah->ah_version != AR5K_AR5210) {
-		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
-			AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
-		AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
-			AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B);
-	}
-
-	/* Pre-enable interrupts on 5211/5212*/
-	if (ah->ah_version != AR5K_AR5210)
-		ath5k_hw_set_imr(ah, ah->ah_imr);
-
-	/*
-	 * Setup RFKill interrupt if rfkill flag is set on eeprom.
-	 * TODO: Use gpio pin and polarity infos from eeprom
-	 * TODO: Handle this in ath5k_intr because it'll result
-	 * 	 a nasty interrupt storm.
-	 */
-#if 0
-	if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) {
-		ath5k_hw_set_gpio_input(ah, 0);
-		ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0);
-		if (ah->ah_gpio[0] == 0)
-			ath5k_hw_set_gpio_intr(ah, 0, 1);
-		else
-			ath5k_hw_set_gpio_intr(ah, 0, 0);
-	}
-#endif
-
-	/*
-	 * Disable beacons and reset the register
-	 */
-	AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE |
-			AR5K_BEACON_RESET_TSF);
-
-	return 0;
-}
-
-#undef _ATH5K_RESET
diff --git a/roms/ipxe/src/drivers/net/ath5k/ath5k_rfkill.c b/roms/ipxe/src/drivers/net/ath5k/ath5k_rfkill.c
deleted file mode 100644
index 752ef70b98f0488d9633ce58f6ce8814cb9059c4..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/ath5k_rfkill.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * RFKILL support for ath5k
- *
- * Copyright (c) 2009 Tobias Doerffel <tobias.doerffel@gmail.com>
- * Lightly modified for iPXE, Sep 2008 by Joshua Oreman <oremanj@rwcr.net>
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
- *    redistribution must be conditioned upon including a substantially
- *    similar Disclaimer requirement for further binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * NO WARRANTY
- * 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 NONINFRINGEMENT, MERCHANTIBILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-FILE_LICENCE ( MIT );
-
-#include "base.h"
-
-
-static inline void ath5k_rfkill_disable(struct ath5k_softc *sc)
-{
-	DBG("ath5k: rfkill disable (gpio:%d polarity:%d)\n",
-	    sc->rf_kill.gpio, sc->rf_kill.polarity);
-	ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio);
-	ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, !sc->rf_kill.polarity);
-}
-
-
-static inline void ath5k_rfkill_enable(struct ath5k_softc *sc)
-{
-	DBG("ath5k: rfkill enable (gpio:%d polarity:%d)\n",
-	    sc->rf_kill.gpio, sc->rf_kill.polarity);
-	ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio);
-	ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, sc->rf_kill.polarity);
-}
-
-static inline void ath5k_rfkill_set_intr(struct ath5k_softc *sc, int enable)
-{
-	struct ath5k_hw *ah = sc->ah;
-	u32 curval;
-
-	ath5k_hw_set_gpio_input(ah, sc->rf_kill.gpio);
-	curval = ath5k_hw_get_gpio(ah, sc->rf_kill.gpio);
-	ath5k_hw_set_gpio_intr(ah, sc->rf_kill.gpio, enable ?
-			       !!curval : !curval);
-}
-
-static int __unused
-ath5k_is_rfkill_set(struct ath5k_softc *sc)
-{
-	/* configuring GPIO for input for some reason disables rfkill */
-	/*ath5k_hw_set_gpio_input(sc->ah, sc->rf_kill.gpio);*/
-	return (ath5k_hw_get_gpio(sc->ah, sc->rf_kill.gpio) ==
-		sc->rf_kill.polarity);
-}
-
-void
-ath5k_rfkill_hw_start(struct ath5k_hw *ah)
-{
-	struct ath5k_softc *sc = ah->ah_sc;
-
-	/* read rfkill GPIO configuration from EEPROM header */
-	sc->rf_kill.gpio = ah->ah_capabilities.cap_eeprom.ee_rfkill_pin;
-	sc->rf_kill.polarity = ah->ah_capabilities.cap_eeprom.ee_rfkill_pol;
-
-	ath5k_rfkill_disable(sc);
-
-	/* enable interrupt for rfkill switch */
-	if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header))
-		ath5k_rfkill_set_intr(sc, 1);
-}
-
-
-void
-ath5k_rfkill_hw_stop(struct ath5k_hw *ah)
-{
-	struct ath5k_softc *sc = ah->ah_sc;
-
-	/* disable interrupt for rfkill switch */
-	if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header))
-		ath5k_rfkill_set_intr(sc, 0);
-
-	/* enable RFKILL when stopping HW so Wifi LED is turned off */
-	ath5k_rfkill_enable(sc);
-}
diff --git a/roms/ipxe/src/drivers/net/ath5k/base.h b/roms/ipxe/src/drivers/net/ath5k/base.h
deleted file mode 100644
index 976a3f306c91d703a8e2cd94f2723cd6b0017628..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/base.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/*-
- * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
- * All rights reserved.
- *
- * Modified for iPXE, July 2009, by Joshua Oreman <oremanj@rwcr.net>
- * Original from Linux kernel 2.6.30.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
- *    redistribution must be conditioned upon including a substantially
- *    similar Disclaimer requirement for further binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * 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 NONINFRINGEMENT, MERCHANTIBILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- *
- */
-
-/*
- * Defintions for the Atheros Wireless LAN controller driver.
- */
-#ifndef _DEV_ATH_ATHVAR_H
-#define _DEV_ATH_ATHVAR_H
-
-FILE_LICENCE ( BSD3 );
-
-#include "ath5k.h"
-#include <ipxe/iobuf.h>
-
-#define	ATH_RXBUF	16		/* number of RX buffers */
-#define	ATH_TXBUF	16		/* number of TX buffers */
-
-struct ath5k_buf {
-	struct list_head	list;
-	unsigned int		flags;	/* rx descriptor flags */
-	struct ath5k_desc	*desc;	/* virtual addr of desc */
-	u32			daddr;	/* physical addr of desc */
-	struct io_buffer	*iob;	/* I/O buffer for buf */
-	u32			iobaddr;/* physical addr of iob data */
-};
-
-/*
- * Data transmit queue state.  One of these exists for each
- * hardware transmit queue.  Packets sent to us from above
- * are assigned to queues based on their priority.  Not all
- * devices support a complete set of hardware transmit queues.
- * For those devices the array sc_ac2q will map multiple
- * priorities to fewer hardware queues (typically all to one
- * hardware queue).
- */
-struct ath5k_txq {
-	unsigned int		qnum;	/* hardware q number */
-	u32			*link;	/* link ptr in last TX desc */
-	struct list_head	q;	/* transmit queue */
-	int			setup;
-};
-
-#if CHAN_DEBUG
-#define ATH_CHAN_MAX	(26+26+26+200+200)
-#else
-#define ATH_CHAN_MAX	(14+14+14+252+20)
-#endif
-
-/* Software Carrier, keeps track of the driver state
- * associated with an instance of a device */
-struct ath5k_softc {
-	struct pci_device	*pdev;		/* for dma mapping */
-	void			*iobase;	/* address of the device */
-	struct net80211_device	*dev;		/* IEEE 802.11 common */
-	struct ath5k_hw		*ah;		/* Atheros HW */
-	struct net80211_hw_info	*hwinfo;
-	int			curband;
-	int			irq_ena; 	/* interrupts enabled */
-
-	struct ath5k_buf	*bufptr;	/* allocated buffer ptr */
-	struct ath5k_desc	*desc;		/* TX/RX descriptors */
-	u32			desc_daddr;	/* DMA (physical) address */
-	size_t			desc_len;	/* size of TX/RX descriptors */
-	u16			cachelsz;	/* cache line size */
-
-	int			status;
-#define ATH_STAT_INVALID	0x01		/* disable hardware accesses */
-#define ATH_STAT_MRRETRY	0x02		/* multi-rate retry support */
-#define ATH_STAT_PROMISC	0x04
-#define ATH_STAT_LEDSOFT	0x08		/* enable LED gpio status */
-#define ATH_STAT_STARTED	0x10		/* opened & irqs enabled */
-
-	unsigned int		filter_flags;	/* HW flags, AR5K_RX_FILTER_* */
-	unsigned int		curmode;	/* current phy mode */
-	struct net80211_channel	*curchan;	/* current h/w channel */
-
-	enum ath5k_int		imask;		/* interrupt mask copy */
-
-	u8			bssidmask[ETH_ALEN];
-
-	unsigned int		rxbufsize;	/* rx size based on mtu */
-	struct list_head	rxbuf;		/* receive buffer */
-	u32			*rxlink;	/* link ptr in last RX desc */
-
-	struct list_head	txbuf;		/* transmit buffer */
-	unsigned int		txbuf_len;	/* buf count in txbuf list */
-	struct ath5k_txq	txq;		/* tx queue */
-
-	struct {
-		u16 gpio;
-		unsigned polarity;
-	} rf_kill;
-
-	int			last_calib_ticks;
-
-	int 			power_level;	/* Requested tx power in dbm */
-	int			assoc;		/* assocate state */
-
-	int			hw_rate;	/* Hardware tx rate code */
-	int			hw_rtscts_rate;	/* Hardware rts/cts rate code */
-};
-
-#define ath5k_hw_hasbssidmask(_ah) \
-	(ath5k_hw_get_capability(_ah, AR5K_CAP_BSSIDMASK, 0, NULL) == 0)
-#define ath5k_hw_hasveol(_ah) \
-	(ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0)
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/ath5k/desc.h b/roms/ipxe/src/drivers/net/ath5k/desc.h
deleted file mode 100644
index 6e11b0d43d6bb8359c98e933c07069f6706b2f9c..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/desc.h
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-/*
- * Internal RX/TX descriptor structures
- * (rX: reserved fields possibily used by future versions of the ar5k chipset)
- */
-
-/*
- * common hardware RX control descriptor
- */
-struct ath5k_hw_rx_ctl {
-	u32	rx_control_0; /* RX control word 0 */
-	u32	rx_control_1; /* RX control word 1 */
-} __attribute__ ((packed));
-
-/* RX control word 0 field/sflags */
-#define AR5K_DESC_RX_CTL0			0x00000000
-
-/* RX control word 1 fields/flags */
-#define AR5K_DESC_RX_CTL1_BUF_LEN		0x00000fff
-#define AR5K_DESC_RX_CTL1_INTREQ		0x00002000
-
-/*
- * common hardware RX status descriptor
- * 5210/11 and 5212 differ only in the flags defined below
- */
-struct ath5k_hw_rx_status {
-	u32	rx_status_0; /* RX status word 0 */
-	u32	rx_status_1; /* RX status word 1 */
-} __attribute__ ((packed));
-
-/* 5210/5211 */
-/* RX status word 0 fields/flags */
-#define AR5K_5210_RX_DESC_STATUS0_DATA_LEN		0x00000fff
-#define AR5K_5210_RX_DESC_STATUS0_MORE			0x00001000
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE		0x00078000
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_RATE_S	15
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL	0x07f80000
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	19
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA	0x38000000
-#define AR5K_5210_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	27
-
-/* RX status word 1 fields/flags */
-#define AR5K_5210_RX_DESC_STATUS1_DONE			0x00000001
-#define AR5K_5210_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
-#define AR5K_5210_RX_DESC_STATUS1_CRC_ERROR		0x00000004
-#define AR5K_5210_RX_DESC_STATUS1_FIFO_OVERRUN		0x00000008
-#define AR5K_5210_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000010
-#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR		0x000000e0
-#define AR5K_5210_RX_DESC_STATUS1_PHY_ERROR_S		5
-#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
-#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX		0x00007e00
-#define AR5K_5210_RX_DESC_STATUS1_KEY_INDEX_S		9
-#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x0fff8000
-#define AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	15
-#define AR5K_5210_RX_DESC_STATUS1_KEY_CACHE_MISS	0x10000000
-
-/* 5212 */
-/* RX status word 0 fields/flags */
-#define AR5K_5212_RX_DESC_STATUS0_DATA_LEN		0x00000fff
-#define AR5K_5212_RX_DESC_STATUS0_MORE			0x00001000
-#define AR5K_5212_RX_DESC_STATUS0_DECOMP_CRC_ERROR	0x00002000
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE		0x000f8000
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE_S	15
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL	0x0ff00000
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	20
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA	0xf0000000
-#define AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	28
-
-/* RX status word 1 fields/flags */
-#define AR5K_5212_RX_DESC_STATUS1_DONE			0x00000001
-#define AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
-#define AR5K_5212_RX_DESC_STATUS1_CRC_ERROR		0x00000004
-#define AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000008
-#define AR5K_5212_RX_DESC_STATUS1_PHY_ERROR		0x00000010
-#define AR5K_5212_RX_DESC_STATUS1_MIC_ERROR		0x00000020
-#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
-#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX		0x0000fe00
-#define AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_S		9
-#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x7fff0000
-#define AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	16
-#define AR5K_5212_RX_DESC_STATUS1_KEY_CACHE_MISS	0x80000000
-
-/*
- * common hardware RX error descriptor
- */
-struct ath5k_hw_rx_error {
-	u32	rx_error_0; /* RX status word 0 */
-	u32	rx_error_1; /* RX status word 1 */
-} __attribute__ ((packed));
-
-/* RX error word 0 fields/flags */
-#define AR5K_RX_DESC_ERROR0			0x00000000
-
-/* RX error word 1 fields/flags */
-#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE	0x0000ff00
-#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S	8
-
-/* PHY Error codes */
-#define AR5K_DESC_RX_PHY_ERROR_NONE		0x00
-#define AR5K_DESC_RX_PHY_ERROR_TIMING		0x20
-#define AR5K_DESC_RX_PHY_ERROR_PARITY		0x40
-#define AR5K_DESC_RX_PHY_ERROR_RATE		0x60
-#define AR5K_DESC_RX_PHY_ERROR_LENGTH		0x80
-#define AR5K_DESC_RX_PHY_ERROR_64QAM		0xa0
-#define AR5K_DESC_RX_PHY_ERROR_SERVICE		0xc0
-#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR	0xe0
-
-/*
- * 5210/5211 hardware 2-word TX control descriptor
- */
-struct ath5k_hw_2w_tx_ctl {
-	u32	tx_control_0; /* TX control word 0 */
-	u32	tx_control_1; /* TX control word 1 */
-} __attribute__ ((packed));
-
-/* TX control word 0 fields/flags */
-#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
-#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN		0x0003f000 /*[5210 ?]*/
-#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S	12
-#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE		0x003c0000
-#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S	18
-#define AR5K_2W_TX_DESC_CTL0_RTSENA		0x00400000
-#define AR5K_2W_TX_DESC_CTL0_CLRDMASK		0x01000000
-#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET	0x00800000 /*[5210]*/
-#define AR5K_2W_TX_DESC_CTL0_VEOL		0x00800000 /*[5211]*/
-#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE		0x1c000000 /*[5210]*/
-#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S	26
-#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210	0x02000000
-#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211	0x1e000000
-
-#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT			\
-		(ah->ah_version == AR5K_AR5210 ?		\
-		AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 :	\
-		AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211)
-
-#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
-#define AR5K_2W_TX_DESC_CTL0_INTREQ		0x20000000
-#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
-
-/* TX control word 1 fields/flags */
-#define AR5K_2W_TX_DESC_CTL1_BUF_LEN		0x00000fff
-#define AR5K_2W_TX_DESC_CTL1_MORE		0x00001000
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210	0x0007e000
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211	0x000fe000
-
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX				\
-			(ah->ah_version == AR5K_AR5210 ?		\
-			AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 :	\
-			AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211)
-
-#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
-#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE		0x00700000 /*[5211]*/
-#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S	20
-#define AR5K_2W_TX_DESC_CTL1_NOACK		0x00800000 /*[5211]*/
-#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION	0xfff80000 /*[5210 ?]*/
-
-/* Frame types */
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL   0x00
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM     0x04
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL   0x08
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c
-#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS     0x10
-
-/*
- * 5212 hardware 4-word TX control descriptor
- */
-struct ath5k_hw_4w_tx_ctl {
-	u32	tx_control_0; /* TX control word 0 */
-
-#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
-#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER		0x003f0000
-#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S	16
-#define AR5K_4W_TX_DESC_CTL0_RTSENA		0x00400000
-#define AR5K_4W_TX_DESC_CTL0_VEOL		0x00800000
-#define AR5K_4W_TX_DESC_CTL0_CLRDMASK		0x01000000
-#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT	0x1e000000
-#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
-#define AR5K_4W_TX_DESC_CTL0_INTREQ		0x20000000
-#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
-#define AR5K_4W_TX_DESC_CTL0_CTSENA		0x80000000
-
-	u32	tx_control_1; /* TX control word 1 */
-
-#define AR5K_4W_TX_DESC_CTL1_BUF_LEN		0x00000fff
-#define AR5K_4W_TX_DESC_CTL1_MORE		0x00001000
-#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX	0x000fe000
-#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
-#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE		0x00f00000
-#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S	20
-#define AR5K_4W_TX_DESC_CTL1_NOACK		0x01000000
-#define AR5K_4W_TX_DESC_CTL1_COMP_PROC		0x06000000
-#define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S	25
-#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN	0x18000000
-#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S	27
-#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN	0x60000000
-#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S	29
-
-	u32	tx_control_2; /* TX control word 2 */
-
-#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION		0x00007fff
-#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE	0x00008000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0		0x000f0000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S		16
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1		0x00f00000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S		20
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2		0x0f000000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S		24
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3		0xf0000000
-#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S		28
-
-	u32	tx_control_3; /* TX control word 3 */
-
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0		0x0000001f
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1		0x000003e0
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S	5
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2		0x00007c00
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S	10
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3		0x000f8000
-#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S	15
-#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE	0x01f00000
-#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S	20
-} __attribute__ ((packed));
-
-/*
- * Common TX status descriptor
- */
-struct ath5k_hw_tx_status {
-	u32	tx_status_0; /* TX status word 0 */
-	u32	tx_status_1; /* TX status word 1 */
-} __attribute__ ((packed));
-
-/* TX status word 0 fields/flags */
-#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK	0x00000001
-#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES	0x00000002
-#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN	0x00000004
-#define AR5K_DESC_TX_STATUS0_FILTERED		0x00000008
-/*???
-#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT	0x000000f0
-#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S	4
-*/
-#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT	0x000000f0
-#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S	4
-/*???
-#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT	0x00000f00
-#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S	8
-*/
-#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT	0x00000f00
-#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S	8
-#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT	0x0000f000
-#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S	12
-#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP	0xffff0000
-#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S	16
-
-/* TX status word 1 fields/flags */
-#define AR5K_DESC_TX_STATUS1_DONE		0x00000001
-#define AR5K_DESC_TX_STATUS1_SEQ_NUM		0x00001ffe
-#define AR5K_DESC_TX_STATUS1_SEQ_NUM_S		1
-#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH	0x001fe000
-#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S	13
-#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX	0x00600000
-#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S	21
-#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS	0x00800000
-#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA	0x01000000
-
-/*
- * 5210/5211 hardware TX descriptor
- */
-struct ath5k_hw_5210_tx_desc {
-	struct ath5k_hw_2w_tx_ctl	tx_ctl;
-	struct ath5k_hw_tx_status	tx_stat;
-} __attribute__ ((packed));
-
-/*
- * 5212 hardware TX descriptor
- */
-struct ath5k_hw_5212_tx_desc {
-	struct ath5k_hw_4w_tx_ctl	tx_ctl;
-	struct ath5k_hw_tx_status	tx_stat;
-} __attribute__ ((packed));
-
-/*
- * common hardware RX descriptor
- */
-struct ath5k_hw_all_rx_desc {
-	struct ath5k_hw_rx_ctl			rx_ctl;
-	union {
-		struct ath5k_hw_rx_status	rx_stat;
-		struct ath5k_hw_rx_error	rx_err;
-	} u;
-} __attribute__ ((packed));
-
-/*
- * Atheros hardware descriptor
- * This is read and written to by the hardware
- */
-struct ath5k_desc {
-	u32	ds_link;	/* physical address of the next descriptor */
-	u32	ds_data;	/* physical address of data buffer (skb) */
-
-	union {
-		struct ath5k_hw_5210_tx_desc	ds_tx5210;
-		struct ath5k_hw_5212_tx_desc	ds_tx5212;
-		struct ath5k_hw_all_rx_desc	ds_rx;
-	} ud;
-} __attribute__ ((packed));
-
-#define AR5K_RXDESC_INTREQ	0x0020
-
-#define AR5K_TXDESC_CLRDMASK	0x0001
-#define AR5K_TXDESC_NOACK	0x0002	/*[5211+]*/
-#define AR5K_TXDESC_RTSENA	0x0004
-#define AR5K_TXDESC_CTSENA	0x0008
-#define AR5K_TXDESC_INTREQ	0x0010
-#define AR5K_TXDESC_VEOL	0x0020	/*[5211+]*/
-
diff --git a/roms/ipxe/src/drivers/net/ath5k/eeprom.h b/roms/ipxe/src/drivers/net/ath5k/eeprom.h
deleted file mode 100644
index da454339390e039c0ee31c33815d5d359793e4a5..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/eeprom.h
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-/*
- * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
- */
-#define AR5K_EEPROM_MAGIC		0x003d	/* EEPROM Magic number */
-#define AR5K_EEPROM_MAGIC_VALUE		0x5aa5	/* Default - found on EEPROM */
-#define AR5K_EEPROM_MAGIC_5212		0x0000145c /* 5212 */
-#define AR5K_EEPROM_MAGIC_5211		0x0000145b /* 5211 */
-#define AR5K_EEPROM_MAGIC_5210		0x0000145a /* 5210 */
-
-#define	AR5K_EEPROM_IS_HB63		0x000b	/* Talon detect */
-
-#define AR5K_EEPROM_RFKILL		0x0f
-#define AR5K_EEPROM_RFKILL_GPIO_SEL	0x0000001c
-#define AR5K_EEPROM_RFKILL_GPIO_SEL_S	2
-#define AR5K_EEPROM_RFKILL_POLARITY	0x00000002
-#define AR5K_EEPROM_RFKILL_POLARITY_S	1
-
-#define AR5K_EEPROM_REG_DOMAIN		0x00bf	/* EEPROM regdom */
-#define AR5K_EEPROM_CHECKSUM		0x00c0	/* EEPROM checksum */
-#define AR5K_EEPROM_INFO_BASE		0x00c0	/* EEPROM header */
-#define AR5K_EEPROM_INFO_MAX		(0x400 - AR5K_EEPROM_INFO_BASE)
-#define AR5K_EEPROM_INFO_CKSUM		0xffff
-#define AR5K_EEPROM_INFO(_n)		(AR5K_EEPROM_INFO_BASE + (_n))
-
-#define AR5K_EEPROM_VERSION		AR5K_EEPROM_INFO(1)	/* EEPROM Version */
-#define AR5K_EEPROM_VERSION_3_0		0x3000	/* No idea what's going on before this version */
-#define AR5K_EEPROM_VERSION_3_1		0x3001	/* ob/db values for 2Ghz (ar5211_rfregs) */
-#define AR5K_EEPROM_VERSION_3_2		0x3002	/* different frequency representation (eeprom_bin2freq) */
-#define AR5K_EEPROM_VERSION_3_3		0x3003	/* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
-#define AR5K_EEPROM_VERSION_3_4		0x3004	/* has ee_i_gain, ee_cck_ofdm_power_delta (eeprom_read_modes) */
-#define AR5K_EEPROM_VERSION_4_0		0x4000	/* has ee_misc, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
-#define AR5K_EEPROM_VERSION_4_1		0x4001	/* has ee_margin_tx_rx (eeprom_init) */
-#define AR5K_EEPROM_VERSION_4_2		0x4002	/* has ee_cck_ofdm_gain_delta (eeprom_init) */
-#define AR5K_EEPROM_VERSION_4_3		0x4003	/* power calibration changes */
-#define AR5K_EEPROM_VERSION_4_4		0x4004
-#define AR5K_EEPROM_VERSION_4_5		0x4005
-#define AR5K_EEPROM_VERSION_4_6		0x4006	/* has ee_scaled_cck_delta */
-#define AR5K_EEPROM_VERSION_4_7		0x3007	/* 4007 ? */
-#define AR5K_EEPROM_VERSION_4_9		0x4009	/* EAR futureproofing */
-#define AR5K_EEPROM_VERSION_5_0		0x5000	/* Has 2413 PDADC calibration etc */
-#define AR5K_EEPROM_VERSION_5_1		0x5001	/* Has capability values */
-#define AR5K_EEPROM_VERSION_5_3		0x5003	/* Has spur mitigation tables */
-
-#define AR5K_EEPROM_MODE_11A		0
-#define AR5K_EEPROM_MODE_11B		1
-#define AR5K_EEPROM_MODE_11G		2
-
-#define AR5K_EEPROM_HDR			AR5K_EEPROM_INFO(2)	/* Header that contains the device caps */
-#define AR5K_EEPROM_HDR_11A(_v)		(((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
-#define AR5K_EEPROM_HDR_11B(_v)		(((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
-#define AR5K_EEPROM_HDR_11G(_v)		(((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
-#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v)	(((_v) >> 3) & 0x1)	/* Disable turbo for 2Ghz (?) */
-#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v)	(((_v) >> 4) & 0x7f)	/* Max turbo power for a/XR mode (eeprom_init) */
-#define AR5K_EEPROM_HDR_DEVICE(_v)	(((_v) >> 11) & 0x7)
-#define AR5K_EEPROM_HDR_RFKILL(_v)	(((_v) >> 14) & 0x1)	/* Device has RFKill support */
-#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v)	(((_v) >> 15) & 0x1)	/* Disable turbo for 5Ghz */
-
-#define AR5K_EEPROM_RFKILL_GPIO_SEL	0x0000001c
-#define AR5K_EEPROM_RFKILL_GPIO_SEL_S	2
-#define AR5K_EEPROM_RFKILL_POLARITY	0x00000002
-#define AR5K_EEPROM_RFKILL_POLARITY_S	1
-
-/* Newer EEPROMs are using a different offset */
-#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
-	(((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
-
-#define AR5K_EEPROM_ANT_GAIN(_v)	AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
-#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v)	((s8)(((_v) >> 8) & 0xff))
-#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v)	((s8)((_v) & 0xff))
-
-/* Misc values available since EEPROM 4.0 */
-#define AR5K_EEPROM_MISC0		AR5K_EEPROM_INFO(4)
-#define AR5K_EEPROM_EARSTART(_v)	((_v) & 0xfff)
-#define AR5K_EEPROM_HDR_XR2_DIS(_v)	(((_v) >> 12) & 0x1)
-#define AR5K_EEPROM_HDR_XR5_DIS(_v)	(((_v) >> 13) & 0x1)
-#define AR5K_EEPROM_EEMAP(_v)		(((_v) >> 14) & 0x3)
-
-#define AR5K_EEPROM_MISC1			AR5K_EEPROM_INFO(5)
-#define AR5K_EEPROM_TARGET_PWRSTART(_v)		((_v) & 0xfff)
-#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)		(((_v) >> 14) & 0x1)
-#define AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(_v)	(((_v) >> 15) & 0x1)
-
-#define AR5K_EEPROM_MISC2			AR5K_EEPROM_INFO(6)
-#define AR5K_EEPROM_EEP_FILE_VERSION(_v)	(((_v) >> 8) & 0xff)
-#define AR5K_EEPROM_EAR_FILE_VERSION(_v)	((_v) & 0xff)
-
-#define AR5K_EEPROM_MISC3		AR5K_EEPROM_INFO(7)
-#define AR5K_EEPROM_ART_BUILD_NUM(_v)	(((_v) >> 10) & 0x3f)
-#define AR5K_EEPROM_EAR_FILE_ID(_v)	((_v) & 0xff)
-
-#define AR5K_EEPROM_MISC4		AR5K_EEPROM_INFO(8)
-#define AR5K_EEPROM_CAL_DATA_START(_v)	(((_v) >> 4) & 0xfff)
-#define AR5K_EEPROM_MASK_R0(_v)		(((_v) >> 2) & 0x3)
-#define AR5K_EEPROM_MASK_R1(_v)		((_v) & 0x3)
-
-#define AR5K_EEPROM_MISC5		AR5K_EEPROM_INFO(9)
-#define AR5K_EEPROM_COMP_DIS(_v)	((_v) & 0x1)
-#define AR5K_EEPROM_AES_DIS(_v)		(((_v) >> 1) & 0x1)
-#define AR5K_EEPROM_FF_DIS(_v)		(((_v) >> 2) & 0x1)
-#define AR5K_EEPROM_BURST_DIS(_v)	(((_v) >> 3) & 0x1)
-#define AR5K_EEPROM_MAX_QCU(_v)		(((_v) >> 4) & 0xf)
-#define AR5K_EEPROM_HEAVY_CLIP_EN(_v)	(((_v) >> 8) & 0x1)
-#define AR5K_EEPROM_KEY_CACHE_SIZE(_v)	(((_v) >> 12) & 0xf)
-
-#define AR5K_EEPROM_MISC6		AR5K_EEPROM_INFO(10)
-#define AR5K_EEPROM_TX_CHAIN_DIS	((_v) & 0x8)
-#define AR5K_EEPROM_RX_CHAIN_DIS	(((_v) >> 3) & 0x8)
-#define AR5K_EEPROM_FCC_MID_EN		(((_v) >> 6) & 0x1)
-#define AR5K_EEPROM_JAP_U1EVEN_EN	(((_v) >> 7) & 0x1)
-#define AR5K_EEPROM_JAP_U2_EN		(((_v) >> 8) & 0x1)
-#define AR5K_EEPROM_JAP_U1ODD_EN	(((_v) >> 9) & 0x1)
-#define AR5K_EEPROM_JAP_11A_NEW_EN	(((_v) >> 10) & 0x1)
-
-/* calibration settings */
-#define AR5K_EEPROM_MODES_11A(_v)	AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
-#define AR5K_EEPROM_MODES_11B(_v)	AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
-#define AR5K_EEPROM_MODES_11G(_v)	AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
-#define AR5K_EEPROM_CTL(_v)		AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128)	/* Conformance test limits */
-#define AR5K_EEPROM_GROUPS_START(_v)	AR5K_EEPROM_OFF(_v, 0x0100, 0x0150)	/* Start of Groups */
-#define AR5K_EEPROM_GROUP1_OFFSET	0x0
-#define AR5K_EEPROM_GROUP2_OFFSET	0x5
-#define AR5K_EEPROM_GROUP3_OFFSET	0x37
-#define AR5K_EEPROM_GROUP4_OFFSET	0x46
-#define AR5K_EEPROM_GROUP5_OFFSET	0x55
-#define AR5K_EEPROM_GROUP6_OFFSET	0x65
-#define AR5K_EEPROM_GROUP7_OFFSET	0x69
-#define AR5K_EEPROM_GROUP8_OFFSET	0x6f
-
-#define AR5K_EEPROM_TARGET_PWR_OFF_11A(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
-								AR5K_EEPROM_GROUP5_OFFSET, 0x0000)
-#define AR5K_EEPROM_TARGET_PWR_OFF_11B(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
-								AR5K_EEPROM_GROUP6_OFFSET, 0x0010)
-#define AR5K_EEPROM_TARGET_PWR_OFF_11G(_v)	AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \
-								AR5K_EEPROM_GROUP7_OFFSET, 0x0014)
-
-/* [3.1 - 3.3] */
-#define AR5K_EEPROM_OBDB0_2GHZ		0x00ec
-#define AR5K_EEPROM_OBDB1_2GHZ		0x00ed
-
-#define AR5K_EEPROM_PROTECT		0x003f	/* EEPROM protect status */
-#define AR5K_EEPROM_PROTECT_RD_0_31	0x0001	/* Read protection bit for offsets 0x0 - 0x1f */
-#define AR5K_EEPROM_PROTECT_WR_0_31	0x0002	/* Write protection bit for offsets 0x0 - 0x1f */
-#define AR5K_EEPROM_PROTECT_RD_32_63	0x0004	/* 0x20 - 0x3f */
-#define AR5K_EEPROM_PROTECT_WR_32_63	0x0008
-#define AR5K_EEPROM_PROTECT_RD_64_127	0x0010	/* 0x40 - 0x7f */
-#define AR5K_EEPROM_PROTECT_WR_64_127	0x0020
-#define AR5K_EEPROM_PROTECT_RD_128_191	0x0040	/* 0x80 - 0xbf (regdom) */
-#define AR5K_EEPROM_PROTECT_WR_128_191	0x0080
-#define AR5K_EEPROM_PROTECT_RD_192_207	0x0100	/* 0xc0 - 0xcf */
-#define AR5K_EEPROM_PROTECT_WR_192_207	0x0200
-#define AR5K_EEPROM_PROTECT_RD_208_223	0x0400	/* 0xd0 - 0xdf */
-#define AR5K_EEPROM_PROTECT_WR_208_223	0x0800
-#define AR5K_EEPROM_PROTECT_RD_224_239	0x1000	/* 0xe0 - 0xef */
-#define AR5K_EEPROM_PROTECT_WR_224_239	0x2000
-#define AR5K_EEPROM_PROTECT_RD_240_255	0x4000	/* 0xf0 - 0xff */
-#define AR5K_EEPROM_PROTECT_WR_240_255	0x8000
-
-/* Some EEPROM defines */
-#define AR5K_EEPROM_EEP_SCALE		100
-#define AR5K_EEPROM_EEP_DELTA		10
-#define AR5K_EEPROM_N_MODES		3
-#define AR5K_EEPROM_N_5GHZ_CHAN		10
-#define AR5K_EEPROM_N_2GHZ_CHAN		3
-#define AR5K_EEPROM_N_2GHZ_CHAN_2413	4
-#define	AR5K_EEPROM_N_2GHZ_CHAN_MAX	4
-#define AR5K_EEPROM_MAX_CHAN		10
-#define AR5K_EEPROM_N_PWR_POINTS_5111	11
-#define AR5K_EEPROM_N_PCDAC		11
-#define AR5K_EEPROM_N_PHASE_CAL		5
-#define AR5K_EEPROM_N_TEST_FREQ		8
-#define AR5K_EEPROM_N_EDGES		8
-#define AR5K_EEPROM_N_INTERCEPTS	11
-#define AR5K_EEPROM_FREQ_M(_v)		AR5K_EEPROM_OFF(_v, 0x7f, 0xff)
-#define AR5K_EEPROM_PCDAC_M		0x3f
-#define AR5K_EEPROM_PCDAC_START		1
-#define AR5K_EEPROM_PCDAC_STOP		63
-#define AR5K_EEPROM_PCDAC_STEP		1
-#define AR5K_EEPROM_NON_EDGE_M		0x40
-#define AR5K_EEPROM_CHANNEL_POWER	8
-#define AR5K_EEPROM_N_OBDB		4
-#define AR5K_EEPROM_OBDB_DIS		0xffff
-#define AR5K_EEPROM_CHANNEL_DIS		0xff
-#define AR5K_EEPROM_SCALE_OC_DELTA(_x)	(((_x) * 2) / 10)
-#define AR5K_EEPROM_N_CTLS(_v)		AR5K_EEPROM_OFF(_v, 16, 32)
-#define AR5K_EEPROM_MAX_CTLS		32
-#define AR5K_EEPROM_N_PD_CURVES		4
-#define AR5K_EEPROM_N_XPD0_POINTS	4
-#define AR5K_EEPROM_N_XPD3_POINTS	3
-#define AR5K_EEPROM_N_PD_GAINS		4
-#define AR5K_EEPROM_N_PD_POINTS		5
-#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ	35
-#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ	55
-#define AR5K_EEPROM_POWER_M		0x3f
-#define AR5K_EEPROM_POWER_MIN		0
-#define AR5K_EEPROM_POWER_MAX		3150
-#define AR5K_EEPROM_POWER_STEP		50
-#define AR5K_EEPROM_POWER_TABLE_SIZE	64
-#define AR5K_EEPROM_N_POWER_LOC_11B	4
-#define AR5K_EEPROM_N_POWER_LOC_11G	6
-#define AR5K_EEPROM_I_GAIN		10
-#define AR5K_EEPROM_CCK_OFDM_DELTA	15
-#define AR5K_EEPROM_N_IQ_CAL		2
-
-#define AR5K_EEPROM_READ(_o, _v) do {			\
-	ret = ath5k_hw_eeprom_read(ah, (_o), &(_v));	\
-	if (ret)					\
-		return ret;				\
-} while (0)
-
-#define AR5K_EEPROM_READ_HDR(_o, _v)					\
-	AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v);	\
-
-enum ath5k_ant_setting {
-	AR5K_ANT_VARIABLE	= 0,	/* variable by programming */
-	AR5K_ANT_FIXED_A	= 1,	/* fixed to 11a frequencies */
-	AR5K_ANT_FIXED_B	= 2,	/* fixed to 11b frequencies */
-	AR5K_ANT_MAX		= 3,
-};
-
-enum ath5k_ctl_mode {
-	AR5K_CTL_11A = 0,
-	AR5K_CTL_11B = 1,
-	AR5K_CTL_11G = 2,
-	AR5K_CTL_TURBO = 3,
-	AR5K_CTL_TURBOG = 4,
-	AR5K_CTL_2GHT20 = 5,
-	AR5K_CTL_5GHT20 = 6,
-	AR5K_CTL_2GHT40 = 7,
-	AR5K_CTL_5GHT40 = 8,
-	AR5K_CTL_MODE_M = 15,
-};
-
-/* Default CTL ids for the 3 main reg domains.
- * Atheros only uses these by default but vendors
- * can have up to 32 different CTLs for different
- * scenarios. Note that theese values are ORed with
- * the mode id (above) so we can have up to 24 CTL
- * datasets out of these 3 main regdomains. That leaves
- * 8 ids that can be used by vendors and since 0x20 is
- * missing from HAL sources i guess this is the set of
- * custom CTLs vendors can use. */
-#define	AR5K_CTL_FCC	0x10
-#define	AR5K_CTL_CUSTOM	0x20
-#define	AR5K_CTL_ETSI	0x30
-#define	AR5K_CTL_MKK	0x40
-
-/* Indicates a CTL with only mode set and
- * no reg domain mapping, such CTLs are used
- * for world roaming domains or simply when
- * a reg domain is not set */
-#define	AR5K_CTL_NO_REGDOMAIN	0xf0
-
-/* Indicates an empty (invalid) CTL */
-#define AR5K_CTL_NO_CTL		0xff
-
-/* Per channel calibration data, used for power table setup */
-struct ath5k_chan_pcal_info_rf5111 {
-	/* Power levels in half dbm units
-	 * for one power curve. */
-	u8 pwr[AR5K_EEPROM_N_PWR_POINTS_5111];
-	/* PCDAC table steps
-	 * for the above values */
-	u8 pcdac[AR5K_EEPROM_N_PWR_POINTS_5111];
-	/* Starting PCDAC step */
-	u8 pcdac_min;
-	/* Final PCDAC step */
-	u8 pcdac_max;
-};
-
-struct ath5k_chan_pcal_info_rf5112 {
-	/* Power levels in quarter dBm units
-	 * for lower (0) and higher (3)
-	 * level curves in 0.25dB units */
-	s8 pwr_x0[AR5K_EEPROM_N_XPD0_POINTS];
-	s8 pwr_x3[AR5K_EEPROM_N_XPD3_POINTS];
-	/* PCDAC table steps
-	 * for the above values */
-	u8 pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS];
-	u8 pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS];
-};
-
-struct ath5k_chan_pcal_info_rf2413 {
-	/* Starting pwr/pddac values */
-	s8 pwr_i[AR5K_EEPROM_N_PD_GAINS];
-	u8 pddac_i[AR5K_EEPROM_N_PD_GAINS];
-	/* (pwr,pddac) points
-	 * power levels in 0.5dB units */
-	s8 pwr[AR5K_EEPROM_N_PD_GAINS]
-		[AR5K_EEPROM_N_PD_POINTS];
-	u8 pddac[AR5K_EEPROM_N_PD_GAINS]
-		[AR5K_EEPROM_N_PD_POINTS];
-};
-
-enum ath5k_powertable_type {
-	AR5K_PWRTABLE_PWR_TO_PCDAC = 0,
-	AR5K_PWRTABLE_LINEAR_PCDAC = 1,
-	AR5K_PWRTABLE_PWR_TO_PDADC = 2,
-};
-
-struct ath5k_pdgain_info {
-	u8 pd_points;
-	u8 *pd_step;
-	/* Power values are in
-	 * 0.25dB units */
-	s16 *pd_pwr;
-};
-
-struct ath5k_chan_pcal_info {
-	/* Frequency */
-	u16	freq;
-	/* Tx power boundaries */
-	s16	max_pwr;
-	s16	min_pwr;
-	union {
-		struct ath5k_chan_pcal_info_rf5111 rf5111_info;
-		struct ath5k_chan_pcal_info_rf5112 rf5112_info;
-		struct ath5k_chan_pcal_info_rf2413 rf2413_info;
-	};
-	/* Raw values used by phy code
-	 * Curves are stored in order from lower
-	 * gain to higher gain (max txpower -> min txpower) */
-	struct ath5k_pdgain_info *pd_curves;
-};
-
-/* Per rate calibration data for each mode,
- * used for rate power table setup.
- * Note: Values in 0.5dB units */
-struct ath5k_rate_pcal_info {
-	u16	freq; /* Frequency */
-	/* Power level for 6-24Mbit/s rates or
-	 * 1Mb rate */
-	u16	target_power_6to24;
-	/* Power level for 36Mbit rate or
-	 * 2Mb rate */
-	u16	target_power_36;
-	/* Power level for 48Mbit rate or
-	 * 5.5Mbit rate */
-	u16	target_power_48;
-	/* Power level for 54Mbit rate or
-	 * 11Mbit rate */
-	u16	target_power_54;
-};
-
-/* Power edges for conformance test limits */
-struct ath5k_edge_power {
-	u16 freq;
-	u16 edge; /* in half dBm */
-	int flag;
-};
-
-/* EEPROM calibration data */
-struct ath5k_eeprom_info {
-
-	/* Header information */
-	u16	ee_magic;
-	u16	ee_protect;
-	u16	ee_regdomain;
-	u16	ee_version;
-	u16	ee_header;
-	u16	ee_ant_gain;
-	u8	ee_rfkill_pin;
-	int	ee_rfkill_pol;
-	int	ee_is_hb63;
-	u16	ee_misc0;
-	u16	ee_misc1;
-	u16	ee_misc2;
-	u16	ee_misc3;
-	u16	ee_misc4;
-	u16	ee_misc5;
-	u16	ee_misc6;
-	u16	ee_cck_ofdm_gain_delta;
-	u16	ee_cck_ofdm_power_delta;
-	u16	ee_scaled_cck_delta;
-
-	/* RF Calibration settings (reset, rfregs) */
-	u16	ee_i_cal[AR5K_EEPROM_N_MODES];
-	u16	ee_q_cal[AR5K_EEPROM_N_MODES];
-	u16	ee_fixed_bias[AR5K_EEPROM_N_MODES];
-	u16	ee_turbo_max_power[AR5K_EEPROM_N_MODES];
-	u16	ee_xr_power[AR5K_EEPROM_N_MODES];
-	u16	ee_switch_settling[AR5K_EEPROM_N_MODES];
-	u16	ee_atn_tx_rx[AR5K_EEPROM_N_MODES];
-	u16	ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
-	u16	ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
-	u16	ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
-	u16	ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES];
-	u16	ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES];
-	u16	ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES];
-	u16	ee_thr_62[AR5K_EEPROM_N_MODES];
-	u16	ee_xlna_gain[AR5K_EEPROM_N_MODES];
-	u16	ee_xpd[AR5K_EEPROM_N_MODES];
-	u16	ee_x_gain[AR5K_EEPROM_N_MODES];
-	u16	ee_i_gain[AR5K_EEPROM_N_MODES];
-	u16	ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
-	u16	ee_switch_settling_turbo[AR5K_EEPROM_N_MODES];
-	u16	ee_margin_tx_rx_turbo[AR5K_EEPROM_N_MODES];
-	u16	ee_atn_tx_rx_turbo[AR5K_EEPROM_N_MODES];
-
-	/* Power calibration data */
-	u16	ee_false_detect[AR5K_EEPROM_N_MODES];
-
-	/* Number of pd gain curves per mode */
-	u8	ee_pd_gains[AR5K_EEPROM_N_MODES];
-	/* Back mapping pdcurve number -> pdcurve index in pd->pd_curves */
-	u8	ee_pdc_to_idx[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PD_GAINS];
-
-	u8	ee_n_piers[AR5K_EEPROM_N_MODES];
-	struct ath5k_chan_pcal_info	ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN];
-	struct ath5k_chan_pcal_info	ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
-	struct ath5k_chan_pcal_info	ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
-
-	/* Per rate target power levels */
-	u8	ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES];
-	struct ath5k_rate_pcal_info	ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN];
-	struct ath5k_rate_pcal_info	ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
-	struct ath5k_rate_pcal_info	ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN_MAX];
-
-	/* Conformance test limits (Unused) */
-	u8	ee_ctls;
-	u8	ee_ctl[AR5K_EEPROM_MAX_CTLS];
-	struct ath5k_edge_power ee_ctl_pwr[AR5K_EEPROM_N_EDGES * AR5K_EEPROM_MAX_CTLS];
-
-	/* Noise Floor Calibration settings */
-	s16	ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
-	s8	ee_adc_desired_size[AR5K_EEPROM_N_MODES];
-	s8	ee_pga_desired_size[AR5K_EEPROM_N_MODES];
-	s8	ee_adc_desired_size_turbo[AR5K_EEPROM_N_MODES];
-	s8	ee_pga_desired_size_turbo[AR5K_EEPROM_N_MODES];
-	s8	ee_pd_gain_overlap;
-
-	u32	ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
-};
-
diff --git a/roms/ipxe/src/drivers/net/ath5k/reg.h b/roms/ipxe/src/drivers/net/ath5k/reg.h
deleted file mode 100644
index 7070d1543cdc54359107b72ffe7032dbe16cf327..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/reg.h
+++ /dev/null
@@ -1,2589 +0,0 @@
-/*
- * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
- * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2007-2008 Michael Taylor <mike.taylor@apprion.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-/*
- * Register values for Atheros 5210/5211/5212 cards from OpenBSD's ar5k
- * maintained by Reyk Floeter
- *
- * I tried to document those registers by looking at ar5k code, some
- * 802.11 (802.11e mostly) papers and by reading various public available
- * Atheros presentations and papers like these:
- *
- * 5210 - http://nova.stanford.edu/~bbaas/ps/isscc2002_slides.pdf
- *        http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf
- *
- * 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf
- *
- * This file also contains register values found on a memory dump of
- * Atheros's ART program (Atheros Radio Test), on ath9k, on legacy-hal
- * released by Atheros and on various debug messages found on the net.
- */
-
-
-
-/*====MAC DMA REGISTERS====*/
-
-/*
- * AR5210-Specific TXDP registers
- * 5210 has only 2 transmit queues so no DCU/QCU, just
- * 2 transmit descriptor pointers...
- */
-#define AR5K_NOQCU_TXDP0	0x0000		/* Queue 0 - data */
-#define AR5K_NOQCU_TXDP1	0x0004		/* Queue 1 - beacons */
-
-/*
- * Mac Control Register
- */
-#define	AR5K_CR		0x0008			/* Register Address */
-#define AR5K_CR_TXE0	0x00000001	/* TX Enable for queue 0 on 5210 */
-#define AR5K_CR_TXE1	0x00000002	/* TX Enable for queue 1 on 5210 */
-#define	AR5K_CR_RXE	0x00000004	/* RX Enable */
-#define AR5K_CR_TXD0	0x00000008	/* TX Disable for queue 0 on 5210 */
-#define AR5K_CR_TXD1	0x00000010	/* TX Disable for queue 1 on 5210 */
-#define	AR5K_CR_RXD	0x00000020	/* RX Disable */
-#define	AR5K_CR_SWI	0x00000040	/* Software Interrupt */
-
-/*
- * RX Descriptor Pointer register
- */
-#define	AR5K_RXDP	0x000c
-
-/*
- * Configuration and status register
- */
-#define	AR5K_CFG		0x0014			/* Register Address */
-#define	AR5K_CFG_SWTD		0x00000001	/* Byte-swap TX descriptor (for big endian archs) */
-#define	AR5K_CFG_SWTB		0x00000002	/* Byte-swap TX buffer */
-#define	AR5K_CFG_SWRD		0x00000004	/* Byte-swap RX descriptor */
-#define	AR5K_CFG_SWRB		0x00000008	/* Byte-swap RX buffer */
-#define	AR5K_CFG_SWRG		0x00000010	/* Byte-swap Register access */
-#define AR5K_CFG_IBSS		0x00000020 	/* 0-BSS, 1-IBSS [5211+] */
-#define AR5K_CFG_PHY_OK		0x00000100	/* [5211+] */
-#define AR5K_CFG_EEBS		0x00000200	/* EEPROM is busy */
-#define	AR5K_CFG_CLKGD		0x00000400	/* Clock gated (Disable dynamic clock) */
-#define AR5K_CFG_TXCNT		0x00007800	/* Tx frame count (?) [5210] */
-#define AR5K_CFG_TXCNT_S	11
-#define AR5K_CFG_TXFSTAT	0x00008000	/* Tx frame status (?) [5210] */
-#define AR5K_CFG_TXFSTRT	0x00010000	/* [5210] */
-#define	AR5K_CFG_PCI_THRES	0x00060000	/* PCI Master req q threshold [5211+] */
-#define	AR5K_CFG_PCI_THRES_S	17
-
-/*
- * Interrupt enable register
- */
-#define AR5K_IER		0x0024		/* Register Address */
-#define AR5K_IER_DISABLE	0x00000000	/* Disable card interrupts */
-#define AR5K_IER_ENABLE		0x00000001	/* Enable card interrupts */
-
-
-/*
- * 0x0028 is Beacon Control Register on 5210
- * and first RTS duration register on 5211
- */
-
-/*
- * Beacon control register [5210]
- */
-#define AR5K_BCR		0x0028		/* Register Address */
-#define AR5K_BCR_AP		0x00000000	/* AP mode */
-#define AR5K_BCR_ADHOC		0x00000001	/* Ad-Hoc mode */
-#define AR5K_BCR_BDMAE		0x00000002	/* DMA enable */
-#define AR5K_BCR_TQ1FV		0x00000004	/* Use Queue1 for CAB traffic */
-#define AR5K_BCR_TQ1V		0x00000008	/* Use Queue1 for Beacon traffic */
-#define AR5K_BCR_BCGET		0x00000010
-
-/*
- * First RTS duration register [5211]
- */
-#define AR5K_RTSD0		0x0028		/* Register Address */
-#define	AR5K_RTSD0_6		0x000000ff	/* 6Mb RTS duration mask (?) */
-#define	AR5K_RTSD0_6_S		0		/* 6Mb RTS duration shift (?) */
-#define	AR5K_RTSD0_9		0x0000ff00	/* 9Mb*/
-#define	AR5K_RTSD0_9_S		8
-#define	AR5K_RTSD0_12		0x00ff0000	/* 12Mb*/
-#define	AR5K_RTSD0_12_S		16
-#define	AR5K_RTSD0_18		0xff000000	/* 16Mb*/
-#define	AR5K_RTSD0_18_S		24
-
-
-/*
- * 0x002c is Beacon Status Register on 5210
- * and second RTS duration register on 5211
- */
-
-/*
- * Beacon status register [5210]
- *
- * As i can see in ar5k_ar5210_tx_start Reyk uses some of the values of BCR
- * for this register, so i guess TQ1V,TQ1FV and BDMAE have the same meaning
- * here and SNP/SNAP means "snapshot" (so this register gets synced with BCR).
- * So SNAPPEDBCRVALID sould also stand for "snapped BCR -values- valid", so i
- * renamed it to SNAPSHOTSVALID to make more sense. I realy have no idea what
- * else can it be. I also renamed SNPBCMD to SNPADHOC to match BCR.
- */
-#define AR5K_BSR		0x002c			/* Register Address */
-#define AR5K_BSR_BDLYSW		0x00000001	/* SW Beacon delay (?) */
-#define AR5K_BSR_BDLYDMA	0x00000002	/* DMA Beacon delay (?) */
-#define AR5K_BSR_TXQ1F		0x00000004	/* Beacon queue (1) finished */
-#define AR5K_BSR_ATIMDLY	0x00000008	/* ATIM delay (?) */
-#define AR5K_BSR_SNPADHOC	0x00000100	/* Ad-hoc mode set (?) */
-#define AR5K_BSR_SNPBDMAE	0x00000200	/* Beacon DMA enabled (?) */
-#define AR5K_BSR_SNPTQ1FV	0x00000400	/* Queue1 is used for CAB traffic (?) */
-#define AR5K_BSR_SNPTQ1V	0x00000800	/* Queue1 is used for Beacon traffic (?) */
-#define AR5K_BSR_SNAPSHOTSVALID	0x00001000	/* BCR snapshots are valid (?) */
-#define AR5K_BSR_SWBA_CNT	0x00ff0000
-
-/*
- * Second RTS duration register [5211]
- */
-#define AR5K_RTSD1		0x002c			/* Register Address */
-#define	AR5K_RTSD1_24		0x000000ff	/* 24Mb */
-#define	AR5K_RTSD1_24_S		0
-#define	AR5K_RTSD1_36		0x0000ff00	/* 36Mb */
-#define	AR5K_RTSD1_36_S		8
-#define	AR5K_RTSD1_48		0x00ff0000	/* 48Mb */
-#define	AR5K_RTSD1_48_S		16
-#define	AR5K_RTSD1_54		0xff000000	/* 54Mb */
-#define	AR5K_RTSD1_54_S		24
-
-
-/*
- * Transmit configuration register
- */
-#define AR5K_TXCFG			0x0030			/* Register Address */
-#define AR5K_TXCFG_SDMAMR		0x00000007	/* DMA size (read) */
-#define AR5K_TXCFG_SDMAMR_S		0
-#define AR5K_TXCFG_B_MODE		0x00000008	/* Set b mode for 5111 (enable 2111) */
-#define AR5K_TXCFG_TXFSTP		0x00000008	/* TX DMA full Stop [5210] */
-#define AR5K_TXCFG_TXFULL		0x000003f0	/* TX Triger level mask */
-#define AR5K_TXCFG_TXFULL_S		4
-#define AR5K_TXCFG_TXFULL_0B		0x00000000
-#define AR5K_TXCFG_TXFULL_64B		0x00000010
-#define AR5K_TXCFG_TXFULL_128B		0x00000020
-#define AR5K_TXCFG_TXFULL_192B		0x00000030
-#define AR5K_TXCFG_TXFULL_256B		0x00000040
-#define AR5K_TXCFG_TXCONT_EN		0x00000080
-#define AR5K_TXCFG_DMASIZE		0x00000100	/* Flag for passing DMA size [5210] */
-#define AR5K_TXCFG_JUMBO_DESC_EN	0x00000400	/* Enable jumbo tx descriptors [5211+] */
-#define AR5K_TXCFG_ADHOC_BCN_ATIM	0x00000800	/* Adhoc Beacon ATIM Policy */
-#define AR5K_TXCFG_ATIM_WINDOW_DEF_DIS	0x00001000	/* Disable ATIM window defer [5211+] */
-#define AR5K_TXCFG_RTSRND		0x00001000	/* [5211+] */
-#define AR5K_TXCFG_FRMPAD_DIS		0x00002000	/* [5211+] */
-#define AR5K_TXCFG_RDY_CBR_DIS		0x00004000	/* Ready time CBR disable [5211+] */
-#define AR5K_TXCFG_JUMBO_FRM_MODE	0x00008000	/* Jumbo frame mode [5211+] */
-#define	AR5K_TXCFG_DCU_DBL_BUF_DIS	0x00008000	/* Disable double buffering on DCU */
-#define AR5K_TXCFG_DCU_CACHING_DIS	0x00010000	/* Disable DCU caching */
-
-/*
- * Receive configuration register
- */
-#define AR5K_RXCFG		0x0034			/* Register Address */
-#define AR5K_RXCFG_SDMAMW	0x00000007	/* DMA size (write) */
-#define AR5K_RXCFG_SDMAMW_S	0
-#define AR5K_RXCFG_ZLFDMA	0x00000008	/* Enable Zero-length frame DMA */
-#define	AR5K_RXCFG_DEF_ANTENNA	0x00000010	/* Default antenna (?) */
-#define AR5K_RXCFG_JUMBO_RXE	0x00000020	/* Enable jumbo rx descriptors [5211+] */
-#define AR5K_RXCFG_JUMBO_WRAP	0x00000040	/* Wrap jumbo frames [5211+] */
-#define AR5K_RXCFG_SLE_ENTRY	0x00000080	/* Sleep entry policy */
-
-/*
- * Receive jumbo descriptor last address register
- * Only found in 5211 (?)
- */
-#define AR5K_RXJLA		0x0038
-
-/*
- * MIB control register
- */
-#define AR5K_MIBC		0x0040			/* Register Address */
-#define AR5K_MIBC_COW		0x00000001	/* Warn test indicator */
-#define AR5K_MIBC_FMC		0x00000002	/* Freeze MIB Counters  */
-#define AR5K_MIBC_CMC		0x00000004	/* Clean MIB Counters  */
-#define AR5K_MIBC_MCS		0x00000008	/* MIB counter strobe */
-
-/*
- * Timeout prescale register
- */
-#define AR5K_TOPS		0x0044
-#define	AR5K_TOPS_M		0x0000ffff
-
-/*
- * Receive timeout register (no frame received)
- */
-#define AR5K_RXNOFRM		0x0048
-#define	AR5K_RXNOFRM_M		0x000003ff
-
-/*
- * Transmit timeout register (no frame sent)
- */
-#define AR5K_TXNOFRM		0x004c
-#define	AR5K_TXNOFRM_M		0x000003ff
-#define	AR5K_TXNOFRM_QCU	0x000ffc00
-#define	AR5K_TXNOFRM_QCU_S	10
-
-/*
- * Receive frame gap timeout register
- */
-#define AR5K_RPGTO		0x0050
-#define AR5K_RPGTO_M		0x000003ff
-
-/*
- * Receive frame count limit register
- */
-#define AR5K_RFCNT		0x0054
-#define AR5K_RFCNT_M		0x0000001f	/* [5211+] (?) */
-#define AR5K_RFCNT_RFCL		0x0000000f	/* [5210] */
-
-/*
- * Misc settings register
- * (reserved0-3)
- */
-#define AR5K_MISC		0x0058			/* Register Address */
-#define	AR5K_MISC_DMA_OBS_M	0x000001e0
-#define	AR5K_MISC_DMA_OBS_S	5
-#define	AR5K_MISC_MISC_OBS_M	0x00000e00
-#define	AR5K_MISC_MISC_OBS_S	9
-#define	AR5K_MISC_MAC_OBS_LSB_M	0x00007000
-#define	AR5K_MISC_MAC_OBS_LSB_S	12
-#define	AR5K_MISC_MAC_OBS_MSB_M	0x00038000
-#define	AR5K_MISC_MAC_OBS_MSB_S	15
-#define AR5K_MISC_LED_DECAY	0x001c0000	/* [5210] */
-#define AR5K_MISC_LED_BLINK	0x00e00000	/* [5210] */
-
-/*
- * QCU/DCU clock gating register (5311)
- * (reserved4-5)
- */
-#define	AR5K_QCUDCU_CLKGT	0x005c			/* Register Address (?) */
-#define	AR5K_QCUDCU_CLKGT_QCU	0x0000ffff	/* Mask for QCU clock */
-#define	AR5K_QCUDCU_CLKGT_DCU	0x07ff0000	/* Mask for DCU clock */
-
-/*
- * Interrupt Status Registers
- *
- * For 5210 there is only one status register but for
- * 5211/5212 we have one primary and 4 secondary registers.
- * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212.
- * Most of these bits are common for all chipsets.
- */
-#define AR5K_ISR		0x001c			/* Register Address [5210] */
-#define AR5K_PISR		0x0080			/* Register Address [5211+] */
-#define AR5K_ISR_RXOK		0x00000001	/* Frame successfuly recieved */
-#define AR5K_ISR_RXDESC		0x00000002	/* RX descriptor request */
-#define AR5K_ISR_RXERR		0x00000004	/* Receive error */
-#define AR5K_ISR_RXNOFRM	0x00000008	/* No frame received (receive timeout) */
-#define AR5K_ISR_RXEOL		0x00000010	/* Empty RX descriptor */
-#define AR5K_ISR_RXORN		0x00000020	/* Receive FIFO overrun */
-#define AR5K_ISR_TXOK		0x00000040	/* Frame successfuly transmited */
-#define AR5K_ISR_TXDESC		0x00000080	/* TX descriptor request */
-#define AR5K_ISR_TXERR		0x00000100	/* Transmit error */
-#define AR5K_ISR_TXNOFRM	0x00000200	/* No frame transmited (transmit timeout) */
-#define AR5K_ISR_TXEOL		0x00000400	/* Empty TX descriptor */
-#define AR5K_ISR_TXURN		0x00000800	/* Transmit FIFO underrun */
-#define AR5K_ISR_MIB		0x00001000	/* Update MIB counters */
-#define AR5K_ISR_SWI		0x00002000	/* Software interrupt */
-#define AR5K_ISR_RXPHY		0x00004000	/* PHY error */
-#define AR5K_ISR_RXKCM		0x00008000	/* RX Key cache miss */
-#define AR5K_ISR_SWBA		0x00010000	/* Software beacon alert */
-#define AR5K_ISR_BRSSI		0x00020000	/* Beacon rssi below threshold (?) */
-#define AR5K_ISR_BMISS		0x00040000	/* Beacon missed */
-#define AR5K_ISR_HIUERR		0x00080000	/* Host Interface Unit error [5211+] */
-#define AR5K_ISR_BNR		0x00100000 	/* Beacon not ready [5211+] */
-#define AR5K_ISR_MCABT		0x00100000	/* Master Cycle Abort [5210] */
-#define AR5K_ISR_RXCHIRP	0x00200000	/* CHIRP Received [5212+] */
-#define AR5K_ISR_SSERR		0x00200000	/* Signaled System Error [5210] */
-#define AR5K_ISR_DPERR		0x00400000	/* Det par Error (?) [5210] */
-#define AR5K_ISR_RXDOPPLER	0x00400000	/* Doppler chirp received [5212+] */
-#define AR5K_ISR_TIM		0x00800000	/* [5211+] */
-#define AR5K_ISR_BCNMISC	0x00800000	/* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT,
-						CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */
-#define AR5K_ISR_GPIO		0x01000000	/* GPIO (rf kill) */
-#define AR5K_ISR_QCBRORN	0x02000000	/* QCU CBR overrun [5211+] */
-#define AR5K_ISR_QCBRURN	0x04000000	/* QCU CBR underrun [5211+] */
-#define AR5K_ISR_QTRIG		0x08000000	/* QCU scheduling trigger [5211+] */
-
-/*
- * Secondary status registers [5211+] (0 - 4)
- *
- * These give the status for each QCU, only QCUs 0-9 are
- * represented.
- */
-#define AR5K_SISR0		0x0084			/* Register Address [5211+] */
-#define AR5K_SISR0_QCU_TXOK	0x000003ff	/* Mask for QCU_TXOK */
-#define AR5K_SISR0_QCU_TXOK_S	0
-#define AR5K_SISR0_QCU_TXDESC	0x03ff0000	/* Mask for QCU_TXDESC */
-#define AR5K_SISR0_QCU_TXDESC_S	16
-
-#define AR5K_SISR1		0x0088			/* Register Address [5211+] */
-#define AR5K_SISR1_QCU_TXERR	0x000003ff	/* Mask for QCU_TXERR */
-#define AR5K_SISR1_QCU_TXERR_S	0
-#define AR5K_SISR1_QCU_TXEOL	0x03ff0000	/* Mask for QCU_TXEOL */
-#define AR5K_SISR1_QCU_TXEOL_S	16
-
-#define AR5K_SISR2		0x008c			/* Register Address [5211+] */
-#define AR5K_SISR2_QCU_TXURN	0x000003ff	/* Mask for QCU_TXURN */
-#define	AR5K_SISR2_QCU_TXURN_S	0
-#define	AR5K_SISR2_MCABT	0x00100000	/* Master Cycle Abort */
-#define	AR5K_SISR2_SSERR	0x00200000	/* Signaled System Error */
-#define	AR5K_SISR2_DPERR	0x00400000	/* Bus parity error */
-#define	AR5K_SISR2_TIM		0x01000000	/* [5212+] */
-#define	AR5K_SISR2_CAB_END	0x02000000	/* [5212+] */
-#define	AR5K_SISR2_DTIM_SYNC	0x04000000	/* DTIM sync lost [5212+] */
-#define	AR5K_SISR2_BCN_TIMEOUT	0x08000000	/* Beacon Timeout [5212+] */
-#define	AR5K_SISR2_CAB_TIMEOUT	0x10000000	/* CAB Timeout [5212+] */
-#define	AR5K_SISR2_DTIM		0x20000000	/* [5212+] */
-#define	AR5K_SISR2_TSFOOR	0x80000000	/* TSF OOR (?) */
-
-#define AR5K_SISR3		0x0090			/* Register Address [5211+] */
-#define AR5K_SISR3_QCBRORN	0x000003ff	/* Mask for QCBRORN */
-#define AR5K_SISR3_QCBRORN_S	0
-#define AR5K_SISR3_QCBRURN	0x03ff0000	/* Mask for QCBRURN */
-#define AR5K_SISR3_QCBRURN_S	16
-
-#define AR5K_SISR4		0x0094			/* Register Address [5211+] */
-#define AR5K_SISR4_QTRIG	0x000003ff	/* Mask for QTRIG */
-#define AR5K_SISR4_QTRIG_S	0
-
-/*
- * Shadow read-and-clear interrupt status registers [5211+]
- */
-#define AR5K_RAC_PISR		0x00c0		/* Read and clear PISR */
-#define AR5K_RAC_SISR0		0x00c4		/* Read and clear SISR0 */
-#define AR5K_RAC_SISR1		0x00c8		/* Read and clear SISR1 */
-#define AR5K_RAC_SISR2		0x00cc		/* Read and clear SISR2 */
-#define AR5K_RAC_SISR3		0x00d0		/* Read and clear SISR3 */
-#define AR5K_RAC_SISR4		0x00d4		/* Read and clear SISR4 */
-
-/*
- * Interrupt Mask Registers
- *
- * As whith ISRs 5210 has one IMR (AR5K_IMR) and 5211/5212 has one primary
- * (AR5K_PIMR) and 4 secondary IMRs (AR5K_SIMRx). Note that ISR/IMR flags match.
- */
-#define	AR5K_IMR		0x0020			/* Register Address [5210] */
-#define AR5K_PIMR		0x00a0			/* Register Address [5211+] */
-#define AR5K_IMR_RXOK		0x00000001	/* Frame successfuly recieved*/
-#define AR5K_IMR_RXDESC		0x00000002	/* RX descriptor request*/
-#define AR5K_IMR_RXERR		0x00000004	/* Receive error*/
-#define AR5K_IMR_RXNOFRM	0x00000008	/* No frame received (receive timeout)*/
-#define AR5K_IMR_RXEOL		0x00000010	/* Empty RX descriptor*/
-#define AR5K_IMR_RXORN		0x00000020	/* Receive FIFO overrun*/
-#define AR5K_IMR_TXOK		0x00000040	/* Frame successfuly transmited*/
-#define AR5K_IMR_TXDESC		0x00000080	/* TX descriptor request*/
-#define AR5K_IMR_TXERR		0x00000100	/* Transmit error*/
-#define AR5K_IMR_TXNOFRM	0x00000200	/* No frame transmited (transmit timeout)*/
-#define AR5K_IMR_TXEOL		0x00000400	/* Empty TX descriptor*/
-#define AR5K_IMR_TXURN		0x00000800	/* Transmit FIFO underrun*/
-#define AR5K_IMR_MIB		0x00001000	/* Update MIB counters*/
-#define AR5K_IMR_SWI		0x00002000	/* Software interrupt */
-#define AR5K_IMR_RXPHY		0x00004000	/* PHY error*/
-#define AR5K_IMR_RXKCM		0x00008000	/* RX Key cache miss */
-#define AR5K_IMR_SWBA		0x00010000	/* Software beacon alert*/
-#define AR5K_IMR_BRSSI		0x00020000	/* Beacon rssi below threshold (?) */
-#define AR5K_IMR_BMISS		0x00040000	/* Beacon missed*/
-#define AR5K_IMR_HIUERR		0x00080000	/* Host Interface Unit error [5211+] */
-#define AR5K_IMR_BNR		0x00100000 	/* Beacon not ready [5211+] */
-#define AR5K_IMR_MCABT		0x00100000	/* Master Cycle Abort [5210] */
-#define AR5K_IMR_RXCHIRP	0x00200000	/* CHIRP Received [5212+]*/
-#define AR5K_IMR_SSERR		0x00200000	/* Signaled System Error [5210] */
-#define AR5K_IMR_DPERR		0x00400000	/* Det par Error (?) [5210] */
-#define AR5K_IMR_RXDOPPLER	0x00400000	/* Doppler chirp received [5212+] */
-#define AR5K_IMR_TIM		0x00800000	/* [5211+] */
-#define AR5K_IMR_BCNMISC	0x00800000	/* 'or' of TIM, CAB_END, DTIM_SYNC, BCN_TIMEOUT,
-						CAB_TIMEOUT and DTIM bits from SISR2 [5212+] */
-#define AR5K_IMR_GPIO		0x01000000	/* GPIO (rf kill)*/
-#define AR5K_IMR_QCBRORN	0x02000000	/* QCU CBR overrun (?) [5211+] */
-#define AR5K_IMR_QCBRURN	0x04000000	/* QCU CBR underrun (?) [5211+] */
-#define AR5K_IMR_QTRIG		0x08000000	/* QCU scheduling trigger [5211+] */
-
-/*
- * Secondary interrupt mask registers [5211+] (0 - 4)
- */
-#define AR5K_SIMR0		0x00a4			/* Register Address [5211+] */
-#define AR5K_SIMR0_QCU_TXOK	0x000003ff	/* Mask for QCU_TXOK */
-#define AR5K_SIMR0_QCU_TXOK_S	0
-#define AR5K_SIMR0_QCU_TXDESC	0x03ff0000	/* Mask for QCU_TXDESC */
-#define AR5K_SIMR0_QCU_TXDESC_S	16
-
-#define AR5K_SIMR1		0x00a8			/* Register Address [5211+] */
-#define AR5K_SIMR1_QCU_TXERR	0x000003ff	/* Mask for QCU_TXERR */
-#define AR5K_SIMR1_QCU_TXERR_S	0
-#define AR5K_SIMR1_QCU_TXEOL	0x03ff0000	/* Mask for QCU_TXEOL */
-#define AR5K_SIMR1_QCU_TXEOL_S	16
-
-#define AR5K_SIMR2		0x00ac			/* Register Address [5211+] */
-#define AR5K_SIMR2_QCU_TXURN	0x000003ff	/* Mask for QCU_TXURN */
-#define AR5K_SIMR2_QCU_TXURN_S	0
-#define	AR5K_SIMR2_MCABT	0x00100000	/* Master Cycle Abort */
-#define	AR5K_SIMR2_SSERR	0x00200000	/* Signaled System Error */
-#define	AR5K_SIMR2_DPERR	0x00400000	/* Bus parity error */
-#define	AR5K_SIMR2_TIM		0x01000000	/* [5212+] */
-#define	AR5K_SIMR2_CAB_END	0x02000000	/* [5212+] */
-#define	AR5K_SIMR2_DTIM_SYNC	0x04000000	/* DTIM Sync lost [5212+] */
-#define	AR5K_SIMR2_BCN_TIMEOUT	0x08000000	/* Beacon Timeout [5212+] */
-#define	AR5K_SIMR2_CAB_TIMEOUT	0x10000000	/* CAB Timeout [5212+] */
-#define	AR5K_SIMR2_DTIM		0x20000000	/* [5212+] */
-#define	AR5K_SIMR2_TSFOOR	0x80000000	/* TSF OOR (?) */
-
-#define AR5K_SIMR3		0x00b0			/* Register Address [5211+] */
-#define AR5K_SIMR3_QCBRORN	0x000003ff	/* Mask for QCBRORN */
-#define AR5K_SIMR3_QCBRORN_S	0
-#define AR5K_SIMR3_QCBRURN	0x03ff0000	/* Mask for QCBRURN */
-#define AR5K_SIMR3_QCBRURN_S	16
-
-#define AR5K_SIMR4		0x00b4			/* Register Address [5211+] */
-#define AR5K_SIMR4_QTRIG	0x000003ff	/* Mask for QTRIG */
-#define AR5K_SIMR4_QTRIG_S	0
-
-/*
- * DMA Debug registers 0-7
- * 0xe0 - 0xfc
- */
-
-/*
- * Decompression mask registers [5212+]
- */
-#define AR5K_DCM_ADDR		0x0400		/*Decompression mask address (index) */
-#define AR5K_DCM_DATA		0x0404		/*Decompression mask data */
-
-/*
- * Wake On Wireless pattern control register [5212+]
- */
-#define	AR5K_WOW_PCFG			0x0410			/* Register Address */
-#define	AR5K_WOW_PCFG_PAT_MATCH_EN	0x00000001	/* Pattern match enable */
-#define	AR5K_WOW_PCFG_LONG_FRAME_POL	0x00000002	/* Long frame policy */
-#define	AR5K_WOW_PCFG_WOBMISS		0x00000004	/* Wake on bea(con) miss (?) */
-#define	AR5K_WOW_PCFG_PAT_0_EN		0x00000100	/* Enable pattern 0 */
-#define	AR5K_WOW_PCFG_PAT_1_EN		0x00000200	/* Enable pattern 1 */
-#define	AR5K_WOW_PCFG_PAT_2_EN		0x00000400	/* Enable pattern 2 */
-#define	AR5K_WOW_PCFG_PAT_3_EN		0x00000800	/* Enable pattern 3 */
-#define	AR5K_WOW_PCFG_PAT_4_EN		0x00001000	/* Enable pattern 4 */
-#define	AR5K_WOW_PCFG_PAT_5_EN		0x00002000	/* Enable pattern 5 */
-
-/*
- * Wake On Wireless pattern index register (?) [5212+]
- */
-#define	AR5K_WOW_PAT_IDX	0x0414
-
-/*
- * Wake On Wireless pattern data register [5212+]
- */
-#define	AR5K_WOW_PAT_DATA	0x0418			/* Register Address */
-#define	AR5K_WOW_PAT_DATA_0_3_V	0x00000001	/* Pattern 0, 3 value */
-#define	AR5K_WOW_PAT_DATA_1_4_V	0x00000100	/* Pattern 1, 4 value */
-#define	AR5K_WOW_PAT_DATA_2_5_V	0x00010000	/* Pattern 2, 5 value */
-#define	AR5K_WOW_PAT_DATA_0_3_M	0x01000000	/* Pattern 0, 3 mask */
-#define	AR5K_WOW_PAT_DATA_1_4_M	0x04000000	/* Pattern 1, 4 mask */
-#define	AR5K_WOW_PAT_DATA_2_5_M	0x10000000	/* Pattern 2, 5 mask */
-
-/*
- * Decompression configuration registers [5212+]
- */
-#define AR5K_DCCFG		0x0420			/* Register Address */
-#define AR5K_DCCFG_GLOBAL_EN	0x00000001	/* Enable decompression on all queues */
-#define AR5K_DCCFG_BYPASS_EN	0x00000002	/* Bypass decompression */
-#define AR5K_DCCFG_BCAST_EN	0x00000004	/* Enable decompression for bcast frames */
-#define AR5K_DCCFG_MCAST_EN	0x00000008	/* Enable decompression for mcast frames */
-
-/*
- * Compression configuration registers [5212+]
- */
-#define AR5K_CCFG		0x0600			/* Register Address */
-#define	AR5K_CCFG_WINDOW_SIZE	0x00000007	/* Compression window size */
-#define	AR5K_CCFG_CPC_EN	0x00000008	/* Enable performance counters */
-
-#define AR5K_CCFG_CCU		0x0604			/* Register Address */
-#define AR5K_CCFG_CCU_CUP_EN	0x00000001	/* CCU Catchup enable */
-#define AR5K_CCFG_CCU_CREDIT	0x00000002	/* CCU Credit (field) */
-#define AR5K_CCFG_CCU_CD_THRES	0x00000080	/* CCU Cyc(lic?) debt threshold (field) */
-#define AR5K_CCFG_CCU_CUP_LCNT	0x00010000	/* CCU Catchup lit(?) count */
-#define	AR5K_CCFG_CCU_INIT	0x00100200	/* Initial value during reset */
-
-/*
- * Compression performance counter registers [5212+]
- */
-#define AR5K_CPC0		0x0610		/* Compression performance counter 0 */
-#define AR5K_CPC1		0x0614		/* Compression performance counter 1*/
-#define AR5K_CPC2		0x0618		/* Compression performance counter 2 */
-#define AR5K_CPC3		0x061c		/* Compression performance counter 3 */
-#define AR5K_CPCOVF		0x0620		/* Compression performance overflow */
-
-
-/*
- * Queue control unit (QCU) registers [5211+]
- *
- * Card has 12 TX Queues but i see that only 0-9 are used (?)
- * both in binary HAL (see ah.h) and ar5k. Each queue has it's own
- * TXDP at addresses 0x0800 - 0x082c, a CBR (Constant Bit Rate)
- * configuration register (0x08c0 - 0x08ec), a ready time configuration
- * register (0x0900 - 0x092c), a misc configuration register (0x09c0 -
- * 0x09ec) and a status register (0x0a00 - 0x0a2c). We also have some
- * global registers, QCU transmit enable/disable and "one shot arm (?)"
- * set/clear, which contain status for all queues (we shift by 1 for each
- * queue). To access these registers easily we define some macros here
- * that are used inside HAL. For more infos check out *_tx_queue functs.
- */
-
-/*
- * Generic QCU Register access macros
- */
-#define	AR5K_QUEUE_REG(_r, _q)		(((_q) << 2) + _r)
-#define AR5K_QCU_GLOBAL_READ(_r, _q)	(AR5K_REG_READ(_r) & (1 << _q))
-#define AR5K_QCU_GLOBAL_WRITE(_r, _q)	AR5K_REG_WRITE(_r, (1 << _q))
-
-/*
- * QCU Transmit descriptor pointer registers
- */
-#define AR5K_QCU_TXDP_BASE	0x0800		/* Register Address - Queue0 TXDP */
-#define AR5K_QUEUE_TXDP(_q)	AR5K_QUEUE_REG(AR5K_QCU_TXDP_BASE, _q)
-
-/*
- * QCU Transmit enable register
- */
-#define AR5K_QCU_TXE		0x0840
-#define AR5K_ENABLE_QUEUE(_q)	AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXE, _q)
-#define AR5K_QUEUE_ENABLED(_q)	AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXE, _q)
-
-/*
- * QCU Transmit disable register
- */
-#define AR5K_QCU_TXD		0x0880
-#define AR5K_DISABLE_QUEUE(_q)	AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXD, _q)
-#define AR5K_QUEUE_DISABLED(_q)	AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXD, _q)
-
-/*
- * QCU Constant Bit Rate configuration registers
- */
-#define	AR5K_QCU_CBRCFG_BASE		0x08c0	/* Register Address - Queue0 CBRCFG */
-#define	AR5K_QCU_CBRCFG_INTVAL		0x00ffffff	/* CBR Interval mask */
-#define AR5K_QCU_CBRCFG_INTVAL_S	0
-#define	AR5K_QCU_CBRCFG_ORN_THRES	0xff000000	/* CBR overrun threshold mask */
-#define AR5K_QCU_CBRCFG_ORN_THRES_S	24
-#define	AR5K_QUEUE_CBRCFG(_q)		AR5K_QUEUE_REG(AR5K_QCU_CBRCFG_BASE, _q)
-
-/*
- * QCU Ready time configuration registers
- */
-#define	AR5K_QCU_RDYTIMECFG_BASE	0x0900	/* Register Address - Queue0 RDYTIMECFG */
-#define	AR5K_QCU_RDYTIMECFG_INTVAL	0x00ffffff	/* Ready time interval mask */
-#define AR5K_QCU_RDYTIMECFG_INTVAL_S	0
-#define	AR5K_QCU_RDYTIMECFG_ENABLE	0x01000000	/* Ready time enable mask */
-#define AR5K_QUEUE_RDYTIMECFG(_q)	AR5K_QUEUE_REG(AR5K_QCU_RDYTIMECFG_BASE, _q)
-
-/*
- * QCU one shot arm set registers
- */
-#define	AR5K_QCU_ONESHOTARM_SET		0x0940	/* Register Address -QCU "one shot arm set (?)" */
-#define	AR5K_QCU_ONESHOTARM_SET_M	0x0000ffff
-
-/*
- * QCU one shot arm clear registers
- */
-#define	AR5K_QCU_ONESHOTARM_CLEAR	0x0980	/* Register Address -QCU "one shot arm clear (?)" */
-#define	AR5K_QCU_ONESHOTARM_CLEAR_M	0x0000ffff
-
-/*
- * QCU misc registers
- */
-#define AR5K_QCU_MISC_BASE		0x09c0			/* Register Address -Queue0 MISC */
-#define	AR5K_QCU_MISC_FRSHED_M		0x0000000f	/* Frame sheduling mask */
-#define	AR5K_QCU_MISC_FRSHED_ASAP		0	/* ASAP */
-#define	AR5K_QCU_MISC_FRSHED_CBR		1	/* Constant Bit Rate */
-#define	AR5K_QCU_MISC_FRSHED_DBA_GT		2	/* DMA Beacon alert gated */
-#define	AR5K_QCU_MISC_FRSHED_TIM_GT		3	/* TIMT gated */
-#define	AR5K_QCU_MISC_FRSHED_BCN_SENT_GT	4	/* Beacon sent gated */
-#define	AR5K_QCU_MISC_ONESHOT_ENABLE	0x00000010	/* Oneshot enable */
-#define	AR5K_QCU_MISC_CBREXP_DIS	0x00000020	/* Disable CBR expired counter (normal queue) */
-#define	AR5K_QCU_MISC_CBREXP_BCN_DIS	0x00000040	/* Disable CBR expired counter (beacon queue) */
-#define	AR5K_QCU_MISC_BCN_ENABLE	0x00000080	/* Enable Beacon use */
-#define	AR5K_QCU_MISC_CBR_THRES_ENABLE	0x00000100	/* CBR expired threshold enabled */
-#define	AR5K_QCU_MISC_RDY_VEOL_POLICY	0x00000200	/* TXE reset when RDYTIME expired or VEOL */
-#define	AR5K_QCU_MISC_CBR_RESET_CNT	0x00000400	/* CBR threshold (counter) reset */
-#define	AR5K_QCU_MISC_DCU_EARLY		0x00000800	/* DCU early termination */
-#define AR5K_QCU_MISC_DCU_CMP_EN	0x00001000	/* Enable frame compression */
-#define AR5K_QUEUE_MISC(_q)		AR5K_QUEUE_REG(AR5K_QCU_MISC_BASE, _q)
-
-
-/*
- * QCU status registers
- */
-#define AR5K_QCU_STS_BASE	0x0a00			/* Register Address - Queue0 STS */
-#define	AR5K_QCU_STS_FRMPENDCNT	0x00000003	/* Frames pending counter */
-#define	AR5K_QCU_STS_CBREXPCNT	0x0000ff00	/* CBR expired counter */
-#define	AR5K_QUEUE_STATUS(_q)	AR5K_QUEUE_REG(AR5K_QCU_STS_BASE, _q)
-
-/*
- * QCU ready time shutdown register
- */
-#define AR5K_QCU_RDYTIMESHDN	0x0a40
-#define AR5K_QCU_RDYTIMESHDN_M	0x000003ff
-
-/*
- * QCU compression buffer base registers [5212+]
- */
-#define AR5K_QCU_CBB_SELECT	0x0b00
-#define AR5K_QCU_CBB_ADDR	0x0b04
-#define AR5K_QCU_CBB_ADDR_S	9
-
-/*
- * QCU compression buffer configuration register [5212+]
- * (buffer size)
- */
-#define AR5K_QCU_CBCFG		0x0b08
-
-
-
-/*
- * Distributed Coordination Function (DCF) control unit (DCU)
- * registers [5211+]
- *
- * These registers control the various characteristics of each queue
- * for 802.11e (WME) combatibility so they go together with
- * QCU registers in pairs. For each queue we have a QCU mask register,
- * (0x1000 - 0x102c), a local-IFS settings register (0x1040 - 0x106c),
- * a retry limit register (0x1080 - 0x10ac), a channel time register
- * (0x10c0 - 0x10ec), a misc-settings register (0x1100 - 0x112c) and
- * a sequence number register (0x1140 - 0x116c). It seems that "global"
- * registers here afect all queues (see use of DCU_GBL_IFS_SLOT in ar5k).
- * We use the same macros here for easier register access.
- *
- */
-
-/*
- * DCU QCU mask registers
- */
-#define AR5K_DCU_QCUMASK_BASE	0x1000		/* Register Address -Queue0 DCU_QCUMASK */
-#define AR5K_DCU_QCUMASK_M	0x000003ff
-#define AR5K_QUEUE_QCUMASK(_q)	AR5K_QUEUE_REG(AR5K_DCU_QCUMASK_BASE, _q)
-
-/*
- * DCU local Inter Frame Space settings register
- */
-#define AR5K_DCU_LCL_IFS_BASE		0x1040			/* Register Address -Queue0 DCU_LCL_IFS */
-#define	AR5K_DCU_LCL_IFS_CW_MIN	        0x000003ff	/* Minimum Contention Window */
-#define	AR5K_DCU_LCL_IFS_CW_MIN_S	0
-#define	AR5K_DCU_LCL_IFS_CW_MAX	        0x000ffc00	/* Maximum Contention Window */
-#define	AR5K_DCU_LCL_IFS_CW_MAX_S	10
-#define	AR5K_DCU_LCL_IFS_AIFS		0x0ff00000	/* Arbitrated Interframe Space */
-#define	AR5K_DCU_LCL_IFS_AIFS_S		20
-#define	AR5K_DCU_LCL_IFS_AIFS_MAX	0xfc		/* Anything above that can cause DCU to hang */
-#define	AR5K_QUEUE_DFS_LOCAL_IFS(_q)	AR5K_QUEUE_REG(AR5K_DCU_LCL_IFS_BASE, _q)
-
-/*
- * DCU retry limit registers
- */
-#define AR5K_DCU_RETRY_LMT_BASE		0x1080			/* Register Address -Queue0 DCU_RETRY_LMT */
-#define AR5K_DCU_RETRY_LMT_SH_RETRY	0x0000000f	/* Short retry limit mask */
-#define AR5K_DCU_RETRY_LMT_SH_RETRY_S	0
-#define AR5K_DCU_RETRY_LMT_LG_RETRY	0x000000f0	/* Long retry limit mask */
-#define AR5K_DCU_RETRY_LMT_LG_RETRY_S	4
-#define AR5K_DCU_RETRY_LMT_SSH_RETRY	0x00003f00	/* Station short retry limit mask (?) */
-#define AR5K_DCU_RETRY_LMT_SSH_RETRY_S	8
-#define AR5K_DCU_RETRY_LMT_SLG_RETRY	0x000fc000	/* Station long retry limit mask (?) */
-#define AR5K_DCU_RETRY_LMT_SLG_RETRY_S	14
-#define	AR5K_QUEUE_DFS_RETRY_LIMIT(_q)	AR5K_QUEUE_REG(AR5K_DCU_RETRY_LMT_BASE, _q)
-
-/*
- * DCU channel time registers
- */
-#define AR5K_DCU_CHAN_TIME_BASE		0x10c0			/* Register Address -Queue0 DCU_CHAN_TIME */
-#define	AR5K_DCU_CHAN_TIME_DUR		0x000fffff	/* Channel time duration */
-#define	AR5K_DCU_CHAN_TIME_DUR_S	0
-#define	AR5K_DCU_CHAN_TIME_ENABLE	0x00100000	/* Enable channel time */
-#define AR5K_QUEUE_DFS_CHANNEL_TIME(_q)	AR5K_QUEUE_REG(AR5K_DCU_CHAN_TIME_BASE, _q)
-
-/*
- * DCU misc registers [5211+]
- *
- * Note: Arbiter lockout control controls the
- * behaviour on low priority queues when we have multiple queues
- * with pending frames. Intra-frame lockout means we wait until
- * the queue's current frame transmits (with post frame backoff and bursting)
- * before we transmit anything else and global lockout means we
- * wait for the whole queue to finish before higher priority queues
- * can transmit (this is used on beacon and CAB queues).
- * No lockout means there is no special handling.
- */
-#define AR5K_DCU_MISC_BASE		0x1100			/* Register Address -Queue0 DCU_MISC */
-#define	AR5K_DCU_MISC_BACKOFF		0x0000003f	/* Mask for backoff threshold */
-#define	AR5K_DCU_MISC_ETS_RTS_POL	0x00000040	/* End of transmission series
-							station RTS/data failure count
-							reset policy (?) */
-#define AR5K_DCU_MISC_ETS_CW_POL	0x00000080	/* End of transmission series
-							CW reset policy */
-#define	AR5K_DCU_MISC_FRAG_WAIT		0x00000100	/* Wait for next fragment */
-#define AR5K_DCU_MISC_BACKOFF_FRAG	0x00000200	/* Enable backoff while bursting */
-#define	AR5K_DCU_MISC_HCFPOLL_ENABLE	0x00000800	/* CF - Poll enable */
-#define	AR5K_DCU_MISC_BACKOFF_PERSIST	0x00001000	/* Persistent backoff */
-#define	AR5K_DCU_MISC_FRMPRFTCH_ENABLE	0x00002000	/* Enable frame pre-fetch */
-#define	AR5K_DCU_MISC_VIRTCOL		0x0000c000	/* Mask for Virtual Collision (?) */
-#define	AR5K_DCU_MISC_VIRTCOL_NORMAL	0
-#define	AR5K_DCU_MISC_VIRTCOL_IGNORE	1
-#define	AR5K_DCU_MISC_BCN_ENABLE	0x00010000	/* Enable Beacon use */
-#define	AR5K_DCU_MISC_ARBLOCK_CTL	0x00060000	/* Arbiter lockout control mask */
-#define	AR5K_DCU_MISC_ARBLOCK_CTL_S	17
-#define	AR5K_DCU_MISC_ARBLOCK_CTL_NONE		0	/* No arbiter lockout */
-#define	AR5K_DCU_MISC_ARBLOCK_CTL_INTFRM	1	/* Intra-frame lockout */
-#define	AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL	2	/* Global lockout */
-#define	AR5K_DCU_MISC_ARBLOCK_IGNORE	0x00080000	/* Ignore Arbiter lockout */
-#define	AR5K_DCU_MISC_SEQ_NUM_INCR_DIS	0x00100000	/* Disable sequence number increment */
-#define	AR5K_DCU_MISC_POST_FR_BKOFF_DIS	0x00200000	/* Disable post-frame backoff */
-#define	AR5K_DCU_MISC_VIRT_COLL_POLICY	0x00400000	/* Virtual Collision cw policy */
-#define	AR5K_DCU_MISC_BLOWN_IFS_POLICY	0x00800000	/* Blown IFS policy (?) */
-#define	AR5K_DCU_MISC_SEQNUM_CTL	0x01000000	/* Sequence number control (?) */
-#define AR5K_QUEUE_DFS_MISC(_q)		AR5K_QUEUE_REG(AR5K_DCU_MISC_BASE, _q)
-
-/*
- * DCU frame sequence number registers
- */
-#define AR5K_DCU_SEQNUM_BASE		0x1140
-#define	AR5K_DCU_SEQNUM_M		0x00000fff
-#define	AR5K_QUEUE_DCU_SEQNUM(_q)	AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q)
-
-/*
- * DCU global IFS SIFS register
- */
-#define AR5K_DCU_GBL_IFS_SIFS	0x1030
-#define AR5K_DCU_GBL_IFS_SIFS_M	0x0000ffff
-
-/*
- * DCU global IFS slot interval register
- */
-#define AR5K_DCU_GBL_IFS_SLOT	0x1070
-#define AR5K_DCU_GBL_IFS_SLOT_M	0x0000ffff
-
-/*
- * DCU global IFS EIFS register
- */
-#define AR5K_DCU_GBL_IFS_EIFS	0x10b0
-#define AR5K_DCU_GBL_IFS_EIFS_M	0x0000ffff
-
-/*
- * DCU global IFS misc register
- *
- * LFSR stands for Linear Feedback Shift Register
- * and it's used for generating pseudo-random
- * number sequences.
- *
- * (If i understand corectly, random numbers are
- * used for idle sensing -multiplied with cwmin/max etc-)
- */
-#define AR5K_DCU_GBL_IFS_MISC			0x10f0			/* Register Address */
-#define	AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE	0x00000007	/* LFSR Slice Select */
-#define	AR5K_DCU_GBL_IFS_MISC_TURBO_MODE	0x00000008	/* Turbo mode */
-#define	AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC	0x000003f0	/* SIFS Duration mask */
-#define	AR5K_DCU_GBL_IFS_MISC_USEC_DUR		0x000ffc00	/* USEC Duration mask */
-#define	AR5K_DCU_GBL_IFS_MISC_USEC_DUR_S	10
-#define	AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY	0x00300000	/* DCU Arbiter delay mask */
-#define AR5K_DCU_GBL_IFS_MISC_SIFS_CNT_RST	0x00400000	/* SIFS cnt reset policy (?) */
-#define AR5K_DCU_GBL_IFS_MISC_AIFS_CNT_RST	0x00800000	/* AIFS cnt reset policy (?) */
-#define AR5K_DCU_GBL_IFS_MISC_RND_LFSR_SL_DIS	0x01000000	/* Disable random LFSR slice */
-
-/*
- * DCU frame prefetch control register
- */
-#define AR5K_DCU_FP			0x1230			/* Register Address */
-#define AR5K_DCU_FP_NOBURST_DCU_EN	0x00000001	/* Enable non-burst prefetch on DCU (?) */
-#define AR5K_DCU_FP_NOBURST_EN		0x00000010	/* Enable non-burst prefetch (?) */
-#define AR5K_DCU_FP_BURST_DCU_EN	0x00000020	/* Enable burst prefetch on DCU (?) */
-
-/*
- * DCU transmit pause control/status register
- */
-#define AR5K_DCU_TXP		0x1270			/* Register Address */
-#define	AR5K_DCU_TXP_M		0x000003ff	/* Tx pause mask */
-#define	AR5K_DCU_TXP_STATUS	0x00010000	/* Tx pause status */
-
-/*
- * DCU transmit filter table 0 (32 entries)
- * each entry contains a 32bit slice of the
- * 128bit tx filter for each DCU (4 slices per DCU)
- */
-#define AR5K_DCU_TX_FILTER_0_BASE	0x1038
-#define	AR5K_DCU_TX_FILTER_0(_n)	(AR5K_DCU_TX_FILTER_0_BASE + (_n * 64))
-
-/*
- * DCU transmit filter table 1 (16 entries)
- */
-#define AR5K_DCU_TX_FILTER_1_BASE	0x103c
-#define	AR5K_DCU_TX_FILTER_1(_n)	(AR5K_DCU_TX_FILTER_1_BASE + (_n * 64))
-
-/*
- * DCU clear transmit filter register
- */
-#define AR5K_DCU_TX_FILTER_CLR	0x143c
-
-/*
- * DCU set transmit filter register
- */
-#define AR5K_DCU_TX_FILTER_SET	0x147c
-
-/*
- * Reset control register
- */
-#define AR5K_RESET_CTL		0x4000			/* Register Address */
-#define AR5K_RESET_CTL_PCU	0x00000001	/* Protocol Control Unit reset */
-#define AR5K_RESET_CTL_DMA	0x00000002	/* DMA (Rx/Tx) reset [5210] */
-#define	AR5K_RESET_CTL_BASEBAND	0x00000002	/* Baseband reset [5211+] */
-#define AR5K_RESET_CTL_MAC	0x00000004	/* MAC reset (PCU+Baseband ?) [5210] */
-#define AR5K_RESET_CTL_PHY	0x00000008	/* PHY reset [5210] */
-#define AR5K_RESET_CTL_PCI	0x00000010	/* PCI Core reset (interrupts etc) */
-
-/*
- * Sleep control register
- */
-#define AR5K_SLEEP_CTL			0x4004			/* Register Address */
-#define AR5K_SLEEP_CTL_SLDUR		0x0000ffff	/* Sleep duration mask */
-#define AR5K_SLEEP_CTL_SLDUR_S		0
-#define AR5K_SLEEP_CTL_SLE		0x00030000	/* Sleep enable mask */
-#define AR5K_SLEEP_CTL_SLE_S		16
-#define AR5K_SLEEP_CTL_SLE_WAKE		0x00000000	/* Force chip awake */
-#define AR5K_SLEEP_CTL_SLE_SLP		0x00010000	/* Force chip sleep */
-#define AR5K_SLEEP_CTL_SLE_ALLOW	0x00020000	/* Normal sleep policy */
-#define AR5K_SLEEP_CTL_SLE_UNITS	0x00000008	/* [5211+] */
-#define AR5K_SLEEP_CTL_DUR_TIM_POL	0x00040000	/* Sleep duration timing policy */
-#define AR5K_SLEEP_CTL_DUR_WRITE_POL	0x00080000	/* Sleep duration write policy */
-#define AR5K_SLEEP_CTL_SLE_POL		0x00100000	/* Sleep policy mode */
-
-/*
- * Interrupt pending register
- */
-#define AR5K_INTPEND	0x4008
-#define AR5K_INTPEND_M	0x00000001
-
-/*
- * Sleep force register
- */
-#define AR5K_SFR	0x400c
-#define AR5K_SFR_EN	0x00000001
-
-/*
- * PCI configuration register
- * TODO: Fix LED stuff
- */
-#define AR5K_PCICFG			0x4010			/* Register Address */
-#define AR5K_PCICFG_EEAE		0x00000001	/* Eeprom access enable [5210] */
-#define AR5K_PCICFG_SLEEP_CLOCK_EN	0x00000002	/* Enable sleep clock */
-#define AR5K_PCICFG_CLKRUNEN		0x00000004	/* CLKRUN enable [5211+] */
-#define AR5K_PCICFG_EESIZE		0x00000018	/* Mask for EEPROM size [5211+] */
-#define AR5K_PCICFG_EESIZE_S		3
-#define AR5K_PCICFG_EESIZE_4K		0		/* 4K */
-#define AR5K_PCICFG_EESIZE_8K		1		/* 8K */
-#define AR5K_PCICFG_EESIZE_16K		2		/* 16K */
-#define AR5K_PCICFG_EESIZE_FAIL		3		/* Failed to get size [5211+] */
-#define AR5K_PCICFG_LED			0x00000060	/* Led status [5211+] */
-#define AR5K_PCICFG_LED_NONE		0x00000000	/* Default [5211+] */
-#define AR5K_PCICFG_LED_PEND		0x00000020	/* Scan / Auth pending */
-#define AR5K_PCICFG_LED_ASSOC		0x00000040	/* Associated */
-#define	AR5K_PCICFG_BUS_SEL		0x00000380	/* Mask for "bus select" [5211+] (?) */
-#define AR5K_PCICFG_CBEFIX_DIS		0x00000400	/* Disable CBE fix */
-#define AR5K_PCICFG_SL_INTEN		0x00000800	/* Enable interrupts when asleep */
-#define AR5K_PCICFG_LED_BCTL		0x00001000	/* Led blink (?) [5210] */
-#define AR5K_PCICFG_RETRY_FIX		0x00001000	/* Enable pci core retry fix */
-#define AR5K_PCICFG_SL_INPEN		0x00002000	/* Sleep even whith pending interrupts*/
-#define AR5K_PCICFG_SPWR_DN		0x00010000	/* Mask for power status */
-#define AR5K_PCICFG_LEDMODE		0x000e0000	/* Ledmode [5211+] */
-#define AR5K_PCICFG_LEDMODE_PROP	0x00000000	/* Blink on standard traffic [5211+] */
-#define AR5K_PCICFG_LEDMODE_PROM	0x00020000	/* Default mode (blink on any traffic) [5211+] */
-#define AR5K_PCICFG_LEDMODE_PWR		0x00040000	/* Some other blinking mode  (?) [5211+] */
-#define AR5K_PCICFG_LEDMODE_RAND	0x00060000	/* Random blinking (?) [5211+] */
-#define AR5K_PCICFG_LEDBLINK		0x00700000	/* Led blink rate */
-#define AR5K_PCICFG_LEDBLINK_S		20
-#define AR5K_PCICFG_LEDSLOW		0x00800000	/* Slowest led blink rate [5211+] */
-#define AR5K_PCICFG_LEDSTATE				\
-	(AR5K_PCICFG_LED | AR5K_PCICFG_LEDMODE |	\
-	AR5K_PCICFG_LEDBLINK | AR5K_PCICFG_LEDSLOW)
-#define	AR5K_PCICFG_SLEEP_CLOCK_RATE	0x03000000	/* Sleep clock rate */
-#define	AR5K_PCICFG_SLEEP_CLOCK_RATE_S	24
-
-/*
- * "General Purpose Input/Output" (GPIO) control register
- *
- * I'm not sure about this but after looking at the code
- * for all chipsets here is what i got.
- *
- * We have 6 GPIOs (pins), each GPIO has 4 modes (2 bits)
- * Mode 0 -> always input
- * Mode 1 -> output when GPIODO for this GPIO is set to 0
- * Mode 2 -> output when GPIODO for this GPIO is set to 1
- * Mode 3 -> always output
- *
- * For more infos check out get_gpio/set_gpio and
- * set_gpio_input/set_gpio_output functs.
- * For more infos on gpio interrupt check out set_gpio_intr.
- */
-#define AR5K_NUM_GPIO	6
-
-#define AR5K_GPIOCR		0x4014				/* Register Address */
-#define AR5K_GPIOCR_INT_ENA	0x00008000		/* Enable GPIO interrupt */
-#define AR5K_GPIOCR_INT_SELL	0x00000000		/* Generate interrupt when pin is low */
-#define AR5K_GPIOCR_INT_SELH	0x00010000		/* Generate interrupt when pin is high */
-#define AR5K_GPIOCR_IN(n)	(0 << ((n) * 2))	/* Mode 0 for pin n */
-#define AR5K_GPIOCR_OUT0(n)	(1 << ((n) * 2))	/* Mode 1 for pin n */
-#define AR5K_GPIOCR_OUT1(n)	(2 << ((n) * 2))	/* Mode 2 for pin n */
-#define AR5K_GPIOCR_OUT(n)	(3 << ((n) * 2))	/* Mode 3 for pin n */
-#define AR5K_GPIOCR_INT_SEL(n)	((n) << 12)		/* Interrupt for GPIO pin n */
-
-/*
- * "General Purpose Input/Output" (GPIO) data output register
- */
-#define AR5K_GPIODO	0x4018
-
-/*
- * "General Purpose Input/Output" (GPIO) data input register
- */
-#define AR5K_GPIODI	0x401c
-#define AR5K_GPIODI_M	0x0000002f
-
-/*
- * Silicon revision register
- */
-#define AR5K_SREV		0x4020			/* Register Address */
-#define AR5K_SREV_REV		0x0000000f	/* Mask for revision */
-#define AR5K_SREV_REV_S		0
-#define AR5K_SREV_VER		0x000000ff	/* Mask for version */
-#define AR5K_SREV_VER_S		4
-
-/*
- * TXE write posting register
- */
-#define	AR5K_TXEPOST	0x4028
-
-/*
- * QCU sleep mask
- */
-#define	AR5K_QCU_SLEEP_MASK	0x402c
-
-/* 0x4068 is compression buffer configuration
- * register on 5414 and pm configuration register
- * on 5424 and newer pci-e chips. */
-
-/*
- * Compression buffer configuration
- * register (enable/disable) [5414]
- */
-#define AR5K_5414_CBCFG		0x4068
-#define AR5K_5414_CBCFG_BUF_DIS	0x10	/* Disable buffer */
-
-/*
- * PCI-E Power managment configuration
- * and status register [5424+]
- */
-#define	AR5K_PCIE_PM_CTL		0x4068			/* Register address */
-/* Only 5424 */
-#define	AR5K_PCIE_PM_CTL_L1_WHEN_D2	0x00000001	/* enable PCIe core enter L1
-							when d2_sleep_en is asserted */
-#define	AR5K_PCIE_PM_CTL_L0_L0S_CLEAR	0x00000002	/* Clear L0 and L0S counters */
-#define	AR5K_PCIE_PM_CTL_L0_L0S_EN	0x00000004	/* Start L0 nd L0S counters */
-#define	AR5K_PCIE_PM_CTL_LDRESET_EN	0x00000008	/* Enable reset when link goes
-							down */
-/* Wake On Wireless */
-#define	AR5K_PCIE_PM_CTL_PME_EN		0x00000010	/* PME Enable */
-#define	AR5K_PCIE_PM_CTL_AUX_PWR_DET	0x00000020	/* Aux power detect */
-#define	AR5K_PCIE_PM_CTL_PME_CLEAR	0x00000040	/* Clear PME */
-#define	AR5K_PCIE_PM_CTL_PSM_D0		0x00000080
-#define	AR5K_PCIE_PM_CTL_PSM_D1		0x00000100
-#define	AR5K_PCIE_PM_CTL_PSM_D2		0x00000200
-#define	AR5K_PCIE_PM_CTL_PSM_D3		0x00000400
-
-/*
- * PCI-E Workaround enable register
- */
-#define	AR5K_PCIE_WAEN	0x407c
-
-/*
- * PCI-E Serializer/Desirializer
- * registers
- */
-#define	AR5K_PCIE_SERDES	0x4080
-#define	AR5K_PCIE_SERDES_RESET	0x4084
-
-/*====EEPROM REGISTERS====*/
-
-/*
- * EEPROM access registers
- *
- * Here we got a difference between 5210/5211-12
- * read data register for 5210 is at 0x6800 and
- * status register is at 0x6c00. There is also
- * no eeprom command register on 5210 and the
- * offsets are different.
- *
- * To read eeprom data for a specific offset:
- * 5210 - enable eeprom access (AR5K_PCICFG_EEAE)
- *        read AR5K_EEPROM_BASE +(4 * offset)
- *        check the eeprom status register
- *        and read eeprom data register.
- *
- * 5211 - write offset to AR5K_EEPROM_BASE
- * 5212   write AR5K_EEPROM_CMD_READ on AR5K_EEPROM_CMD
- *        check the eeprom status register
- *        and read eeprom data register.
- *
- * To write eeprom data for a specific offset:
- * 5210 - enable eeprom access (AR5K_PCICFG_EEAE)
- *        write data to AR5K_EEPROM_BASE +(4 * offset)
- *        check the eeprom status register
- * 5211 - write AR5K_EEPROM_CMD_RESET on AR5K_EEPROM_CMD
- * 5212   write offset to AR5K_EEPROM_BASE
- *        write data to data register
- *	  write AR5K_EEPROM_CMD_WRITE on AR5K_EEPROM_CMD
- *        check the eeprom status register
- *
- * For more infos check eeprom_* functs and the ar5k.c
- * file posted in madwifi-devel mailing list.
- * http://sourceforge.net/mailarchive/message.php?msg_id=8966525
- *
- */
-#define AR5K_EEPROM_BASE	0x6000
-
-/*
- * EEPROM data register
- */
-#define AR5K_EEPROM_DATA_5211	0x6004
-#define AR5K_EEPROM_DATA_5210	0x6800
-#define	AR5K_EEPROM_DATA	(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211)
-
-/*
- * EEPROM command register
- */
-#define AR5K_EEPROM_CMD		0x6008			/* Register Addres */
-#define AR5K_EEPROM_CMD_READ	0x00000001	/* EEPROM read */
-#define AR5K_EEPROM_CMD_WRITE	0x00000002	/* EEPROM write */
-#define AR5K_EEPROM_CMD_RESET	0x00000004	/* EEPROM reset */
-
-/*
- * EEPROM status register
- */
-#define AR5K_EEPROM_STAT_5210	0x6c00			/* Register Address [5210] */
-#define AR5K_EEPROM_STAT_5211	0x600c			/* Register Address [5211+] */
-#define	AR5K_EEPROM_STATUS	(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211)
-#define AR5K_EEPROM_STAT_RDERR	0x00000001	/* EEPROM read failed */
-#define AR5K_EEPROM_STAT_RDDONE	0x00000002	/* EEPROM read successful */
-#define AR5K_EEPROM_STAT_WRERR	0x00000004	/* EEPROM write failed */
-#define AR5K_EEPROM_STAT_WRDONE	0x00000008	/* EEPROM write successful */
-
-/*
- * EEPROM config register
- */
-#define AR5K_EEPROM_CFG			0x6010			/* Register Addres */
-#define AR5K_EEPROM_CFG_SIZE		0x00000003		/* Size determination override */
-#define AR5K_EEPROM_CFG_SIZE_AUTO	0
-#define AR5K_EEPROM_CFG_SIZE_4KBIT	1
-#define AR5K_EEPROM_CFG_SIZE_8KBIT	2
-#define AR5K_EEPROM_CFG_SIZE_16KBIT	3
-#define AR5K_EEPROM_CFG_WR_WAIT_DIS	0x00000004	/* Disable write wait */
-#define AR5K_EEPROM_CFG_CLK_RATE	0x00000018	/* Clock rate */
-#define AR5K_EEPROM_CFG_CLK_RATE_S		3
-#define AR5K_EEPROM_CFG_CLK_RATE_156KHZ	0
-#define AR5K_EEPROM_CFG_CLK_RATE_312KHZ	1
-#define AR5K_EEPROM_CFG_CLK_RATE_625KHZ	2
-#define AR5K_EEPROM_CFG_PROT_KEY	0x00ffff00      /* Protection key */
-#define AR5K_EEPROM_CFG_PROT_KEY_S	8
-#define AR5K_EEPROM_CFG_LIND_EN		0x01000000	/* Enable length indicator (?) */
-
-
-/*
- * TODO: Wake On Wireless registers
- * Range 0x7000 - 0x7ce0
- */
-
-/*
- * Protocol Control Unit (PCU) registers
- */
-/*
- * Used for checking initial register writes
- * during channel reset (see reset func)
- */
-#define AR5K_PCU_MIN	0x8000
-#define AR5K_PCU_MAX	0x8fff
-
-/*
- * First station id register (Lower 32 bits of MAC address)
- */
-#define AR5K_STA_ID0		0x8000
-#define	AR5K_STA_ID0_ARRD_L32	0xffffffff
-
-/*
- * Second station id register (Upper 16 bits of MAC address + PCU settings)
- */
-#define AR5K_STA_ID1			0x8004			/* Register Address */
-#define	AR5K_STA_ID1_ADDR_U16		0x0000ffff	/* Upper 16 bits of MAC addres */
-#define AR5K_STA_ID1_AP			0x00010000	/* Set AP mode */
-#define AR5K_STA_ID1_ADHOC		0x00020000	/* Set Ad-Hoc mode */
-#define AR5K_STA_ID1_PWR_SV		0x00040000	/* Power save reporting */
-#define AR5K_STA_ID1_NO_KEYSRCH		0x00080000	/* No key search */
-#define AR5K_STA_ID1_NO_PSPOLL		0x00100000	/* No power save polling [5210] */
-#define AR5K_STA_ID1_PCF_5211		0x00100000	/* Enable PCF on [5211+] */
-#define AR5K_STA_ID1_PCF_5210		0x00200000	/* Enable PCF on [5210]*/
-#define	AR5K_STA_ID1_PCF		(ah->ah_version == AR5K_AR5210 ? \
-					AR5K_STA_ID1_PCF_5210 : AR5K_STA_ID1_PCF_5211)
-#define AR5K_STA_ID1_DEFAULT_ANTENNA	0x00200000	/* Use default antenna */
-#define AR5K_STA_ID1_DESC_ANTENNA	0x00400000	/* Update antenna from descriptor */
-#define AR5K_STA_ID1_RTS_DEF_ANTENNA	0x00800000	/* Use default antenna for RTS */
-#define AR5K_STA_ID1_ACKCTS_6MB		0x01000000	/* Use 6Mbit/s for ACK/CTS */
-#define AR5K_STA_ID1_BASE_RATE_11B	0x02000000	/* Use 11b base rate for ACK/CTS [5211+] */
-#define AR5K_STA_ID1_SELFGEN_DEF_ANT	0x04000000	/* Use def. antenna for self generated frames */
-#define AR5K_STA_ID1_CRYPT_MIC_EN	0x08000000	/* Enable MIC */
-#define AR5K_STA_ID1_KEYSRCH_MODE	0x10000000	/* Look up key when key id != 0 */
-#define AR5K_STA_ID1_PRESERVE_SEQ_NUM	0x20000000	/* Preserve sequence number */
-#define AR5K_STA_ID1_CBCIV_ENDIAN	0x40000000	/* ??? */
-#define AR5K_STA_ID1_KEYSRCH_MCAST	0x80000000	/* Do key cache search for mcast frames */
-
-/*
- * First BSSID register (MAC address, lower 32bits)
- */
-#define AR5K_BSS_ID0	0x8008
-
-/*
- * Second BSSID register (MAC address in upper 16 bits)
- *
- * AID: Association ID
- */
-#define AR5K_BSS_ID1		0x800c
-#define AR5K_BSS_ID1_AID	0xffff0000
-#define AR5K_BSS_ID1_AID_S	16
-
-/*
- * Backoff slot time register
- */
-#define AR5K_SLOT_TIME	0x8010
-
-/*
- * ACK/CTS timeout register
- */
-#define AR5K_TIME_OUT		0x8014			/* Register Address */
-#define AR5K_TIME_OUT_ACK	0x00001fff	/* ACK timeout mask */
-#define AR5K_TIME_OUT_ACK_S	0
-#define AR5K_TIME_OUT_CTS	0x1fff0000	/* CTS timeout mask */
-#define AR5K_TIME_OUT_CTS_S	16
-
-/*
- * RSSI threshold register
- */
-#define AR5K_RSSI_THR			0x8018		/* Register Address */
-#define AR5K_RSSI_THR_M			0x000000ff	/* Mask for RSSI threshold [5211+] */
-#define AR5K_RSSI_THR_BMISS_5210	0x00000700	/* Mask for Beacon Missed threshold [5210] */
-#define AR5K_RSSI_THR_BMISS_5210_S	8
-#define AR5K_RSSI_THR_BMISS_5211	0x0000ff00	/* Mask for Beacon Missed threshold [5211+] */
-#define AR5K_RSSI_THR_BMISS_5211_S	8
-#define	AR5K_RSSI_THR_BMISS		(ah->ah_version == AR5K_AR5210 ? \
-					AR5K_RSSI_THR_BMISS_5210 : AR5K_RSSI_THR_BMISS_5211)
-#define	AR5K_RSSI_THR_BMISS_S		8
-
-/*
- * 5210 has more PCU registers because there is no QCU/DCU
- * so queue parameters are set here, this way a lot common
- * registers have different address for 5210. To make things
- * easier we define a macro based on ah->ah_version for common
- * registers with different addresses and common flags.
- */
-
-/*
- * Retry limit register
- *
- * Retry limit register for 5210 (no QCU/DCU so it's done in PCU)
- */
-#define AR5K_NODCU_RETRY_LMT		0x801c			/* Register Address */
-#define AR5K_NODCU_RETRY_LMT_SH_RETRY	0x0000000f	/* Short retry limit mask */
-#define AR5K_NODCU_RETRY_LMT_SH_RETRY_S	0
-#define AR5K_NODCU_RETRY_LMT_LG_RETRY	0x000000f0	/* Long retry mask */
-#define AR5K_NODCU_RETRY_LMT_LG_RETRY_S	4
-#define AR5K_NODCU_RETRY_LMT_SSH_RETRY	0x00003f00	/* Station short retry limit mask */
-#define AR5K_NODCU_RETRY_LMT_SSH_RETRY_S	8
-#define AR5K_NODCU_RETRY_LMT_SLG_RETRY	0x000fc000	/* Station long retry limit mask */
-#define AR5K_NODCU_RETRY_LMT_SLG_RETRY_S	14
-#define AR5K_NODCU_RETRY_LMT_CW_MIN	0x3ff00000	/* Minimum contention window mask */
-#define AR5K_NODCU_RETRY_LMT_CW_MIN_S	20
-
-/*
- * Transmit latency register
- */
-#define AR5K_USEC_5210			0x8020			/* Register Address [5210] */
-#define AR5K_USEC_5211			0x801c			/* Register Address [5211+] */
-#define AR5K_USEC			(ah->ah_version == AR5K_AR5210 ? \
-					AR5K_USEC_5210 : AR5K_USEC_5211)
-#define AR5K_USEC_1			0x0000007f	/* clock cycles for 1us */
-#define AR5K_USEC_1_S			0
-#define AR5K_USEC_32			0x00003f80	/* clock cycles for 1us while on 32Mhz clock */
-#define AR5K_USEC_32_S			7
-#define AR5K_USEC_TX_LATENCY_5211	0x007fc000
-#define AR5K_USEC_TX_LATENCY_5211_S	14
-#define AR5K_USEC_RX_LATENCY_5211	0x1f800000
-#define AR5K_USEC_RX_LATENCY_5211_S	23
-#define AR5K_USEC_TX_LATENCY_5210	0x000fc000	/* also for 5311 */
-#define AR5K_USEC_TX_LATENCY_5210_S	14
-#define AR5K_USEC_RX_LATENCY_5210	0x03f00000	/* also for 5311 */
-#define AR5K_USEC_RX_LATENCY_5210_S	20
-
-/*
- * PCU beacon control register
- */
-#define AR5K_BEACON_5210	0x8024			/*Register Address [5210] */
-#define AR5K_BEACON_5211	0x8020			/*Register Address [5211+] */
-#define AR5K_BEACON		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_BEACON_5210 : AR5K_BEACON_5211)
-#define AR5K_BEACON_PERIOD	0x0000ffff	/* Mask for beacon period */
-#define AR5K_BEACON_PERIOD_S	0
-#define AR5K_BEACON_TIM		0x007f0000	/* Mask for TIM offset */
-#define AR5K_BEACON_TIM_S	16
-#define AR5K_BEACON_ENABLE	0x00800000	/* Enable beacons */
-#define AR5K_BEACON_RESET_TSF	0x01000000	/* Force TSF reset */
-
-/*
- * CFP period register
- */
-#define AR5K_CFP_PERIOD_5210	0x8028
-#define AR5K_CFP_PERIOD_5211	0x8024
-#define AR5K_CFP_PERIOD		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_CFP_PERIOD_5210 : AR5K_CFP_PERIOD_5211)
-
-/*
- * Next beacon time register
- */
-#define AR5K_TIMER0_5210	0x802c
-#define AR5K_TIMER0_5211	0x8028
-#define AR5K_TIMER0		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_TIMER0_5210 : AR5K_TIMER0_5211)
-
-/*
- * Next DMA beacon alert register
- */
-#define AR5K_TIMER1_5210	0x8030
-#define AR5K_TIMER1_5211	0x802c
-#define AR5K_TIMER1		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_TIMER1_5210 : AR5K_TIMER1_5211)
-
-/*
- * Next software beacon alert register
- */
-#define AR5K_TIMER2_5210	0x8034
-#define AR5K_TIMER2_5211	0x8030
-#define AR5K_TIMER2		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_TIMER2_5210 : AR5K_TIMER2_5211)
-
-/*
- * Next ATIM window time register
- */
-#define AR5K_TIMER3_5210	0x8038
-#define AR5K_TIMER3_5211	0x8034
-#define AR5K_TIMER3		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_TIMER3_5210 : AR5K_TIMER3_5211)
-
-
-/*
- * 5210 First inter frame spacing register (IFS)
- */
-#define AR5K_IFS0		0x8040
-#define AR5K_IFS0_SIFS		0x000007ff
-#define AR5K_IFS0_SIFS_S	0
-#define AR5K_IFS0_DIFS		0x007ff800
-#define AR5K_IFS0_DIFS_S	11
-
-/*
- * 5210 Second inter frame spacing register (IFS)
- */
-#define AR5K_IFS1		0x8044
-#define AR5K_IFS1_PIFS		0x00000fff
-#define AR5K_IFS1_PIFS_S	0
-#define AR5K_IFS1_EIFS		0x03fff000
-#define AR5K_IFS1_EIFS_S	12
-#define AR5K_IFS1_CS_EN		0x04000000
-
-
-/*
- * CFP duration register
- */
-#define AR5K_CFP_DUR_5210	0x8048
-#define AR5K_CFP_DUR_5211	0x8038
-#define AR5K_CFP_DUR		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_CFP_DUR_5210 : AR5K_CFP_DUR_5211)
-
-/*
- * Receive filter register
- */
-#define AR5K_RX_FILTER_5210	0x804c			/* Register Address [5210] */
-#define AR5K_RX_FILTER_5211	0x803c			/* Register Address [5211+] */
-#define AR5K_RX_FILTER		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_RX_FILTER_5210 : AR5K_RX_FILTER_5211)
-#define	AR5K_RX_FILTER_UCAST 	0x00000001	/* Don't filter unicast frames */
-#define	AR5K_RX_FILTER_MCAST 	0x00000002	/* Don't filter multicast frames */
-#define	AR5K_RX_FILTER_BCAST 	0x00000004	/* Don't filter broadcast frames */
-#define	AR5K_RX_FILTER_CONTROL 	0x00000008	/* Don't filter control frames */
-#define	AR5K_RX_FILTER_BEACON 	0x00000010	/* Don't filter beacon frames */
-#define	AR5K_RX_FILTER_PROM 	0x00000020	/* Set promiscuous mode */
-#define	AR5K_RX_FILTER_XRPOLL 	0x00000040	/* Don't filter XR poll frame [5212+] */
-#define	AR5K_RX_FILTER_PROBEREQ 0x00000080	/* Don't filter probe requests [5212+] */
-#define	AR5K_RX_FILTER_PHYERR_5212	0x00000100	/* Don't filter phy errors [5212+] */
-#define	AR5K_RX_FILTER_RADARERR_5212 	0x00000200	/* Don't filter phy radar errors [5212+] */
-#define AR5K_RX_FILTER_PHYERR_5211	0x00000040	/* [5211] */
-#define AR5K_RX_FILTER_RADARERR_5211	0x00000080	/* [5211] */
-#define AR5K_RX_FILTER_PHYERR  \
-	((ah->ah_version == AR5K_AR5211 ? \
-	AR5K_RX_FILTER_PHYERR_5211 : AR5K_RX_FILTER_PHYERR_5212))
-#define        AR5K_RX_FILTER_RADARERR \
-	((ah->ah_version == AR5K_AR5211 ? \
-	AR5K_RX_FILTER_RADARERR_5211 : AR5K_RX_FILTER_RADARERR_5212))
-
-/*
- * Multicast filter register (lower 32 bits)
- */
-#define AR5K_MCAST_FILTER0_5210	0x8050
-#define AR5K_MCAST_FILTER0_5211	0x8040
-#define AR5K_MCAST_FILTER0	(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_MCAST_FILTER0_5210 : AR5K_MCAST_FILTER0_5211)
-
-/*
- * Multicast filter register (higher 16 bits)
- */
-#define AR5K_MCAST_FILTER1_5210	0x8054
-#define AR5K_MCAST_FILTER1_5211	0x8044
-#define AR5K_MCAST_FILTER1	(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_MCAST_FILTER1_5210 : AR5K_MCAST_FILTER1_5211)
-
-
-/*
- * Transmit mask register (lower 32 bits) [5210]
- */
-#define AR5K_TX_MASK0	0x8058
-
-/*
- * Transmit mask register (higher 16 bits) [5210]
- */
-#define AR5K_TX_MASK1	0x805c
-
-/*
- * Clear transmit mask [5210]
- */
-#define AR5K_CLR_TMASK	0x8060
-
-/*
- * Trigger level register (before transmission) [5210]
- */
-#define AR5K_TRIG_LVL	0x8064
-
-
-/*
- * PCU control register
- *
- * Only DIS_RX is used in the code, the rest i guess are
- * for tweaking/diagnostics.
- */
-#define AR5K_DIAG_SW_5210		0x8068			/* Register Address [5210] */
-#define AR5K_DIAG_SW_5211		0x8048			/* Register Address [5211+] */
-#define AR5K_DIAG_SW			(ah->ah_version == AR5K_AR5210 ? \
-					AR5K_DIAG_SW_5210 : AR5K_DIAG_SW_5211)
-#define AR5K_DIAG_SW_DIS_WEP_ACK	0x00000001	/* Disable ACKs if WEP key is invalid */
-#define AR5K_DIAG_SW_DIS_ACK		0x00000002	/* Disable ACKs */
-#define AR5K_DIAG_SW_DIS_CTS		0x00000004	/* Disable CTSs */
-#define AR5K_DIAG_SW_DIS_ENC		0x00000008	/* Disable encryption */
-#define AR5K_DIAG_SW_DIS_DEC		0x00000010	/* Disable decryption */
-#define AR5K_DIAG_SW_DIS_TX		0x00000020	/* Disable transmit [5210] */
-#define AR5K_DIAG_SW_DIS_RX_5210	0x00000040	/* Disable recieve */
-#define AR5K_DIAG_SW_DIS_RX_5211	0x00000020
-#define	AR5K_DIAG_SW_DIS_RX		(ah->ah_version == AR5K_AR5210 ? \
-					AR5K_DIAG_SW_DIS_RX_5210 : AR5K_DIAG_SW_DIS_RX_5211)
-#define AR5K_DIAG_SW_LOOP_BACK_5210	0x00000080	/* Loopback (i guess it goes with DIS_TX) [5210] */
-#define AR5K_DIAG_SW_LOOP_BACK_5211	0x00000040
-#define AR5K_DIAG_SW_LOOP_BACK		(ah->ah_version == AR5K_AR5210 ? \
-					AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211)
-#define AR5K_DIAG_SW_CORR_FCS_5210	0x00000100	/* Corrupted FCS */
-#define AR5K_DIAG_SW_CORR_FCS_5211	0x00000080
-#define AR5K_DIAG_SW_CORR_FCS		(ah->ah_version == AR5K_AR5210 ? \
-					AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211)
-#define AR5K_DIAG_SW_CHAN_INFO_5210	0x00000200	/* Dump channel info */
-#define AR5K_DIAG_SW_CHAN_INFO_5211	0x00000100
-#define AR5K_DIAG_SW_CHAN_INFO		(ah->ah_version == AR5K_AR5210 ? \
-					AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211)
-#define AR5K_DIAG_SW_EN_SCRAM_SEED_5210	0x00000400	/* Enable fixed scrambler seed */
-#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211	0x00000200
-#define AR5K_DIAG_SW_EN_SCRAM_SEED	(ah->ah_version == AR5K_AR5210 ? \
-					AR5K_DIAG_SW_EN_SCRAM_SEED_5210 : AR5K_DIAG_SW_EN_SCRAM_SEED_5211)
-#define AR5K_DIAG_SW_ECO_ENABLE		0x00000400	/* [5211+] */
-#define AR5K_DIAG_SW_SCVRAM_SEED	0x0003f800	/* [5210] */
-#define AR5K_DIAG_SW_SCRAM_SEED_M	0x0001fc00	/* Scrambler seed mask */
-#define AR5K_DIAG_SW_SCRAM_SEED_S	10
-#define AR5K_DIAG_SW_DIS_SEQ_INC	0x00040000	/* Disable seqnum increment (?)[5210] */
-#define AR5K_DIAG_SW_FRAME_NV0_5210	0x00080000
-#define AR5K_DIAG_SW_FRAME_NV0_5211	0x00020000	/* Accept frames of non-zero protocol number */
-#define	AR5K_DIAG_SW_FRAME_NV0		(ah->ah_version == AR5K_AR5210 ? \
-					AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211)
-#define AR5K_DIAG_SW_OBSPT_M		0x000c0000	/* Observation point select (?) */
-#define AR5K_DIAG_SW_OBSPT_S		18
-#define AR5K_DIAG_SW_RX_CLEAR_HIGH	0x0010000	/* Force RX Clear high */
-#define AR5K_DIAG_SW_IGNORE_CARR_SENSE	0x0020000	/* Ignore virtual carrier sense */
-#define AR5K_DIAG_SW_CHANEL_IDLE_HIGH	0x0040000	/* Force channel idle high */
-#define AR5K_DIAG_SW_PHEAR_ME		0x0080000	/* ??? */
-
-/*
- * TSF (clock) register (lower 32 bits)
- */
-#define AR5K_TSF_L32_5210	0x806c
-#define AR5K_TSF_L32_5211	0x804c
-#define	AR5K_TSF_L32		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211)
-
-/*
- * TSF (clock) register (higher 32 bits)
- */
-#define AR5K_TSF_U32_5210	0x8070
-#define AR5K_TSF_U32_5211	0x8050
-#define	AR5K_TSF_U32		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211)
-
-/*
- * Last beacon timestamp register (Read Only)
- */
-#define AR5K_LAST_TSTP	0x8080
-
-/*
- * ADDAC test register [5211+]
- */
-#define AR5K_ADDAC_TEST			0x8054			/* Register Address */
-#define AR5K_ADDAC_TEST_TXCONT 		0x00000001	/* Test continuous tx */
-#define AR5K_ADDAC_TEST_TST_MODE	0x00000002	/* Test mode */
-#define AR5K_ADDAC_TEST_LOOP_EN		0x00000004	/* Enable loop */
-#define AR5K_ADDAC_TEST_LOOP_LEN	0x00000008	/* Loop length (field) */
-#define AR5K_ADDAC_TEST_USE_U8		0x00004000	/* Use upper 8 bits */
-#define AR5K_ADDAC_TEST_MSB		0x00008000	/* State of MSB */
-#define AR5K_ADDAC_TEST_TRIG_SEL	0x00010000	/* Trigger select */
-#define AR5K_ADDAC_TEST_TRIG_PTY	0x00020000	/* Trigger polarity */
-#define AR5K_ADDAC_TEST_RXCONT		0x00040000	/* Continuous capture */
-#define AR5K_ADDAC_TEST_CAPTURE		0x00080000	/* Begin capture */
-#define AR5K_ADDAC_TEST_TST_ARM		0x00100000	/* ARM rx buffer for capture */
-
-/*
- * Default antenna register [5211+]
- */
-#define AR5K_DEFAULT_ANTENNA	0x8058
-
-/*
- * Frame control QoS mask register (?) [5211+]
- * (FC_QOS_MASK)
- */
-#define AR5K_FRAME_CTL_QOSM	0x805c
-
-/*
- * Seq mask register (?) [5211+]
- */
-#define AR5K_SEQ_MASK	0x8060
-
-/*
- * Retry count register [5210]
- */
-#define AR5K_RETRY_CNT		0x8084			/* Register Address [5210] */
-#define AR5K_RETRY_CNT_SSH	0x0000003f	/* Station short retry count (?) */
-#define AR5K_RETRY_CNT_SLG	0x00000fc0	/* Station long retry count (?) */
-
-/*
- * Back-off status register [5210]
- */
-#define AR5K_BACKOFF		0x8088			/* Register Address [5210] */
-#define AR5K_BACKOFF_CW		0x000003ff	/* Backoff Contention Window (?) */
-#define AR5K_BACKOFF_CNT	0x03ff0000	/* Backoff count (?) */
-
-
-
-/*
- * NAV register (current)
- */
-#define AR5K_NAV_5210		0x808c
-#define AR5K_NAV_5211		0x8084
-#define	AR5K_NAV		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_NAV_5210 : AR5K_NAV_5211)
-
-/*
- * RTS success register
- */
-#define AR5K_RTS_OK_5210	0x8090
-#define AR5K_RTS_OK_5211	0x8088
-#define	AR5K_RTS_OK		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211)
-
-/*
- * RTS failure register
- */
-#define AR5K_RTS_FAIL_5210	0x8094
-#define AR5K_RTS_FAIL_5211	0x808c
-#define	AR5K_RTS_FAIL		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211)
-
-/*
- * ACK failure register
- */
-#define AR5K_ACK_FAIL_5210	0x8098
-#define AR5K_ACK_FAIL_5211	0x8090
-#define	AR5K_ACK_FAIL		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211)
-
-/*
- * FCS failure register
- */
-#define AR5K_FCS_FAIL_5210	0x809c
-#define AR5K_FCS_FAIL_5211	0x8094
-#define	AR5K_FCS_FAIL		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_FCS_FAIL_5210 : AR5K_FCS_FAIL_5211)
-
-/*
- * Beacon count register
- */
-#define AR5K_BEACON_CNT_5210	0x80a0
-#define AR5K_BEACON_CNT_5211	0x8098
-#define	AR5K_BEACON_CNT		(ah->ah_version == AR5K_AR5210 ? \
-				AR5K_BEACON_CNT_5210 : AR5K_BEACON_CNT_5211)
-
-
-/*===5212 Specific PCU registers===*/
-
-/*
- * Transmit power control register
- */
-#define AR5K_TPC			0x80e8
-#define AR5K_TPC_ACK			0x0000003f	/* ack frames */
-#define AR5K_TPC_ACK_S			0
-#define AR5K_TPC_CTS			0x00003f00	/* cts frames */
-#define AR5K_TPC_CTS_S			8
-#define AR5K_TPC_CHIRP			0x003f0000	/* chirp frames */
-#define AR5K_TPC_CHIRP_S		16
-#define AR5K_TPC_DOPPLER		0x0f000000	/* doppler chirp span */
-#define AR5K_TPC_DOPPLER_S		24
-
-/*
- * XR (eXtended Range) mode register
- */
-#define AR5K_XRMODE			0x80c0			/* Register Address */
-#define	AR5K_XRMODE_POLL_TYPE_M		0x0000003f	/* Mask for Poll type (?) */
-#define	AR5K_XRMODE_POLL_TYPE_S		0
-#define	AR5K_XRMODE_POLL_SUBTYPE_M	0x0000003c	/* Mask for Poll subtype (?) */
-#define	AR5K_XRMODE_POLL_SUBTYPE_S	2
-#define	AR5K_XRMODE_POLL_WAIT_ALL	0x00000080	/* Wait for poll */
-#define	AR5K_XRMODE_SIFS_DELAY		0x000fff00	/* Mask for SIFS delay */
-#define	AR5K_XRMODE_FRAME_HOLD_M	0xfff00000	/* Mask for frame hold (?) */
-#define	AR5K_XRMODE_FRAME_HOLD_S	20
-
-/*
- * XR delay register
- */
-#define AR5K_XRDELAY			0x80c4			/* Register Address */
-#define AR5K_XRDELAY_SLOT_DELAY_M	0x0000ffff	/* Mask for slot delay */
-#define AR5K_XRDELAY_SLOT_DELAY_S	0
-#define AR5K_XRDELAY_CHIRP_DELAY_M	0xffff0000	/* Mask for CHIRP data delay */
-#define AR5K_XRDELAY_CHIRP_DELAY_S	16
-
-/*
- * XR timeout register
- */
-#define AR5K_XRTIMEOUT			0x80c8			/* Register Address */
-#define AR5K_XRTIMEOUT_CHIRP_M		0x0000ffff	/* Mask for CHIRP timeout */
-#define AR5K_XRTIMEOUT_CHIRP_S		0
-#define AR5K_XRTIMEOUT_POLL_M		0xffff0000	/* Mask for Poll timeout */
-#define AR5K_XRTIMEOUT_POLL_S		16
-
-/*
- * XR chirp register
- */
-#define AR5K_XRCHIRP			0x80cc			/* Register Address */
-#define AR5K_XRCHIRP_SEND		0x00000001	/* Send CHIRP */
-#define AR5K_XRCHIRP_GAP		0xffff0000	/* Mask for CHIRP gap (?) */
-
-/*
- * XR stomp register
- */
-#define AR5K_XRSTOMP			0x80d0			/* Register Address */
-#define AR5K_XRSTOMP_TX			0x00000001	/* Stomp Tx (?) */
-#define AR5K_XRSTOMP_RX			0x00000002	/* Stomp Rx (?) */
-#define AR5K_XRSTOMP_TX_RSSI		0x00000004	/* Stomp Tx RSSI (?) */
-#define AR5K_XRSTOMP_TX_BSSID		0x00000008	/* Stomp Tx BSSID (?) */
-#define AR5K_XRSTOMP_DATA		0x00000010	/* Stomp data (?)*/
-#define AR5K_XRSTOMP_RSSI_THRES		0x0000ff00	/* Mask for XR RSSI threshold */
-
-/*
- * First enhanced sleep register
- */
-#define AR5K_SLEEP0			0x80d4			/* Register Address */
-#define AR5K_SLEEP0_NEXT_DTIM		0x0007ffff	/* Mask for next DTIM (?) */
-#define AR5K_SLEEP0_NEXT_DTIM_S		0
-#define AR5K_SLEEP0_ASSUME_DTIM		0x00080000	/* Assume DTIM */
-#define AR5K_SLEEP0_ENH_SLEEP_EN	0x00100000	/* Enable enchanced sleep control */
-#define AR5K_SLEEP0_CABTO		0xff000000	/* Mask for CAB Time Out */
-#define AR5K_SLEEP0_CABTO_S		24
-
-/*
- * Second enhanced sleep register
- */
-#define AR5K_SLEEP1			0x80d8			/* Register Address */
-#define AR5K_SLEEP1_NEXT_TIM		0x0007ffff	/* Mask for next TIM (?) */
-#define AR5K_SLEEP1_NEXT_TIM_S		0
-#define AR5K_SLEEP1_BEACON_TO		0xff000000	/* Mask for Beacon Time Out */
-#define AR5K_SLEEP1_BEACON_TO_S		24
-
-/*
- * Third enhanced sleep register
- */
-#define AR5K_SLEEP2			0x80dc			/* Register Address */
-#define AR5K_SLEEP2_TIM_PER		0x0000ffff	/* Mask for TIM period (?) */
-#define AR5K_SLEEP2_TIM_PER_S		0
-#define AR5K_SLEEP2_DTIM_PER		0xffff0000	/* Mask for DTIM period (?) */
-#define AR5K_SLEEP2_DTIM_PER_S		16
-
-/*
- * BSSID mask registers
- */
-#define AR5K_BSS_IDM0			0x80e0	/* Upper bits */
-#define AR5K_BSS_IDM1			0x80e4	/* Lower bits */
-
-/*
- * TX power control (TPC) register
- *
- * XXX: PCDAC steps (0.5dbm) or DBM ?
- *
- */
-#define AR5K_TXPC			0x80e8			/* Register Address */
-#define AR5K_TXPC_ACK_M			0x0000003f	/* ACK tx power */
-#define AR5K_TXPC_ACK_S			0
-#define AR5K_TXPC_CTS_M			0x00003f00	/* CTS tx power */
-#define AR5K_TXPC_CTS_S			8
-#define AR5K_TXPC_CHIRP_M		0x003f0000	/* CHIRP tx power */
-#define AR5K_TXPC_CHIRP_S		16
-#define AR5K_TXPC_DOPPLER		0x0f000000	/* Doppler chirp span (?) */
-#define AR5K_TXPC_DOPPLER_S		24
-
-/*
- * Profile count registers
- */
-#define AR5K_PROFCNT_TX			0x80ec	/* Tx count */
-#define AR5K_PROFCNT_RX			0x80f0	/* Rx count */
-#define AR5K_PROFCNT_RXCLR		0x80f4	/* Clear Rx count */
-#define AR5K_PROFCNT_CYCLE		0x80f8	/* Cycle count (?) */
-
-/*
- * Quiet period control registers
- */
-#define AR5K_QUIET_CTL1			0x80fc			/* Register Address */
-#define AR5K_QUIET_CTL1_NEXT_QT_TSF	0x0000ffff	/* Next quiet period TSF (TU) */
-#define AR5K_QUIET_CTL1_NEXT_QT_TSF_S	0
-#define AR5K_QUIET_CTL1_QT_EN		0x00010000	/* Enable quiet period */
-#define AR5K_QUIET_CTL1_ACK_CTS_EN	0x00020000	/* Send ACK/CTS during quiet period */
-
-#define AR5K_QUIET_CTL2			0x8100			/* Register Address */
-#define AR5K_QUIET_CTL2_QT_PER		0x0000ffff	/* Mask for quiet period periodicity */
-#define AR5K_QUIET_CTL2_QT_PER_S	0
-#define AR5K_QUIET_CTL2_QT_DUR		0xffff0000	/* Mask for quiet period duration */
-#define AR5K_QUIET_CTL2_QT_DUR_S	16
-
-/*
- * TSF parameter register
- */
-#define AR5K_TSF_PARM			0x8104			/* Register Address */
-#define AR5K_TSF_PARM_INC		0x000000ff	/* Mask for TSF increment */
-#define AR5K_TSF_PARM_INC_S		0
-
-/*
- * QoS NOACK policy
- */
-#define AR5K_QOS_NOACK			0x8108			/* Register Address */
-#define AR5K_QOS_NOACK_2BIT_VALUES	0x0000000f	/* ??? */
-#define AR5K_QOS_NOACK_2BIT_VALUES_S	0
-#define AR5K_QOS_NOACK_BIT_OFFSET	0x00000070	/* ??? */
-#define AR5K_QOS_NOACK_BIT_OFFSET_S	4
-#define AR5K_QOS_NOACK_BYTE_OFFSET	0x00000180	/* ??? */
-#define AR5K_QOS_NOACK_BYTE_OFFSET_S	7
-
-/*
- * PHY error filter register
- */
-#define AR5K_PHY_ERR_FIL		0x810c
-#define AR5K_PHY_ERR_FIL_RADAR		0x00000020	/* Radar signal */
-#define AR5K_PHY_ERR_FIL_OFDM		0x00020000	/* OFDM false detect (ANI) */
-#define AR5K_PHY_ERR_FIL_CCK		0x02000000	/* CCK false detect (ANI) */
-
-/*
- * XR latency register
- */
-#define AR5K_XRLAT_TX		0x8110
-
-/*
- * ACK SIFS register
- */
-#define AR5K_ACKSIFS		0x8114			/* Register Address */
-#define AR5K_ACKSIFS_INC	0x00000000	/* ACK SIFS Increment (field) */
-
-/*
- * MIC QoS control register (?)
- */
-#define	AR5K_MIC_QOS_CTL		0x8118			/* Register Address */
-#define	AR5K_MIC_QOS_CTL_OFF(_n)	(1 << (_n * 2))
-#define	AR5K_MIC_QOS_CTL_MQ_EN		0x00010000	/* Enable MIC QoS */
-
-/*
- * MIC QoS select register (?)
- */
-#define	AR5K_MIC_QOS_SEL		0x811c
-#define	AR5K_MIC_QOS_SEL_OFF(_n)	(1 << (_n * 4))
-
-/*
- * Misc mode control register (?)
- */
-#define	AR5K_MISC_MODE			0x8120			/* Register Address */
-#define	AR5K_MISC_MODE_FBSSID_MATCH	0x00000001	/* Force BSSID match */
-#define	AR5K_MISC_MODE_ACKSIFS_MEM	0x00000002	/* ACK SIFS memory (?) */
-#define	AR5K_MISC_MODE_COMBINED_MIC	0x00000004	/* use rx/tx MIC key */
-/* more bits */
-
-/*
- * OFDM Filter counter
- */
-#define	AR5K_OFDM_FIL_CNT		0x8124
-
-/*
- * CCK Filter counter
- */
-#define	AR5K_CCK_FIL_CNT		0x8128
-
-/*
- * PHY Error Counters (?)
- */
-#define	AR5K_PHYERR_CNT1		0x812c
-#define	AR5K_PHYERR_CNT1_MASK		0x8130
-
-#define	AR5K_PHYERR_CNT2		0x8134
-#define	AR5K_PHYERR_CNT2_MASK		0x8138
-
-/*
- * TSF Threshold register (?)
- */
-#define	AR5K_TSF_THRES			0x813c
-
-/*
- * TODO: Wake On Wireless registers
- * Range: 0x8147 - 0x818c
- */
-
-/*
- * Rate -> ACK SIFS mapping table (32 entries)
- */
-#define	AR5K_RATE_ACKSIFS_BASE		0x8680			/* Register Address */
-#define	AR5K_RATE_ACKSIFS(_n)		(AR5K_RATE_ACKSIFS_BSE + ((_n) << 2))
-#define	AR5K_RATE_ACKSIFS_NORMAL	0x00000001	/* Normal SIFS (field) */
-#define	AR5K_RATE_ACKSIFS_TURBO		0x00000400	/* Turbo SIFS (field) */
-
-/*
- * Rate -> duration mapping table (32 entries)
- */
-#define AR5K_RATE_DUR_BASE		0x8700
-#define AR5K_RATE_DUR(_n)		(AR5K_RATE_DUR_BASE + ((_n) << 2))
-
-/*
- * Rate -> db mapping table
- * (8 entries, each one has 4 8bit fields)
- */
-#define AR5K_RATE2DB_BASE		0x87c0
-#define AR5K_RATE2DB(_n)		(AR5K_RATE2DB_BASE + ((_n) << 2))
-
-/*
- * db -> Rate mapping table
- * (8 entries, each one has 4 8bit fields)
- */
-#define AR5K_DB2RATE_BASE		0x87e0
-#define AR5K_DB2RATE(_n)		(AR5K_DB2RATE_BASE + ((_n) << 2))
-
-/*===5212 end===*/
-
-/*
- * Key table (WEP) register
- */
-#define AR5K_KEYTABLE_0_5210		0x9000
-#define AR5K_KEYTABLE_0_5211		0x8800
-#define AR5K_KEYTABLE_5210(_n)		(AR5K_KEYTABLE_0_5210 + ((_n) << 5))
-#define AR5K_KEYTABLE_5211(_n)		(AR5K_KEYTABLE_0_5211 + ((_n) << 5))
-#define	AR5K_KEYTABLE(_n)		(ah->ah_version == AR5K_AR5210 ? \
-					AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n))
-#define AR5K_KEYTABLE_OFF(_n, x)	(AR5K_KEYTABLE(_n) + (x << 2))
-#define AR5K_KEYTABLE_TYPE(_n)		AR5K_KEYTABLE_OFF(_n, 5)
-#define AR5K_KEYTABLE_TYPE_40		0x00000000
-#define AR5K_KEYTABLE_TYPE_104		0x00000001
-#define AR5K_KEYTABLE_TYPE_128		0x00000003
-#define AR5K_KEYTABLE_TYPE_TKIP		0x00000004	/* [5212+] */
-#define AR5K_KEYTABLE_TYPE_AES		0x00000005	/* [5211+] */
-#define AR5K_KEYTABLE_TYPE_CCM		0x00000006	/* [5212+] */
-#define AR5K_KEYTABLE_TYPE_NULL		0x00000007	/* [5211+] */
-#define AR5K_KEYTABLE_ANTENNA		0x00000008	/* [5212+] */
-#define AR5K_KEYTABLE_MAC0(_n)		AR5K_KEYTABLE_OFF(_n, 6)
-#define AR5K_KEYTABLE_MAC1(_n)		AR5K_KEYTABLE_OFF(_n, 7)
-#define AR5K_KEYTABLE_VALID		0x00008000
-
-/* If key type is TKIP and MIC is enabled
- * MIC key goes in offset entry + 64 */
-#define	AR5K_KEYTABLE_MIC_OFFSET	64
-
-/* WEP 40-bit	= 40-bit  entered key + 24 bit IV = 64-bit
- * WEP 104-bit	= 104-bit entered key + 24-bit IV = 128-bit
- * WEP 128-bit	= 128-bit entered key + 24 bit IV = 152-bit
- *
- * Some vendors have introduced bigger WEP keys to address
- * security vulnerabilities in WEP. This includes:
- *
- * WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit
- *
- * We can expand this if we find ar5k Atheros cards with a larger
- * key table size.
- */
-#define AR5K_KEYTABLE_SIZE_5210		64
-#define AR5K_KEYTABLE_SIZE_5211		128
-#define	AR5K_KEYTABLE_SIZE		(ah->ah_version == AR5K_AR5210 ? \
-					AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211)
-
-
-/*===PHY REGISTERS===*/
-
-/*
- * PHY registers start
- */
-#define	AR5K_PHY_BASE			0x9800
-#define	AR5K_PHY(_n)			(AR5K_PHY_BASE + ((_n) << 2))
-
-/*
- * TST_2 (Misc config parameters)
- */
-#define	AR5K_PHY_TST2			0x9800			/* Register Address */
-#define AR5K_PHY_TST2_TRIG_SEL		0x00000007	/* Trigger select (?)*/
-#define AR5K_PHY_TST2_TRIG		0x00000010	/* Trigger (?) */
-#define AR5K_PHY_TST2_CBUS_MODE		0x00000060	/* Cardbus mode (?) */
-#define AR5K_PHY_TST2_CLK32		0x00000400	/* CLK_OUT is CLK32 (32Khz external) */
-#define AR5K_PHY_TST2_CHANCOR_DUMP_EN	0x00000800	/* Enable Chancor dump (?) */
-#define AR5K_PHY_TST2_EVEN_CHANCOR_DUMP	0x00001000	/* Even Chancor dump (?) */
-#define AR5K_PHY_TST2_RFSILENT_EN	0x00002000	/* Enable RFSILENT */
-#define AR5K_PHY_TST2_ALT_RFDATA	0x00004000	/* Alternate RFDATA (5-2GHz switch ?) */
-#define AR5K_PHY_TST2_MINI_OBS_EN	0x00008000	/* Enable mini OBS (?) */
-#define AR5K_PHY_TST2_RX2_IS_RX5_INV	0x00010000	/* 2GHz rx path is the 5GHz path inverted (?) */
-#define AR5K_PHY_TST2_SLOW_CLK160	0x00020000	/* Slow CLK160 (?) */
-#define AR5K_PHY_TST2_AGC_OBS_SEL_3	0x00040000	/* AGC OBS Select 3 (?) */
-#define AR5K_PHY_TST2_BBB_OBS_SEL	0x00080000	/* BB OBS Select (field ?) */
-#define AR5K_PHY_TST2_ADC_OBS_SEL	0x00800000	/* ADC OBS Select (field ?) */
-#define AR5K_PHY_TST2_RX_CLR_SEL	0x08000000	/* RX Clear Select (?) */
-#define AR5K_PHY_TST2_FORCE_AGC_CLR	0x10000000	/* Force AGC clear (?) */
-#define AR5K_PHY_SHIFT_2GHZ		0x00004007	/* Used to access 2GHz radios */
-#define AR5K_PHY_SHIFT_5GHZ		0x00000007	/* Used to access 5GHz radios (default) */
-
-/*
- * PHY frame control register [5110] /turbo mode register [5111+]
- *
- * There is another frame control register for [5111+]
- * at address 0x9944 (see below) but the 2 first flags
- * are common here between 5110 frame control register
- * and [5111+] turbo mode register, so this also works as
- * a "turbo mode register" for 5110. We treat this one as
- * a frame control register for 5110 below.
- */
-#define	AR5K_PHY_TURBO			0x9804			/* Register Address */
-#define	AR5K_PHY_TURBO_MODE		0x00000001	/* Enable turbo mode */
-#define	AR5K_PHY_TURBO_SHORT		0x00000002	/* Set short symbols to turbo mode */
-#define	AR5K_PHY_TURBO_MIMO		0x00000004	/* Set turbo for mimo mimo */
-
-/*
- * PHY agility command register
- * (aka TST_1)
- */
-#define	AR5K_PHY_AGC			0x9808			/* Register Address */
-#define	AR5K_PHY_TST1			0x9808
-#define	AR5K_PHY_AGC_DISABLE		0x08000000	/* Disable AGC to A2 (?)*/
-#define	AR5K_PHY_TST1_TXHOLD		0x00003800	/* Set tx hold (?) */
-#define	AR5K_PHY_TST1_TXSRC_SRC		0x00000002	/* Used with bit 7 (?) */
-#define	AR5K_PHY_TST1_TXSRC_SRC_S	1
-#define	AR5K_PHY_TST1_TXSRC_ALT		0x00000080	/* Set input to tsdac (?) */
-#define	AR5K_PHY_TST1_TXSRC_ALT_S	7
-
-
-/*
- * PHY timing register 3 [5112+]
- */
-#define	AR5K_PHY_TIMING_3		0x9814
-#define	AR5K_PHY_TIMING_3_DSC_MAN	0xfffe0000
-#define	AR5K_PHY_TIMING_3_DSC_MAN_S	17
-#define	AR5K_PHY_TIMING_3_DSC_EXP	0x0001e000
-#define	AR5K_PHY_TIMING_3_DSC_EXP_S	13
-
-/*
- * PHY chip revision register
- */
-#define	AR5K_PHY_CHIP_ID		0x9818
-
-/*
- * PHY activation register
- */
-#define	AR5K_PHY_ACT			0x981c			/* Register Address */
-#define	AR5K_PHY_ACT_ENABLE		0x00000001	/* Activate PHY */
-#define	AR5K_PHY_ACT_DISABLE		0x00000002	/* Deactivate PHY */
-
-/*
- * PHY RF control registers
- */
-#define AR5K_PHY_RF_CTL2		0x9824			/* Register Address */
-#define	AR5K_PHY_RF_CTL2_TXF2TXD_START	0x0000000f	/* TX frame to TX data start */
-#define	AR5K_PHY_RF_CTL2_TXF2TXD_START_S	0
-
-#define AR5K_PHY_RF_CTL3		0x9828			/* Register Address */
-#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON	0x0000ff00	/* TX end to XLNA on */
-#define	AR5K_PHY_RF_CTL3_TXE2XLNA_ON_S	8
-
-#define	AR5K_PHY_ADC_CTL			0x982c
-#define	AR5K_PHY_ADC_CTL_INBUFGAIN_OFF		0x00000003
-#define	AR5K_PHY_ADC_CTL_INBUFGAIN_OFF_S	0
-#define	AR5K_PHY_ADC_CTL_PWD_DAC_OFF		0x00002000
-#define	AR5K_PHY_ADC_CTL_PWD_BAND_GAP_OFF	0x00004000
-#define	AR5K_PHY_ADC_CTL_PWD_ADC_OFF		0x00008000
-#define	AR5K_PHY_ADC_CTL_INBUFGAIN_ON		0x00030000
-#define	AR5K_PHY_ADC_CTL_INBUFGAIN_ON_S		16
-
-#define AR5K_PHY_RF_CTL4		0x9834			/* Register Address */
-#define AR5K_PHY_RF_CTL4_TXF2XPA_A_ON	0x00000001	/* TX frame to XPA A on (field) */
-#define AR5K_PHY_RF_CTL4_TXF2XPA_B_ON	0x00000100	/* TX frame to XPA B on (field) */
-#define	AR5K_PHY_RF_CTL4_TXE2XPA_A_OFF	0x00010000	/* TX end to XPA A off (field) */
-#define AR5K_PHY_RF_CTL4_TXE2XPA_B_OFF	0x01000000	/* TX end to XPA B off (field) */
-
-/*
- * Pre-Amplifier control register
- * (XPA -> external pre-amplifier)
- */
-#define	AR5K_PHY_PA_CTL			0x9838			/* Register Address */
-#define	AR5K_PHY_PA_CTL_XPA_A_HI	0x00000001	/* XPA A high (?) */
-#define	AR5K_PHY_PA_CTL_XPA_B_HI	0x00000002	/* XPA B high (?) */
-#define	AR5K_PHY_PA_CTL_XPA_A_EN	0x00000004	/* Enable XPA A */
-#define	AR5K_PHY_PA_CTL_XPA_B_EN	0x00000008	/* Enable XPA B */
-
-/*
- * PHY settling register
- */
-#define AR5K_PHY_SETTLING		0x9844			/* Register Address */
-#define	AR5K_PHY_SETTLING_AGC		0x0000007f	/* AGC settling time */
-#define	AR5K_PHY_SETTLING_AGC_S		0
-#define	AR5K_PHY_SETTLING_SWITCH	0x00003f80	/* Switch settlig time */
-#define	AR5K_PHY_SETTLING_SWITCH_S	7
-
-/*
- * PHY Gain registers
- */
-#define AR5K_PHY_GAIN			0x9848			/* Register Address */
-#define	AR5K_PHY_GAIN_TXRX_ATTEN	0x0003f000	/* TX-RX Attenuation */
-#define	AR5K_PHY_GAIN_TXRX_ATTEN_S	12
-#define	AR5K_PHY_GAIN_TXRX_RF_MAX	0x007c0000
-#define	AR5K_PHY_GAIN_TXRX_RF_MAX_S	18
-
-#define	AR5K_PHY_GAIN_OFFSET		0x984c			/* Register Address */
-#define	AR5K_PHY_GAIN_OFFSET_RXTX_FLAG	0x00020000	/* RX-TX flag (?) */
-
-/*
- * Desired ADC/PGA size register
- * (for more infos read ANI patent)
- */
-#define AR5K_PHY_DESIRED_SIZE		0x9850			/* Register Address */
-#define	AR5K_PHY_DESIRED_SIZE_ADC	0x000000ff	/* ADC desired size */
-#define	AR5K_PHY_DESIRED_SIZE_ADC_S	0
-#define	AR5K_PHY_DESIRED_SIZE_PGA	0x0000ff00	/* PGA desired size */
-#define	AR5K_PHY_DESIRED_SIZE_PGA_S	8
-#define	AR5K_PHY_DESIRED_SIZE_TOT	0x0ff00000	/* Total desired size */
-#define	AR5K_PHY_DESIRED_SIZE_TOT_S	20
-
-/*
- * PHY signal register
- * (for more infos read ANI patent)
- */
-#define	AR5K_PHY_SIG			0x9858			/* Register Address */
-#define	AR5K_PHY_SIG_FIRSTEP		0x0003f000	/* FIRSTEP */
-#define	AR5K_PHY_SIG_FIRSTEP_S		12
-#define	AR5K_PHY_SIG_FIRPWR		0x03fc0000	/* FIPWR */
-#define	AR5K_PHY_SIG_FIRPWR_S		18
-
-/*
- * PHY coarse agility control register
- * (for more infos read ANI patent)
- */
-#define	AR5K_PHY_AGCCOARSE		0x985c			/* Register Address */
-#define	AR5K_PHY_AGCCOARSE_LO		0x00007f80	/* AGC Coarse low */
-#define	AR5K_PHY_AGCCOARSE_LO_S		7
-#define	AR5K_PHY_AGCCOARSE_HI		0x003f8000	/* AGC Coarse high */
-#define	AR5K_PHY_AGCCOARSE_HI_S		15
-
-/*
- * PHY agility control register
- */
-#define	AR5K_PHY_AGCCTL			0x9860			/* Register address */
-#define	AR5K_PHY_AGCCTL_CAL		0x00000001	/* Enable PHY calibration */
-#define	AR5K_PHY_AGCCTL_NF		0x00000002	/* Enable Noise Floor calibration */
-#define	AR5K_PHY_AGCCTL_NF_EN		0x00008000	/* Enable nf calibration to happen (?) */
-#define	AR5K_PHY_AGCCTL_NF_NOUPDATE	0x00020000	/* Don't update nf automaticaly */
-
-/*
- * PHY noise floor status register
- */
-#define AR5K_PHY_NF			0x9864			/* Register address */
-#define AR5K_PHY_NF_M			0x000001ff	/* Noise floor mask */
-#define AR5K_PHY_NF_ACTIVE		0x00000100	/* Noise floor calibration still active */
-#define AR5K_PHY_NF_RVAL(_n)		(((_n) >> 19) & AR5K_PHY_NF_M)
-#define AR5K_PHY_NF_AVAL(_n)		(-((_n) ^ AR5K_PHY_NF_M) + 1)
-#define AR5K_PHY_NF_SVAL(_n)		(((_n) & AR5K_PHY_NF_M) | (1 << 9))
-#define	AR5K_PHY_NF_THRESH62		0x0007f000	/* Thresh62 -check ANI patent- (field) */
-#define	AR5K_PHY_NF_THRESH62_S		12
-#define	AR5K_PHY_NF_MINCCA_PWR		0x0ff80000	/* ??? */
-#define	AR5K_PHY_NF_MINCCA_PWR_S	19
-
-/*
- * PHY ADC saturation register [5110]
- */
-#define	AR5K_PHY_ADCSAT			0x9868
-#define	AR5K_PHY_ADCSAT_ICNT		0x0001f800
-#define	AR5K_PHY_ADCSAT_ICNT_S		11
-#define	AR5K_PHY_ADCSAT_THR		0x000007e0
-#define	AR5K_PHY_ADCSAT_THR_S		5
-
-/*
- * PHY Weak ofdm signal detection threshold registers (ANI) [5212+]
- */
-
-/* High thresholds */
-#define AR5K_PHY_WEAK_OFDM_HIGH_THR		0x9868
-#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT	0x0000001f
-#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT_S	0
-#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1		0x00fe0000
-#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1_S	17
-#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2		0x7f000000
-#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_S	24
-
-/* Low thresholds */
-#define AR5K_PHY_WEAK_OFDM_LOW_THR 		0x986c
-#define AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN	0x00000001
-#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT	0x00003f00
-#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT_S	8
-#define AR5K_PHY_WEAK_OFDM_LOW_THR_M1		0x001fc000
-#define AR5K_PHY_WEAK_OFDM_LOW_THR_M1_S		14
-#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2		0x0fe00000
-#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_S		21
-
-
-/*
- * PHY sleep registers [5112+]
- */
-#define AR5K_PHY_SCR			0x9870
-
-#define AR5K_PHY_SLMT			0x9874
-#define AR5K_PHY_SLMT_32MHZ		0x0000007f
-
-#define AR5K_PHY_SCAL			0x9878
-#define AR5K_PHY_SCAL_32MHZ		0x0000000e
-#define	AR5K_PHY_SCAL_32MHZ_2417	0x0000000a
-#define	AR5K_PHY_SCAL_32MHZ_HB63	0x00000032
-
-/*
- * PHY PLL (Phase Locked Loop) control register
- */
-#define	AR5K_PHY_PLL			0x987c
-#define	AR5K_PHY_PLL_20MHZ		0x00000013	/* For half rate (?) */
-/* 40MHz -> 5GHz band */
-#define	AR5K_PHY_PLL_40MHZ_5211		0x00000018
-#define	AR5K_PHY_PLL_40MHZ_5212		0x000000aa
-#define	AR5K_PHY_PLL_40MHZ_5413		0x00000004
-#define	AR5K_PHY_PLL_40MHZ		(ah->ah_version == AR5K_AR5211 ? \
-					AR5K_PHY_PLL_40MHZ_5211 : AR5K_PHY_PLL_40MHZ_5212)
-/* 44MHz -> 2.4GHz band */
-#define	AR5K_PHY_PLL_44MHZ_5211		0x00000019
-#define	AR5K_PHY_PLL_44MHZ_5212		0x000000ab
-#define	AR5K_PHY_PLL_44MHZ		(ah->ah_version == AR5K_AR5211 ? \
-					AR5K_PHY_PLL_44MHZ_5211 : AR5K_PHY_PLL_44MHZ_5212)
-
-#define AR5K_PHY_PLL_RF5111		0x00000000
-#define AR5K_PHY_PLL_RF5112		0x00000040
-#define	AR5K_PHY_PLL_HALF_RATE		0x00000100
-#define	AR5K_PHY_PLL_QUARTER_RATE	0x00000200
-
-/*
- * RF Buffer register
- *
- * It's obvious from the code that 0x989c is the buffer register but
- * for the other special registers that we write to after sending each
- * packet, i have no idea. So i'll name them BUFFER_CONTROL_X registers
- * for now. It's interesting that they are also used for some other operations.
- */
-
-#define AR5K_RF_BUFFER			0x989c
-#define AR5K_RF_BUFFER_CONTROL_0	0x98c0	/* Channel on 5110 */
-#define AR5K_RF_BUFFER_CONTROL_1	0x98c4	/* Bank 7 on 5112 */
-#define AR5K_RF_BUFFER_CONTROL_2	0x98cc	/* Bank 7 on 5111 */
-
-#define AR5K_RF_BUFFER_CONTROL_3	0x98d0	/* Bank 2 on 5112 */
-						/* Channel set on 5111 */
-						/* Used to read radio revision*/
-
-#define AR5K_RF_BUFFER_CONTROL_4	0x98d4  /* RF Stage register on 5110 */
-						/* Bank 0,1,2,6 on 5111 */
-						/* Bank 1 on 5112 */
-						/* Used during activation on 5111 */
-
-#define AR5K_RF_BUFFER_CONTROL_5	0x98d8	/* Bank 3 on 5111 */
-						/* Used during activation on 5111 */
-						/* Channel on 5112 */
-						/* Bank 6 on 5112 */
-
-#define AR5K_RF_BUFFER_CONTROL_6	0x98dc	/* Bank 3 on 5112 */
-
-/*
- * PHY RF stage register [5210]
- */
-#define AR5K_PHY_RFSTG			0x98d4
-#define AR5K_PHY_RFSTG_DISABLE		0x00000021
-
-/*
- * BIN masks (?)
- */
-#define	AR5K_PHY_BIN_MASK_1	0x9900
-#define	AR5K_PHY_BIN_MASK_2	0x9904
-#define	AR5K_PHY_BIN_MASK_3	0x9908
-
-#define	AR5K_PHY_BIN_MASK_CTL		0x990c
-#define	AR5K_PHY_BIN_MASK_CTL_MASK_4	0x00003fff
-#define	AR5K_PHY_BIN_MASK_CTL_MASK_4_S	0
-#define	AR5K_PHY_BIN_MASK_CTL_RATE	0xff000000
-#define	AR5K_PHY_BIN_MASK_CTL_RATE_S	24
-
-/*
- * PHY Antenna control register
- */
-#define AR5K_PHY_ANT_CTL		0x9910			/* Register Address */
-#define	AR5K_PHY_ANT_CTL_TXRX_EN	0x00000001	/* Enable TX/RX (?) */
-#define	AR5K_PHY_ANT_CTL_SECTORED_ANT	0x00000004	/* Sectored Antenna */
-#define	AR5K_PHY_ANT_CTL_HITUNE5	0x00000008	/* Hitune5 (?) */
-#define	AR5K_PHY_ANT_CTL_SWTABLE_IDLE	0x000003f0	/* Switch table idle (?) */
-#define	AR5K_PHY_ANT_CTL_SWTABLE_IDLE_S	4
-
-/*
- * PHY receiver delay register [5111+]
- */
-#define	AR5K_PHY_RX_DELAY		0x9914			/* Register Address */
-#define	AR5K_PHY_RX_DELAY_M		0x00003fff	/* Mask for RX activate to receive delay (/100ns) */
-
-/*
- * PHY max rx length register (?) [5111]
- */
-#define	AR5K_PHY_MAX_RX_LEN		0x991c
-
-/*
- * PHY timing register 4
- * I(nphase)/Q(adrature) calibration register [5111+]
- */
-#define	AR5K_PHY_IQ			0x9920			/* Register Address */
-#define	AR5K_PHY_IQ_CORR_Q_Q_COFF	0x0000001f	/* Mask for q correction info */
-#define	AR5K_PHY_IQ_CORR_Q_I_COFF	0x000007e0	/* Mask for i correction info */
-#define	AR5K_PHY_IQ_CORR_Q_I_COFF_S	5
-#define	AR5K_PHY_IQ_CORR_ENABLE		0x00000800	/* Enable i/q correction */
-#define	AR5K_PHY_IQ_CAL_NUM_LOG_MAX	0x0000f000	/* Mask for max number of samples in log scale */
-#define	AR5K_PHY_IQ_CAL_NUM_LOG_MAX_S	12
-#define	AR5K_PHY_IQ_RUN			0x00010000	/* Run i/q calibration */
-#define	AR5K_PHY_IQ_USE_PT_DF		0x00020000	/* Use pilot track df (?) */
-#define	AR5K_PHY_IQ_EARLY_TRIG_THR	0x00200000	/* Early trigger threshold (?) (field) */
-#define	AR5K_PHY_IQ_PILOT_MASK_EN	0x10000000	/* Enable pilot mask (?) */
-#define	AR5K_PHY_IQ_CHAN_MASK_EN	0x20000000	/* Enable channel mask (?) */
-#define	AR5K_PHY_IQ_SPUR_FILT_EN	0x40000000	/* Enable spur filter */
-#define	AR5K_PHY_IQ_SPUR_RSSI_EN	0x80000000	/* Enable spur rssi */
-
-/*
- * PHY timing register 5
- * OFDM Self-correlator Cyclic RSSI threshold params
- * (Check out bb_cycpwr_thr1 on ANI patent)
- */
-#define	AR5K_PHY_OFDM_SELFCORR			0x9924			/* Register Address */
-#define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_EN	0x00000001	/* Enable cyclic RSSI thr 1 */
-#define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1	0x000000fe	/* Mask for Cyclic RSSI threshold 1 */
-#define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_S	1
-#define	AR5K_PHY_OFDM_SELFCORR_CYPWR_THR3	0x00000100	/* Cyclic RSSI threshold 3 (field) (?) */
-#define	AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR_EN	0x00008000	/* Enable 1A RSSI threshold (?) */
-#define	AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR	0x00010000	/* 1A RSSI threshold (field) (?) */
-#define	AR5K_PHY_OFDM_SELFCORR_LSCTHR_HIRSSI	0x00800000	/* Long sc threshold hi rssi (?) */
-
-/*
- * PHY-only warm reset register
- */
-#define	AR5K_PHY_WARM_RESET		0x9928
-
-/*
- * PHY-only control register
- */
-#define AR5K_PHY_CTL			0x992c			/* Register Address */
-#define	AR5K_PHY_CTL_RX_DRAIN_RATE	0x00000001	/* RX drain rate (?) */
-#define	AR5K_PHY_CTL_LATE_TX_SIG_SYM	0x00000002	/* Late tx signal symbol (?) */
-#define	AR5K_PHY_CTL_GEN_SCRAMBLER	0x00000004	/* Generate scrambler */
-#define	AR5K_PHY_CTL_TX_ANT_SEL		0x00000008	/* TX antenna select */
-#define	AR5K_PHY_CTL_TX_ANT_STATIC	0x00000010	/* Static TX antenna */
-#define	AR5K_PHY_CTL_RX_ANT_SEL		0x00000020	/* RX antenna select */
-#define	AR5K_PHY_CTL_RX_ANT_STATIC	0x00000040	/* Static RX antenna */
-#define	AR5K_PHY_CTL_LOW_FREQ_SLE_EN	0x00000080	/* Enable low freq sleep */
-
-/*
- * PHY PAPD probe register [5111+]
- */
-#define	AR5K_PHY_PAPD_PROBE		0x9930
-#define	AR5K_PHY_PAPD_PROBE_SH_HI_PAR	0x00000001
-#define	AR5K_PHY_PAPD_PROBE_PCDAC_BIAS	0x00000002
-#define	AR5K_PHY_PAPD_PROBE_COMP_GAIN	0x00000040
-#define	AR5K_PHY_PAPD_PROBE_TXPOWER	0x00007e00
-#define	AR5K_PHY_PAPD_PROBE_TXPOWER_S	9
-#define	AR5K_PHY_PAPD_PROBE_TX_NEXT	0x00008000
-#define	AR5K_PHY_PAPD_PROBE_PREDIST_EN	0x00010000
-#define	AR5K_PHY_PAPD_PROBE_TYPE	0x01800000	/* [5112+] */
-#define	AR5K_PHY_PAPD_PROBE_TYPE_S	23
-#define	AR5K_PHY_PAPD_PROBE_TYPE_OFDM	0
-#define	AR5K_PHY_PAPD_PROBE_TYPE_XR	1
-#define	AR5K_PHY_PAPD_PROBE_TYPE_CCK	2
-#define	AR5K_PHY_PAPD_PROBE_GAINF	0xfe000000
-#define	AR5K_PHY_PAPD_PROBE_GAINF_S	25
-#define	AR5K_PHY_PAPD_PROBE_INI_5111	0x00004883	/* [5212+] */
-#define	AR5K_PHY_PAPD_PROBE_INI_5112	0x00004882	/* [5212+] */
-
-/*
- * PHY TX rate power registers [5112+]
- */
-#define	AR5K_PHY_TXPOWER_RATE1			0x9934
-#define	AR5K_PHY_TXPOWER_RATE2			0x9938
-#define	AR5K_PHY_TXPOWER_RATE_MAX		0x993c
-#define	AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE	0x00000040
-#define	AR5K_PHY_TXPOWER_RATE3			0xa234
-#define	AR5K_PHY_TXPOWER_RATE4			0xa238
-
-/*
- * PHY frame control register [5111+]
- */
-#define	AR5K_PHY_FRAME_CTL_5210		0x9804
-#define	AR5K_PHY_FRAME_CTL_5211		0x9944
-#define	AR5K_PHY_FRAME_CTL		(ah->ah_version == AR5K_AR5210 ? \
-					AR5K_PHY_FRAME_CTL_5210 : AR5K_PHY_FRAME_CTL_5211)
-/*---[5111+]---*/
-#define	AR5K_PHY_FRAME_CTL_TX_CLIP	0x00000038	/* Mask for tx clip (?) */
-#define	AR5K_PHY_FRAME_CTL_TX_CLIP_S	3
-#define	AR5K_PHY_FRAME_CTL_PREP_CHINFO	0x00010000	/* Prepend chan info */
-#define	AR5K_PHY_FRAME_CTL_EMU		0x80000000
-#define	AR5K_PHY_FRAME_CTL_EMU_S	31
-/*---[5110/5111]---*/
-#define	AR5K_PHY_FRAME_CTL_TIMING_ERR	0x01000000	/* PHY timing error */
-#define	AR5K_PHY_FRAME_CTL_PARITY_ERR	0x02000000	/* Parity error */
-#define	AR5K_PHY_FRAME_CTL_ILLRATE_ERR	0x04000000	/* Illegal rate */
-#define	AR5K_PHY_FRAME_CTL_ILLLEN_ERR	0x08000000	/* Illegal length */
-#define	AR5K_PHY_FRAME_CTL_SERVICE_ERR	0x20000000
-#define	AR5K_PHY_FRAME_CTL_TXURN_ERR	0x40000000	/* TX underrun */
-#define AR5K_PHY_FRAME_CTL_INI		AR5K_PHY_FRAME_CTL_SERVICE_ERR | \
-			AR5K_PHY_FRAME_CTL_TXURN_ERR | \
-			AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \
-			AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \
-			AR5K_PHY_FRAME_CTL_PARITY_ERR | \
-			AR5K_PHY_FRAME_CTL_TIMING_ERR
-
-/*
- * PHY Tx Power adjustment register [5212A+]
- */
-#define	AR5K_PHY_TX_PWR_ADJ			0x994c
-#define	AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA	0x00000fc0
-#define	AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA_S	6
-#define	AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX	0x00fc0000
-#define	AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX_S	18
-
-/*
- * PHY radar detection register [5111+]
- */
-#define	AR5K_PHY_RADAR			0x9954
-#define	AR5K_PHY_RADAR_ENABLE		0x00000001
-#define	AR5K_PHY_RADAR_DISABLE		0x00000000
-#define AR5K_PHY_RADAR_INBANDTHR    	0x0000003e	/* Inband threshold
-							5-bits, units unknown {0..31}
-							(? MHz ?) */
-#define AR5K_PHY_RADAR_INBANDTHR_S	1
-
-#define AR5K_PHY_RADAR_PRSSI_THR    	0x00000fc0	/* Pulse RSSI/SNR threshold
-							6-bits, dBm range {0..63}
-							in dBm units. */
-#define AR5K_PHY_RADAR_PRSSI_THR_S	6
-
-#define AR5K_PHY_RADAR_PHEIGHT_THR   	0x0003f000	/* Pulse height threshold
-							6-bits, dBm range {0..63}
-							in dBm units. */
-#define AR5K_PHY_RADAR_PHEIGHT_THR_S	12
-
-#define AR5K_PHY_RADAR_RSSI_THR    	0x00fc0000	/* Radar RSSI/SNR threshold.
-							6-bits, dBm range {0..63}
-							in dBm units. */
-#define AR5K_PHY_RADAR_RSSI_THR_S	18
-
-#define AR5K_PHY_RADAR_FIRPWR_THR	0x7f000000	/* Finite Impulse Response
-							filter power out threshold.
-							7-bits, standard power range
-							{0..127} in 1/2 dBm units. */
-#define AR5K_PHY_RADAR_FIRPWR_THRS	24
-
-/*
- * PHY antenna switch table registers
- */
-#define AR5K_PHY_ANT_SWITCH_TABLE_0	0x9960
-#define AR5K_PHY_ANT_SWITCH_TABLE_1	0x9964
-
-/*
- * PHY Noise floor threshold
- */
-#define AR5K_PHY_NFTHRES		0x9968
-
-/*
- * Sigma Delta register (?) [5213]
- */
-#define AR5K_PHY_SIGMA_DELTA		0x996C
-#define AR5K_PHY_SIGMA_DELTA_ADC_SEL	0x00000003
-#define AR5K_PHY_SIGMA_DELTA_ADC_SEL_S	0
-#define AR5K_PHY_SIGMA_DELTA_FILT2	0x000000f8
-#define AR5K_PHY_SIGMA_DELTA_FILT2_S	3
-#define AR5K_PHY_SIGMA_DELTA_FILT1	0x00001f00
-#define AR5K_PHY_SIGMA_DELTA_FILT1_S	8
-#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP	0x01ffe000
-#define AR5K_PHY_SIGMA_DELTA_ADC_CLIP_S	13
-
-/*
- * RF restart register [5112+] (?)
- */
-#define AR5K_PHY_RESTART		0x9970		/* restart */
-#define AR5K_PHY_RESTART_DIV_GC		0x001c0000	/* Fast diversity gc_limit (?) */
-#define AR5K_PHY_RESTART_DIV_GC_S	18
-
-/*
- * RF Bus access request register (for synth-oly channel switching)
- */
-#define AR5K_PHY_RFBUS_REQ		0x997C
-#define AR5K_PHY_RFBUS_REQ_REQUEST	0x00000001
-
-/*
- * Spur mitigation masks (?)
- */
-#define AR5K_PHY_TIMING_7		0x9980
-#define AR5K_PHY_TIMING_8		0x9984
-#define AR5K_PHY_TIMING_8_PILOT_MASK_2		0x000fffff
-#define AR5K_PHY_TIMING_8_PILOT_MASK_2_S	0
-
-#define AR5K_PHY_BIN_MASK2_1		0x9988
-#define AR5K_PHY_BIN_MASK2_2		0x998c
-#define AR5K_PHY_BIN_MASK2_3		0x9990
-
-#define AR5K_PHY_BIN_MASK2_4		0x9994
-#define AR5K_PHY_BIN_MASK2_4_MASK_4	0x00003fff
-#define AR5K_PHY_BIN_MASK2_4_MASK_4_S	0
-
-#define AR5K_PHY_TIMING_9			0x9998
-#define AR5K_PHY_TIMING_10			0x999c
-#define AR5K_PHY_TIMING_10_PILOT_MASK_2		0x000fffff
-#define AR5K_PHY_TIMING_10_PILOT_MASK_2_S	0
-
-/*
- * Spur mitigation control
- */
-#define AR5K_PHY_TIMING_11			0x99a0		/* Register address */
-#define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE	0x000fffff	/* Spur delta phase */
-#define AR5K_PHY_TIMING_11_SPUR_DELTA_PHASE_S	0
-#define AR5K_PHY_TIMING_11_SPUR_FREQ_SD		0x3ff00000	/* Freq sigma delta */
-#define AR5K_PHY_TIMING_11_SPUR_FREQ_SD_S	20
-#define AR5K_PHY_TIMING_11_USE_SPUR_IN_AGC	0x40000000	/* Spur filter in AGC detector */
-#define AR5K_PHY_TIMING_11_USE_SPUR_IN_SELFCOR	0x80000000	/* Spur filter in OFDM self correlator */
-
-/*
- * Gain tables
- */
-#define	AR5K_BB_GAIN_BASE		0x9b00	/* BaseBand Amplifier Gain table base address */
-#define AR5K_BB_GAIN(_n)		(AR5K_BB_GAIN_BASE + ((_n) << 2))
-#define	AR5K_RF_GAIN_BASE		0x9a00	/* RF Amplrifier Gain table base address */
-#define AR5K_RF_GAIN(_n)		(AR5K_RF_GAIN_BASE + ((_n) << 2))
-
-/*
- * PHY timing IQ calibration result register [5111+]
- */
-#define	AR5K_PHY_IQRES_CAL_PWR_I	0x9c10	/* I (Inphase) power value */
-#define	AR5K_PHY_IQRES_CAL_PWR_Q	0x9c14	/* Q (Quadrature) power value */
-#define	AR5K_PHY_IQRES_CAL_CORR		0x9c18	/* I/Q Correlation */
-
-/*
- * PHY current RSSI register [5111+]
- */
-#define	AR5K_PHY_CURRENT_RSSI	0x9c1c
-
-/*
- * PHY RF Bus grant register
- */
-#define	AR5K_PHY_RFBUS_GRANT	0x9c20
-#define	AR5K_PHY_RFBUS_GRANT_OK	0x00000001
-
-/*
- * PHY ADC test register
- */
-#define	AR5K_PHY_ADC_TEST	0x9c24
-#define	AR5K_PHY_ADC_TEST_I	0x00000001
-#define	AR5K_PHY_ADC_TEST_Q	0x00000200
-
-/*
- * PHY DAC test register
- */
-#define	AR5K_PHY_DAC_TEST	0x9c28
-#define	AR5K_PHY_DAC_TEST_I	0x00000001
-#define	AR5K_PHY_DAC_TEST_Q	0x00000200
-
-/*
- * PHY PTAT register (?)
- */
-#define	AR5K_PHY_PTAT		0x9c2c
-
-/*
- * PHY Illegal TX rate register [5112+]
- */
-#define	AR5K_PHY_BAD_TX_RATE	0x9c30
-
-/*
- * PHY SPUR Power register [5112+]
- */
-#define	AR5K_PHY_SPUR_PWR	0x9c34			/* Register Address */
-#define	AR5K_PHY_SPUR_PWR_I	0x00000001	/* SPUR Power estimate for I (field) */
-#define	AR5K_PHY_SPUR_PWR_Q	0x00000100	/* SPUR Power estimate for Q (field) */
-#define	AR5K_PHY_SPUR_PWR_FILT	0x00010000	/* Power with SPUR removed (field) */
-
-/*
- * PHY Channel status register [5112+] (?)
- */
-#define	AR5K_PHY_CHAN_STATUS		0x9c38
-#define	AR5K_PHY_CHAN_STATUS_BT_ACT	0x00000001
-#define	AR5K_PHY_CHAN_STATUS_RX_CLR_RAW	0x00000002
-#define	AR5K_PHY_CHAN_STATUS_RX_CLR_MAC	0x00000004
-#define	AR5K_PHY_CHAN_STATUS_RX_CLR_PAP	0x00000008
-
-/*
- * Heavy clip enable register
- */
-#define	AR5K_PHY_HEAVY_CLIP_ENABLE	0x99e0
-
-/*
- * PHY clock sleep registers [5112+]
- */
-#define AR5K_PHY_SCLOCK			0x99f0
-#define AR5K_PHY_SCLOCK_32MHZ		0x0000000c
-#define AR5K_PHY_SDELAY			0x99f4
-#define AR5K_PHY_SDELAY_32MHZ		0x000000ff
-#define AR5K_PHY_SPENDING		0x99f8
-
-
-/*
- * PHY PAPD I (power?) table (?)
- * (92! entries)
- */
-#define	AR5K_PHY_PAPD_I_BASE	0xa000
-#define	AR5K_PHY_PAPD_I(_n)	(AR5K_PHY_PAPD_I_BASE + ((_n) << 2))
-
-/*
- * PHY PCDAC TX power table
- */
-#define	AR5K_PHY_PCDAC_TXPOWER_BASE	0xa180
-#define	AR5K_PHY_PCDAC_TXPOWER(_n)	(AR5K_PHY_PCDAC_TXPOWER_BASE + ((_n) << 2))
-
-/*
- * PHY mode register [5111+]
- */
-#define	AR5K_PHY_MODE			0x0a200			/* Register Address */
-#define	AR5K_PHY_MODE_MOD		0x00000001	/* PHY Modulation bit */
-#define AR5K_PHY_MODE_MOD_OFDM		0
-#define AR5K_PHY_MODE_MOD_CCK		1
-#define AR5K_PHY_MODE_FREQ		0x00000002	/* Freq mode bit */
-#define	AR5K_PHY_MODE_FREQ_5GHZ		0
-#define	AR5K_PHY_MODE_FREQ_2GHZ		2
-#define AR5K_PHY_MODE_MOD_DYN		0x00000004	/* Enable Dynamic OFDM/CCK mode [5112+] */
-#define AR5K_PHY_MODE_RAD		0x00000008	/* [5212+] */
-#define AR5K_PHY_MODE_RAD_RF5111	0
-#define AR5K_PHY_MODE_RAD_RF5112	8
-#define AR5K_PHY_MODE_XR		0x00000010	/* Enable XR mode [5112+] */
-#define	AR5K_PHY_MODE_HALF_RATE		0x00000020	/* Enable Half rate (test) */
-#define	AR5K_PHY_MODE_QUARTER_RATE	0x00000040	/* Enable Quarter rat (test) */
-
-/*
- * PHY CCK transmit control register [5111+ (?)]
- */
-#define AR5K_PHY_CCKTXCTL		0xa204
-#define AR5K_PHY_CCKTXCTL_WORLD		0x00000000
-#define AR5K_PHY_CCKTXCTL_JAPAN		0x00000010
-#define	AR5K_PHY_CCKTXCTL_SCRAMBLER_DIS	0x00000001
-#define	AR5K_PHY_CCKTXCTK_DAC_SCALE	0x00000004
-
-/*
- * PHY CCK Cross-correlator Barker RSSI threshold register [5212+]
- */
-#define AR5K_PHY_CCK_CROSSCORR			0xa208
-#define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR	0x0000000f
-#define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR_S	0
-
-/* Same address is used for antenna diversity activation */
-#define	AR5K_PHY_FAST_ANT_DIV		0xa208
-#define	AR5K_PHY_FAST_ANT_DIV_EN	0x00002000
-
-/*
- * PHY 2GHz gain register [5111+]
- */
-#define	AR5K_PHY_GAIN_2GHZ			0xa20c
-#define	AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX		0x00fc0000
-#define	AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX_S	18
-#define	AR5K_PHY_GAIN_2GHZ_INI_5111		0x6480416c
-
-#define	AR5K_PHY_CCK_RX_CTL_4			0xa21c
-#define	AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT	0x01f80000
-#define	AR5K_PHY_CCK_RX_CTL_4_FREQ_EST_SHORT_S	19
-
-#define	AR5K_PHY_DAG_CCK_CTL			0xa228
-#define	AR5K_PHY_DAG_CCK_CTL_EN_RSSI_THR	0x00000200
-#define	AR5K_PHY_DAG_CCK_CTL_RSSI_THR		0x0001fc00
-#define	AR5K_PHY_DAG_CCK_CTL_RSSI_THR_S		10
-
-#define	AR5K_PHY_FAST_ADC	0xa24c
-
-#define	AR5K_PHY_BLUETOOTH	0xa254
-
-/*
- * Transmit Power Control register
- * [2413+]
- */
-#define	AR5K_PHY_TPC_RG1		0xa258
-#define	AR5K_PHY_TPC_RG1_NUM_PD_GAIN	0x0000c000
-#define	AR5K_PHY_TPC_RG1_NUM_PD_GAIN_S	14
-#define AR5K_PHY_TPC_RG1_PDGAIN_1	0x00030000
-#define AR5K_PHY_TPC_RG1_PDGAIN_1_S	16
-#define AR5K_PHY_TPC_RG1_PDGAIN_2	0x000c0000
-#define AR5K_PHY_TPC_RG1_PDGAIN_2_S	18
-#define AR5K_PHY_TPC_RG1_PDGAIN_3	0x00300000
-#define AR5K_PHY_TPC_RG1_PDGAIN_3_S	20
-
-#define	AR5K_PHY_TPC_RG5			0xa26C
-#define	AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP	0x0000000F
-#define	AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP_S	0
-#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1	0x000003F0
-#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1_S	4
-#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2	0x0000FC00
-#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2_S	10
-#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3	0x003F0000
-#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3_S	16
-#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4	0x0FC00000
-#define	AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4_S	22
-
-/*
- * PHY PDADC Tx power table
- */
-#define AR5K_PHY_PDADC_TXPOWER_BASE	0xa280
-#define	AR5K_PHY_PDADC_TXPOWER(_n)	(AR5K_PHY_PDADC_TXPOWER_BASE + ((_n) << 2))
diff --git a/roms/ipxe/src/drivers/net/ath5k/rfbuffer.h b/roms/ipxe/src/drivers/net/ath5k/rfbuffer.h
deleted file mode 100644
index e50baff66175a969a36110b36256b31f59c7c195..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/rfbuffer.h
+++ /dev/null
@@ -1,1181 +0,0 @@
-/*
- * RF Buffer handling functions
- *
- * Copyright (c) 2009 Nick Kossifidis <mickflemm@gmail.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-
-/*
- * There are some special registers on the RF chip
- * that control various operation settings related mostly to
- * the analog parts (channel, gain adjustment etc).
- *
- * We don't write on those registers directly but
- * we send a data packet on the chip, using a special register,
- * that holds all the settings we need. After we 've sent the
- * data packet, we write on another special register to notify hw
- * to apply the settings. This is done so that control registers
- * can be dynamicaly programmed during operation and the settings
- * are applied faster on the hw.
- *
- * We call each data packet an "RF Bank" and all the data we write
- * (all RF Banks) "RF Buffer". This file holds initial RF Buffer
- * data for the different RF chips, and various info to match RF
- * Buffer offsets with specific RF registers so that we can access
- * them. We tweak these settings on rfregs_init function.
- *
- * Also check out reg.h and U.S. Patent 6677779 B1 (about buffer
- * registers and control registers):
- *
- * http://www.google.com/patents?id=qNURAAAAEBAJ
- */
-
-
-/*
- * Struct to hold default mode specific RF
- * register values (RF Banks)
- */
-struct ath5k_ini_rfbuffer {
-	u8	rfb_bank;		/* RF Bank number */
-	u16	rfb_ctrl_register;	/* RF Buffer control register */
-	u32	rfb_mode_data[5];	/* RF Buffer data for each mode */
-};
-
-/*
- * Struct to hold RF Buffer field
- * infos used to access certain RF
- * analog registers
- */
-struct ath5k_rfb_field {
-	u8	len;	/* Field length */
-	u16	pos;	/* Offset on the raw packet */
-	u8	col;	/* Column -used for shifting */
-};
-
-/*
- * RF analog register definition
- */
-struct ath5k_rf_reg {
-	u8			bank;	/* RF Buffer Bank number */
-	u8			index;	/* Register's index on rf_regs_idx */
-	struct ath5k_rfb_field	field;	/* RF Buffer field for this register */
-};
-
-/* Map RF registers to indexes
- * We do this to handle common bits and make our
- * life easier by using an index for each register
- * instead of a full rfb_field */
-enum ath5k_rf_regs_idx {
-	/* BANK 6 */
-	AR5K_RF_OB_2GHZ = 0,
-	AR5K_RF_OB_5GHZ,
-	AR5K_RF_DB_2GHZ,
-	AR5K_RF_DB_5GHZ,
-	AR5K_RF_FIXED_BIAS_A,
-	AR5K_RF_FIXED_BIAS_B,
-	AR5K_RF_PWD_XPD,
-	AR5K_RF_XPD_SEL,
-	AR5K_RF_XPD_GAIN,
-	AR5K_RF_PD_GAIN_LO,
-	AR5K_RF_PD_GAIN_HI,
-	AR5K_RF_HIGH_VC_CP,
-	AR5K_RF_MID_VC_CP,
-	AR5K_RF_LOW_VC_CP,
-	AR5K_RF_PUSH_UP,
-	AR5K_RF_PAD2GND,
-	AR5K_RF_XB2_LVL,
-	AR5K_RF_XB5_LVL,
-	AR5K_RF_PWD_ICLOBUF_2G,
-	AR5K_RF_PWD_84,
-	AR5K_RF_PWD_90,
-	AR5K_RF_PWD_130,
-	AR5K_RF_PWD_131,
-	AR5K_RF_PWD_132,
-	AR5K_RF_PWD_136,
-	AR5K_RF_PWD_137,
-	AR5K_RF_PWD_138,
-	AR5K_RF_PWD_166,
-	AR5K_RF_PWD_167,
-	AR5K_RF_DERBY_CHAN_SEL_MODE,
-	/* BANK 7 */
-	AR5K_RF_GAIN_I,
-	AR5K_RF_PLO_SEL,
-	AR5K_RF_RFGAIN_SEL,
-	AR5K_RF_RFGAIN_STEP,
-	AR5K_RF_WAIT_S,
-	AR5K_RF_WAIT_I,
-	AR5K_RF_MAX_TIME,
-	AR5K_RF_MIXVGA_OVR,
-	AR5K_RF_MIXGAIN_OVR,
-	AR5K_RF_MIXGAIN_STEP,
-	AR5K_RF_PD_DELAY_A,
-	AR5K_RF_PD_DELAY_B,
-	AR5K_RF_PD_DELAY_XR,
-	AR5K_RF_PD_PERIOD_A,
-	AR5K_RF_PD_PERIOD_B,
-	AR5K_RF_PD_PERIOD_XR,
-};
-
-
-/*******************\
-* RF5111 (Sombrero) *
-\*******************/
-
-/* BANK 6				len  pos col */
-#define	AR5K_RF5111_OB_2GHZ		{ 3, 119, 0 }
-#define	AR5K_RF5111_DB_2GHZ		{ 3, 122, 0 }
-
-#define	AR5K_RF5111_OB_5GHZ		{ 3, 104, 0 }
-#define	AR5K_RF5111_DB_5GHZ		{ 3, 107, 0 }
-
-#define	AR5K_RF5111_PWD_XPD		{ 1, 95,  0 }
-#define	AR5K_RF5111_XPD_GAIN		{ 4, 96,  0 }
-
-/* Access to PWD registers */
-#define AR5K_RF5111_PWD(_n)		{ 1, (135 - _n), 3 }
-
-/* BANK 7				len  pos col */
-#define	AR5K_RF5111_GAIN_I		{ 6, 29,  0 }
-#define	AR5K_RF5111_PLO_SEL		{ 1, 4,   0 }
-#define	AR5K_RF5111_RFGAIN_SEL		{ 1, 36,  0 }
-#define AR5K_RF5111_RFGAIN_STEP		{ 6, 37,  0 }
-/* Only on AR5212 BaseBand and up */
-#define	AR5K_RF5111_WAIT_S		{ 5, 19,  0 }
-#define	AR5K_RF5111_WAIT_I		{ 5, 24,  0 }
-#define	AR5K_RF5111_MAX_TIME		{ 2, 49,  0 }
-
-static const struct ath5k_rf_reg rf_regs_5111[] = {
-	{6, AR5K_RF_OB_2GHZ,		AR5K_RF5111_OB_2GHZ},
-	{6, AR5K_RF_DB_2GHZ,		AR5K_RF5111_DB_2GHZ},
-	{6, AR5K_RF_OB_5GHZ,		AR5K_RF5111_OB_5GHZ},
-	{6, AR5K_RF_DB_5GHZ,		AR5K_RF5111_DB_5GHZ},
-	{6, AR5K_RF_PWD_XPD,		AR5K_RF5111_PWD_XPD},
-	{6, AR5K_RF_XPD_GAIN,		AR5K_RF5111_XPD_GAIN},
-	{6, AR5K_RF_PWD_84,		AR5K_RF5111_PWD(84)},
-	{6, AR5K_RF_PWD_90,		AR5K_RF5111_PWD(90)},
-	{7, AR5K_RF_GAIN_I,		AR5K_RF5111_GAIN_I},
-	{7, AR5K_RF_PLO_SEL,		AR5K_RF5111_PLO_SEL},
-	{7, AR5K_RF_RFGAIN_SEL,		AR5K_RF5111_RFGAIN_SEL},
-	{7, AR5K_RF_RFGAIN_STEP,	AR5K_RF5111_RFGAIN_STEP},
-	{7, AR5K_RF_WAIT_S,		AR5K_RF5111_WAIT_S},
-	{7, AR5K_RF_WAIT_I,		AR5K_RF5111_WAIT_I},
-	{7, AR5K_RF_MAX_TIME,		AR5K_RF5111_MAX_TIME}
-};
-
-/* Default mode specific settings */
-static const struct ath5k_ini_rfbuffer rfb_5111[] = {
-	{ 0, 0x989c,
-	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0, 0x989c,
-	    { 0x00380000, 0x00380000, 0x00380000, 0x00380000, 0x00380000 } },
-	{ 0, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 0, 0x989c,
-	    { 0x00000000, 0x00000000, 0x000000c0, 0x00000080, 0x00000080 } },
-	{ 0, 0x989c,
-	    { 0x000400f9, 0x000400f9, 0x000400ff, 0x000400fd, 0x000400fd } },
-	{ 0, 0x98d4,
-	    { 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000004 } },
-	{ 1, 0x98d4,
-	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-	{ 2, 0x98d4,
-	    { 0x00000010, 0x00000014, 0x00000010, 0x00000010, 0x00000014 } },
-	{ 3, 0x98d8,
-	    { 0x00601068, 0x00601068, 0x00601068, 0x00601068, 0x00601068 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
-	{ 6, 0x989c,
-	    { 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x0a000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x003800c0, 0x00380080, 0x023800c0, 0x003800c0, 0x003800c0 } },
-	{ 6, 0x989c,
-	    { 0x00020006, 0x00020006, 0x00000006, 0x00020006, 0x00020006 } },
-	{ 6, 0x989c,
-	    { 0x00000089, 0x00000089, 0x00000089, 0x00000089, 0x00000089 } },
-	{ 6, 0x989c,
-	    { 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0 } },
-	{ 6, 0x989c,
-	    { 0x00040007, 0x00040007, 0x00040007, 0x00040007, 0x00040007 } },
-	{ 6, 0x98d4,
-	    { 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a } },
-	{ 7, 0x989c,
-	    { 0x00000040, 0x00000048, 0x00000040, 0x00000040, 0x00000040 } },
-	{ 7, 0x989c,
-	    { 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } },
-	{ 7, 0x989c,
-	    { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
-	{ 7, 0x989c,
-	    { 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f } },
-	{ 7, 0x989c,
-	    { 0x000000f1, 0x000000f1, 0x00000061, 0x000000f1, 0x000000f1 } },
-	{ 7, 0x989c,
-	    { 0x0000904f, 0x0000904f, 0x0000904c, 0x0000904f, 0x0000904f } },
-	{ 7, 0x989c,
-	    { 0x0000125a, 0x0000125a, 0x0000129a, 0x0000125a, 0x0000125a } },
-	{ 7, 0x98cc,
-	    { 0x0000000e, 0x0000000e, 0x0000000f, 0x0000000e, 0x0000000e } },
-};
-
-
-
-/***********************\
-* RF5112/RF2112 (Derby) *
-\***********************/
-
-/* BANK 7 (Common)			len  pos col */
-#define	AR5K_RF5112X_GAIN_I		{ 6, 14,  0 }
-#define	AR5K_RF5112X_MIXVGA_OVR		{ 1, 36,  0 }
-#define	AR5K_RF5112X_MIXGAIN_OVR	{ 2, 37,  0 }
-#define AR5K_RF5112X_MIXGAIN_STEP	{ 4, 32,  0 }
-#define	AR5K_RF5112X_PD_DELAY_A		{ 4, 58,  0 }
-#define	AR5K_RF5112X_PD_DELAY_B		{ 4, 62,  0 }
-#define	AR5K_RF5112X_PD_DELAY_XR	{ 4, 66,  0 }
-#define	AR5K_RF5112X_PD_PERIOD_A	{ 4, 70,  0 }
-#define	AR5K_RF5112X_PD_PERIOD_B	{ 4, 74,  0 }
-#define	AR5K_RF5112X_PD_PERIOD_XR	{ 4, 78,  0 }
-
-/* RFX112 (Derby 1) */
-
-/* BANK 6 				len  pos col */
-#define	AR5K_RF5112_OB_2GHZ		{ 3, 269, 0 }
-#define	AR5K_RF5112_DB_2GHZ		{ 3, 272, 0 }
-
-#define	AR5K_RF5112_OB_5GHZ		{ 3, 261, 0 }
-#define	AR5K_RF5112_DB_5GHZ		{ 3, 264, 0 }
-
-#define	AR5K_RF5112_FIXED_BIAS_A	{ 1, 260, 0 }
-#define	AR5K_RF5112_FIXED_BIAS_B	{ 1, 259, 0 }
-
-#define	AR5K_RF5112_XPD_SEL		{ 1, 284, 0 }
-#define	AR5K_RF5112_XPD_GAIN		{ 2, 252, 0 }
-
-/* Access to PWD registers */
-#define AR5K_RF5112_PWD(_n)		{ 1, (302 - _n), 3 }
-
-static const struct ath5k_rf_reg rf_regs_5112[] = {
-	{6, AR5K_RF_OB_2GHZ,		AR5K_RF5112_OB_2GHZ},
-	{6, AR5K_RF_DB_2GHZ,		AR5K_RF5112_DB_2GHZ},
-	{6, AR5K_RF_OB_5GHZ,		AR5K_RF5112_OB_5GHZ},
-	{6, AR5K_RF_DB_5GHZ,		AR5K_RF5112_DB_5GHZ},
-	{6, AR5K_RF_FIXED_BIAS_A,	AR5K_RF5112_FIXED_BIAS_A},
-	{6, AR5K_RF_FIXED_BIAS_B,	AR5K_RF5112_FIXED_BIAS_B},
-	{6, AR5K_RF_XPD_SEL,		AR5K_RF5112_XPD_SEL},
-	{6, AR5K_RF_XPD_GAIN,		AR5K_RF5112_XPD_GAIN},
-	{6, AR5K_RF_PWD_130,		AR5K_RF5112_PWD(130)},
-	{6, AR5K_RF_PWD_131,		AR5K_RF5112_PWD(131)},
-	{6, AR5K_RF_PWD_132,		AR5K_RF5112_PWD(132)},
-	{6, AR5K_RF_PWD_136,		AR5K_RF5112_PWD(136)},
-	{6, AR5K_RF_PWD_137,		AR5K_RF5112_PWD(137)},
-	{6, AR5K_RF_PWD_138,		AR5K_RF5112_PWD(138)},
-	{7, AR5K_RF_GAIN_I,		AR5K_RF5112X_GAIN_I},
-	{7, AR5K_RF_MIXVGA_OVR,		AR5K_RF5112X_MIXVGA_OVR},
-	{7, AR5K_RF_MIXGAIN_OVR,	AR5K_RF5112X_MIXGAIN_OVR},
-	{7, AR5K_RF_MIXGAIN_STEP,	AR5K_RF5112X_MIXGAIN_STEP},
-	{7, AR5K_RF_PD_DELAY_A,		AR5K_RF5112X_PD_DELAY_A},
-	{7, AR5K_RF_PD_DELAY_B,		AR5K_RF5112X_PD_DELAY_B},
-	{7, AR5K_RF_PD_DELAY_XR,	AR5K_RF5112X_PD_DELAY_XR},
-	{7, AR5K_RF_PD_PERIOD_A,	AR5K_RF5112X_PD_PERIOD_A},
-	{7, AR5K_RF_PD_PERIOD_B,	AR5K_RF5112X_PD_PERIOD_B},
-	{7, AR5K_RF_PD_PERIOD_XR,	AR5K_RF5112X_PD_PERIOD_XR},
-};
-
-/* Default mode specific settings */
-static const struct ath5k_ini_rfbuffer rfb_5112[] = {
-	{ 1, 0x98d4,
-	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-	{ 2, 0x98d0,
-	    { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
-	{ 3, 0x98dc,
-	    { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } },
-	{ 6, 0x989c,
-	    { 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000 } },
-	{ 6, 0x989c,
-	    { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00660000, 0x00660000, 0x00660000, 0x00660000, 0x00660000 } },
-	{ 6, 0x989c,
-	    { 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000 } },
-	{ 6, 0x989c,
-	    { 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000 } },
-	{ 6, 0x989c,
-	    { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
-	{ 6, 0x989c,
-	    { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
-	{ 6, 0x989c,
-	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
-	{ 6, 0x989c,
-	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
-	{ 6, 0x989c,
-	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
-	{ 6, 0x989c,
-	    { 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000 } },
-	{ 6, 0x989c,
-	    { 0x00600000, 0x00600000, 0x00600000, 0x00600000, 0x00600000 } },
-	{ 6, 0x989c,
-	    { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
-	{ 6, 0x989c,
-	    { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
-	{ 6, 0x989c,
-	    { 0x00640000, 0x00640000, 0x00640000, 0x00640000, 0x00640000 } },
-	{ 6, 0x989c,
-	    { 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000 } },
-	{ 6, 0x989c,
-	    { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
-	{ 6, 0x989c,
-	    { 0x00250000, 0x00250000, 0x00250000, 0x00250000, 0x00250000 } },
-	{ 6, 0x989c,
-	    { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
-	{ 6, 0x989c,
-	    { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
-	{ 6, 0x989c,
-	    { 0x00510000, 0x00510000, 0x00510000, 0x00510000, 0x00510000 } },
-	{ 6, 0x989c,
-	    { 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000 } },
-	{ 6, 0x989c,
-	    { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
-	{ 6, 0x989c,
-	    { 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000 } },
-	{ 6, 0x989c,
-	    { 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000 } },
-	{ 6, 0x989c,
-	    { 0x03090000, 0x03090000, 0x03090000, 0x03090000, 0x03090000 } },
-	{ 6, 0x989c,
-	    { 0x06000000, 0x06000000, 0x06000000, 0x06000000, 0x06000000 } },
-	{ 6, 0x989c,
-	    { 0x000000b0, 0x000000b0, 0x000000a8, 0x000000a8, 0x000000a8 } },
-	{ 6, 0x989c,
-	    { 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e } },
-	{ 6, 0x989c,
-	    { 0x006c4a41, 0x006c4a41, 0x006c4af1, 0x006c4a61, 0x006c4a61 } },
-	{ 6, 0x989c,
-	    { 0x0050892a, 0x0050892a, 0x0050892b, 0x0050892b, 0x0050892b } },
-	{ 6, 0x989c,
-	    { 0x00842400, 0x00842400, 0x00842400, 0x00842400, 0x00842400 } },
-	{ 6, 0x989c,
-	    { 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200 } },
-	{ 6, 0x98d0,
-	    { 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c } },
-	{ 7, 0x989c,
-	    { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
-	{ 7, 0x989c,
-	    { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
-	{ 7, 0x989c,
-	    { 0x0000000a, 0x0000000a, 0x00000012, 0x00000012, 0x00000012 } },
-	{ 7, 0x989c,
-	    { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
-	{ 7, 0x989c,
-	    { 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1 } },
-	{ 7, 0x989c,
-	    { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
-	{ 7, 0x989c,
-	    { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
-	{ 7, 0x989c,
-	    { 0x00000022, 0x00000022, 0x00000022, 0x00000022, 0x00000022 } },
-	{ 7, 0x989c,
-	    { 0x00000092, 0x00000092, 0x00000092, 0x00000092, 0x00000092 } },
-	{ 7, 0x989c,
-	    { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
-	{ 7, 0x989c,
-	    { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
-	{ 7, 0x989c,
-	    { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
-	{ 7, 0x98c4,
-	    { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
-};
-
-/* RFX112A (Derby 2) */
-
-/* BANK 6				len  pos col */
-#define	AR5K_RF5112A_OB_2GHZ		{ 3, 287, 0 }
-#define	AR5K_RF5112A_DB_2GHZ		{ 3, 290, 0 }
-
-#define	AR5K_RF5112A_OB_5GHZ		{ 3, 279, 0 }
-#define	AR5K_RF5112A_DB_5GHZ		{ 3, 282, 0 }
-
-#define	AR5K_RF5112A_FIXED_BIAS_A	{ 1, 278, 0 }
-#define	AR5K_RF5112A_FIXED_BIAS_B	{ 1, 277, 0 }
-
-#define	AR5K_RF5112A_XPD_SEL		{ 1, 302, 0 }
-#define	AR5K_RF5112A_PDGAINLO		{ 2, 270, 0 }
-#define	AR5K_RF5112A_PDGAINHI		{ 2, 257, 0 }
-
-/* Access to PWD registers */
-#define AR5K_RF5112A_PWD(_n)		{ 1, (306 - _n), 3 }
-
-/* Voltage regulators */
-#define	AR5K_RF5112A_HIGH_VC_CP		{ 2, 90,  2 }
-#define	AR5K_RF5112A_MID_VC_CP		{ 2, 92,  2 }
-#define	AR5K_RF5112A_LOW_VC_CP		{ 2, 94,  2 }
-#define	AR5K_RF5112A_PUSH_UP		{ 1, 254,  2 }
-
-/* Power consumption */
-#define	AR5K_RF5112A_PAD2GND		{ 1, 281, 1 }
-#define	AR5K_RF5112A_XB2_LVL		{ 2, 1,	  3 }
-#define	AR5K_RF5112A_XB5_LVL		{ 2, 3,	  3 }
-
-static const struct ath5k_rf_reg rf_regs_5112a[] = {
-	{6, AR5K_RF_OB_2GHZ,		AR5K_RF5112A_OB_2GHZ},
-	{6, AR5K_RF_DB_2GHZ,		AR5K_RF5112A_DB_2GHZ},
-	{6, AR5K_RF_OB_5GHZ,		AR5K_RF5112A_OB_5GHZ},
-	{6, AR5K_RF_DB_5GHZ,		AR5K_RF5112A_DB_5GHZ},
-	{6, AR5K_RF_FIXED_BIAS_A,	AR5K_RF5112A_FIXED_BIAS_A},
-	{6, AR5K_RF_FIXED_BIAS_B,	AR5K_RF5112A_FIXED_BIAS_B},
-	{6, AR5K_RF_XPD_SEL,		AR5K_RF5112A_XPD_SEL},
-	{6, AR5K_RF_PD_GAIN_LO,		AR5K_RF5112A_PDGAINLO},
-	{6, AR5K_RF_PD_GAIN_HI,		AR5K_RF5112A_PDGAINHI},
-	{6, AR5K_RF_PWD_130,		AR5K_RF5112A_PWD(130)},
-	{6, AR5K_RF_PWD_131,		AR5K_RF5112A_PWD(131)},
-	{6, AR5K_RF_PWD_132,		AR5K_RF5112A_PWD(132)},
-	{6, AR5K_RF_PWD_136,		AR5K_RF5112A_PWD(136)},
-	{6, AR5K_RF_PWD_137,		AR5K_RF5112A_PWD(137)},
-	{6, AR5K_RF_PWD_138,		AR5K_RF5112A_PWD(138)},
-	{6, AR5K_RF_PWD_166,		AR5K_RF5112A_PWD(166)},
-	{6, AR5K_RF_PWD_167,		AR5K_RF5112A_PWD(167)},
-	{6, AR5K_RF_HIGH_VC_CP,		AR5K_RF5112A_HIGH_VC_CP},
-	{6, AR5K_RF_MID_VC_CP,		AR5K_RF5112A_MID_VC_CP},
-	{6, AR5K_RF_LOW_VC_CP,		AR5K_RF5112A_LOW_VC_CP},
-	{6, AR5K_RF_PUSH_UP,		AR5K_RF5112A_PUSH_UP},
-	{6, AR5K_RF_PAD2GND,		AR5K_RF5112A_PAD2GND},
-	{6, AR5K_RF_XB2_LVL,		AR5K_RF5112A_XB2_LVL},
-	{6, AR5K_RF_XB5_LVL,		AR5K_RF5112A_XB5_LVL},
-	{7, AR5K_RF_GAIN_I,		AR5K_RF5112X_GAIN_I},
-	{7, AR5K_RF_MIXVGA_OVR,		AR5K_RF5112X_MIXVGA_OVR},
-	{7, AR5K_RF_MIXGAIN_OVR,	AR5K_RF5112X_MIXGAIN_OVR},
-	{7, AR5K_RF_MIXGAIN_STEP,	AR5K_RF5112X_MIXGAIN_STEP},
-	{7, AR5K_RF_PD_DELAY_A,		AR5K_RF5112X_PD_DELAY_A},
-	{7, AR5K_RF_PD_DELAY_B,		AR5K_RF5112X_PD_DELAY_B},
-	{7, AR5K_RF_PD_DELAY_XR,	AR5K_RF5112X_PD_DELAY_XR},
-	{7, AR5K_RF_PD_PERIOD_A,	AR5K_RF5112X_PD_PERIOD_A},
-	{7, AR5K_RF_PD_PERIOD_B,	AR5K_RF5112X_PD_PERIOD_B},
-	{7, AR5K_RF_PD_PERIOD_XR,	AR5K_RF5112X_PD_PERIOD_XR},
-};
-
-/* Default mode specific settings */
-static const struct ath5k_ini_rfbuffer rfb_5112a[] = {
-	{ 1, 0x98d4,
-	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-	{ 2, 0x98d0,
-	    { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
-	{ 3, 0x98dc,
-	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
-	{ 6, 0x989c,
-	    { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000 } },
-	{ 6, 0x989c,
-	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
-	{ 6, 0x989c,
-	    { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00180000, 0x00180000, 0x00180000, 0x00180000, 0x00180000 } },
-	{ 6, 0x989c,
-	    { 0x00600000, 0x00600000, 0x006e0000, 0x006e0000, 0x006e0000 } },
-	{ 6, 0x989c,
-	    { 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000 } },
-	{ 6, 0x989c,
-	    { 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000 } },
-	{ 6, 0x989c,
-	    { 0x04480000, 0x04480000, 0x04480000, 0x04480000, 0x04480000 } },
-	{ 6, 0x989c,
-	    { 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000 } },
-	{ 6, 0x989c,
-	    { 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000 } },
-	{ 6, 0x989c,
-	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
-	{ 6, 0x989c,
-	    { 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000 } },
-	{ 6, 0x989c,
-	    { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
-	{ 6, 0x989c,
-	    { 0x02190000, 0x02190000, 0x02190000, 0x02190000, 0x02190000 } },
-	{ 6, 0x989c,
-	    { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
-	{ 6, 0x989c,
-	    { 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000 } },
-	{ 6, 0x989c,
-	    { 0x00990000, 0x00990000, 0x00990000, 0x00990000, 0x00990000 } },
-	{ 6, 0x989c,
-	    { 0x00500000, 0x00500000, 0x00500000, 0x00500000, 0x00500000 } },
-	{ 6, 0x989c,
-	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
-	{ 6, 0x989c,
-	    { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
-	{ 6, 0x989c,
-	    { 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000 } },
-	{ 6, 0x989c,
-	    { 0x01740000, 0x01740000, 0x01740000, 0x01740000, 0x01740000 } },
-	{ 6, 0x989c,
-	    { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
-	{ 6, 0x989c,
-	    { 0x86280000, 0x86280000, 0x86280000, 0x86280000, 0x86280000 } },
-	{ 6, 0x989c,
-	    { 0x31840000, 0x31840000, 0x31840000, 0x31840000, 0x31840000 } },
-	{ 6, 0x989c,
-	    { 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080 } },
-	{ 6, 0x989c,
-	    { 0x00270019, 0x00270019, 0x00270019, 0x00270019, 0x00270019 } },
-	{ 6, 0x989c,
-	    { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2 } },
-	{ 6, 0x989c,
-	    { 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084 } },
-	{ 6, 0x989c,
-	    { 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4 } },
-	{ 6, 0x989c,
-	    { 0x00119220, 0x00119220, 0x00119220, 0x00119220, 0x00119220 } },
-	{ 6, 0x989c,
-	    { 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800 } },
-	{ 6, 0x98d8,
-	    { 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230 } },
-	{ 7, 0x989c,
-	    { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
-	{ 7, 0x989c,
-	    { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
-	{ 7, 0x989c,
-	    { 0x00000012, 0x00000012, 0x00000012, 0x00000012, 0x00000012 } },
-	{ 7, 0x989c,
-	    { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
-	{ 7, 0x989c,
-	    { 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9 } },
-	{ 7, 0x989c,
-	    { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
-	{ 7, 0x989c,
-	    { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
-	{ 7, 0x989c,
-	    { 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2 } },
-	{ 7, 0x989c,
-	    { 0x00000052, 0x00000052, 0x00000052, 0x00000052, 0x00000052 } },
-	{ 7, 0x989c,
-	    { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
-	{ 7, 0x989c,
-	    { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
-	{ 7, 0x989c,
-	    { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
-	{ 7, 0x98c4,
-	    { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
-};
-
-
-
-/******************\
-* RF2413 (Griffin) *
-\******************/
-
-/* BANK 6 				len  pos col */
-#define	AR5K_RF2413_OB_2GHZ		{ 3, 168, 0 }
-#define	AR5K_RF2413_DB_2GHZ		{ 3, 165, 0 }
-
-static const struct ath5k_rf_reg rf_regs_2413[] = {
-	{6, AR5K_RF_OB_2GHZ,		AR5K_RF2413_OB_2GHZ},
-	{6, AR5K_RF_DB_2GHZ,		AR5K_RF2413_DB_2GHZ},
-};
-
-/* Default mode specific settings
- * XXX: a/aTurbo ???
- */
-static const struct ath5k_ini_rfbuffer rfb_2413[] = {
-	{ 1, 0x98d4,
-	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-	{ 2, 0x98d0,
-	    { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
-	{ 3, 0x98dc,
-	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
-	{ 6, 0x989c,
-	    { 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x40400000, 0x40400000, 0x40400000, 0x40400000, 0x40400000 } },
-	{ 6, 0x989c,
-	    { 0x65050000, 0x65050000, 0x65050000, 0x65050000, 0x65050000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00420000, 0x00420000, 0x00420000, 0x00420000, 0x00420000 } },
-	{ 6, 0x989c,
-	    { 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000 } },
-	{ 6, 0x989c,
-	    { 0x00030000, 0x00030000, 0x00030000, 0x00030000, 0x00030000 } },
-	{ 6, 0x989c,
-	    { 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000 } },
-	{ 6, 0x989c,
-	    { 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000 } },
-	{ 6, 0x989c,
-	    { 0x00220000, 0x00220000, 0x00220000, 0x00220000, 0x00220000 } },
-	{ 6, 0x989c,
-	    { 0x04220000, 0x04220000, 0x04220000, 0x04220000, 0x04220000 } },
-	{ 6, 0x989c,
-	    { 0x00230018, 0x00230018, 0x00230018, 0x00230018, 0x00230018 } },
-	{ 6, 0x989c,
-	    { 0x00280000, 0x00280000, 0x00280060, 0x00280060, 0x00280060 } },
-	{ 6, 0x989c,
-	    { 0x005000c0, 0x005000c0, 0x005000c3, 0x005000c3, 0x005000c3 } },
-	{ 6, 0x989c,
-	    { 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f } },
-	{ 6, 0x989c,
-	    { 0x00000458, 0x00000458, 0x00000458, 0x00000458, 0x00000458 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000 } },
-	{ 6, 0x98d8,
-	    { 0x00400230, 0x00400230, 0x00400230, 0x00400230, 0x00400230 } },
-	{ 7, 0x989c,
-	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
-	{ 7, 0x989c,
-	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
-	{ 7, 0x98cc,
-	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
-};
-
-
-
-/***************************\
-* RF2315/RF2316 (Cobra SoC) *
-\***************************/
-
-/* BANK 6				len  pos col */
-#define	AR5K_RF2316_OB_2GHZ		{ 3, 178, 0 }
-#define	AR5K_RF2316_DB_2GHZ		{ 3, 175, 0 }
-
-static const struct ath5k_rf_reg rf_regs_2316[] = {
-	{6, AR5K_RF_OB_2GHZ,		AR5K_RF2316_OB_2GHZ},
-	{6, AR5K_RF_DB_2GHZ,		AR5K_RF2316_DB_2GHZ},
-};
-
-/* Default mode specific settings */
-static const struct ath5k_ini_rfbuffer rfb_2316[] = {
-	{ 1, 0x98d4,
-	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-	{ 2, 0x98d0,
-	    { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
-	{ 3, 0x98dc,
-	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000 } },
-	{ 6, 0x989c,
-	    { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } },
-	{ 6, 0x989c,
-	    { 0x02000000, 0x02000000, 0x02000000, 0x02000000, 0x02000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x95150000, 0x95150000, 0x95150000, 0x95150000, 0x95150000 } },
-	{ 6, 0x989c,
-	    { 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00080000, 0x00080000, 0x00080000, 0x00080000, 0x00080000 } },
-	{ 6, 0x989c,
-	    { 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000 } },
-	{ 6, 0x989c,
-	    { 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000 } },
-	{ 6, 0x989c,
-	    { 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000 } },
-	{ 6, 0x989c,
-	    { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } },
-	{ 6, 0x989c,
-	    { 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000 } },
-	{ 6, 0x989c,
-	    { 0x10880000, 0x10880000, 0x10880000, 0x10880000, 0x10880000 } },
-	{ 6, 0x989c,
-	    { 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060 } },
-	{ 6, 0x989c,
-	    { 0x00a00000, 0x00a00000, 0x00a00080, 0x00a00080, 0x00a00080 } },
-	{ 6, 0x989c,
-	    { 0x00400000, 0x00400000, 0x0040000d, 0x0040000d, 0x0040000d } },
-	{ 6, 0x989c,
-	    { 0x00110400, 0x00110400, 0x00110400, 0x00110400, 0x00110400 } },
-	{ 6, 0x989c,
-	    { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
-	{ 6, 0x989c,
-	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
-	{ 6, 0x989c,
-	    { 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00 } },
-	{ 6, 0x989c,
-	    { 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8 } },
-	{ 6, 0x98c0,
-	    { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } },
-	{ 7, 0x989c,
-	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
-	{ 7, 0x989c,
-	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
-	{ 7, 0x98cc,
-	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
-};
-
-
-
-/******************************\
-* RF5413/RF5424 (Eagle/Condor) *
-\******************************/
-
-/* BANK 6				len  pos col */
-#define	AR5K_RF5413_OB_2GHZ		{ 3, 241, 0 }
-#define	AR5K_RF5413_DB_2GHZ		{ 3, 238, 0 }
-
-#define	AR5K_RF5413_OB_5GHZ		{ 3, 247, 0 }
-#define	AR5K_RF5413_DB_5GHZ		{ 3, 244, 0 }
-
-#define	AR5K_RF5413_PWD_ICLOBUF2G	{ 3, 131, 3 }
-#define	AR5K_RF5413_DERBY_CHAN_SEL_MODE	{ 1, 291, 2 }
-
-static const struct ath5k_rf_reg rf_regs_5413[] = {
-	{6, AR5K_RF_OB_2GHZ,		 AR5K_RF5413_OB_2GHZ},
-	{6, AR5K_RF_DB_2GHZ,		 AR5K_RF5413_DB_2GHZ},
-	{6, AR5K_RF_OB_5GHZ,		 AR5K_RF5413_OB_5GHZ},
-	{6, AR5K_RF_DB_5GHZ,		 AR5K_RF5413_DB_5GHZ},
-	{6, AR5K_RF_PWD_ICLOBUF_2G,	 AR5K_RF5413_PWD_ICLOBUF2G},
-	{6, AR5K_RF_DERBY_CHAN_SEL_MODE, AR5K_RF5413_DERBY_CHAN_SEL_MODE},
-};
-
-/* Default mode specific settings */
-static const struct ath5k_ini_rfbuffer rfb_5413[] = {
-	{ 1, 0x98d4,
-	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-	{ 2, 0x98d0,
-	    { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
-	{ 3, 0x98dc,
-	    { 0x00a000c0, 0x00a000c0, 0x00e000c0, 0x00e000c0, 0x00e000c0 } },
-	{ 6, 0x989c,
-	    { 0x33000000, 0x33000000, 0x33000000, 0x33000000, 0x33000000 } },
-	{ 6, 0x989c,
-	    { 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000 } },
-	{ 6, 0x989c,
-	    { 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000 } },
-	{ 6, 0x989c,
-	    { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
-	{ 6, 0x989c,
-	    { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
-	{ 6, 0x989c,
-	    { 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000 } },
-	{ 6, 0x989c,
-	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
-	{ 6, 0x989c,
-	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
-	{ 6, 0x989c,
-	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
-	{ 6, 0x989c,
-	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
-	{ 6, 0x989c,
-	    { 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000 } },
-	{ 6, 0x989c,
-	    { 0x00610000, 0x00610000, 0x00610000, 0x00610000, 0x00610000 } },
-	{ 6, 0x989c,
-	    { 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000 } },
-	{ 6, 0x989c,
-	    { 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000 } },
-	{ 6, 0x989c,
-	    { 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000 } },
-	{ 6, 0x989c,
-	    { 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000 } },
-	{ 6, 0x989c,
-	    { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } },
-	{ 6, 0x989c,
-	    { 0x00440000, 0x00440000, 0x00440000, 0x00440000, 0x00440000 } },
-	{ 6, 0x989c,
-	    { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
-	{ 6, 0x989c,
-	    { 0x00100080, 0x00100080, 0x00100080, 0x00100080, 0x00100080 } },
-	{ 6, 0x989c,
-	    { 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034 } },
-	{ 6, 0x989c,
-	    { 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0 } },
-	{ 6, 0x989c,
-	    { 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f } },
-	{ 6, 0x989c,
-	    { 0x00510040, 0x00510040, 0x00510040, 0x00510040, 0x00510040 } },
-	{ 6, 0x989c,
-	    { 0x005000da, 0x005000da, 0x005000da, 0x005000da, 0x005000da } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00004044, 0x00004044, 0x00004044, 0x00004044, 0x00004044 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0 } },
-	{ 6, 0x989c,
-	    { 0x00002c00, 0x00002c00, 0x00003600, 0x00003600, 0x00002c00 } },
-	{ 6, 0x98c8,
-	    { 0x00000403, 0x00000403, 0x00040403, 0x00040403, 0x00040403 } },
-	{ 7, 0x989c,
-	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
-	{ 7, 0x989c,
-	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
-	{ 7, 0x98cc,
-	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
-};
-
-
-
-/***************************\
-* RF2425/RF2417 (Swan/Nala) *
-* AR2317 (Spider SoC)       *
-\***************************/
-
-/* BANK 6				len  pos col */
-#define	AR5K_RF2425_OB_2GHZ		{ 3, 193, 0 }
-#define	AR5K_RF2425_DB_2GHZ		{ 3, 190, 0 }
-
-static const struct ath5k_rf_reg rf_regs_2425[] = {
-	{6, AR5K_RF_OB_2GHZ,		AR5K_RF2425_OB_2GHZ},
-	{6, AR5K_RF_DB_2GHZ,		AR5K_RF2425_DB_2GHZ},
-};
-
-/* Default mode specific settings
- * XXX: a/aTurbo ?
- */
-static const struct ath5k_ini_rfbuffer rfb_2425[] = {
-	{ 1, 0x98d4,
-	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-	{ 2, 0x98d0,
-	    { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } },
-	{ 3, 0x98dc,
-	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
-	{ 6, 0x989c,
-	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
-	{ 6, 0x989c,
-	    { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
-	{ 6, 0x989c,
-	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
-	{ 6, 0x989c,
-	    { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
-	{ 6, 0x989c,
-	    { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } },
-	{ 6, 0x989c,
-	    { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } },
-	{ 6, 0x989c,
-	    { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
-	{ 6, 0x989c,
-	    { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } },
-	{ 6, 0x989c,
-	    { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
-	{ 6, 0x989c,
-	    { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
-	{ 6, 0x989c,
-	    { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
-	{ 6, 0x989c,
-	    { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } },
-	{ 6, 0x98c4,
-	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
-	{ 7, 0x989c,
-	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
-	{ 7, 0x989c,
-	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
-	{ 7, 0x98cc,
-	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
-};
-
-/*
- * TODO: Handle the few differences with swan during
- * bank modification and get rid of this
- */
-static const struct ath5k_ini_rfbuffer rfb_2317[] = {
-	{ 1, 0x98d4,
-	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-	{ 2, 0x98d0,
-	    { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
-	{ 3, 0x98dc,
-	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
-	{ 6, 0x989c,
-	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
-	{ 6, 0x989c,
-	    { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
-	{ 6, 0x989c,
-	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
-	{ 6, 0x989c,
-	    { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
-	{ 6, 0x989c,
-	    { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } },
-	{ 6, 0x989c,
-	    { 0x00140100, 0x00140100, 0x00140100, 0x00140100, 0x00140100 } },
-	{ 6, 0x989c,
-	    { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
-	{ 6, 0x989c,
-	    { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } },
-	{ 6, 0x989c,
-	    { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
-	{ 6, 0x989c,
-	    { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
-	{ 6, 0x989c,
-	    { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
-	{ 6, 0x989c,
-	    { 0x00009688, 0x00009688, 0x00009688, 0x00009688, 0x00009688 } },
-	{ 6, 0x98c4,
-	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
-	{ 7, 0x989c,
-	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
-	{ 7, 0x989c,
-	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
-	{ 7, 0x98cc,
-	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
-};
-
-/*
- * TODO: Handle the few differences with swan during
- * bank modification and get rid of this
- * XXX: a/aTurbo ?
- */
-static const struct ath5k_ini_rfbuffer rfb_2417[] = {
-	{ 1, 0x98d4,
-	/*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-	{ 2, 0x98d0,
-	    { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } },
-	{ 3, 0x98dc,
-	    { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
-	{ 6, 0x989c,
-	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
-	{ 6, 0x989c,
-	    { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
-	{ 6, 0x989c,
-	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
-	{ 6, 0x989c,
-	    { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
-	{ 6, 0x989c,
-	    { 0x00e70000, 0x00e70000, 0x80e70000, 0x80e70000, 0x00e70000 } },
-	{ 6, 0x989c,
-	    { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } },
-	{ 6, 0x989c,
-	    { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
-	{ 6, 0x989c,
-	    { 0x0007001a, 0x0007001a, 0x0207001a, 0x0207001a, 0x0007001a } },
-	{ 6, 0x989c,
-	    { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
-	{ 6, 0x989c,
-	    { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
-	{ 6, 0x989c,
-	    { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-	{ 6, 0x989c,
-	    { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
-	{ 6, 0x989c,
-	    { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } },
-	{ 6, 0x98c4,
-	    { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
-	{ 7, 0x989c,
-	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
-	{ 7, 0x989c,
-	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
-	{ 7, 0x98cc,
-	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
-};
diff --git a/roms/ipxe/src/drivers/net/ath5k/rfgain.h b/roms/ipxe/src/drivers/net/ath5k/rfgain.h
deleted file mode 100644
index 1354d8c392c814f14c72d1b4e8b1f202b2d366a0..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ath5k/rfgain.h
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * RF Gain optimization
- *
- * Copyright (c) 2004-2009 Reyk Floeter <reyk@openbsd.org>
- * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- */
-
-/*
- * Mode-specific RF Gain table (64bytes) for RF5111/5112
- * (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial
- * RF Gain values are included in AR5K_AR5210_INI)
- */
-struct ath5k_ini_rfgain {
-	u16	rfg_register;	/* RF Gain register address */
-	u32	rfg_value[2];	/* [freq (see below)] */
-};
-
-/* Initial RF Gain settings for RF5111 */
-static const struct ath5k_ini_rfgain rfgain_5111[] = {
-	/*			      5Ghz	2Ghz	*/
-	{ AR5K_RF_GAIN(0),	{ 0x000001a9, 0x00000000 } },
-	{ AR5K_RF_GAIN(1),	{ 0x000001e9, 0x00000040 } },
-	{ AR5K_RF_GAIN(2),	{ 0x00000029, 0x00000080 } },
-	{ AR5K_RF_GAIN(3),	{ 0x00000069, 0x00000150 } },
-	{ AR5K_RF_GAIN(4),	{ 0x00000199, 0x00000190 } },
-	{ AR5K_RF_GAIN(5),	{ 0x000001d9, 0x000001d0 } },
-	{ AR5K_RF_GAIN(6),	{ 0x00000019, 0x00000010 } },
-	{ AR5K_RF_GAIN(7),	{ 0x00000059, 0x00000044 } },
-	{ AR5K_RF_GAIN(8),	{ 0x00000099, 0x00000084 } },
-	{ AR5K_RF_GAIN(9),	{ 0x000001a5, 0x00000148 } },
-	{ AR5K_RF_GAIN(10),	{ 0x000001e5, 0x00000188 } },
-	{ AR5K_RF_GAIN(11),	{ 0x00000025, 0x000001c8 } },
-	{ AR5K_RF_GAIN(12),	{ 0x000001c8, 0x00000014 } },
-	{ AR5K_RF_GAIN(13),	{ 0x00000008, 0x00000042 } },
-	{ AR5K_RF_GAIN(14),	{ 0x00000048, 0x00000082 } },
-	{ AR5K_RF_GAIN(15),	{ 0x00000088, 0x00000178 } },
-	{ AR5K_RF_GAIN(16),	{ 0x00000198, 0x000001b8 } },
-	{ AR5K_RF_GAIN(17),	{ 0x000001d8, 0x000001f8 } },
-	{ AR5K_RF_GAIN(18),	{ 0x00000018, 0x00000012 } },
-	{ AR5K_RF_GAIN(19),	{ 0x00000058, 0x00000052 } },
-	{ AR5K_RF_GAIN(20),	{ 0x00000098, 0x00000092 } },
-	{ AR5K_RF_GAIN(21),	{ 0x000001a4, 0x0000017c } },
-	{ AR5K_RF_GAIN(22),	{ 0x000001e4, 0x000001bc } },
-	{ AR5K_RF_GAIN(23),	{ 0x00000024, 0x000001fc } },
-	{ AR5K_RF_GAIN(24),	{ 0x00000064, 0x0000000a } },
-	{ AR5K_RF_GAIN(25),	{ 0x000000a4, 0x0000004a } },
-	{ AR5K_RF_GAIN(26),	{ 0x000000e4, 0x0000008a } },
-	{ AR5K_RF_GAIN(27),	{ 0x0000010a, 0x0000015a } },
-	{ AR5K_RF_GAIN(28),	{ 0x0000014a, 0x0000019a } },
-	{ AR5K_RF_GAIN(29),	{ 0x0000018a, 0x000001da } },
-	{ AR5K_RF_GAIN(30),	{ 0x000001ca, 0x0000000e } },
-	{ AR5K_RF_GAIN(31),	{ 0x0000000a, 0x0000004e } },
-	{ AR5K_RF_GAIN(32),	{ 0x0000004a, 0x0000008e } },
-	{ AR5K_RF_GAIN(33),	{ 0x0000008a, 0x0000015e } },
-	{ AR5K_RF_GAIN(34),	{ 0x000001ba, 0x0000019e } },
-	{ AR5K_RF_GAIN(35),	{ 0x000001fa, 0x000001de } },
-	{ AR5K_RF_GAIN(36),	{ 0x0000003a, 0x00000009 } },
-	{ AR5K_RF_GAIN(37),	{ 0x0000007a, 0x00000049 } },
-	{ AR5K_RF_GAIN(38),	{ 0x00000186, 0x00000089 } },
-	{ AR5K_RF_GAIN(39),	{ 0x000001c6, 0x00000179 } },
-	{ AR5K_RF_GAIN(40),	{ 0x00000006, 0x000001b9 } },
-	{ AR5K_RF_GAIN(41),	{ 0x00000046, 0x000001f9 } },
-	{ AR5K_RF_GAIN(42),	{ 0x00000086, 0x00000039 } },
-	{ AR5K_RF_GAIN(43),	{ 0x000000c6, 0x00000079 } },
-	{ AR5K_RF_GAIN(44),	{ 0x000000c6, 0x000000b9 } },
-	{ AR5K_RF_GAIN(45),	{ 0x000000c6, 0x000001bd } },
-	{ AR5K_RF_GAIN(46),	{ 0x000000c6, 0x000001fd } },
-	{ AR5K_RF_GAIN(47),	{ 0x000000c6, 0x0000003d } },
-	{ AR5K_RF_GAIN(48),	{ 0x000000c6, 0x0000007d } },
-	{ AR5K_RF_GAIN(49),	{ 0x000000c6, 0x000000bd } },
-	{ AR5K_RF_GAIN(50),	{ 0x000000c6, 0x000000fd } },
-	{ AR5K_RF_GAIN(51),	{ 0x000000c6, 0x000000fd } },
-	{ AR5K_RF_GAIN(52),	{ 0x000000c6, 0x000000fd } },
-	{ AR5K_RF_GAIN(53),	{ 0x000000c6, 0x000000fd } },
-	{ AR5K_RF_GAIN(54),	{ 0x000000c6, 0x000000fd } },
-	{ AR5K_RF_GAIN(55),	{ 0x000000c6, 0x000000fd } },
-	{ AR5K_RF_GAIN(56),	{ 0x000000c6, 0x000000fd } },
-	{ AR5K_RF_GAIN(57),	{ 0x000000c6, 0x000000fd } },
-	{ AR5K_RF_GAIN(58),	{ 0x000000c6, 0x000000fd } },
-	{ AR5K_RF_GAIN(59),	{ 0x000000c6, 0x000000fd } },
-	{ AR5K_RF_GAIN(60),	{ 0x000000c6, 0x000000fd } },
-	{ AR5K_RF_GAIN(61),	{ 0x000000c6, 0x000000fd } },
-	{ AR5K_RF_GAIN(62),	{ 0x000000c6, 0x000000fd } },
-	{ AR5K_RF_GAIN(63),	{ 0x000000c6, 0x000000fd } },
-};
-
-/* Initial RF Gain settings for RF5112 */
-static const struct ath5k_ini_rfgain rfgain_5112[] = {
-	/*			      5Ghz	2Ghz	*/
-	{ AR5K_RF_GAIN(0),	{ 0x00000007, 0x00000007 } },
-	{ AR5K_RF_GAIN(1),	{ 0x00000047, 0x00000047 } },
-	{ AR5K_RF_GAIN(2),	{ 0x00000087, 0x00000087 } },
-	{ AR5K_RF_GAIN(3),	{ 0x000001a0, 0x000001a0 } },
-	{ AR5K_RF_GAIN(4),	{ 0x000001e0, 0x000001e0 } },
-	{ AR5K_RF_GAIN(5),	{ 0x00000020, 0x00000020 } },
-	{ AR5K_RF_GAIN(6),	{ 0x00000060, 0x00000060 } },
-	{ AR5K_RF_GAIN(7),	{ 0x000001a1, 0x000001a1 } },
-	{ AR5K_RF_GAIN(8),	{ 0x000001e1, 0x000001e1 } },
-	{ AR5K_RF_GAIN(9),	{ 0x00000021, 0x00000021 } },
-	{ AR5K_RF_GAIN(10),	{ 0x00000061, 0x00000061 } },
-	{ AR5K_RF_GAIN(11),	{ 0x00000162, 0x00000162 } },
-	{ AR5K_RF_GAIN(12),	{ 0x000001a2, 0x000001a2 } },
-	{ AR5K_RF_GAIN(13),	{ 0x000001e2, 0x000001e2 } },
-	{ AR5K_RF_GAIN(14),	{ 0x00000022, 0x00000022 } },
-	{ AR5K_RF_GAIN(15),	{ 0x00000062, 0x00000062 } },
-	{ AR5K_RF_GAIN(16),	{ 0x00000163, 0x00000163 } },
-	{ AR5K_RF_GAIN(17),	{ 0x000001a3, 0x000001a3 } },
-	{ AR5K_RF_GAIN(18),	{ 0x000001e3, 0x000001e3 } },
-	{ AR5K_RF_GAIN(19),	{ 0x00000023, 0x00000023 } },
-	{ AR5K_RF_GAIN(20),	{ 0x00000063, 0x00000063 } },
-	{ AR5K_RF_GAIN(21),	{ 0x00000184, 0x00000184 } },
-	{ AR5K_RF_GAIN(22),	{ 0x000001c4, 0x000001c4 } },
-	{ AR5K_RF_GAIN(23),	{ 0x00000004, 0x00000004 } },
-	{ AR5K_RF_GAIN(24),	{ 0x000001ea, 0x0000000b } },
-	{ AR5K_RF_GAIN(25),	{ 0x0000002a, 0x0000004b } },
-	{ AR5K_RF_GAIN(26),	{ 0x0000006a, 0x0000008b } },
-	{ AR5K_RF_GAIN(27),	{ 0x000000aa, 0x000001ac } },
-	{ AR5K_RF_GAIN(28),	{ 0x000001ab, 0x000001ec } },
-	{ AR5K_RF_GAIN(29),	{ 0x000001eb, 0x0000002c } },
-	{ AR5K_RF_GAIN(30),	{ 0x0000002b, 0x00000012 } },
-	{ AR5K_RF_GAIN(31),	{ 0x0000006b, 0x00000052 } },
-	{ AR5K_RF_GAIN(32),	{ 0x000000ab, 0x00000092 } },
-	{ AR5K_RF_GAIN(33),	{ 0x000001ac, 0x00000193 } },
-	{ AR5K_RF_GAIN(34),	{ 0x000001ec, 0x000001d3 } },
-	{ AR5K_RF_GAIN(35),	{ 0x0000002c, 0x00000013 } },
-	{ AR5K_RF_GAIN(36),	{ 0x0000003a, 0x00000053 } },
-	{ AR5K_RF_GAIN(37),	{ 0x0000007a, 0x00000093 } },
-	{ AR5K_RF_GAIN(38),	{ 0x000000ba, 0x00000194 } },
-	{ AR5K_RF_GAIN(39),	{ 0x000001bb, 0x000001d4 } },
-	{ AR5K_RF_GAIN(40),	{ 0x000001fb, 0x00000014 } },
-	{ AR5K_RF_GAIN(41),	{ 0x0000003b, 0x0000003a } },
-	{ AR5K_RF_GAIN(42),	{ 0x0000007b, 0x0000007a } },
-	{ AR5K_RF_GAIN(43),	{ 0x000000bb, 0x000000ba } },
-	{ AR5K_RF_GAIN(44),	{ 0x000001bc, 0x000001bb } },
-	{ AR5K_RF_GAIN(45),	{ 0x000001fc, 0x000001fb } },
-	{ AR5K_RF_GAIN(46),	{ 0x0000003c, 0x0000003b } },
-	{ AR5K_RF_GAIN(47),	{ 0x0000007c, 0x0000007b } },
-	{ AR5K_RF_GAIN(48),	{ 0x000000bc, 0x000000bb } },
-	{ AR5K_RF_GAIN(49),	{ 0x000000fc, 0x000001bc } },
-	{ AR5K_RF_GAIN(50),	{ 0x000000fc, 0x000001fc } },
-	{ AR5K_RF_GAIN(51),	{ 0x000000fc, 0x0000003c } },
-	{ AR5K_RF_GAIN(52),	{ 0x000000fc, 0x0000007c } },
-	{ AR5K_RF_GAIN(53),	{ 0x000000fc, 0x000000bc } },
-	{ AR5K_RF_GAIN(54),	{ 0x000000fc, 0x000000fc } },
-	{ AR5K_RF_GAIN(55),	{ 0x000000fc, 0x000000fc } },
-	{ AR5K_RF_GAIN(56),	{ 0x000000fc, 0x000000fc } },
-	{ AR5K_RF_GAIN(57),	{ 0x000000fc, 0x000000fc } },
-	{ AR5K_RF_GAIN(58),	{ 0x000000fc, 0x000000fc } },
-	{ AR5K_RF_GAIN(59),	{ 0x000000fc, 0x000000fc } },
-	{ AR5K_RF_GAIN(60),	{ 0x000000fc, 0x000000fc } },
-	{ AR5K_RF_GAIN(61),	{ 0x000000fc, 0x000000fc } },
-	{ AR5K_RF_GAIN(62),	{ 0x000000fc, 0x000000fc } },
-	{ AR5K_RF_GAIN(63),	{ 0x000000fc, 0x000000fc } },
-};
-
-/* Initial RF Gain settings for RF2413 */
-static const struct ath5k_ini_rfgain rfgain_2413[] = {
-	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
-	{ AR5K_RF_GAIN(1),	{ 0x00000000, 0x00000040 } },
-	{ AR5K_RF_GAIN(2),	{ 0x00000000, 0x00000080 } },
-	{ AR5K_RF_GAIN(3),	{ 0x00000000, 0x00000181 } },
-	{ AR5K_RF_GAIN(4),	{ 0x00000000, 0x000001c1 } },
-	{ AR5K_RF_GAIN(5),	{ 0x00000000, 0x00000001 } },
-	{ AR5K_RF_GAIN(6),	{ 0x00000000, 0x00000041 } },
-	{ AR5K_RF_GAIN(7),	{ 0x00000000, 0x00000081 } },
-	{ AR5K_RF_GAIN(8),	{ 0x00000000, 0x00000168 } },
-	{ AR5K_RF_GAIN(9),	{ 0x00000000, 0x000001a8 } },
-	{ AR5K_RF_GAIN(10),	{ 0x00000000, 0x000001e8 } },
-	{ AR5K_RF_GAIN(11),	{ 0x00000000, 0x00000028 } },
-	{ AR5K_RF_GAIN(12),	{ 0x00000000, 0x00000068 } },
-	{ AR5K_RF_GAIN(13),	{ 0x00000000, 0x00000189 } },
-	{ AR5K_RF_GAIN(14),	{ 0x00000000, 0x000001c9 } },
-	{ AR5K_RF_GAIN(15),	{ 0x00000000, 0x00000009 } },
-	{ AR5K_RF_GAIN(16),	{ 0x00000000, 0x00000049 } },
-	{ AR5K_RF_GAIN(17),	{ 0x00000000, 0x00000089 } },
-	{ AR5K_RF_GAIN(18),	{ 0x00000000, 0x00000190 } },
-	{ AR5K_RF_GAIN(19),	{ 0x00000000, 0x000001d0 } },
-	{ AR5K_RF_GAIN(20),	{ 0x00000000, 0x00000010 } },
-	{ AR5K_RF_GAIN(21),	{ 0x00000000, 0x00000050 } },
-	{ AR5K_RF_GAIN(22),	{ 0x00000000, 0x00000090 } },
-	{ AR5K_RF_GAIN(23),	{ 0x00000000, 0x00000191 } },
-	{ AR5K_RF_GAIN(24),	{ 0x00000000, 0x000001d1 } },
-	{ AR5K_RF_GAIN(25),	{ 0x00000000, 0x00000011 } },
-	{ AR5K_RF_GAIN(26),	{ 0x00000000, 0x00000051 } },
-	{ AR5K_RF_GAIN(27),	{ 0x00000000, 0x00000091 } },
-	{ AR5K_RF_GAIN(28),	{ 0x00000000, 0x00000178 } },
-	{ AR5K_RF_GAIN(29),	{ 0x00000000, 0x000001b8 } },
-	{ AR5K_RF_GAIN(30),	{ 0x00000000, 0x000001f8 } },
-	{ AR5K_RF_GAIN(31),	{ 0x00000000, 0x00000038 } },
-	{ AR5K_RF_GAIN(32),	{ 0x00000000, 0x00000078 } },
-	{ AR5K_RF_GAIN(33),	{ 0x00000000, 0x00000199 } },
-	{ AR5K_RF_GAIN(34),	{ 0x00000000, 0x000001d9 } },
-	{ AR5K_RF_GAIN(35),	{ 0x00000000, 0x00000019 } },
-	{ AR5K_RF_GAIN(36),	{ 0x00000000, 0x00000059 } },
-	{ AR5K_RF_GAIN(37),	{ 0x00000000, 0x00000099 } },
-	{ AR5K_RF_GAIN(38),	{ 0x00000000, 0x000000d9 } },
-	{ AR5K_RF_GAIN(39),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(40),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(41),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(42),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(43),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(44),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(45),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(46),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(47),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(48),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(49),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(50),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(51),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(52),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(53),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(54),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(55),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(56),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(57),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(58),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(59),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(60),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(61),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(62),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(63),	{ 0x00000000, 0x000000f9 } },
-};
-
-/* Initial RF Gain settings for AR2316 */
-static const struct ath5k_ini_rfgain rfgain_2316[] = {
-	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
-	{ AR5K_RF_GAIN(1),	{ 0x00000000, 0x00000040 } },
-	{ AR5K_RF_GAIN(2),	{ 0x00000000, 0x00000080 } },
-	{ AR5K_RF_GAIN(3),	{ 0x00000000, 0x000000c0 } },
-	{ AR5K_RF_GAIN(4),	{ 0x00000000, 0x000000e0 } },
-	{ AR5K_RF_GAIN(5),	{ 0x00000000, 0x000000e0 } },
-	{ AR5K_RF_GAIN(6),	{ 0x00000000, 0x00000128 } },
-	{ AR5K_RF_GAIN(7),	{ 0x00000000, 0x00000128 } },
-	{ AR5K_RF_GAIN(8),	{ 0x00000000, 0x00000128 } },
-	{ AR5K_RF_GAIN(9),	{ 0x00000000, 0x00000168 } },
-	{ AR5K_RF_GAIN(10),	{ 0x00000000, 0x000001a8 } },
-	{ AR5K_RF_GAIN(11),	{ 0x00000000, 0x000001e8 } },
-	{ AR5K_RF_GAIN(12),	{ 0x00000000, 0x00000028 } },
-	{ AR5K_RF_GAIN(13),	{ 0x00000000, 0x00000068 } },
-	{ AR5K_RF_GAIN(14),	{ 0x00000000, 0x000000a8 } },
-	{ AR5K_RF_GAIN(15),	{ 0x00000000, 0x000000e8 } },
-	{ AR5K_RF_GAIN(16),	{ 0x00000000, 0x000000e8 } },
-	{ AR5K_RF_GAIN(17),	{ 0x00000000, 0x00000130 } },
-	{ AR5K_RF_GAIN(18),	{ 0x00000000, 0x00000130 } },
-	{ AR5K_RF_GAIN(19),	{ 0x00000000, 0x00000170 } },
-	{ AR5K_RF_GAIN(20),	{ 0x00000000, 0x000001b0 } },
-	{ AR5K_RF_GAIN(21),	{ 0x00000000, 0x000001f0 } },
-	{ AR5K_RF_GAIN(22),	{ 0x00000000, 0x00000030 } },
-	{ AR5K_RF_GAIN(23),	{ 0x00000000, 0x00000070 } },
-	{ AR5K_RF_GAIN(24),	{ 0x00000000, 0x000000b0 } },
-	{ AR5K_RF_GAIN(25),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(26),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(27),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(28),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(29),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(30),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(31),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(32),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(33),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(34),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(35),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(36),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(37),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(38),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(39),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(40),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(41),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(42),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(43),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(44),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(45),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(46),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(47),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(48),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(49),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(50),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(51),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(52),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(53),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(54),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(55),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(56),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(57),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(58),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(59),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(60),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(61),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(62),	{ 0x00000000, 0x000000f0 } },
-	{ AR5K_RF_GAIN(63),	{ 0x00000000, 0x000000f0 } },
-};
-
-
-/* Initial RF Gain settings for RF5413 */
-static const struct ath5k_ini_rfgain rfgain_5413[] = {
-	/*			      5Ghz	2Ghz	*/
-	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
-	{ AR5K_RF_GAIN(1),	{ 0x00000040, 0x00000040 } },
-	{ AR5K_RF_GAIN(2),	{ 0x00000080, 0x00000080 } },
-	{ AR5K_RF_GAIN(3),	{ 0x000001a1, 0x00000161 } },
-	{ AR5K_RF_GAIN(4),	{ 0x000001e1, 0x000001a1 } },
-	{ AR5K_RF_GAIN(5),	{ 0x00000021, 0x000001e1 } },
-	{ AR5K_RF_GAIN(6),	{ 0x00000061, 0x00000021 } },
-	{ AR5K_RF_GAIN(7),	{ 0x00000188, 0x00000061 } },
-	{ AR5K_RF_GAIN(8),	{ 0x000001c8, 0x00000188 } },
-	{ AR5K_RF_GAIN(9),	{ 0x00000008, 0x000001c8 } },
-	{ AR5K_RF_GAIN(10),	{ 0x00000048, 0x00000008 } },
-	{ AR5K_RF_GAIN(11),	{ 0x00000088, 0x00000048 } },
-	{ AR5K_RF_GAIN(12),	{ 0x000001a9, 0x00000088 } },
-	{ AR5K_RF_GAIN(13),	{ 0x000001e9, 0x00000169 } },
-	{ AR5K_RF_GAIN(14),	{ 0x00000029, 0x000001a9 } },
-	{ AR5K_RF_GAIN(15),	{ 0x00000069, 0x000001e9 } },
-	{ AR5K_RF_GAIN(16),	{ 0x000001d0, 0x00000029 } },
-	{ AR5K_RF_GAIN(17),	{ 0x00000010, 0x00000069 } },
-	{ AR5K_RF_GAIN(18),	{ 0x00000050, 0x00000190 } },
-	{ AR5K_RF_GAIN(19),	{ 0x00000090, 0x000001d0 } },
-	{ AR5K_RF_GAIN(20),	{ 0x000001b1, 0x00000010 } },
-	{ AR5K_RF_GAIN(21),	{ 0x000001f1, 0x00000050 } },
-	{ AR5K_RF_GAIN(22),	{ 0x00000031, 0x00000090 } },
-	{ AR5K_RF_GAIN(23),	{ 0x00000071, 0x00000171 } },
-	{ AR5K_RF_GAIN(24),	{ 0x000001b8, 0x000001b1 } },
-	{ AR5K_RF_GAIN(25),	{ 0x000001f8, 0x000001f1 } },
-	{ AR5K_RF_GAIN(26),	{ 0x00000038, 0x00000031 } },
-	{ AR5K_RF_GAIN(27),	{ 0x00000078, 0x00000071 } },
-	{ AR5K_RF_GAIN(28),	{ 0x00000199, 0x00000198 } },
-	{ AR5K_RF_GAIN(29),	{ 0x000001d9, 0x000001d8 } },
-	{ AR5K_RF_GAIN(30),	{ 0x00000019, 0x00000018 } },
-	{ AR5K_RF_GAIN(31),	{ 0x00000059, 0x00000058 } },
-	{ AR5K_RF_GAIN(32),	{ 0x00000099, 0x00000098 } },
-	{ AR5K_RF_GAIN(33),	{ 0x000000d9, 0x00000179 } },
-	{ AR5K_RF_GAIN(34),	{ 0x000000f9, 0x000001b9 } },
-	{ AR5K_RF_GAIN(35),	{ 0x000000f9, 0x000001f9 } },
-	{ AR5K_RF_GAIN(36),	{ 0x000000f9, 0x00000039 } },
-	{ AR5K_RF_GAIN(37),	{ 0x000000f9, 0x00000079 } },
-	{ AR5K_RF_GAIN(38),	{ 0x000000f9, 0x000000b9 } },
-	{ AR5K_RF_GAIN(39),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(40),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(41),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(42),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(43),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(44),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(45),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(46),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(47),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(48),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(49),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(50),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(51),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(52),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(53),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(54),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(55),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(56),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(57),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(58),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(59),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(60),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(61),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(62),	{ 0x000000f9, 0x000000f9 } },
-	{ AR5K_RF_GAIN(63),	{ 0x000000f9, 0x000000f9 } },
-};
-
-
-/* Initial RF Gain settings for RF2425 */
-static const struct ath5k_ini_rfgain rfgain_2425[] = {
-	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
-	{ AR5K_RF_GAIN(1),	{ 0x00000000, 0x00000040 } },
-	{ AR5K_RF_GAIN(2),	{ 0x00000000, 0x00000080 } },
-	{ AR5K_RF_GAIN(3),	{ 0x00000000, 0x00000181 } },
-	{ AR5K_RF_GAIN(4),	{ 0x00000000, 0x000001c1 } },
-	{ AR5K_RF_GAIN(5),	{ 0x00000000, 0x00000001 } },
-	{ AR5K_RF_GAIN(6),	{ 0x00000000, 0x00000041 } },
-	{ AR5K_RF_GAIN(7),	{ 0x00000000, 0x00000081 } },
-	{ AR5K_RF_GAIN(8),	{ 0x00000000, 0x00000188 } },
-	{ AR5K_RF_GAIN(9),	{ 0x00000000, 0x000001c8 } },
-	{ AR5K_RF_GAIN(10),	{ 0x00000000, 0x00000008 } },
-	{ AR5K_RF_GAIN(11),	{ 0x00000000, 0x00000048 } },
-	{ AR5K_RF_GAIN(12),	{ 0x00000000, 0x00000088 } },
-	{ AR5K_RF_GAIN(13),	{ 0x00000000, 0x00000189 } },
-	{ AR5K_RF_GAIN(14),	{ 0x00000000, 0x000001c9 } },
-	{ AR5K_RF_GAIN(15),	{ 0x00000000, 0x00000009 } },
-	{ AR5K_RF_GAIN(16),	{ 0x00000000, 0x00000049 } },
-	{ AR5K_RF_GAIN(17),	{ 0x00000000, 0x00000089 } },
-	{ AR5K_RF_GAIN(18),	{ 0x00000000, 0x000001b0 } },
-	{ AR5K_RF_GAIN(19),	{ 0x00000000, 0x000001f0 } },
-	{ AR5K_RF_GAIN(20),	{ 0x00000000, 0x00000030 } },
-	{ AR5K_RF_GAIN(21),	{ 0x00000000, 0x00000070 } },
-	{ AR5K_RF_GAIN(22),	{ 0x00000000, 0x00000171 } },
-	{ AR5K_RF_GAIN(23),	{ 0x00000000, 0x000001b1 } },
-	{ AR5K_RF_GAIN(24),	{ 0x00000000, 0x000001f1 } },
-	{ AR5K_RF_GAIN(25),	{ 0x00000000, 0x00000031 } },
-	{ AR5K_RF_GAIN(26),	{ 0x00000000, 0x00000071 } },
-	{ AR5K_RF_GAIN(27),	{ 0x00000000, 0x000001b8 } },
-	{ AR5K_RF_GAIN(28),	{ 0x00000000, 0x000001f8 } },
-	{ AR5K_RF_GAIN(29),	{ 0x00000000, 0x00000038 } },
-	{ AR5K_RF_GAIN(30),	{ 0x00000000, 0x00000078 } },
-	{ AR5K_RF_GAIN(31),	{ 0x00000000, 0x000000b8 } },
-	{ AR5K_RF_GAIN(32),	{ 0x00000000, 0x000001b9 } },
-	{ AR5K_RF_GAIN(33),	{ 0x00000000, 0x000001f9 } },
-	{ AR5K_RF_GAIN(34),	{ 0x00000000, 0x00000039 } },
-	{ AR5K_RF_GAIN(35),	{ 0x00000000, 0x00000079 } },
-	{ AR5K_RF_GAIN(36),	{ 0x00000000, 0x000000b9 } },
-	{ AR5K_RF_GAIN(37),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(38),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(39),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(40),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(41),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(42),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(43),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(44),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(45),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(46),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(47),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(48),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(49),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(50),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(51),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(52),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(53),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(54),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(55),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(56),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(57),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(58),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(59),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(60),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(61),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(62),	{ 0x00000000, 0x000000f9 } },
-	{ AR5K_RF_GAIN(63),	{ 0x00000000, 0x000000f9 } },
-};
-
-#define AR5K_GAIN_CRN_FIX_BITS_5111		4
-#define AR5K_GAIN_CRN_FIX_BITS_5112		7
-#define AR5K_GAIN_CRN_MAX_FIX_BITS		AR5K_GAIN_CRN_FIX_BITS_5112
-#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN		15
-#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN		20
-#define AR5K_GAIN_CCK_PROBE_CORR		5
-#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA		15
-#define AR5K_GAIN_STEP_COUNT			10
-
-/* Check if our current measurement is inside our
- * current variable attenuation window */
-#define AR5K_GAIN_CHECK_ADJUST(_g) 		\
-	((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
-
-struct ath5k_gain_opt_step {
-	s8				gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
-	s8				gos_gain;
-};
-
-struct ath5k_gain_opt {
-	u8				go_default;
-	u8				go_steps_count;
-	const struct ath5k_gain_opt_step	go_step[AR5K_GAIN_STEP_COUNT];
-};
-
-/*
- * Parameters on gos_param:
- * 1) Tx clip PHY register
- * 2) PWD 90 RF register
- * 3) PWD 84 RF register
- * 4) RFGainSel RF register
- */
-static const struct ath5k_gain_opt rfgain_opt_5111 = {
-	4,
-	9,
-	{
-		{ { 4, 1, 1, 1 }, 6 },
-		{ { 4, 0, 1, 1 }, 4 },
-		{ { 3, 1, 1, 1 }, 3 },
-		{ { 4, 0, 0, 1 }, 1 },
-		{ { 4, 1, 1, 0 }, 0 },
-		{ { 4, 0, 1, 0 }, -2 },
-		{ { 3, 1, 1, 0 }, -3 },
-		{ { 4, 0, 0, 0 }, -4 },
-		{ { 2, 1, 1, 0 }, -6 }
-	}
-};
-
-/*
- * Parameters on gos_param:
- * 1) Mixgain ovr RF register
- * 2) PWD 138 RF register
- * 3) PWD 137 RF register
- * 4) PWD 136 RF register
- * 5) PWD 132 RF register
- * 6) PWD 131 RF register
- * 7) PWD 130 RF register
- */
-static const struct ath5k_gain_opt rfgain_opt_5112 = {
-	1,
-	8,
-	{
-		{ { 3, 0, 0, 0, 0, 0, 0 }, 6 },
-		{ { 2, 0, 0, 0, 0, 0, 0 }, 0 },
-		{ { 1, 0, 0, 0, 0, 0, 0 }, -3 },
-		{ { 0, 0, 0, 0, 0, 0, 0 }, -6 },
-		{ { 0, 1, 1, 0, 0, 0, 0 }, -8 },
-		{ { 0, 1, 1, 0, 1, 1, 0 }, -10 },
-		{ { 0, 1, 0, 1, 1, 1, 0 }, -13 },
-		{ { 0, 1, 0, 1, 1, 0, 1 }, -16 },
-	}
-};
-
diff --git a/roms/ipxe/src/drivers/net/atl1e.c b/roms/ipxe/src/drivers/net/atl1e.c
index e4dd5c973c23a00da857fd79b42f..1ff0f0d106bcdc181868ef3f7006 100644
--- a/roms/ipxe/src/drivers/net/atl1e.c
+++ b/roms/ipxe/src/drivers/net/atl1e.c
@@ -17,8 +17,8 @@
  * more details.
  *
  * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/net/atl1e.h b/roms/ipxe/src/drivers/net/atl1e.h
index e759ea49ba86ab7844adf0c9214c..2c972ea10880b7e1eb79d6b0e03d 100644
--- a/roms/ipxe/src/drivers/net/atl1e.h
+++ b/roms/ipxe/src/drivers/net/atl1e.h
@@ -18,8 +18,8 @@
  * more details.
  *
  * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/net/b44.c b/roms/ipxe/src/drivers/net/b44.c
index 66fa8ea3c840a12826984ea7c860..d9aeb1b4bae05bd0dee5d52f8efb 100644
--- a/roms/ipxe/src/drivers/net/b44.c
+++ b/roms/ipxe/src/drivers/net/b44.c
@@ -14,7 +14,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  *
  * This driver is a port of the b44 linux driver version 1.01
  *
@@ -78,24 +79,21 @@ static inline void bflush(const struct b44_private *bp, u32 reg, u32 timeout)
 
 
 /**
- * Return non-zero if the installed RAM is within
- * the limit given and zero if it is outside.
- * Hopefully will be removed soon.
+ * Check if card can access address
+ *
+ * @v address		Virtual address
+ * @v address_ok	Card can access address
  */
-int phys_ram_within_limit(u64 limit)
-{
-	struct memory_map memmap;
-	struct memory_region *highest = NULL;
-	get_memmap(&memmap);
+static inline __attribute__ (( always_inline )) int
+b44_address_ok ( void *address ) {
 
-	if (memmap.count == 0)
-		return 0;
-	highest = &memmap.regions[memmap.count - 1];
+	/* Card can address anything with a 30-bit address */
+	if ( ( virt_to_bus ( address ) & ~B44_30BIT_DMA_MASK ) == 0 )
+		return 1;
 
-	return (highest->end < limit);
+	return 0;
 }
 
-
 /**
  * Ring cells waiting to be processed are between 'tx_cur' and 'pending'
  * indexes in the ring.
@@ -404,6 +402,7 @@ static void b44_populate_rx_descriptor(struct b44_private *bp, u32 idx)
  */
 static void b44_rx_refill(struct b44_private *bp, u32 pending)
 {
+	struct io_buffer *iobuf;
 	u32 i;
 
 	// skip pending
@@ -411,11 +410,17 @@ static void b44_rx_refill(struct b44_private *bp, u32 pending)
 		if (bp->rx_iobuf[i] != NULL)
 			continue;
 
-		bp->rx_iobuf[i] = alloc_iob(RX_PKT_BUF_SZ);
-		if (!bp->rx_iobuf[i]) {
+		iobuf = alloc_iob(RX_PKT_BUF_SZ);
+		if (!iobuf) {
 			DBG("Refill rx ring failed!!\n");
 			break;
 		}
+		if (!b44_address_ok(iobuf->data)) {
+			DBG("Refill rx ring bad address!!\n");
+			free_iob(iobuf);
+			break;
+		}
+		bp->rx_iobuf[i] = iobuf;
 
 		b44_populate_rx_descriptor(bp, i);
 	}
@@ -444,6 +449,10 @@ static int b44_init_rx_ring(struct b44_private *bp)
 	bp->rx = malloc_dma(B44_RX_RING_LEN_BYTES, B44_DMA_ALIGNMENT);
 	if (!bp->rx)
 		return -ENOMEM;
+	if (!b44_address_ok(bp->rx)) {
+		free_dma(bp->rx, B44_RX_RING_LEN_BYTES);
+		return -ENOTSUP;
+	}
 
 	memset(bp->rx_iobuf, 0, sizeof(bp->rx_iobuf));
 
@@ -472,6 +481,10 @@ static int b44_init_tx_ring(struct b44_private *bp)
 	bp->tx = malloc_dma(B44_TX_RING_LEN_BYTES, B44_DMA_ALIGNMENT);
 	if (!bp->tx)
 		return -ENOMEM;
+	if (!b44_address_ok(bp->tx)) {
+		free_dma(bp->tx, B44_TX_RING_LEN_BYTES);
+		return -ENOTSUP;
+	}
 
 	memset(bp->tx, 0, B44_TX_RING_LEN_BYTES);
 	memset(bp->tx_iobuf, 0, sizeof(bp->tx_iobuf));
@@ -644,17 +657,6 @@ static int b44_probe(struct pci_device *pci)
 	struct b44_private *bp;
 	int rc;
 
-	/*
-	 * Bail out if more than 1GB of physical RAM is installed.
-	 * This limitation will be removed later when dma mapping
-	 * is merged into mainline.
-	 */
-	if (!phys_ram_within_limit(B44_30BIT_DMA_MASK)) {
-		DBG("Sorry, this version of the driver does not\n"
-		    "support systems with more than 1GB of RAM.\n");
-		return -ENOMEM;
-	}
-
 	/* Set up netdev */
 	netdev = alloc_etherdev(sizeof(*bp));
 	if (!netdev)
@@ -793,6 +795,10 @@ static int b44_transmit(struct net_device *netdev, struct io_buffer *iobuf)
 		return -ENOBUFS;
 	}
 
+	/* Check for addressability */
+	if (!b44_address_ok(iobuf->data))
+		return -ENOTSUP;
+
 	/* Will call netdev_tx_complete() on the iobuf later */
 	bp->tx_iobuf[cur] = iobuf;
 
diff --git a/roms/ipxe/src/drivers/net/b44.h b/roms/ipxe/src/drivers/net/b44.h
index 2d1f206e0499c945003cd5a8fcac..089580926c56dc5f2a2457fcb9ca 100644
--- a/roms/ipxe/src/drivers/net/b44.h
+++ b/roms/ipxe/src/drivers/net/b44.h
@@ -14,7 +14,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  *
  * This driver is a port of the b44 linux driver version 1.01
  *
diff --git a/roms/ipxe/src/drivers/net/cs89x0.c b/roms/ipxe/src/drivers/net/cs89x0.c
index ee34d0c5942640f48eda15968f86..17b7157a165380883782d2a6a58e 100644
--- a/roms/ipxe/src/drivers/net/cs89x0.c
+++ b/roms/ipxe/src/drivers/net/cs89x0.c
@@ -58,7 +58,7 @@ FILE_LICENCE ( GPL2_ONLY );
   Fri Nov 22 23:00:00 1996  Markus Gutschke  <gutschk@math.uni-muenster.de>
 
   * read the manuals for the CS89x0 chipsets and took note of all the
-    changes that will be neccessary in order to adapt Russel Nelson's code
+    changes that will be necessary in order to adapt Russel Nelson's code
     to the requirements of a BOOT-Prom
 
   * 6
@@ -92,7 +92,6 @@ FILE_LICENCE ( GPL2_ONLY );
 #include "etherboot.h"
 #include "nic.h"
 #include <ipxe/isa.h>
-#include <ipxe/console.h>
 #include "cs89x0.h"
 
 static unsigned short	eth_nic_base;
diff --git a/roms/ipxe/src/drivers/net/cs89x0.h b/roms/ipxe/src/drivers/net/cs89x0.h
index a36b907c6d038835db5ee693c8f4..432fe94ebadd69c33cbc58197dd9 100644
--- a/roms/ipxe/src/drivers/net/cs89x0.h
+++ b/roms/ipxe/src/drivers/net/cs89x0.h
@@ -31,7 +31,8 @@ FILE_LICENCE ( GPL2_ONLY );
 
    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.  */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
 
 #define PP_ChipID 0x0000	/* offset   0h -> Corp -ID              */
 				/* offset   2h -> Model/Product Number  */
diff --git a/roms/ipxe/src/drivers/net/davicom.c b/roms/ipxe/src/drivers/net/davicom.c
index 141177426867cb68a1b844579f93..a4870a729742e29f403b05fbdfd9 100644
--- a/roms/ipxe/src/drivers/net/davicom.c
+++ b/roms/ipxe/src/drivers/net/davicom.c
@@ -213,11 +213,11 @@ static int phy_read(int location)
  phy_write_1bit(io_dcr9, PHY_DATA_1);
  phy_write_1bit(io_dcr9, PHY_DATA_0);
 
- /* Send Phy addres */
+ /* Send Phy address */
  for (i=0x10; i>0; i=i>>1)
      phy_write_1bit(io_dcr9, phy_addr&i ? PHY_DATA_1: PHY_DATA_0);
    
- /* Send register addres */
+ /* Send register address */
  for (i=0x10; i>0; i=i>>1)
      phy_write_1bit(io_dcr9, location&i ? PHY_DATA_1: PHY_DATA_0);
 
@@ -257,11 +257,11 @@ static void phy_write(int location, u16 phy_data)
  phy_write_1bit(io_dcr9, PHY_DATA_0);
  phy_write_1bit(io_dcr9, PHY_DATA_1);
 
- /* Send Phy addres */
+ /* Send Phy address */
  for (i=0x10; i>0; i=i>>1)
    phy_write_1bit(io_dcr9, phy_addr&i ? PHY_DATA_1: PHY_DATA_0);
 
- /* Send register addres */
+ /* Send register address */
  for (i=0x10; i>0; i=i>>1)
    phy_write_1bit(io_dcr9, location&i ? PHY_DATA_1: PHY_DATA_0);
 
diff --git a/roms/ipxe/src/drivers/net/depca.c b/roms/ipxe/src/drivers/net/depca.c
index 735a52dfbbae577347203b52313e..016f28bb2db51938b008ee1fcfef 100644
--- a/roms/ipxe/src/drivers/net/depca.c
+++ b/roms/ipxe/src/drivers/net/depca.c
@@ -240,7 +240,6 @@ FILE_LICENCE ( GPL_ANY );
 #include "etherboot.h"
 #include "nic.h"
 #include <ipxe/isa.h>
-#include <ipxe/console.h>
 #include <ipxe/ethernet.h>
 
 /*
diff --git a/roms/ipxe/src/drivers/net/dmfe.c b/roms/ipxe/src/drivers/net/dmfe.c
index dd6c1dec215f844a381f3bef9758..aae40fce761bc783e203a04aa839 100644
--- a/roms/ipxe/src/drivers/net/dmfe.c
+++ b/roms/ipxe/src/drivers/net/dmfe.c
@@ -17,7 +17,8 @@
 *
 *    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.
+*    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+*    02110-1301, USA.
 *
 *    Portions of this code based on:
 *
@@ -260,15 +261,15 @@ static void dmfe_reset(struct nic *nic)
 		db->cr0_data = 0;
 		db->dm910x_chk_mode = 1;	/* Enter the check mode */
 	}
-	/* Initilize DM910X board */
+	/* Initialize DM910X board */
 	dmfe_init_dm910x(nic);
 
 	return;
 }
 
-/*	Initilize DM910X board
+/*	Initialize DM910X board
  *	Reset DM910X board
- *	Initilize TX/Rx descriptor chain structure
+ *	Initialize TX/Rx descriptor chain structure
  *	Send the set-up frame
  *	Enable Tx/Rx machine
  */
@@ -306,7 +307,7 @@ static void dmfe_init_dm910x(struct nic *nic)
 	if (!(db->media_mode & DMFE_AUTO))
 		db->op_mode = db->media_mode;	/* Force Mode */
 
-	/* Initiliaze Transmit/Receive decriptor and CR3/4 */
+	/* Initiliaze Transmit/Receive descriptor and CR3/4 */
 	dmfe_descriptor_init(nic, ioaddr);
 
 	/* tx descriptor start pointer */
@@ -571,7 +572,7 @@ static void update_cr6(u32 cr6_data, unsigned long ioaddr)
 
 /*
  *	Send a setup frame for DM9132
- *	This setup frame initilize DM910X addres filter mode
+ *	This setup frame initialize DM910X address filter mode
 */
 
 static void dm9132_id_table(struct nic *nic __unused)
@@ -622,7 +623,7 @@ static void dm9132_id_table(struct nic *nic __unused)
 
 /*
  *	Send a setup frame for DM9102/DM9102A
- *	This setup frame initilize DM910X addres filter mode
+ *	This setup frame initialize DM910X address filter mode
  */
 
 static void send_filter_frame(struct nic *nic)
@@ -902,13 +903,13 @@ static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset,
 		phy_write_1bit(ioaddr, PHY_DATA_0);
 		phy_write_1bit(ioaddr, PHY_DATA_1);
 
-		/* Send Phy addres */
+		/* Send Phy address */
 		for (i = 0x10; i > 0; i = i >> 1)
 			phy_write_1bit(ioaddr,
 				       phy_addr & i ? PHY_DATA_1 :
 				       PHY_DATA_0);
 
-		/* Send register addres */
+		/* Send register address */
 		for (i = 0x10; i > 0; i = i >> 1)
 			phy_write_1bit(ioaddr,
 				       offset & i ? PHY_DATA_1 :
@@ -958,13 +959,13 @@ static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset,
 		phy_write_1bit(ioaddr, PHY_DATA_1);
 		phy_write_1bit(ioaddr, PHY_DATA_0);
 
-		/* Send Phy addres */
+		/* Send Phy address */
 		for (i = 0x10; i > 0; i = i >> 1)
 			phy_write_1bit(ioaddr,
 				       phy_addr & i ? PHY_DATA_1 :
 				       PHY_DATA_0);
 
-		/* Send register addres */
+		/* Send register address */
 		for (i = 0x10; i > 0; i = i >> 1)
 			phy_write_1bit(ioaddr,
 				       offset & i ? PHY_DATA_1 :
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000.c b/roms/ipxe/src/drivers/net/e1000/e1000.c
deleted file mode 100644
index a32a4d7c45b8ee7975aca86296055824422f89a9..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-REQUIRE_OBJECT(e1000_main);
-REQUIRE_OBJECT(e1000_82540);
-REQUIRE_OBJECT(e1000_82541);
-REQUIRE_OBJECT(e1000_82542);
-REQUIRE_OBJECT(e1000_82543);
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000.h b/roms/ipxe/src/drivers/net/e1000/e1000.h
deleted file mode 100644
index 31dbb859a0eca46b75f2c033d7018cfbe872f6e8..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000.h
+++ /dev/null
@@ -1,326 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-/* Linux PRO/1000 Ethernet Driver main header file */
-
-#ifndef _E1000_H_
-#define _E1000_H_
-
-#include "e1000_api.h"
-
-#define BAR_0		0
-#define BAR_1		1
-#define BAR_5		5
-
-struct e1000_adapter;
-
-/* TX/RX descriptor defines */
-#define E1000_DEFAULT_TXD                  256
-#define E1000_MAX_TXD                      256
-#define E1000_MIN_TXD                       80
-#define E1000_MAX_82544_TXD               4096
-
-#define E1000_DEFAULT_TXD_PWR               12
-#define E1000_MAX_TXD_PWR                   12
-#define E1000_MIN_TXD_PWR                    7
-
-#define E1000_DEFAULT_RXD                  256
-#define E1000_MAX_RXD                      256
-
-#define E1000_MIN_RXD                       80
-#define E1000_MAX_82544_RXD               4096
-
-#define E1000_MIN_ITR_USECS                 10 /* 100000 irq/sec */
-#define E1000_MAX_ITR_USECS              10000 /* 100    irq/sec */
-
-
-/* this is the size past which hardware will drop packets when setting LPE=0 */
-#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
-
-/* Supported Rx Buffer Sizes */
-#define E1000_RXBUFFER_128   128
-#define E1000_RXBUFFER_256   256
-#define E1000_RXBUFFER_512   512
-#define E1000_RXBUFFER_1024  1024
-#define E1000_RXBUFFER_2048  2048
-#define E1000_RXBUFFER_4096  4096
-#define E1000_RXBUFFER_8192  8192
-#define E1000_RXBUFFER_16384 16384
-
-/* SmartSpeed delimiters */
-#define E1000_SMARTSPEED_DOWNSHIFT 3
-#define E1000_SMARTSPEED_MAX       15
-
-/* Packet Buffer allocations */
-#define E1000_PBA_BYTES_SHIFT 0xA
-#define E1000_TX_HEAD_ADDR_SHIFT 7
-#define E1000_PBA_TX_MASK 0xFFFF0000
-
-/* Early Receive defines */
-#define E1000_ERT_2048 0x100
-
-#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */
-
-/* How many Tx Descriptors do we need to call netif_wake_queue ? */
-#define E1000_TX_QUEUE_WAKE	16
-/* How many Rx Buffers do we bundle into one write to the hardware ? */
-#define E1000_RX_BUFFER_WRITE	16	/* Must be power of 2 */
-
-#define AUTO_ALL_MODES            0
-#define E1000_EEPROM_82544_APM    0x0004
-#define E1000_EEPROM_APME         0x0400
-
-/* wrapper around a pointer to a socket buffer,
- * so a DMA handle can be stored along with the buffer */
-struct e1000_buffer {
-	struct sk_buff *skb;
-	dma_addr_t dma;
-	unsigned long time_stamp;
-	u16 length;
-	u16 next_to_watch;
-};
-
-struct e1000_rx_buffer {
-	struct sk_buff *skb;
-	dma_addr_t dma;
-	struct page *page;
-};
-
-
-
-struct e1000_tx_ring {
-	/* pointer to the descriptor ring memory */
-	void *desc;
-	/* physical address of the descriptor ring */
-	dma_addr_t dma;
-	/* length of descriptor ring in bytes */
-	unsigned int size;
-	/* number of descriptors in the ring */
-	unsigned int count;
-	/* next descriptor to associate a buffer with */
-	unsigned int next_to_use;
-	/* next descriptor to check for DD status bit */
-	unsigned int next_to_clean;
-	/* array of buffer information structs */
-	struct e1000_buffer *buffer_info;
-
-	spinlock_t tx_lock;
-	u16 tdh;
-	u16 tdt;
-
-	/* TXDdescriptor index increment to be used when advancing
-	* to the next descriptor. This is normally one, but on some
-	* architectures, but on some architectures there are cache
-	* coherency issues that require only the first descriptor in
-	* cache line can be used.
-	*/
-	unsigned int step;
-
-	bool last_tx_tso;
-};
-
-struct e1000_rx_ring {
-	struct e1000_adapter *adapter; /* back link */
-	/* pointer to the descriptor ring memory */
-	void *desc;
-	/* physical address of the descriptor ring */
-	dma_addr_t dma;
-	/* length of descriptor ring in bytes */
-	unsigned int size;
-	/* number of descriptors in the ring */
-	unsigned int count;
-	/* next descriptor to associate a buffer with */
-	unsigned int next_to_use;
-	/* next descriptor to check for DD status bit */
-	unsigned int next_to_clean;
-	/* array of buffer information structs */
-	struct e1000_rx_buffer *buffer_info;
-	struct sk_buff *rx_skb_top;
-
-	/* cpu for rx queue */
-	int cpu;
-
-	u16 rdh;
-	u16 rdt;
-};
-
-
-#define E1000_TX_DESC_INC(R,index) \
-	{index += (R)->step; if (index == (R)->count) index = 0; }
-
-#define E1000_TX_DESC_DEC(R,index) \
-	{ if (index == 0) index = (R)->count - (R)->step; \
-	else index -= (R)->step; }
-
-#define E1000_DESC_UNUSED(R) \
-	((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
-	(R)->next_to_clean - (R)->next_to_use - 1)
-
-#define E1000_RX_DESC_EXT(R, i)	    \
-	(&(((union e1000_rx_desc_extended *)((R).desc))[i]))
-#define E1000_GET_DESC(R, i, type)	(&(((struct type *)((R).desc))[i]))
-#define E1000_RX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_rx_desc)
-#define E1000_TX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_tx_desc)
-#define E1000_CONTEXT_DESC(R, i)	E1000_GET_DESC(R, i, e1000_context_desc)
-
-/* board specific private data structure */
-
-struct e1000_adapter {
-	u32 bd_number;
-	u32 rx_buffer_len;
-	u32 wol;
-	u32 smartspeed;
-	u32 en_mng_pt;
-	u16 link_speed;
-	u16 link_duplex;
-	spinlock_t stats_lock;
-	unsigned int total_tx_bytes;
-	unsigned int total_tx_packets;
-	unsigned int total_rx_bytes;
-	unsigned int total_rx_packets;
-	/* Interrupt Throttle Rate */
-	u32 itr;
-	u32 itr_setting;
-	u16 tx_itr;
-	u16 rx_itr;
-
-	bool fc_autoneg;
-
-	/* TX */
-	struct e1000_tx_ring *tx_ring;
-	unsigned int restart_queue;
-	unsigned long tx_queue_len;
-	u32 txd_cmd;
-	u32 tx_int_delay;
-	u32 tx_abs_int_delay;
-	u32 gotc;
-	u64 gotc_old;
-	u64 tpt_old;
-	u64 colc_old;
-	u32 tx_timeout_count;
-	u32 tx_fifo_head;
-	u32 tx_head_addr;
-	u32 tx_fifo_size;
-	u8 tx_timeout_factor;
-	bool pcix_82544;
-	bool detect_tx_hung;
-
-	/* RX */
-	bool (*clean_rx) (struct e1000_adapter *adapter,
-			       struct e1000_rx_ring *rx_ring);
-	void (*alloc_rx_buf) (struct e1000_adapter *adapter,
-			      struct e1000_rx_ring *rx_ring,
-				int cleaned_count);
-	struct e1000_rx_ring *rx_ring;
-
-	u64 hw_csum_err;
-	u64 hw_csum_good;
-	u32 alloc_rx_buff_failed;
-	u32 rx_int_delay;
-	u32 rx_abs_int_delay;
-	bool rx_csum;
-	u32 gorc;
-	u64 gorc_old;
-	u32 max_frame_size;
-	u32 min_frame_size;
-
-
-	/* OS defined structs */
-	struct net_device *netdev;
-	struct pci_device *pdev;
-	struct net_device_stats net_stats;
-
-	/* structs defined in e1000_hw.h */
-	struct e1000_hw hw;
-	struct e1000_hw_stats stats;
-	struct e1000_phy_info phy_info;
-	struct e1000_phy_stats phy_stats;
-
-	int msg_enable;
-	/* to not mess up cache alignment, always add to the bottom */
-	unsigned long state;
-	u32 eeprom_wol;
-
-	u32 *config_space;
-
-	/* hardware capability, feature, and workaround flags */
-	unsigned int flags;
-
-	/* upper limit parameter for tx desc size */
-	u32 tx_desc_pwr;
-
-#define NUM_TX_DESC	8
-#define NUM_RX_DESC	8
-
-	struct io_buffer *tx_iobuf[NUM_TX_DESC];
-	struct io_buffer *rx_iobuf[NUM_RX_DESC];
-
-	struct e1000_tx_desc *tx_base;
-	struct e1000_rx_desc *rx_base;
-
-	uint32_t tx_ring_size;
-	uint32_t rx_ring_size;
-
-	uint32_t tx_head;
-	uint32_t tx_tail;
-	uint32_t tx_fill_ctr;
-
-	uint32_t rx_curr;
-
-	uint32_t ioaddr;
-	uint32_t irqno;
-};
-
-#define E1000_FLAG_HAS_SMBUS                (1 << 0)
-#define E1000_FLAG_HAS_INTR_MODERATION      (1 << 4)
-#define E1000_FLAG_BAD_TX_CARRIER_STATS_FD  (1 << 6)
-#define E1000_FLAG_QUAD_PORT_A              (1 << 8)
-#define E1000_FLAG_SMART_POWER_DOWN         (1 << 9)
-
-extern char e1000_driver_name[];
-extern const char e1000_driver_version[];
-
-extern void e1000_power_up_phy(struct e1000_hw *hw);
-
-extern void e1000_set_ethtool_ops(struct net_device *netdev);
-extern void e1000_check_options(struct e1000_adapter *adapter);
-
-extern int e1000_up(struct e1000_adapter *adapter);
-extern void e1000_down(struct e1000_adapter *adapter);
-extern void e1000_reinit_locked(struct e1000_adapter *adapter);
-extern void e1000_reset(struct e1000_adapter *adapter);
-extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx);
-extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
-extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
-extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
-extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
-extern void e1000_update_stats(struct e1000_adapter *adapter);
-
-#endif /* _E1000_H_ */
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_82540.c b/roms/ipxe/src/drivers/net/e1000/e1000_82540.c
deleted file mode 100644
index 41f3f979fb0684feed51be53e0ca7227ef3bfeb5..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_82540.c
+++ /dev/null
@@ -1,754 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/*
- * 82540EM Gigabit Ethernet Controller
- * 82540EP Gigabit Ethernet Controller
- * 82545EM Gigabit Ethernet Controller (Copper)
- * 82545EM Gigabit Ethernet Controller (Fiber)
- * 82545GM Gigabit Ethernet Controller
- * 82546EB Gigabit Ethernet Controller (Copper)
- * 82546EB Gigabit Ethernet Controller (Fiber)
- * 82546GB Gigabit Ethernet Controller
- */
-
-#include "e1000_api.h"
-
-static s32  e1000_init_phy_params_82540(struct e1000_hw *hw);
-static s32  e1000_init_nvm_params_82540(struct e1000_hw *hw);
-static s32  e1000_init_mac_params_82540(struct e1000_hw *hw);
-static s32  e1000_adjust_serdes_amplitude_82540(struct e1000_hw *hw);
-static void e1000_clear_hw_cntrs_82540(struct e1000_hw *hw);
-static s32  e1000_init_hw_82540(struct e1000_hw *hw);
-static s32  e1000_reset_hw_82540(struct e1000_hw *hw);
-static s32  e1000_set_phy_mode_82540(struct e1000_hw *hw);
-static s32  e1000_set_vco_speed_82540(struct e1000_hw *hw);
-static s32  e1000_setup_copper_link_82540(struct e1000_hw *hw);
-static s32  e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw);
-static void e1000_power_down_phy_copper_82540(struct e1000_hw *hw);
-static s32  e1000_read_mac_addr_82540(struct e1000_hw *hw);
-
-/**
- * e1000_init_phy_params_82540 - Init PHY func ptrs.
- * @hw: pointer to the HW structure
- **/
-static s32 e1000_init_phy_params_82540(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-
-	phy->addr                      = 1;
-	phy->autoneg_mask              = AUTONEG_ADVERTISE_SPEED_DEFAULT;
-	phy->reset_delay_us            = 10000;
-	phy->type                      = e1000_phy_m88;
-
-	/* Function Pointers */
-	phy->ops.check_polarity        = e1000_check_polarity_m88;
-	phy->ops.commit                = e1000_phy_sw_reset_generic;
-#if 0
-	phy->ops.force_speed_duplex    = e1000_phy_force_speed_duplex_m88;
-#endif
-#if 0
-	phy->ops.get_cable_length      = e1000_get_cable_length_m88;
-#endif
-	phy->ops.get_cfg_done          = e1000_get_cfg_done_generic;
-	phy->ops.read_reg              = e1000_read_phy_reg_m88;
-	phy->ops.reset                 = e1000_phy_hw_reset_generic;
-	phy->ops.write_reg             = e1000_write_phy_reg_m88;
-	phy->ops.get_info              = e1000_get_phy_info_m88;
-	phy->ops.power_up              = e1000_power_up_phy_copper;
-	phy->ops.power_down            = e1000_power_down_phy_copper_82540;
-
-	ret_val = e1000_get_phy_id(hw);
-	if (ret_val)
-		goto out;
-
-	/* Verify phy id */
-	switch (hw->mac.type) {
-	case e1000_82540:
-	case e1000_82545:
-	case e1000_82545_rev_3:
-	case e1000_82546:
-	case e1000_82546_rev_3:
-		if (phy->id == M88E1011_I_PHY_ID)
-			break;
-		/* Fall Through */
-	default:
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-		break;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- * e1000_init_nvm_params_82540 - Init NVM func ptrs.
- * @hw: pointer to the HW structure
- **/
-static s32 e1000_init_nvm_params_82540(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
-
-	DEBUGFUNC("e1000_init_nvm_params_82540");
-
-	nvm->type               = e1000_nvm_eeprom_microwire;
-	nvm->delay_usec         = 50;
-	nvm->opcode_bits        = 3;
-	switch (nvm->override) {
-	case e1000_nvm_override_microwire_large:
-		nvm->address_bits       = 8;
-		nvm->word_size          = 256;
-		break;
-	case e1000_nvm_override_microwire_small:
-		nvm->address_bits       = 6;
-		nvm->word_size          = 64;
-		break;
-	default:
-		nvm->address_bits       = eecd & E1000_EECD_SIZE ? 8 : 6;
-		nvm->word_size          = eecd & E1000_EECD_SIZE ? 256 : 64;
-		break;
-	}
-
-	/* Function Pointers */
-	nvm->ops.acquire            = e1000_acquire_nvm_generic;
-	nvm->ops.read               = e1000_read_nvm_microwire;
-	nvm->ops.release            = e1000_release_nvm_generic;
-	nvm->ops.update             = e1000_update_nvm_checksum_generic;
-	nvm->ops.valid_led_default  = e1000_valid_led_default_generic;
-	nvm->ops.validate           = e1000_validate_nvm_checksum_generic;
-	nvm->ops.write              = e1000_write_nvm_microwire;
-
-	return E1000_SUCCESS;
-}
-
-/**
- * e1000_init_mac_params_82540 - Init MAC func ptrs.
- * @hw: pointer to the HW structure
- **/
-static s32 e1000_init_mac_params_82540(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_init_mac_params_82540");
-
-	/* Set media type */
-	switch (hw->device_id) {
-	case E1000_DEV_ID_82545EM_FIBER:
-	case E1000_DEV_ID_82545GM_FIBER:
-	case E1000_DEV_ID_82546EB_FIBER:
-	case E1000_DEV_ID_82546GB_FIBER:
-		hw->phy.media_type = e1000_media_type_fiber;
-		break;
-	case E1000_DEV_ID_82545GM_SERDES:
-	case E1000_DEV_ID_82546GB_SERDES:
-		hw->phy.media_type = e1000_media_type_internal_serdes;
-		break;
-	default:
-		hw->phy.media_type = e1000_media_type_copper;
-		break;
-	}
-
-	/* Set mta register count */
-	mac->mta_reg_count = 128;
-	/* Set rar entry count */
-	mac->rar_entry_count = E1000_RAR_ENTRIES;
-
-	/* Function pointers */
-
-	/* bus type/speed/width */
-	mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
-	/* function id */
-	mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci;
-	/* reset */
-	mac->ops.reset_hw = e1000_reset_hw_82540;
-	/* hw initialization */
-	mac->ops.init_hw = e1000_init_hw_82540;
-	/* link setup */
-	mac->ops.setup_link = e1000_setup_link_generic;
-	/* physical interface setup */
-	mac->ops.setup_physical_interface =
-	        (hw->phy.media_type == e1000_media_type_copper)
-	                ? e1000_setup_copper_link_82540
-	                : e1000_setup_fiber_serdes_link_82540;
-	/* check for link */
-	switch (hw->phy.media_type) {
-	case e1000_media_type_copper:
-		mac->ops.check_for_link = e1000_check_for_copper_link_generic;
-		break;
-	case e1000_media_type_fiber:
-		mac->ops.check_for_link = e1000_check_for_fiber_link_generic;
-		break;
-	case e1000_media_type_internal_serdes:
-		mac->ops.check_for_link = e1000_check_for_serdes_link_generic;
-		break;
-	default:
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-		break;
-	}
-	/* link info */
-	mac->ops.get_link_up_info =
-	        (hw->phy.media_type == e1000_media_type_copper)
-	                ? e1000_get_speed_and_duplex_copper_generic
-	                : e1000_get_speed_and_duplex_fiber_serdes_generic;
-	/* multicast address update */
-	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
-	/* writing VFTA */
-	mac->ops.write_vfta = e1000_write_vfta_generic;
-	/* clearing VFTA */
-	mac->ops.clear_vfta = e1000_clear_vfta_generic;
-	/* setting MTA */
-	mac->ops.mta_set = e1000_mta_set_generic;
-	/* read mac address */
-	mac->ops.read_mac_addr = e1000_read_mac_addr_82540;
-	/* ID LED init */
-	mac->ops.id_led_init = e1000_id_led_init_generic;
-	/* setup LED */
-	mac->ops.setup_led = e1000_setup_led_generic;
-	/* cleanup LED */
-	mac->ops.cleanup_led = e1000_cleanup_led_generic;
-	/* turn on/off LED */
-	mac->ops.led_on = e1000_led_on_generic;
-	mac->ops.led_off = e1000_led_off_generic;
-	/* clear hardware counters */
-	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82540;
-
-out:
-	return ret_val;
-}
-
-/**
- * e1000_init_function_pointers_82540 - Init func ptrs.
- * @hw: pointer to the HW structure
- *
- * Called to initialize all function pointers and parameters.
- **/
-void e1000_init_function_pointers_82540(struct e1000_hw *hw)
-{
-	DEBUGFUNC("e1000_init_function_pointers_82540");
-
-	hw->mac.ops.init_params = e1000_init_mac_params_82540;
-	hw->nvm.ops.init_params = e1000_init_nvm_params_82540;
-	hw->phy.ops.init_params = e1000_init_phy_params_82540;
-}
-
-/**
- *  e1000_reset_hw_82540 - Reset hardware
- *  @hw: pointer to the HW structure
- *
- *  This resets the hardware into a known state.
- **/
-static s32 e1000_reset_hw_82540(struct e1000_hw *hw)
-{
-	u32 ctrl, manc;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_reset_hw_82540");
-
-	DEBUGOUT("Masking off all interrupts\n");
-	E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
-
-	E1000_WRITE_REG(hw, E1000_RCTL, 0);
-	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
-	E1000_WRITE_FLUSH(hw);
-
-	/*
-	 * Delay to allow any outstanding PCI transactions to complete
-	 * before resetting the device.
-	 */
-	msec_delay(10);
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	DEBUGOUT("Issuing a global reset to 82540/82545/82546 MAC\n");
-	switch (hw->mac.type) {
-	case e1000_82545_rev_3:
-	case e1000_82546_rev_3:
-		E1000_WRITE_REG(hw, E1000_CTRL_DUP, ctrl | E1000_CTRL_RST);
-		break;
-	default:
-		/*
-		 * These controllers can't ack the 64-bit write when
-		 * issuing the reset, so we use IO-mapping as a
-		 * workaround to issue the reset.
-		 */
-		E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
-		break;
-	}
-
-	/* Wait for EEPROM reload */
-	msec_delay(5);
-
-	/* Disable HW ARPs on ASF enabled adapters */
-	manc = E1000_READ_REG(hw, E1000_MANC);
-	manc &= ~E1000_MANC_ARP_EN;
-	E1000_WRITE_REG(hw, E1000_MANC, manc);
-
-	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
-	E1000_READ_REG(hw, E1000_ICR);
-
-	return ret_val;
-}
-
-/**
- *  e1000_init_hw_82540 - Initialize hardware
- *  @hw: pointer to the HW structure
- *
- *  This inits the hardware readying it for operation.
- **/
-static s32 e1000_init_hw_82540(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 txdctl, ctrl_ext;
-	s32 ret_val = E1000_SUCCESS;
-	u16 i;
-
-	DEBUGFUNC("e1000_init_hw_82540");
-
-	/* Initialize identification LED */
-	ret_val = mac->ops.id_led_init(hw);
-	if (ret_val) {
-		DEBUGOUT("Error initializing identification LED\n");
-		/* This is not fatal and we should not stop init due to this */
-	}
-
-	/* Disabling VLAN filtering */
-	DEBUGOUT("Initializing the IEEE VLAN\n");
-	if (mac->type < e1000_82545_rev_3)
-		E1000_WRITE_REG(hw, E1000_VET, 0);
-
-	mac->ops.clear_vfta(hw);
-
-	/* Setup the receive address. */
-	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
-
-	/* Zero out the Multicast HASH table */
-	DEBUGOUT("Zeroing the MTA\n");
-	for (i = 0; i < mac->mta_reg_count; i++) {
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
-		/*
-		 * Avoid back to back register writes by adding the register
-		 * read (flush).  This is to protect against some strange
-		 * bridge configurations that may issue Memory Write Block
-		 * (MWB) to our register space.  The *_rev_3 hardware at
-		 * least doesn't respond correctly to every other dword in an
-		 * MWB to our register space.
-		 */
-		E1000_WRITE_FLUSH(hw);
-	}
-
-	if (mac->type < e1000_82545_rev_3)
-		e1000_pcix_mmrbc_workaround_generic(hw);
-
-	/* Setup link and flow control */
-	ret_val = mac->ops.setup_link(hw);
-
-	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
-	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
-	         E1000_TXDCTL_FULL_TX_DESC_WB;
-	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
-
-	/*
-	 * Clear all of the statistics registers (clear on read).  It is
-	 * important that we do this after we have tried to establish link
-	 * because the symbol error count will increment wildly if there
-	 * is no link.
-	 */
-	e1000_clear_hw_cntrs_82540(hw);
-
-	if ((hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER) ||
-	    (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3)) {
-		ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
-		/*
-		 * Relaxed ordering must be disabled to avoid a parity
-		 * error crash in a PCI slot.
-		 */
-		ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
-		E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000_setup_copper_link_82540 - Configure copper link settings
- *  @hw: pointer to the HW structure
- *
- *  Calls the appropriate function to configure the link for auto-neg or forced
- *  speed and duplex.  Then we check for link, once link is established calls
- *  to configure collision distance and flow control are called.  If link is
- *  not established, we return -E1000_ERR_PHY (-2).
- **/
-static s32 e1000_setup_copper_link_82540(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val = E1000_SUCCESS;
-	u16 data;
-
-	DEBUGFUNC("e1000_setup_copper_link_82540");
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	ctrl |= E1000_CTRL_SLU;
-	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-	ret_val = e1000_set_phy_mode_82540(hw);
-	if (ret_val)
-		goto out;
-
-	if (hw->mac.type == e1000_82545_rev_3 ||
-	    hw->mac.type == e1000_82546_rev_3) {
-		ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &data);
-		if (ret_val)
-			goto out;
-		data |= 0x00000008;
-		ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, data);
-		if (ret_val)
-			goto out;
-	}
-
-	ret_val = e1000_copper_link_setup_m88(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000_setup_copper_link_generic(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_setup_fiber_serdes_link_82540 - Setup link for fiber/serdes
- *  @hw: pointer to the HW structure
- *
- *  Set the output amplitude to the value in the EEPROM and adjust the VCO
- *  speed to improve Bit Error Rate (BER) performance.  Configures collision
- *  distance and flow control for fiber and serdes links.  Upon successful
- *  setup, poll for link.
- **/
-static s32 e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_setup_fiber_serdes_link_82540");
-
-	switch (mac->type) {
-	case e1000_82545_rev_3:
-	case e1000_82546_rev_3:
-		if (hw->phy.media_type == e1000_media_type_internal_serdes) {
-			/*
-			 * If we're on serdes media, adjust the output
-			 * amplitude to value set in the EEPROM.
-			 */
-			ret_val = e1000_adjust_serdes_amplitude_82540(hw);
-			if (ret_val)
-				goto out;
-		}
-		/* Adjust VCO speed to improve BER performance */
-		ret_val = e1000_set_vco_speed_82540(hw);
-		if (ret_val)
-			goto out;
-	default:
-		break;
-	}
-
-	ret_val = e1000_setup_fiber_serdes_link_generic(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_adjust_serdes_amplitude_82540 - Adjust amplitude based on EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Adjust the SERDES output amplitude based on the EEPROM settings.
- **/
-static s32 e1000_adjust_serdes_amplitude_82540(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 nvm_data;
-
-	DEBUGFUNC("e1000_adjust_serdes_amplitude_82540");
-
-	ret_val = hw->nvm.ops.read(hw, NVM_SERDES_AMPLITUDE, 1, &nvm_data);
-	if (ret_val)
-		goto out;
-
-	if (nvm_data != NVM_RESERVED_WORD) {
-		/* Adjust serdes output amplitude only. */
-		nvm_data &= NVM_SERDES_AMPLITUDE_MASK;
-		ret_val = hw->phy.ops.write_reg(hw,
-		                             M88E1000_PHY_EXT_CTRL,
-		                             nvm_data);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_set_vco_speed_82540 - Set VCO speed for better performance
- *  @hw: pointer to the HW structure
- *
- *  Set the VCO speed to improve Bit Error Rate (BER) performance.
- **/
-static s32 e1000_set_vco_speed_82540(struct e1000_hw *hw)
-{
-	s32  ret_val = E1000_SUCCESS;
-	u16 default_page = 0;
-	u16 phy_data;
-
-	DEBUGFUNC("e1000_set_vco_speed_82540");
-
-	/* Set PHY register 30, page 5, bit 8 to 0 */
-
-	ret_val = hw->phy.ops.read_reg(hw,
-	                            M88E1000_PHY_PAGE_SELECT,
-	                            &default_page);
-	if (ret_val)
-		goto out;
-
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005);
-	if (ret_val)
-		goto out;
-
-	ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data &= ~M88E1000_PHY_VCO_REG_BIT8;
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
-	if (ret_val)
-		goto out;
-
-	/* Set PHY register 30, page 4, bit 11 to 1 */
-
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004);
-	if (ret_val)
-		goto out;
-
-	ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data |= M88E1000_PHY_VCO_REG_BIT11;
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
-	if (ret_val)
-		goto out;
-
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT,
-	                              default_page);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_set_phy_mode_82540 - Set PHY to class A mode
- *  @hw: pointer to the HW structure
- *
- *  Sets the PHY to class A mode and assumes the following operations will
- *  follow to enable the new class mode:
- *    1.  Do a PHY soft reset.
- *    2.  Restart auto-negotiation or force link.
- **/
-static s32 e1000_set_phy_mode_82540(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 nvm_data;
-
-	DEBUGFUNC("e1000_set_phy_mode_82540");
-
-	if (hw->mac.type != e1000_82545_rev_3)
-		goto out;
-
-	ret_val = hw->nvm.ops.read(hw, NVM_PHY_CLASS_WORD, 1, &nvm_data);
-	if (ret_val) {
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-
-	if ((nvm_data != NVM_RESERVED_WORD) && (nvm_data & NVM_PHY_CLASS_A)) {
-		ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT,
-		                              0x000B);
-		if (ret_val) {
-			ret_val = -E1000_ERR_PHY;
-			goto out;
-		}
-		ret_val = hw->phy.ops.write_reg(hw,
-		                              M88E1000_PHY_GEN_CONTROL,
-		                              0x8104);
-		if (ret_val) {
-			ret_val = -E1000_ERR_PHY;
-			goto out;
-		}
-
-		phy->reset_disable = false;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- * e1000_power_down_phy_copper_82540 - Remove link in case of PHY power down
- * @hw: pointer to the HW structure
- *
- * In the case of a PHY power down to save power, or to turn off link during a
- * driver unload, or wake on lan is not enabled, remove the link.
- **/
-static void e1000_power_down_phy_copper_82540(struct e1000_hw *hw)
-{
-	/* If the management interface is not enabled, then power down */
-	if (!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_SMBUS_EN))
-		e1000_power_down_phy_copper(hw);
-
-	return;
-}
-
-/**
- *  e1000_clear_hw_cntrs_82540 - Clear device specific hardware counters
- *  @hw: pointer to the HW structure
- *
- *  Clears the hardware counters by reading the counter registers.
- **/
-static void e1000_clear_hw_cntrs_82540(struct e1000_hw *hw)
-{
-	DEBUGFUNC("e1000_clear_hw_cntrs_82540");
-
-	e1000_clear_hw_cntrs_base_generic(hw);
-
-#if 0
-	E1000_READ_REG(hw, E1000_PRC64);
-	E1000_READ_REG(hw, E1000_PRC127);
-	E1000_READ_REG(hw, E1000_PRC255);
-	E1000_READ_REG(hw, E1000_PRC511);
-	E1000_READ_REG(hw, E1000_PRC1023);
-	E1000_READ_REG(hw, E1000_PRC1522);
-	E1000_READ_REG(hw, E1000_PTC64);
-	E1000_READ_REG(hw, E1000_PTC127);
-	E1000_READ_REG(hw, E1000_PTC255);
-	E1000_READ_REG(hw, E1000_PTC511);
-	E1000_READ_REG(hw, E1000_PTC1023);
-	E1000_READ_REG(hw, E1000_PTC1522);
-
-	E1000_READ_REG(hw, E1000_ALGNERRC);
-	E1000_READ_REG(hw, E1000_RXERRC);
-	E1000_READ_REG(hw, E1000_TNCRS);
-	E1000_READ_REG(hw, E1000_CEXTERR);
-	E1000_READ_REG(hw, E1000_TSCTC);
-	E1000_READ_REG(hw, E1000_TSCTFC);
-
-	E1000_READ_REG(hw, E1000_MGTPRC);
-	E1000_READ_REG(hw, E1000_MGTPDC);
-	E1000_READ_REG(hw, E1000_MGTPTC);
-#endif
-}
-
-/**
- *  e1000_read_mac_addr_82540 - Read device MAC address
- *  @hw: pointer to the HW structure
- *
- *  Reads the device MAC address from the EEPROM and stores the value.
- *  Since devices with two ports use the same EEPROM, we increment the
- *  last bit in the MAC address for the second port.
- *
- *  This version is being used over generic because of customer issues
- *  with VmWare and Virtual Box when using generic. It seems in
- *  the emulated 82545, RAR[0] does NOT have a valid address after a
- *  reset, this older method works and using this breaks nothing for
- *  these legacy adapters.
- **/
-s32 e1000_read_mac_addr_82540(struct e1000_hw *hw)
-{
-	s32  ret_val = E1000_SUCCESS;
-	u16 offset, nvm_data, i;
-
-	DEBUGFUNC("e1000_read_mac_addr");
-
-	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
-		offset = i >> 1;
-		ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
-		if (ret_val) {
-			DEBUGOUT("NVM Read Error\n");
-			goto out;
-		}
-		hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
-		hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
-	}
-
-	/* Flip last bit of mac address if we're on second port */
-	if (hw->bus.func == E1000_FUNC_1)
-		hw->mac.perm_addr[5] ^= 1;
-
-	for (i = 0; i < ETH_ADDR_LEN; i++)
-		hw->mac.addr[i] = hw->mac.perm_addr[i];
-
-out:
-	return ret_val;
-}
-
-static struct pci_device_id e1000_82540_nics[] = {
-     PCI_ROM(0x8086, 0x100E, "E1000_DEV_ID_82540EM", "E1000_DEV_ID_82540EM", e1000_82540),
-     PCI_ROM(0x8086, 0x1015, "E1000_DEV_ID_82540EM_LOM", "E1000_DEV_ID_82540EM_LOM", e1000_82540),
-     PCI_ROM(0x8086, 0x1016, "E1000_DEV_ID_82540EP_LOM", "E1000_DEV_ID_82540EP_LOM", e1000_82540),
-     PCI_ROM(0x8086, 0x1017, "E1000_DEV_ID_82540EP", "E1000_DEV_ID_82540EP", e1000_82540),
-     PCI_ROM(0x8086, 0x101E, "E1000_DEV_ID_82540EP_LP", "E1000_DEV_ID_82540EP_LP", e1000_82540),
-     PCI_ROM(0x8086, 0x100F, "E1000_DEV_ID_82545EM_COPPER", "E1000_DEV_ID_82545EM_COPPER", e1000_82545),
-     PCI_ROM(0x8086, 0x1011, "E1000_DEV_ID_82545EM_FIBER", "E1000_DEV_ID_82545EM_FIBER", e1000_82545),
-     PCI_ROM(0x8086, 0x1026, "E1000_DEV_ID_82545GM_COPPER", "E1000_DEV_ID_82545GM_COPPER", e1000_82545_rev_3),
-     PCI_ROM(0x8086, 0x1027, "E1000_DEV_ID_82545GM_FIBER", "E1000_DEV_ID_82545GM_FIBER", e1000_82545_rev_3),
-     PCI_ROM(0x8086, 0x1028, "E1000_DEV_ID_82545GM_SERDES", "E1000_DEV_ID_82545GM_SERDES", e1000_82545_rev_3),
-     PCI_ROM(0x8086, 0x1010, "E1000_DEV_ID_82546EB_COPPER", "E1000_DEV_ID_82546EB_COPPER", e1000_82546),
-     PCI_ROM(0x8086, 0x1012, "E1000_DEV_ID_82546EB_FIBER", "E1000_DEV_ID_82546EB_FIBER", e1000_82546),
-     PCI_ROM(0x8086, 0x101D, "E1000_DEV_ID_82546EB_QUAD_COPPER", "E1000_DEV_ID_82546EB_QUAD_COPPER", e1000_82546),
-     PCI_ROM(0x8086, 0x1079, "E1000_DEV_ID_82546GB_COPPER", "E1000_DEV_ID_82546GB_COPPER", e1000_82546_rev_3),
-     PCI_ROM(0x8086, 0x107A, "E1000_DEV_ID_82546GB_FIBER", "E1000_DEV_ID_82546GB_FIBER", e1000_82546_rev_3),
-     PCI_ROM(0x8086, 0x107B, "E1000_DEV_ID_82546GB_SERDES", "E1000_DEV_ID_82546GB_SERDES", e1000_82546_rev_3),
-     PCI_ROM(0x8086, 0x108A, "E1000_DEV_ID_82546GB_PCIE", "E1000_DEV_ID_82546GB_PCIE", e1000_82546_rev_3),
-     PCI_ROM(0x8086, 0x1099, "E1000_DEV_ID_82546GB_QUAD_COPPER", "E1000_DEV_ID_82546GB_QUAD_COPPER", e1000_82546_rev_3),
-     PCI_ROM(0x8086, 0x10B5, "E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3", "E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3", e1000_82546_rev_3),
-};
-
-struct pci_driver e1000_82540_driver __pci_driver = {
-	.ids = e1000_82540_nics,
-	.id_count = (sizeof (e1000_82540_nics) / sizeof (e1000_82540_nics[0])),
-	.probe = e1000_probe,
-	.remove = e1000_remove,
-};
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_82541.c b/roms/ipxe/src/drivers/net/e1000/e1000_82541.c
deleted file mode 100644
index 2d1aecc70f2912a9791e32ab4e5a3f85a6c87066..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_82541.c
+++ /dev/null
@@ -1,1314 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/*
- * 82541EI Gigabit Ethernet Controller
- * 82541ER Gigabit Ethernet Controller
- * 82541GI Gigabit Ethernet Controller
- * 82541PI Gigabit Ethernet Controller
- * 82547EI Gigabit Ethernet Controller
- * 82547GI Gigabit Ethernet Controller
- */
-
-#include "e1000_api.h"
-
-static s32  e1000_init_phy_params_82541(struct e1000_hw *hw);
-static s32  e1000_init_nvm_params_82541(struct e1000_hw *hw);
-static s32  e1000_init_mac_params_82541(struct e1000_hw *hw);
-static s32  e1000_reset_hw_82541(struct e1000_hw *hw);
-static s32  e1000_init_hw_82541(struct e1000_hw *hw);
-static s32  e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed,
-                                         u16 *duplex);
-static s32  e1000_phy_hw_reset_82541(struct e1000_hw *hw);
-static s32  e1000_setup_copper_link_82541(struct e1000_hw *hw);
-static s32  e1000_check_for_link_82541(struct e1000_hw *hw);
-#if 0
-static s32  e1000_get_cable_length_igp_82541(struct e1000_hw *hw);
-#endif
-static s32  e1000_set_d3_lplu_state_82541(struct e1000_hw *hw,
-                                          bool active);
-static s32  e1000_setup_led_82541(struct e1000_hw *hw);
-static s32  e1000_cleanup_led_82541(struct e1000_hw *hw);
-static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw);
-#if 0
-static s32  e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,
-                                                     bool link_up);
-#endif
-static s32  e1000_phy_init_script_82541(struct e1000_hw *hw);
-static void e1000_power_down_phy_copper_82541(struct e1000_hw *hw);
-
-#if 0
-static const u16 e1000_igp_cable_length_table[] =
-    { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-      5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25,
-      25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40,
-      40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60,
-      60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90,
-      90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
-      100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
-      110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120};
-#define IGP01E1000_AGC_LENGTH_TABLE_SIZE \
-                (sizeof(e1000_igp_cable_length_table) / \
-                 sizeof(e1000_igp_cable_length_table[0]))
-#endif
-/**
- *  e1000_init_phy_params_82541 - Init PHY func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000_init_phy_params_82541(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_init_phy_params_82541");
-
-	phy->addr                      = 1;
-	phy->autoneg_mask              = AUTONEG_ADVERTISE_SPEED_DEFAULT;
-	phy->reset_delay_us            = 10000;
-	phy->type                      = e1000_phy_igp;
-
-	/* Function Pointers */
-	phy->ops.check_polarity        = e1000_check_polarity_igp;
-#if 0
-	phy->ops.force_speed_duplex    = e1000_phy_force_speed_duplex_igp;
-#endif
-#if 0
-	phy->ops.get_cable_length      = e1000_get_cable_length_igp_82541;
-#endif
-	phy->ops.get_cfg_done          = e1000_get_cfg_done_generic;
-	phy->ops.get_info              = e1000_get_phy_info_igp;
-	phy->ops.read_reg              = e1000_read_phy_reg_igp;
-	phy->ops.reset                 = e1000_phy_hw_reset_82541;
-	phy->ops.set_d3_lplu_state     = e1000_set_d3_lplu_state_82541;
-	phy->ops.write_reg             = e1000_write_phy_reg_igp;
-	phy->ops.power_up              = e1000_power_up_phy_copper;
-	phy->ops.power_down            = e1000_power_down_phy_copper_82541;
-
-	ret_val = e1000_get_phy_id(hw);
-	if (ret_val)
-		goto out;
-
-	/* Verify phy id */
-	if (phy->id != IGP01E1000_I_PHY_ID) {
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_init_nvm_params_82541 - Init NVM func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000_init_nvm_params_82541(struct e1000_hw *hw)
-{
-	struct   e1000_nvm_info *nvm = &hw->nvm;
-	s32  ret_val = E1000_SUCCESS;
-	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
-	u16 size;
-
-	DEBUGFUNC("e1000_init_nvm_params_82541");
-
-	switch (nvm->override) {
-	case e1000_nvm_override_spi_large:
-		nvm->type = e1000_nvm_eeprom_spi;
-		eecd |= E1000_EECD_ADDR_BITS;
-		break;
-	case e1000_nvm_override_spi_small:
-		nvm->type = e1000_nvm_eeprom_spi;
-		eecd &= ~E1000_EECD_ADDR_BITS;
-		break;
-	case e1000_nvm_override_microwire_large:
-		nvm->type = e1000_nvm_eeprom_microwire;
-		eecd |= E1000_EECD_SIZE;
-		break;
-	case e1000_nvm_override_microwire_small:
-		nvm->type = e1000_nvm_eeprom_microwire;
-		eecd &= ~E1000_EECD_SIZE;
-		break;
-	default:
-		nvm->type = eecd & E1000_EECD_TYPE
-		            ? e1000_nvm_eeprom_spi
-		            : e1000_nvm_eeprom_microwire;
-		break;
-	}
-
-	if (nvm->type == e1000_nvm_eeprom_spi) {
-		nvm->address_bits       = (eecd & E1000_EECD_ADDR_BITS)
-		                          ? 16 : 8;
-		nvm->delay_usec         = 1;
-		nvm->opcode_bits        = 8;
-		nvm->page_size          = (eecd & E1000_EECD_ADDR_BITS)
-		                          ? 32 : 8;
-
-		/* Function Pointers */
-		nvm->ops.acquire        = e1000_acquire_nvm_generic;
-		nvm->ops.read           = e1000_read_nvm_spi;
-		nvm->ops.release        = e1000_release_nvm_generic;
-		nvm->ops.update         = e1000_update_nvm_checksum_generic;
-		nvm->ops.valid_led_default = e1000_valid_led_default_generic;
-		nvm->ops.validate       = e1000_validate_nvm_checksum_generic;
-		nvm->ops.write          = e1000_write_nvm_spi;
-
-		/*
-		 * nvm->word_size must be discovered after the pointers
-		 * are set so we can verify the size from the nvm image
-		 * itself.  Temporarily set it to a dummy value so the
-		 * read will work.
-		 */
-		nvm->word_size = 64;
-		ret_val = nvm->ops.read(hw, NVM_CFG, 1, &size);
-		if (ret_val)
-			goto out;
-		size = (size & NVM_SIZE_MASK) >> NVM_SIZE_SHIFT;
-		/*
-		 * if size != 0, it can be added to a constant and become
-		 * the left-shift value to set the word_size.  Otherwise,
-		 * word_size stays at 64.
-		 */
-		if (size) {
-			size += NVM_WORD_SIZE_BASE_SHIFT_82541;
-			nvm->word_size = 1 << size;
-		}
-	} else {
-		nvm->address_bits       = (eecd & E1000_EECD_ADDR_BITS)
-		                          ? 8 : 6;
-		nvm->delay_usec         = 50;
-		nvm->opcode_bits        = 3;
-		nvm->word_size          = (eecd & E1000_EECD_ADDR_BITS)
-		                          ? 256 : 64;
-
-		/* Function Pointers */
-		nvm->ops.acquire        = e1000_acquire_nvm_generic;
-		nvm->ops.read           = e1000_read_nvm_microwire;
-		nvm->ops.release        = e1000_release_nvm_generic;
-		nvm->ops.update         = e1000_update_nvm_checksum_generic;
-		nvm->ops.valid_led_default = e1000_valid_led_default_generic;
-		nvm->ops.validate       = e1000_validate_nvm_checksum_generic;
-		nvm->ops.write          = e1000_write_nvm_microwire;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_init_mac_params_82541 - Init MAC func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000_init_mac_params_82541(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-
-	DEBUGFUNC("e1000_init_mac_params_82541");
-
-	/* Set media type */
-	hw->phy.media_type = e1000_media_type_copper;
-	/* Set mta register count */
-	mac->mta_reg_count = 128;
-	/* Set rar entry count */
-	mac->rar_entry_count = E1000_RAR_ENTRIES;
-	/* Set if part includes ASF firmware */
-	mac->asf_firmware_present = true;
-
-	/* Function Pointers */
-
-	/* bus type/speed/width */
-	mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
-	/* function id */
-	mac->ops.set_lan_id = e1000_set_lan_id_single_port;
-	/* reset */
-	mac->ops.reset_hw = e1000_reset_hw_82541;
-	/* hw initialization */
-	mac->ops.init_hw = e1000_init_hw_82541;
-	/* link setup */
-	mac->ops.setup_link = e1000_setup_link_generic;
-	/* physical interface link setup */
-	mac->ops.setup_physical_interface = e1000_setup_copper_link_82541;
-	/* check for link */
-	mac->ops.check_for_link = e1000_check_for_link_82541;
-	/* link info */
-	mac->ops.get_link_up_info = e1000_get_link_up_info_82541;
-	/* multicast address update */
-	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
-	/* writing VFTA */
-	mac->ops.write_vfta = e1000_write_vfta_generic;
-	/* clearing VFTA */
-	mac->ops.clear_vfta = e1000_clear_vfta_generic;
-	/* setting MTA */
-	mac->ops.mta_set = e1000_mta_set_generic;
-	/* ID LED init */
-	mac->ops.id_led_init = e1000_id_led_init_generic;
-	/* setup LED */
-	mac->ops.setup_led = e1000_setup_led_82541;
-	/* cleanup LED */
-	mac->ops.cleanup_led = e1000_cleanup_led_82541;
-	/* turn on/off LED */
-	mac->ops.led_on = e1000_led_on_generic;
-	mac->ops.led_off = e1000_led_off_generic;
-	/* clear hardware counters */
-	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82541;
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_init_function_pointers_82541 - Init func ptrs.
- *  @hw: pointer to the HW structure
- *
- *  Called to initialize all function pointers and parameters.
- **/
-void e1000_init_function_pointers_82541(struct e1000_hw *hw)
-{
-	DEBUGFUNC("e1000_init_function_pointers_82541");
-
-	hw->mac.ops.init_params = e1000_init_mac_params_82541;
-	hw->nvm.ops.init_params = e1000_init_nvm_params_82541;
-	hw->phy.ops.init_params = e1000_init_phy_params_82541;
-}
-
-/**
- *  e1000_reset_hw_82541 - Reset hardware
- *  @hw: pointer to the HW structure
- *
- *  This resets the hardware into a known state.
- **/
-static s32 e1000_reset_hw_82541(struct e1000_hw *hw)
-{
-	u32 ledctl, ctrl, manc;
-
-	DEBUGFUNC("e1000_reset_hw_82541");
-
-	DEBUGOUT("Masking off all interrupts\n");
-	E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
-
-	E1000_WRITE_REG(hw, E1000_RCTL, 0);
-	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
-	E1000_WRITE_FLUSH(hw);
-
-	/*
-	 * Delay to allow any outstanding PCI transactions to complete
-	 * before resetting the device.
-	 */
-	msec_delay(10);
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	/* Must reset the Phy before resetting the MAC */
-	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
-		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_PHY_RST));
-		msec_delay(5);
-	}
-
-	DEBUGOUT("Issuing a global reset to 82541/82547 MAC\n");
-	switch (hw->mac.type) {
-	case e1000_82541:
-	case e1000_82541_rev_2:
-		/*
-		 * These controllers can't ack the 64-bit write when
-		 * issuing the reset, so we use IO-mapping as a
-		 * workaround to issue the reset.
-		 */
-		E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
-		break;
-	default:
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
-		break;
-	}
-
-	/* Wait for NVM reload */
-	msec_delay(20);
-
-	/* Disable HW ARPs on ASF enabled adapters */
-	manc = E1000_READ_REG(hw, E1000_MANC);
-	manc &= ~E1000_MANC_ARP_EN;
-	E1000_WRITE_REG(hw, E1000_MANC, manc);
-
-	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
-		e1000_phy_init_script_82541(hw);
-
-		/* Configure activity LED after Phy reset */
-		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
-		ledctl &= IGP_ACTIVITY_LED_MASK;
-		ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
-		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
-	}
-
-	/* Once again, mask the interrupts */
-	DEBUGOUT("Masking off all interrupts\n");
-	E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
-
-	/* Clear any pending interrupt events. */
-	E1000_READ_REG(hw, E1000_ICR);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_init_hw_82541 - Initialize hardware
- *  @hw: pointer to the HW structure
- *
- *  This inits the hardware readying it for operation.
- **/
-static s32 e1000_init_hw_82541(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
-	u32 i, txdctl;
-	s32 ret_val;
-
-	DEBUGFUNC("e1000_init_hw_82541");
-
-	/* Initialize identification LED */
-	ret_val = mac->ops.id_led_init(hw);
-	if (ret_val) {
-		DEBUGOUT("Error initializing identification LED\n");
-		/* This is not fatal and we should not stop init due to this */
-	}
-
-	/* Storing the Speed Power Down  value for later use */
-	ret_val = hw->phy.ops.read_reg(hw,
-	                               IGP01E1000_GMII_FIFO,
-	                               &dev_spec->spd_default);
-	if (ret_val)
-		goto out;
-
-	/* Disabling VLAN filtering */
-	DEBUGOUT("Initializing the IEEE VLAN\n");
-	mac->ops.clear_vfta(hw);
-
-	/* Setup the receive address. */
-	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
-
-	/* Zero out the Multicast HASH table */
-	DEBUGOUT("Zeroing the MTA\n");
-	for (i = 0; i < mac->mta_reg_count; i++) {
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
-		/*
-		 * Avoid back to back register writes by adding the register
-		 * read (flush).  This is to protect against some strange
-		 * bridge configurations that may issue Memory Write Block
-		 * (MWB) to our register space.
-		 */
-		E1000_WRITE_FLUSH(hw);
-	}
-
-	/* Setup link and flow control */
-	ret_val = mac->ops.setup_link(hw);
-
-	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
-	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
-	         E1000_TXDCTL_FULL_TX_DESC_WB;
-	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
-
-	/*
-	 * Clear all of the statistics registers (clear on read).  It is
-	 * important that we do this after we have tried to establish link
-	 * because the symbol error count will increment wildly if there
-	 * is no link.
-	 */
-	e1000_clear_hw_cntrs_82541(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- * e1000_get_link_up_info_82541 - Report speed and duplex
- * @hw: pointer to the HW structure
- * @speed: pointer to speed buffer
- * @duplex: pointer to duplex buffer
- *
- * Retrieve the current speed and duplex configuration.
- **/
-static s32 e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed,
-                                        u16 *duplex)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-
-	DEBUGFUNC("e1000_get_link_up_info_82541");
-
-	ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
-	if (ret_val)
-		goto out;
-
-	if (!phy->speed_downgraded)
-		goto out;
-
-	/*
-	 * IGP01 PHY may advertise full duplex operation after speed
-	 * downgrade even if it is operating at half duplex.
-	 * Here we set the duplex settings to match the duplex in the
-	 * link partner's capabilities.
-	 */
-	ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_EXP, &data);
-	if (ret_val)
-		goto out;
-
-	if (!(data & NWAY_ER_LP_NWAY_CAPS)) {
-		*duplex = HALF_DUPLEX;
-	} else {
-		ret_val = phy->ops.read_reg(hw, PHY_LP_ABILITY, &data);
-		if (ret_val)
-			goto out;
-
-		if (*speed == SPEED_100) {
-			if (!(data & NWAY_LPAR_100TX_FD_CAPS))
-				*duplex = HALF_DUPLEX;
-		} else if (*speed == SPEED_10) {
-			if (!(data & NWAY_LPAR_10T_FD_CAPS))
-				*duplex = HALF_DUPLEX;
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_phy_hw_reset_82541 - PHY hardware reset
- *  @hw: pointer to the HW structure
- *
- *  Verify the reset block is not blocking us from resetting.  Acquire
- *  semaphore (if necessary) and read/set/write the device control reset
- *  bit in the PHY.  Wait the appropriate delay time for the device to
- *  reset and release the semaphore (if necessary).
- **/
-static s32 e1000_phy_hw_reset_82541(struct e1000_hw *hw)
-{
-	s32 ret_val;
-	u32 ledctl;
-
-	DEBUGFUNC("e1000_phy_hw_reset_82541");
-
-	ret_val = e1000_phy_hw_reset_generic(hw);
-	if (ret_val)
-		goto out;
-
-	e1000_phy_init_script_82541(hw);
-
-	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
-		/* Configure activity LED after PHY reset */
-		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
-		ledctl &= IGP_ACTIVITY_LED_MASK;
-		ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
-		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_setup_copper_link_82541 - Configure copper link settings
- *  @hw: pointer to the HW structure
- *
- *  Calls the appropriate function to configure the link for auto-neg or forced
- *  speed and duplex.  Then we check for link, once link is established calls
- *  to configure collision distance and flow control are called.  If link is
- *  not established, we return -E1000_ERR_PHY (-2).
- **/
-static s32 e1000_setup_copper_link_82541(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
-	s32  ret_val;
-	u32 ctrl, ledctl;
-
-	DEBUGFUNC("e1000_setup_copper_link_82541");
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	ctrl |= E1000_CTRL_SLU;
-	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-	hw->phy.reset_disable = false;
-
-	/* Earlier revs of the IGP phy require us to force MDI. */
-	if (hw->mac.type == e1000_82541 || hw->mac.type == e1000_82547) {
-		dev_spec->dsp_config = e1000_dsp_config_disabled;
-		phy->mdix = 1;
-	} else {
-		dev_spec->dsp_config = e1000_dsp_config_enabled;
-	}
-
-	ret_val = e1000_copper_link_setup_igp(hw);
-	if (ret_val)
-		goto out;
-
-	if (hw->mac.autoneg) {
-		if (dev_spec->ffe_config == e1000_ffe_config_active)
-			dev_spec->ffe_config = e1000_ffe_config_enabled;
-	}
-
-	/* Configure activity LED after Phy reset */
-	ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
-	ledctl &= IGP_ACTIVITY_LED_MASK;
-	ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
-	E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
-
-	ret_val = e1000_setup_copper_link_generic(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_check_for_link_82541 - Check/Store link connection
- *  @hw: pointer to the HW structure
- *
- *  This checks the link condition of the adapter and stores the
- *  results in the hw->mac structure.
- **/
-static s32 e1000_check_for_link_82541(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val;
-	bool link;
-
-	DEBUGFUNC("e1000_check_for_link_82541");
-
-	/*
-	 * We only want to go out to the PHY registers to see if Auto-Neg
-	 * has completed and/or if our link status has changed.  The
-	 * get_link_status flag is set upon receiving a Link Status
-	 * Change or Rx Sequence Error interrupt.
-	 */
-	if (!mac->get_link_status) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	/*
-	 * First we want to see if the MII Status Register reports
-	 * link.  If so, then we want to get the current speed/duplex
-	 * of the PHY.
-	 */
-	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		goto out;
-
-	if (!link) {
-		ret_val = -E1000_ERR_CONFIG;
-#if 0
-		ret_val = e1000_config_dsp_after_link_change_82541(hw, false);
-#endif
-		goto out; /* No link detected */
-	}
-
-	mac->get_link_status = false;
-
-	/*
-	 * Check if there was DownShift, must be checked
-	 * immediately after link-up
-	 */
-	e1000_check_downshift_generic(hw);
-
-	/*
-	 * If we are forcing speed/duplex, then we simply return since
-	 * we have already determined whether we have link or not.
-	 */
-	if (!mac->autoneg) {
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-#if 0
-	ret_val = e1000_config_dsp_after_link_change_82541(hw, true);
-#endif
-
-	/*
-	 * Auto-Neg is enabled.  Auto Speed Detection takes care
-	 * of MAC speed/duplex configuration.  So we only need to
-	 * configure Collision Distance in the MAC.
-	 */
-	e1000_config_collision_dist_generic(hw);
-
-	/*
-	 * Configure Flow Control now that Auto-Neg has completed.
-	 * First, we need to restore the desired flow control
-	 * settings because we may have had to re-autoneg with a
-	 * different link partner.
-	 */
-	ret_val = e1000_config_fc_after_link_up_generic(hw);
-	if (ret_val) {
-		DEBUGOUT("Error configuring flow control\n");
-	}
-
-out:
-	return ret_val;
-}
-
-#if 0
-/**
- *  e1000_config_dsp_after_link_change_82541 - Config DSP after link
- *  @hw: pointer to the HW structure
- *  @link_up: boolean flag for link up status
- *
- *  Return E1000_ERR_PHY when failing to read/write the PHY, else E1000_SUCCESS
- *  at any other case.
- *
- *  82541_rev_2 & 82547_rev_2 have the capability to configure the DSP when a
- *  gigabit link is achieved to improve link quality.
- **/
-static s32 e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,
-                                                    bool link_up)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
-	s32 ret_val;
-	u32 idle_errs = 0;
-	u16 phy_data, phy_saved_data, speed, duplex, i;
-	u16 ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20;
-	u16 dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
-	                                           {IGP01E1000_PHY_AGC_PARAM_A,
-	                                            IGP01E1000_PHY_AGC_PARAM_B,
-	                                            IGP01E1000_PHY_AGC_PARAM_C,
-	                                            IGP01E1000_PHY_AGC_PARAM_D};
-
-	DEBUGFUNC("e1000_config_dsp_after_link_change_82541");
-
-	if (link_up) {
-		ret_val = hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
-		if (ret_val) {
-			DEBUGOUT("Error getting link speed and duplex\n");
-			goto out;
-		}
-
-		if (speed != SPEED_1000) {
-			ret_val = E1000_SUCCESS;
-			goto out;
-		}
-
-#if 0
-		ret_val = phy->ops.get_cable_length(hw);
-#endif
-		ret_val = -E1000_ERR_CONFIG;
-		if (ret_val)
-			goto out;
-
-		if ((dev_spec->dsp_config == e1000_dsp_config_enabled) &&
-		    phy->min_cable_length >= 50) {
-
-			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
-				ret_val = phy->ops.read_reg(hw,
-				                            dsp_reg_array[i],
-				                            &phy_data);
-				if (ret_val)
-					goto out;
-
-				phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
-
-				ret_val = phy->ops.write_reg(hw,
-				                             dsp_reg_array[i],
-				                             phy_data);
-				if (ret_val)
-					goto out;
-			}
-			dev_spec->dsp_config = e1000_dsp_config_activated;
-		}
-
-		if ((dev_spec->ffe_config != e1000_ffe_config_enabled) ||
-		    (phy->min_cable_length >= 50)) {
-			ret_val = E1000_SUCCESS;
-			goto out;
-		}
-
-		/* clear previous idle error counts */
-		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
-		if (ret_val)
-			goto out;
-
-		for (i = 0; i < ffe_idle_err_timeout; i++) {
-			usec_delay(1000);
-			ret_val = phy->ops.read_reg(hw,
-			                            PHY_1000T_STATUS,
-			                            &phy_data);
-			if (ret_val)
-				goto out;
-
-			idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT);
-			if (idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
-				dev_spec->ffe_config = e1000_ffe_config_active;
-
-				ret_val = phy->ops.write_reg(hw,
-				                  IGP01E1000_PHY_DSP_FFE,
-				                  IGP01E1000_PHY_DSP_FFE_CM_CP);
-				if (ret_val)
-					goto out;
-				break;
-			}
-
-			if (idle_errs)
-				ffe_idle_err_timeout =
-				                 FFE_IDLE_ERR_COUNT_TIMEOUT_100;
-		}
-	} else {
-		if (dev_spec->dsp_config == e1000_dsp_config_activated) {
-			/*
-			 * Save off the current value of register 0x2F5B
-			 * to be restored at the end of the routines.
-			 */
-			ret_val = phy->ops.read_reg(hw,
-			                            0x2F5B,
-			                            &phy_saved_data);
-			if (ret_val)
-				goto out;
-
-			/* Disable the PHY transmitter */
-			ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003);
-			if (ret_val)
-				goto out;
-
-			msec_delay_irq(20);
-
-			ret_val = phy->ops.write_reg(hw,
-			                             0x0000,
-			                             IGP01E1000_IEEE_FORCE_GIG);
-			if (ret_val)
-				goto out;
-			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
-				ret_val = phy->ops.read_reg(hw,
-				                            dsp_reg_array[i],
-				                            &phy_data);
-				if (ret_val)
-					goto out;
-
-				phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
-				phy_data |= IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS;
-
-				ret_val = phy->ops.write_reg(hw,
-				                             dsp_reg_array[i],
-				                             phy_data);
-				if (ret_val)
-					goto out;
-			}
-
-			ret_val = phy->ops.write_reg(hw,
-			                       0x0000,
-			                       IGP01E1000_IEEE_RESTART_AUTONEG);
-			if (ret_val)
-				goto out;
-
-			msec_delay_irq(20);
-
-			/* Now enable the transmitter */
-			ret_val = phy->ops.write_reg(hw,
-			                             0x2F5B,
-			                             phy_saved_data);
-			if (ret_val)
-				goto out;
-
-			dev_spec->dsp_config = e1000_dsp_config_enabled;
-		}
-
-		if (dev_spec->ffe_config != e1000_ffe_config_active) {
-			ret_val = E1000_SUCCESS;
-			goto out;
-		}
-
-		/*
-		 * Save off the current value of register 0x2F5B
-		 * to be restored at the end of the routines.
-		 */
-		ret_val = phy->ops.read_reg(hw, 0x2F5B, &phy_saved_data);
-		if (ret_val)
-			goto out;
-
-		/* Disable the PHY transmitter */
-		ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003);
-		if (ret_val)
-			goto out;
-
-		msec_delay_irq(20);
-
-		ret_val = phy->ops.write_reg(hw,
-		                             0x0000,
-		                             IGP01E1000_IEEE_FORCE_GIG);
-		if (ret_val)
-			goto out;
-
-		ret_val = phy->ops.write_reg(hw,
-		                             IGP01E1000_PHY_DSP_FFE,
-		                             IGP01E1000_PHY_DSP_FFE_DEFAULT);
-		if (ret_val)
-			goto out;
-
-		ret_val = phy->ops.write_reg(hw,
-		                             0x0000,
-		                             IGP01E1000_IEEE_RESTART_AUTONEG);
-		if (ret_val)
-			goto out;
-
-		msec_delay_irq(20);
-
-		/* Now enable the transmitter */
-		ret_val = phy->ops.write_reg(hw, 0x2F5B, phy_saved_data);
-
-		if (ret_val)
-			goto out;
-
-		dev_spec->ffe_config = e1000_ffe_config_enabled;
-	}
-
-out:
-	return ret_val;
-}
-#endif
-
-#if 0
-/**
- *  e1000_get_cable_length_igp_82541 - Determine cable length for igp PHY
- *  @hw: pointer to the HW structure
- *
- *  The automatic gain control (agc) normalizes the amplitude of the
- *  received signal, adjusting for the attenuation produced by the
- *  cable.  By reading the AGC registers, which represent the
- *  combination of coarse and fine gain value, the value can be put
- *  into a lookup table to obtain the approximate cable length
- *  for each channel.
- **/
-static s32 e1000_get_cable_length_igp_82541(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 i, data;
-	u16 cur_agc_value, agc_value = 0;
-	u16 min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
-	u16 agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
-	                                                 {IGP01E1000_PHY_AGC_A,
-	                                                  IGP01E1000_PHY_AGC_B,
-	                                                  IGP01E1000_PHY_AGC_C,
-	                                                  IGP01E1000_PHY_AGC_D};
-
-	DEBUGFUNC("e1000_get_cable_length_igp_82541");
-
-	/* Read the AGC registers for all channels */
-	for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
-		ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &data);
-		if (ret_val)
-			goto out;
-
-		cur_agc_value = data >> IGP01E1000_AGC_LENGTH_SHIFT;
-
-		/* Bounds checking */
-		if ((cur_agc_value >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
-		    (cur_agc_value == 0)) {
-			ret_val = -E1000_ERR_PHY;
-			goto out;
-		}
-
-		agc_value += cur_agc_value;
-
-		if (min_agc_value > cur_agc_value)
-			min_agc_value = cur_agc_value;
-	}
-
-	/* Remove the minimal AGC result for length < 50m */
-	if (agc_value < IGP01E1000_PHY_CHANNEL_NUM * 50) {
-		agc_value -= min_agc_value;
-		/* Average the three remaining channels for the length. */
-		agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1);
-	} else {
-		/* Average the channels for the length. */
-		agc_value /= IGP01E1000_PHY_CHANNEL_NUM;
-	}
-
-	phy->min_cable_length = (e1000_igp_cable_length_table[agc_value] >
-	                         IGP01E1000_AGC_RANGE)
-	                        ? (e1000_igp_cable_length_table[agc_value] -
-	                           IGP01E1000_AGC_RANGE)
-	                        : 0;
-	phy->max_cable_length = e1000_igp_cable_length_table[agc_value] +
-	                        IGP01E1000_AGC_RANGE;
-
-	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
-
-out:
-	return ret_val;
-}
-#endif
-
-/**
- *  e1000_set_d3_lplu_state_82541 - Sets low power link up state for D3
- *  @hw: pointer to the HW structure
- *  @active: boolean used to enable/disable lplu
- *
- *  Success returns 0, Failure returns 1
- *
- *  The low power link up (lplu) state is set to the power management level D3
- *  and SmartSpeed is disabled when active is true, else clear lplu for D3
- *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
- *  is used during Dx states where the power conservation is most important.
- *  During driver activity, SmartSpeed should be enabled so performance is
- *  maintained.
- **/
-static s32 e1000_set_d3_lplu_state_82541(struct e1000_hw *hw, bool active)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-
-	DEBUGFUNC("e1000_set_d3_lplu_state_82541");
-
-	switch (hw->mac.type) {
-	case e1000_82541_rev_2:
-	case e1000_82547_rev_2:
-		break;
-	default:
-		ret_val = e1000_set_d3_lplu_state_generic(hw, active);
-		goto out;
-		break;
-	}
-
-	ret_val = phy->ops.read_reg(hw, IGP01E1000_GMII_FIFO, &data);
-	if (ret_val)
-		goto out;
-
-	if (!active) {
-		data &= ~IGP01E1000_GMII_FLEX_SPD;
-		ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data);
-		if (ret_val)
-			goto out;
-
-		/*
-		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
-		 * during Dx states where the power conservation is most
-		 * important.  During driver activity we should enable
-		 * SmartSpeed, so performance is maintained.
-		 */
-		if (phy->smart_speed == e1000_smart_speed_on) {
-			ret_val = phy->ops.read_reg(hw,
-			                            IGP01E1000_PHY_PORT_CONFIG,
-			                            &data);
-			if (ret_val)
-				goto out;
-
-			data |= IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = phy->ops.write_reg(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		} else if (phy->smart_speed == e1000_smart_speed_off) {
-			ret_val = phy->ops.read_reg(hw,
-			                            IGP01E1000_PHY_PORT_CONFIG,
-			                            &data);
-			if (ret_val)
-				goto out;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = phy->ops.write_reg(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		}
-	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
-	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
-	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
-		data |= IGP01E1000_GMII_FLEX_SPD;
-		ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data);
-		if (ret_val)
-			goto out;
-
-		/* When LPLU is enabled, we should disable SmartSpeed */
-		ret_val = phy->ops.read_reg(hw,
-		                            IGP01E1000_PHY_PORT_CONFIG,
-		                            &data);
-		if (ret_val)
-			goto out;
-
-		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-		ret_val = phy->ops.write_reg(hw,
-		                             IGP01E1000_PHY_PORT_CONFIG,
-		                             data);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_setup_led_82541 - Configures SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  This prepares the SW controllable LED for use and saves the current state
- *  of the LED so it can be later restored.
- **/
-static s32 e1000_setup_led_82541(struct e1000_hw *hw __unused)
-{
-#if 0
-	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
-	s32 ret_val;
-
-	DEBUGFUNC("e1000_setup_led_82541");
-
-	ret_val = hw->phy.ops.read_reg(hw,
-	                               IGP01E1000_GMII_FIFO,
-	                               &dev_spec->spd_default);
-	if (ret_val)
-		goto out;
-
-	ret_val = hw->phy.ops.write_reg(hw,
-	                                IGP01E1000_GMII_FIFO,
-	                                (u16)(dev_spec->spd_default &
-	                                        ~IGP01E1000_GMII_SPD));
-	if (ret_val)
-		goto out;
-
-	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
-
-out:
-	return ret_val;
-#endif
-        return 0;
-}
-
-/**
- *  e1000_cleanup_led_82541 - Set LED config to default operation
- *  @hw: pointer to the HW structure
- *
- *  Remove the current LED configuration and set the LED configuration
- *  to the default value, saved from the EEPROM.
- **/
-static s32 e1000_cleanup_led_82541(struct e1000_hw *hw __unused)
-{
-#if 0
-	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
-	s32 ret_val;
-
-	DEBUGFUNC("e1000_cleanup_led_82541");
-
-	ret_val = hw->phy.ops.write_reg(hw,
-	                                IGP01E1000_GMII_FIFO,
-	                                dev_spec->spd_default);
-	if (ret_val)
-		goto out;
-
-	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
-
-out:
-	return ret_val;
-#endif
-        return 0;
-}
-
-/**
- *  e1000_phy_init_script_82541 - Initialize GbE PHY
- *  @hw: pointer to the HW structure
- *
- *  Initializes the IGP PHY.
- **/
-static s32 e1000_phy_init_script_82541(struct e1000_hw *hw)
-{
-	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
-	u32 ret_val;
-	u16 phy_saved_data;
-
-	DEBUGFUNC("e1000_phy_init_script_82541");
-
-	if (!dev_spec->phy_init_script) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	/* Delay after phy reset to enable NVM configuration to load */
-	msec_delay(20);
-
-	/*
-	 * Save off the current value of register 0x2F5B to be restored at
-	 * the end of this routine.
-	 */
-	ret_val = hw->phy.ops.read_reg(hw, 0x2F5B, &phy_saved_data);
-
-	/* Disabled the PHY transmitter */
-	hw->phy.ops.write_reg(hw, 0x2F5B, 0x0003);
-
-	msec_delay(20);
-
-	hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
-
-	msec_delay(5);
-
-	switch (hw->mac.type) {
-	case e1000_82541:
-	case e1000_82547:
-		hw->phy.ops.write_reg(hw, 0x1F95, 0x0001);
-
-		hw->phy.ops.write_reg(hw, 0x1F71, 0xBD21);
-
-		hw->phy.ops.write_reg(hw, 0x1F79, 0x0018);
-
-		hw->phy.ops.write_reg(hw, 0x1F30, 0x1600);
-
-		hw->phy.ops.write_reg(hw, 0x1F31, 0x0014);
-
-		hw->phy.ops.write_reg(hw, 0x1F32, 0x161C);
-
-		hw->phy.ops.write_reg(hw, 0x1F94, 0x0003);
-
-		hw->phy.ops.write_reg(hw, 0x1F96, 0x003F);
-
-		hw->phy.ops.write_reg(hw, 0x2010, 0x0008);
-		break;
-	case e1000_82541_rev_2:
-	case e1000_82547_rev_2:
-		hw->phy.ops.write_reg(hw, 0x1F73, 0x0099);
-		break;
-	default:
-		break;
-	}
-
-	hw->phy.ops.write_reg(hw, 0x0000, 0x3300);
-
-	msec_delay(20);
-
-	/* Now enable the transmitter */
-	hw->phy.ops.write_reg(hw, 0x2F5B, phy_saved_data);
-
-	if (hw->mac.type == e1000_82547) {
-		u16 fused, fine, coarse;
-
-		/* Move to analog registers page */
-		hw->phy.ops.read_reg(hw,
-		                  IGP01E1000_ANALOG_SPARE_FUSE_STATUS,
-		                  &fused);
-
-		if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
-			hw->phy.ops.read_reg(hw,
-			                  IGP01E1000_ANALOG_FUSE_STATUS,
-			                  &fused);
-
-			fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK;
-			coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK;
-
-			if (coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
-				coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10;
-				fine -= IGP01E1000_ANALOG_FUSE_FINE_1;
-			} else if (coarse ==
-			           IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
-				fine -= IGP01E1000_ANALOG_FUSE_FINE_10;
-
-			fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) |
-			        (fine & IGP01E1000_ANALOG_FUSE_FINE_MASK) |
-			        (coarse & IGP01E1000_ANALOG_FUSE_COARSE_MASK);
-
-			hw->phy.ops.write_reg(hw,
-			                   IGP01E1000_ANALOG_FUSE_CONTROL,
-			                   fused);
-			hw->phy.ops.write_reg(hw,
-			              IGP01E1000_ANALOG_FUSE_BYPASS,
-			              IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL);
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- * e1000_power_down_phy_copper_82541 - Remove link in case of PHY power down
- * @hw: pointer to the HW structure
- *
- * In the case of a PHY power down to save power, or to turn off link during a
- * driver unload, or wake on lan is not enabled, remove the link.
- **/
-static void e1000_power_down_phy_copper_82541(struct e1000_hw *hw)
-{
-	/* If the management interface is not enabled, then power down */
-	if (!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_SMBUS_EN))
-		e1000_power_down_phy_copper(hw);
-
-	return;
-}
-
-/**
- *  e1000_clear_hw_cntrs_82541 - Clear device specific hardware counters
- *  @hw: pointer to the HW structure
- *
- *  Clears the hardware counters by reading the counter registers.
- **/
-static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw)
-{
-	DEBUGFUNC("e1000_clear_hw_cntrs_82541");
-
-	e1000_clear_hw_cntrs_base_generic(hw);
-
-#if 0
-	E1000_READ_REG(hw, E1000_PRC64);
-	E1000_READ_REG(hw, E1000_PRC127);
-	E1000_READ_REG(hw, E1000_PRC255);
-	E1000_READ_REG(hw, E1000_PRC511);
-	E1000_READ_REG(hw, E1000_PRC1023);
-	E1000_READ_REG(hw, E1000_PRC1522);
-	E1000_READ_REG(hw, E1000_PTC64);
-	E1000_READ_REG(hw, E1000_PTC127);
-	E1000_READ_REG(hw, E1000_PTC255);
-	E1000_READ_REG(hw, E1000_PTC511);
-	E1000_READ_REG(hw, E1000_PTC1023);
-	E1000_READ_REG(hw, E1000_PTC1522);
-
-	E1000_READ_REG(hw, E1000_ALGNERRC);
-	E1000_READ_REG(hw, E1000_RXERRC);
-	E1000_READ_REG(hw, E1000_TNCRS);
-	E1000_READ_REG(hw, E1000_CEXTERR);
-	E1000_READ_REG(hw, E1000_TSCTC);
-	E1000_READ_REG(hw, E1000_TSCTFC);
-
-	E1000_READ_REG(hw, E1000_MGTPRC);
-	E1000_READ_REG(hw, E1000_MGTPDC);
-	E1000_READ_REG(hw, E1000_MGTPTC);
-#endif
-}
-
-static struct pci_device_id e1000_82541_nics[] = {
-     PCI_ROM(0x8086, 0x1013, "E1000_DEV_ID_82541EI", "E1000_DEV_ID_82541EI", e1000_82541),
-     PCI_ROM(0x8086, 0x1014, "E1000_DEV_ID_82541ER_LOM", "E1000_DEV_ID_82541ER_LOM", e1000_82541),
-     PCI_ROM(0x8086, 0x1018, "E1000_DEV_ID_82541EI_MOBILE", "E1000_DEV_ID_82541EI_MOBILE", e1000_82541),
-     PCI_ROM(0x8086, 0x1019, "E1000_DEV_ID_82547EI", "E1000_DEV_ID_82547EI", e1000_82547),
-     PCI_ROM(0x8086, 0x101A, "E1000_DEV_ID_82547EI_MOBILE", "E1000_DEV_ID_82547EI_MOBILE", e1000_82547),
-     PCI_ROM(0x8086, 0x1075, "E1000_DEV_ID_82547GI", "E1000_DEV_ID_82547GI", e1000_82547_rev_2),
-     PCI_ROM(0x8086, 0x1076, "E1000_DEV_ID_82541GI", "E1000_DEV_ID_82541GI", e1000_82541_rev_2),
-     PCI_ROM(0x8086, 0x1077, "E1000_DEV_ID_82541GI_MOBILE", "E1000_DEV_ID_82541GI_MOBILE", e1000_82541_rev_2),
-     PCI_ROM(0x8086, 0x1078, "E1000_DEV_ID_82541ER", "E1000_DEV_ID_82541ER", e1000_82541_rev_2),
-     PCI_ROM(0x8086, 0x107C, "E1000_DEV_ID_82541GI_LF", "E1000_DEV_ID_82541GI_LF", e1000_82541_rev_2),
-};
-
-struct pci_driver e1000_82541_driver __pci_driver = {
-	.ids = e1000_82541_nics,
-	.id_count = (sizeof (e1000_82541_nics) / sizeof (e1000_82541_nics[0])),
-	.probe = e1000_probe,
-	.remove = e1000_remove,
-};
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_82541.h b/roms/ipxe/src/drivers/net/e1000/e1000_82541.h
deleted file mode 100644
index f86a1482e33e45f42f1abfd4b0f6831b9f339d0d..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_82541.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000_82541_H_
-#define _E1000_82541_H_
-
-#define NVM_WORD_SIZE_BASE_SHIFT_82541 (NVM_WORD_SIZE_BASE_SHIFT + 1)
-
-#define IGP01E1000_PHY_CHANNEL_NUM                    4
-
-#define IGP01E1000_PHY_AGC_A                     0x1172
-#define IGP01E1000_PHY_AGC_B                     0x1272
-#define IGP01E1000_PHY_AGC_C                     0x1472
-#define IGP01E1000_PHY_AGC_D                     0x1872
-
-#define IGP01E1000_PHY_AGC_PARAM_A               0x1171
-#define IGP01E1000_PHY_AGC_PARAM_B               0x1271
-#define IGP01E1000_PHY_AGC_PARAM_C               0x1471
-#define IGP01E1000_PHY_AGC_PARAM_D               0x1871
-
-#define IGP01E1000_PHY_EDAC_MU_INDEX             0xC000
-#define IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS      0x8000
-
-#define IGP01E1000_PHY_DSP_RESET                 0x1F33
-
-#define IGP01E1000_PHY_DSP_FFE                   0x1F35
-#define IGP01E1000_PHY_DSP_FFE_CM_CP             0x0069
-#define IGP01E1000_PHY_DSP_FFE_DEFAULT           0x002A
-
-#define IGP01E1000_IEEE_FORCE_GIG                0x0140
-#define IGP01E1000_IEEE_RESTART_AUTONEG          0x3300
-
-#define IGP01E1000_AGC_LENGTH_SHIFT                   7
-#define IGP01E1000_AGC_RANGE                         10
-
-#define FFE_IDLE_ERR_COUNT_TIMEOUT_20                20
-#define FFE_IDLE_ERR_COUNT_TIMEOUT_100              100
-
-#define IGP01E1000_ANALOG_FUSE_STATUS            0x20D0
-#define IGP01E1000_ANALOG_SPARE_FUSE_STATUS      0x20D1
-#define IGP01E1000_ANALOG_FUSE_CONTROL           0x20DC
-#define IGP01E1000_ANALOG_FUSE_BYPASS            0x20DE
-
-#define IGP01E1000_ANALOG_SPARE_FUSE_ENABLED     0x0100
-#define IGP01E1000_ANALOG_FUSE_FINE_MASK         0x0F80
-#define IGP01E1000_ANALOG_FUSE_COARSE_MASK       0x0070
-#define IGP01E1000_ANALOG_FUSE_COARSE_THRESH     0x0040
-#define IGP01E1000_ANALOG_FUSE_COARSE_10         0x0010
-#define IGP01E1000_ANALOG_FUSE_FINE_1            0x0080
-#define IGP01E1000_ANALOG_FUSE_FINE_10           0x0500
-#define IGP01E1000_ANALOG_FUSE_POLY_MASK         0xF000
-#define IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL 0x0002
-
-#define IGP01E1000_MSE_CHANNEL_D                 0x000F
-#define IGP01E1000_MSE_CHANNEL_C                 0x00F0
-#define IGP01E1000_MSE_CHANNEL_B                 0x0F00
-#define IGP01E1000_MSE_CHANNEL_A                 0xF000
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_82542.c b/roms/ipxe/src/drivers/net/e1000/e1000_82542.c
deleted file mode 100644
index b6d5202cc77786503b434fb1804f7900b8d5e72b..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_82542.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/*
- * 82542 Gigabit Ethernet Controller
- */
-
-#include "e1000_api.h"
-
-static s32  e1000_init_phy_params_82542(struct e1000_hw *hw);
-static s32  e1000_init_nvm_params_82542(struct e1000_hw *hw);
-static s32  e1000_init_mac_params_82542(struct e1000_hw *hw);
-static s32  e1000_get_bus_info_82542(struct e1000_hw *hw);
-static s32  e1000_reset_hw_82542(struct e1000_hw *hw);
-static s32  e1000_init_hw_82542(struct e1000_hw *hw);
-static s32  e1000_setup_link_82542(struct e1000_hw *hw);
-static s32  e1000_led_on_82542(struct e1000_hw *hw);
-static s32  e1000_led_off_82542(struct e1000_hw *hw);
-static void e1000_rar_set_82542(struct e1000_hw *hw, u8 *addr, u32 index);
-static void e1000_clear_hw_cntrs_82542(struct e1000_hw *hw);
-
-/**
- *  e1000_init_phy_params_82542 - Init PHY func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000_init_phy_params_82542(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_init_phy_params_82542");
-
-	phy->type               = e1000_phy_none;
-
-	return ret_val;
-}
-
-/**
- *  e1000_init_nvm_params_82542 - Init NVM func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000_init_nvm_params_82542(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-
-	DEBUGFUNC("e1000_init_nvm_params_82542");
-
-	nvm->address_bits       =  6;
-	nvm->delay_usec         = 50;
-	nvm->opcode_bits        =  3;
-	nvm->type               = e1000_nvm_eeprom_microwire;
-	nvm->word_size          = 64;
-
-	/* Function Pointers */
-	nvm->ops.read           = e1000_read_nvm_microwire;
-	nvm->ops.release        = e1000_stop_nvm;
-	nvm->ops.write          = e1000_write_nvm_microwire;
-	nvm->ops.update         = e1000_update_nvm_checksum_generic;
-	nvm->ops.validate       = e1000_validate_nvm_checksum_generic;
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_init_mac_params_82542 - Init MAC func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000_init_mac_params_82542(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-
-	DEBUGFUNC("e1000_init_mac_params_82542");
-
-	/* Set media type */
-	hw->phy.media_type = e1000_media_type_fiber;
-
-	/* Set mta register count */
-	mac->mta_reg_count = 128;
-	/* Set rar entry count */
-	mac->rar_entry_count = E1000_RAR_ENTRIES;
-
-	/* Function pointers */
-
-	/* bus type/speed/width */
-	mac->ops.get_bus_info = e1000_get_bus_info_82542;
-	/* function id */
-	mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci;
-	/* reset */
-	mac->ops.reset_hw = e1000_reset_hw_82542;
-	/* hw initialization */
-	mac->ops.init_hw = e1000_init_hw_82542;
-	/* link setup */
-	mac->ops.setup_link = e1000_setup_link_82542;
-	/* phy/fiber/serdes setup */
-	mac->ops.setup_physical_interface = e1000_setup_fiber_serdes_link_generic;
-	/* check for link */
-	mac->ops.check_for_link = e1000_check_for_fiber_link_generic;
-	/* multicast address update */
-	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
-	/* writing VFTA */
-	mac->ops.write_vfta = e1000_write_vfta_generic;
-	/* clearing VFTA */
-	mac->ops.clear_vfta = e1000_clear_vfta_generic;
-	/* setting MTA */
-	mac->ops.mta_set = e1000_mta_set_generic;
-	/* set RAR */
-	mac->ops.rar_set = e1000_rar_set_82542;
-	/* turn on/off LED */
-	mac->ops.led_on = e1000_led_on_82542;
-	mac->ops.led_off = e1000_led_off_82542;
-	/* clear hardware counters */
-	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82542;
-	/* link info */
-	mac->ops.get_link_up_info = e1000_get_speed_and_duplex_fiber_serdes_generic;
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_init_function_pointers_82542 - Init func ptrs.
- *  @hw: pointer to the HW structure
- *
- *  Called to initialize all function pointers and parameters.
- **/
-void e1000_init_function_pointers_82542(struct e1000_hw *hw)
-{
-	DEBUGFUNC("e1000_init_function_pointers_82542");
-
-	hw->mac.ops.init_params = e1000_init_mac_params_82542;
-	hw->nvm.ops.init_params = e1000_init_nvm_params_82542;
-	hw->phy.ops.init_params = e1000_init_phy_params_82542;
-}
-
-/**
- *  e1000_get_bus_info_82542 - Obtain bus information for adapter
- *  @hw: pointer to the HW structure
- *
- *  This will obtain information about the HW bus for which the
- *  adapter is attached and stores it in the hw structure.
- **/
-static s32 e1000_get_bus_info_82542(struct e1000_hw *hw)
-{
-	DEBUGFUNC("e1000_get_bus_info_82542");
-
-	hw->bus.type = e1000_bus_type_pci;
-	hw->bus.speed = e1000_bus_speed_unknown;
-	hw->bus.width = e1000_bus_width_unknown;
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_reset_hw_82542 - Reset hardware
- *  @hw: pointer to the HW structure
- *
- *  This resets the hardware into a known state.
- **/
-static s32 e1000_reset_hw_82542(struct e1000_hw *hw)
-{
-	struct e1000_bus_info *bus = &hw->bus;
-	s32 ret_val = E1000_SUCCESS;
-	u32 ctrl;
-
-	DEBUGFUNC("e1000_reset_hw_82542");
-
-	if (hw->revision_id == E1000_REVISION_2) {
-		DEBUGOUT("Disabling MWI on 82542 rev 2\n");
-		e1000_pci_clear_mwi(hw);
-	}
-
-	DEBUGOUT("Masking off all interrupts\n");
-	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
-
-	E1000_WRITE_REG(hw, E1000_RCTL, 0);
-	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
-	E1000_WRITE_FLUSH(hw);
-
-	/*
-	 * Delay to allow any outstanding PCI transactions to complete before
-	 * resetting the device
-	 */
-	msec_delay(10);
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	DEBUGOUT("Issuing a global reset to 82542/82543 MAC\n");
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
-
-	hw->nvm.ops.reload(hw);
-	msec_delay(2);
-
-	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
-	E1000_READ_REG(hw, E1000_ICR);
-
-	if (hw->revision_id == E1000_REVISION_2) {
-		if (bus->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
-			e1000_pci_set_mwi(hw);
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000_init_hw_82542 - Initialize hardware
- *  @hw: pointer to the HW structure
- *
- *  This inits the hardware readying it for operation.
- **/
-static s32 e1000_init_hw_82542(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	struct e1000_dev_spec_82542 *dev_spec = &hw->dev_spec._82542;
-	s32 ret_val = E1000_SUCCESS;
-	u32 ctrl;
-	u16 i;
-
-	DEBUGFUNC("e1000_init_hw_82542");
-
-	/* Disabling VLAN filtering */
-	E1000_WRITE_REG(hw, E1000_VET, 0);
-	mac->ops.clear_vfta(hw);
-
-	/* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
-	if (hw->revision_id == E1000_REVISION_2) {
-		DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
-		e1000_pci_clear_mwi(hw);
-		E1000_WRITE_REG(hw, E1000_RCTL, E1000_RCTL_RST);
-		E1000_WRITE_FLUSH(hw);
-		msec_delay(5);
-	}
-
-	/* Setup the receive address. */
-	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
-
-	/* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
-	if (hw->revision_id == E1000_REVISION_2) {
-		E1000_WRITE_REG(hw, E1000_RCTL, 0);
-		E1000_WRITE_FLUSH(hw);
-		msec_delay(1);
-		if (hw->bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
-			e1000_pci_set_mwi(hw);
-	}
-
-	/* Zero out the Multicast HASH table */
-	DEBUGOUT("Zeroing the MTA\n");
-	for (i = 0; i < mac->mta_reg_count; i++)
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
-
-	/*
-	 * Set the PCI priority bit correctly in the CTRL register.  This
-	 * determines if the adapter gives priority to receives, or if it
-	 * gives equal priority to transmits and receives.
-	 */
-	if (dev_spec->dma_fairness) {
-		ctrl = E1000_READ_REG(hw, E1000_CTRL);
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PRIOR);
-	}
-
-	/* Setup link and flow control */
-	ret_val = e1000_setup_link_82542(hw);
-
-	/*
-	 * Clear all of the statistics registers (clear on read).  It is
-	 * important that we do this after we have tried to establish link
-	 * because the symbol error count will increment wildly if there
-	 * is no link.
-	 */
-	e1000_clear_hw_cntrs_82542(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000_setup_link_82542 - Setup flow control and link settings
- *  @hw: pointer to the HW structure
- *
- *  Determines which flow control settings to use, then configures flow
- *  control.  Calls the appropriate media-specific link configuration
- *  function.  Assuming the adapter has a valid link partner, a valid link
- *  should be established.  Assumes the hardware has previously been reset
- *  and the transmitter and receiver are not enabled.
- **/
-static s32 e1000_setup_link_82542(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_setup_link_82542");
-
-	ret_val = e1000_set_default_fc_generic(hw);
-	if (ret_val)
-		goto out;
-
-	hw->fc.requested_mode &= ~e1000_fc_tx_pause;
-
-	if (mac->report_tx_early == 1)
-		hw->fc.requested_mode &= ~e1000_fc_rx_pause;
-
-	/*
-	 * Save off the requested flow control mode for use later.  Depending
-	 * on the link partner's capabilities, we may or may not use this mode.
-	 */
-	hw->fc.current_mode = hw->fc.requested_mode;
-
-	DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
-	                                             hw->fc.current_mode);
-
-	/* Call the necessary subroutine to configure the link. */
-	ret_val = mac->ops.setup_physical_interface(hw);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Initialize the flow control address, type, and PAUSE timer
-	 * registers to their default values.  This is done even if flow
-	 * control is disabled, because it does not hurt anything to
-	 * initialize these registers.
-	 */
-	DEBUGOUT("Initializing Flow Control address, type and timer regs\n");
-
-	E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
-	E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
-	E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE);
-
-	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
-
-	ret_val = e1000_set_fc_watermarks_generic(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_led_on_82542 - Turn on SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  Turns the SW defined LED on.
- **/
-static s32 e1000_led_on_82542(struct e1000_hw *hw __unused)
-{
-#if 0
-	u32 ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	DEBUGFUNC("e1000_led_on_82542");
-
-	ctrl |= E1000_CTRL_SWDPIN0;
-	ctrl |= E1000_CTRL_SWDPIO0;
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-	return E1000_SUCCESS;
-#endif
-	return 0;
-}
-
-/**
- *  e1000_led_off_82542 - Turn off SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  Turns the SW defined LED off.
- **/
-static s32 e1000_led_off_82542(struct e1000_hw *hw __unused)
-{
-#if 0
-	u32 ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	DEBUGFUNC("e1000_led_off_82542");
-
-	ctrl &= ~E1000_CTRL_SWDPIN0;
-	ctrl |= E1000_CTRL_SWDPIO0;
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-	return E1000_SUCCESS;
-#endif
-	return 0;
-}
-
-/**
- *  e1000_rar_set_82542 - Set receive address register
- *  @hw: pointer to the HW structure
- *  @addr: pointer to the receive address
- *  @index: receive address array register
- *
- *  Sets the receive address array register at index to the address passed
- *  in by addr.
- **/
-static void e1000_rar_set_82542(struct e1000_hw *hw, u8 *addr, u32 index)
-{
-	u32 rar_low, rar_high;
-
-	DEBUGFUNC("e1000_rar_set_82542");
-
-	/*
-	 * HW expects these in little endian so we reverse the byte order
-	 * from network order (big endian) to little endian
-	 */
-	rar_low = ((u32) addr[0] |
-	           ((u32) addr[1] << 8) |
-	           ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
-
-	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
-
-	/* If MAC address zero, no need to set the AV bit */
-	if (rar_low || rar_high)
-		rar_high |= E1000_RAH_AV;
-
-	E1000_WRITE_REG_ARRAY(hw, E1000_RA, (index << 1), rar_low);
-	E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((index << 1) + 1), rar_high);
-}
-
-/**
- *  e1000_translate_register_82542 - Translate the proper register offset
- *  @reg: e1000 register to be read
- *
- *  Registers in 82542 are located in different offsets than other adapters
- *  even though they function in the same manner.  This function takes in
- *  the name of the register to read and returns the correct offset for
- *  82542 silicon.
- **/
-u32 e1000_translate_register_82542(u32 reg)
-{
-	/*
-	 * Some of the 82542 registers are located at different
-	 * offsets than they are in newer adapters.
-	 * Despite the difference in location, the registers
-	 * function in the same manner.
-	 */
-	switch (reg) {
-	case E1000_RA:
-		reg = 0x00040;
-		break;
-	case E1000_RDTR:
-		reg = 0x00108;
-		break;
-	case E1000_RDBAL(0):
-		reg = 0x00110;
-		break;
-	case E1000_RDBAH(0):
-		reg = 0x00114;
-		break;
-	case E1000_RDLEN(0):
-		reg = 0x00118;
-		break;
-	case E1000_RDH(0):
-		reg = 0x00120;
-		break;
-	case E1000_RDT(0):
-		reg = 0x00128;
-		break;
-	case E1000_RDBAL(1):
-		reg = 0x00138;
-		break;
-	case E1000_RDBAH(1):
-		reg = 0x0013C;
-		break;
-	case E1000_RDLEN(1):
-		reg = 0x00140;
-		break;
-	case E1000_RDH(1):
-		reg = 0x00148;
-		break;
-	case E1000_RDT(1):
-		reg = 0x00150;
-		break;
-	case E1000_FCRTH:
-		reg = 0x00160;
-		break;
-	case E1000_FCRTL:
-		reg = 0x00168;
-		break;
-	case E1000_MTA:
-		reg = 0x00200;
-		break;
-	case E1000_TDBAL(0):
-		reg = 0x00420;
-		break;
-	case E1000_TDBAH(0):
-		reg = 0x00424;
-		break;
-	case E1000_TDLEN(0):
-		reg = 0x00428;
-		break;
-	case E1000_TDH(0):
-		reg = 0x00430;
-		break;
-	case E1000_TDT(0):
-		reg = 0x00438;
-		break;
-	case E1000_TIDV:
-		reg = 0x00440;
-		break;
-	case E1000_VFTA:
-		reg = 0x00600;
-		break;
-	case E1000_TDFH:
-		reg = 0x08010;
-		break;
-	case E1000_TDFT:
-		reg = 0x08018;
-		break;
-	default:
-		break;
-	}
-
-	return reg;
-}
-
-/**
- *  e1000_clear_hw_cntrs_82542 - Clear device specific hardware counters
- *  @hw: pointer to the HW structure
- *
- *  Clears the hardware counters by reading the counter registers.
- **/
-static void e1000_clear_hw_cntrs_82542(struct e1000_hw *hw)
-{
-	DEBUGFUNC("e1000_clear_hw_cntrs_82542");
-
-	e1000_clear_hw_cntrs_base_generic(hw);
-
-#if 0
-	E1000_READ_REG(hw, E1000_PRC64);
-	E1000_READ_REG(hw, E1000_PRC127);
-	E1000_READ_REG(hw, E1000_PRC255);
-	E1000_READ_REG(hw, E1000_PRC511);
-	E1000_READ_REG(hw, E1000_PRC1023);
-	E1000_READ_REG(hw, E1000_PRC1522);
-	E1000_READ_REG(hw, E1000_PTC64);
-	E1000_READ_REG(hw, E1000_PTC127);
-	E1000_READ_REG(hw, E1000_PTC255);
-	E1000_READ_REG(hw, E1000_PTC511);
-	E1000_READ_REG(hw, E1000_PTC1023);
-	E1000_READ_REG(hw, E1000_PTC1522);
-#endif
-}
-
-static struct pci_device_id e1000_82542_nics[] = {
-     PCI_ROM(0x8086, 0x1000, "E1000_DEV_ID_82542", "E1000_DEV_ID_82542", e1000_82542),
-};
-
-struct pci_driver e1000_82542_driver __pci_driver = {
-	.ids = e1000_82542_nics,
-	.id_count = (sizeof (e1000_82542_nics) / sizeof (e1000_82542_nics[0])),
-	.probe = e1000_probe,
-	.remove = e1000_remove,
-};
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_82543.c b/roms/ipxe/src/drivers/net/e1000/e1000_82543.c
deleted file mode 100644
index 848c99e76b49ca4162b8441d9e617800a1ec4113..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_82543.c
+++ /dev/null
@@ -1,1635 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/*
- * 82543GC Gigabit Ethernet Controller (Fiber)
- * 82543GC Gigabit Ethernet Controller (Copper)
- * 82544EI Gigabit Ethernet Controller (Copper)
- * 82544EI Gigabit Ethernet Controller (Fiber)
- * 82544GC Gigabit Ethernet Controller (Copper)
- * 82544GC Gigabit Ethernet Controller (LOM)
- */
-
-#include "e1000_api.h"
-
-static s32  e1000_init_phy_params_82543(struct e1000_hw *hw);
-static s32  e1000_init_nvm_params_82543(struct e1000_hw *hw);
-static s32  e1000_init_mac_params_82543(struct e1000_hw *hw);
-static s32  e1000_read_phy_reg_82543(struct e1000_hw *hw, u32 offset,
-                                     u16 *data);
-static s32  e1000_write_phy_reg_82543(struct e1000_hw *hw, u32 offset,
-                                      u16 data);
-#if 0
-static s32  e1000_phy_force_speed_duplex_82543(struct e1000_hw *hw);
-#endif
-static s32  e1000_phy_hw_reset_82543(struct e1000_hw *hw);
-static s32  e1000_reset_hw_82543(struct e1000_hw *hw);
-static s32  e1000_init_hw_82543(struct e1000_hw *hw);
-static s32  e1000_setup_link_82543(struct e1000_hw *hw);
-static s32  e1000_setup_copper_link_82543(struct e1000_hw *hw);
-static s32  e1000_setup_fiber_link_82543(struct e1000_hw *hw);
-static s32  e1000_check_for_copper_link_82543(struct e1000_hw *hw);
-static s32  e1000_check_for_fiber_link_82543(struct e1000_hw *hw);
-static s32  e1000_led_on_82543(struct e1000_hw *hw);
-static s32  e1000_led_off_82543(struct e1000_hw *hw);
-static void e1000_write_vfta_82543(struct e1000_hw *hw, u32 offset,
-                                   u32 value);
-static void e1000_mta_set_82543(struct e1000_hw *hw, u32 hash_value);
-static void e1000_clear_hw_cntrs_82543(struct e1000_hw *hw);
-static s32  e1000_config_mac_to_phy_82543(struct e1000_hw *hw);
-static bool e1000_init_phy_disabled_82543(struct e1000_hw *hw);
-static void e1000_lower_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl);
-static s32  e1000_polarity_reversal_workaround_82543(struct e1000_hw *hw);
-static void e1000_raise_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl);
-static u16  e1000_shift_in_mdi_bits_82543(struct e1000_hw *hw);
-static void e1000_shift_out_mdi_bits_82543(struct e1000_hw *hw, u32 data,
-                                           u16 count);
-static bool e1000_tbi_compatibility_enabled_82543(struct e1000_hw *hw);
-static void e1000_set_tbi_compatibility_82543(struct e1000_hw *hw, bool state);
-static void e1000_set_tbi_sbp_82543(struct e1000_hw *hw, bool state);
-
-/**
- *  e1000_init_phy_params_82543 - Init PHY func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000_init_phy_params_82543(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_init_phy_params_82543");
-
-	if (hw->phy.media_type != e1000_media_type_copper) {
-		phy->type               = e1000_phy_none;
-		goto out;
-	} else {
-		phy->ops.power_up       = e1000_power_up_phy_copper;
-		phy->ops.power_down     = e1000_power_down_phy_copper;
-	}
-
-	phy->addr                       = 1;
-	phy->autoneg_mask               = AUTONEG_ADVERTISE_SPEED_DEFAULT;
-	phy->reset_delay_us             = 10000;
-	phy->type                       = e1000_phy_m88;
-
-	/* Function Pointers */
-	phy->ops.check_polarity         = e1000_check_polarity_m88;
-	phy->ops.commit                 = e1000_phy_sw_reset_generic;
-#if 0
-	phy->ops.force_speed_duplex     = e1000_phy_force_speed_duplex_82543;
-#endif
-#if 0
-	phy->ops.get_cable_length       = e1000_get_cable_length_m88;
-#endif
-	phy->ops.get_cfg_done           = e1000_get_cfg_done_generic;
-	phy->ops.read_reg               = (hw->mac.type == e1000_82543)
-	                                  ? e1000_read_phy_reg_82543
-	                                  : e1000_read_phy_reg_m88;
-	phy->ops.reset                  = (hw->mac.type == e1000_82543)
-	                                  ? e1000_phy_hw_reset_82543
-	                                  : e1000_phy_hw_reset_generic;
-	phy->ops.write_reg              = (hw->mac.type == e1000_82543)
-	                                  ? e1000_write_phy_reg_82543
-	                                  : e1000_write_phy_reg_m88;
-	phy->ops.get_info               = e1000_get_phy_info_m88;
-
-	/*
-	 * The external PHY of the 82543 can be in a funky state.
-	 * Resetting helps us read the PHY registers for acquiring
-	 * the PHY ID.
-	 */
-	if (!e1000_init_phy_disabled_82543(hw)) {
-		ret_val = phy->ops.reset(hw);
-		if (ret_val) {
-			DEBUGOUT("Resetting PHY during init failed.\n");
-			goto out;
-		}
-		msec_delay(20);
-	}
-
-	ret_val = e1000_get_phy_id(hw);
-	if (ret_val)
-		goto out;
-
-	/* Verify phy id */
-	switch (hw->mac.type) {
-	case e1000_82543:
-		if (phy->id != M88E1000_E_PHY_ID) {
-			ret_val = -E1000_ERR_PHY;
-			goto out;
-		}
-		break;
-	case e1000_82544:
-		if (phy->id != M88E1000_I_PHY_ID) {
-			ret_val = -E1000_ERR_PHY;
-			goto out;
-		}
-		break;
-	default:
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-		break;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_init_nvm_params_82543 - Init NVM func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000_init_nvm_params_82543(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-
-	DEBUGFUNC("e1000_init_nvm_params_82543");
-
-	nvm->type               = e1000_nvm_eeprom_microwire;
-	nvm->word_size          = 64;
-	nvm->delay_usec         = 50;
-	nvm->address_bits       =  6;
-	nvm->opcode_bits        =  3;
-
-	/* Function Pointers */
-	nvm->ops.read           = e1000_read_nvm_microwire;
-	nvm->ops.update         = e1000_update_nvm_checksum_generic;
-	nvm->ops.valid_led_default = e1000_valid_led_default_generic;
-	nvm->ops.validate       = e1000_validate_nvm_checksum_generic;
-	nvm->ops.write          = e1000_write_nvm_microwire;
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_init_mac_params_82543 - Init MAC func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000_init_mac_params_82543(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-
-	DEBUGFUNC("e1000_init_mac_params_82543");
-
-	/* Set media type */
-	switch (hw->device_id) {
-	case E1000_DEV_ID_82543GC_FIBER:
-	case E1000_DEV_ID_82544EI_FIBER:
-		hw->phy.media_type = e1000_media_type_fiber;
-		break;
-	default:
-		hw->phy.media_type = e1000_media_type_copper;
-		break;
-	}
-
-	/* Set mta register count */
-	mac->mta_reg_count = 128;
-	/* Set rar entry count */
-	mac->rar_entry_count = E1000_RAR_ENTRIES;
-
-	/* Function pointers */
-
-	/* bus type/speed/width */
-	mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
-	/* function id */
-	mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci;
-	/* reset */
-	mac->ops.reset_hw = e1000_reset_hw_82543;
-	/* hw initialization */
-	mac->ops.init_hw = e1000_init_hw_82543;
-	/* link setup */
-	mac->ops.setup_link = e1000_setup_link_82543;
-	/* physical interface setup */
-	mac->ops.setup_physical_interface =
-	        (hw->phy.media_type == e1000_media_type_copper)
-	                ? e1000_setup_copper_link_82543
-	                : e1000_setup_fiber_link_82543;
-	/* check for link */
-	mac->ops.check_for_link =
-	        (hw->phy.media_type == e1000_media_type_copper)
-	                ? e1000_check_for_copper_link_82543
-	                : e1000_check_for_fiber_link_82543;
-	/* link info */
-	mac->ops.get_link_up_info =
-	        (hw->phy.media_type == e1000_media_type_copper)
-	                ? e1000_get_speed_and_duplex_copper_generic
-	                : e1000_get_speed_and_duplex_fiber_serdes_generic;
-	/* multicast address update */
-	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
-	/* writing VFTA */
-	mac->ops.write_vfta = e1000_write_vfta_82543;
-	/* clearing VFTA */
-	mac->ops.clear_vfta = e1000_clear_vfta_generic;
-	/* setting MTA */
-	mac->ops.mta_set = e1000_mta_set_82543;
-	/* turn on/off LED */
-	mac->ops.led_on = e1000_led_on_82543;
-	mac->ops.led_off = e1000_led_off_82543;
-	/* clear hardware counters */
-	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82543;
-
-	/* Set tbi compatibility */
-	if ((hw->mac.type != e1000_82543) ||
-	    (hw->phy.media_type == e1000_media_type_fiber))
-		e1000_set_tbi_compatibility_82543(hw, false);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_init_function_pointers_82543 - Init func ptrs.
- *  @hw: pointer to the HW structure
- *
- *  Called to initialize all function pointers and parameters.
- **/
-void e1000_init_function_pointers_82543(struct e1000_hw *hw)
-{
-	DEBUGFUNC("e1000_init_function_pointers_82543");
-
-	hw->mac.ops.init_params = e1000_init_mac_params_82543;
-	hw->nvm.ops.init_params = e1000_init_nvm_params_82543;
-	hw->phy.ops.init_params = e1000_init_phy_params_82543;
-}
-
-/**
- *  e1000_tbi_compatibility_enabled_82543 - Returns TBI compat status
- *  @hw: pointer to the HW structure
- *
- *  Returns the current status of 10-bit Interface (TBI) compatibility
- *  (enabled/disabled).
- **/
-static bool e1000_tbi_compatibility_enabled_82543(struct e1000_hw *hw)
-{
-	struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
-	bool state = false;
-
-	DEBUGFUNC("e1000_tbi_compatibility_enabled_82543");
-
-	if (hw->mac.type != e1000_82543) {
-		DEBUGOUT("TBI compatibility workaround for 82543 only.\n");
-		goto out;
-	}
-
-	state = (dev_spec->tbi_compatibility & TBI_COMPAT_ENABLED)
-	        ? true : false;
-
-out:
-	return state;
-}
-
-/**
- *  e1000_set_tbi_compatibility_82543 - Set TBI compatibility
- *  @hw: pointer to the HW structure
- *  @state: enable/disable TBI compatibility
- *
- *  Enables or disabled 10-bit Interface (TBI) compatibility.
- **/
-static void e1000_set_tbi_compatibility_82543(struct e1000_hw *hw, bool state)
-{
-	struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
-
-	DEBUGFUNC("e1000_set_tbi_compatibility_82543");
-
-	if (hw->mac.type != e1000_82543) {
-		DEBUGOUT("TBI compatibility workaround for 82543 only.\n");
-		goto out;
-	}
-
-	if (state)
-		dev_spec->tbi_compatibility |= TBI_COMPAT_ENABLED;
-	else
-		dev_spec->tbi_compatibility &= ~TBI_COMPAT_ENABLED;
-
-out:
-	return;
-}
-
-/**
- *  e1000_tbi_sbp_enabled_82543 - Returns TBI SBP status
- *  @hw: pointer to the HW structure
- *
- *  Returns the current status of 10-bit Interface (TBI) store bad packet (SBP)
- *  (enabled/disabled).
- **/
-bool e1000_tbi_sbp_enabled_82543(struct e1000_hw *hw)
-{
-	struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
-	bool state = false;
-
-	DEBUGFUNC("e1000_tbi_sbp_enabled_82543");
-
-	if (hw->mac.type != e1000_82543) {
-		DEBUGOUT("TBI compatibility workaround for 82543 only.\n");
-		goto out;
-	}
-
-	state = (dev_spec->tbi_compatibility & TBI_SBP_ENABLED)
-	        ? true : false;
-
-out:
-	return state;
-}
-
-/**
- *  e1000_set_tbi_sbp_82543 - Set TBI SBP
- *  @hw: pointer to the HW structure
- *  @state: enable/disable TBI store bad packet
- *
- *  Enables or disabled 10-bit Interface (TBI) store bad packet (SBP).
- **/
-static void e1000_set_tbi_sbp_82543(struct e1000_hw *hw, bool state)
-{
-	struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
-
-	DEBUGFUNC("e1000_set_tbi_sbp_82543");
-
-	if (state && e1000_tbi_compatibility_enabled_82543(hw))
-		dev_spec->tbi_compatibility |= TBI_SBP_ENABLED;
-	else
-		dev_spec->tbi_compatibility &= ~TBI_SBP_ENABLED;
-
-	return;
-}
-
-/**
- *  e1000_init_phy_disabled_82543 - Returns init PHY status
- *  @hw: pointer to the HW structure
- *
- *  Returns the current status of whether PHY initialization is disabled.
- *  True if PHY initialization is disabled else false.
- **/
-static bool e1000_init_phy_disabled_82543(struct e1000_hw *hw)
-{
-	struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
-	bool ret_val;
-
-	DEBUGFUNC("e1000_init_phy_disabled_82543");
-
-	if (hw->mac.type != e1000_82543) {
-		ret_val = false;
-		goto out;
-	}
-
-	ret_val = dev_spec->init_phy_disabled;
-
-out:
-	return ret_val;
-}
-
-#if 0
-/**
- *  e1000_tbi_adjust_stats_82543 - Adjust stats when TBI enabled
- *  @hw: pointer to the HW structure
- *  @stats: Struct containing statistic register values
- *  @frame_len: The length of the frame in question
- *  @mac_addr: The Ethernet destination address of the frame in question
- *  @max_frame_size: The maximum frame size
- *
- *  Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
- **/
-void e1000_tbi_adjust_stats_82543(struct e1000_hw *hw,
-                                  struct e1000_hw_stats *stats, u32 frame_len,
-                                  u8 *mac_addr, u32 max_frame_size)
-{
-	if (!(e1000_tbi_sbp_enabled_82543(hw)))
-		goto out;
-
-	/* First adjust the frame length. */
-	frame_len--;
-	/*
-	 * We need to adjust the statistics counters, since the hardware
-	 * counters overcount this packet as a CRC error and undercount
-	 * the packet as a good packet
-	 */
-	/* This packet should not be counted as a CRC error.    */
-	stats->crcerrs--;
-	/* This packet does count as a Good Packet Received.    */
-	stats->gprc++;
-
-	/* Adjust the Good Octets received counters             */
-	stats->gorc += frame_len;
-
-	/*
-	 * Is this a broadcast or multicast?  Check broadcast first,
-	 * since the test for a multicast frame will test positive on
-	 * a broadcast frame.
-	 */
-	if ((mac_addr[0] == 0xff) && (mac_addr[1] == 0xff))
-		/* Broadcast packet */
-		stats->bprc++;
-	else if (*mac_addr & 0x01)
-		/* Multicast packet */
-		stats->mprc++;
-
-	/*
-	 * In this case, the hardware has overcounted the number of
-	 * oversize frames.
-	 */
-	if ((frame_len == max_frame_size) && (stats->roc > 0))
-		stats->roc--;
-
-	/*
-	 * Adjust the bin counters when the extra byte put the frame in the
-	 * wrong bin. Remember that the frame_len was adjusted above.
-	 */
-	if (frame_len == 64) {
-		stats->prc64++;
-		stats->prc127--;
-	} else if (frame_len == 127) {
-		stats->prc127++;
-		stats->prc255--;
-	} else if (frame_len == 255) {
-		stats->prc255++;
-		stats->prc511--;
-	} else if (frame_len == 511) {
-		stats->prc511++;
-		stats->prc1023--;
-	} else if (frame_len == 1023) {
-		stats->prc1023++;
-		stats->prc1522--;
-	} else if (frame_len == 1522) {
-		stats->prc1522++;
-	}
-
-out:
-	return;
-}
-#endif
-
-/**
- *  e1000_read_phy_reg_82543 - Read PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Reads the PHY at offset and stores the information read to data.
- **/
-static s32 e1000_read_phy_reg_82543(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	u32 mdic;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_read_phy_reg_82543");
-
-	if (offset > MAX_PHY_REG_ADDRESS) {
-		DEBUGOUT1("PHY Address %d is out of range\n", offset);
-		ret_val = -E1000_ERR_PARAM;
-		goto out;
-	}
-
-	/*
-	 * We must first send a preamble through the MDIO pin to signal the
-	 * beginning of an MII instruction.  This is done by sending 32
-	 * consecutive "1" bits.
-	 */
-	e1000_shift_out_mdi_bits_82543(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
-
-	/*
-	 * Now combine the next few fields that are required for a read
-	 * operation.  We use this method instead of calling the
-	 * e1000_shift_out_mdi_bits routine five different times.  The format
-	 * of an MII read instruction consists of a shift out of 14 bits and
-	 * is defined as follows:
-	 * 	<Preamble><SOF><Op Code><Phy Addr><Offset>
-	 * followed by a shift in of 18 bits.  This first two bits shifted in
-	 * are TurnAround bits used to avoid contention on the MDIO pin when a
-	 * READ operation is performed.  These two bits are thrown away
-	 * followed by a shift in of 16 bits which contains the desired data.
-	 */
-	mdic = (offset | (hw->phy.addr << 5) |
-		(PHY_OP_READ << 10) | (PHY_SOF << 12));
-
-	e1000_shift_out_mdi_bits_82543(hw, mdic, 14);
-
-	/*
-	 * Now that we've shifted out the read command to the MII, we need to
-	 * "shift in" the 16-bit value (18 total bits) of the requested PHY
-	 * register address.
-	 */
-	*data = e1000_shift_in_mdi_bits_82543(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_write_phy_reg_82543 - Write PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be written
- *  @data: pointer to the data to be written at offset
- *
- *  Writes data to the PHY at offset.
- **/
-static s32 e1000_write_phy_reg_82543(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	u32 mdic;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_write_phy_reg_82543");
-
-	if (offset > MAX_PHY_REG_ADDRESS) {
-		DEBUGOUT1("PHY Address %d is out of range\n", offset);
-		ret_val = -E1000_ERR_PARAM;
-		goto out;
-	}
-
-	/*
-	 * We'll need to use the SW defined pins to shift the write command
-	 * out to the PHY. We first send a preamble to the PHY to signal the
-	 * beginning of the MII instruction.  This is done by sending 32
-	 * consecutive "1" bits.
-	 */
-	e1000_shift_out_mdi_bits_82543(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
-
-	/*
-	 * Now combine the remaining required fields that will indicate a
-	 * write operation. We use this method instead of calling the
-	 * e1000_shift_out_mdi_bits routine for each field in the command. The
-	 * format of a MII write instruction is as follows:
-	 * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
-	 */
-	mdic = ((PHY_TURNAROUND) | (offset << 2) | (hw->phy.addr << 7) |
-	        (PHY_OP_WRITE << 12) | (PHY_SOF << 14));
-	mdic <<= 16;
-	mdic |= (u32) data;
-
-	e1000_shift_out_mdi_bits_82543(hw, mdic, 32);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_raise_mdi_clk_82543 - Raise Management Data Input clock
- *  @hw: pointer to the HW structure
- *  @ctrl: pointer to the control register
- *
- *  Raise the management data input clock by setting the MDC bit in the control
- *  register.
- **/
-static void e1000_raise_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl)
-{
-	/*
-	 * Raise the clock input to the Management Data Clock (by setting the
-	 * MDC bit), and then delay a sufficient amount of time.
-	 */
-	E1000_WRITE_REG(hw, E1000_CTRL, (*ctrl | E1000_CTRL_MDC));
-	E1000_WRITE_FLUSH(hw);
-	usec_delay(10);
-}
-
-/**
- *  e1000_lower_mdi_clk_82543 - Lower Management Data Input clock
- *  @hw: pointer to the HW structure
- *  @ctrl: pointer to the control register
- *
- *  Lower the management data input clock by clearing the MDC bit in the
- *  control register.
- **/
-static void e1000_lower_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl)
-{
-	/*
-	 * Lower the clock input to the Management Data Clock (by clearing the
-	 * MDC bit), and then delay a sufficient amount of time.
-	 */
-	E1000_WRITE_REG(hw, E1000_CTRL, (*ctrl & ~E1000_CTRL_MDC));
-	E1000_WRITE_FLUSH(hw);
-	usec_delay(10);
-}
-
-/**
- *  e1000_shift_out_mdi_bits_82543 - Shift data bits our to the PHY
- *  @hw: pointer to the HW structure
- *  @data: data to send to the PHY
- *  @count: number of bits to shift out
- *
- *  We need to shift 'count' bits out to the PHY.  So, the value in the
- *  "data" parameter will be shifted out to the PHY one bit at a time.
- *  In order to do this, "data" must be broken down into bits.
- **/
-static void e1000_shift_out_mdi_bits_82543(struct e1000_hw *hw, u32 data,
-                                           u16 count)
-{
-	u32 ctrl, mask;
-
-	/*
-	 * We need to shift "count" number of bits out to the PHY.  So, the
-	 * value in the "data" parameter will be shifted out to the PHY one
-	 * bit at a time.  In order to do this, "data" must be broken down
-	 * into bits.
-	 */
-	mask = 0x01;
-	mask <<= (count -1);
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	/* Set MDIO_DIR and MDC_DIR direction bits to be used as output pins. */
-	ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
-
-	while (mask) {
-		/*
-		 * A "1" is shifted out to the PHY by setting the MDIO bit to
-		 * "1" and then raising and lowering the Management Data Clock.
-		 * A "0" is shifted out to the PHY by setting the MDIO bit to
-		 * "0" and then raising and lowering the clock.
-		 */
-		if (data & mask) ctrl |= E1000_CTRL_MDIO;
-		else ctrl &= ~E1000_CTRL_MDIO;
-
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-		E1000_WRITE_FLUSH(hw);
-
-		usec_delay(10);
-
-		e1000_raise_mdi_clk_82543(hw, &ctrl);
-		e1000_lower_mdi_clk_82543(hw, &ctrl);
-
-		mask >>= 1;
-	}
-}
-
-/**
- *  e1000_shift_in_mdi_bits_82543 - Shift data bits in from the PHY
- *  @hw: pointer to the HW structure
- *
- *  In order to read a register from the PHY, we need to shift 18 bits
- *  in from the PHY.  Bits are "shifted in" by raising the clock input to
- *  the PHY (setting the MDC bit), and then reading the value of the data out
- *  MDIO bit.
- **/
-static u16 e1000_shift_in_mdi_bits_82543(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	u16 data = 0;
-	u8 i;
-
-	/*
-	 * In order to read a register from the PHY, we need to shift in a
-	 * total of 18 bits from the PHY.  The first two bit (turnaround)
-	 * times are used to avoid contention on the MDIO pin when a read
-	 * operation is performed.  These two bits are ignored by us and
-	 * thrown away.  Bits are "shifted in" by raising the input to the
-	 * Management Data Clock (setting the MDC bit) and then reading the
-	 * value of the MDIO bit.
-	 */
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	/*
-	 * Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as
-	 * input.
-	 */
-	ctrl &= ~E1000_CTRL_MDIO_DIR;
-	ctrl &= ~E1000_CTRL_MDIO;
-
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-	E1000_WRITE_FLUSH(hw);
-
-	/*
-	 * Raise and lower the clock before reading in the data.  This accounts
-	 * for the turnaround bits.  The first clock occurred when we clocked
-	 * out the last bit of the Register Address.
-	 */
-	e1000_raise_mdi_clk_82543(hw, &ctrl);
-	e1000_lower_mdi_clk_82543(hw, &ctrl);
-
-	for (data = 0, i = 0; i < 16; i++) {
-		data <<= 1;
-		e1000_raise_mdi_clk_82543(hw, &ctrl);
-		ctrl = E1000_READ_REG(hw, E1000_CTRL);
-		/* Check to see if we shifted in a "1". */
-		if (ctrl & E1000_CTRL_MDIO)
-			data |= 1;
-		e1000_lower_mdi_clk_82543(hw, &ctrl);
-	}
-
-	e1000_raise_mdi_clk_82543(hw, &ctrl);
-	e1000_lower_mdi_clk_82543(hw, &ctrl);
-
-	return data;
-}
-
-#if 0
-/**
- *  e1000_phy_force_speed_duplex_82543 - Force speed/duplex for PHY
- *  @hw: pointer to the HW structure
- *
- *  Calls the function to force speed and duplex for the m88 PHY, and
- *  if the PHY is not auto-negotiating and the speed is forced to 10Mbit,
- *  then call the function for polarity reversal workaround.
- **/
-static s32 e1000_phy_force_speed_duplex_82543(struct e1000_hw *hw)
-{
-	s32 ret_val;
-
-	DEBUGFUNC("e1000_phy_force_speed_duplex_82543");
-
-	ret_val = e1000_phy_force_speed_duplex_m88(hw);
-	if (ret_val)
-		goto out;
-
-	if (!hw->mac.autoneg &&
-	    (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED))
-		ret_val = e1000_polarity_reversal_workaround_82543(hw);
-
-out:
-	return ret_val;
-}
-#endif
-
-/**
- *  e1000_polarity_reversal_workaround_82543 - Workaround polarity reversal
- *  @hw: pointer to the HW structure
- *
- *  When forcing link to 10 Full or 10 Half, the PHY can reverse the polarity
- *  inadvertently.  To workaround the issue, we disable the transmitter on
- *  the PHY until we have established the link partner's link parameters.
- **/
-static s32 e1000_polarity_reversal_workaround_82543(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 mii_status_reg;
-	u16 i;
-	bool link;
-
-	if (!(hw->phy.ops.write_reg))
-		goto out;
-
-	/* Polarity reversal workaround for forced 10F/10H links. */
-
-	/* Disable the transmitter on the PHY */
-
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
-	if (ret_val)
-		goto out;
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFFF);
-	if (ret_val)
-		goto out;
-
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * This loop will early-out if the NO link condition has been met.
-	 * In other words, DO NOT use e1000_phy_has_link_generic() here.
-	 */
-	for (i = PHY_FORCE_TIME; i > 0; i--) {
-		/*
-		 * Read the MII Status Register and wait for Link Status bit
-		 * to be clear.
-		 */
-
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
-		if (ret_val)
-			goto out;
-
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
-		if (ret_val)
-			goto out;
-
-		if ((mii_status_reg & ~MII_SR_LINK_STATUS) == 0)
-			break;
-		msec_delay_irq(100);
-	}
-
-	/* Recommended delay time after link has been lost */
-	msec_delay_irq(1000);
-
-	/* Now we will re-enable the transmitter on the PHY */
-
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
-	if (ret_val)
-		goto out;
-	msec_delay_irq(50);
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFF0);
-	if (ret_val)
-		goto out;
-	msec_delay_irq(50);
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFF00);
-	if (ret_val)
-		goto out;
-	msec_delay_irq(50);
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x0000);
-	if (ret_val)
-		goto out;
-
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Read the MII Status Register and wait for Link Status bit
-	 * to be set.
-	 */
-	ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_TIME, 100000, &link);
-	if (ret_val)
-		goto out;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_phy_hw_reset_82543 - PHY hardware reset
- *  @hw: pointer to the HW structure
- *
- *  Sets the PHY_RESET_DIR bit in the extended device control register
- *  to put the PHY into a reset and waits for completion.  Once the reset
- *  has been accomplished, clear the PHY_RESET_DIR bit to take the PHY out
- *  of reset.
- **/
-static s32 e1000_phy_hw_reset_82543(struct e1000_hw *hw)
-{
-	u32 ctrl_ext;
-	s32 ret_val;
-
-	DEBUGFUNC("e1000_phy_hw_reset_82543");
-
-	/*
-	 * Read the Extended Device Control Register, assert the PHY_RESET_DIR
-	 * bit to put the PHY into reset...
-	 */
-	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
-	ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
-	ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
-	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
-	E1000_WRITE_FLUSH(hw);
-
-	msec_delay(10);
-
-	/* ...then take it out of reset. */
-	ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
-	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
-	E1000_WRITE_FLUSH(hw);
-
-	usec_delay(150);
-
-	if (!(hw->phy.ops.get_cfg_done))
-		return E1000_SUCCESS;
-
-	ret_val = hw->phy.ops.get_cfg_done(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000_reset_hw_82543 - Reset hardware
- *  @hw: pointer to the HW structure
- *
- *  This resets the hardware into a known state.
- **/
-static s32 e1000_reset_hw_82543(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_reset_hw_82543");
-
-	DEBUGOUT("Masking off all interrupts\n");
-	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
-
-	E1000_WRITE_REG(hw, E1000_RCTL, 0);
-	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
-	E1000_WRITE_FLUSH(hw);
-
-	e1000_set_tbi_sbp_82543(hw, false);
-
-	/*
-	 * Delay to allow any outstanding PCI transactions to complete before
-	 * resetting the device
-	 */
-	msec_delay(10);
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	DEBUGOUT("Issuing a global reset to 82543/82544 MAC\n");
-	if (hw->mac.type == e1000_82543) {
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
-	} else {
-		/*
-		 * The 82544 can't ACK the 64-bit write when issuing the
-		 * reset, so use IO-mapping as a workaround.
-		 */
-		E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
-	}
-
-	/*
-	 * After MAC reset, force reload of NVM to restore power-on
-	 * settings to device.
-	 */
-	hw->nvm.ops.reload(hw);
-	msec_delay(2);
-
-	/* Masking off and clearing any pending interrupts */
-	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
-	E1000_READ_REG(hw, E1000_ICR);
-
-	return ret_val;
-}
-
-/**
- *  e1000_init_hw_82543 - Initialize hardware
- *  @hw: pointer to the HW structure
- *
- *  This inits the hardware readying it for operation.
- **/
-static s32 e1000_init_hw_82543(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543;
-	u32 ctrl;
-	s32 ret_val;
-	u16 i;
-
-	DEBUGFUNC("e1000_init_hw_82543");
-
-	/* Disabling VLAN filtering */
-	E1000_WRITE_REG(hw, E1000_VET, 0);
-	mac->ops.clear_vfta(hw);
-
-	/* Setup the receive address. */
-	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
-
-	/* Zero out the Multicast HASH table */
-	DEBUGOUT("Zeroing the MTA\n");
-	for (i = 0; i < mac->mta_reg_count; i++) {
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
-		E1000_WRITE_FLUSH(hw);
-	}
-
-	/*
-	 * Set the PCI priority bit correctly in the CTRL register.  This
-	 * determines if the adapter gives priority to receives, or if it
-	 * gives equal priority to transmits and receives.
-	 */
-	if (hw->mac.type == e1000_82543 && dev_spec->dma_fairness) {
-		ctrl = E1000_READ_REG(hw, E1000_CTRL);
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PRIOR);
-	}
-
-	e1000_pcix_mmrbc_workaround_generic(hw);
-
-	/* Setup link and flow control */
-	ret_val = mac->ops.setup_link(hw);
-
-	/*
-	 * Clear all of the statistics registers (clear on read).  It is
-	 * important that we do this after we have tried to establish link
-	 * because the symbol error count will increment wildly if there
-	 * is no link.
-	 */
-	e1000_clear_hw_cntrs_82543(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000_setup_link_82543 - Setup flow control and link settings
- *  @hw: pointer to the HW structure
- *
- *  Read the EEPROM to determine the initial polarity value and write the
- *  extended device control register with the information before calling
- *  the generic setup link function, which does the following:
- *  Determines which flow control settings to use, then configures flow
- *  control.  Calls the appropriate media-specific link configuration
- *  function.  Assuming the adapter has a valid link partner, a valid link
- *  should be established.  Assumes the hardware has previously been reset
- *  and the transmitter and receiver are not enabled.
- **/
-static s32 e1000_setup_link_82543(struct e1000_hw *hw)
-{
-	u32 ctrl_ext;
-	s32  ret_val;
-	u16 data;
-
-	DEBUGFUNC("e1000_setup_link_82543");
-
-	/*
-	 * Take the 4 bits from NVM word 0xF that determine the initial
-	 * polarity value for the SW controlled pins, and setup the
-	 * Extended Device Control reg with that info.
-	 * This is needed because one of the SW controlled pins is used for
-	 * signal detection.  So this should be done before phy setup.
-	 */
-	if (hw->mac.type == e1000_82543) {
-		ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &data);
-		if (ret_val) {
-			DEBUGOUT("NVM Read Error\n");
-			ret_val = -E1000_ERR_NVM;
-			goto out;
-		}
-		ctrl_ext = ((data & NVM_WORD0F_SWPDIO_EXT_MASK) <<
-		            NVM_SWDPIO_EXT_SHIFT);
-		E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
-	}
-
-	ret_val = e1000_setup_link_generic(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_setup_copper_link_82543 - Configure copper link settings
- *  @hw: pointer to the HW structure
- *
- *  Configures the link for auto-neg or forced speed and duplex.  Then we check
- *  for link, once link is established calls to configure collision distance
- *  and flow control are called.
- **/
-static s32 e1000_setup_copper_link_82543(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val;
-	bool link;
-
-	DEBUGFUNC("e1000_setup_copper_link_82543");
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL) | E1000_CTRL_SLU;
-	/*
-	 * With 82543, we need to force speed and duplex on the MAC
-	 * equal to what the PHY speed and duplex configuration is.
-	 * In addition, we need to perform a hardware reset on the
-	 * PHY to take it out of reset.
-	 */
-	if (hw->mac.type == e1000_82543) {
-		ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-		ret_val = hw->phy.ops.reset(hw);
-		if (ret_val)
-			goto out;
-		hw->phy.reset_disable = false;
-	} else {
-		ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-	}
-
-	/* Set MDI/MDI-X, Polarity Reversal, and downshift settings */
-	ret_val = e1000_copper_link_setup_m88(hw);
-	if (ret_val)
-		goto out;
-
-	if (hw->mac.autoneg) {
-		/*
-		 * Setup autoneg and flow control advertisement and perform
-		 * autonegotiation.
-		 */
-		ret_val = e1000_copper_link_autoneg(hw);
-		if (ret_val)
-			goto out;
-	} else {
-		/*
-		 * PHY will be set to 10H, 10F, 100H or 100F
-		 * depending on user settings.
-		 */
-#if 0
-		DEBUGOUT("Forcing Speed and Duplex\n");
-		ret_val = e1000_phy_force_speed_duplex_82543(hw);
-		if (ret_val) {
-			DEBUGOUT("Error Forcing Speed and Duplex\n");
-			goto out;
-		}
-#endif
-	}
-
-	/*
-	 * Check link status. Wait up to 100 microseconds for link to become
-	 * valid.
-	 */
-	ret_val = e1000_phy_has_link_generic(hw,
-	                                     COPPER_LINK_UP_LIMIT,
-	                                     10,
-	                                     &link);
-	if (ret_val)
-		goto out;
-
-
-	if (link) {
-		DEBUGOUT("Valid link established!!!\n");
-		/* Config the MAC and PHY after link is up */
-		if (hw->mac.type == e1000_82544) {
-			e1000_config_collision_dist_generic(hw);
-		} else {
-			ret_val = e1000_config_mac_to_phy_82543(hw);
-			if (ret_val)
-				goto out;
-		}
-		ret_val = e1000_config_fc_after_link_up_generic(hw);
-	} else {
-		DEBUGOUT("Unable to establish link!!!\n");
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_setup_fiber_link_82543 - Setup link for fiber
- *  @hw: pointer to the HW structure
- *
- *  Configures collision distance and flow control for fiber links.  Upon
- *  successful setup, poll for link.
- **/
-static s32 e1000_setup_fiber_link_82543(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val;
-
-	DEBUGFUNC("e1000_setup_fiber_link_82543");
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	/* Take the link out of reset */
-	ctrl &= ~E1000_CTRL_LRST;
-
-	e1000_config_collision_dist_generic(hw);
-
-	ret_val = e1000_commit_fc_settings_generic(hw);
-	if (ret_val)
-		goto out;
-
-	DEBUGOUT("Auto-negotiation enabled\n");
-
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-	E1000_WRITE_FLUSH(hw);
-	msec_delay(1);
-
-	/*
-	 * For these adapters, the SW definable pin 1 is cleared when the
-	 * optics detect a signal.  If we have a signal, then poll for a
-	 * "Link-Up" indication.
-	 */
-	if (!(E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) {
-		ret_val = e1000_poll_fiber_serdes_link_generic(hw);
-	} else {
-		DEBUGOUT("No signal detected\n");
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_check_for_copper_link_82543 - Check for link (Copper)
- *  @hw: pointer to the HW structure
- *
- *  Checks the phy for link, if link exists, do the following:
- *   - check for downshift
- *   - do polarity workaround (if necessary)
- *   - configure collision distance
- *   - configure flow control after link up
- *   - configure tbi compatibility
- **/
-static s32 e1000_check_for_copper_link_82543(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 icr, rctl;
-	s32 ret_val;
-	u16 speed, duplex;
-	bool link;
-
-	DEBUGFUNC("e1000_check_for_copper_link_82543");
-
-	if (!mac->get_link_status) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		goto out;
-
-	if (!link)
-		goto out; /* No link detected */
-
-	mac->get_link_status = false;
-
-	e1000_check_downshift_generic(hw);
-
-	/*
-	 * If we are forcing speed/duplex, then we can return since
-	 * we have already determined whether we have link or not.
-	 */
-	if (!mac->autoneg) {
-		/*
-		 * If speed and duplex are forced to 10H or 10F, then we will
-		 * implement the polarity reversal workaround.  We disable
-		 * interrupts first, and upon returning, place the devices
-		 * interrupt state to its previous value except for the link
-		 * status change interrupt which will happened due to the
-		 * execution of this workaround.
-		 */
-		if (mac->forced_speed_duplex & E1000_ALL_10_SPEED) {
-			E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
-			ret_val = e1000_polarity_reversal_workaround_82543(hw);
-			icr = E1000_READ_REG(hw, E1000_ICR);
-			E1000_WRITE_REG(hw, E1000_ICS, (icr & ~E1000_ICS_LSC));
-			E1000_WRITE_REG(hw, E1000_IMS, IMS_ENABLE_MASK);
-		}
-
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	/*
-	 * We have a M88E1000 PHY and Auto-Neg is enabled.  If we
-	 * have Si on board that is 82544 or newer, Auto
-	 * Speed Detection takes care of MAC speed/duplex
-	 * configuration.  So we only need to configure Collision
-	 * Distance in the MAC.  Otherwise, we need to force
-	 * speed/duplex on the MAC to the current PHY speed/duplex
-	 * settings.
-	 */
-	if (mac->type == e1000_82544)
-		e1000_config_collision_dist_generic(hw);
-	else {
-		ret_val = e1000_config_mac_to_phy_82543(hw);
-		if (ret_val) {
-			DEBUGOUT("Error configuring MAC to PHY settings\n");
-			goto out;
-		}
-	}
-
-	/*
-	 * Configure Flow Control now that Auto-Neg has completed.
-	 * First, we need to restore the desired flow control
-	 * settings because we may have had to re-autoneg with a
-	 * different link partner.
-	 */
-	ret_val = e1000_config_fc_after_link_up_generic(hw);
-	if (ret_val) {
-		DEBUGOUT("Error configuring flow control\n");
-	}
-
-	/*
-	 * At this point we know that we are on copper and we have
-	 * auto-negotiated link.  These are conditions for checking the link
-	 * partner capability register.  We use the link speed to determine if
-	 * TBI compatibility needs to be turned on or off.  If the link is not
-	 * at gigabit speed, then TBI compatibility is not needed.  If we are
-	 * at gigabit speed, we turn on TBI compatibility.
-	 */
-	if (e1000_tbi_compatibility_enabled_82543(hw)) {
-		ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
-		if (ret_val) {
-			DEBUGOUT("Error getting link speed and duplex\n");
-			return ret_val;
-		}
-		if (speed != SPEED_1000) {
-			/*
-			 * If link speed is not set to gigabit speed,
-			 * we do not need to enable TBI compatibility.
-			 */
-			if (e1000_tbi_sbp_enabled_82543(hw)) {
-				/*
-				 * If we previously were in the mode,
-				 * turn it off.
-				 */
-				e1000_set_tbi_sbp_82543(hw, false);
-				rctl = E1000_READ_REG(hw, E1000_RCTL);
-				rctl &= ~E1000_RCTL_SBP;
-				E1000_WRITE_REG(hw, E1000_RCTL, rctl);
-			}
-		} else {
-			/*
-			 * If TBI compatibility is was previously off,
-			 * turn it on. For compatibility with a TBI link
-			 * partner, we will store bad packets. Some
-			 * frames have an additional byte on the end and
-			 * will look like CRC errors to to the hardware.
-			 */
-			if (!e1000_tbi_sbp_enabled_82543(hw)) {
-				e1000_set_tbi_sbp_82543(hw, true);
-				rctl = E1000_READ_REG(hw, E1000_RCTL);
-				rctl |= E1000_RCTL_SBP;
-				E1000_WRITE_REG(hw, E1000_RCTL, rctl);
-			}
-		}
-	}
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_check_for_fiber_link_82543 - Check for link (Fiber)
- *  @hw: pointer to the HW structure
- *
- *  Checks for link up on the hardware.  If link is not up and we have
- *  a signal, then we need to force link up.
- **/
-static s32 e1000_check_for_fiber_link_82543(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 rxcw, ctrl, status;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_check_for_fiber_link_82543");
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	status = E1000_READ_REG(hw, E1000_STATUS);
-	rxcw = E1000_READ_REG(hw, E1000_RXCW);
-
-	/*
-	 * If we don't have link (auto-negotiation failed or link partner
-	 * cannot auto-negotiate), the cable is plugged in (we have signal),
-	 * and our link partner is not trying to auto-negotiate with us (we
-	 * are receiving idles or data), we need to force link up. We also
-	 * need to give auto-negotiation time to complete, in case the cable
-	 * was just plugged in. The autoneg_failed flag does this.
-	 */
-	/* (ctrl & E1000_CTRL_SWDPIN1) == 0 == have signal */
-	if ((!(ctrl & E1000_CTRL_SWDPIN1)) &&
-	    (!(status & E1000_STATUS_LU)) &&
-	    (!(rxcw & E1000_RXCW_C))) {
-		if (mac->autoneg_failed == 0) {
-			mac->autoneg_failed = 1;
-			ret_val = 0;
-			goto out;
-		}
-		DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
-
-		/* Disable auto-negotiation in the TXCW register */
-		E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
-
-		/* Force link-up and also force full-duplex. */
-		ctrl = E1000_READ_REG(hw, E1000_CTRL);
-		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-		/* Configure Flow Control after forcing link up. */
-		ret_val = e1000_config_fc_after_link_up_generic(hw);
-		if (ret_val) {
-			DEBUGOUT("Error configuring flow control\n");
-			goto out;
-		}
-	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
-		/*
-		 * If we are forcing link and we are receiving /C/ ordered
-		 * sets, re-enable auto-negotiation in the TXCW register
-		 * and disable forced link in the Device Control register
-		 * in an attempt to auto-negotiate with our link partner.
-		 */
-		DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
-		E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
-		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
-
-		mac->serdes_has_link = true;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_config_mac_to_phy_82543 - Configure MAC to PHY settings
- *  @hw: pointer to the HW structure
- *
- *  For the 82543 silicon, we need to set the MAC to match the settings
- *  of the PHY, even if the PHY is auto-negotiating.
- **/
-static s32 e1000_config_mac_to_phy_82543(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val = E1000_SUCCESS;
-	u16 phy_data;
-
-	DEBUGFUNC("e1000_config_mac_to_phy_82543");
-
-	if (!(hw->phy.ops.read_reg))
-		goto out;
-
-	/* Set the bits to force speed and duplex */
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-	ctrl &= ~(E1000_CTRL_SPD_SEL | E1000_CTRL_ILOS);
-
-	/*
-	 * Set up duplex in the Device Control and Transmit Control
-	 * registers depending on negotiated values.
-	 */
-	ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
-	if (ret_val)
-		goto out;
-
-	ctrl &= ~E1000_CTRL_FD;
-	if (phy_data & M88E1000_PSSR_DPLX)
-		ctrl |= E1000_CTRL_FD;
-
-	e1000_config_collision_dist_generic(hw);
-
-	/*
-	 * Set up speed in the Device Control register depending on
-	 * negotiated values.
-	 */
-	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
-		ctrl |= E1000_CTRL_SPD_1000;
-	else if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
-		ctrl |= E1000_CTRL_SPD_100;
-
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_write_vfta_82543 - Write value to VLAN filter table
- *  @hw: pointer to the HW structure
- *  @offset: the 32-bit offset in which to write the value to.
- *  @value: the 32-bit value to write at location offset.
- *
- *  This writes a 32-bit value to a 32-bit offset in the VLAN filter
- *  table.
- **/
-static void e1000_write_vfta_82543(struct e1000_hw *hw, u32 offset, u32 value)
-{
-	u32 temp;
-
-	DEBUGFUNC("e1000_write_vfta_82543");
-
-	if ((hw->mac.type == e1000_82544) && (offset & 1)) {
-		temp = E1000_READ_REG_ARRAY(hw, E1000_VFTA, offset - 1);
-		E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
-		E1000_WRITE_FLUSH(hw);
-		E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset - 1, temp);
-		E1000_WRITE_FLUSH(hw);
-	} else {
-		e1000_write_vfta_generic(hw, offset, value);
-	}
-}
-
-/**
- *  e1000_mta_set_82543 - Set multicast filter table address
- *  @hw: pointer to the HW structure
- *  @hash_value: determines the MTA register and bit to set
- *
- *  The multicast table address is a register array of 32-bit registers.
- *  The hash_value is used to determine what register the bit is in, the
- *  current value is read, the new bit is OR'd in and the new value is
- *  written back into the register.
- **/
-static void e1000_mta_set_82543(struct e1000_hw *hw, u32 hash_value)
-{
-	u32 hash_bit, hash_reg, mta, temp;
-
-	DEBUGFUNC("e1000_mta_set_82543");
-
-	hash_reg = (hash_value >> 5);
-
-	/*
-	 * If we are on an 82544 and we are trying to write an odd offset
-	 * in the MTA, save off the previous entry before writing and
-	 * restore the old value after writing.
-	 */
-	if ((hw->mac.type == e1000_82544) && (hash_reg & 1)) {
-		hash_reg &= (hw->mac.mta_reg_count - 1);
-		hash_bit = hash_value & 0x1F;
-		mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg);
-		mta |= (1 << hash_bit);
-		temp = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg - 1);
-
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta);
-		E1000_WRITE_FLUSH(hw);
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg - 1, temp);
-		E1000_WRITE_FLUSH(hw);
-	} else {
-		e1000_mta_set_generic(hw, hash_value);
-	}
-}
-
-/**
- *  e1000_led_on_82543 - Turn on SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  Turns the SW defined LED on.
- **/
-static s32 e1000_led_on_82543(struct e1000_hw *hw __unused)
-{
-#if 0
-	u32 ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	DEBUGFUNC("e1000_led_on_82543");
-
-	if (hw->mac.type == e1000_82544 &&
-	    hw->phy.media_type == e1000_media_type_copper) {
-		/* Clear SW-definable Pin 0 to turn on the LED */
-		ctrl &= ~E1000_CTRL_SWDPIN0;
-		ctrl |= E1000_CTRL_SWDPIO0;
-	} else {
-		/* Fiber 82544 and all 82543 use this method */
-		ctrl |= E1000_CTRL_SWDPIN0;
-		ctrl |= E1000_CTRL_SWDPIO0;
-	}
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-	return E1000_SUCCESS;
-#endif
-        return 0;
-}
-
-/**
- *  e1000_led_off_82543 - Turn off SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  Turns the SW defined LED off.
- **/
-static s32 e1000_led_off_82543(struct e1000_hw *hw __unused)
-{
-#if 0
-	u32 ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	DEBUGFUNC("e1000_led_off_82543");
-
-	if (hw->mac.type == e1000_82544 &&
-	    hw->phy.media_type == e1000_media_type_copper) {
-		/* Set SW-definable Pin 0 to turn off the LED */
-		ctrl |= E1000_CTRL_SWDPIN0;
-		ctrl |= E1000_CTRL_SWDPIO0;
-	} else {
-		ctrl &= ~E1000_CTRL_SWDPIN0;
-		ctrl |= E1000_CTRL_SWDPIO0;
-	}
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-	return E1000_SUCCESS;
-#endif
-        return 0;
-}
-
-/**
- *  e1000_clear_hw_cntrs_82543 - Clear device specific hardware counters
- *  @hw: pointer to the HW structure
- *
- *  Clears the hardware counters by reading the counter registers.
- **/
-static void e1000_clear_hw_cntrs_82543(struct e1000_hw *hw)
-{
-	DEBUGFUNC("e1000_clear_hw_cntrs_82543");
-
-	e1000_clear_hw_cntrs_base_generic(hw);
-
-#if 0
-	E1000_READ_REG(hw, E1000_PRC64);
-	E1000_READ_REG(hw, E1000_PRC127);
-	E1000_READ_REG(hw, E1000_PRC255);
-	E1000_READ_REG(hw, E1000_PRC511);
-	E1000_READ_REG(hw, E1000_PRC1023);
-	E1000_READ_REG(hw, E1000_PRC1522);
-	E1000_READ_REG(hw, E1000_PTC64);
-	E1000_READ_REG(hw, E1000_PTC127);
-	E1000_READ_REG(hw, E1000_PTC255);
-	E1000_READ_REG(hw, E1000_PTC511);
-	E1000_READ_REG(hw, E1000_PTC1023);
-	E1000_READ_REG(hw, E1000_PTC1522);
-
-	E1000_READ_REG(hw, E1000_ALGNERRC);
-	E1000_READ_REG(hw, E1000_RXERRC);
-	E1000_READ_REG(hw, E1000_TNCRS);
-	E1000_READ_REG(hw, E1000_CEXTERR);
-	E1000_READ_REG(hw, E1000_TSCTC);
-	E1000_READ_REG(hw, E1000_TSCTFC);
-#endif
-}
-
-static struct pci_device_id e1000_82543_nics[] = {
-     PCI_ROM(0x8086, 0x1001, "E1000_DEV_ID_82543GC_FIBER", "E1000_DEV_ID_82543GC_FIBER", e1000_82543),
-     PCI_ROM(0x8086, 0x1004, "E1000_DEV_ID_82543GC_COPPER", "E1000_DEV_ID_82543GC_COPPER", e1000_82543),
-     PCI_ROM(0x8086, 0x1008, "E1000_DEV_ID_82544EI_COPPER", "E1000_DEV_ID_82544EI_COPPER", e1000_82544),
-     PCI_ROM(0x8086, 0x1009, "E1000_DEV_ID_82544EI_FIBER", "E1000_DEV_ID_82544EI_FIBER", e1000_82544),
-     PCI_ROM(0x8086, 0x100C, "E1000_DEV_ID_82544GC_COPPER", "E1000_DEV_ID_82544GC_COPPER", e1000_82544),
-     PCI_ROM(0x8086, 0x100D, "E1000_DEV_ID_82544GC_LOM", "E1000_DEV_ID_82544GC_LOM", e1000_82544),
-};
-
-struct pci_driver e1000_82543_driver __pci_driver = {
-	.ids = e1000_82543_nics,
-	.id_count = (sizeof (e1000_82543_nics) / sizeof (e1000_82543_nics[0])),
-	.probe = e1000_probe,
-	.remove = e1000_remove,
-};
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_82543.h b/roms/ipxe/src/drivers/net/e1000/e1000_82543.h
deleted file mode 100644
index 30073e8bfc8e10083ed0bb907a442d5a4c267a15..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_82543.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000_82543_H_
-#define _E1000_82543_H_
-
-#define PHY_PREAMBLE      0xFFFFFFFF
-#define PHY_PREAMBLE_SIZE 32
-#define PHY_SOF           0x1
-#define PHY_OP_READ       0x2
-#define PHY_OP_WRITE      0x1
-#define PHY_TURNAROUND    0x2
-
-#define TBI_COMPAT_ENABLED 0x1 /* Global "knob" for the workaround */
-/* If TBI_COMPAT_ENABLED, then this is the current state (on/off) */
-#define TBI_SBP_ENABLED    0x2
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_api.c b/roms/ipxe/src/drivers/net/e1000/e1000_api.c
deleted file mode 100644
index 72aac4c4808242bdc5066cd399a5eb8b05a06d51..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_api.c
+++ /dev/null
@@ -1,1108 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include "e1000_api.h"
-
-/**
- *  e1000_init_mac_params - Initialize MAC function pointers
- *  @hw: pointer to the HW structure
- *
- *  This function initializes the function pointers for the MAC
- *  set of functions.  Called by drivers or by e1000_setup_init_funcs.
- **/
-s32 e1000_init_mac_params(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->mac.ops.init_params) {
-		ret_val = hw->mac.ops.init_params(hw);
-		if (ret_val) {
-			DEBUGOUT("MAC Initialization Error\n");
-			goto out;
-		}
-	} else {
-		DEBUGOUT("mac.init_mac_params was NULL\n");
-		ret_val = -E1000_ERR_CONFIG;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_init_nvm_params - Initialize NVM function pointers
- *  @hw: pointer to the HW structure
- *
- *  This function initializes the function pointers for the NVM
- *  set of functions.  Called by drivers or by e1000_setup_init_funcs.
- **/
-s32 e1000_init_nvm_params(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->nvm.ops.init_params) {
-		ret_val = hw->nvm.ops.init_params(hw);
-		if (ret_val) {
-			DEBUGOUT("NVM Initialization Error\n");
-			goto out;
-		}
-	} else {
-		DEBUGOUT("nvm.init_nvm_params was NULL\n");
-		ret_val = -E1000_ERR_CONFIG;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_init_phy_params - Initialize PHY function pointers
- *  @hw: pointer to the HW structure
- *
- *  This function initializes the function pointers for the PHY
- *  set of functions.  Called by drivers or by e1000_setup_init_funcs.
- **/
-s32 e1000_init_phy_params(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->phy.ops.init_params) {
-		ret_val = hw->phy.ops.init_params(hw);
-		if (ret_val) {
-			DEBUGOUT("PHY Initialization Error\n");
-			goto out;
-		}
-	} else {
-		DEBUGOUT("phy.init_phy_params was NULL\n");
-		ret_val =  -E1000_ERR_CONFIG;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_set_mac_type - Sets MAC type
- *  @hw: pointer to the HW structure
- *
- *  This function sets the mac type of the adapter based on the
- *  device ID stored in the hw structure.
- *  MUST BE FIRST FUNCTION CALLED (explicitly or through
- *  e1000_setup_init_funcs()).
- **/
-s32 e1000_set_mac_type(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_set_mac_type");
-
-	switch (hw->device_id) {
-	case E1000_DEV_ID_82542:
-		mac->type = e1000_82542;
-		break;
-	case E1000_DEV_ID_82543GC_FIBER:
-	case E1000_DEV_ID_82543GC_COPPER:
-		mac->type = e1000_82543;
-		break;
-	case E1000_DEV_ID_82544EI_COPPER:
-	case E1000_DEV_ID_82544EI_FIBER:
-	case E1000_DEV_ID_82544GC_COPPER:
-	case E1000_DEV_ID_82544GC_LOM:
-		mac->type = e1000_82544;
-		break;
-	case E1000_DEV_ID_82540EM:
-	case E1000_DEV_ID_82540EM_LOM:
-	case E1000_DEV_ID_82540EP:
-	case E1000_DEV_ID_82540EP_LOM:
-	case E1000_DEV_ID_82540EP_LP:
-		mac->type = e1000_82540;
-		break;
-	case E1000_DEV_ID_82545EM_COPPER:
-	case E1000_DEV_ID_82545EM_FIBER:
-		mac->type = e1000_82545;
-		break;
-	case E1000_DEV_ID_82545GM_COPPER:
-	case E1000_DEV_ID_82545GM_FIBER:
-	case E1000_DEV_ID_82545GM_SERDES:
-		mac->type = e1000_82545_rev_3;
-		break;
-	case E1000_DEV_ID_82546EB_COPPER:
-	case E1000_DEV_ID_82546EB_FIBER:
-	case E1000_DEV_ID_82546EB_QUAD_COPPER:
-		mac->type = e1000_82546;
-		break;
-	case E1000_DEV_ID_82546GB_COPPER:
-	case E1000_DEV_ID_82546GB_FIBER:
-	case E1000_DEV_ID_82546GB_SERDES:
-	case E1000_DEV_ID_82546GB_PCIE:
-	case E1000_DEV_ID_82546GB_QUAD_COPPER:
-	case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
-		mac->type = e1000_82546_rev_3;
-		break;
-	case E1000_DEV_ID_82541EI:
-	case E1000_DEV_ID_82541EI_MOBILE:
-	case E1000_DEV_ID_82541ER_LOM:
-		mac->type = e1000_82541;
-		break;
-	case E1000_DEV_ID_82541ER:
-	case E1000_DEV_ID_82541GI:
-	case E1000_DEV_ID_82541GI_LF:
-	case E1000_DEV_ID_82541GI_MOBILE:
-		mac->type = e1000_82541_rev_2;
-		break;
-	case E1000_DEV_ID_82547EI:
-	case E1000_DEV_ID_82547EI_MOBILE:
-		mac->type = e1000_82547;
-		break;
-	case E1000_DEV_ID_82547GI:
-		mac->type = e1000_82547_rev_2;
-		break;
-	default:
-		/* Should never have loaded on this device */
-		ret_val = -E1000_ERR_MAC_INIT;
-		break;
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000_setup_init_funcs - Initializes function pointers
- *  @hw: pointer to the HW structure
- *  @init_device: true will initialize the rest of the function pointers
- *                 getting the device ready for use.  false will only set
- *                 MAC type and the function pointers for the other init
- *                 functions.  Passing false will not generate any hardware
- *                 reads or writes.
- *
- *  This function must be called by a driver in order to use the rest
- *  of the 'shared' code files. Called by drivers only.
- **/
-s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device)
-{
-	s32 ret_val;
-
-	/* Can't do much good without knowing the MAC type. */
-	ret_val = e1000_set_mac_type(hw);
-	if (ret_val) {
-		DEBUGOUT("ERROR: MAC type could not be set properly.\n");
-		goto out;
-	}
-
-	if (!hw->hw_addr) {
-		DEBUGOUT("ERROR: Registers not mapped\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	/*
-	 * Init function pointers to generic implementations. We do this first
-	 * allowing a driver module to override it afterward.
-	 */
-	e1000_init_mac_ops_generic(hw);
-	e1000_init_phy_ops_generic(hw);
-	e1000_init_nvm_ops_generic(hw);
-
-	/*
-	 * Set up the init function pointers. These are functions within the
-	 * adapter family file that sets up function pointers for the rest of
-	 * the functions in that family.
-	 */
-	switch (hw->mac.type) {
-	case e1000_82542:
-		e1000_init_function_pointers_82542(hw);
-		break;
-	case e1000_82543:
-	case e1000_82544:
-		e1000_init_function_pointers_82543(hw);
-		break;
-	case e1000_82540:
-	case e1000_82545:
-	case e1000_82545_rev_3:
-	case e1000_82546:
-	case e1000_82546_rev_3:
-		e1000_init_function_pointers_82540(hw);
-		break;
-	case e1000_82541:
-	case e1000_82541_rev_2:
-	case e1000_82547:
-	case e1000_82547_rev_2:
-		e1000_init_function_pointers_82541(hw);
-		break;
-	default:
-		DEBUGOUT("Hardware not supported\n");
-		ret_val = -E1000_ERR_CONFIG;
-		break;
-	}
-
-	/*
-	 * Initialize the rest of the function pointers. These require some
-	 * register reads/writes in some cases.
-	 */
-	if (!(ret_val) && init_device) {
-		ret_val = e1000_init_mac_params(hw);
-		if (ret_val)
-			goto out;
-
-		ret_val = e1000_init_nvm_params(hw);
-		if (ret_val)
-			goto out;
-
-		ret_val = e1000_init_phy_params(hw);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_get_bus_info - Obtain bus information for adapter
- *  @hw: pointer to the HW structure
- *
- *  This will obtain information about the HW bus for which the
- *  adapter is attached and stores it in the hw structure. This is a
- *  function pointer entry point called by drivers.
- **/
-s32 e1000_get_bus_info(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.get_bus_info)
-		return hw->mac.ops.get_bus_info(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_clear_vfta - Clear VLAN filter table
- *  @hw: pointer to the HW structure
- *
- *  This clears the VLAN filter table on the adapter. This is a function
- *  pointer entry point called by drivers.
- **/
-void e1000_clear_vfta(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.clear_vfta)
-		hw->mac.ops.clear_vfta(hw);
-}
-
-/**
- *  e1000_write_vfta - Write value to VLAN filter table
- *  @hw: pointer to the HW structure
- *  @offset: the 32-bit offset in which to write the value to.
- *  @value: the 32-bit value to write at location offset.
- *
- *  This writes a 32-bit value to a 32-bit offset in the VLAN filter
- *  table. This is a function pointer entry point called by drivers.
- **/
-void e1000_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
-{
-	if (hw->mac.ops.write_vfta)
-		hw->mac.ops.write_vfta(hw, offset, value);
-}
-
-/**
- *  e1000_update_mc_addr_list - Update Multicast addresses
- *  @hw: pointer to the HW structure
- *  @mc_addr_list: array of multicast addresses to program
- *  @mc_addr_count: number of multicast addresses to program
- *
- *  Updates the Multicast Table Array.
- *  The caller must have a packed mc_addr_list of multicast addresses.
- **/
-void e1000_update_mc_addr_list(struct e1000_hw *hw, u8 *mc_addr_list,
-                               u32 mc_addr_count)
-{
-	if (hw->mac.ops.update_mc_addr_list)
-		hw->mac.ops.update_mc_addr_list(hw, mc_addr_list,
-		                                mc_addr_count);
-}
-
-/**
- *  e1000_force_mac_fc - Force MAC flow control
- *  @hw: pointer to the HW structure
- *
- *  Force the MAC's flow control settings. Currently no func pointer exists
- *  and all implementations are handled in the generic version of this
- *  function.
- **/
-s32 e1000_force_mac_fc(struct e1000_hw *hw)
-{
-	return e1000_force_mac_fc_generic(hw);
-}
-
-/**
- *  e1000_check_for_link - Check/Store link connection
- *  @hw: pointer to the HW structure
- *
- *  This checks the link condition of the adapter and stores the
- *  results in the hw->mac structure. This is a function pointer entry
- *  point called by drivers.
- **/
-s32 e1000_check_for_link(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.check_for_link)
-		return hw->mac.ops.check_for_link(hw);
-
-	return -E1000_ERR_CONFIG;
-}
-
-#if 0
-/**
- *  e1000_check_mng_mode - Check management mode
- *  @hw: pointer to the HW structure
- *
- *  This checks if the adapter has manageability enabled.
- *  This is a function pointer entry point called by drivers.
- **/
-bool e1000_check_mng_mode(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.check_mng_mode)
-		return hw->mac.ops.check_mng_mode(hw);
-
-	return false;
-}
-
-/**
- *  e1000_mng_write_dhcp_info - Writes DHCP info to host interface
- *  @hw: pointer to the HW structure
- *  @buffer: pointer to the host interface
- *  @length: size of the buffer
- *
- *  Writes the DHCP information to the host interface.
- **/
-s32 e1000_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length)
-{
-	return e1000_mng_write_dhcp_info_generic(hw, buffer, length);
-}
-#endif
-
-/**
- *  e1000_reset_hw - Reset hardware
- *  @hw: pointer to the HW structure
- *
- *  This resets the hardware into a known state. This is a function pointer
- *  entry point called by drivers.
- **/
-s32 e1000_reset_hw(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.reset_hw)
-		return hw->mac.ops.reset_hw(hw);
-
-	return -E1000_ERR_CONFIG;
-}
-
-/**
- *  e1000_init_hw - Initialize hardware
- *  @hw: pointer to the HW structure
- *
- *  This inits the hardware readying it for operation. This is a function
- *  pointer entry point called by drivers.
- **/
-s32 e1000_init_hw(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.init_hw)
-		return hw->mac.ops.init_hw(hw);
-
-	return -E1000_ERR_CONFIG;
-}
-
-/**
- *  e1000_setup_link - Configures link and flow control
- *  @hw: pointer to the HW structure
- *
- *  This configures link and flow control settings for the adapter. This
- *  is a function pointer entry point called by drivers. While modules can
- *  also call this, they probably call their own version of this function.
- **/
-s32 e1000_setup_link(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.setup_link)
-		return hw->mac.ops.setup_link(hw);
-
-	return -E1000_ERR_CONFIG;
-}
-
-/**
- *  e1000_get_speed_and_duplex - Returns current speed and duplex
- *  @hw: pointer to the HW structure
- *  @speed: pointer to a 16-bit value to store the speed
- *  @duplex: pointer to a 16-bit value to store the duplex.
- *
- *  This returns the speed and duplex of the adapter in the two 'out'
- *  variables passed in. This is a function pointer entry point called
- *  by drivers.
- **/
-s32 e1000_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed, u16 *duplex)
-{
-	if (hw->mac.ops.get_link_up_info)
-		return hw->mac.ops.get_link_up_info(hw, speed, duplex);
-
-	return -E1000_ERR_CONFIG;
-}
-
-/**
- *  e1000_setup_led - Configures SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  This prepares the SW controllable LED for use and saves the current state
- *  of the LED so it can be later restored. This is a function pointer entry
- *  point called by drivers.
- **/
-s32 e1000_setup_led(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.setup_led)
-		return hw->mac.ops.setup_led(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_cleanup_led - Restores SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  This restores the SW controllable LED to the value saved off by
- *  e1000_setup_led. This is a function pointer entry point called by drivers.
- **/
-s32 e1000_cleanup_led(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.cleanup_led)
-		return hw->mac.ops.cleanup_led(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_blink_led - Blink SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  This starts the adapter LED blinking. Request the LED to be setup first
- *  and cleaned up after. This is a function pointer entry point called by
- *  drivers.
- **/
-s32 e1000_blink_led(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.blink_led)
-		return hw->mac.ops.blink_led(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_id_led_init - store LED configurations in SW
- *  @hw: pointer to the HW structure
- *
- *  Initializes the LED config in SW. This is a function pointer entry point
- *  called by drivers.
- **/
-s32 e1000_id_led_init(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.id_led_init)
-		return hw->mac.ops.id_led_init(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_led_on - Turn on SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  Turns the SW defined LED on. This is a function pointer entry point
- *  called by drivers.
- **/
-s32 e1000_led_on(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.led_on)
-		return hw->mac.ops.led_on(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_led_off - Turn off SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  Turns the SW defined LED off. This is a function pointer entry point
- *  called by drivers.
- **/
-s32 e1000_led_off(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.led_off)
-		return hw->mac.ops.led_off(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_reset_adaptive - Reset adaptive IFS
- *  @hw: pointer to the HW structure
- *
- *  Resets the adaptive IFS. Currently no func pointer exists and all
- *  implementations are handled in the generic version of this function.
- **/
-void e1000_reset_adaptive(struct e1000_hw *hw)
-{
-	e1000_reset_adaptive_generic(hw);
-}
-
-/**
- *  e1000_update_adaptive - Update adaptive IFS
- *  @hw: pointer to the HW structure
- *
- *  Updates adapter IFS. Currently no func pointer exists and all
- *  implementations are handled in the generic version of this function.
- **/
-void e1000_update_adaptive(struct e1000_hw *hw)
-{
-	e1000_update_adaptive_generic(hw);
-}
-
-/**
- *  e1000_disable_pcie_master - Disable PCI-Express master access
- *  @hw: pointer to the HW structure
- *
- *  Disables PCI-Express master access and verifies there are no pending
- *  requests. Currently no func pointer exists and all implementations are
- *  handled in the generic version of this function.
- **/
-s32 e1000_disable_pcie_master(struct e1000_hw *hw)
-{
-	return e1000_disable_pcie_master_generic(hw);
-}
-
-/**
- *  e1000_config_collision_dist - Configure collision distance
- *  @hw: pointer to the HW structure
- *
- *  Configures the collision distance to the default value and is used
- *  during link setup.
- **/
-void e1000_config_collision_dist(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.config_collision_dist)
-		hw->mac.ops.config_collision_dist(hw);
-}
-
-/**
- *  e1000_rar_set - Sets a receive address register
- *  @hw: pointer to the HW structure
- *  @addr: address to set the RAR to
- *  @index: the RAR to set
- *
- *  Sets a Receive Address Register (RAR) to the specified address.
- **/
-void e1000_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
-{
-	if (hw->mac.ops.rar_set)
-		hw->mac.ops.rar_set(hw, addr, index);
-}
-
-/**
- *  e1000_validate_mdi_setting - Ensures valid MDI/MDIX SW state
- *  @hw: pointer to the HW structure
- *
- *  Ensures that the MDI/MDIX SW state is valid.
- **/
-s32 e1000_validate_mdi_setting(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.validate_mdi_setting)
-		return hw->mac.ops.validate_mdi_setting(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_mta_set - Sets multicast table bit
- *  @hw: pointer to the HW structure
- *  @hash_value: Multicast hash value.
- *
- *  This sets the bit in the multicast table corresponding to the
- *  hash value.  This is a function pointer entry point called by drivers.
- **/
-void e1000_mta_set(struct e1000_hw *hw, u32 hash_value)
-{
-	if (hw->mac.ops.mta_set)
-		hw->mac.ops.mta_set(hw, hash_value);
-}
-
-/**
- *  e1000_hash_mc_addr - Determines address location in multicast table
- *  @hw: pointer to the HW structure
- *  @mc_addr: Multicast address to hash.
- *
- *  This hashes an address to determine its location in the multicast
- *  table. Currently no func pointer exists and all implementations
- *  are handled in the generic version of this function.
- **/
-u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr)
-{
-	return e1000_hash_mc_addr_generic(hw, mc_addr);
-}
-
-#if 0
-/**
- *  e1000_enable_tx_pkt_filtering - Enable packet filtering on TX
- *  @hw: pointer to the HW structure
- *
- *  Enables packet filtering on transmit packets if manageability is enabled
- *  and host interface is enabled.
- *  Currently no func pointer exists and all implementations are handled in the
- *  generic version of this function.
- **/
-bool e1000_enable_tx_pkt_filtering(struct e1000_hw *hw)
-{
-	return e1000_enable_tx_pkt_filtering_generic(hw);
-}
-
-/**
- *  e1000_mng_host_if_write - Writes to the manageability host interface
- *  @hw: pointer to the HW structure
- *  @buffer: pointer to the host interface buffer
- *  @length: size of the buffer
- *  @offset: location in the buffer to write to
- *  @sum: sum of the data (not checksum)
- *
- *  This function writes the buffer content at the offset given on the host if.
- *  It also does alignment considerations to do the writes in most efficient
- *  way.  Also fills up the sum of the buffer in *buffer parameter.
- **/
-s32 e1000_mng_host_if_write(struct e1000_hw * hw, u8 *buffer, u16 length,
-                            u16 offset, u8 *sum)
-{
-	if (hw->mac.ops.mng_host_if_write)
-		return hw->mac.ops.mng_host_if_write(hw, buffer, length,
-		                                     offset, sum);
-
-	return E1000_NOT_IMPLEMENTED;
-}
-
-/**
- *  e1000_mng_write_cmd_header - Writes manageability command header
- *  @hw: pointer to the HW structure
- *  @hdr: pointer to the host interface command header
- *
- *  Writes the command header after does the checksum calculation.
- **/
-s32 e1000_mng_write_cmd_header(struct e1000_hw *hw,
-                               struct e1000_host_mng_command_header *hdr)
-{
-	if (hw->mac.ops.mng_write_cmd_header)
-		return hw->mac.ops.mng_write_cmd_header(hw, hdr);
-
-	return E1000_NOT_IMPLEMENTED;
-}
-
-/**
- *  e1000_mng_enable_host_if - Checks host interface is enabled
- *  @hw: pointer to the HW structure
- *
- *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
- *
- *  This function checks whether the HOST IF is enabled for command operation
- *  and also checks whether the previous command is completed.  It busy waits
- *  in case of previous command is not completed.
- **/
-s32 e1000_mng_enable_host_if(struct e1000_hw * hw)
-{
-	if (hw->mac.ops.mng_enable_host_if)
-		return hw->mac.ops.mng_enable_host_if(hw);
-
-	return E1000_NOT_IMPLEMENTED;
-}
-#endif
-
-/**
- *  e1000_wait_autoneg - Waits for autonegotiation completion
- *  @hw: pointer to the HW structure
- *
- *  Waits for autoneg to complete. Currently no func pointer exists and all
- *  implementations are handled in the generic version of this function.
- **/
-s32 e1000_wait_autoneg(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.wait_autoneg)
-		return hw->mac.ops.wait_autoneg(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_check_reset_block - Verifies PHY can be reset
- *  @hw: pointer to the HW structure
- *
- *  Checks if the PHY is in a state that can be reset or if manageability
- *  has it tied up. This is a function pointer entry point called by drivers.
- **/
-s32 e1000_check_reset_block(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.check_reset_block)
-		return hw->phy.ops.check_reset_block(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_read_phy_reg - Reads PHY register
- *  @hw: pointer to the HW structure
- *  @offset: the register to read
- *  @data: the buffer to store the 16-bit read.
- *
- *  Reads the PHY register and returns the value in data.
- *  This is a function pointer entry point called by drivers.
- **/
-s32 e1000_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	if (hw->phy.ops.read_reg)
-		return hw->phy.ops.read_reg(hw, offset, data);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_write_phy_reg - Writes PHY register
- *  @hw: pointer to the HW structure
- *  @offset: the register to write
- *  @data: the value to write.
- *
- *  Writes the PHY register at offset with the value in data.
- *  This is a function pointer entry point called by drivers.
- **/
-s32 e1000_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	if (hw->phy.ops.write_reg)
-		return hw->phy.ops.write_reg(hw, offset, data);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_release_phy - Generic release PHY
- *  @hw: pointer to the HW structure
- *
- *  Return if silicon family does not require a semaphore when accessing the
- *  PHY.
- **/
-void e1000_release_phy(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.release)
-		hw->phy.ops.release(hw);
-}
-
-/**
- *  e1000_acquire_phy - Generic acquire PHY
- *  @hw: pointer to the HW structure
- *
- *  Return success if silicon family does not require a semaphore when
- *  accessing the PHY.
- **/
-s32 e1000_acquire_phy(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.acquire)
-		return hw->phy.ops.acquire(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_read_kmrn_reg - Reads register using Kumeran interface
- *  @hw: pointer to the HW structure
- *  @offset: the register to read
- *  @data: the location to store the 16-bit value read.
- *
- *  Reads a register out of the Kumeran interface. Currently no func pointer
- *  exists and all implementations are handled in the generic version of
- *  this function.
- **/
-s32 e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	return e1000_read_kmrn_reg_generic(hw, offset, data);
-}
-
-/**
- *  e1000_write_kmrn_reg - Writes register using Kumeran interface
- *  @hw: pointer to the HW structure
- *  @offset: the register to write
- *  @data: the value to write.
- *
- *  Writes a register to the Kumeran interface. Currently no func pointer
- *  exists and all implementations are handled in the generic version of
- *  this function.
- **/
-s32 e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	return e1000_write_kmrn_reg_generic(hw, offset, data);
-}
-
-#if 0
-/**
- *  e1000_get_cable_length - Retrieves cable length estimation
- *  @hw: pointer to the HW structure
- *
- *  This function estimates the cable length and stores them in
- *  hw->phy.min_length and hw->phy.max_length. This is a function pointer
- *  entry point called by drivers.
- **/
-s32 e1000_get_cable_length(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.get_cable_length)
-		return hw->phy.ops.get_cable_length(hw);
-
-	return E1000_SUCCESS;
-}
-#endif
-
-/**
- *  e1000_get_phy_info - Retrieves PHY information from registers
- *  @hw: pointer to the HW structure
- *
- *  This function gets some information from various PHY registers and
- *  populates hw->phy values with it. This is a function pointer entry
- *  point called by drivers.
- **/
-s32 e1000_get_phy_info(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.get_info)
-		return hw->phy.ops.get_info(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_phy_hw_reset - Hard PHY reset
- *  @hw: pointer to the HW structure
- *
- *  Performs a hard PHY reset. This is a function pointer entry point called
- *  by drivers.
- **/
-s32 e1000_phy_hw_reset(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.reset)
-		return hw->phy.ops.reset(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_phy_commit - Soft PHY reset
- *  @hw: pointer to the HW structure
- *
- *  Performs a soft PHY reset on those that apply. This is a function pointer
- *  entry point called by drivers.
- **/
-s32 e1000_phy_commit(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.commit)
-		return hw->phy.ops.commit(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_set_d0_lplu_state - Sets low power link up state for D0
- *  @hw: pointer to the HW structure
- *  @active: boolean used to enable/disable lplu
- *
- *  Success returns 0, Failure returns 1
- *
- *  The low power link up (lplu) state is set to the power management level D0
- *  and SmartSpeed is disabled when active is true, else clear lplu for D0
- *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
- *  is used during Dx states where the power conservation is most important.
- *  During driver activity, SmartSpeed should be enabled so performance is
- *  maintained.  This is a function pointer entry point called by drivers.
- **/
-s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active)
-{
-	if (hw->phy.ops.set_d0_lplu_state)
-		return hw->phy.ops.set_d0_lplu_state(hw, active);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_set_d3_lplu_state - Sets low power link up state for D3
- *  @hw: pointer to the HW structure
- *  @active: boolean used to enable/disable lplu
- *
- *  Success returns 0, Failure returns 1
- *
- *  The low power link up (lplu) state is set to the power management level D3
- *  and SmartSpeed is disabled when active is true, else clear lplu for D3
- *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
- *  is used during Dx states where the power conservation is most important.
- *  During driver activity, SmartSpeed should be enabled so performance is
- *  maintained.  This is a function pointer entry point called by drivers.
- **/
-s32 e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active)
-{
-	if (hw->phy.ops.set_d3_lplu_state)
-		return hw->phy.ops.set_d3_lplu_state(hw, active);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_read_mac_addr - Reads MAC address
- *  @hw: pointer to the HW structure
- *
- *  Reads the MAC address out of the adapter and stores it in the HW structure.
- *  Currently no func pointer exists and all implementations are handled in the
- *  generic version of this function.
- **/
-s32 e1000_read_mac_addr(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.read_mac_addr)
-		return hw->mac.ops.read_mac_addr(hw);
-
-	return e1000_read_mac_addr_generic(hw);
-}
-
-/**
- *  e1000_read_pba_num - Read device part number
- *  @hw: pointer to the HW structure
- *  @pba_num: pointer to device part number
- *
- *  Reads the product board assembly (PBA) number from the EEPROM and stores
- *  the value in pba_num.
- *  Currently no func pointer exists and all implementations are handled in the
- *  generic version of this function.
- **/
-s32 e1000_read_pba_num(struct e1000_hw *hw, u32 *pba_num)
-{
-	return e1000_read_pba_num_generic(hw, pba_num);
-}
-
-/**
- *  e1000_validate_nvm_checksum - Verifies NVM (EEPROM) checksum
- *  @hw: pointer to the HW structure
- *
- *  Validates the NVM checksum is correct. This is a function pointer entry
- *  point called by drivers.
- **/
-s32 e1000_validate_nvm_checksum(struct e1000_hw *hw)
-{
-	if (hw->nvm.ops.validate)
-		return hw->nvm.ops.validate(hw);
-
-	return -E1000_ERR_CONFIG;
-}
-
-/**
- *  e1000_update_nvm_checksum - Updates NVM (EEPROM) checksum
- *  @hw: pointer to the HW structure
- *
- *  Updates the NVM checksum. Currently no func pointer exists and all
- *  implementations are handled in the generic version of this function.
- **/
-s32 e1000_update_nvm_checksum(struct e1000_hw *hw)
-{
-	if (hw->nvm.ops.update)
-		return hw->nvm.ops.update(hw);
-
-	return -E1000_ERR_CONFIG;
-}
-
-/**
- *  e1000_reload_nvm - Reloads EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
- *  extended control register.
- **/
-void e1000_reload_nvm(struct e1000_hw *hw)
-{
-	if (hw->nvm.ops.reload)
-		hw->nvm.ops.reload(hw);
-}
-
-/**
- *  e1000_read_nvm - Reads NVM (EEPROM)
- *  @hw: pointer to the HW structure
- *  @offset: the word offset to read
- *  @words: number of 16-bit words to read
- *  @data: pointer to the properly sized buffer for the data.
- *
- *  Reads 16-bit chunks of data from the NVM (EEPROM). This is a function
- *  pointer entry point called by drivers.
- **/
-s32 e1000_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	if (hw->nvm.ops.read)
-		return hw->nvm.ops.read(hw, offset, words, data);
-
-	return -E1000_ERR_CONFIG;
-}
-
-/**
- *  e1000_write_nvm - Writes to NVM (EEPROM)
- *  @hw: pointer to the HW structure
- *  @offset: the word offset to read
- *  @words: number of 16-bit words to write
- *  @data: pointer to the properly sized buffer for the data.
- *
- *  Writes 16-bit chunks of data to the NVM (EEPROM). This is a function
- *  pointer entry point called by drivers.
- **/
-s32 e1000_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	if (hw->nvm.ops.write)
-		return hw->nvm.ops.write(hw, offset, words, data);
-
-	return E1000_SUCCESS;
-}
-
-/**
- * e1000_power_up_phy - Restores link in case of PHY power down
- * @hw: pointer to the HW structure
- *
- * The phy may be powered down to save power, to turn off link when the
- * driver is unloaded, or wake on lan is not enabled (among others).
- **/
-void e1000_power_up_phy(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.power_up)
-		hw->phy.ops.power_up(hw);
-
-	e1000_setup_link(hw);
-}
-
-/**
- * e1000_power_down_phy - Power down PHY
- * @hw: pointer to the HW structure
- *
- * The phy may be powered down to save power, to turn off link when the
- * driver is unloaded, or wake on lan is not enabled (among others).
- **/
-void e1000_power_down_phy(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.power_down)
-		hw->phy.ops.power_down(hw);
-}
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_api.h b/roms/ipxe/src/drivers/net/e1000/e1000_api.h
deleted file mode 100644
index fc1e533d2c7983d58a659425f89e2d535c919481..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_api.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000_API_H_
-#define _E1000_API_H_
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <ipxe/io.h>
-#include <errno.h>
-#include <byteswap.h>
-#include <ipxe/pci.h>
-#include <ipxe/malloc.h>
-#include <ipxe/if_ether.h>
-#include <ipxe/ethernet.h>
-#include <ipxe/iobuf.h>
-#include <ipxe/netdevice.h>
-
-#include "e1000_hw.h"
-
-extern void    e1000_init_function_pointers_82542(struct e1000_hw *hw) __attribute__((weak));
-extern void    e1000_init_function_pointers_82543(struct e1000_hw *hw) __attribute__((weak));
-extern void    e1000_init_function_pointers_82540(struct e1000_hw *hw) __attribute__((weak));
-extern void    e1000_init_function_pointers_82541(struct e1000_hw *hw) __attribute__((weak));
-
-s32  e1000_set_mac_type(struct e1000_hw *hw);
-s32  e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device);
-s32  e1000_init_mac_params(struct e1000_hw *hw);
-s32  e1000_init_nvm_params(struct e1000_hw *hw);
-s32  e1000_init_phy_params(struct e1000_hw *hw);
-s32  e1000_get_bus_info(struct e1000_hw *hw);
-void e1000_clear_vfta(struct e1000_hw *hw);
-void e1000_write_vfta(struct e1000_hw *hw, u32 offset, u32 value);
-s32  e1000_force_mac_fc(struct e1000_hw *hw);
-s32  e1000_check_for_link(struct e1000_hw *hw);
-s32  e1000_reset_hw(struct e1000_hw *hw);
-s32  e1000_init_hw(struct e1000_hw *hw);
-s32  e1000_setup_link(struct e1000_hw *hw);
-s32  e1000_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed,
-                                u16 *duplex);
-s32  e1000_disable_pcie_master(struct e1000_hw *hw);
-void e1000_config_collision_dist(struct e1000_hw *hw);
-void e1000_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
-void e1000_mta_set(struct e1000_hw *hw, u32 hash_value);
-u32  e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr);
-void e1000_update_mc_addr_list(struct e1000_hw *hw,
-                               u8 *mc_addr_list, u32 mc_addr_count);
-s32  e1000_setup_led(struct e1000_hw *hw);
-s32  e1000_cleanup_led(struct e1000_hw *hw);
-s32  e1000_check_reset_block(struct e1000_hw *hw);
-s32  e1000_blink_led(struct e1000_hw *hw);
-s32  e1000_led_on(struct e1000_hw *hw);
-s32  e1000_led_off(struct e1000_hw *hw);
-s32 e1000_id_led_init(struct e1000_hw *hw);
-void e1000_reset_adaptive(struct e1000_hw *hw);
-void e1000_update_adaptive(struct e1000_hw *hw);
-#if 0
-s32  e1000_get_cable_length(struct e1000_hw *hw);
-#endif
-s32  e1000_validate_mdi_setting(struct e1000_hw *hw);
-s32  e1000_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data);
-s32  e1000_get_phy_info(struct e1000_hw *hw);
-void e1000_release_phy(struct e1000_hw *hw);
-s32  e1000_acquire_phy(struct e1000_hw *hw);
-s32  e1000_phy_hw_reset(struct e1000_hw *hw);
-s32  e1000_phy_commit(struct e1000_hw *hw);
-void e1000_power_up_phy(struct e1000_hw *hw);
-void e1000_power_down_phy(struct e1000_hw *hw);
-s32  e1000_read_mac_addr(struct e1000_hw *hw);
-s32  e1000_read_pba_num(struct e1000_hw *hw, u32 *part_num);
-void e1000_reload_nvm(struct e1000_hw *hw);
-s32  e1000_update_nvm_checksum(struct e1000_hw *hw);
-s32  e1000_validate_nvm_checksum(struct e1000_hw *hw);
-s32  e1000_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
-s32  e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
-s32  e1000_write_nvm(struct e1000_hw *hw, u16 offset, u16 words,
-                     u16 *data);
-s32  e1000_wait_autoneg(struct e1000_hw *hw);
-s32  e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active);
-s32  e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active);
-bool e1000_check_mng_mode(struct e1000_hw *hw);
-bool e1000_enable_tx_pkt_filtering(struct e1000_hw *hw);
-s32  e1000_mng_enable_host_if(struct e1000_hw *hw);
-s32  e1000_mng_host_if_write(struct e1000_hw *hw,
-                             u8 *buffer, u16 length, u16 offset, u8 *sum);
-s32  e1000_mng_write_cmd_header(struct e1000_hw *hw,
-                                struct e1000_host_mng_command_header *hdr);
-s32  e1000_mng_write_dhcp_info(struct e1000_hw * hw,
-                                    u8 *buffer, u16 length);
-u32  e1000_translate_register_82542(u32 reg) __attribute__((weak));
-
-extern int e1000_probe(struct pci_device *pdev);
-extern void e1000_remove(struct pci_device *pdev);
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_defines.h b/roms/ipxe/src/drivers/net/e1000/e1000_defines.h
deleted file mode 100644
index c585f09bc59a1dbb17498d3e392d80c2963d3727..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_defines.h
+++ /dev/null
@@ -1,1416 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000_DEFINES_H_
-#define _E1000_DEFINES_H_
-
-/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
-#define REQ_TX_DESCRIPTOR_MULTIPLE  8
-#define REQ_RX_DESCRIPTOR_MULTIPLE  8
-
-/* Definitions for power management and wakeup registers */
-/* Wake Up Control */
-#define E1000_WUC_APME       0x00000001 /* APM Enable */
-#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
-#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
-#define E1000_WUC_APMPME     0x00000008 /* Assert PME on APM Wakeup */
-#define E1000_WUC_LSCWE      0x00000010 /* Link Status wake up enable */
-#define E1000_WUC_LSCWO      0x00000020 /* Link Status wake up override */
-#define E1000_WUC_SPM        0x80000000 /* Enable SPM */
-#define E1000_WUC_PHY_WAKE   0x00000100 /* if PHY supports wakeup */
-
-/* Wake Up Filter Control */
-#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
-#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
-#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
-#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
-#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
-#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
-#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
-#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
-#define E1000_WUFC_IGNORE_TCO   0x00008000 /* Ignore WakeOn TCO packets */
-#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
-#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
-#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
-#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
-#define E1000_WUFC_ALL_FILTERS  0x000F00FF /* Mask for all wakeup filters */
-#define E1000_WUFC_FLX_OFFSET   16 /* Offset to the Flexible Filters bits */
-#define E1000_WUFC_FLX_FILTERS  0x000F0000 /*Mask for the 4 flexible filters */
-
-/* Wake Up Status */
-#define E1000_WUS_LNKC         E1000_WUFC_LNKC
-#define E1000_WUS_MAG          E1000_WUFC_MAG
-#define E1000_WUS_EX           E1000_WUFC_EX
-#define E1000_WUS_MC           E1000_WUFC_MC
-#define E1000_WUS_BC           E1000_WUFC_BC
-#define E1000_WUS_ARP          E1000_WUFC_ARP
-#define E1000_WUS_IPV4         E1000_WUFC_IPV4
-#define E1000_WUS_IPV6         E1000_WUFC_IPV6
-#define E1000_WUS_FLX0         E1000_WUFC_FLX0
-#define E1000_WUS_FLX1         E1000_WUFC_FLX1
-#define E1000_WUS_FLX2         E1000_WUFC_FLX2
-#define E1000_WUS_FLX3         E1000_WUFC_FLX3
-#define E1000_WUS_FLX_FILTERS  E1000_WUFC_FLX_FILTERS
-
-/* Wake Up Packet Length */
-#define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
-
-/* Four Flexible Filters are supported */
-#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
-
-/* Each Flexible Filter is at most 128 (0x80) bytes in length */
-#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
-
-#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
-#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
-#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
-
-/* Extended Device Control */
-#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */
-#define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
-#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
-#define E1000_CTRL_EXT_GPI2_EN   0x00000004 /* Maps SDP6 to GPI2 */
-#define E1000_CTRL_EXT_GPI3_EN   0x00000008 /* Maps SDP7 to GPI3 */
-/* Reserved (bits 4,5) in >= 82575 */
-#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Definable Pin 4 */
-#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */
-#define E1000_CTRL_EXT_PHY_INT   E1000_CTRL_EXT_SDP5_DATA
-#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */
-#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */
-/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */
-#define E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
-#define E1000_CTRL_EXT_SDP5_DIR  0x00000200 /* Direction of SDP5 0=in 1=out */
-#define E1000_CTRL_EXT_SDP6_DIR  0x00000400 /* Direction of SDP6 0=in 1=out */
-#define E1000_CTRL_EXT_SDP7_DIR  0x00000800 /* Direction of SDP7 0=in 1=out */
-#define E1000_CTRL_EXT_ASDCHK    0x00001000 /* Initiate an ASD sequence */
-#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
-#define E1000_CTRL_EXT_IPS       0x00004000 /* Invert Power State */
-#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
-#define E1000_CTRL_EXT_RO_DIS    0x00020000 /* Relaxed Ordering disable */
-#define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 /* DMA Dynamic Clock Gating */
-#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
-#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
-#define E1000_CTRL_EXT_LINK_MODE_TBI  0x00C00000
-#define E1000_CTRL_EXT_LINK_MODE_KMRN    0x00000000
-#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
-#define E1000_CTRL_EXT_LINK_MODE_PCIX_SERDES  0x00800000
-#define E1000_CTRL_EXT_LINK_MODE_SGMII   0x00800000
-#define E1000_CTRL_EXT_EIAME          0x01000000
-#define E1000_CTRL_EXT_IRCA           0x00000001
-#define E1000_CTRL_EXT_WR_WMARK_MASK  0x03000000
-#define E1000_CTRL_EXT_WR_WMARK_256   0x00000000
-#define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
-#define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
-#define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
-#define E1000_CTRL_EXT_CANC           0x04000000 /* Int delay cancellation */
-#define E1000_CTRL_EXT_DRV_LOAD       0x10000000 /* Driver loaded bit for FW */
-/* IAME enable bit (27) was removed in >= 82575 */
-#define E1000_CTRL_EXT_IAME          0x08000000 /* Int acknowledge Auto-mask */
-#define E1000_CRTL_EXT_PB_PAREN       0x01000000 /* packet buffer parity error
-                                                  * detection enabled */
-#define E1000_CTRL_EXT_DF_PAREN       0x02000000 /* descriptor FIFO parity
-                                                  * error detection enable */
-#define E1000_CTRL_EXT_GHOST_PAREN    0x40000000
-#define E1000_CTRL_EXT_PBA_CLR        0x80000000 /* PBA Clear */
-#define E1000_I2CCMD_REG_ADDR_SHIFT   16
-#define E1000_I2CCMD_REG_ADDR         0x00FF0000
-#define E1000_I2CCMD_PHY_ADDR_SHIFT   24
-#define E1000_I2CCMD_PHY_ADDR         0x07000000
-#define E1000_I2CCMD_OPCODE_READ      0x08000000
-#define E1000_I2CCMD_OPCODE_WRITE     0x00000000
-#define E1000_I2CCMD_RESET            0x10000000
-#define E1000_I2CCMD_READY            0x20000000
-#define E1000_I2CCMD_INTERRUPT_ENA    0x40000000
-#define E1000_I2CCMD_ERROR            0x80000000
-#define E1000_MAX_SGMII_PHY_REG_ADDR  255
-#define E1000_I2CCMD_PHY_TIMEOUT      200
-
-/* Receive Descriptor bit definitions */
-#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
-#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
-#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
-#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
-#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum calculated */
-#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
-#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
-#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
-#define E1000_RXD_STAT_CRCV     0x100   /* Speculative CRC Valid */
-#define E1000_RXD_STAT_IPIDV    0x200   /* IP identification valid */
-#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
-#define E1000_RXD_STAT_DYNINT   0x800   /* Pkt caused INT via DYNINT */
-#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
-#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
-#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
-#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
-#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
-#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
-#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
-#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
-#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
-#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
-#define E1000_RXD_SPC_PRI_SHIFT 13
-#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
-#define E1000_RXD_SPC_CFI_SHIFT 12
-
-#define E1000_RXDEXT_STATERR_CE    0x01000000
-#define E1000_RXDEXT_STATERR_SE    0x02000000
-#define E1000_RXDEXT_STATERR_SEQ   0x04000000
-#define E1000_RXDEXT_STATERR_CXE   0x10000000
-#define E1000_RXDEXT_STATERR_TCPE  0x20000000
-#define E1000_RXDEXT_STATERR_IPE   0x40000000
-#define E1000_RXDEXT_STATERR_RXE   0x80000000
-
-/* mask to determine if packets should be dropped due to frame errors */
-#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
-    E1000_RXD_ERR_CE  |                \
-    E1000_RXD_ERR_SE  |                \
-    E1000_RXD_ERR_SEQ |                \
-    E1000_RXD_ERR_CXE |                \
-    E1000_RXD_ERR_RXE)
-
-/* Same mask, but for extended and packet split descriptors */
-#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
-    E1000_RXDEXT_STATERR_CE  |            \
-    E1000_RXDEXT_STATERR_SE  |            \
-    E1000_RXDEXT_STATERR_SEQ |            \
-    E1000_RXDEXT_STATERR_CXE |            \
-    E1000_RXDEXT_STATERR_RXE)
-
-#define E1000_MRQC_ENABLE_MASK                 0x00000007
-#define E1000_MRQC_ENABLE_RSS_2Q               0x00000001
-#define E1000_MRQC_ENABLE_RSS_INT              0x00000004
-#define E1000_MRQC_RSS_FIELD_MASK              0xFFFF0000
-#define E1000_MRQC_RSS_FIELD_IPV4_TCP          0x00010000
-#define E1000_MRQC_RSS_FIELD_IPV4              0x00020000
-#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX       0x00040000
-#define E1000_MRQC_RSS_FIELD_IPV6_EX           0x00080000
-#define E1000_MRQC_RSS_FIELD_IPV6              0x00100000
-#define E1000_MRQC_RSS_FIELD_IPV6_TCP          0x00200000
-
-#define E1000_RXDPS_HDRSTAT_HDRSP              0x00008000
-#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK        0x000003FF
-
-/* Management Control */
-#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
-#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
-#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
-#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
-#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
-#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
-#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
-#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
-#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
-/* Enable Neighbor Discovery Filtering */
-#define E1000_MANC_NEIGHBOR_EN   0x00004000
-#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response Filtering */
-#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
-#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
-#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
-#define E1000_MANC_RCV_ALL       0x00080000 /* Receive All Enabled */
-#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
-/* Enable MAC address filtering */
-#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000
-/* Enable MNG packets to host memory */
-#define E1000_MANC_EN_MNG2HOST   0x00200000
-/* Enable IP address filtering */
-#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000
-#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
-#define E1000_MANC_BR_EN            0x01000000 /* Enable broadcast filtering */
-#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
-#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
-#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
-#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
-#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
-#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
-
-#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
-#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
-
-/* Receive Control */
-#define E1000_RCTL_RST            0x00000001    /* Software reset */
-#define E1000_RCTL_EN             0x00000002    /* enable */
-#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
-#define E1000_RCTL_UPE            0x00000008    /* unicast promisc enable */
-#define E1000_RCTL_MPE            0x00000010    /* multicast promisc enable */
-#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
-#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
-#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
-#define E1000_RCTL_LBM_SLP        0x00000080    /* serial link loopback mode */
-#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
-#define E1000_RCTL_DTYP_MASK      0x00000C00    /* Descriptor type mask */
-#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
-#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min thresh size */
-#define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min thresh size */
-#define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min thresh size */
-#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
-#define E1000_RCTL_MO_0           0x00000000    /* multicast offset 11:0 */
-#define E1000_RCTL_MO_1           0x00001000    /* multicast offset 12:1 */
-#define E1000_RCTL_MO_2           0x00002000    /* multicast offset 13:2 */
-#define E1000_RCTL_MO_3           0x00003000    /* multicast offset 15:4 */
-#define E1000_RCTL_MDR            0x00004000    /* multicast desc ring 0 */
-#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
-#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
-#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
-#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
-#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
-#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
-#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
-#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
-#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
-#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
-#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
-#define E1000_RCTL_DPF            0x00400000    /* discard pause frames */
-#define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
-#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
-#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
-#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
-#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
-
-/*
- * Use byte values for the following shift parameters
- * Usage:
- *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
- *                  E1000_PSRCTL_BSIZE0_MASK) |
- *                ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
- *                  E1000_PSRCTL_BSIZE1_MASK) |
- *                ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
- *                  E1000_PSRCTL_BSIZE2_MASK) |
- *                ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
- *                  E1000_PSRCTL_BSIZE3_MASK))
- * where value0 = [128..16256],  default=256
- *       value1 = [1024..64512], default=4096
- *       value2 = [0..64512],    default=4096
- *       value3 = [0..64512],    default=0
- */
-
-#define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
-#define E1000_PSRCTL_BSIZE1_MASK   0x00003F00
-#define E1000_PSRCTL_BSIZE2_MASK   0x003F0000
-#define E1000_PSRCTL_BSIZE3_MASK   0x3F000000
-
-#define E1000_PSRCTL_BSIZE0_SHIFT  7            /* Shift _right_ 7 */
-#define E1000_PSRCTL_BSIZE1_SHIFT  2            /* Shift _right_ 2 */
-#define E1000_PSRCTL_BSIZE2_SHIFT  6            /* Shift _left_ 6 */
-#define E1000_PSRCTL_BSIZE3_SHIFT 14            /* Shift _left_ 14 */
-
-/* SWFW_SYNC Definitions */
-#define E1000_SWFW_EEP_SM   0x01
-#define E1000_SWFW_PHY0_SM  0x02
-#define E1000_SWFW_PHY1_SM  0x04
-#define E1000_SWFW_CSR_SM   0x08
-
-/* FACTPS Definitions */
-#define E1000_FACTPS_LFS    0x40000000  /* LAN Function Select */
-/* Device Control */
-#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
-#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
-#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
-#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master reqs */
-#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
-#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
-#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
-#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
-#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
-#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
-#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
-#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
-#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
-#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
-#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
-#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
-#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
-#define E1000_CTRL_D_UD_EN  0x00002000  /* Dock/Undock enable */
-#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock
-                                             * indication in SDP[0] */
-#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through
-                                               * PHYRST_N pin */
-#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external
-                                           * LINK_0 and LINK_1 pins */
-#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
-#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
-#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
-#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
-#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
-#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
-#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
-#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
-#define E1000_CTRL_RST      0x04000000  /* Global reset */
-#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
-#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
-#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
-#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
-#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
-#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to ME */
-#define E1000_CTRL_I2C_ENA  0x02000000  /* I2C enable */
-
-/*
- * Bit definitions for the Management Data IO (MDIO) and Management Data
- * Clock (MDC) pins in the Device Control Register.
- */
-#define E1000_CTRL_PHY_RESET_DIR  E1000_CTRL_SWDPIO0
-#define E1000_CTRL_PHY_RESET      E1000_CTRL_SWDPIN0
-#define E1000_CTRL_MDIO_DIR       E1000_CTRL_SWDPIO2
-#define E1000_CTRL_MDIO           E1000_CTRL_SWDPIN2
-#define E1000_CTRL_MDC_DIR        E1000_CTRL_SWDPIO3
-#define E1000_CTRL_MDC            E1000_CTRL_SWDPIN3
-#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
-#define E1000_CTRL_PHY_RESET4     E1000_CTRL_EXT_SDP4_DATA
-
-#define E1000_CONNSW_ENRGSRC             0x4
-#define E1000_PCS_CFG_PCS_EN             8
-#define E1000_PCS_LCTL_FLV_LINK_UP       1
-#define E1000_PCS_LCTL_FSV_10            0
-#define E1000_PCS_LCTL_FSV_100           2
-#define E1000_PCS_LCTL_FSV_1000          4
-#define E1000_PCS_LCTL_FDV_FULL          8
-#define E1000_PCS_LCTL_FSD               0x10
-#define E1000_PCS_LCTL_FORCE_LINK        0x20
-#define E1000_PCS_LCTL_LOW_LINK_LATCH    0x40
-#define E1000_PCS_LCTL_FORCE_FCTRL       0x80
-#define E1000_PCS_LCTL_AN_ENABLE         0x10000
-#define E1000_PCS_LCTL_AN_RESTART        0x20000
-#define E1000_PCS_LCTL_AN_TIMEOUT        0x40000
-#define E1000_PCS_LCTL_AN_SGMII_BYPASS   0x80000
-#define E1000_PCS_LCTL_AN_SGMII_TRIGGER  0x100000
-#define E1000_PCS_LCTL_FAST_LINK_TIMER   0x1000000
-#define E1000_PCS_LCTL_LINK_OK_FIX       0x2000000
-#define E1000_PCS_LCTL_CRS_ON_NI         0x4000000
-#define E1000_ENABLE_SERDES_LOOPBACK     0x0410
-
-#define E1000_PCS_LSTS_LINK_OK           1
-#define E1000_PCS_LSTS_SPEED_10          0
-#define E1000_PCS_LSTS_SPEED_100         2
-#define E1000_PCS_LSTS_SPEED_1000        4
-#define E1000_PCS_LSTS_DUPLEX_FULL       8
-#define E1000_PCS_LSTS_SYNK_OK           0x10
-#define E1000_PCS_LSTS_AN_COMPLETE       0x10000
-#define E1000_PCS_LSTS_AN_PAGE_RX        0x20000
-#define E1000_PCS_LSTS_AN_TIMED_OUT      0x40000
-#define E1000_PCS_LSTS_AN_REMOTE_FAULT   0x80000
-#define E1000_PCS_LSTS_AN_ERROR_RWS      0x100000
-
-/* Device Status */
-#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
-#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
-#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
-#define E1000_STATUS_FUNC_SHIFT 2
-#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
-#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
-#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
-#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
-#define E1000_STATUS_SPEED_MASK 0x000000C0
-#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
-#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
-#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
-#define E1000_STATUS_LAN_INIT_DONE 0x00000200  /* Lan Init Completion by NVM */
-#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
-#define E1000_STATUS_PHYRA      0x00000400      /* PHY Reset Asserted */
-#define E1000_STATUS_DOCK_CI    0x00000800      /* Change in Dock/Undock state.
-                                                 * Clear on write '0'. */
-#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Master request status */
-#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
-#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
-#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
-#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
-#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
-#define E1000_STATUS_BMC_SKU_0  0x00100000 /* BMC USB redirect disabled */
-#define E1000_STATUS_BMC_SKU_1  0x00200000 /* BMC SRAM disabled */
-#define E1000_STATUS_BMC_SKU_2  0x00400000 /* BMC SDRAM disabled */
-#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
-#define E1000_STATUS_BMC_LITE   0x01000000 /* BMC external code execution
-                                            * disabled */
-#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */
-#define E1000_STATUS_FUSE_8       0x04000000
-#define E1000_STATUS_FUSE_9       0x08000000
-#define E1000_STATUS_SERDES0_DIS  0x10000000 /* SERDES disabled on port 0 */
-#define E1000_STATUS_SERDES1_DIS  0x20000000 /* SERDES disabled on port 1 */
-
-/* Constants used to interpret the masked PCI-X bus speed. */
-#define E1000_STATUS_PCIX_SPEED_66  0x00000000 /* PCI-X bus speed 50-66 MHz */
-#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */
-#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /*PCI-X bus speed 100-133 MHz*/
-
-#define SPEED_10    10
-#define SPEED_100   100
-#define SPEED_1000  1000
-#define HALF_DUPLEX 1
-#define FULL_DUPLEX 2
-
-#define PHY_FORCE_TIME   20
-
-#define ADVERTISE_10_HALF                 0x0001
-#define ADVERTISE_10_FULL                 0x0002
-#define ADVERTISE_100_HALF                0x0004
-#define ADVERTISE_100_FULL                0x0008
-#define ADVERTISE_1000_HALF               0x0010 /* Not used, just FYI */
-#define ADVERTISE_1000_FULL               0x0020
-
-/* 1000/H is not supported, nor spec-compliant. */
-#define E1000_ALL_SPEED_DUPLEX  (ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
-                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL | \
-                                                     ADVERTISE_1000_FULL)
-#define E1000_ALL_NOT_GIG       (ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
-                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
-#define E1000_ALL_100_SPEED    (ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
-#define E1000_ALL_10_SPEED      (ADVERTISE_10_HALF |   ADVERTISE_10_FULL)
-#define E1000_ALL_FULL_DUPLEX   (ADVERTISE_10_FULL |  ADVERTISE_100_FULL | \
-                                                     ADVERTISE_1000_FULL)
-#define E1000_ALL_HALF_DUPLEX   (ADVERTISE_10_HALF |  ADVERTISE_100_HALF)
-
-#define AUTONEG_ADVERTISE_SPEED_DEFAULT   E1000_ALL_SPEED_DUPLEX
-
-/* LED Control */
-#define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
-#define E1000_LEDCTL_LED0_MODE_SHIFT      0
-#define E1000_LEDCTL_LED0_BLINK_RATE      0x00000020
-#define E1000_LEDCTL_LED0_IVRT            0x00000040
-#define E1000_LEDCTL_LED0_BLINK           0x00000080
-#define E1000_LEDCTL_LED1_MODE_MASK       0x00000F00
-#define E1000_LEDCTL_LED1_MODE_SHIFT      8
-#define E1000_LEDCTL_LED1_BLINK_RATE      0x00002000
-#define E1000_LEDCTL_LED1_IVRT            0x00004000
-#define E1000_LEDCTL_LED1_BLINK           0x00008000
-#define E1000_LEDCTL_LED2_MODE_MASK       0x000F0000
-#define E1000_LEDCTL_LED2_MODE_SHIFT      16
-#define E1000_LEDCTL_LED2_BLINK_RATE      0x00200000
-#define E1000_LEDCTL_LED2_IVRT            0x00400000
-#define E1000_LEDCTL_LED2_BLINK           0x00800000
-#define E1000_LEDCTL_LED3_MODE_MASK       0x0F000000
-#define E1000_LEDCTL_LED3_MODE_SHIFT      24
-#define E1000_LEDCTL_LED3_BLINK_RATE      0x20000000
-#define E1000_LEDCTL_LED3_IVRT            0x40000000
-#define E1000_LEDCTL_LED3_BLINK           0x80000000
-
-#define E1000_LEDCTL_MODE_LINK_10_1000  0x0
-#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
-#define E1000_LEDCTL_MODE_LINK_UP       0x2
-#define E1000_LEDCTL_MODE_ACTIVITY      0x3
-#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
-#define E1000_LEDCTL_MODE_LINK_10       0x5
-#define E1000_LEDCTL_MODE_LINK_100      0x6
-#define E1000_LEDCTL_MODE_LINK_1000     0x7
-#define E1000_LEDCTL_MODE_PCIX_MODE     0x8
-#define E1000_LEDCTL_MODE_FULL_DUPLEX   0x9
-#define E1000_LEDCTL_MODE_COLLISION     0xA
-#define E1000_LEDCTL_MODE_BUS_SPEED     0xB
-#define E1000_LEDCTL_MODE_BUS_SIZE      0xC
-#define E1000_LEDCTL_MODE_PAUSED        0xD
-#define E1000_LEDCTL_MODE_LED_ON        0xE
-#define E1000_LEDCTL_MODE_LED_OFF       0xF
-
-/* Transmit Descriptor bit definitions */
-#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
-#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
-#define E1000_TXD_POPTS_SHIFT 8         /* POPTS shift */
-#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
-#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
-#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
-#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
-#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
-#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
-#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
-#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
-#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
-#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
-#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
-#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
-#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
-#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
-#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
-#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
-#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
-#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
-/* Extended desc bits for Linksec and timesync */
-
-/* Transmit Control */
-#define E1000_TCTL_RST    0x00000001    /* software reset */
-#define E1000_TCTL_EN     0x00000002    /* enable tx */
-#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
-#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
-#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
-#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
-#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
-#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
-#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
-#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
-#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
-
-/* Transmit Arbitration Count */
-#define E1000_TARC0_ENABLE     0x00000400   /* Enable Tx Queue 0 */
-
-/* SerDes Control */
-#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
-
-/* Receive Checksum Control */
-#define E1000_RXCSUM_PCSS_MASK 0x000000FF   /* Packet Checksum Start */
-#define E1000_RXCSUM_IPOFL     0x00000100   /* IPv4 checksum offload */
-#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
-#define E1000_RXCSUM_IPV6OFL   0x00000400   /* IPv6 checksum offload */
-#define E1000_RXCSUM_CRCOFL    0x00000800   /* CRC32 offload enable */
-#define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
-#define E1000_RXCSUM_PCSD      0x00002000   /* packet checksum disabled */
-
-/* Header split receive */
-#define E1000_RFCTL_ISCSI_DIS           0x00000001
-#define E1000_RFCTL_ISCSI_DWC_MASK      0x0000003E
-#define E1000_RFCTL_ISCSI_DWC_SHIFT     1
-#define E1000_RFCTL_NFSW_DIS            0x00000040
-#define E1000_RFCTL_NFSR_DIS            0x00000080
-#define E1000_RFCTL_NFS_VER_MASK        0x00000300
-#define E1000_RFCTL_NFS_VER_SHIFT       8
-#define E1000_RFCTL_IPV6_DIS            0x00000400
-#define E1000_RFCTL_IPV6_XSUM_DIS       0x00000800
-#define E1000_RFCTL_ACK_DIS             0x00001000
-#define E1000_RFCTL_ACKD_DIS            0x00002000
-#define E1000_RFCTL_IPFRSP_DIS          0x00004000
-#define E1000_RFCTL_EXTEN               0x00008000
-#define E1000_RFCTL_IPV6_EX_DIS         0x00010000
-#define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
-#define E1000_RFCTL_LEF                 0x00040000
-
-/* Collision related configuration parameters */
-#define E1000_COLLISION_THRESHOLD       15
-#define E1000_CT_SHIFT                  4
-#define E1000_COLLISION_DISTANCE        63
-#define E1000_COLD_SHIFT                12
-
-/* Default values for the transmit IPG register */
-#define DEFAULT_82542_TIPG_IPGT        10
-#define DEFAULT_82543_TIPG_IPGT_FIBER  9
-#define DEFAULT_82543_TIPG_IPGT_COPPER 8
-
-#define E1000_TIPG_IPGT_MASK  0x000003FF
-#define E1000_TIPG_IPGR1_MASK 0x000FFC00
-#define E1000_TIPG_IPGR2_MASK 0x3FF00000
-
-#define DEFAULT_82542_TIPG_IPGR1 2
-#define DEFAULT_82543_TIPG_IPGR1 8
-#define E1000_TIPG_IPGR1_SHIFT  10
-
-#define DEFAULT_82542_TIPG_IPGR2 10
-#define DEFAULT_82543_TIPG_IPGR2 6
-#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
-#define E1000_TIPG_IPGR2_SHIFT  20
-
-/* Ethertype field values */
-#define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
-
-#define ETHERNET_FCS_SIZE       4
-#define MAX_JUMBO_FRAME_SIZE    0x3F00
-
-/* Extended Configuration Control and Size */
-#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP      0x00000020
-#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE       0x00000001
-#define E1000_EXTCNF_CTRL_SWFLAG                 0x00000020
-#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK   0x00FF0000
-#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT          16
-#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK   0x0FFF0000
-#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT          16
-
-#define E1000_PHY_CTRL_SPD_EN             0x00000001
-#define E1000_PHY_CTRL_D0A_LPLU           0x00000002
-#define E1000_PHY_CTRL_NOND0A_LPLU        0x00000004
-#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
-#define E1000_PHY_CTRL_GBE_DISABLE        0x00000040
-
-#define E1000_KABGTXD_BGSQLBIAS           0x00050000
-
-/* PBA constants */
-#define E1000_PBA_6K  0x0006    /* 6KB */
-#define E1000_PBA_8K  0x0008    /* 8KB */
-#define E1000_PBA_10K 0x000A    /* 10KB */
-#define E1000_PBA_12K 0x000C    /* 12KB */
-#define E1000_PBA_14K 0x000E    /* 14KB */
-#define E1000_PBA_16K 0x0010    /* 16KB */
-#define E1000_PBA_18K 0x0012
-#define E1000_PBA_20K 0x0014
-#define E1000_PBA_22K 0x0016
-#define E1000_PBA_24K 0x0018
-#define E1000_PBA_26K 0x001A
-#define E1000_PBA_30K 0x001E
-#define E1000_PBA_32K 0x0020
-#define E1000_PBA_34K 0x0022
-#define E1000_PBA_35K 0x0023
-#define E1000_PBA_38K 0x0026
-#define E1000_PBA_40K 0x0028
-#define E1000_PBA_48K 0x0030    /* 48KB */
-#define E1000_PBA_64K 0x0040    /* 64KB */
-
-#define E1000_PBS_16K E1000_PBA_16K
-#define E1000_PBS_24K E1000_PBA_24K
-
-#define IFS_MAX       80
-#define IFS_MIN       40
-#define IFS_RATIO     4
-#define IFS_STEP      10
-#define MIN_NUM_XMITS 1000
-
-/* SW Semaphore Register */
-#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
-#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
-#define E1000_SWSM_WMNG         0x00000004 /* Wake MNG Clock */
-#define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
-
-#define E1000_SWSM2_LOCK        0x00000002 /* Secondary driver semaphore bit */
-
-/* Interrupt Cause Read */
-#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
-#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
-#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
-#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
-#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
-#define E1000_ICR_RXO           0x00000040 /* rx overrun */
-#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
-#define E1000_ICR_VMMB          0x00000100 /* VM MB event */
-#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
-#define E1000_ICR_RXCFG         0x00000400 /* Rx /c/ ordered set */
-#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
-#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
-#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
-#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
-#define E1000_ICR_TXD_LOW       0x00008000
-#define E1000_ICR_SRPD          0x00010000
-#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
-#define E1000_ICR_MNG           0x00040000 /* Manageability event */
-#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
-#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver
-                                            * should claim the interrupt */
-#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* Q0 Rx desc FIFO parity error */
-#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* Q0 Tx desc FIFO parity error */
-#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity err */
-#define E1000_ICR_PB_PAR        0x00800000 /* packet buffer parity error */
-#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* Q1 Rx desc FIFO parity error */
-#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* Q1 Tx desc FIFO parity error */
-#define E1000_ICR_ALL_PARITY    0x03F00000 /* all parity error bits */
-#define E1000_ICR_DSW           0x00000020 /* FW changed the status of DISSW
-                                            * bit in the FWSM */
-#define E1000_ICR_PHYINT        0x00001000 /* LAN connected device generates
-                                            * an interrupt */
-#define E1000_ICR_DOUTSYNC      0x10000000 /* NIC DMA out of sync */
-#define E1000_ICR_EPRST         0x00100000 /* ME hardware reset occurs */
-
-
-/*
- * This defines the bits that are set in the Interrupt Mask
- * Set/Read Register.  Each bit is documented below:
- *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
- *   o RXSEQ  = Receive Sequence Error
- */
-#define POLL_IMS_ENABLE_MASK ( \
-    E1000_IMS_RXDMT0 |    \
-    E1000_IMS_RXSEQ)
-
-/*
- * This defines the bits that are set in the Interrupt Mask
- * Set/Read Register.  Each bit is documented below:
- *   o RXT0   = Receiver Timer Interrupt (ring 0)
- *   o TXDW   = Transmit Descriptor Written Back
- *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
- *   o RXSEQ  = Receive Sequence Error
- *   o LSC    = Link Status Change
- */
-#define IMS_ENABLE_MASK ( \
-    E1000_IMS_RXT0   |    \
-    E1000_IMS_TXDW   |    \
-    E1000_IMS_RXDMT0 |    \
-    E1000_IMS_RXSEQ  |    \
-    E1000_IMS_LSC)
-
-/* Interrupt Mask Set */
-#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Tx desc written back */
-#define E1000_IMS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
-#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
-#define E1000_IMS_VMMB      E1000_ICR_VMMB      /* Mail box activity */
-#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
-#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
-#define E1000_IMS_RXO       E1000_ICR_RXO       /* rx overrun */
-#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
-#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
-#define E1000_IMS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
-#define E1000_IMS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
-#define E1000_IMS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
-#define E1000_IMS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
-#define E1000_IMS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
-#define E1000_IMS_TXD_LOW   E1000_ICR_TXD_LOW
-#define E1000_IMS_SRPD      E1000_ICR_SRPD
-#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
-#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
-#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
-#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
-                                                         * parity error */
-#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
-                                                         * parity error */
-#define E1000_IMS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer
-                                                         * parity error */
-#define E1000_IMS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity
-                                                         * error */
-#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
-                                                         * parity error */
-#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
-                                                         * parity error */
-#define E1000_IMS_DSW       E1000_ICR_DSW
-#define E1000_IMS_PHYINT    E1000_ICR_PHYINT
-#define E1000_IMS_DOUTSYNC  E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
-#define E1000_IMS_EPRST     E1000_ICR_EPRST
-
-/* Interrupt Cause Set */
-#define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Tx desc written back */
-#define E1000_ICS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
-#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
-#define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
-#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
-#define E1000_ICS_RXO       E1000_ICR_RXO       /* rx overrun */
-#define E1000_ICS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
-#define E1000_ICS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
-#define E1000_ICS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
-#define E1000_ICS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
-#define E1000_ICS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
-#define E1000_ICS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
-#define E1000_ICS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
-#define E1000_ICS_TXD_LOW   E1000_ICR_TXD_LOW
-#define E1000_ICS_SRPD      E1000_ICR_SRPD
-#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
-#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
-#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
-#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
-                                                         * parity error */
-#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
-                                                         * parity error */
-#define E1000_ICS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer
-                                                         * parity error */
-#define E1000_ICS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity
-                                                         * error */
-#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
-                                                         * parity error */
-#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
-                                                         * parity error */
-#define E1000_ICS_DSW       E1000_ICR_DSW
-#define E1000_ICS_DOUTSYNC  E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
-#define E1000_ICS_PHYINT    E1000_ICR_PHYINT
-#define E1000_ICS_EPRST     E1000_ICR_EPRST
-
-/* Transmit Descriptor Control */
-#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
-#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */
-#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
-#define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
-#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
-#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
-#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */
-/* Enable the counting of descriptors still to be processed. */
-#define E1000_TXDCTL_COUNT_DESC 0x00400000
-
-/* Flow Control Constants */
-#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
-#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
-#define FLOW_CONTROL_TYPE         0x8808
-
-/* 802.1q VLAN Packet Size */
-#define VLAN_TAG_SIZE              4    /* 802.3ac tag (not DMA'd) */
-#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
-
-/* Receive Address */
-/*
- * Number of high/low register pairs in the RAR. The RAR (Receive Address
- * Registers) holds the directed and multicast addresses that we monitor.
- * Technically, we have 16 spots.  However, we reserve one of these spots
- * (RAR[15]) for our directed address used by controllers with
- * manageability enabled, allowing us room for 15 multicast addresses.
- */
-#define E1000_RAR_ENTRIES     15
-#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
-#define E1000_RAL_MAC_ADDR_LEN 4
-#define E1000_RAH_MAC_ADDR_LEN 2
-#define E1000_RAH_POOL_MASK 0x03FC0000
-#define E1000_RAH_POOL_1 0x00040000
-
-/* Error Codes */
-#define E1000_SUCCESS      0
-#define E1000_ERR_NVM      1
-#define E1000_ERR_PHY      2
-#define E1000_ERR_CONFIG   3
-#define E1000_ERR_PARAM    4
-#define E1000_ERR_MAC_INIT 5
-#define E1000_ERR_PHY_TYPE 6
-#define E1000_ERR_RESET   9
-#define E1000_ERR_MASTER_REQUESTS_PENDING 10
-#define E1000_ERR_HOST_INTERFACE_COMMAND 11
-#define E1000_BLK_PHY_RESET   12
-#define E1000_ERR_SWFW_SYNC 13
-#define E1000_NOT_IMPLEMENTED 14
-#define E1000_ERR_MBX      15
-
-/* Loop limit on how long we wait for auto-negotiation to complete */
-#define FIBER_LINK_UP_LIMIT               50
-#define COPPER_LINK_UP_LIMIT              10
-#define PHY_AUTO_NEG_LIMIT                45
-#define PHY_FORCE_LIMIT                   20
-/* Number of 100 microseconds we wait for PCI Express master disable */
-#define MASTER_DISABLE_TIMEOUT      800
-/* Number of milliseconds we wait for PHY configuration done after MAC reset */
-#define PHY_CFG_TIMEOUT             100
-/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
-#define MDIO_OWNERSHIP_TIMEOUT      10
-/* Number of milliseconds for NVM auto read done after MAC reset. */
-#define AUTO_READ_DONE_TIMEOUT      10
-
-/* Flow Control */
-#define E1000_FCRTH_RTH  0x0000FFF8     /* Mask Bits[15:3] for RTH */
-#define E1000_FCRTH_XFCE 0x80000000     /* External Flow Control Enable */
-#define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
-#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
-
-/* Transmit Configuration Word */
-#define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
-#define E1000_TXCW_HD         0x00000040        /* TXCW half duplex */
-#define E1000_TXCW_PAUSE      0x00000080        /* TXCW sym pause request */
-#define E1000_TXCW_ASM_DIR    0x00000100        /* TXCW astm pause direction */
-#define E1000_TXCW_PAUSE_MASK 0x00000180        /* TXCW pause request mask */
-#define E1000_TXCW_RF         0x00003000        /* TXCW remote fault */
-#define E1000_TXCW_NP         0x00008000        /* TXCW next page */
-#define E1000_TXCW_CW         0x0000ffff        /* TxConfigWord mask */
-#define E1000_TXCW_TXC        0x40000000        /* Transmit Config control */
-#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
-
-/* Receive Configuration Word */
-#define E1000_RXCW_CW         0x0000ffff        /* RxConfigWord mask */
-#define E1000_RXCW_NC         0x04000000        /* Receive config no carrier */
-#define E1000_RXCW_IV         0x08000000        /* Receive config invalid */
-#define E1000_RXCW_CC         0x10000000        /* Receive config change */
-#define E1000_RXCW_C          0x20000000        /* Receive config */
-#define E1000_RXCW_SYNCH      0x40000000        /* Receive config synch */
-#define E1000_RXCW_ANC        0x80000000        /* Auto-neg complete */
-
-
-/* PCI Express Control */
-#define E1000_GCR_RXD_NO_SNOOP          0x00000001
-#define E1000_GCR_RXDSCW_NO_SNOOP       0x00000002
-#define E1000_GCR_RXDSCR_NO_SNOOP       0x00000004
-#define E1000_GCR_TXD_NO_SNOOP          0x00000008
-#define E1000_GCR_TXDSCW_NO_SNOOP       0x00000010
-#define E1000_GCR_TXDSCR_NO_SNOOP       0x00000020
-#define E1000_GCR_CMPL_TMOUT_MASK       0x0000F000
-#define E1000_GCR_CMPL_TMOUT_10ms       0x00001000
-#define E1000_GCR_CMPL_TMOUT_RESEND     0x00010000
-#define E1000_GCR_CAP_VER2              0x00040000
-
-#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP         | \
-                           E1000_GCR_RXDSCW_NO_SNOOP      | \
-                           E1000_GCR_RXDSCR_NO_SNOOP      | \
-                           E1000_GCR_TXD_NO_SNOOP         | \
-                           E1000_GCR_TXDSCW_NO_SNOOP      | \
-                           E1000_GCR_TXDSCR_NO_SNOOP)
-
-/* PHY Control Register */
-#define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
-#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
-#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
-#define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */
-#define MII_CR_POWER_DOWN       0x0800  /* Power down */
-#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
-#define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
-#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
-#define MII_CR_SPEED_1000       0x0040
-#define MII_CR_SPEED_100        0x2000
-#define MII_CR_SPEED_10         0x0000
-
-/* PHY Status Register */
-#define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */
-#define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */
-#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
-#define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */
-#define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */
-#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
-#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
-#define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */
-#define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */
-#define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */
-#define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */
-#define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */
-#define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */
-#define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */
-#define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */
-
-/* Autoneg Advertisement Register */
-#define NWAY_AR_SELECTOR_FIELD   0x0001   /* indicates IEEE 802.3 CSMA/CD */
-#define NWAY_AR_10T_HD_CAPS      0x0020   /* 10T   Half Duplex Capable */
-#define NWAY_AR_10T_FD_CAPS      0x0040   /* 10T   Full Duplex Capable */
-#define NWAY_AR_100TX_HD_CAPS    0x0080   /* 100TX Half Duplex Capable */
-#define NWAY_AR_100TX_FD_CAPS    0x0100   /* 100TX Full Duplex Capable */
-#define NWAY_AR_100T4_CAPS       0x0200   /* 100T4 Capable */
-#define NWAY_AR_PAUSE            0x0400   /* Pause operation desired */
-#define NWAY_AR_ASM_DIR          0x0800   /* Asymmetric Pause Direction bit */
-#define NWAY_AR_REMOTE_FAULT     0x2000   /* Remote Fault detected */
-#define NWAY_AR_NEXT_PAGE        0x8000   /* Next Page ability supported */
-
-/* Link Partner Ability Register (Base Page) */
-#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
-#define NWAY_LPAR_10T_HD_CAPS    0x0020 /* LP is 10T   Half Duplex Capable */
-#define NWAY_LPAR_10T_FD_CAPS    0x0040 /* LP is 10T   Full Duplex Capable */
-#define NWAY_LPAR_100TX_HD_CAPS  0x0080 /* LP is 100TX Half Duplex Capable */
-#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP is 100TX Full Duplex Capable */
-#define NWAY_LPAR_100T4_CAPS     0x0200 /* LP is 100T4 Capable */
-#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
-#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
-#define NWAY_LPAR_REMOTE_FAULT   0x2000 /* LP has detected Remote Fault */
-#define NWAY_LPAR_ACKNOWLEDGE    0x4000 /* LP has rx'd link code word */
-#define NWAY_LPAR_NEXT_PAGE      0x8000 /* Next Page ability supported */
-
-/* Autoneg Expansion Register */
-#define NWAY_ER_LP_NWAY_CAPS      0x0001 /* LP has Auto Neg Capability */
-#define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */
-#define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */
-#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
-#define NWAY_ER_PAR_DETECT_FAULT  0x0010 /* LP is 100TX Full Duplex Capable */
-
-/* 1000BASE-T Control Register */
-#define CR_1000T_ASYM_PAUSE      0x0080 /* Advertise asymmetric pause bit */
-#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
-#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
-#define CR_1000T_REPEATER_DTE    0x0400 /* 1=Repeater/switch device port */
-                                        /* 0=DTE device */
-#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
-                                        /* 0=Configure PHY as Slave */
-#define CR_1000T_MS_ENABLE      0x1000 /* 1=Master/Slave manual config value */
-                                        /* 0=Automatic Master/Slave config */
-#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
-#define CR_1000T_TEST_MODE_1     0x2000 /* Transmit Waveform test */
-#define CR_1000T_TEST_MODE_2     0x4000 /* Master Transmit Jitter test */
-#define CR_1000T_TEST_MODE_3     0x6000 /* Slave Transmit Jitter test */
-#define CR_1000T_TEST_MODE_4     0x8000 /* Transmitter Distortion test */
-
-/* 1000BASE-T Status Register */
-#define SR_1000T_IDLE_ERROR_CNT   0x00FF /* Num idle errors since last read */
-#define SR_1000T_ASYM_PAUSE_DIR  0x0100 /* LP asymmetric pause direction bit */
-#define SR_1000T_LP_HD_CAPS       0x0400 /* LP is 1000T HD capable */
-#define SR_1000T_LP_FD_CAPS       0x0800 /* LP is 1000T FD capable */
-#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
-#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
-#define SR_1000T_MS_CONFIG_RES    0x4000 /* 1=Local Tx is Master, 0=Slave */
-#define SR_1000T_MS_CONFIG_FAULT  0x8000 /* Master/Slave config fault */
-
-#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5
-
-/* PHY 1000 MII Register/Bit Definitions */
-/* PHY Registers defined by IEEE */
-#define PHY_CONTROL      0x00 /* Control Register */
-#define PHY_STATUS       0x01 /* Status Register */
-#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
-#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
-#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
-#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
-#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
-#define PHY_NEXT_PAGE_TX 0x07 /* Next Page Tx */
-#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
-#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
-#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
-#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
-
-#define PHY_CONTROL_LB   0x4000 /* PHY Loopback bit */
-
-/* NVM Control */
-#define E1000_EECD_SK        0x00000001 /* NVM Clock */
-#define E1000_EECD_CS        0x00000002 /* NVM Chip Select */
-#define E1000_EECD_DI        0x00000004 /* NVM Data In */
-#define E1000_EECD_DO        0x00000008 /* NVM Data Out */
-#define E1000_EECD_FWE_MASK  0x00000030
-#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
-#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
-#define E1000_EECD_FWE_SHIFT 4
-#define E1000_EECD_REQ       0x00000040 /* NVM Access Request */
-#define E1000_EECD_GNT       0x00000080 /* NVM Access Grant */
-#define E1000_EECD_PRES      0x00000100 /* NVM Present */
-#define E1000_EECD_SIZE      0x00000200 /* NVM Size (0=64 word 1=256 word) */
-/* NVM Addressing bits based on type 0=small, 1=large */
-#define E1000_EECD_ADDR_BITS 0x00000400
-#define E1000_EECD_TYPE      0x00002000 /* NVM Type (1-SPI, 0-Microwire) */
-#define E1000_NVM_GRANT_ATTEMPTS   1000 /* NVM # attempts to gain grant */
-#define E1000_EECD_AUTO_RD          0x00000200  /* NVM Auto Read done */
-#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* NVM Size */
-#define E1000_EECD_SIZE_EX_SHIFT     11
-#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
-#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
-#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
-#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
-#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
-#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
-#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
-#define E1000_EECD_SECVAL_SHIFT      22
-#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES)
-
-#define E1000_NVM_SWDPIN0   0x0001   /* SWDPIN 0 NVM Value */
-#define E1000_NVM_LED_LOGIC 0x0020   /* Led Logic Word */
-#define E1000_NVM_RW_REG_DATA   16  /* Offset to data in NVM read/write regs */
-#define E1000_NVM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
-#define E1000_NVM_RW_REG_START  1    /* Start operation */
-#define E1000_NVM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
-#define E1000_NVM_POLL_WRITE    1    /* Flag for polling for write complete */
-#define E1000_NVM_POLL_READ     0    /* Flag for polling for read complete */
-#define E1000_FLASH_UPDATES  2000
-
-/* NVM Word Offsets */
-#define NVM_COMPAT                 0x0003
-#define NVM_ID_LED_SETTINGS        0x0004
-#define NVM_VERSION                0x0005
-#define NVM_SERDES_AMPLITUDE       0x0006 /* SERDES output amplitude */
-#define NVM_PHY_CLASS_WORD         0x0007
-#define NVM_INIT_CONTROL1_REG      0x000A
-#define NVM_INIT_CONTROL2_REG      0x000F
-#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010
-#define NVM_INIT_CONTROL3_PORT_B   0x0014
-#define NVM_INIT_3GIO_3            0x001A
-#define NVM_SWDEF_PINS_CTRL_PORT_0 0x0020
-#define NVM_INIT_CONTROL3_PORT_A   0x0024
-#define NVM_CFG                    0x0012
-#define NVM_FLASH_VERSION          0x0032
-#define NVM_ALT_MAC_ADDR_PTR       0x0037
-#define NVM_CHECKSUM_REG           0x003F
-
-#define E1000_NVM_CFG_DONE_PORT_0  0x040000 /* MNG config cycle done */
-#define E1000_NVM_CFG_DONE_PORT_1  0x080000 /* ...for second port */
-
-/* Mask bits for fields in Word 0x0f of the NVM */
-#define NVM_WORD0F_PAUSE_MASK       0x3000
-#define NVM_WORD0F_PAUSE            0x1000
-#define NVM_WORD0F_ASM_DIR          0x2000
-#define NVM_WORD0F_ANE              0x0800
-#define NVM_WORD0F_SWPDIO_EXT_MASK  0x00F0
-#define NVM_WORD0F_LPLU             0x0001
-
-/* Mask bits for fields in Word 0x1a of the NVM */
-#define NVM_WORD1A_ASPM_MASK  0x000C
-
-/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
-#define NVM_SUM                    0xBABA
-
-#define NVM_MAC_ADDR_OFFSET        0
-#define NVM_PBA_OFFSET_0           8
-#define NVM_PBA_OFFSET_1           9
-#define NVM_RESERVED_WORD          0xFFFF
-#define NVM_PHY_CLASS_A            0x8000
-#define NVM_SERDES_AMPLITUDE_MASK  0x000F
-#define NVM_SIZE_MASK              0x1C00
-#define NVM_SIZE_SHIFT             10
-#define NVM_WORD_SIZE_BASE_SHIFT   6
-#define NVM_SWDPIO_EXT_SHIFT       4
-
-/* NVM Commands - Microwire */
-#define NVM_READ_OPCODE_MICROWIRE  0x6  /* NVM read opcode */
-#define NVM_WRITE_OPCODE_MICROWIRE 0x5  /* NVM write opcode */
-#define NVM_ERASE_OPCODE_MICROWIRE 0x7  /* NVM erase opcode */
-#define NVM_EWEN_OPCODE_MICROWIRE  0x13 /* NVM erase/write enable */
-#define NVM_EWDS_OPCODE_MICROWIRE  0x10 /* NVM erase/write disable */
-
-/* NVM Commands - SPI */
-#define NVM_MAX_RETRY_SPI          5000 /* Max wait of 5ms, for RDY signal */
-#define NVM_READ_OPCODE_SPI        0x03 /* NVM read opcode */
-#define NVM_WRITE_OPCODE_SPI       0x02 /* NVM write opcode */
-#define NVM_A8_OPCODE_SPI          0x08 /* opcode bit-3 = address bit-8 */
-#define NVM_WREN_OPCODE_SPI        0x06 /* NVM set Write Enable latch */
-#define NVM_WRDI_OPCODE_SPI        0x04 /* NVM reset Write Enable latch */
-#define NVM_RDSR_OPCODE_SPI        0x05 /* NVM read Status register */
-#define NVM_WRSR_OPCODE_SPI        0x01 /* NVM write Status register */
-
-/* SPI NVM Status Register */
-#define NVM_STATUS_RDY_SPI         0x01
-#define NVM_STATUS_WEN_SPI         0x02
-#define NVM_STATUS_BP0_SPI         0x04
-#define NVM_STATUS_BP1_SPI         0x08
-#define NVM_STATUS_WPEN_SPI        0x80
-
-/* Word definitions for ID LED Settings */
-#define ID_LED_RESERVED_0000 0x0000
-#define ID_LED_RESERVED_FFFF 0xFFFF
-#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2  << 12) | \
-                              (ID_LED_OFF1_OFF2 <<  8) | \
-                              (ID_LED_DEF1_DEF2 <<  4) | \
-                              (ID_LED_DEF1_DEF2))
-#define ID_LED_DEF1_DEF2     0x1
-#define ID_LED_DEF1_ON2      0x2
-#define ID_LED_DEF1_OFF2     0x3
-#define ID_LED_ON1_DEF2      0x4
-#define ID_LED_ON1_ON2       0x5
-#define ID_LED_ON1_OFF2      0x6
-#define ID_LED_OFF1_DEF2     0x7
-#define ID_LED_OFF1_ON2      0x8
-#define ID_LED_OFF1_OFF2     0x9
-
-#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
-#define IGP_ACTIVITY_LED_ENABLE 0x0300
-#define IGP_LED3_MODE           0x07000000
-
-/* PCI/PCI-X/PCI-EX Config space */
-#define PCIX_COMMAND_REGISTER        0xE6
-#define PCIX_STATUS_REGISTER_LO      0xE8
-#define PCIX_STATUS_REGISTER_HI      0xEA
-#define PCI_HEADER_TYPE_REGISTER     0x0E
-#define PCIE_LINK_STATUS             0x12
-#define PCIE_DEVICE_CONTROL2         0x28
-
-#define PCIX_COMMAND_MMRBC_MASK      0x000C
-#define PCIX_COMMAND_MMRBC_SHIFT     0x2
-#define PCIX_STATUS_HI_MMRBC_MASK    0x0060
-#define PCIX_STATUS_HI_MMRBC_SHIFT   0x5
-#define PCIX_STATUS_HI_MMRBC_4K      0x3
-#define PCIX_STATUS_HI_MMRBC_2K      0x2
-#define PCIX_STATUS_LO_FUNC_MASK     0x7
-#define PCI_HEADER_TYPE_MULTIFUNC    0x80
-#define PCIE_LINK_WIDTH_MASK         0x3F0
-#define PCIE_LINK_WIDTH_SHIFT        4
-#define PCIE_DEVICE_CONTROL2_16ms    0x0005
-
-#ifndef ETH_ADDR_LEN
-#define ETH_ADDR_LEN                 6
-#endif
-
-#define PHY_REVISION_MASK      0xFFFFFFF0
-#define MAX_PHY_REG_ADDRESS    0x1F  /* 5 bit address bus (0-0x1F) */
-#define MAX_PHY_MULTI_PAGE_REG 0xF
-
-/* Bit definitions for valid PHY IDs. */
-/*
- * I = Integrated
- * E = External
- */
-#define M88E1000_E_PHY_ID    0x01410C50
-#define M88E1000_I_PHY_ID    0x01410C30
-#define M88E1011_I_PHY_ID    0x01410C20
-#define IGP01E1000_I_PHY_ID  0x02A80380
-#define M88E1011_I_REV_4     0x04
-#define M88E1111_I_PHY_ID    0x01410CC0
-#define GG82563_E_PHY_ID     0x01410CA0
-#define IGP03E1000_E_PHY_ID  0x02A80390
-#define IFE_E_PHY_ID         0x02A80330
-#define IFE_PLUS_E_PHY_ID    0x02A80320
-#define IFE_C_E_PHY_ID       0x02A80310
-#define M88_VENDOR           0x0141
-
-/* M88E1000 Specific Registers */
-#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
-#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
-#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
-#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
-#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
-#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
-
-#define M88E1000_PHY_EXT_CTRL      0x1A  /* PHY extend control register */
-#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
-#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
-#define M88E1000_PHY_VCO_REG_BIT8  0x100 /* Bits 8 & 11 are adjusted for */
-#define M88E1000_PHY_VCO_REG_BIT11 0x800    /* improved BER performance */
-
-/* M88E1000 PHY Specific Control Register */
-#define M88E1000_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
-#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reverse enabled */
-#define M88E1000_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
-/* 1=CLK125 low, 0=CLK125 toggling */
-#define M88E1000_PSCR_CLK125_DISABLE    0x0010
-#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000 /* MDI Crossover Mode bits 6:5 */
-                                               /* Manual MDI configuration */
-#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
-/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
-#define M88E1000_PSCR_AUTO_X_1000T     0x0040
-/* Auto crossover enabled all speeds */
-#define M88E1000_PSCR_AUTO_X_MODE      0x0060
-/*
- * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold
- * 0=Normal 10BASE-T Rx Threshold
- */
-#define M88E1000_PSCR_EN_10BT_EXT_DIST 0x0080
-/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
-#define M88E1000_PSCR_MII_5BIT_ENABLE      0x0100
-#define M88E1000_PSCR_SCRAMBLER_DISABLE    0x0200 /* 1=Scrambler disable */
-#define M88E1000_PSCR_FORCE_LINK_GOOD      0x0400 /* 1=Force link good */
-#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Tx */
-
-/* M88E1000 PHY Specific Status Register */
-#define M88E1000_PSSR_JABBER             0x0001 /* 1=Jabber */
-#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
-#define M88E1000_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
-#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
-/*
- * 0 = <50M
- * 1 = 50-80M
- * 2 = 80-110M
- * 3 = 110-140M
- * 4 = >140M
- */
-#define M88E1000_PSSR_CABLE_LENGTH       0x0380
-#define M88E1000_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
-#define M88E1000_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
-#define M88E1000_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
-#define M88E1000_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
-#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
-#define M88E1000_PSSR_10MBS              0x0000 /* 00=10Mbs */
-#define M88E1000_PSSR_100MBS             0x4000 /* 01=100Mbs */
-#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
-
-#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
-
-/* M88E1000 Extended PHY Specific Control Register */
-#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
-/*
- * 1 = Lost lock detect enabled.
- * Will assert lost lock and bring
- * link down if idle not seen
- * within 1ms in 1000BASE-T
- */
-#define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000
-/*
- * Number of times we will attempt to autonegotiate before downshifting if we
- * are the master
- */
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X   0x0400
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X   0x0800
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X   0x0C00
-/*
- * Number of times we will attempt to autonegotiate before downshifting if we
- * are the slave
- */
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS   0x0000
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X    0x0200
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X    0x0300
-#define M88E1000_EPSCR_TX_CLK_2_5     0x0060 /* 2.5 MHz TX_CLK */
-#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
-#define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
-
-/* M88EC018 Rev 2 specific DownShift settings */
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK  0x0E00
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X    0x0000
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X    0x0200
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X    0x0400
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X    0x0600
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X    0x0800
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X    0x0A00
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X    0x0C00
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X    0x0E00
-
-/*
- * Bits...
- * 15-5: page
- * 4-0: register offset
- */
-#define GG82563_PAGE_SHIFT        5
-#define GG82563_REG(page, reg)    \
-        (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
-#define GG82563_MIN_ALT_REG       30
-
-/* GG82563 Specific Registers */
-#define GG82563_PHY_SPEC_CTRL           \
-        GG82563_REG(0, 16) /* PHY Specific Control */
-#define GG82563_PHY_SPEC_STATUS         \
-        GG82563_REG(0, 17) /* PHY Specific Status */
-#define GG82563_PHY_INT_ENABLE          \
-        GG82563_REG(0, 18) /* Interrupt Enable */
-#define GG82563_PHY_SPEC_STATUS_2       \
-        GG82563_REG(0, 19) /* PHY Specific Status 2 */
-#define GG82563_PHY_RX_ERR_CNTR         \
-        GG82563_REG(0, 21) /* Receive Error Counter */
-#define GG82563_PHY_PAGE_SELECT         \
-        GG82563_REG(0, 22) /* Page Select */
-#define GG82563_PHY_SPEC_CTRL_2         \
-        GG82563_REG(0, 26) /* PHY Specific Control 2 */
-#define GG82563_PHY_PAGE_SELECT_ALT     \
-        GG82563_REG(0, 29) /* Alternate Page Select */
-#define GG82563_PHY_TEST_CLK_CTRL       \
-        GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */
-
-#define GG82563_PHY_MAC_SPEC_CTRL       \
-        GG82563_REG(2, 21) /* MAC Specific Control Register */
-#define GG82563_PHY_MAC_SPEC_CTRL_2     \
-        GG82563_REG(2, 26) /* MAC Specific Control 2 */
-
-#define GG82563_PHY_DSP_DISTANCE    \
-        GG82563_REG(5, 26) /* DSP Distance */
-
-/* Page 193 - Port Control Registers */
-#define GG82563_PHY_KMRN_MODE_CTRL   \
-        GG82563_REG(193, 16) /* Kumeran Mode Control */
-#define GG82563_PHY_PORT_RESET          \
-        GG82563_REG(193, 17) /* Port Reset */
-#define GG82563_PHY_REVISION_ID         \
-        GG82563_REG(193, 18) /* Revision ID */
-#define GG82563_PHY_DEVICE_ID           \
-        GG82563_REG(193, 19) /* Device ID */
-#define GG82563_PHY_PWR_MGMT_CTRL       \
-        GG82563_REG(193, 20) /* Power Management Control */
-#define GG82563_PHY_RATE_ADAPT_CTRL     \
-        GG82563_REG(193, 25) /* Rate Adaptation Control */
-
-/* Page 194 - KMRN Registers */
-#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \
-        GG82563_REG(194, 16) /* FIFO's Control/Status */
-#define GG82563_PHY_KMRN_CTRL           \
-        GG82563_REG(194, 17) /* Control */
-#define GG82563_PHY_INBAND_CTRL         \
-        GG82563_REG(194, 18) /* Inband Control */
-#define GG82563_PHY_KMRN_DIAGNOSTIC     \
-        GG82563_REG(194, 19) /* Diagnostic */
-#define GG82563_PHY_ACK_TIMEOUTS        \
-        GG82563_REG(194, 20) /* Acknowledge Timeouts */
-#define GG82563_PHY_ADV_ABILITY         \
-        GG82563_REG(194, 21) /* Advertised Ability */
-#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \
-        GG82563_REG(194, 23) /* Link Partner Advertised Ability */
-#define GG82563_PHY_ADV_NEXT_PAGE       \
-        GG82563_REG(194, 24) /* Advertised Next Page */
-#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \
-        GG82563_REG(194, 25) /* Link Partner Advertised Next page */
-#define GG82563_PHY_KMRN_MISC           \
-        GG82563_REG(194, 26) /* Misc. */
-
-/* MDI Control */
-#define E1000_MDIC_DATA_MASK 0x0000FFFF
-#define E1000_MDIC_REG_MASK  0x001F0000
-#define E1000_MDIC_REG_SHIFT 16
-#define E1000_MDIC_PHY_MASK  0x03E00000
-#define E1000_MDIC_PHY_SHIFT 21
-#define E1000_MDIC_OP_WRITE  0x04000000
-#define E1000_MDIC_OP_READ   0x08000000
-#define E1000_MDIC_READY     0x10000000
-#define E1000_MDIC_INT_EN    0x20000000
-#define E1000_MDIC_ERROR     0x40000000
-
-/* SerDes Control */
-#define E1000_GEN_CTL_READY             0x80000000
-#define E1000_GEN_CTL_ADDRESS_SHIFT     8
-#define E1000_GEN_POLL_TIMEOUT          640
-
-
-
-#endif /* _E1000_DEFINES_H_ */
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_hw.h b/roms/ipxe/src/drivers/net/e1000/e1000_hw.h
deleted file mode 100644
index 753f75e7eacc54f127b5cc29c1a56bcfdd92751d..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_hw.h
+++ /dev/null
@@ -1,728 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000_HW_H_
-#define _E1000_HW_H_
-
-#include "e1000_osdep.h"
-#include "e1000_regs.h"
-#include "e1000_defines.h"
-
-struct e1000_hw;
-
-#define E1000_DEV_ID_82542                    0x1000
-#define E1000_DEV_ID_82543GC_FIBER            0x1001
-#define E1000_DEV_ID_82543GC_COPPER           0x1004
-#define E1000_DEV_ID_82544EI_COPPER           0x1008
-#define E1000_DEV_ID_82544EI_FIBER            0x1009
-#define E1000_DEV_ID_82544GC_COPPER           0x100C
-#define E1000_DEV_ID_82544GC_LOM              0x100D
-#define E1000_DEV_ID_82540EM                  0x100E
-#define E1000_DEV_ID_82540EM_LOM              0x1015
-#define E1000_DEV_ID_82540EP_LOM              0x1016
-#define E1000_DEV_ID_82540EP                  0x1017
-#define E1000_DEV_ID_82540EP_LP               0x101E
-#define E1000_DEV_ID_82545EM_COPPER           0x100F
-#define E1000_DEV_ID_82545EM_FIBER            0x1011
-#define E1000_DEV_ID_82545GM_COPPER           0x1026
-#define E1000_DEV_ID_82545GM_FIBER            0x1027
-#define E1000_DEV_ID_82545GM_SERDES           0x1028
-#define E1000_DEV_ID_82546EB_COPPER           0x1010
-#define E1000_DEV_ID_82546EB_FIBER            0x1012
-#define E1000_DEV_ID_82546EB_QUAD_COPPER      0x101D
-#define E1000_DEV_ID_82546GB_COPPER           0x1079
-#define E1000_DEV_ID_82546GB_FIBER            0x107A
-#define E1000_DEV_ID_82546GB_SERDES           0x107B
-#define E1000_DEV_ID_82546GB_PCIE             0x108A
-#define E1000_DEV_ID_82546GB_QUAD_COPPER      0x1099
-#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
-#define E1000_DEV_ID_82541EI                  0x1013
-#define E1000_DEV_ID_82541EI_MOBILE           0x1018
-#define E1000_DEV_ID_82541ER_LOM              0x1014
-#define E1000_DEV_ID_82541ER                  0x1078
-#define E1000_DEV_ID_82541GI                  0x1076
-#define E1000_DEV_ID_82541GI_LF               0x107C
-#define E1000_DEV_ID_82541GI_MOBILE           0x1077
-#define E1000_DEV_ID_82547EI                  0x1019
-#define E1000_DEV_ID_82547EI_MOBILE           0x101A
-#define E1000_DEV_ID_82547GI                  0x1075
-#define E1000_REVISION_0 0
-#define E1000_REVISION_1 1
-#define E1000_REVISION_2 2
-#define E1000_REVISION_3 3
-#define E1000_REVISION_4 4
-
-#define E1000_FUNC_0     0
-#define E1000_FUNC_1     1
-
-#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0   0
-#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1   3
-
-enum e1000_mac_type {
-	e1000_undefined = 0,
-	e1000_82542,
-	e1000_82543,
-	e1000_82544,
-	e1000_82540,
-	e1000_82545,
-	e1000_82545_rev_3,
-	e1000_82546,
-	e1000_82546_rev_3,
-	e1000_82541,
-	e1000_82541_rev_2,
-	e1000_82547,
-	e1000_82547_rev_2,
-	e1000_num_macs  /* List is 1-based, so subtract 1 for true count. */
-};
-
-enum e1000_media_type {
-	e1000_media_type_unknown = 0,
-	e1000_media_type_copper = 1,
-	e1000_media_type_fiber = 2,
-	e1000_media_type_internal_serdes = 3,
-	e1000_num_media_types
-};
-
-enum e1000_nvm_type {
-	e1000_nvm_unknown = 0,
-	e1000_nvm_none,
-	e1000_nvm_eeprom_spi,
-	e1000_nvm_eeprom_microwire,
-	e1000_nvm_flash_hw,
-	e1000_nvm_flash_sw
-};
-
-enum e1000_nvm_override {
-	e1000_nvm_override_none = 0,
-	e1000_nvm_override_spi_small,
-	e1000_nvm_override_spi_large,
-	e1000_nvm_override_microwire_small,
-	e1000_nvm_override_microwire_large
-};
-
-enum e1000_phy_type {
-	e1000_phy_unknown = 0,
-	e1000_phy_none,
-	e1000_phy_m88,
-	e1000_phy_igp,
-	e1000_phy_igp_2,
-	e1000_phy_gg82563,
-	e1000_phy_igp_3,
-	e1000_phy_ife,
-};
-
-enum e1000_bus_type {
-	e1000_bus_type_unknown = 0,
-	e1000_bus_type_pci,
-	e1000_bus_type_pcix,
-	e1000_bus_type_pci_express,
-	e1000_bus_type_reserved
-};
-
-enum e1000_bus_speed {
-	e1000_bus_speed_unknown = 0,
-	e1000_bus_speed_33,
-	e1000_bus_speed_66,
-	e1000_bus_speed_100,
-	e1000_bus_speed_120,
-	e1000_bus_speed_133,
-	e1000_bus_speed_2500,
-	e1000_bus_speed_5000,
-	e1000_bus_speed_reserved
-};
-
-enum e1000_bus_width {
-	e1000_bus_width_unknown = 0,
-	e1000_bus_width_pcie_x1,
-	e1000_bus_width_pcie_x2,
-	e1000_bus_width_pcie_x4 = 4,
-	e1000_bus_width_pcie_x8 = 8,
-	e1000_bus_width_32,
-	e1000_bus_width_64,
-	e1000_bus_width_reserved
-};
-
-enum e1000_1000t_rx_status {
-	e1000_1000t_rx_status_not_ok = 0,
-	e1000_1000t_rx_status_ok,
-	e1000_1000t_rx_status_undefined = 0xFF
-};
-
-enum e1000_rev_polarity {
-	e1000_rev_polarity_normal = 0,
-	e1000_rev_polarity_reversed,
-	e1000_rev_polarity_undefined = 0xFF
-};
-
-enum e1000_fc_mode {
-	e1000_fc_none = 0,
-	e1000_fc_rx_pause,
-	e1000_fc_tx_pause,
-	e1000_fc_full,
-	e1000_fc_default = 0xFF
-};
-
-enum e1000_ffe_config {
-	e1000_ffe_config_enabled = 0,
-	e1000_ffe_config_active,
-	e1000_ffe_config_blocked
-};
-
-enum e1000_dsp_config {
-	e1000_dsp_config_disabled = 0,
-	e1000_dsp_config_enabled,
-	e1000_dsp_config_activated,
-	e1000_dsp_config_undefined = 0xFF
-};
-
-enum e1000_ms_type {
-	e1000_ms_hw_default = 0,
-	e1000_ms_force_master,
-	e1000_ms_force_slave,
-	e1000_ms_auto
-};
-
-enum e1000_smart_speed {
-	e1000_smart_speed_default = 0,
-	e1000_smart_speed_on,
-	e1000_smart_speed_off
-};
-
-enum e1000_serdes_link_state {
-	e1000_serdes_link_down = 0,
-	e1000_serdes_link_autoneg_progress,
-	e1000_serdes_link_autoneg_complete,
-	e1000_serdes_link_forced_up
-};
-
-/* Receive Descriptor */
-struct e1000_rx_desc {
-	__le64 buffer_addr; /* Address of the descriptor's data buffer */
-	__le16 length;      /* Length of data DMAed into data buffer */
-	__le16 csum;        /* Packet checksum */
-	u8  status;         /* Descriptor status */
-	u8  errors;         /* Descriptor Errors */
-	__le16 special;
-};
-
-/* Receive Descriptor - Extended */
-union e1000_rx_desc_extended {
-	struct {
-		__le64 buffer_addr;
-		__le64 reserved;
-	} read;
-	struct {
-		struct {
-			__le32 mrq;           /* Multiple Rx Queues */
-			union {
-				__le32 rss;         /* RSS Hash */
-				struct {
-					__le16 ip_id;  /* IP id */
-					__le16 csum;   /* Packet Checksum */
-				} csum_ip;
-			} hi_dword;
-		} lower;
-		struct {
-			__le32 status_error;  /* ext status/error */
-			__le16 length;
-			__le16 vlan;          /* VLAN tag */
-		} upper;
-	} wb;  /* writeback */
-};
-
-#define MAX_PS_BUFFERS 4
-/* Receive Descriptor - Packet Split */
-union e1000_rx_desc_packet_split {
-	struct {
-		/* one buffer for protocol header(s), three data buffers */
-		__le64 buffer_addr[MAX_PS_BUFFERS];
-	} read;
-	struct {
-		struct {
-			__le32 mrq;           /* Multiple Rx Queues */
-			union {
-				__le32 rss;           /* RSS Hash */
-				struct {
-					__le16 ip_id;    /* IP id */
-					__le16 csum;     /* Packet Checksum */
-				} csum_ip;
-			} hi_dword;
-		} lower;
-		struct {
-			__le32 status_error;  /* ext status/error */
-			__le16 length0;       /* length of buffer 0 */
-			__le16 vlan;          /* VLAN tag */
-		} middle;
-		struct {
-			__le16 header_status;
-			__le16 length[3];     /* length of buffers 1-3 */
-		} upper;
-		__le64 reserved;
-	} wb; /* writeback */
-};
-
-/* Transmit Descriptor */
-struct e1000_tx_desc {
-	__le64 buffer_addr;   /* Address of the descriptor's data buffer */
-	union {
-		__le32 data;
-		struct {
-			__le16 length;    /* Data buffer length */
-			u8 cso;           /* Checksum offset */
-			u8 cmd;           /* Descriptor control */
-		} flags;
-	} lower;
-	union {
-		__le32 data;
-		struct {
-			u8 status;        /* Descriptor status */
-			u8 css;           /* Checksum start */
-			__le16 special;
-		} fields;
-	} upper;
-};
-
-/* Offload Context Descriptor */
-struct e1000_context_desc {
-	union {
-		__le32 ip_config;
-		struct {
-			u8 ipcss;         /* IP checksum start */
-			u8 ipcso;         /* IP checksum offset */
-			__le16 ipcse;     /* IP checksum end */
-		} ip_fields;
-	} lower_setup;
-	union {
-		__le32 tcp_config;
-		struct {
-			u8 tucss;         /* TCP checksum start */
-			u8 tucso;         /* TCP checksum offset */
-			__le16 tucse;     /* TCP checksum end */
-		} tcp_fields;
-	} upper_setup;
-	__le32 cmd_and_length;
-	union {
-		__le32 data;
-		struct {
-			u8 status;        /* Descriptor status */
-			u8 hdr_len;       /* Header length */
-			__le16 mss;       /* Maximum segment size */
-		} fields;
-	} tcp_seg_setup;
-};
-
-/* Offload data descriptor */
-struct e1000_data_desc {
-	__le64 buffer_addr;   /* Address of the descriptor's buffer address */
-	union {
-		__le32 data;
-		struct {
-			__le16 length;    /* Data buffer length */
-			u8 typ_len_ext;
-			u8 cmd;
-		} flags;
-	} lower;
-	union {
-		__le32 data;
-		struct {
-			u8 status;        /* Descriptor status */
-			u8 popts;         /* Packet Options */
-			__le16 special;
-		} fields;
-	} upper;
-};
-
-/* Statistics counters collected by the MAC */
-struct e1000_hw_stats {
-	u64 crcerrs;
-	u64 algnerrc;
-	u64 symerrs;
-	u64 rxerrc;
-	u64 mpc;
-	u64 scc;
-	u64 ecol;
-	u64 mcc;
-	u64 latecol;
-	u64 colc;
-	u64 dc;
-	u64 tncrs;
-	u64 sec;
-	u64 cexterr;
-	u64 rlec;
-	u64 xonrxc;
-	u64 xontxc;
-	u64 xoffrxc;
-	u64 xofftxc;
-	u64 fcruc;
-	u64 prc64;
-	u64 prc127;
-	u64 prc255;
-	u64 prc511;
-	u64 prc1023;
-	u64 prc1522;
-	u64 gprc;
-	u64 bprc;
-	u64 mprc;
-	u64 gptc;
-	u64 gorc;
-	u64 gotc;
-	u64 rnbc;
-	u64 ruc;
-	u64 rfc;
-	u64 roc;
-	u64 rjc;
-	u64 mgprc;
-	u64 mgpdc;
-	u64 mgptc;
-	u64 tor;
-	u64 tot;
-	u64 tpr;
-	u64 tpt;
-	u64 ptc64;
-	u64 ptc127;
-	u64 ptc255;
-	u64 ptc511;
-	u64 ptc1023;
-	u64 ptc1522;
-	u64 mptc;
-	u64 bptc;
-	u64 tsctc;
-	u64 tsctfc;
-	u64 iac;
-	u64 icrxptc;
-	u64 icrxatc;
-	u64 ictxptc;
-	u64 ictxatc;
-	u64 ictxqec;
-	u64 ictxqmtc;
-	u64 icrxdmtc;
-	u64 icrxoc;
-	u64 cbtmpc;
-	u64 htdpmc;
-	u64 cbrdpc;
-	u64 cbrmpc;
-	u64 rpthc;
-	u64 hgptc;
-	u64 htcbdpc;
-	u64 hgorc;
-	u64 hgotc;
-	u64 lenerrs;
-	u64 scvpc;
-	u64 hrmpc;
-	u64 doosync;
-};
-
-
-struct e1000_phy_stats {
-	u32 idle_errors;
-	u32 receive_errors;
-};
-
-struct e1000_host_mng_dhcp_cookie {
-	u32 signature;
-	u8  status;
-	u8  reserved0;
-	u16 vlan_id;
-	u32 reserved1;
-	u16 reserved2;
-	u8  reserved3;
-	u8  checksum;
-};
-
-/* Host Interface "Rev 1" */
-struct e1000_host_command_header {
-	u8 command_id;
-	u8 command_length;
-	u8 command_options;
-	u8 checksum;
-};
-
-#define E1000_HI_MAX_DATA_LENGTH     252
-struct e1000_host_command_info {
-	struct e1000_host_command_header command_header;
-	u8 command_data[E1000_HI_MAX_DATA_LENGTH];
-};
-
-/* Host Interface "Rev 2" */
-struct e1000_host_mng_command_header {
-	u8  command_id;
-	u8  checksum;
-	u16 reserved1;
-	u16 reserved2;
-	u16 command_length;
-};
-
-#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
-struct e1000_host_mng_command_info {
-	struct e1000_host_mng_command_header command_header;
-	u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
-};
-
-#include "e1000_mac.h"
-#include "e1000_phy.h"
-#include "e1000_nvm.h"
-#include "e1000_manage.h"
-
-struct e1000_mac_operations {
-	/* Function pointers for the MAC. */
-	s32  (*init_params)(struct e1000_hw *);
-	s32  (*id_led_init)(struct e1000_hw *);
-	s32  (*blink_led)(struct e1000_hw *);
-	s32  (*check_for_link)(struct e1000_hw *);
-	bool (*check_mng_mode)(struct e1000_hw *hw);
-	s32  (*cleanup_led)(struct e1000_hw *);
-	void (*clear_hw_cntrs)(struct e1000_hw *);
-	void (*clear_vfta)(struct e1000_hw *);
-	s32  (*get_bus_info)(struct e1000_hw *);
-	void (*set_lan_id)(struct e1000_hw *);
-	s32  (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
-	s32  (*led_on)(struct e1000_hw *);
-	s32  (*led_off)(struct e1000_hw *);
-	void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32);
-	s32  (*reset_hw)(struct e1000_hw *);
-	s32  (*init_hw)(struct e1000_hw *);
-	s32  (*setup_link)(struct e1000_hw *);
-	s32  (*setup_physical_interface)(struct e1000_hw *);
-	s32  (*setup_led)(struct e1000_hw *);
-	void (*write_vfta)(struct e1000_hw *, u32, u32);
-	void (*mta_set)(struct e1000_hw *, u32);
-	void (*config_collision_dist)(struct e1000_hw *);
-	void (*rar_set)(struct e1000_hw *, u8*, u32);
-	s32  (*read_mac_addr)(struct e1000_hw *);
-	s32  (*validate_mdi_setting)(struct e1000_hw *);
-	s32  (*mng_host_if_write)(struct e1000_hw *, u8*, u16, u16, u8*);
-	s32  (*mng_write_cmd_header)(struct e1000_hw *hw,
-                      struct e1000_host_mng_command_header*);
-	s32  (*mng_enable_host_if)(struct e1000_hw *);
-	s32  (*wait_autoneg)(struct e1000_hw *);
-};
-
-struct e1000_phy_operations {
-	s32  (*init_params)(struct e1000_hw *);
-	s32  (*acquire)(struct e1000_hw *);
-	s32  (*check_polarity)(struct e1000_hw *);
-	s32  (*check_reset_block)(struct e1000_hw *);
-	s32  (*commit)(struct e1000_hw *);
-#if 0
-	s32  (*force_speed_duplex)(struct e1000_hw *);
-#endif
-	s32  (*get_cfg_done)(struct e1000_hw *hw);
-#if 0
-	s32  (*get_cable_length)(struct e1000_hw *);
-#endif
-	s32  (*get_info)(struct e1000_hw *);
-	s32  (*read_reg)(struct e1000_hw *, u32, u16 *);
-	void (*release)(struct e1000_hw *);
-	s32  (*reset)(struct e1000_hw *);
-	s32  (*set_d0_lplu_state)(struct e1000_hw *, bool);
-	s32  (*set_d3_lplu_state)(struct e1000_hw *, bool);
-	s32  (*write_reg)(struct e1000_hw *, u32, u16);
-	void (*power_up)(struct e1000_hw *);
-	void (*power_down)(struct e1000_hw *);
-};
-
-struct e1000_nvm_operations {
-	s32  (*init_params)(struct e1000_hw *);
-	s32  (*acquire)(struct e1000_hw *);
-	s32  (*read)(struct e1000_hw *, u16, u16, u16 *);
-	void (*release)(struct e1000_hw *);
-	void (*reload)(struct e1000_hw *);
-	s32  (*update)(struct e1000_hw *);
-	s32  (*valid_led_default)(struct e1000_hw *, u16 *);
-	s32  (*validate)(struct e1000_hw *);
-	s32  (*write)(struct e1000_hw *, u16, u16, u16 *);
-};
-
-struct e1000_mac_info {
-	struct e1000_mac_operations ops;
-	u8 addr[6];
-	u8 perm_addr[6];
-
-	enum e1000_mac_type type;
-
-	u32 collision_delta;
-	u32 ledctl_default;
-	u32 ledctl_mode1;
-	u32 ledctl_mode2;
-	u32 mc_filter_type;
-	u32 tx_packet_delta;
-	u32 txcw;
-
-	u16 current_ifs_val;
-	u16 ifs_max_val;
-	u16 ifs_min_val;
-	u16 ifs_ratio;
-	u16 ifs_step_size;
-	u16 mta_reg_count;
-
-	/* Maximum size of the MTA register table in all supported adapters */
-	#define MAX_MTA_REG 128
-	u32 mta_shadow[MAX_MTA_REG];
-	u16 rar_entry_count;
-
-	u8  forced_speed_duplex;
-
-	bool adaptive_ifs;
-	bool arc_subsystem_valid;
-	bool asf_firmware_present;
-	bool autoneg;
-	bool autoneg_failed;
-	bool get_link_status;
-	bool in_ifs_mode;
-	bool report_tx_early;
-	enum e1000_serdes_link_state serdes_link_state;
-	bool serdes_has_link;
-	bool tx_pkt_filtering;
-};
-
-struct e1000_phy_info {
-	struct e1000_phy_operations ops;
-	enum e1000_phy_type type;
-
-	enum e1000_1000t_rx_status local_rx;
-	enum e1000_1000t_rx_status remote_rx;
-	enum e1000_ms_type ms_type;
-	enum e1000_ms_type original_ms_type;
-	enum e1000_rev_polarity cable_polarity;
-	enum e1000_smart_speed smart_speed;
-
-	u32 addr;
-	u32 id;
-	u32 reset_delay_us; /* in usec */
-	u32 revision;
-
-	enum e1000_media_type media_type;
-
-	u16 autoneg_advertised;
-	u16 autoneg_mask;
-	u16 cable_length;
-	u16 max_cable_length;
-	u16 min_cable_length;
-
-	u8 mdix;
-
-	bool disable_polarity_correction;
-	bool is_mdix;
-	bool polarity_correction;
-	bool reset_disable;
-	bool speed_downgraded;
-	bool autoneg_wait_to_complete;
-};
-
-struct e1000_nvm_info {
-	struct e1000_nvm_operations ops;
-	enum e1000_nvm_type type;
-	enum e1000_nvm_override override;
-
-	u32 flash_bank_size;
-	u32 flash_base_addr;
-
-	u16 word_size;
-	u16 delay_usec;
-	u16 address_bits;
-	u16 opcode_bits;
-	u16 page_size;
-};
-
-struct e1000_bus_info {
-	enum e1000_bus_type type;
-	enum e1000_bus_speed speed;
-	enum e1000_bus_width width;
-
-	u16 func;
-	u16 pci_cmd_word;
-};
-
-struct e1000_fc_info {
-	u32 high_water;          /* Flow control high-water mark */
-	u32 low_water;           /* Flow control low-water mark */
-	u16 pause_time;          /* Flow control pause timer */
-	bool send_xon;           /* Flow control send XON */
-	bool strict_ieee;        /* Strict IEEE mode */
-	enum e1000_fc_mode current_mode; /* FC mode in effect */
-	enum e1000_fc_mode requested_mode; /* FC mode requested by caller */
-};
-
-struct e1000_dev_spec_82541 {
-	enum e1000_dsp_config dsp_config;
-	enum e1000_ffe_config ffe_config;
-	u16 spd_default;
-	bool phy_init_script;
-};
-
-struct e1000_dev_spec_82542 {
-	bool dma_fairness;
-};
-
-struct e1000_dev_spec_82543 {
-	u32  tbi_compatibility;
-	bool dma_fairness;
-	bool init_phy_disabled;
-};
-
-struct e1000_hw {
-	void *back;
-
-	u8 __iomem *hw_addr;
-	u8 __iomem *flash_address;
-	unsigned long io_base;
-
-	struct e1000_mac_info  mac;
-	struct e1000_fc_info   fc;
-	struct e1000_phy_info  phy;
-	struct e1000_nvm_info  nvm;
-	struct e1000_bus_info  bus;
-	struct e1000_host_mng_dhcp_cookie mng_cookie;
-
-	union {
-		struct e1000_dev_spec_82541	_82541;
-		struct e1000_dev_spec_82542	_82542;
-		struct e1000_dev_spec_82543	_82543;
-	} dev_spec;
-
-	u16 device_id;
-	u16 subsystem_vendor_id;
-	u16 subsystem_device_id;
-	u16 vendor_id;
-
-	u8  revision_id;
-};
-
-#include "e1000_82541.h"
-#include "e1000_82543.h"
-
-/* These functions must be implemented by drivers */
-void e1000_pci_clear_mwi(struct e1000_hw *hw);
-void e1000_pci_set_mwi(struct e1000_hw *hw);
-s32  e1000_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
-void e1000_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value);
-void e1000_write_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value);
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_mac.c b/roms/ipxe/src/drivers/net/e1000/e1000_mac.c
deleted file mode 100644
index 235138798168d1fc24dddc14c9de61ad27b0da75..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_mac.c
+++ /dev/null
@@ -1,2196 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include "e1000_api.h"
-
-static s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw);
-static void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
-
-/**
- *  e1000_init_mac_ops_generic - Initialize MAC function pointers
- *  @hw: pointer to the HW structure
- *
- *  Setups up the function pointers to no-op functions
- **/
-void e1000_init_mac_ops_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	DEBUGFUNC("e1000_init_mac_ops_generic");
-
-	/* General Setup */
-	mac->ops.init_params = e1000_null_ops_generic;
-	mac->ops.init_hw = e1000_null_ops_generic;
-	mac->ops.reset_hw = e1000_null_ops_generic;
-	mac->ops.setup_physical_interface = e1000_null_ops_generic;
-	mac->ops.get_bus_info = e1000_null_ops_generic;
-	mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pcie;
-	mac->ops.read_mac_addr = e1000_read_mac_addr_generic;
-	mac->ops.config_collision_dist = e1000_config_collision_dist_generic;
-	mac->ops.clear_hw_cntrs = e1000_null_mac_generic;
-	/* LED */
-	mac->ops.cleanup_led = e1000_null_ops_generic;
-	mac->ops.setup_led = e1000_null_ops_generic;
-	mac->ops.blink_led = e1000_null_ops_generic;
-	mac->ops.led_on = e1000_null_ops_generic;
-	mac->ops.led_off = e1000_null_ops_generic;
-	/* LINK */
-	mac->ops.setup_link = e1000_null_ops_generic;
-	mac->ops.get_link_up_info = e1000_null_link_info;
-	mac->ops.check_for_link = e1000_null_ops_generic;
-	mac->ops.wait_autoneg = e1000_wait_autoneg_generic;
-#if 0
-	/* Management */
-	mac->ops.check_mng_mode = e1000_null_mng_mode;
-	mac->ops.mng_host_if_write = e1000_mng_host_if_write_generic;
-	mac->ops.mng_write_cmd_header = e1000_mng_write_cmd_header_generic;
-	mac->ops.mng_enable_host_if = e1000_mng_enable_host_if_generic;
-#endif
-	/* VLAN, MC, etc. */
-	mac->ops.update_mc_addr_list = e1000_null_update_mc;
-	mac->ops.clear_vfta = e1000_null_mac_generic;
-	mac->ops.write_vfta = e1000_null_write_vfta;
-	mac->ops.mta_set = e1000_null_mta_set;
-	mac->ops.rar_set = e1000_rar_set_generic;
-	mac->ops.validate_mdi_setting = e1000_validate_mdi_setting_generic;
-}
-
-/**
- *  e1000_null_ops_generic - No-op function, returns 0
- *  @hw: pointer to the HW structure
- **/
-s32 e1000_null_ops_generic(struct e1000_hw *hw __unused)
-{
-	DEBUGFUNC("e1000_null_ops_generic");
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_null_mac_generic - No-op function, return void
- *  @hw: pointer to the HW structure
- **/
-void e1000_null_mac_generic(struct e1000_hw *hw __unused)
-{
-	DEBUGFUNC("e1000_null_mac_generic");
-	return;
-}
-
-/**
- *  e1000_null_link_info - No-op function, return 0
- *  @hw: pointer to the HW structure
- **/
-s32 e1000_null_link_info(struct e1000_hw *hw __unused,
-                         u16 *s __unused, u16 *d __unused)
-{
-	DEBUGFUNC("e1000_null_link_info");
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_null_mng_mode - No-op function, return false
- *  @hw: pointer to the HW structure
- **/
-bool e1000_null_mng_mode(struct e1000_hw *hw __unused)
-{
-	DEBUGFUNC("e1000_null_mng_mode");
-	return false;
-}
-
-/**
- *  e1000_null_update_mc - No-op function, return void
- *  @hw: pointer to the HW structure
- **/
-void e1000_null_update_mc(struct e1000_hw *hw __unused,
-                          u8 *h __unused, u32 a __unused)
-{
-	DEBUGFUNC("e1000_null_update_mc");
-	return;
-}
-
-/**
- *  e1000_null_write_vfta - No-op function, return void
- *  @hw: pointer to the HW structure
- **/
-void e1000_null_write_vfta(struct e1000_hw *hw __unused,
-                           u32 a __unused, u32 b __unused)
-{
-	DEBUGFUNC("e1000_null_write_vfta");
-	return;
-}
-
-/**
- *  e1000_null_set_mta - No-op function, return void
- *  @hw: pointer to the HW structure
- **/
-void e1000_null_mta_set(struct e1000_hw *hw __unused, u32 a __unused)
-{
-	DEBUGFUNC("e1000_null_mta_set");
-	return;
-}
-
-/**
- *  e1000_null_rar_set - No-op function, return void
- *  @hw: pointer to the HW structure
- **/
-void e1000_null_rar_set(struct e1000_hw *hw __unused, u8 *h __unused,
-                        u32 a __unused)
-{
-	DEBUGFUNC("e1000_null_rar_set");
-	return;
-}
-
-/**
- *  e1000_get_bus_info_pci_generic - Get PCI(x) bus information
- *  @hw: pointer to the HW structure
- *
- *  Determines and stores the system bus information for a particular
- *  network interface.  The following bus information is determined and stored:
- *  bus speed, bus width, type (PCI/PCIx), and PCI(-x) function.
- **/
-s32 e1000_get_bus_info_pci_generic(struct e1000_hw *hw __unused)
-{
-#if 0
-	struct e1000_mac_info *mac = &hw->mac;
-	struct e1000_bus_info *bus = &hw->bus;
-	u32 status = E1000_READ_REG(hw, E1000_STATUS);
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_get_bus_info_pci_generic");
-
-	/* PCI or PCI-X? */
-	bus->type = (status & E1000_STATUS_PCIX_MODE)
-			? e1000_bus_type_pcix
-			: e1000_bus_type_pci;
-
-	/* Bus speed */
-	if (bus->type == e1000_bus_type_pci) {
-		bus->speed = (status & E1000_STATUS_PCI66)
-		             ? e1000_bus_speed_66
-		             : e1000_bus_speed_33;
-	} else {
-		switch (status & E1000_STATUS_PCIX_SPEED) {
-		case E1000_STATUS_PCIX_SPEED_66:
-			bus->speed = e1000_bus_speed_66;
-			break;
-		case E1000_STATUS_PCIX_SPEED_100:
-			bus->speed = e1000_bus_speed_100;
-			break;
-		case E1000_STATUS_PCIX_SPEED_133:
-			bus->speed = e1000_bus_speed_133;
-			break;
-		default:
-			bus->speed = e1000_bus_speed_reserved;
-			break;
-		}
-	}
-
-	/* Bus width */
-	bus->width = (status & E1000_STATUS_BUS64)
-	             ? e1000_bus_width_64
-	             : e1000_bus_width_32;
-
-	/* Which PCI(-X) function? */
-	mac->ops.set_lan_id(hw);
-
-	return ret_val;
-#endif
-	return 0;
-}
-
-/**
- *  e1000_get_bus_info_pcie_generic - Get PCIe bus information
- *  @hw: pointer to the HW structure
- *
- *  Determines and stores the system bus information for a particular
- *  network interface.  The following bus information is determined and stored:
- *  bus speed, bus width, type (PCIe), and PCIe function.
- **/
-s32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw __unused)
-{
-#if 0
-	struct e1000_mac_info *mac = &hw->mac;
-	struct e1000_bus_info *bus = &hw->bus;
-
-	s32 ret_val;
-	u16 pcie_link_status;
-
-	DEBUGFUNC("e1000_get_bus_info_pcie_generic");
-
-	bus->type = e1000_bus_type_pci_express;
-	bus->speed = e1000_bus_speed_2500;
-
-	ret_val = e1000_read_pcie_cap_reg(hw,
-	                                  PCIE_LINK_STATUS,
-	                                  &pcie_link_status);
-	if (ret_val)
-		bus->width = e1000_bus_width_unknown;
-	else
-		bus->width = (enum e1000_bus_width)((pcie_link_status &
-		                                PCIE_LINK_WIDTH_MASK) >>
-		                               PCIE_LINK_WIDTH_SHIFT);
-
-	mac->ops.set_lan_id(hw);
-
-	return E1000_SUCCESS;
-#endif
-	return 0;
-}
-
-/**
- *  e1000_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices
- *
- *  @hw: pointer to the HW structure
- *
- *  Determines the LAN function id by reading memory-mapped registers
- *  and swaps the port value if requested.
- **/
-static void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw)
-{
-	struct e1000_bus_info *bus = &hw->bus;
-	u32 reg;
-
-	/*
-	 * The status register reports the correct function number
-	 * for the device regardless of function swap state.
-	 */
-	reg = E1000_READ_REG(hw, E1000_STATUS);
-	bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
-}
-
-/**
- *  e1000_set_lan_id_multi_port_pci - Set LAN id for PCI multiple port devices
- *  @hw: pointer to the HW structure
- *
- *  Determines the LAN function id by reading PCI config space.
- **/
-void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw)
-{
-	struct e1000_bus_info *bus = &hw->bus;
-	u16 pci_header_type;
-	u32 status;
-
-	e1000_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type);
-	if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
-		status = E1000_READ_REG(hw, E1000_STATUS);
-		bus->func = (status & E1000_STATUS_FUNC_MASK)
-		            >> E1000_STATUS_FUNC_SHIFT;
-	} else {
-		bus->func = 0;
-	}
-}
-
-/**
- *  e1000_set_lan_id_single_port - Set LAN id for a single port device
- *  @hw: pointer to the HW structure
- *
- *  Sets the LAN function id to zero for a single port device.
- **/
-void e1000_set_lan_id_single_port(struct e1000_hw *hw)
-{
-	struct e1000_bus_info *bus = &hw->bus;
-
-	bus->func = 0;
-}
-
-/**
- *  e1000_clear_vfta_generic - Clear VLAN filter table
- *  @hw: pointer to the HW structure
- *
- *  Clears the register array which contains the VLAN filter table by
- *  setting all the values to 0.
- **/
-void e1000_clear_vfta_generic(struct e1000_hw *hw)
-{
-	u32 offset;
-
-	DEBUGFUNC("e1000_clear_vfta_generic");
-
-	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
-		E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0);
-		E1000_WRITE_FLUSH(hw);
-	}
-}
-
-/**
- *  e1000_write_vfta_generic - Write value to VLAN filter table
- *  @hw: pointer to the HW structure
- *  @offset: register offset in VLAN filter table
- *  @value: register value written to VLAN filter table
- *
- *  Writes value at the given offset in the register array which stores
- *  the VLAN filter table.
- **/
-void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value)
-{
-	DEBUGFUNC("e1000_write_vfta_generic");
-
-	E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
-	E1000_WRITE_FLUSH(hw);
-}
-
-/**
- *  e1000_init_rx_addrs_generic - Initialize receive address's
- *  @hw: pointer to the HW structure
- *  @rar_count: receive address registers
- *
- *  Setups the receive address registers by setting the base receive address
- *  register to the devices MAC address and clearing all the other receive
- *  address registers to 0.
- **/
-void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count)
-{
-	u32 i;
-	u8 mac_addr[ETH_ADDR_LEN] = {0};
-
-	DEBUGFUNC("e1000_init_rx_addrs_generic");
-
-	/* Setup the receive address */
-	DEBUGOUT("Programming MAC Address into RAR[0]\n");
-
-	hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
-
-	/* Zero out the other (rar_entry_count - 1) receive addresses */
-	DEBUGOUT1("Clearing RAR[1-%u]\n", rar_count-1);
-	for (i = 1; i < rar_count; i++)
-		hw->mac.ops.rar_set(hw, mac_addr, i);
-}
-
-/**
- *  e1000_check_alt_mac_addr_generic - Check for alternate MAC addr
- *  @hw: pointer to the HW structure
- *
- *  Checks the nvm for an alternate MAC address.  An alternate MAC address
- *  can be setup by pre-boot software and must be treated like a permanent
- *  address and must override the actual permanent MAC address. If an
- *  alternate MAC address is found it is programmed into RAR0, replacing
- *  the permanent address that was installed into RAR0 by the Si on reset.
- *  This function will return SUCCESS unless it encounters an error while
- *  reading the EEPROM.
- **/
-s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw)
-{
-	u32 i;
-	s32 ret_val = E1000_SUCCESS;
-	u16 offset, nvm_alt_mac_addr_offset, nvm_data;
-	u8 alt_mac_addr[ETH_ADDR_LEN];
-
-	DEBUGFUNC("e1000_check_alt_mac_addr_generic");
-
-	ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1,
-	                         &nvm_alt_mac_addr_offset);
-	if (ret_val) {
-		DEBUGOUT("NVM Read Error\n");
-		goto out;
-	}
-
-	if (nvm_alt_mac_addr_offset == 0xFFFF) {
-		/* There is no Alternate MAC Address */
-		goto out;
-	}
-
-	if (hw->bus.func == E1000_FUNC_1)
-		nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
-	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
-		offset = nvm_alt_mac_addr_offset + (i >> 1);
-		ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
-		if (ret_val) {
-			DEBUGOUT("NVM Read Error\n");
-			goto out;
-		}
-
-		alt_mac_addr[i] = (u8)(nvm_data & 0xFF);
-		alt_mac_addr[i + 1] = (u8)(nvm_data >> 8);
-	}
-
-	/* if multicast bit is set, the alternate address will not be used */
-	if (alt_mac_addr[0] & 0x01) {
-		DEBUGOUT("Ignoring Alternate Mac Address with MC bit set\n");
-		goto out;
-	}
-
-	/*
-	 * We have a valid alternate MAC address, and we want to treat it the
-	 * same as the normal permanent MAC address stored by the HW into the
-	 * RAR. Do this by mapping this address into RAR0.
-	 */
-	hw->mac.ops.rar_set(hw, alt_mac_addr, 0);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_rar_set_generic - Set receive address register
- *  @hw: pointer to the HW structure
- *  @addr: pointer to the receive address
- *  @index: receive address array register
- *
- *  Sets the receive address array register at index to the address passed
- *  in by addr.
- **/
-void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index)
-{
-	u32 rar_low, rar_high;
-
-	DEBUGFUNC("e1000_rar_set_generic");
-
-	/*
-	 * HW expects these in little endian so we reverse the byte order
-	 * from network order (big endian) to little endian
-	 */
-	rar_low = ((u32) addr[0] |
-	           ((u32) addr[1] << 8) |
-	           ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
-
-	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
-
-	/* If MAC address zero, no need to set the AV bit */
-	if (rar_low || rar_high)
-		rar_high |= E1000_RAH_AV;
-
-	/*
-	 * Some bridges will combine consecutive 32-bit writes into
-	 * a single burst write, which will malfunction on some parts.
-	 * The flushes avoid this.
-	 */
-	E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
-	E1000_WRITE_FLUSH(hw);
-	E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
-	E1000_WRITE_FLUSH(hw);
-}
-
-/**
- *  e1000_mta_set_generic - Set multicast filter table address
- *  @hw: pointer to the HW structure
- *  @hash_value: determines the MTA register and bit to set
- *
- *  The multicast table address is a register array of 32-bit registers.
- *  The hash_value is used to determine what register the bit is in, the
- *  current value is read, the new bit is OR'd in and the new value is
- *  written back into the register.
- **/
-void e1000_mta_set_generic(struct e1000_hw *hw, u32 hash_value)
-{
-	u32 hash_bit, hash_reg, mta;
-
-	DEBUGFUNC("e1000_mta_set_generic");
-	/*
-	 * The MTA is a register array of 32-bit registers. It is
-	 * treated like an array of (32*mta_reg_count) bits.  We want to
-	 * set bit BitArray[hash_value]. So we figure out what register
-	 * the bit is in, read it, OR in the new bit, then write
-	 * back the new value.  The (hw->mac.mta_reg_count - 1) serves as a
-	 * mask to bits 31:5 of the hash value which gives us the
-	 * register we're modifying.  The hash bit within that register
-	 * is determined by the lower 5 bits of the hash value.
-	 */
-	hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
-	hash_bit = hash_value & 0x1F;
-
-	mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg);
-
-	mta |= (1 << hash_bit);
-
-	E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta);
-	E1000_WRITE_FLUSH(hw);
-}
-
-/**
- *  e1000_update_mc_addr_list_generic - Update Multicast addresses
- *  @hw: pointer to the HW structure
- *  @mc_addr_list: array of multicast addresses to program
- *  @mc_addr_count: number of multicast addresses to program
- *
- *  Updates entire Multicast Table Array.
- *  The caller must have a packed mc_addr_list of multicast addresses.
- **/
-void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
-                                       u8 *mc_addr_list, u32 mc_addr_count)
-{
-	u32 hash_value, hash_bit, hash_reg;
-	int i;
-
-	DEBUGFUNC("e1000_update_mc_addr_list_generic");
-
-	/* clear mta_shadow */
-	memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
-
-	/* update mta_shadow from mc_addr_list */
-	for (i = 0; (u32) i < mc_addr_count; i++) {
-		hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list);
-
-		hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
-		hash_bit = hash_value & 0x1F;
-
-		hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
-		mc_addr_list += (ETH_ADDR_LEN);
-	}
-
-	/* replace the entire MTA table */
-	for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]);
-	E1000_WRITE_FLUSH(hw);
-}
-
-/**
- *  e1000_hash_mc_addr_generic - Generate a multicast hash value
- *  @hw: pointer to the HW structure
- *  @mc_addr: pointer to a multicast address
- *
- *  Generates a multicast address hash value which is used to determine
- *  the multicast filter table array address and new table value.  See
- *  e1000_mta_set_generic()
- **/
-u32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr)
-{
-	u32 hash_value, hash_mask;
-	u8 bit_shift = 0;
-
-	DEBUGFUNC("e1000_hash_mc_addr_generic");
-
-	/* Register count multiplied by bits per register */
-	hash_mask = (hw->mac.mta_reg_count * 32) - 1;
-
-	/*
-	 * For a mc_filter_type of 0, bit_shift is the number of left-shifts
-	 * where 0xFF would still fall within the hash mask.
-	 */
-	while (hash_mask >> bit_shift != 0xFF)
-		bit_shift++;
-
-	/*
-	 * The portion of the address that is used for the hash table
-	 * is determined by the mc_filter_type setting.
-	 * The algorithm is such that there is a total of 8 bits of shifting.
-	 * The bit_shift for a mc_filter_type of 0 represents the number of
-	 * left-shifts where the MSB of mc_addr[5] would still fall within
-	 * the hash_mask.  Case 0 does this exactly.  Since there are a total
-	 * of 8 bits of shifting, then mc_addr[4] will shift right the
-	 * remaining number of bits. Thus 8 - bit_shift.  The rest of the
-	 * cases are a variation of this algorithm...essentially raising the
-	 * number of bits to shift mc_addr[5] left, while still keeping the
-	 * 8-bit shifting total.
-	 *
-	 * For example, given the following Destination MAC Address and an
-	 * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
-	 * we can see that the bit_shift for case 0 is 4.  These are the hash
-	 * values resulting from each mc_filter_type...
-	 * [0] [1] [2] [3] [4] [5]
-	 * 01  AA  00  12  34  56
-	 * LSB                 MSB
-	 *
-	 * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
-	 * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
-	 * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
-	 * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
-	 */
-	switch (hw->mac.mc_filter_type) {
-	default:
-	case 0:
-		break;
-	case 1:
-		bit_shift += 1;
-		break;
-	case 2:
-		bit_shift += 2;
-		break;
-	case 3:
-		bit_shift += 4;
-		break;
-	}
-
-	hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
-	                          (((u16) mc_addr[5]) << bit_shift)));
-
-	return hash_value;
-}
-
-/**
- *  e1000_pcix_mmrbc_workaround_generic - Fix incorrect MMRBC value
- *  @hw: pointer to the HW structure
- *
- *  In certain situations, a system BIOS may report that the PCIx maximum
- *  memory read byte count (MMRBC) value is higher than than the actual
- *  value. We check the PCIx command register with the current PCIx status
- *  register.
- **/
-void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw)
-{
-	u16 cmd_mmrbc;
-	u16 pcix_cmd;
-	u16 pcix_stat_hi_word;
-	u16 stat_mmrbc;
-
-	DEBUGFUNC("e1000_pcix_mmrbc_workaround_generic");
-
-	/* Workaround for PCI-X issue when BIOS sets MMRBC incorrectly */
-	if (hw->bus.type != e1000_bus_type_pcix)
-		return;
-
-	e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd);
-	e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI, &pcix_stat_hi_word);
-	cmd_mmrbc = (pcix_cmd & PCIX_COMMAND_MMRBC_MASK) >>
-	             PCIX_COMMAND_MMRBC_SHIFT;
-	stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
-	              PCIX_STATUS_HI_MMRBC_SHIFT;
-	if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
-		stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
-	if (cmd_mmrbc > stat_mmrbc) {
-		pcix_cmd &= ~PCIX_COMMAND_MMRBC_MASK;
-		pcix_cmd |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
-		e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd);
-	}
-}
-
-/**
- *  e1000_clear_hw_cntrs_base_generic - Clear base hardware counters
- *  @hw: pointer to the HW structure
- *
- *  Clears the base hardware counters by reading the counter registers.
- **/
-void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw __unused)
-{
-	DEBUGFUNC("e1000_clear_hw_cntrs_base_generic");
-
-#if 0
-	E1000_READ_REG(hw, E1000_CRCERRS);
-	E1000_READ_REG(hw, E1000_SYMERRS);
-	E1000_READ_REG(hw, E1000_MPC);
-	E1000_READ_REG(hw, E1000_SCC);
-	E1000_READ_REG(hw, E1000_ECOL);
-	E1000_READ_REG(hw, E1000_MCC);
-	E1000_READ_REG(hw, E1000_LATECOL);
-	E1000_READ_REG(hw, E1000_COLC);
-	E1000_READ_REG(hw, E1000_DC);
-	E1000_READ_REG(hw, E1000_SEC);
-	E1000_READ_REG(hw, E1000_RLEC);
-	E1000_READ_REG(hw, E1000_XONRXC);
-	E1000_READ_REG(hw, E1000_XONTXC);
-	E1000_READ_REG(hw, E1000_XOFFRXC);
-	E1000_READ_REG(hw, E1000_XOFFTXC);
-	E1000_READ_REG(hw, E1000_FCRUC);
-	E1000_READ_REG(hw, E1000_GPRC);
-	E1000_READ_REG(hw, E1000_BPRC);
-	E1000_READ_REG(hw, E1000_MPRC);
-	E1000_READ_REG(hw, E1000_GPTC);
-	E1000_READ_REG(hw, E1000_GORCL);
-	E1000_READ_REG(hw, E1000_GORCH);
-	E1000_READ_REG(hw, E1000_GOTCL);
-	E1000_READ_REG(hw, E1000_GOTCH);
-	E1000_READ_REG(hw, E1000_RNBC);
-	E1000_READ_REG(hw, E1000_RUC);
-	E1000_READ_REG(hw, E1000_RFC);
-	E1000_READ_REG(hw, E1000_ROC);
-	E1000_READ_REG(hw, E1000_RJC);
-	E1000_READ_REG(hw, E1000_TORL);
-	E1000_READ_REG(hw, E1000_TORH);
-	E1000_READ_REG(hw, E1000_TOTL);
-	E1000_READ_REG(hw, E1000_TOTH);
-	E1000_READ_REG(hw, E1000_TPR);
-	E1000_READ_REG(hw, E1000_TPT);
-	E1000_READ_REG(hw, E1000_MPTC);
-	E1000_READ_REG(hw, E1000_BPTC);
-#endif
-}
-
-/**
- *  e1000_check_for_copper_link_generic - Check for link (Copper)
- *  @hw: pointer to the HW structure
- *
- *  Checks to see of the link status of the hardware has changed.  If a
- *  change in link status has been detected, then we read the PHY registers
- *  to get the current speed/duplex if link exists.
- **/
-s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val;
-	bool link;
-
-	DEBUGFUNC("e1000_check_for_copper_link");
-
-	/*
-	 * We only want to go out to the PHY registers to see if Auto-Neg
-	 * has completed and/or if our link status has changed.  The
-	 * get_link_status flag is set upon receiving a Link Status
-	 * Change or Rx Sequence Error interrupt.
-	 */
-	if (!mac->get_link_status) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	/*
-	 * First we want to see if the MII Status Register reports
-	 * link.  If so, then we want to get the current speed/duplex
-	 * of the PHY.
-	 */
-	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		goto out;
-
-	if (!link)
-		goto out; /* No link detected */
-
-	mac->get_link_status = false;
-
-	/*
-	 * Check if there was DownShift, must be checked
-	 * immediately after link-up
-	 */
-	e1000_check_downshift_generic(hw);
-
-	/*
-	 * If we are forcing speed/duplex, then we simply return since
-	 * we have already determined whether we have link or not.
-	 */
-	if (!mac->autoneg) {
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	/*
-	 * Auto-Neg is enabled.  Auto Speed Detection takes care
-	 * of MAC speed/duplex configuration.  So we only need to
-	 * configure Collision Distance in the MAC.
-	 */
-	e1000_config_collision_dist_generic(hw);
-
-	/*
-	 * Configure Flow Control now that Auto-Neg has completed.
-	 * First, we need to restore the desired flow control
-	 * settings because we may have had to re-autoneg with a
-	 * different link partner.
-	 */
-	ret_val = e1000_config_fc_after_link_up_generic(hw);
-	if (ret_val)
-		DEBUGOUT("Error configuring flow control\n");
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_check_for_fiber_link_generic - Check for link (Fiber)
- *  @hw: pointer to the HW structure
- *
- *  Checks for link up on the hardware.  If link is not up and we have
- *  a signal, then we need to force link up.
- **/
-s32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 rxcw;
-	u32 ctrl;
-	u32 status;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_check_for_fiber_link_generic");
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	status = E1000_READ_REG(hw, E1000_STATUS);
-	rxcw = E1000_READ_REG(hw, E1000_RXCW);
-
-	/*
-	 * If we don't have link (auto-negotiation failed or link partner
-	 * cannot auto-negotiate), the cable is plugged in (we have signal),
-	 * and our link partner is not trying to auto-negotiate with us (we
-	 * are receiving idles or data), we need to force link up. We also
-	 * need to give auto-negotiation time to complete, in case the cable
-	 * was just plugged in. The autoneg_failed flag does this.
-	 */
-	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
-	if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) &&
-	    (!(rxcw & E1000_RXCW_C))) {
-		if (mac->autoneg_failed == 0) {
-			mac->autoneg_failed = 1;
-			goto out;
-		}
-		DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
-
-		/* Disable auto-negotiation in the TXCW register */
-		E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
-
-		/* Force link-up and also force full-duplex. */
-		ctrl = E1000_READ_REG(hw, E1000_CTRL);
-		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-		/* Configure Flow Control after forcing link up. */
-		ret_val = e1000_config_fc_after_link_up_generic(hw);
-		if (ret_val) {
-			DEBUGOUT("Error configuring flow control\n");
-			goto out;
-		}
-	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
-		/*
-		 * If we are forcing link and we are receiving /C/ ordered
-		 * sets, re-enable auto-negotiation in the TXCW register
-		 * and disable forced link in the Device Control register
-		 * in an attempt to auto-negotiate with our link partner.
-		 */
-		DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
-		E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
-		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
-
-		mac->serdes_has_link = true;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_check_for_serdes_link_generic - Check for link (Serdes)
- *  @hw: pointer to the HW structure
- *
- *  Checks for link up on the hardware.  If link is not up and we have
- *  a signal, then we need to force link up.
- **/
-s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 rxcw;
-	u32 ctrl;
-	u32 status;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_check_for_serdes_link_generic");
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	status = E1000_READ_REG(hw, E1000_STATUS);
-	rxcw = E1000_READ_REG(hw, E1000_RXCW);
-
-	/*
-	 * If we don't have link (auto-negotiation failed or link partner
-	 * cannot auto-negotiate), and our link partner is not trying to
-	 * auto-negotiate with us (we are receiving idles or data),
-	 * we need to force link up. We also need to give auto-negotiation
-	 * time to complete.
-	 */
-	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
-	if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) {
-		if (mac->autoneg_failed == 0) {
-			mac->autoneg_failed = 1;
-			goto out;
-		}
-		DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
-
-		/* Disable auto-negotiation in the TXCW register */
-		E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
-
-		/* Force link-up and also force full-duplex. */
-		ctrl = E1000_READ_REG(hw, E1000_CTRL);
-		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-		/* Configure Flow Control after forcing link up. */
-		ret_val = e1000_config_fc_after_link_up_generic(hw);
-		if (ret_val) {
-			DEBUGOUT("Error configuring flow control\n");
-			goto out;
-		}
-	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
-		/*
-		 * If we are forcing link and we are receiving /C/ ordered
-		 * sets, re-enable auto-negotiation in the TXCW register
-		 * and disable forced link in the Device Control register
-		 * in an attempt to auto-negotiate with our link partner.
-		 */
-		DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
-		E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
-		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
-
-		mac->serdes_has_link = true;
-	} else if (!(E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW))) {
-		/*
-		 * If we force link for non-auto-negotiation switch, check
-		 * link status based on MAC synchronization for internal
-		 * serdes media type.
-		 */
-		/* SYNCH bit and IV bit are sticky. */
-		usec_delay(10);
-		rxcw = E1000_READ_REG(hw, E1000_RXCW);
-		if (rxcw & E1000_RXCW_SYNCH) {
-			if (!(rxcw & E1000_RXCW_IV)) {
-				mac->serdes_has_link = true;
-				DEBUGOUT("SERDES: Link up - forced.\n");
-			}
-		} else {
-			mac->serdes_has_link = false;
-			DEBUGOUT("SERDES: Link down - force failed.\n");
-		}
-	}
-
-	if (E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW)) {
-		status = E1000_READ_REG(hw, E1000_STATUS);
-		if (status & E1000_STATUS_LU) {
-			/* SYNCH bit and IV bit are sticky, so reread rxcw. */
-			usec_delay(10);
-			rxcw = E1000_READ_REG(hw, E1000_RXCW);
-			if (rxcw & E1000_RXCW_SYNCH) {
-				if (!(rxcw & E1000_RXCW_IV)) {
-					mac->serdes_has_link = true;
-					DEBUGOUT("SERDES: Link up - autoneg "
-					   "completed sucessfully.\n");
-				} else {
-					mac->serdes_has_link = false;
-					DEBUGOUT("SERDES: Link down - invalid"
-					   "codewords detected in autoneg.\n");
-				}
-			} else {
-				mac->serdes_has_link = false;
-				DEBUGOUT("SERDES: Link down - no sync.\n");
-			}
-		} else {
-			mac->serdes_has_link = false;
-			DEBUGOUT("SERDES: Link down - autoneg failed\n");
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_setup_link_generic - Setup flow control and link settings
- *  @hw: pointer to the HW structure
- *
- *  Determines which flow control settings to use, then configures flow
- *  control.  Calls the appropriate media-specific link configuration
- *  function.  Assuming the adapter has a valid link partner, a valid link
- *  should be established.  Assumes the hardware has previously been reset
- *  and the transmitter and receiver are not enabled.
- **/
-s32 e1000_setup_link_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_setup_link_generic");
-
-	/*
-	 * In the case of the phy reset being blocked, we already have a link.
-	 * We do not need to set it up again.
-	 */
-	if (hw->phy.ops.check_reset_block)
-		if (hw->phy.ops.check_reset_block(hw))
-			goto out;
-
-	/*
-	 * If requested flow control is set to default, set flow control
-	 * based on the EEPROM flow control settings.
-	 */
-	if (hw->fc.requested_mode == e1000_fc_default) {
-		ret_val = e1000_set_default_fc_generic(hw);
-		if (ret_val)
-			goto out;
-	}
-
-	/*
-	 * Save off the requested flow control mode for use later.  Depending
-	 * on the link partner's capabilities, we may or may not use this mode.
-	 */
-	hw->fc.current_mode = hw->fc.requested_mode;
-
-	DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
-		hw->fc.current_mode);
-
-	/* Call the necessary media_type subroutine to configure the link. */
-	ret_val = hw->mac.ops.setup_physical_interface(hw);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Initialize the flow control address, type, and PAUSE timer
-	 * registers to their default values.  This is done even if flow
-	 * control is disabled, because it does not hurt anything to
-	 * initialize these registers.
-	 */
-	DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
-	E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE);
-	E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
-	E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
-
-	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
-
-	ret_val = e1000_set_fc_watermarks_generic(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_setup_fiber_serdes_link_generic - Setup link for fiber/serdes
- *  @hw: pointer to the HW structure
- *
- *  Configures collision distance and flow control for fiber and serdes
- *  links.  Upon successful setup, poll for link.
- **/
-s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_setup_fiber_serdes_link_generic");
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	/* Take the link out of reset */
-	ctrl &= ~E1000_CTRL_LRST;
-
-	e1000_config_collision_dist_generic(hw);
-
-	ret_val = e1000_commit_fc_settings_generic(hw);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Since auto-negotiation is enabled, take the link out of reset (the
-	 * link will be in reset, because we previously reset the chip). This
-	 * will restart auto-negotiation.  If auto-negotiation is successful
-	 * then the link-up status bit will be set and the flow control enable
-	 * bits (RFCE and TFCE) will be set according to their negotiated value.
-	 */
-	DEBUGOUT("Auto-negotiation enabled\n");
-
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-	E1000_WRITE_FLUSH(hw);
-	msec_delay(1);
-
-	/*
-	 * For these adapters, the SW definable pin 1 is set when the optics
-	 * detect a signal.  If we have a signal, then poll for a "Link-Up"
-	 * indication.
-	 */
-	if (hw->phy.media_type == e1000_media_type_internal_serdes ||
-	    (E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) {
-		ret_val = e1000_poll_fiber_serdes_link_generic(hw);
-	} else {
-		DEBUGOUT("No signal detected\n");
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_config_collision_dist_generic - Configure collision distance
- *  @hw: pointer to the HW structure
- *
- *  Configures the collision distance to the default value and is used
- *  during link setup. Currently no func pointer exists and all
- *  implementations are handled in the generic version of this function.
- **/
-void e1000_config_collision_dist_generic(struct e1000_hw *hw)
-{
-	u32 tctl;
-
-	DEBUGFUNC("e1000_config_collision_dist_generic");
-
-	tctl = E1000_READ_REG(hw, E1000_TCTL);
-
-	tctl &= ~E1000_TCTL_COLD;
-	tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
-
-	E1000_WRITE_REG(hw, E1000_TCTL, tctl);
-	E1000_WRITE_FLUSH(hw);
-}
-
-/**
- *  e1000_poll_fiber_serdes_link_generic - Poll for link up
- *  @hw: pointer to the HW structure
- *
- *  Polls for link up by reading the status register, if link fails to come
- *  up with auto-negotiation, then the link is forced if a signal is detected.
- **/
-s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 i, status;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_poll_fiber_serdes_link_generic");
-
-	/*
-	 * If we have a signal (the cable is plugged in, or assumed true for
-	 * serdes media) then poll for a "Link-Up" indication in the Device
-	 * Status Register.  Time-out if a link isn't seen in 500 milliseconds
-	 * seconds (Auto-negotiation should complete in less than 500
-	 * milliseconds even if the other end is doing it in SW).
-	 */
-	for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
-		msec_delay(10);
-		status = E1000_READ_REG(hw, E1000_STATUS);
-		if (status & E1000_STATUS_LU)
-			break;
-	}
-	if (i == FIBER_LINK_UP_LIMIT) {
-		DEBUGOUT("Never got a valid link from auto-neg!!!\n");
-		mac->autoneg_failed = 1;
-		/*
-		 * AutoNeg failed to achieve a link, so we'll call
-		 * mac->check_for_link. This routine will force the
-		 * link up if we detect a signal. This will allow us to
-		 * communicate with non-autonegotiating link partners.
-		 */
-		ret_val = hw->mac.ops.check_for_link(hw);
-		if (ret_val) {
-			DEBUGOUT("Error while checking for link\n");
-			goto out;
-		}
-		mac->autoneg_failed = 0;
-	} else {
-		mac->autoneg_failed = 0;
-		DEBUGOUT("Valid Link Found\n");
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_commit_fc_settings_generic - Configure flow control
- *  @hw: pointer to the HW structure
- *
- *  Write the flow control settings to the Transmit Config Word Register (TXCW)
- *  base on the flow control settings in e1000_mac_info.
- **/
-s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 txcw;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_commit_fc_settings_generic");
-
-	/*
-	 * Check for a software override of the flow control settings, and
-	 * setup the device accordingly.  If auto-negotiation is enabled, then
-	 * software will have to set the "PAUSE" bits to the correct value in
-	 * the Transmit Config Word Register (TXCW) and re-start auto-
-	 * negotiation.  However, if auto-negotiation is disabled, then
-	 * software will have to manually configure the two flow control enable
-	 * bits in the CTRL register.
-	 *
-	 * The possible values of the "fc" parameter are:
-	 *      0:  Flow control is completely disabled
-	 *      1:  Rx flow control is enabled (we can receive pause frames,
-	 *          but not send pause frames).
-	 *      2:  Tx flow control is enabled (we can send pause frames but we
-	 *          do not support receiving pause frames).
-	 *      3:  Both Rx and Tx flow control (symmetric) are enabled.
-	 */
-	switch (hw->fc.current_mode) {
-	case e1000_fc_none:
-		/* Flow control completely disabled by a software over-ride. */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
-		break;
-	case e1000_fc_rx_pause:
-		/*
-		 * Rx Flow control is enabled and Tx Flow control is disabled
-		 * by a software over-ride. Since there really isn't a way to
-		 * advertise that we are capable of Rx Pause ONLY, we will
-		 * advertise that we support both symmetric and asymmetric RX
-		 * PAUSE.  Later, we will disable the adapter's ability to send
-		 * PAUSE frames.
-		 */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
-		break;
-	case e1000_fc_tx_pause:
-		/*
-		 * Tx Flow control is enabled, and Rx Flow control is disabled,
-		 * by a software over-ride.
-		 */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
-		break;
-	case e1000_fc_full:
-		/*
-		 * Flow control (both Rx and Tx) is enabled by a software
-		 * over-ride.
-		 */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
-		break;
-	default:
-		DEBUGOUT("Flow control param set incorrectly\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-		break;
-	}
-
-	E1000_WRITE_REG(hw, E1000_TXCW, txcw);
-	mac->txcw = txcw;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_set_fc_watermarks_generic - Set flow control high/low watermarks
- *  @hw: pointer to the HW structure
- *
- *  Sets the flow control high/low threshold (watermark) registers.  If
- *  flow control XON frame transmission is enabled, then set XON frame
- *  transmission as well.
- **/
-s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u32 fcrtl = 0, fcrth = 0;
-
-	DEBUGFUNC("e1000_set_fc_watermarks_generic");
-
-	/*
-	 * Set the flow control receive threshold registers.  Normally,
-	 * these registers will be set to a default threshold that may be
-	 * adjusted later by the driver's runtime code.  However, if the
-	 * ability to transmit pause frames is not enabled, then these
-	 * registers will be set to 0.
-	 */
-	if (hw->fc.current_mode & e1000_fc_tx_pause) {
-		/*
-		 * We need to set up the Receive Threshold high and low water
-		 * marks as well as (optionally) enabling the transmission of
-		 * XON frames.
-		 */
-		fcrtl = hw->fc.low_water;
-		if (hw->fc.send_xon)
-			fcrtl |= E1000_FCRTL_XONE;
-
-		fcrth = hw->fc.high_water;
-	}
-	E1000_WRITE_REG(hw, E1000_FCRTL, fcrtl);
-	E1000_WRITE_REG(hw, E1000_FCRTH, fcrth);
-
-	return ret_val;
-}
-
-/**
- *  e1000_set_default_fc_generic - Set flow control default values
- *  @hw: pointer to the HW structure
- *
- *  Read the EEPROM for the default values for flow control and store the
- *  values.
- **/
-s32 e1000_set_default_fc_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 nvm_data;
-
-	DEBUGFUNC("e1000_set_default_fc_generic");
-
-	/*
-	 * Read and store word 0x0F of the EEPROM. This word contains bits
-	 * that determine the hardware's default PAUSE (flow control) mode,
-	 * a bit that determines whether the HW defaults to enabling or
-	 * disabling auto-negotiation, and the direction of the
-	 * SW defined pins. If there is no SW over-ride of the flow
-	 * control setting, then the variable hw->fc will
-	 * be initialized based on a value in the EEPROM.
-	 */
-	ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
-
-	if (ret_val) {
-		DEBUGOUT("NVM Read Error\n");
-		goto out;
-	}
-
-	if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
-		hw->fc.requested_mode = e1000_fc_none;
-	else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
-		 NVM_WORD0F_ASM_DIR)
-		hw->fc.requested_mode = e1000_fc_tx_pause;
-	else
-		hw->fc.requested_mode = e1000_fc_full;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_force_mac_fc_generic - Force the MAC's flow control settings
- *  @hw: pointer to the HW structure
- *
- *  Force the MAC's flow control settings.  Sets the TFCE and RFCE bits in the
- *  device control register to reflect the adapter settings.  TFCE and RFCE
- *  need to be explicitly set by software when a copper PHY is used because
- *  autonegotiation is managed by the PHY rather than the MAC.  Software must
- *  also configure these bits when link is forced on a fiber connection.
- **/
-s32 e1000_force_mac_fc_generic(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_force_mac_fc_generic");
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	/*
-	 * Because we didn't get link via the internal auto-negotiation
-	 * mechanism (we either forced link or we got link via PHY
-	 * auto-neg), we have to manually enable/disable transmit an
-	 * receive flow control.
-	 *
-	 * The "Case" statement below enables/disable flow control
-	 * according to the "hw->fc.current_mode" parameter.
-	 *
-	 * The possible values of the "fc" parameter are:
-	 *      0:  Flow control is completely disabled
-	 *      1:  Rx flow control is enabled (we can receive pause
-	 *          frames but not send pause frames).
-	 *      2:  Tx flow control is enabled (we can send pause frames
-	 *          frames but we do not receive pause frames).
-	 *      3:  Both Rx and Tx flow control (symmetric) is enabled.
-	 *  other:  No other values should be possible at this point.
-	 */
-	DEBUGOUT1("hw->fc.current_mode = %u\n", hw->fc.current_mode);
-
-	switch (hw->fc.current_mode) {
-	case e1000_fc_none:
-		ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
-		break;
-	case e1000_fc_rx_pause:
-		ctrl &= (~E1000_CTRL_TFCE);
-		ctrl |= E1000_CTRL_RFCE;
-		break;
-	case e1000_fc_tx_pause:
-		ctrl &= (~E1000_CTRL_RFCE);
-		ctrl |= E1000_CTRL_TFCE;
-		break;
-	case e1000_fc_full:
-		ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
-		break;
-	default:
-		DEBUGOUT("Flow control param set incorrectly\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_config_fc_after_link_up_generic - Configures flow control after link
- *  @hw: pointer to the HW structure
- *
- *  Checks the status of auto-negotiation after link up to ensure that the
- *  speed and duplex were not forced.  If the link needed to be forced, then
- *  flow control needs to be forced also.  If auto-negotiation is enabled
- *  and did not fail, then we configure flow control based on our link
- *  partner.
- **/
-s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val = E1000_SUCCESS;
-	u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
-	u16 speed, duplex;
-
-	DEBUGFUNC("e1000_config_fc_after_link_up_generic");
-
-	/*
-	 * Check for the case where we have fiber media and auto-neg failed
-	 * so we had to force link.  In this case, we need to force the
-	 * configuration of the MAC to match the "fc" parameter.
-	 */
-	if (mac->autoneg_failed) {
-		if (hw->phy.media_type == e1000_media_type_fiber ||
-		    hw->phy.media_type == e1000_media_type_internal_serdes)
-			ret_val = e1000_force_mac_fc_generic(hw);
-	} else {
-		if (hw->phy.media_type == e1000_media_type_copper)
-			ret_val = e1000_force_mac_fc_generic(hw);
-	}
-
-	if (ret_val) {
-		DEBUGOUT("Error forcing flow control settings\n");
-		goto out;
-	}
-
-	/*
-	 * Check for the case where we have copper media and auto-neg is
-	 * enabled.  In this case, we need to check and see if Auto-Neg
-	 * has completed, and if so, how the PHY and link partner has
-	 * flow control configured.
-	 */
-	if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) {
-		/*
-		 * Read the MII Status Register and check to see if AutoNeg
-		 * has completed.  We read this twice because this reg has
-		 * some "sticky" (latched) bits.
-		 */
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
-		if (ret_val)
-			goto out;
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
-		if (ret_val)
-			goto out;
-
-		if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
-			DEBUGOUT("Copper PHY and Auto Neg "
-			         "has not completed.\n");
-			goto out;
-		}
-
-		/*
-		 * The AutoNeg process has completed, so we now need to
-		 * read both the Auto Negotiation Advertisement
-		 * Register (Address 4) and the Auto_Negotiation Base
-		 * Page Ability Register (Address 5) to determine how
-		 * flow control was negotiated.
-		 */
-		ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
-		                             &mii_nway_adv_reg);
-		if (ret_val)
-			goto out;
-		ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
-		                             &mii_nway_lp_ability_reg);
-		if (ret_val)
-			goto out;
-
-		/*
-		 * Two bits in the Auto Negotiation Advertisement Register
-		 * (Address 4) and two bits in the Auto Negotiation Base
-		 * Page Ability Register (Address 5) determine flow control
-		 * for both the PHY and the link partner.  The following
-		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
-		 * 1999, describes these PAUSE resolution bits and how flow
-		 * control is determined based upon these settings.
-		 * NOTE:  DC = Don't Care
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
-		 *-------|---------|-------|---------|--------------------
-		 *   0   |    0    |  DC   |   DC    | e1000_fc_none
-		 *   0   |    1    |   0   |   DC    | e1000_fc_none
-		 *   0   |    1    |   1   |    0    | e1000_fc_none
-		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
-		 *   1   |    0    |   0   |   DC    | e1000_fc_none
-		 *   1   |   DC    |   1   |   DC    | e1000_fc_full
-		 *   1   |    1    |   0   |    0    | e1000_fc_none
-		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
-		 *
-		 * Are both PAUSE bits set to 1?  If so, this implies
-		 * Symmetric Flow Control is enabled at both ends.  The
-		 * ASM_DIR bits are irrelevant per the spec.
-		 *
-		 * For Symmetric Flow Control:
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-		 *-------|---------|-------|---------|--------------------
-		 *   1   |   DC    |   1   |   DC    | E1000_fc_full
-		 *
-		 */
-		if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-		    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
-			/*
-			 * Now we need to check if the user selected Rx ONLY
-			 * of pause frames.  In this case, we had to advertise
-			 * FULL flow control because we could not advertise RX
-			 * ONLY. Hence, we must now check to see if we need to
-			 * turn OFF  the TRANSMISSION of PAUSE frames.
-			 */
-			if (hw->fc.requested_mode == e1000_fc_full) {
-				hw->fc.current_mode = e1000_fc_full;
-				DEBUGOUT("Flow Control = FULL.\r\n");
-			} else {
-				hw->fc.current_mode = e1000_fc_rx_pause;
-				DEBUGOUT("Flow Control = "
-				         "RX PAUSE frames only.\r\n");
-			}
-		}
-		/*
-		 * For receiving PAUSE frames ONLY.
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-		 *-------|---------|-------|---------|--------------------
-		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
-		 */
-		else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-		          (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
-		          (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
-		          (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
-			hw->fc.current_mode = e1000_fc_tx_pause;
-			DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
-		}
-		/*
-		 * For transmitting PAUSE frames ONLY.
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-		 *-------|---------|-------|---------|--------------------
-		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
-		 */
-		else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-		         (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
-		         !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
-		         (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
-			hw->fc.current_mode = e1000_fc_rx_pause;
-			DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
-		} else {
-			/*
-			 * Per the IEEE spec, at this point flow control
-			 * should be disabled.
-			 */
-			hw->fc.current_mode = e1000_fc_none;
-			DEBUGOUT("Flow Control = NONE.\r\n");
-		}
-
-		/*
-		 * Now we need to do one last check...  If we auto-
-		 * negotiated to HALF DUPLEX, flow control should not be
-		 * enabled per IEEE 802.3 spec.
-		 */
-		ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
-		if (ret_val) {
-			DEBUGOUT("Error getting link speed and duplex\n");
-			goto out;
-		}
-
-		if (duplex == HALF_DUPLEX)
-			hw->fc.current_mode = e1000_fc_none;
-
-		/*
-		 * Now we call a subroutine to actually force the MAC
-		 * controller to use the correct flow control settings.
-		 */
-		ret_val = e1000_force_mac_fc_generic(hw);
-		if (ret_val) {
-			DEBUGOUT("Error forcing flow control settings\n");
-			goto out;
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_get_speed_and_duplex_copper_generic - Retrieve current speed/duplex
- *  @hw: pointer to the HW structure
- *  @speed: stores the current speed
- *  @duplex: stores the current duplex
- *
- *  Read the status register for the current speed/duplex and store the current
- *  speed and duplex for copper connections.
- **/
-s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed,
-                                              u16 *duplex)
-{
-	u32 status;
-
-	DEBUGFUNC("e1000_get_speed_and_duplex_copper_generic");
-
-	status = E1000_READ_REG(hw, E1000_STATUS);
-	if (status & E1000_STATUS_SPEED_1000) {
-		*speed = SPEED_1000;
-		DEBUGOUT("1000 Mbs, ");
-	} else if (status & E1000_STATUS_SPEED_100) {
-		*speed = SPEED_100;
-		DEBUGOUT("100 Mbs, ");
-	} else {
-		*speed = SPEED_10;
-		DEBUGOUT("10 Mbs, ");
-	}
-
-	if (status & E1000_STATUS_FD) {
-		*duplex = FULL_DUPLEX;
-		DEBUGOUT("Full Duplex\n");
-	} else {
-		*duplex = HALF_DUPLEX;
-		DEBUGOUT("Half Duplex\n");
-	}
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_get_speed_and_duplex_fiber_generic - Retrieve current speed/duplex
- *  @hw: pointer to the HW structure
- *  @speed: stores the current speed
- *  @duplex: stores the current duplex
- *
- *  Sets the speed and duplex to gigabit full duplex (the only possible option)
- *  for fiber/serdes links.
- **/
-s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw __unused,
-                                                    u16 *speed, u16 *duplex)
-{
-	DEBUGFUNC("e1000_get_speed_and_duplex_fiber_serdes_generic");
-
-	*speed = SPEED_1000;
-	*duplex = FULL_DUPLEX;
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_get_hw_semaphore_generic - Acquire hardware semaphore
- *  @hw: pointer to the HW structure
- *
- *  Acquire the HW semaphore to access the PHY or NVM
- **/
-s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw __unused)
-{
-#if 0
-	u32 swsm;
-	s32 ret_val = E1000_SUCCESS;
-	s32 timeout = hw->nvm.word_size + 1;
-	s32 i = 0;
-
-	DEBUGFUNC("e1000_get_hw_semaphore_generic");
-
-	/* Get the SW semaphore */
-	while (i < timeout) {
-		swsm = E1000_READ_REG(hw, E1000_SWSM);
-		if (!(swsm & E1000_SWSM_SMBI))
-			break;
-
-		usec_delay(50);
-		i++;
-	}
-
-	if (i == timeout) {
-		DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	/* Get the FW semaphore. */
-	for (i = 0; i < timeout; i++) {
-		swsm = E1000_READ_REG(hw, E1000_SWSM);
-		E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
-
-		/* Semaphore acquired if bit latched */
-		if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI)
-			break;
-
-		usec_delay(50);
-	}
-
-	if (i == timeout) {
-		/* Release semaphores */
-		e1000_put_hw_semaphore_generic(hw);
-		DEBUGOUT("Driver can't access the NVM\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-out:
-	return ret_val;
-#endif
-	return 0;
-}
-
-/**
- *  e1000_put_hw_semaphore_generic - Release hardware semaphore
- *  @hw: pointer to the HW structure
- *
- *  Release hardware semaphore used to access the PHY or NVM
- **/
-void e1000_put_hw_semaphore_generic(struct e1000_hw *hw __unused)
-{
-#if 0
-	u32 swsm;
-
-	DEBUGFUNC("e1000_put_hw_semaphore_generic");
-
-	swsm = E1000_READ_REG(hw, E1000_SWSM);
-
-	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
-
-	E1000_WRITE_REG(hw, E1000_SWSM, swsm);
-#endif
-}
-
-/**
- *  e1000_get_auto_rd_done_generic - Check for auto read completion
- *  @hw: pointer to the HW structure
- *
- *  Check EEPROM for Auto Read done bit.
- **/
-s32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw)
-{
-	s32 i = 0;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_get_auto_rd_done_generic");
-
-	while (i < AUTO_READ_DONE_TIMEOUT) {
-		if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_AUTO_RD)
-			break;
-		msec_delay(1);
-		i++;
-	}
-
-	if (i == AUTO_READ_DONE_TIMEOUT) {
-		DEBUGOUT("Auto read by HW from NVM has not completed.\n");
-		ret_val = -E1000_ERR_RESET;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_valid_led_default_generic - Verify a valid default LED config
- *  @hw: pointer to the HW structure
- *  @data: pointer to the NVM (EEPROM)
- *
- *  Read the EEPROM for the current default LED configuration.  If the
- *  LED configuration is not valid, set to a valid LED configuration.
- **/
-s32 e1000_valid_led_default_generic(struct e1000_hw *hw, u16 *data)
-{
-	s32 ret_val;
-
-	DEBUGFUNC("e1000_valid_led_default_generic");
-
-	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
-	if (ret_val) {
-		DEBUGOUT("NVM Read Error\n");
-		goto out;
-	}
-
-	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
-		*data = ID_LED_DEFAULT;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_id_led_init_generic -
- *  @hw: pointer to the HW structure
- *
- **/
-s32 e1000_id_led_init_generic(struct e1000_hw *hw __unused)
-{
-#if 0
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val;
-	const u32 ledctl_mask = 0x000000FF;
-	const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
-	const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
-	u16 data, i, temp;
-	const u16 led_mask = 0x0F;
-
-	DEBUGFUNC("e1000_id_led_init_generic");
-
-	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
-	if (ret_val)
-		goto out;
-
-	mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
-	mac->ledctl_mode1 = mac->ledctl_default;
-	mac->ledctl_mode2 = mac->ledctl_default;
-
-	for (i = 0; i < 4; i++) {
-		temp = (data >> (i << 2)) & led_mask;
-		switch (temp) {
-		case ID_LED_ON1_DEF2:
-		case ID_LED_ON1_ON2:
-		case ID_LED_ON1_OFF2:
-			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode1 |= ledctl_on << (i << 3);
-			break;
-		case ID_LED_OFF1_DEF2:
-		case ID_LED_OFF1_ON2:
-		case ID_LED_OFF1_OFF2:
-			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode1 |= ledctl_off << (i << 3);
-			break;
-		default:
-			/* Do nothing */
-			break;
-		}
-		switch (temp) {
-		case ID_LED_DEF1_ON2:
-		case ID_LED_ON1_ON2:
-		case ID_LED_OFF1_ON2:
-			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode2 |= ledctl_on << (i << 3);
-			break;
-		case ID_LED_DEF1_OFF2:
-		case ID_LED_ON1_OFF2:
-		case ID_LED_OFF1_OFF2:
-			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode2 |= ledctl_off << (i << 3);
-			break;
-		default:
-			/* Do nothing */
-			break;
-		}
-	}
-
-out:
-	return ret_val;
-#endif
-	return 0;
-}
-
-/**
- *  e1000_setup_led_generic - Configures SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  This prepares the SW controllable LED for use and saves the current state
- *  of the LED so it can be later restored.
- **/
-s32 e1000_setup_led_generic(struct e1000_hw *hw __unused)
-{
-#if 0
-	u32 ledctl;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_setup_led_generic");
-
-	if (hw->mac.ops.setup_led != e1000_setup_led_generic) {
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	if (hw->phy.media_type == e1000_media_type_fiber) {
-		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
-		hw->mac.ledctl_default = ledctl;
-		/* Turn off LED0 */
-		ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
-		            E1000_LEDCTL_LED0_BLINK |
-		            E1000_LEDCTL_LED0_MODE_MASK);
-		ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
-		           E1000_LEDCTL_LED0_MODE_SHIFT);
-		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
-	} else if (hw->phy.media_type == e1000_media_type_copper) {
-		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
-	}
-
-out:
-	return ret_val;
-#endif
-	return 0;
-}
-
-/**
- *  e1000_cleanup_led_generic - Set LED config to default operation
- *  @hw: pointer to the HW structure
- *
- *  Remove the current LED configuration and set the LED configuration
- *  to the default value, saved from the EEPROM.
- **/
-s32 e1000_cleanup_led_generic(struct e1000_hw *hw __unused)
-{
-#if 0
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_cleanup_led_generic");
-
-	if (hw->mac.ops.cleanup_led != e1000_cleanup_led_generic) {
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
-
-out:
-	return ret_val;
-#endif
-	return 0;
-}
-
-/**
- *  e1000_blink_led_generic - Blink LED
- *  @hw: pointer to the HW structure
- *
- *  Blink the LEDs which are set to be on.
- **/
-s32 e1000_blink_led_generic(struct e1000_hw *hw __unused)
-{
-#if 0
-	u32 ledctl_blink = 0;
-	u32 i;
-
-	DEBUGFUNC("e1000_blink_led_generic");
-
-	if (hw->phy.media_type == e1000_media_type_fiber) {
-		/* always blink LED0 for PCI-E fiber */
-		ledctl_blink = E1000_LEDCTL_LED0_BLINK |
-		     (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
-	} else {
-		/*
-		 * set the blink bit for each LED that's "on" (0x0E)
-		 * in ledctl_mode2
-		 */
-		ledctl_blink = hw->mac.ledctl_mode2;
-		for (i = 0; i < 4; i++)
-			if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
-			    E1000_LEDCTL_MODE_LED_ON)
-				ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
-				                 (i * 8));
-	}
-
-	E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl_blink);
-
-	return E1000_SUCCESS;
-#endif
-	return 0;
-}
-
-/**
- *  e1000_led_on_generic - Turn LED on
- *  @hw: pointer to the HW structure
- *
- *  Turn LED on.
- **/
-s32 e1000_led_on_generic(struct e1000_hw *hw __unused)
-{
-#if 0
-	u32 ctrl;
-
-	DEBUGFUNC("e1000_led_on_generic");
-
-	switch (hw->phy.media_type) {
-	case e1000_media_type_fiber:
-		ctrl = E1000_READ_REG(hw, E1000_CTRL);
-		ctrl &= ~E1000_CTRL_SWDPIN0;
-		ctrl |= E1000_CTRL_SWDPIO0;
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-		break;
-	case e1000_media_type_copper:
-		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
-		break;
-	default:
-		break;
-	}
-
-	return E1000_SUCCESS;
-#endif
-	return 0;
-}
-
-/**
- *  e1000_led_off_generic - Turn LED off
- *  @hw: pointer to the HW structure
- *
- *  Turn LED off.
- **/
-s32 e1000_led_off_generic(struct e1000_hw *hw __unused)
-{
-#if 0
-	u32 ctrl;
-
-	DEBUGFUNC("e1000_led_off_generic");
-
-	switch (hw->phy.media_type) {
-	case e1000_media_type_fiber:
-		ctrl = E1000_READ_REG(hw, E1000_CTRL);
-		ctrl |= E1000_CTRL_SWDPIN0;
-		ctrl |= E1000_CTRL_SWDPIO0;
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-		break;
-	case e1000_media_type_copper:
-		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
-		break;
-	default:
-		break;
-	}
-
-	return E1000_SUCCESS;
-#endif
-	return 0;
-}
-
-/**
- *  e1000_set_pcie_no_snoop_generic - Set PCI-express capabilities
- *  @hw: pointer to the HW structure
- *  @no_snoop: bitmap of snoop events
- *
- *  Set the PCI-express register to snoop for events enabled in 'no_snoop'.
- **/
-void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop)
-{
-	u32 gcr;
-
-	DEBUGFUNC("e1000_set_pcie_no_snoop_generic");
-
-	if (hw->bus.type != e1000_bus_type_pci_express)
-		goto out;
-
-	if (no_snoop) {
-		gcr = E1000_READ_REG(hw, E1000_GCR);
-		gcr &= ~(PCIE_NO_SNOOP_ALL);
-		gcr |= no_snoop;
-		E1000_WRITE_REG(hw, E1000_GCR, gcr);
-	}
-out:
-	return;
-}
-
-/**
- *  e1000_disable_pcie_master_generic - Disables PCI-express master access
- *  @hw: pointer to the HW structure
- *
- *  Returns 0 (E1000_SUCCESS) if successful, else returns -10
- *  (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
- *  the master requests to be disabled.
- *
- *  Disables PCI-Express master access and verifies there are no pending
- *  requests.
- **/
-s32 e1000_disable_pcie_master_generic(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 timeout = MASTER_DISABLE_TIMEOUT;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_disable_pcie_master_generic");
-
-	if (hw->bus.type != e1000_bus_type_pci_express)
-		goto out;
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-	while (timeout) {
-		if (!(E1000_READ_REG(hw, E1000_STATUS) &
-		      E1000_STATUS_GIO_MASTER_ENABLE))
-			break;
-		usec_delay(100);
-		timeout--;
-	}
-
-	if (!timeout) {
-		DEBUGOUT("Master requests are pending.\n");
-		ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_reset_adaptive_generic - Reset Adaptive Interframe Spacing
- *  @hw: pointer to the HW structure
- *
- *  Reset the Adaptive Interframe Spacing throttle to default values.
- **/
-void e1000_reset_adaptive_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-
-	DEBUGFUNC("e1000_reset_adaptive_generic");
-
-	if (!mac->adaptive_ifs) {
-		DEBUGOUT("Not in Adaptive IFS mode!\n");
-		goto out;
-	}
-
-	mac->current_ifs_val = 0;
-	mac->ifs_min_val = IFS_MIN;
-	mac->ifs_max_val = IFS_MAX;
-	mac->ifs_step_size = IFS_STEP;
-	mac->ifs_ratio = IFS_RATIO;
-
-	mac->in_ifs_mode = false;
-	E1000_WRITE_REG(hw, E1000_AIT, 0);
-out:
-	return;
-}
-
-/**
- *  e1000_update_adaptive_generic - Update Adaptive Interframe Spacing
- *  @hw: pointer to the HW structure
- *
- *  Update the Adaptive Interframe Spacing Throttle value based on the
- *  time between transmitted packets and time between collisions.
- **/
-void e1000_update_adaptive_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-
-	DEBUGFUNC("e1000_update_adaptive_generic");
-
-	if (!mac->adaptive_ifs) {
-		DEBUGOUT("Not in Adaptive IFS mode!\n");
-		goto out;
-	}
-
-	if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
-		if (mac->tx_packet_delta > MIN_NUM_XMITS) {
-			mac->in_ifs_mode = true;
-			if (mac->current_ifs_val < mac->ifs_max_val) {
-				if (!mac->current_ifs_val)
-					mac->current_ifs_val = mac->ifs_min_val;
-				else
-					mac->current_ifs_val +=
-						mac->ifs_step_size;
-				E1000_WRITE_REG(hw, E1000_AIT, mac->current_ifs_val);
-			}
-		}
-	} else {
-		if (mac->in_ifs_mode &&
-		    (mac->tx_packet_delta <= MIN_NUM_XMITS)) {
-			mac->current_ifs_val = 0;
-			mac->in_ifs_mode = false;
-			E1000_WRITE_REG(hw, E1000_AIT, 0);
-		}
-	}
-out:
-	return;
-}
-
-/**
- *  e1000_validate_mdi_setting_generic - Verify MDI/MDIx settings
- *  @hw: pointer to the HW structure
- *
- *  Verify that when not using auto-negotiation that MDI/MDIx is correctly
- *  set, which is forced to MDI mode only.
- **/
-static s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_validate_mdi_setting_generic");
-
-	if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) {
-		DEBUGOUT("Invalid MDI setting detected\n");
-		hw->phy.mdix = 1;
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_mac.h b/roms/ipxe/src/drivers/net/e1000/e1000_mac.h
deleted file mode 100644
index 51acae08836900c360f616f73a590ea18228ebd3..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_mac.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000_MAC_H_
-#define _E1000_MAC_H_
-
-/*
- * Functions that should not be called directly from drivers but can be used
- * by other files in this 'shared code'
- */
-void e1000_init_mac_ops_generic(struct e1000_hw *hw);
-void e1000_null_mac_generic(struct e1000_hw *hw);
-s32  e1000_null_ops_generic(struct e1000_hw *hw);
-s32  e1000_null_link_info(struct e1000_hw *hw, u16 *s, u16 *d);
-bool e1000_null_mng_mode(struct e1000_hw *hw);
-void e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a);
-void e1000_null_write_vfta(struct e1000_hw *hw, u32 a, u32 b);
-void e1000_null_mta_set(struct e1000_hw *hw, u32 a);
-void e1000_null_rar_set(struct e1000_hw *hw, u8 *h, u32 a);
-s32  e1000_blink_led_generic(struct e1000_hw *hw);
-s32  e1000_check_for_copper_link_generic(struct e1000_hw *hw);
-s32  e1000_check_for_fiber_link_generic(struct e1000_hw *hw);
-s32  e1000_check_for_serdes_link_generic(struct e1000_hw *hw);
-s32  e1000_cleanup_led_generic(struct e1000_hw *hw);
-s32  e1000_commit_fc_settings_generic(struct e1000_hw *hw);
-s32  e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw);
-s32  e1000_config_fc_after_link_up_generic(struct e1000_hw *hw);
-s32  e1000_disable_pcie_master_generic(struct e1000_hw *hw);
-s32  e1000_force_mac_fc_generic(struct e1000_hw *hw);
-s32  e1000_get_auto_rd_done_generic(struct e1000_hw *hw);
-s32  e1000_get_bus_info_pci_generic(struct e1000_hw *hw);
-s32  e1000_get_bus_info_pcie_generic(struct e1000_hw *hw);
-void e1000_set_lan_id_single_port(struct e1000_hw *hw);
-void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw);
-s32  e1000_get_hw_semaphore_generic(struct e1000_hw *hw);
-s32  e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed,
-                                               u16 *duplex);
-s32  e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw,
-                                                     u16 *speed, u16 *duplex);
-s32  e1000_id_led_init_generic(struct e1000_hw *hw);
-s32  e1000_led_on_generic(struct e1000_hw *hw);
-s32  e1000_led_off_generic(struct e1000_hw *hw);
-void e1000_update_mc_addr_list_generic(struct e1000_hw *hw,
-	                               u8 *mc_addr_list, u32 mc_addr_count);
-s32  e1000_set_default_fc_generic(struct e1000_hw *hw);
-s32  e1000_set_fc_watermarks_generic(struct e1000_hw *hw);
-s32  e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw);
-s32  e1000_setup_led_generic(struct e1000_hw *hw);
-s32  e1000_setup_link_generic(struct e1000_hw *hw);
-
-u32  e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr);
-
-void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw);
-void e1000_clear_vfta_generic(struct e1000_hw *hw);
-void e1000_config_collision_dist_generic(struct e1000_hw *hw);
-void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count);
-void e1000_mta_set_generic(struct e1000_hw *hw, u32 hash_value);
-void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw);
-void e1000_put_hw_semaphore_generic(struct e1000_hw *hw);
-void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index);
-s32  e1000_check_alt_mac_addr_generic(struct e1000_hw *hw);
-void e1000_reset_adaptive_generic(struct e1000_hw *hw);
-void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop);
-void e1000_update_adaptive_generic(struct e1000_hw *hw);
-void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_main.c b/roms/ipxe/src/drivers/net/e1000/e1000_main.c
deleted file mode 100644
index 653323b51b68f237ec7248a1c80294678bc20f66..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_main.c
+++ /dev/null
@@ -1,909 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  Portions Copyright(c) 2010 Marty Connor <mdc@etherboot.org>
-  Portions Copyright(c) 2010 Entity Cyber, Inc.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#include "e1000.h"
-
-/**
- * e1000_irq_disable - Disable interrupt generation
- *
- * @adapter: board private structure
- **/
-static void e1000_irq_disable ( struct e1000_adapter *adapter )
-{
-	E1000_WRITE_REG ( &adapter->hw, E1000_IMC, ~0 );
-	E1000_WRITE_FLUSH ( &adapter->hw );
-}
-
-/**
- * e1000_irq_enable - Enable interrupt generation
- *
- * @adapter: board private structure
- **/
-static void e1000_irq_enable ( struct e1000_adapter *adapter )
-{
-	E1000_WRITE_REG(&adapter->hw, E1000_IMS, IMS_ENABLE_MASK);
-	E1000_WRITE_FLUSH(&adapter->hw);
-}
-
-/**
- * e1000_sw_init - Initialize general software structures (struct e1000_adapter)
- * @adapter: board private structure to initialize
- *
- * e1000_sw_init initializes the Adapter private data structure.
- * Fields are initialized based on PCI device information and
- * OS network device settings (MTU size).
- **/
-static int e1000_sw_init(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	struct pci_device  *pdev = adapter->pdev;
-
-	/* PCI config space info */
-
-	hw->vendor_id = pdev->vendor;
-	hw->device_id = pdev->device;
-
-	pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &hw->subsystem_vendor_id);
-	pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &hw->subsystem_device_id);
-
-	pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
-
-	pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
-
-	adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
-	adapter->max_frame_size = MAXIMUM_ETHERNET_VLAN_SIZE +
-                                  ETH_HLEN + ETH_FCS_LEN;
-	adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
-
-	hw->fc.requested_mode = e1000_fc_none;
-
-	/* Initialize the hardware-specific values */
-	if (e1000_setup_init_funcs(hw, false)) {
-		DBG ("Hardware Initialization Failure\n");
-		return -EIO;
-	}
-
-	/* Explicitly disable IRQ since the NIC can be in any state. */
-	e1000_irq_disable ( adapter );
-
-	return 0;
-}
-
-int32_t e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
-{
-    struct e1000_adapter *adapter = hw->back;
-    uint16_t cap_offset;
-
-#define  PCI_CAP_ID_EXP        0x10    /* PCI Express */
-    cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
-    if (!cap_offset)
-        return -E1000_ERR_CONFIG;
-
-    pci_read_config_word(adapter->pdev, cap_offset + reg, value);
-
-    return 0;
-}
-
-void e1000_pci_clear_mwi ( struct e1000_hw *hw )
-{
-	struct e1000_adapter *adapter = hw->back;
-
-	pci_write_config_word ( adapter->pdev, PCI_COMMAND,
-			        hw->bus.pci_cmd_word & ~PCI_COMMAND_INVALIDATE );
-}
-
-void e1000_pci_set_mwi ( struct e1000_hw *hw )
-{
-	struct e1000_adapter *adapter = hw->back;
-
-	pci_write_config_word ( adapter->pdev, PCI_COMMAND,
-                                hw->bus.pci_cmd_word );
-}
-
-void e1000_read_pci_cfg ( struct e1000_hw *hw, uint32_t reg, uint16_t *value )
-{
-	struct e1000_adapter *adapter = hw->back;
-
-	pci_read_config_word ( adapter->pdev, reg, value );
-}
-
-void e1000_write_pci_cfg ( struct e1000_hw *hw, uint32_t reg, uint16_t *value )
-{
-	struct e1000_adapter *adapter = hw->back;
-
-	pci_write_config_word ( adapter->pdev, reg, *value );
-}
-
-/**
- * e1000_init_manageability - disable interception of ARP packets
- *
- * @v adapter	e1000 private structure
- **/
-static void e1000_init_manageability ( struct e1000_adapter *adapter )
-{
-	if (adapter->en_mng_pt) {
-		u32 manc = E1000_READ_REG(&adapter->hw, E1000_MANC);
-
-		/* disable hardware interception of ARP */
-		manc &= ~(E1000_MANC_ARP_EN);
-
-		E1000_WRITE_REG(&adapter->hw, E1000_MANC, manc);
-	}
-}
-
-/**
- * e1000_setup_tx_resources - allocate Tx resources (Descriptors)
- *
- * @v adapter	e1000 private structure
- *
- * @ret rc       Returns 0 on success, negative on failure
- **/
-static int e1000_setup_tx_resources ( struct e1000_adapter *adapter )
-{
-	DBG ( "e1000_setup_tx_resources\n" );
-
-	/* Allocate transmit descriptor ring memory.
-	   It must not cross a 64K boundary because of hardware errata #23
-	   so we use malloc_dma() requesting a 128 byte block that is
-	   128 byte aligned. This should guarantee that the memory
-	   allocated will not cross a 64K boundary, because 128 is an
-	   even multiple of 65536 ( 65536 / 128 == 512 ), so all possible
-	   allocations of 128 bytes on a 128 byte boundary will not
-	   cross 64K bytes.
-	 */
-
-        adapter->tx_base =
-		malloc_dma ( adapter->tx_ring_size, adapter->tx_ring_size );
-
-	if ( ! adapter->tx_base ) {
-		return -ENOMEM;
-	}
-
-	memset ( adapter->tx_base, 0, adapter->tx_ring_size );
-
-	DBG ( "adapter->tx_base = %#08lx\n", virt_to_bus ( adapter->tx_base ) );
-
-	return 0;
-}
-
-/**
- * e1000_process_tx_packets - process transmitted packets
- *
- * @v netdev	network interface device structure
- **/
-static void e1000_process_tx_packets ( struct net_device *netdev )
-{
-	struct e1000_adapter *adapter = netdev_priv ( netdev );
-	uint32_t i;
-	uint32_t tx_status;
-	struct e1000_tx_desc *tx_curr_desc;
-
-	/* Check status of transmitted packets
-	 */
-	while ( ( i = adapter->tx_head ) != adapter->tx_tail ) {
-
-		tx_curr_desc = ( void * )  ( adapter->tx_base ) +
-					   ( i * sizeof ( *adapter->tx_base ) );
-
-		tx_status = tx_curr_desc->upper.data;
-
-		/* if the packet at tx_head is not owned by hardware it is for us */
-		if ( ! ( tx_status & E1000_TXD_STAT_DD ) )
-			break;
-
-		DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n",
-		      adapter->tx_head, adapter->tx_tail, tx_status );
-
-		if ( tx_status & ( E1000_TXD_STAT_EC | E1000_TXD_STAT_LC |
-				   E1000_TXD_STAT_TU ) ) {
-			netdev_tx_complete_err ( netdev, adapter->tx_iobuf[i], -EINVAL );
-			DBG ( "Error transmitting packet, tx_status: %#08x\n",
-			      tx_status );
-		} else {
-			netdev_tx_complete ( netdev, adapter->tx_iobuf[i] );
-			DBG ( "Success transmitting packet, tx_status: %#08x\n",
-			      tx_status );
-		}
-
-		/* Decrement count of used descriptors, clear this descriptor
-		 */
-		adapter->tx_fill_ctr--;
-		memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
-
-		adapter->tx_head = ( adapter->tx_head + 1 ) % NUM_TX_DESC;
-	}
-}
-
-static void e1000_free_tx_resources ( struct e1000_adapter *adapter )
-{
-	DBG ( "e1000_free_tx_resources\n" );
-
-        free_dma ( adapter->tx_base, adapter->tx_ring_size );
-}
-
-/**
- * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
- * @adapter: board private structure
- *
- * Configure the Tx unit of the MAC after a reset.
- **/
-static void e1000_configure_tx ( struct e1000_adapter *adapter )
-{
-	struct e1000_hw *hw = &adapter->hw;
-	uint32_t tctl;
-
-	DBG ( "e1000_configure_tx\n" );
-
-	E1000_WRITE_REG ( hw, E1000_TDBAH(0), 0 );
-	E1000_WRITE_REG ( hw, E1000_TDBAL(0), virt_to_bus ( adapter->tx_base ) );
-	E1000_WRITE_REG ( hw, E1000_TDLEN(0), adapter->tx_ring_size );
-
-        DBG ( "E1000_TDBAL(0): %#08x\n",  E1000_READ_REG ( hw, E1000_TDBAL(0) ) );
-        DBG ( "E1000_TDLEN(0): %d\n",     E1000_READ_REG ( hw, E1000_TDLEN(0) ) );
-
-	/* Setup the HW Tx Head and Tail descriptor pointers */
-	E1000_WRITE_REG ( hw, E1000_TDH(0), 0 );
-	E1000_WRITE_REG ( hw, E1000_TDT(0), 0 );
-
-	adapter->tx_head = 0;
-	adapter->tx_tail = 0;
-	adapter->tx_fill_ctr = 0;
-
-	/* Setup Transmit Descriptor Settings for eop descriptor */
-	tctl = E1000_TCTL_PSP | E1000_TCTL_EN |
-		(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT) |
-		(E1000_COLLISION_DISTANCE  << E1000_COLD_SHIFT);
-
-	e1000_config_collision_dist ( hw );
-
-	E1000_WRITE_REG ( hw, E1000_TCTL, tctl );
-        E1000_WRITE_FLUSH ( hw );
-}
-
-static void e1000_free_rx_resources ( struct e1000_adapter *adapter )
-{
-	int i;
-
-	DBG ( "e1000_free_rx_resources\n" );
-
-	free_dma ( adapter->rx_base, adapter->rx_ring_size );
-
-	for ( i = 0; i < NUM_RX_DESC; i++ ) {
-		free_iob ( adapter->rx_iobuf[i] );
-	}
-}
-
-/**
- * e1000_refill_rx_ring - allocate Rx io_buffers
- *
- * @v adapter	e1000 private structure
- *
- * @ret rc       Returns 0 on success, negative on failure
- **/
-static int e1000_refill_rx_ring ( struct e1000_adapter *adapter )
-{
-	int i, rx_curr;
-	int rc = 0;
-	struct e1000_rx_desc *rx_curr_desc;
-	struct e1000_hw *hw = &adapter->hw;
-	struct io_buffer *iob;
-
-	DBG ("e1000_refill_rx_ring\n");
-
-	for ( i = 0; i < NUM_RX_DESC; i++ ) {
-		rx_curr = ( ( adapter->rx_curr + i ) % NUM_RX_DESC );
-		rx_curr_desc = adapter->rx_base + rx_curr;
-
-		if ( rx_curr_desc->status & E1000_RXD_STAT_DD )
-			continue;
-
-		if ( adapter->rx_iobuf[rx_curr] != NULL )
-			continue;
-
-		DBG2 ( "Refilling rx desc %d\n", rx_curr );
-
-		iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE );
-		adapter->rx_iobuf[rx_curr] = iob;
-
-		if ( ! iob ) {
-			DBG ( "alloc_iob failed\n" );
-			rc = -ENOMEM;
-			break;
-		} else {
-			rx_curr_desc->buffer_addr = virt_to_bus ( iob->data );
-
-			E1000_WRITE_REG ( hw, E1000_RDT(0), rx_curr );
-		}
-	}
-	return rc;
-}
-
-/**
- * e1000_setup_rx_resources - allocate Rx resources (Descriptors)
- *
- * @v adapter	e1000 private structure
- *
- * @ret rc       Returns 0 on success, negative on failure
- **/
-static int e1000_setup_rx_resources ( struct e1000_adapter *adapter )
-{
-	int i, rc = 0;
-
-	DBG ( "e1000_setup_rx_resources\n" );
-
-	/* Allocate receive descriptor ring memory.
-	   It must not cross a 64K boundary because of hardware errata
-	 */
-
-        adapter->rx_base =
-		malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size );
-
-	if ( ! adapter->rx_base ) {
-		return -ENOMEM;
-	}
-	memset ( adapter->rx_base, 0, adapter->rx_ring_size );
-
-	for ( i = 0; i < NUM_RX_DESC; i++ ) {
-		/* let e1000_refill_rx_ring() io_buffer allocations */
-		adapter->rx_iobuf[i] = NULL;
-	}
-
-	/* allocate io_buffers */
-	rc = e1000_refill_rx_ring ( adapter );
-	if ( rc < 0 )
-		e1000_free_rx_resources ( adapter );
-
-	return rc;
-}
-
-/**
- * e1000_configure_rx - Configure 8254x Receive Unit after Reset
- * @adapter: board private structure
- *
- * Configure the Rx unit of the MAC after a reset.
- **/
-static void e1000_configure_rx ( struct e1000_adapter *adapter )
-{
-	struct e1000_hw *hw = &adapter->hw;
-	uint32_t rctl;
-
-	DBG ( "e1000_configure_rx\n" );
-
-	/* disable receives while setting up the descriptors */
-	rctl = E1000_READ_REG ( hw, E1000_RCTL );
-	E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN );
-	E1000_WRITE_FLUSH ( hw );
-	mdelay(10);
-
-	adapter->rx_curr = 0;
-
-	/* Setup the HW Rx Head and Tail Descriptor Pointers and
-	 * the Base and Length of the Rx Descriptor Ring */
-
-	E1000_WRITE_REG ( hw, E1000_RDBAL(0), virt_to_bus ( adapter->rx_base ) );
-	E1000_WRITE_REG ( hw, E1000_RDBAH(0), 0 );
-	E1000_WRITE_REG ( hw, E1000_RDLEN(0), adapter->rx_ring_size );
-
-	E1000_WRITE_REG ( hw, E1000_RDH(0), 0 );
-	E1000_WRITE_REG ( hw, E1000_RDT(0), NUM_RX_DESC - 1 );
-
-	/* Enable Receives */
-	rctl |=  E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
-		 E1000_RCTL_MPE | E1000_RCTL_SECRC;
-	E1000_WRITE_REG ( hw, E1000_RCTL, rctl );
-	E1000_WRITE_FLUSH ( hw );
-
-        DBG ( "E1000_RDBAL(0): %#08x\n",  E1000_READ_REG ( hw, E1000_RDBAL(0) ) );
-        DBG ( "E1000_RDLEN(0): %d\n",     E1000_READ_REG ( hw, E1000_RDLEN(0) ) );
-        DBG ( "E1000_RCTL:  %#08x\n",  E1000_READ_REG ( hw, E1000_RCTL ) );
-}
-
-/**
- * e1000_process_rx_packets - process received packets
- *
- * @v netdev	network interface device structure
- **/
-static void e1000_process_rx_packets ( struct net_device *netdev )
-{
-	struct e1000_adapter *adapter = netdev_priv ( netdev );
-	uint32_t i;
-	uint32_t rx_status;
-	uint32_t rx_len;
-	uint32_t rx_err;
-	struct e1000_rx_desc *rx_curr_desc;
-
-	/* Process received packets
-	 */
-	while ( 1 ) {
-
-		i = adapter->rx_curr;
-
-		rx_curr_desc = ( void * )  ( adapter->rx_base ) +
-			          ( i * sizeof ( *adapter->rx_base ) );
-		rx_status = rx_curr_desc->status;
-
-		DBG2 ( "Before DD Check RX_status: %#08x\n", rx_status );
-
-		if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
-			break;
-
-		if ( adapter->rx_iobuf[i] == NULL )
-			break;
-
-		DBG ( "E1000_RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, E1000_RCTL ) );
-
-		rx_len = rx_curr_desc->length;
-
-                DBG ( "Received packet, rx_curr: %d  rx_status: %#08x  rx_len: %d\n",
-                      i, rx_status, rx_len );
-
-                rx_err = rx_curr_desc->errors;
-
-		iob_put ( adapter->rx_iobuf[i], rx_len );
-
-		if ( rx_err & E1000_RXD_ERR_FRAME_ERR_MASK ) {
-
-			netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL );
-			DBG ( "e1000_poll: Corrupted packet received!"
-			      " rx_err: %#08x\n", rx_err );
-		} else {
-			/* Add this packet to the receive queue. */
-			netdev_rx ( netdev, adapter->rx_iobuf[i] );
-		}
-		adapter->rx_iobuf[i] = NULL;
-
-		memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
-
-		adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC;
-	}
-}
-
-/**
- * e1000_reset - Put e1000 NIC in known initial state
- *
- * @v adapter	e1000 private structure
- **/
-void e1000_reset ( struct e1000_adapter *adapter )
-{
-	struct e1000_mac_info *mac = &adapter->hw.mac;
-	u32 pba = 0;
-
-	DBG ( "e1000_reset\n" );
-
-	switch (mac->type) {
-	case e1000_82542:
-	case e1000_82543:
-	case e1000_82544:
-	case e1000_82540:
-	case e1000_82541:
-	case e1000_82541_rev_2:
-		pba = E1000_PBA_48K;
-		break;
-	case e1000_82545:
-	case e1000_82545_rev_3:
-	case e1000_82546:
-	case e1000_82546_rev_3:
-		pba = E1000_PBA_48K;
-		break;
-	case e1000_82547:
-	case e1000_82547_rev_2:
-		pba = E1000_PBA_30K;
-		break;
-	case e1000_undefined:
-	case e1000_num_macs:
-		break;
-	}
-
-	E1000_WRITE_REG ( &adapter->hw, E1000_PBA, pba );
-
-	/* Allow time for pending master requests to run */
-	e1000_reset_hw ( &adapter->hw );
-
-	if ( mac->type >= e1000_82544 )
-		E1000_WRITE_REG ( &adapter->hw, E1000_WUC, 0 );
-
-	if ( e1000_init_hw ( &adapter->hw ) )
-		DBG ( "Hardware Error\n" );
-
-	e1000_reset_adaptive ( &adapter->hw );
-	e1000_get_phy_info ( &adapter->hw );
-
-	e1000_init_manageability ( adapter );
-}
-
-/** Functions that implement the iPXE driver API **/
-
-/**
- * e1000_close - Disables a network interface
- *
- * @v netdev	network interface device structure
- *
- **/
-static void e1000_close ( struct net_device *netdev )
-{
-	struct e1000_adapter *adapter = netdev_priv ( netdev );
-	struct e1000_hw *hw = &adapter->hw;
-	uint32_t rctl;
-
-	DBG ( "e1000_close\n" );
-
-	/* Disable and acknowledge interrupts */
-	e1000_irq_disable ( adapter );
-	E1000_READ_REG ( hw, E1000_ICR );
-
-	/* disable receives */
-	rctl = E1000_READ_REG ( hw, E1000_RCTL );
-	E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN );
-	E1000_WRITE_FLUSH ( hw );
-
-	e1000_reset_hw ( hw );
-
-	e1000_free_tx_resources ( adapter );
-	e1000_free_rx_resources ( adapter );
-}
-
-/**
- * e1000_transmit - Transmit a packet
- *
- * @v netdev	Network device
- * @v iobuf	I/O buffer
- *
- * @ret rc       Returns 0 on success, negative on failure
- */
-static int e1000_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
-{
-	struct e1000_adapter *adapter = netdev_priv( netdev );
-	struct e1000_hw *hw = &adapter->hw;
-	uint32_t tx_curr = adapter->tx_tail;
-	struct e1000_tx_desc *tx_curr_desc;
-
-	DBG ("e1000_transmit\n");
-
-	if ( adapter->tx_fill_ctr == NUM_TX_DESC ) {
-		DBG ("TX overflow\n");
-		return -ENOBUFS;
-	}
-
-	/* Save pointer to iobuf we have been given to transmit,
-	   netdev_tx_complete() will need it later
-	 */
-	adapter->tx_iobuf[tx_curr] = iobuf;
-
-	tx_curr_desc = ( void * ) ( adapter->tx_base ) +
-		       ( tx_curr * sizeof ( *adapter->tx_base ) );
-
-	DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
-	DBG ( "tx_curr_desc + 16 = %#08lx\n", virt_to_bus ( tx_curr_desc ) + 16 );
-	DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) );
-
-	/* Add the packet to TX ring
-	 */
-	tx_curr_desc->buffer_addr =
-		virt_to_bus ( iobuf->data );
-	tx_curr_desc->lower.data =
-		E1000_TXD_CMD_RPS  | E1000_TXD_CMD_EOP |
-		E1000_TXD_CMD_IFCS | iob_len ( iobuf );
-	tx_curr_desc->upper.data = 0;
-
-	DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr,
-	      tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
-
-	/* Point to next free descriptor */
-	adapter->tx_tail = ( adapter->tx_tail + 1 ) % NUM_TX_DESC;
-	adapter->tx_fill_ctr++;
-
-	/* Write new tail to NIC, making packet available for transmit
-	 */
-	wmb();
-	E1000_WRITE_REG ( hw, E1000_TDT(0), adapter->tx_tail );
-
-	return 0;
-}
-
-/**
- * e1000_poll - Poll for received packets
- *
- * @v netdev	Network device
- */
-static void e1000_poll ( struct net_device *netdev )
-{
-	struct e1000_adapter *adapter = netdev_priv( netdev );
-	struct e1000_hw *hw = &adapter->hw;
-
-	uint32_t icr;
-
-	DBGP ( "e1000_poll\n" );
-
-	/* Acknowledge interrupts */
-	icr = E1000_READ_REG ( hw, E1000_ICR );
-	if ( ! icr )
-		return;
-
-        DBG ( "e1000_poll: intr_status = %#08x\n", icr );
-
-	e1000_process_tx_packets ( netdev );
-
-	e1000_process_rx_packets ( netdev );
-
-	e1000_refill_rx_ring(adapter);
-}
-
-/**
- * e1000_irq - enable or Disable interrupts
- *
- * @v adapter   e1000 adapter
- * @v action    requested interrupt action
- **/
-static void e1000_irq ( struct net_device *netdev, int enable )
-{
-	struct e1000_adapter *adapter = netdev_priv ( netdev );
-
-	DBG ( "e1000_irq\n" );
-
-	if ( enable ) {
-		e1000_irq_enable ( adapter );
-	} else {
-		e1000_irq_disable ( adapter );
-	}
-}
-
-static struct net_device_operations e1000_operations;
-
-/**
- * e1000_probe - Initial configuration of e1000 NIC
- *
- * @v pci	PCI device
- * @v id	PCI IDs
- *
- * @ret rc	Return status code
- **/
-int e1000_probe ( struct pci_device *pdev )
-{
-	int i, err;
-	struct net_device *netdev;
-	struct e1000_adapter *adapter;
-	unsigned long mmio_start, mmio_len;
-
-	DBG ( "e1000_probe\n" );
-
-	err = -ENOMEM;
-
-	/* Allocate net device ( also allocates memory for netdev->priv
-	   and makes netdev-priv point to it ) */
-	netdev = alloc_etherdev ( sizeof ( struct e1000_adapter ) );
-	if ( ! netdev )
-		goto err_alloc_etherdev;
-
-	/* Associate e1000-specific network operations operations with
-	 * generic network device layer */
-	netdev_init ( netdev, &e1000_operations );
-
-	/* Associate this network device with given PCI device */
-	pci_set_drvdata ( pdev, netdev );
-	netdev->dev = &pdev->dev;
-
-	/* Initialize driver private storage */
-	adapter = netdev_priv ( netdev );
-        memset ( adapter, 0, ( sizeof ( *adapter ) ) );
-
-	adapter->pdev       = pdev;
-
-	adapter->ioaddr     = pdev->ioaddr;
-        adapter->hw.io_base = pdev->ioaddr;
-
-        adapter->irqno      = pdev->irq;
-	adapter->netdev     = netdev;
-	adapter->hw.back    = adapter;
-
-	adapter->tx_ring_size = sizeof ( *adapter->tx_base ) * NUM_TX_DESC;
-	adapter->rx_ring_size = sizeof ( *adapter->rx_base ) * NUM_RX_DESC;
-
-	mmio_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_0 );
-	mmio_len   = pci_bar_size  ( pdev, PCI_BASE_ADDRESS_0 );
-
-	DBG ( "mmio_start: %#08lx\n", mmio_start );
-	DBG ( "mmio_len: %#08lx\n", mmio_len );
-
-	/* Fix up PCI device */
-	adjust_pci_device ( pdev );
-
-	err = -EIO;
-
-	adapter->hw.hw_addr = ioremap ( mmio_start, mmio_len );
-	DBG ( "adapter->hw.hw_addr: %p\n", adapter->hw.hw_addr );
-
-	if ( ! adapter->hw.hw_addr )
-		goto err_ioremap;
-
-	/* Hardware features, flags and workarounds */
-	if (adapter->hw.mac.type >= e1000_82540) {
-		adapter->flags |= E1000_FLAG_HAS_SMBUS;
-		adapter->flags |= E1000_FLAG_HAS_INTR_MODERATION;
-	}
-
-	if (adapter->hw.mac.type == e1000_82543)
-		adapter->flags |= E1000_FLAG_BAD_TX_CARRIER_STATS_FD;
-
-	adapter->hw.phy.autoneg_wait_to_complete = true;
-	adapter->hw.mac.adaptive_ifs = true;
-
-	/* setup the private structure */
-	if ( ( err = e1000_sw_init ( adapter ) ) )
-		goto err_sw_init;
-
-	if ((err = e1000_init_mac_params(&adapter->hw)))
-		goto err_hw_init;
-
-	if ((err = e1000_init_nvm_params(&adapter->hw)))
-		goto err_hw_init;
-
-        /* Force auto-negotiated speed and duplex */
-        adapter->hw.mac.autoneg = 1;
-
-	if ((err = e1000_init_phy_params(&adapter->hw)))
-		goto err_hw_init;
-
-	DBG ( "adapter->hw.mac.type: %#08x\n", adapter->hw.mac.type );
-
-	/* before reading the EEPROM, reset the controller to
-	 * put the device in a known good starting state
-	 */
-	err = e1000_reset_hw ( &adapter->hw );
-	if ( err < 0 ) {
-		DBG ( "Hardware Initialization Failed\n" );
-		goto err_reset;
-	}
-	/* make sure the NVM is good */
-
-	if ( e1000_validate_nvm_checksum(&adapter->hw) < 0 ) {
-		DBG ( "The NVM Checksum Is Not Valid\n" );
-		err = -EIO;
-		goto err_eeprom;
-	}
-
-	/* copy the MAC address out of the EEPROM */
-	if ( e1000_read_mac_addr ( &adapter->hw ) )
-		DBG ( "EEPROM Read Error\n" );
-
-        memcpy ( netdev->hw_addr, adapter->hw.mac.perm_addr, ETH_ALEN );
-
-	/* reset the hardware with the new settings */
-	e1000_reset ( adapter );
-
-	if ( ( err = register_netdev ( netdev ) ) != 0)
-		goto err_register;
-
-	/* Mark as link up; we don't yet handle link state */
-	netdev_link_up ( netdev );
-
-	for (i = 0; i < 6; i++)
-		DBG ("%02x%s", netdev->ll_addr[i], i == 5 ? "\n" : ":");
-
-	DBG ( "e1000_probe succeeded!\n" );
-
-	/* No errors, return success */
-	return 0;
-
-/* Error return paths */
-err_reset:
-err_register:
-err_hw_init:
-err_eeprom:
-	if (!e1000_check_reset_block(&adapter->hw))
-		e1000_phy_hw_reset(&adapter->hw);
-	if (adapter->hw.flash_address)
-		iounmap(adapter->hw.flash_address);
-err_sw_init:
-	iounmap ( adapter->hw.hw_addr );
-err_ioremap:
-	netdev_put ( netdev );
-err_alloc_etherdev:
-	return err;
-}
-
-/**
- * e1000_remove - Device Removal Routine
- *
- * @v pdev PCI device information struct
- *
- **/
-void e1000_remove ( struct pci_device *pdev )
-{
-	struct net_device *netdev = pci_get_drvdata ( pdev );
-	struct e1000_adapter *adapter = netdev_priv ( netdev );
-
-	DBG ( "e1000_remove\n" );
-
-	if ( adapter->hw.flash_address )
-		iounmap ( adapter->hw.flash_address );
-	if  ( adapter->hw.hw_addr )
-		iounmap ( adapter->hw.hw_addr );
-
-	unregister_netdev ( netdev );
-	e1000_reset_hw ( &adapter->hw );
-	netdev_nullify ( netdev );
-	netdev_put ( netdev );
-}
-
-/**
- * e1000_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 e1000_open ( struct net_device *netdev )
-{
-	struct e1000_adapter *adapter = netdev_priv(netdev);
-	int err;
-
-	DBG ( "e1000_open\n" );
-
-	/* allocate transmit descriptors */
-	err = e1000_setup_tx_resources ( adapter );
-	if ( err ) {
-		DBG ( "Error setting up TX resources!\n" );
-		goto err_setup_tx;
-	}
-
-	/* allocate receive descriptors */
-	err = e1000_setup_rx_resources ( adapter );
-	if ( err ) {
-		DBG ( "Error setting up RX resources!\n" );
-		goto err_setup_rx;
-	}
-
-	e1000_configure_tx ( adapter );
-
-	e1000_configure_rx ( adapter );
-
-        DBG ( "E1000_RXDCTL(0): %#08x\n",  E1000_READ_REG ( &adapter->hw, E1000_RXDCTL(0) ) );
-
-	return 0;
-
-err_setup_rx:
-	e1000_free_tx_resources ( adapter );
-err_setup_tx:
-	e1000_reset ( adapter );
-
-	return err;
-}
-
-/** e1000 net device operations */
-static struct net_device_operations e1000_operations = {
-        .open           = e1000_open,
-        .close          = e1000_close,
-        .transmit       = e1000_transmit,
-        .poll           = e1000_poll,
-        .irq            = e1000_irq,
-};
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_manage.c b/roms/ipxe/src/drivers/net/e1000/e1000_manage.c
deleted file mode 100644
index 3362942e151fc33334dfecb869b37bc4e33758b5..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_manage.c
+++ /dev/null
@@ -1,389 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#if 0
-
-#include "e1000_api.h"
-
-static u8 e1000_calculate_checksum(u8 *buffer, u32 length);
-
-/**
- *  e1000_calculate_checksum - Calculate checksum for buffer
- *  @buffer: pointer to EEPROM
- *  @length: size of EEPROM to calculate a checksum for
- *
- *  Calculates the checksum for some buffer on a specified length.  The
- *  checksum calculated is returned.
- **/
-static u8 e1000_calculate_checksum(u8 *buffer, u32 length)
-{
-	u32 i;
-	u8  sum = 0;
-
-	DEBUGFUNC("e1000_calculate_checksum");
-
-	if (!buffer)
-		return 0;
-
-	for (i = 0; i < length; i++)
-		sum += buffer[i];
-
-	return (u8) (0 - sum);
-}
-
-/**
- *  e1000_mng_enable_host_if_generic - Checks host interface is enabled
- *  @hw: pointer to the HW structure
- *
- *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
- *
- *  This function checks whether the HOST IF is enabled for command operation
- *  and also checks whether the previous command is completed.  It busy waits
- *  in case of previous command is not completed.
- **/
-s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw)
-{
-	u32 hicr;
-	s32 ret_val = E1000_SUCCESS;
-	u8  i;
-
-	DEBUGFUNC("e1000_mng_enable_host_if_generic");
-
-	/* Check that the host interface is enabled. */
-	hicr = E1000_READ_REG(hw, E1000_HICR);
-	if ((hicr & E1000_HICR_EN) == 0) {
-		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
-		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
-		goto out;
-	}
-	/* check the previous command is completed */
-	for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
-		hicr = E1000_READ_REG(hw, E1000_HICR);
-		if (!(hicr & E1000_HICR_C))
-			break;
-		msec_delay_irq(1);
-	}
-
-	if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
-		DEBUGOUT("Previous command timeout failed .\n");
-		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_check_mng_mode_generic - Generic check management mode
- *  @hw: pointer to the HW structure
- *
- *  Reads the firmware semaphore register and returns true (>0) if
- *  manageability is enabled, else false (0).
- **/
-bool e1000_check_mng_mode_generic(struct e1000_hw *hw)
-{
-	u32 fwsm;
-
-	DEBUGFUNC("e1000_check_mng_mode_generic");
-
-	fwsm = E1000_READ_REG(hw, E1000_FWSM);
-
-	return (fwsm & E1000_FWSM_MODE_MASK) ==
-	        (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
-}
-
-/**
- *  e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on TX
- *  @hw: pointer to the HW structure
- *
- *  Enables packet filtering on transmit packets if manageability is enabled
- *  and host interface is enabled.
- **/
-bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
-{
-	struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
-	u32 *buffer = (u32 *)&hw->mng_cookie;
-	u32 offset;
-	s32 ret_val, hdr_csum, csum;
-	u8 i, len;
-	bool tx_filter = true;
-
-	DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic");
-
-	/* No manageability, no filtering */
-	if (!hw->mac.ops.check_mng_mode(hw)) {
-		tx_filter = false;
-		goto out;
-	}
-
-	/*
-	 * If we can't read from the host interface for whatever
-	 * reason, disable filtering.
-	 */
-	ret_val = hw->mac.ops.mng_enable_host_if(hw);
-	if (ret_val != E1000_SUCCESS) {
-		tx_filter = false;
-		goto out;
-	}
-
-	/* Read in the header.  Length and offset are in dwords. */
-	len    = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
-	offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
-	for (i = 0; i < len; i++) {
-		*(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw,
-		                                           E1000_HOST_IF,
-		                                           offset + i);
-	}
-	hdr_csum = hdr->checksum;
-	hdr->checksum = 0;
-	csum = e1000_calculate_checksum((u8 *)hdr,
-	                                E1000_MNG_DHCP_COOKIE_LENGTH);
-	/*
-	 * If either the checksums or signature don't match, then
-	 * the cookie area isn't considered valid, in which case we
-	 * take the safe route of assuming Tx filtering is enabled.
-	 */
-	if (hdr_csum != csum)
-		goto out;
-	if (hdr->signature != E1000_IAMT_SIGNATURE)
-		goto out;
-
-	/* Cookie area is valid, make the final check for filtering. */
-	if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING))
-		tx_filter = false;
-
-out:
-	hw->mac.tx_pkt_filtering = tx_filter;
-	return tx_filter;
-}
-
-/**
- *  e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
- *  @hw: pointer to the HW structure
- *  @buffer: pointer to the host interface
- *  @length: size of the buffer
- *
- *  Writes the DHCP information to the host interface.
- **/
-s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer,
-                                      u16 length)
-{
-	struct e1000_host_mng_command_header hdr;
-	s32 ret_val;
-	u32 hicr;
-
-	DEBUGFUNC("e1000_mng_write_dhcp_info_generic");
-
-	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
-	hdr.command_length = length;
-	hdr.reserved1 = 0;
-	hdr.reserved2 = 0;
-	hdr.checksum = 0;
-
-	/* Enable the host interface */
-	ret_val = hw->mac.ops.mng_enable_host_if(hw);
-	if (ret_val)
-		goto out;
-
-	/* Populate the host interface with the contents of "buffer". */
-	ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
-	                                  sizeof(hdr), &(hdr.checksum));
-	if (ret_val)
-		goto out;
-
-	/* Write the manageability command header */
-	ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
-	if (ret_val)
-		goto out;
-
-	/* Tell the ARC a new command is pending. */
-	hicr = E1000_READ_REG(hw, E1000_HICR);
-	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_mng_write_cmd_header_generic - Writes manageability command header
- *  @hw: pointer to the HW structure
- *  @hdr: pointer to the host interface command header
- *
- *  Writes the command header after does the checksum calculation.
- **/
-s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
-                                    struct e1000_host_mng_command_header *hdr)
-{
-	u16 i, length = sizeof(struct e1000_host_mng_command_header);
-
-	DEBUGFUNC("e1000_mng_write_cmd_header_generic");
-
-	/* Write the whole command header structure with new checksum. */
-
-	hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
-
-	length >>= 2;
-	/* Write the relevant command block into the ram area. */
-	for (i = 0; i < length; i++) {
-		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
-		                            *((u32 *) hdr + i));
-		E1000_WRITE_FLUSH(hw);
-	}
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_mng_host_if_write_generic - Write to the manageability host interface
- *  @hw: pointer to the HW structure
- *  @buffer: pointer to the host interface buffer
- *  @length: size of the buffer
- *  @offset: location in the buffer to write to
- *  @sum: sum of the data (not checksum)
- *
- *  This function writes the buffer content at the offset given on the host if.
- *  It also does alignment considerations to do the writes in most efficient
- *  way.  Also fills up the sum of the buffer in *buffer parameter.
- **/
-s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
-                                    u16 length, u16 offset, u8 *sum)
-{
-	u8 *tmp;
-	u8 *bufptr = buffer;
-	u32 data = 0;
-	s32 ret_val = E1000_SUCCESS;
-	u16 remaining, i, j, prev_bytes;
-
-	DEBUGFUNC("e1000_mng_host_if_write_generic");
-
-	/* sum = only sum of the data and it is not checksum */
-
-	if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
-		ret_val = -E1000_ERR_PARAM;
-		goto out;
-	}
-
-	tmp = (u8 *)&data;
-	prev_bytes = offset & 0x3;
-	offset >>= 2;
-
-	if (prev_bytes) {
-		data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
-		for (j = prev_bytes; j < sizeof(u32); j++) {
-			*(tmp + j) = *bufptr++;
-			*sum += *(tmp + j);
-		}
-		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
-		length -= j - prev_bytes;
-		offset++;
-	}
-
-	remaining = length & 0x3;
-	length -= remaining;
-
-	/* Calculate length in DWORDs */
-	length >>= 2;
-
-	/*
-	 * The device driver writes the relevant command block into the
-	 * ram area.
-	 */
-	for (i = 0; i < length; i++) {
-		for (j = 0; j < sizeof(u32); j++) {
-			*(tmp + j) = *bufptr++;
-			*sum += *(tmp + j);
-		}
-
-		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
-		                            data);
-	}
-	if (remaining) {
-		for (j = 0; j < sizeof(u32); j++) {
-			if (j < remaining)
-				*(tmp + j) = *bufptr++;
-			else
-				*(tmp + j) = 0;
-
-			*sum += *(tmp + j);
-		}
-		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_enable_mng_pass_thru - Enable processing of ARP's
- *  @hw: pointer to the HW structure
- *
- *  Verifies the hardware needs to allow ARPs to be processed by the host.
- **/
-bool e1000_enable_mng_pass_thru(struct e1000_hw *hw)
-{
-	u32 manc;
-	u32 fwsm, factps;
-	bool ret_val = false;
-
-	DEBUGFUNC("e1000_enable_mng_pass_thru");
-
-	if (!hw->mac.asf_firmware_present)
-		goto out;
-
-	manc = E1000_READ_REG(hw, E1000_MANC);
-
-	if (!(manc & E1000_MANC_RCV_TCO_EN) ||
-	    !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
-		goto out;
-
-	if (hw->mac.arc_subsystem_valid) {
-		fwsm = E1000_READ_REG(hw, E1000_FWSM);
-		factps = E1000_READ_REG(hw, E1000_FACTPS);
-
-		if (!(factps & E1000_FACTPS_MNGCG) &&
-		    ((fwsm & E1000_FWSM_MODE_MASK) ==
-		     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
-			ret_val = true;
-			goto out;
-		}
-	} else {
-		if ((manc & E1000_MANC_SMBUS_EN) &&
-		    !(manc & E1000_MANC_ASF_EN)) {
-			ret_val = true;
-			goto out;
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_manage.h b/roms/ipxe/src/drivers/net/e1000/e1000_manage.h
deleted file mode 100644
index 14467aa6ca7d8dd6eebc610c534f7ce0cf4abbc0..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_manage.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000_MANAGE_H_
-#define _E1000_MANAGE_H_
-
-bool e1000_check_mng_mode_generic(struct e1000_hw *hw);
-bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw);
-s32  e1000_mng_enable_host_if_generic(struct e1000_hw *hw);
-s32  e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
-                                     u16 length, u16 offset, u8 *sum);
-s32  e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
-                                    struct e1000_host_mng_command_header *hdr);
-s32  e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw,
-                                       u8 *buffer, u16 length);
-bool e1000_enable_mng_pass_thru(struct e1000_hw *hw);
-
-enum e1000_mng_mode {
-	e1000_mng_mode_none = 0,
-	e1000_mng_mode_asf,
-	e1000_mng_mode_pt,
-	e1000_mng_mode_ipmi,
-	e1000_mng_mode_host_if_only
-};
-
-#define E1000_FACTPS_MNGCG    0x20000000
-
-#define E1000_FWSM_MODE_MASK  0xE
-#define E1000_FWSM_MODE_SHIFT 1
-
-#define E1000_MNG_IAMT_MODE                  0x3
-#define E1000_MNG_DHCP_COOKIE_LENGTH         0x10
-#define E1000_MNG_DHCP_COOKIE_OFFSET         0x6F0
-#define E1000_MNG_DHCP_COMMAND_TIMEOUT       10
-#define E1000_MNG_DHCP_TX_PAYLOAD_CMD        64
-#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1
-#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN    0x2
-
-#define E1000_VFTA_ENTRY_SHIFT               5
-#define E1000_VFTA_ENTRY_MASK                0x7F
-#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK      0x1F
-
-#define E1000_HI_MAX_BLOCK_BYTE_LENGTH       1792 /* Num of bytes in range */
-#define E1000_HI_MAX_BLOCK_DWORD_LENGTH      448 /* Num of dwords in range */
-#define E1000_HI_COMMAND_TIMEOUT             500 /* Process HI command limit */
-
-#define E1000_HICR_EN              0x01  /* Enable bit - RO */
-/* Driver sets this bit when done to put command in RAM */
-#define E1000_HICR_C               0x02
-#define E1000_HICR_SV              0x04  /* Status Validity */
-#define E1000_HICR_FW_RESET_ENABLE 0x40
-#define E1000_HICR_FW_RESET        0x80
-
-/* Intel(R) Active Management Technology signature */
-#define E1000_IAMT_SIGNATURE  0x544D4149
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_nvm.c b/roms/ipxe/src/drivers/net/e1000/e1000_nvm.c
deleted file mode 100644
index 488252f4261da9d23c13bb96240f441c229a4e04..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_nvm.c
+++ /dev/null
@@ -1,923 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include "e1000_api.h"
-
-static void e1000_reload_nvm_generic(struct e1000_hw *hw);
-
-/**
- *  e1000_init_nvm_ops_generic - Initialize NVM function pointers
- *  @hw: pointer to the HW structure
- *
- *  Setups up the function pointers to no-op functions
- **/
-void e1000_init_nvm_ops_generic(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	DEBUGFUNC("e1000_init_nvm_ops_generic");
-
-	/* Initialize function pointers */
-	nvm->ops.init_params = e1000_null_ops_generic;
-	nvm->ops.acquire = e1000_null_ops_generic;
-	nvm->ops.read = e1000_null_read_nvm;
-	nvm->ops.release = e1000_null_nvm_generic;
-	nvm->ops.reload = e1000_reload_nvm_generic;
-	nvm->ops.update = e1000_null_ops_generic;
-	nvm->ops.valid_led_default = e1000_null_led_default;
-	nvm->ops.validate = e1000_null_ops_generic;
-	nvm->ops.write = e1000_null_write_nvm;
-}
-
-/**
- *  e1000_null_nvm_read - No-op function, return 0
- *  @hw: pointer to the HW structure
- **/
-s32 e1000_null_read_nvm(struct e1000_hw *hw __unused, u16 a __unused,
-                        u16 b __unused, u16 *c __unused)
-{
-	DEBUGFUNC("e1000_null_read_nvm");
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_null_nvm_generic - No-op function, return void
- *  @hw: pointer to the HW structure
- **/
-void e1000_null_nvm_generic(struct e1000_hw *hw __unused)
-{
-	DEBUGFUNC("e1000_null_nvm_generic");
-	return;
-}
-
-/**
- *  e1000_null_led_default - No-op function, return 0
- *  @hw: pointer to the HW structure
- **/
-s32 e1000_null_led_default(struct e1000_hw *hw __unused,
-                           u16 *data __unused)
-{
-	DEBUGFUNC("e1000_null_led_default");
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_null_write_nvm - No-op function, return 0
- *  @hw: pointer to the HW structure
- **/
-s32 e1000_null_write_nvm(struct e1000_hw *hw __unused, u16 a __unused,
-                         u16 b __unused, u16 *c __unused)
-{
-	DEBUGFUNC("e1000_null_write_nvm");
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_raise_eec_clk - Raise EEPROM clock
- *  @hw: pointer to the HW structure
- *  @eecd: pointer to the EEPROM
- *
- *  Enable/Raise the EEPROM clock bit.
- **/
-static void e1000_raise_eec_clk(struct e1000_hw *hw, u32 *eecd)
-{
-	*eecd = *eecd | E1000_EECD_SK;
-	E1000_WRITE_REG(hw, E1000_EECD, *eecd);
-	E1000_WRITE_FLUSH(hw);
-	usec_delay(hw->nvm.delay_usec);
-}
-
-/**
- *  e1000_lower_eec_clk - Lower EEPROM clock
- *  @hw: pointer to the HW structure
- *  @eecd: pointer to the EEPROM
- *
- *  Clear/Lower the EEPROM clock bit.
- **/
-static void e1000_lower_eec_clk(struct e1000_hw *hw, u32 *eecd)
-{
-	*eecd = *eecd & ~E1000_EECD_SK;
-	E1000_WRITE_REG(hw, E1000_EECD, *eecd);
-	E1000_WRITE_FLUSH(hw);
-	usec_delay(hw->nvm.delay_usec);
-}
-
-/**
- *  e1000_shift_out_eec_bits - Shift data bits our to the EEPROM
- *  @hw: pointer to the HW structure
- *  @data: data to send to the EEPROM
- *  @count: number of bits to shift out
- *
- *  We need to shift 'count' bits out to the EEPROM.  So, the value in the
- *  "data" parameter will be shifted out to the EEPROM one bit at a time.
- *  In order to do this, "data" must be broken down into bits.
- **/
-static void e1000_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
-	u32 mask;
-
-	DEBUGFUNC("e1000_shift_out_eec_bits");
-
-	mask = 0x01 << (count - 1);
-	if (nvm->type == e1000_nvm_eeprom_microwire)
-		eecd &= ~E1000_EECD_DO;
-	else
-	if (nvm->type == e1000_nvm_eeprom_spi)
-		eecd |= E1000_EECD_DO;
-
-	do {
-		eecd &= ~E1000_EECD_DI;
-
-		if (data & mask)
-			eecd |= E1000_EECD_DI;
-
-		E1000_WRITE_REG(hw, E1000_EECD, eecd);
-		E1000_WRITE_FLUSH(hw);
-
-		usec_delay(nvm->delay_usec);
-
-		e1000_raise_eec_clk(hw, &eecd);
-		e1000_lower_eec_clk(hw, &eecd);
-
-		mask >>= 1;
-	} while (mask);
-
-	eecd &= ~E1000_EECD_DI;
-	E1000_WRITE_REG(hw, E1000_EECD, eecd);
-}
-
-/**
- *  e1000_shift_in_eec_bits - Shift data bits in from the EEPROM
- *  @hw: pointer to the HW structure
- *  @count: number of bits to shift in
- *
- *  In order to read a register from the EEPROM, we need to shift 'count' bits
- *  in from the EEPROM.  Bits are "shifted in" by raising the clock input to
- *  the EEPROM (setting the SK bit), and then reading the value of the data out
- *  "DO" bit.  During this "shifting in" process the data in "DI" bit should
- *  always be clear.
- **/
-static u16 e1000_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
-{
-	u32 eecd;
-	u32 i;
-	u16 data;
-
-	DEBUGFUNC("e1000_shift_in_eec_bits");
-
-	eecd = E1000_READ_REG(hw, E1000_EECD);
-
-	eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
-	data = 0;
-
-	for (i = 0; i < count; i++) {
-		data <<= 1;
-		e1000_raise_eec_clk(hw, &eecd);
-
-		eecd = E1000_READ_REG(hw, E1000_EECD);
-
-		eecd &= ~E1000_EECD_DI;
-		if (eecd & E1000_EECD_DO)
-			data |= 1;
-
-		e1000_lower_eec_clk(hw, &eecd);
-	}
-
-	return data;
-}
-
-/**
- *  e1000_poll_eerd_eewr_done - Poll for EEPROM read/write completion
- *  @hw: pointer to the HW structure
- *  @ee_reg: EEPROM flag for polling
- *
- *  Polls the EEPROM status bit for either read or write completion based
- *  upon the value of 'ee_reg'.
- **/
-s32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
-{
-	u32 attempts = 100000;
-	u32 i, reg = 0;
-	s32 ret_val = -E1000_ERR_NVM;
-
-	DEBUGFUNC("e1000_poll_eerd_eewr_done");
-
-	for (i = 0; i < attempts; i++) {
-		if (ee_reg == E1000_NVM_POLL_READ)
-			reg = E1000_READ_REG(hw, E1000_EERD);
-		else
-			reg = E1000_READ_REG(hw, E1000_EEWR);
-
-		if (reg & E1000_NVM_RW_REG_DONE) {
-			ret_val = E1000_SUCCESS;
-			break;
-		}
-
-		usec_delay(5);
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000_acquire_nvm_generic - Generic request for access to EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
- *  Return successful if access grant bit set, else clear the request for
- *  EEPROM access and return -E1000_ERR_NVM (-1).
- **/
-s32 e1000_acquire_nvm_generic(struct e1000_hw *hw)
-{
-	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
-	s32 timeout = E1000_NVM_GRANT_ATTEMPTS;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_acquire_nvm_generic");
-
-	E1000_WRITE_REG(hw, E1000_EECD, eecd | E1000_EECD_REQ);
-	eecd = E1000_READ_REG(hw, E1000_EECD);
-
-	while (timeout) {
-		if (eecd & E1000_EECD_GNT)
-			break;
-		usec_delay(5);
-		eecd = E1000_READ_REG(hw, E1000_EECD);
-		timeout--;
-	}
-
-	if (!timeout) {
-		eecd &= ~E1000_EECD_REQ;
-		E1000_WRITE_REG(hw, E1000_EECD, eecd);
-		DEBUGOUT("Could not acquire NVM grant\n");
-		ret_val = -E1000_ERR_NVM;
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000_standby_nvm - Return EEPROM to standby state
- *  @hw: pointer to the HW structure
- *
- *  Return the EEPROM to a standby state.
- **/
-static void e1000_standby_nvm(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
-
-	DEBUGFUNC("e1000_standby_nvm");
-
-	if (nvm->type == e1000_nvm_eeprom_microwire) {
-		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
-		E1000_WRITE_REG(hw, E1000_EECD, eecd);
-		E1000_WRITE_FLUSH(hw);
-		usec_delay(nvm->delay_usec);
-
-		e1000_raise_eec_clk(hw, &eecd);
-
-		/* Select EEPROM */
-		eecd |= E1000_EECD_CS;
-		E1000_WRITE_REG(hw, E1000_EECD, eecd);
-		E1000_WRITE_FLUSH(hw);
-		usec_delay(nvm->delay_usec);
-
-		e1000_lower_eec_clk(hw, &eecd);
-	} else
-	if (nvm->type == e1000_nvm_eeprom_spi) {
-		/* Toggle CS to flush commands */
-		eecd |= E1000_EECD_CS;
-		E1000_WRITE_REG(hw, E1000_EECD, eecd);
-		E1000_WRITE_FLUSH(hw);
-		usec_delay(nvm->delay_usec);
-		eecd &= ~E1000_EECD_CS;
-		E1000_WRITE_REG(hw, E1000_EECD, eecd);
-		E1000_WRITE_FLUSH(hw);
-		usec_delay(nvm->delay_usec);
-	}
-}
-
-/**
- *  e1000_stop_nvm - Terminate EEPROM command
- *  @hw: pointer to the HW structure
- *
- *  Terminates the current command by inverting the EEPROM's chip select pin.
- **/
-void e1000_stop_nvm(struct e1000_hw *hw)
-{
-	u32 eecd;
-
-	DEBUGFUNC("e1000_stop_nvm");
-
-	eecd = E1000_READ_REG(hw, E1000_EECD);
-	if (hw->nvm.type == e1000_nvm_eeprom_spi) {
-		/* Pull CS high */
-		eecd |= E1000_EECD_CS;
-		e1000_lower_eec_clk(hw, &eecd);
-	} else if (hw->nvm.type == e1000_nvm_eeprom_microwire) {
-		/* CS on Microwire is active-high */
-		eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
-		E1000_WRITE_REG(hw, E1000_EECD, eecd);
-		e1000_raise_eec_clk(hw, &eecd);
-		e1000_lower_eec_clk(hw, &eecd);
-	}
-}
-
-/**
- *  e1000_release_nvm_generic - Release exclusive access to EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
- **/
-void e1000_release_nvm_generic(struct e1000_hw *hw)
-{
-	u32 eecd;
-
-	DEBUGFUNC("e1000_release_nvm_generic");
-
-	e1000_stop_nvm(hw);
-
-	eecd = E1000_READ_REG(hw, E1000_EECD);
-	eecd &= ~E1000_EECD_REQ;
-	E1000_WRITE_REG(hw, E1000_EECD, eecd);
-}
-
-/**
- *  e1000_ready_nvm_eeprom - Prepares EEPROM for read/write
- *  @hw: pointer to the HW structure
- *
- *  Setups the EEPROM for reading and writing.
- **/
-static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
-	s32 ret_val = E1000_SUCCESS;
-	u16 timeout = 0;
-	u8 spi_stat_reg;
-
-	DEBUGFUNC("e1000_ready_nvm_eeprom");
-
-	if (nvm->type == e1000_nvm_eeprom_microwire) {
-		/* Clear SK and DI */
-		eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
-		E1000_WRITE_REG(hw, E1000_EECD, eecd);
-		/* Set CS */
-		eecd |= E1000_EECD_CS;
-		E1000_WRITE_REG(hw, E1000_EECD, eecd);
-	} else
-	if (nvm->type == e1000_nvm_eeprom_spi) {
-		/* Clear SK and CS */
-		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
-		E1000_WRITE_REG(hw, E1000_EECD, eecd);
-		usec_delay(1);
-		timeout = NVM_MAX_RETRY_SPI;
-
-		/*
-		 * Read "Status Register" repeatedly until the LSB is cleared.
-		 * The EEPROM will signal that the command has been completed
-		 * by clearing bit 0 of the internal status register.  If it's
-		 * not cleared within 'timeout', then error out.
-		 */
-		while (timeout) {
-			e1000_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
-			                         hw->nvm.opcode_bits);
-			spi_stat_reg = (u8)e1000_shift_in_eec_bits(hw, 8);
-			if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
-				break;
-
-			usec_delay(5);
-			e1000_standby_nvm(hw);
-			timeout--;
-		}
-
-		if (!timeout) {
-			DEBUGOUT("SPI NVM Status error\n");
-			ret_val = -E1000_ERR_NVM;
-			goto out;
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_read_nvm_spi - Read EEPROM's using SPI
- *  @hw: pointer to the HW structure
- *  @offset: offset of word in the EEPROM to read
- *  @words: number of words to read
- *  @data: word read from the EEPROM
- *
- *  Reads a 16 bit word from the EEPROM.
- **/
-s32 e1000_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 i = 0;
-	s32 ret_val;
-	u16 word_in;
-	u8 read_opcode = NVM_READ_OPCODE_SPI;
-
-	DEBUGFUNC("e1000_read_nvm_spi");
-
-	/*
-	 * A check for invalid values:  offset too large, too many words,
-	 * and not enough words.
-	 */
-	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
-	    (words == 0)) {
-		DEBUGOUT("nvm parameter(s) out of bounds\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	ret_val = nvm->ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000_ready_nvm_eeprom(hw);
-	if (ret_val)
-		goto release;
-
-	e1000_standby_nvm(hw);
-
-	if ((nvm->address_bits == 8) && (offset >= 128))
-		read_opcode |= NVM_A8_OPCODE_SPI;
-
-	/* Send the READ command (opcode + addr) */
-	e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits);
-	e1000_shift_out_eec_bits(hw, (u16)(offset*2), nvm->address_bits);
-
-	/*
-	 * Read the data.  SPI NVMs increment the address with each byte
-	 * read and will roll over if reading beyond the end.  This allows
-	 * us to read the whole NVM from any offset
-	 */
-	for (i = 0; i < words; i++) {
-		word_in = e1000_shift_in_eec_bits(hw, 16);
-		data[i] = (word_in >> 8) | (word_in << 8);
-	}
-
-release:
-	nvm->ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_read_nvm_microwire - Reads EEPROM's using microwire
- *  @hw: pointer to the HW structure
- *  @offset: offset of word in the EEPROM to read
- *  @words: number of words to read
- *  @data: word read from the EEPROM
- *
- *  Reads a 16 bit word from the EEPROM.
- **/
-s32 e1000_read_nvm_microwire(struct e1000_hw *hw, u16 offset, u16 words,
-                             u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 i = 0;
-	s32 ret_val;
-	u8 read_opcode = NVM_READ_OPCODE_MICROWIRE;
-
-	DEBUGFUNC("e1000_read_nvm_microwire");
-
-	/*
-	 * A check for invalid values:  offset too large, too many words,
-	 * and not enough words.
-	 */
-	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
-	    (words == 0)) {
-		DEBUGOUT("nvm parameter(s) out of bounds\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	ret_val = nvm->ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000_ready_nvm_eeprom(hw);
-	if (ret_val)
-		goto release;
-
-	for (i = 0; i < words; i++) {
-		/* Send the READ command (opcode + addr) */
-		e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits);
-		e1000_shift_out_eec_bits(hw, (u16)(offset + i),
-					nvm->address_bits);
-
-		/*
-		 * Read the data.  For microwire, each word requires the
-		 * overhead of setup and tear-down.
-		 */
-		data[i] = e1000_shift_in_eec_bits(hw, 16);
-		e1000_standby_nvm(hw);
-	}
-
-release:
-	nvm->ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_read_nvm_eerd - Reads EEPROM using EERD register
- *  @hw: pointer to the HW structure
- *  @offset: offset of word in the EEPROM to read
- *  @words: number of words to read
- *  @data: word read from the EEPROM
- *
- *  Reads a 16 bit word from the EEPROM using the EERD register.
- **/
-s32 e1000_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 i, eerd = 0;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_read_nvm_eerd");
-
-	/*
-	 * A check for invalid values:  offset too large, too many words,
-	 * too many words for the offset, and not enough words.
-	 */
-	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
-	    (words == 0)) {
-		DEBUGOUT("nvm parameter(s) out of bounds\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	for (i = 0; i < words; i++) {
-		eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
-		       E1000_NVM_RW_REG_START;
-
-		E1000_WRITE_REG(hw, E1000_EERD, eerd);
-		ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
-		if (ret_val)
-			break;
-
-		data[i] = (E1000_READ_REG(hw, E1000_EERD) >>
-		           E1000_NVM_RW_REG_DATA);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_write_nvm_spi - Write to EEPROM using SPI
- *  @hw: pointer to the HW structure
- *  @offset: offset within the EEPROM to be written to
- *  @words: number of words to write
- *  @data: 16 bit word(s) to be written to the EEPROM
- *
- *  Writes data to EEPROM at offset using SPI interface.
- *
- *  If e1000_update_nvm_checksum is not called after this function , the
- *  EEPROM will most likely contain an invalid checksum.
- **/
-s32 e1000_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	s32 ret_val;
-	u16 widx = 0;
-
-	DEBUGFUNC("e1000_write_nvm_spi");
-
-	/*
-	 * A check for invalid values:  offset too large, too many words,
-	 * and not enough words.
-	 */
-	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
-	    (words == 0)) {
-		DEBUGOUT("nvm parameter(s) out of bounds\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	ret_val = nvm->ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	while (widx < words) {
-		u8 write_opcode = NVM_WRITE_OPCODE_SPI;
-
-		ret_val = e1000_ready_nvm_eeprom(hw);
-		if (ret_val)
-			goto release;
-
-		e1000_standby_nvm(hw);
-
-		/* Send the WRITE ENABLE command (8 bit opcode) */
-		e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
-		                         nvm->opcode_bits);
-
-		e1000_standby_nvm(hw);
-
-		/*
-		 * Some SPI eeproms use the 8th address bit embedded in the
-		 * opcode
-		 */
-		if ((nvm->address_bits == 8) && (offset >= 128))
-			write_opcode |= NVM_A8_OPCODE_SPI;
-
-		/* Send the Write command (8-bit opcode + addr) */
-		e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
-		e1000_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
-		                         nvm->address_bits);
-
-		/* Loop to allow for up to whole page write of eeprom */
-		while (widx < words) {
-			u16 word_out = data[widx];
-			word_out = (word_out >> 8) | (word_out << 8);
-			e1000_shift_out_eec_bits(hw, word_out, 16);
-			widx++;
-
-			if ((((offset + widx) * 2) % nvm->page_size) == 0) {
-				e1000_standby_nvm(hw);
-				break;
-			}
-		}
-	}
-
-	msec_delay(10);
-release:
-	nvm->ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_write_nvm_microwire - Writes EEPROM using microwire
- *  @hw: pointer to the HW structure
- *  @offset: offset within the EEPROM to be written to
- *  @words: number of words to write
- *  @data: 16 bit word(s) to be written to the EEPROM
- *
- *  Writes data to EEPROM at offset using microwire interface.
- *
- *  If e1000_update_nvm_checksum is not called after this function , the
- *  EEPROM will most likely contain an invalid checksum.
- **/
-s32 e1000_write_nvm_microwire(struct e1000_hw *hw, u16 offset, u16 words,
-                              u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	s32  ret_val;
-	u32 eecd;
-	u16 words_written = 0;
-	u16 widx = 0;
-
-	DEBUGFUNC("e1000_write_nvm_microwire");
-
-	/*
-	 * A check for invalid values:  offset too large, too many words,
-	 * and not enough words.
-	 */
-	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
-	    (words == 0)) {
-		DEBUGOUT("nvm parameter(s) out of bounds\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	ret_val = nvm->ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000_ready_nvm_eeprom(hw);
-	if (ret_val)
-		goto release;
-
-	e1000_shift_out_eec_bits(hw, NVM_EWEN_OPCODE_MICROWIRE,
-	                         (u16)(nvm->opcode_bits + 2));
-
-	e1000_shift_out_eec_bits(hw, 0, (u16)(nvm->address_bits - 2));
-
-	e1000_standby_nvm(hw);
-
-	while (words_written < words) {
-		e1000_shift_out_eec_bits(hw, NVM_WRITE_OPCODE_MICROWIRE,
-		                         nvm->opcode_bits);
-
-		e1000_shift_out_eec_bits(hw, (u16)(offset + words_written),
-		                         nvm->address_bits);
-
-		e1000_shift_out_eec_bits(hw, data[words_written], 16);
-
-		e1000_standby_nvm(hw);
-
-		for (widx = 0; widx < 200; widx++) {
-			eecd = E1000_READ_REG(hw, E1000_EECD);
-			if (eecd & E1000_EECD_DO)
-				break;
-			usec_delay(50);
-		}
-
-		if (widx == 200) {
-			DEBUGOUT("NVM Write did not complete\n");
-			ret_val = -E1000_ERR_NVM;
-			goto release;
-		}
-
-		e1000_standby_nvm(hw);
-
-		words_written++;
-	}
-
-	e1000_shift_out_eec_bits(hw, NVM_EWDS_OPCODE_MICROWIRE,
-	                         (u16)(nvm->opcode_bits + 2));
-
-	e1000_shift_out_eec_bits(hw, 0, (u16)(nvm->address_bits - 2));
-
-release:
-	nvm->ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_read_pba_num_generic - Read device part number
- *  @hw: pointer to the HW structure
- *  @pba_num: pointer to device part number
- *
- *  Reads the product board assembly (PBA) number from the EEPROM and stores
- *  the value in pba_num.
- **/
-s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num)
-{
-	s32  ret_val;
-	u16 nvm_data;
-
-	DEBUGFUNC("e1000_read_pba_num_generic");
-
-	ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
-	if (ret_val) {
-		DEBUGOUT("NVM Read Error\n");
-		goto out;
-	}
-	*pba_num = (u32)(nvm_data << 16);
-
-	ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
-	if (ret_val) {
-		DEBUGOUT("NVM Read Error\n");
-		goto out;
-	}
-	*pba_num |= nvm_data;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_read_mac_addr_generic - Read device MAC address
- *  @hw: pointer to the HW structure
- *
- *  Reads the device MAC address from the EEPROM and stores the value.
- *  Since devices with two ports use the same EEPROM, we increment the
- *  last bit in the MAC address for the second port.
- **/
-s32 e1000_read_mac_addr_generic(struct e1000_hw *hw)
-{
-	u32 rar_high;
-	u32 rar_low;
-	u16 i;
-
-	rar_high = E1000_READ_REG(hw, E1000_RAH(0));
-	rar_low = E1000_READ_REG(hw, E1000_RAL(0));
-
-	for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++)
-		hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8));
-
-	for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
-		hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8));
-
-	for (i = 0; i < ETH_ADDR_LEN; i++)
-		hw->mac.addr[i] = hw->mac.perm_addr[i];
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_validate_nvm_checksum_generic - Validate EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
- *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
- **/
-s32 e1000_validate_nvm_checksum_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 checksum = 0;
-	u16 i, nvm_data;
-
-	DEBUGFUNC("e1000_validate_nvm_checksum_generic");
-
-	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
-		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
-		if (ret_val) {
-			DEBUGOUT("NVM Read Error\n");
-			goto out;
-		}
-		checksum += nvm_data;
-	}
-
-	if (checksum != (u16) NVM_SUM) {
-		DEBUGOUT("NVM Checksum Invalid\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_update_nvm_checksum_generic - Update EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
- *  up to the checksum.  Then calculates the EEPROM checksum and writes the
- *  value to the EEPROM.
- **/
-s32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw)
-{
-	s32  ret_val;
-	u16 checksum = 0;
-	u16 i, nvm_data;
-
-	DEBUGFUNC("e1000_update_nvm_checksum");
-
-	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
-		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
-		if (ret_val) {
-			DEBUGOUT("NVM Read Error while updating checksum.\n");
-			goto out;
-		}
-		checksum += nvm_data;
-	}
-	checksum = (u16) NVM_SUM - checksum;
-	ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
-	if (ret_val)
-		DEBUGOUT("NVM Write Error while updating checksum.\n");
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_reload_nvm_generic - Reloads EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
- *  extended control register.
- **/
-static void e1000_reload_nvm_generic(struct e1000_hw *hw)
-{
-	u32 ctrl_ext;
-
-	DEBUGFUNC("e1000_reload_nvm_generic");
-
-	usec_delay(10);
-	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
-	ctrl_ext |= E1000_CTRL_EXT_EE_RST;
-	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
-	E1000_WRITE_FLUSH(hw);
-}
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_nvm.h b/roms/ipxe/src/drivers/net/e1000/e1000_nvm.h
deleted file mode 100644
index 1585417cf032d2220abefb2cd3f6865f37b90adf..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_nvm.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000_NVM_H_
-#define _E1000_NVM_H_
-
-void e1000_init_nvm_ops_generic(struct e1000_hw *hw);
-s32  e1000_null_read_nvm(struct e1000_hw *hw, u16 a, u16 b, u16 *c);
-void e1000_null_nvm_generic(struct e1000_hw *hw);
-s32  e1000_null_led_default(struct e1000_hw *hw, u16 *data);
-s32  e1000_null_write_nvm(struct e1000_hw *hw, u16 a, u16 b, u16 *c);
-s32  e1000_acquire_nvm_generic(struct e1000_hw *hw);
-
-s32  e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
-s32  e1000_read_mac_addr_generic(struct e1000_hw *hw);
-s32  e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num);
-s32  e1000_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
-s32  e1000_read_nvm_microwire(struct e1000_hw *hw, u16 offset,
-                              u16 words, u16 *data);
-s32  e1000_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words,
-                         u16 *data);
-s32  e1000_valid_led_default_generic(struct e1000_hw *hw, u16 *data);
-s32  e1000_validate_nvm_checksum_generic(struct e1000_hw *hw);
-s32  e1000_write_nvm_eewr(struct e1000_hw *hw, u16 offset,
-                          u16 words, u16 *data);
-s32  e1000_write_nvm_microwire(struct e1000_hw *hw, u16 offset,
-                               u16 words, u16 *data);
-s32  e1000_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words,
-                         u16 *data);
-s32  e1000_update_nvm_checksum_generic(struct e1000_hw *hw);
-void e1000_stop_nvm(struct e1000_hw *hw);
-void e1000_release_nvm_generic(struct e1000_hw *hw);
-
-#define E1000_STM_OPCODE  0xDB00
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_osdep.h b/roms/ipxe/src/drivers/net/e1000/e1000_osdep.h
deleted file mode 100644
index 5cd8e39103a34c5c11fa5d39b50bdec6e1000d49..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_osdep.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/* glue for the OS-dependent part of e1000
- * includes register access macros
- */
-
-#ifndef _E1000_OSDEP_H_
-#define _E1000_OSDEP_H_
-
-#define u8         unsigned char
-#define bool       boolean_t
-#define dma_addr_t unsigned long
-#define __le16     uint16_t
-#define __le32     uint32_t
-#define __le64     uint64_t
-
-#define __iomem
-
-#define ETH_FCS_LEN 4
-
-typedef int spinlock_t;
-typedef enum {
-    false = 0,
-    true = 1
-} boolean_t;
-
-#define usec_delay(x) udelay(x)
-#define msec_delay(x) mdelay(x)
-#define msec_delay_irq(x) mdelay(x)
-
-#define PCI_COMMAND_REGISTER   PCI_COMMAND
-#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
-#define ETH_ADDR_LEN           ETH_ALEN
-
-#define DEBUGFUNC(F) DBG(F "\n")
-
-#define DEBUGOUT(S)             DBG(S)
-#define DEBUGOUT1(S, A...)      DBG(S, A)
-
-#define DEBUGOUT2 DEBUGOUT1
-#define DEBUGOUT3 DEBUGOUT2
-#define DEBUGOUT7 DEBUGOUT3
-
-#define E1000_REGISTER(a, reg) (((a)->mac.type >= e1000_82543) \
-                               ? reg                           \
-                               : e1000_translate_register_82542(reg))
-
-#define E1000_WRITE_REG(a, reg, value) \
-    writel((value), ((a)->hw_addr + E1000_REGISTER(a, reg)))
-
-#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + E1000_REGISTER(a, reg)))
-
-#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \
-    writel((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 2)))
-
-#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
-    readl((a)->hw_addr + E1000_REGISTER(a, reg) + ((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) ( \
-    writew((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 1))))
-
-#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \
-    readw((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 1)))
-
-#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \
-    writeb((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + (offset))))
-
-#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \
-    readb((a)->hw_addr + E1000_REGISTER(a, reg) + (offset)))
-
-#define E1000_WRITE_REG_IO(a, reg, offset) do { \
-    outl(reg, ((a)->io_base));                  \
-    outl(offset, ((a)->io_base + 4));      } while(0)
-
-#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, E1000_STATUS)
-
-#define E1000_WRITE_FLASH_REG(a, reg, value) ( \
-    writel((value), ((a)->flash_address + reg)))
-
-#define E1000_WRITE_FLASH_REG16(a, reg, value) ( \
-    writew((value), ((a)->flash_address + reg)))
-
-#define E1000_READ_FLASH_REG(a, reg) (readl((a)->flash_address + reg))
-
-#define E1000_READ_FLASH_REG16(a, reg) (readw((a)->flash_address + reg))
-
-#endif /* _E1000_OSDEP_H_ */
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_phy.c b/roms/ipxe/src/drivers/net/e1000/e1000_phy.c
deleted file mode 100644
index b3cad4809394aec813f4321fead102dc491e1d1c..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_phy.c
+++ /dev/null
@@ -1,2308 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include "e1000_api.h"
-
-#if 0
-/* Cable length tables */
-static const u16 e1000_m88_cable_length_table[] =
-	{ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
-#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
-                (sizeof(e1000_m88_cable_length_table) / \
-                 sizeof(e1000_m88_cable_length_table[0]))
-
-static const u16 e1000_igp_2_cable_length_table[] =
-    { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
-      0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
-      6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
-      21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
-      40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
-      60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
-      83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
-      104, 109, 114, 118, 121, 124};
-#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
-                (sizeof(e1000_igp_2_cable_length_table) / \
-                 sizeof(e1000_igp_2_cable_length_table[0]))
-#endif
-
-/**
- *  e1000_init_phy_ops_generic - Initialize PHY function pointers
- *  @hw: pointer to the HW structure
- *
- *  Setups up the function pointers to no-op functions
- **/
-void e1000_init_phy_ops_generic(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	DEBUGFUNC("e1000_init_phy_ops_generic");
-
-	/* Initialize function pointers */
-	phy->ops.init_params = e1000_null_ops_generic;
-	phy->ops.acquire = e1000_null_ops_generic;
-	phy->ops.check_polarity = e1000_null_ops_generic;
-	phy->ops.check_reset_block = e1000_null_ops_generic;
-	phy->ops.commit = e1000_null_ops_generic;
-#if 0
-	phy->ops.force_speed_duplex = e1000_null_ops_generic;
-#endif
-	phy->ops.get_cfg_done = e1000_null_ops_generic;
-#if 0
-	phy->ops.get_cable_length = e1000_null_ops_generic;
-#endif
-	phy->ops.get_info = e1000_null_ops_generic;
-	phy->ops.read_reg = e1000_null_read_reg;
-	phy->ops.release = e1000_null_phy_generic;
-	phy->ops.reset = e1000_null_ops_generic;
-	phy->ops.set_d0_lplu_state = e1000_null_lplu_state;
-	phy->ops.set_d3_lplu_state = e1000_null_lplu_state;
-	phy->ops.write_reg = e1000_null_write_reg;
-	phy->ops.power_up = e1000_null_phy_generic;
-	phy->ops.power_down = e1000_null_phy_generic;
-}
-
-/**
- *  e1000_null_read_reg - No-op function, return 0
- *  @hw: pointer to the HW structure
- **/
-s32 e1000_null_read_reg(struct e1000_hw *hw __unused, u32 offset __unused,
-                        u16 *data __unused)
-{
-	DEBUGFUNC("e1000_null_read_reg");
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_null_phy_generic - No-op function, return void
- *  @hw: pointer to the HW structure
- **/
-void e1000_null_phy_generic(struct e1000_hw *hw __unused)
-{
-	DEBUGFUNC("e1000_null_phy_generic");
-	return;
-}
-
-/**
- *  e1000_null_lplu_state - No-op function, return 0
- *  @hw: pointer to the HW structure
- **/
-s32 e1000_null_lplu_state(struct e1000_hw *hw __unused, bool active __unused)
-{
-	DEBUGFUNC("e1000_null_lplu_state");
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_null_write_reg - No-op function, return 0
- *  @hw: pointer to the HW structure
- **/
-s32 e1000_null_write_reg(struct e1000_hw *hw __unused, u32 offset __unused,
-                         u16 data __unused)
-{
-	DEBUGFUNC("e1000_null_write_reg");
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_check_reset_block_generic - Check if PHY reset is blocked
- *  @hw: pointer to the HW structure
- *
- *  Read the PHY management control register and check whether a PHY reset
- *  is blocked.  If a reset is not blocked return E1000_SUCCESS, otherwise
- *  return E1000_BLK_PHY_RESET (12).
- **/
-s32 e1000_check_reset_block_generic(struct e1000_hw *hw)
-{
-	u32 manc;
-
-	DEBUGFUNC("e1000_check_reset_block");
-
-	manc = E1000_READ_REG(hw, E1000_MANC);
-
-	return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
-	       E1000_BLK_PHY_RESET : E1000_SUCCESS;
-}
-
-/**
- *  e1000_get_phy_id - Retrieve the PHY ID and revision
- *  @hw: pointer to the HW structure
- *
- *  Reads the PHY registers and stores the PHY ID and possibly the PHY
- *  revision in the hardware structure.
- **/
-s32 e1000_get_phy_id(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 phy_id;
-
-	DEBUGFUNC("e1000_get_phy_id");
-
-	if (!(phy->ops.read_reg))
-		goto out;
-
-		ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
-		if (ret_val)
-			goto out;
-
-		phy->id = (u32)(phy_id << 16);
-		usec_delay(20);
-		ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
-		if (ret_val)
-			goto out;
-
-		phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
-		phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_phy_reset_dsp_generic - Reset PHY DSP
- *  @hw: pointer to the HW structure
- *
- *  Reset the digital signal processor.
- **/
-s32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_phy_reset_dsp_generic");
-
-	if (!(hw->phy.ops.write_reg))
-		goto out;
-
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
-	if (ret_val)
-		goto out;
-
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_read_phy_reg_mdic - Read MDI control register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Reads the MDI control register in the PHY at offset and stores the
- *  information read to data.
- **/
-s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, mdic = 0;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_read_phy_reg_mdic");
-
-	/*
-	 * Set up Op-code, Phy Address, and register offset in the MDI
-	 * Control register.  The MAC will take care of interfacing with the
-	 * PHY to retrieve the desired data.
-	 */
-	mdic = ((offset << E1000_MDIC_REG_SHIFT) |
-	        (phy->addr << E1000_MDIC_PHY_SHIFT) |
-	        (E1000_MDIC_OP_READ));
-
-	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
-
-	/*
-	 * Poll the ready bit to see if the MDI read completed
-	 * Increasing the time out as testing showed failures with
-	 * the lower time out
-	 */
-	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
-		usec_delay(50);
-		mdic = E1000_READ_REG(hw, E1000_MDIC);
-		if (mdic & E1000_MDIC_READY)
-			break;
-	}
-	if (!(mdic & E1000_MDIC_READY)) {
-		DEBUGOUT("MDI Read did not complete\n");
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-	if (mdic & E1000_MDIC_ERROR) {
-		DEBUGOUT("MDI Error\n");
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-	*data = (u16) mdic;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_write_phy_reg_mdic - Write MDI control register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write to register at offset
- *
- *  Writes data to MDI control register in the PHY at offset.
- **/
-s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, mdic = 0;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_write_phy_reg_mdic");
-
-	/*
-	 * Set up Op-code, Phy Address, and register offset in the MDI
-	 * Control register.  The MAC will take care of interfacing with the
-	 * PHY to retrieve the desired data.
-	 */
-	mdic = (((u32)data) |
-	        (offset << E1000_MDIC_REG_SHIFT) |
-	        (phy->addr << E1000_MDIC_PHY_SHIFT) |
-	        (E1000_MDIC_OP_WRITE));
-
-	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
-
-	/*
-	 * Poll the ready bit to see if the MDI read completed
-	 * Increasing the time out as testing showed failures with
-	 * the lower time out
-	 */
-	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
-		usec_delay(50);
-		mdic = E1000_READ_REG(hw, E1000_MDIC);
-		if (mdic & E1000_MDIC_READY)
-			break;
-	}
-	if (!(mdic & E1000_MDIC_READY)) {
-		DEBUGOUT("MDI Write did not complete\n");
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-	if (mdic & E1000_MDIC_ERROR) {
-		DEBUGOUT("MDI Error\n");
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_read_phy_reg_m88 - Read m88 PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquires semaphore, if necessary, then reads the PHY register at offset
- *  and storing the retrieved information in data.  Release any acquired
- *  semaphores before exiting.
- **/
-s32 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_read_phy_reg_m88");
-
-	if (!(hw->phy.ops.acquire))
-		goto out;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                  data);
-
-	hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_write_phy_reg_m88 - Write m88 PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquires semaphore, if necessary, then writes the data to PHY register
- *  at the offset.  Release any acquired semaphores before exiting.
- **/
-s32 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_write_phy_reg_m88");
-
-	if (!(hw->phy.ops.acquire))
-		goto out;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                   data);
-
-	hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_read_phy_reg_igp - Read igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquires semaphore, if necessary, then reads the PHY register at offset
- *  and storing the retrieved information in data.  Release any acquired
- *  semaphores before exiting.
- **/
-s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_read_phy_reg_igp");
-
-	if (!(hw->phy.ops.acquire))
-		goto out;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	if (offset > MAX_PHY_MULTI_PAGE_REG) {
-		ret_val = e1000_write_phy_reg_mdic(hw,
-		                                   IGP01E1000_PHY_PAGE_SELECT,
-		                                   (u16)offset);
-		if (ret_val) {
-			hw->phy.ops.release(hw);
-			goto out;
-		}
-	}
-
-	ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                  data);
-
-	hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_write_phy_reg_igp - Write igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquires semaphore, if necessary, then writes the data to PHY register
- *  at the offset.  Release any acquired semaphores before exiting.
- **/
-s32 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_write_phy_reg_igp");
-
-	if (!(hw->phy.ops.acquire))
-		goto out;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	if (offset > MAX_PHY_MULTI_PAGE_REG) {
-		ret_val = e1000_write_phy_reg_mdic(hw,
-		                                   IGP01E1000_PHY_PAGE_SELECT,
-		                                   (u16)offset);
-		if (ret_val) {
-			hw->phy.ops.release(hw);
-			goto out;
-		}
-	}
-
-	ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                   data);
-
-	hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_read_kmrn_reg_generic - Read kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquires semaphore, if necessary.  Then reads the PHY register at offset
- *  using the kumeran interface.  The information retrieved is stored in data.
- *  Release any acquired semaphores before exiting.
- **/
-s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	u32 kmrnctrlsta;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_read_kmrn_reg_generic");
-
-	if (!(hw->phy.ops.acquire))
-		goto out;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
-	               E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
-	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
-
-	usec_delay(2);
-
-	kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA);
-	*data = (u16)kmrnctrlsta;
-
-	hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_write_kmrn_reg_generic - Write kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquires semaphore, if necessary.  Then write the data to PHY register
- *  at the offset using the kumeran interface.  Release any acquired semaphores
- *  before exiting.
- **/
-s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	u32 kmrnctrlsta;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("e1000_write_kmrn_reg_generic");
-
-	if (!(hw->phy.ops.acquire))
-		goto out;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
-	               E1000_KMRNCTRLSTA_OFFSET) | data;
-	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
-
-	usec_delay(2);
-	hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link
- *  @hw: pointer to the HW structure
- *
- *  Sets up MDI/MDI-X and polarity for m88 PHY's.  If necessary, transmit clock
- *  and downshift values are set also.
- **/
-s32 e1000_copper_link_setup_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data;
-
-	DEBUGFUNC("e1000_copper_link_setup_m88");
-
-	if (phy->reset_disable) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	/* Enable CRS on TX. This must be set for half-duplex operation. */
-	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-
-	/*
-	 * Options:
-	 *   MDI/MDI-X = 0 (default)
-	 *   0 - Auto for all speeds
-	 *   1 - MDI mode
-	 *   2 - MDI-X mode
-	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
-	 */
-	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
-
-	switch (phy->mdix) {
-	case 1:
-		phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
-		break;
-	case 2:
-		phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
-		break;
-	case 3:
-		phy_data |= M88E1000_PSCR_AUTO_X_1000T;
-		break;
-	case 0:
-	default:
-		phy_data |= M88E1000_PSCR_AUTO_X_MODE;
-		break;
-	}
-
-	/*
-	 * Options:
-	 *   disable_polarity_correction = 0 (default)
-	 *       Automatic Correction for Reversed Cable Polarity
-	 *   0 - Disabled
-	 *   1 - Enabled
-	 */
-	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
-	if (phy->disable_polarity_correction == 1)
-		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
-
-	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
-	if (ret_val)
-		goto out;
-
-	if (phy->revision < E1000_REVISION_4) {
-		/*
-		 * Force TX_CLK in the Extended PHY Specific Control Register
-		 * to 25MHz clock.
-		 */
-		ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-		                             &phy_data);
-		if (ret_val)
-			goto out;
-
-		phy_data |= M88E1000_EPSCR_TX_CLK_25;
-
-		if ((phy->revision == E1000_REVISION_2) &&
-		    (phy->id == M88E1111_I_PHY_ID)) {
-			/* 82573L PHY - set the downshift counter to 5x. */
-			phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
-			phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
-		} else {
-			/* Configure Master and Slave downshift values */
-			phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
-			             M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
-			phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
-			             M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
-		}
-		ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-		                             phy_data);
-		if (ret_val)
-			goto out;
-	}
-
-	/* Commit the changes. */
-	ret_val = phy->ops.commit(hw);
-	if (ret_val) {
-		DEBUGOUT("Error committing the PHY changes\n");
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_copper_link_setup_igp - Setup igp PHY's for copper link
- *  @hw: pointer to the HW structure
- *
- *  Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
- *  igp PHY's.
- **/
-s32 e1000_copper_link_setup_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-
-	DEBUGFUNC("e1000_copper_link_setup_igp");
-
-	if (phy->reset_disable) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	ret_val = hw->phy.ops.reset(hw);
-	if (ret_val) {
-		DEBUGOUT("Error resetting the PHY.\n");
-		goto out;
-	}
-
-	/*
-	 * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
-	 * timeout issues when LFS is enabled.
-	 */
-	msec_delay(100);
-
-	/*
-	 * The NVM settings will configure LPLU in D3 for
-	 * non-IGP1 PHYs.
-	 */
-	if (phy->type == e1000_phy_igp) {
-		/* disable lplu d3 during driver init */
-		ret_val = hw->phy.ops.set_d3_lplu_state(hw, false);
-		if (ret_val) {
-			DEBUGOUT("Error Disabling LPLU D3\n");
-			goto out;
-		}
-	}
-
-	/* disable lplu d0 during driver init */
-	if (hw->phy.ops.set_d0_lplu_state) {
-		ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
-		if (ret_val) {
-			DEBUGOUT("Error Disabling LPLU D0\n");
-			goto out;
-		}
-	}
-	/* Configure mdi-mdix settings */
-	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data);
-	if (ret_val)
-		goto out;
-
-	data &= ~IGP01E1000_PSCR_AUTO_MDIX;
-
-	switch (phy->mdix) {
-	case 1:
-		data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
-		break;
-	case 2:
-		data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
-		break;
-	case 0:
-	default:
-		data |= IGP01E1000_PSCR_AUTO_MDIX;
-		break;
-	}
-	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data);
-	if (ret_val)
-		goto out;
-
-	/* set auto-master slave resolution settings */
-	if (hw->mac.autoneg) {
-		/*
-		 * when autonegotiation advertisement is only 1000Mbps then we
-		 * should disable SmartSpeed and enable Auto MasterSlave
-		 * resolution as hardware default.
-		 */
-		if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
-			/* Disable SmartSpeed */
-			ret_val = phy->ops.read_reg(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             &data);
-			if (ret_val)
-				goto out;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = phy->ops.write_reg(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-
-			/* Set auto Master/Slave resolution process */
-			ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
-			if (ret_val)
-				goto out;
-
-			data &= ~CR_1000T_MS_ENABLE;
-			ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
-			if (ret_val)
-				goto out;
-		}
-
-		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
-		if (ret_val)
-			goto out;
-
-		/* load defaults for future use */
-		phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
-			((data & CR_1000T_MS_VALUE) ?
-			e1000_ms_force_master :
-			e1000_ms_force_slave) :
-			e1000_ms_auto;
-
-		switch (phy->ms_type) {
-		case e1000_ms_force_master:
-			data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
-			break;
-		case e1000_ms_force_slave:
-			data |= CR_1000T_MS_ENABLE;
-			data &= ~(CR_1000T_MS_VALUE);
-			break;
-		case e1000_ms_auto:
-			data &= ~CR_1000T_MS_ENABLE;
-		default:
-			break;
-		}
-		ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
- *  @hw: pointer to the HW structure
- *
- *  Performs initial bounds checking on autoneg advertisement parameter, then
- *  configure to advertise the full capability.  Setup the PHY to autoneg
- *  and restart the negotiation process between the link partner.  If
- *  autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
- **/
-s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_ctrl;
-
-	DEBUGFUNC("e1000_copper_link_autoneg");
-
-	/*
-	 * Perform some bounds checking on the autoneg advertisement
-	 * parameter.
-	 */
-	phy->autoneg_advertised &= phy->autoneg_mask;
-
-	/*
-	 * If autoneg_advertised is zero, we assume it was not defaulted
-	 * by the calling code so we set to advertise full capability.
-	 */
-	if (phy->autoneg_advertised == 0)
-		phy->autoneg_advertised = phy->autoneg_mask;
-
-	DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
-	ret_val = e1000_phy_setup_autoneg(hw);
-	if (ret_val) {
-		DEBUGOUT("Error Setting up Auto-Negotiation\n");
-		goto out;
-	}
-	DEBUGOUT("Restarting Auto-Neg\n");
-
-	/*
-	 * Restart auto-negotiation by setting the Auto Neg Enable bit and
-	 * the Auto Neg Restart bit in the PHY control register.
-	 */
-	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
-	if (ret_val)
-		goto out;
-
-	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
-	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Does the user want to wait for Auto-Neg to complete here, or
-	 * check at a later time (for example, callback routine).
-	 */
-	if (phy->autoneg_wait_to_complete) {
-		ret_val = hw->mac.ops.wait_autoneg(hw);
-		if (ret_val) {
-			DEBUGOUT("Error while waiting for "
-			         "autoneg to complete\n");
-			goto out;
-		}
-	}
-
-	hw->mac.get_link_status = true;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_phy_setup_autoneg - Configure PHY for auto-negotiation
- *  @hw: pointer to the HW structure
- *
- *  Reads the MII auto-neg advertisement register and/or the 1000T control
- *  register and if the PHY is already setup for auto-negotiation, then
- *  return successful.  Otherwise, setup advertisement and flow control to
- *  the appropriate values for the wanted auto-negotiation.
- **/
-s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 mii_autoneg_adv_reg;
-	u16 mii_1000t_ctrl_reg = 0;
-
-	DEBUGFUNC("e1000_phy_setup_autoneg");
-
-	phy->autoneg_advertised &= phy->autoneg_mask;
-
-	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
-	ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
-	if (ret_val)
-		goto out;
-
-	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
-		/* Read the MII 1000Base-T Control Register (Address 9). */
-		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
-		                            &mii_1000t_ctrl_reg);
-		if (ret_val)
-			goto out;
-	}
-
-	/*
-	 * Need to parse both autoneg_advertised and fc and set up
-	 * the appropriate PHY registers.  First we will parse for
-	 * autoneg_advertised software override.  Since we can advertise
-	 * a plethora of combinations, we need to check each bit
-	 * individually.
-	 */
-
-	/*
-	 * First we clear all the 10/100 mb speed bits in the Auto-Neg
-	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
-	 * the  1000Base-T Control Register (Address 9).
-	 */
-	mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
-	                         NWAY_AR_100TX_HD_CAPS |
-	                         NWAY_AR_10T_FD_CAPS   |
-	                         NWAY_AR_10T_HD_CAPS);
-	mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
-
-	DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised);
-
-	/* Do we want to advertise 10 Mb Half Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
-		DEBUGOUT("Advertise 10mb Half duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
-	}
-
-	/* Do we want to advertise 10 Mb Full Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
-		DEBUGOUT("Advertise 10mb Full duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
-	}
-
-	/* Do we want to advertise 100 Mb Half Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
-		DEBUGOUT("Advertise 100mb Half duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
-	}
-
-	/* Do we want to advertise 100 Mb Full Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
-		DEBUGOUT("Advertise 100mb Full duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
-	}
-
-	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
-	if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
-		DEBUGOUT("Advertise 1000mb Half duplex request denied!\n");
-
-	/* Do we want to advertise 1000 Mb Full Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
-		DEBUGOUT("Advertise 1000mb Full duplex\n");
-		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
-	}
-
-	/*
-	 * Check for a software override of the flow control settings, and
-	 * setup the PHY advertisement registers accordingly.  If
-	 * auto-negotiation is enabled, then software will have to set the
-	 * "PAUSE" bits to the correct value in the Auto-Negotiation
-	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
-	 * negotiation.
-	 *
-	 * The possible values of the "fc" parameter are:
-	 *      0:  Flow control is completely disabled
-	 *      1:  Rx flow control is enabled (we can receive pause frames
-	 *          but not send pause frames).
-	 *      2:  Tx flow control is enabled (we can send pause frames
-	 *          but we do not support receiving pause frames).
-	 *      3:  Both Rx and Tx flow control (symmetric) are enabled.
-	 *  other:  No software override.  The flow control configuration
-	 *          in the EEPROM is used.
-	 */
-	switch (hw->fc.current_mode) {
-	case e1000_fc_none:
-		/*
-		 * Flow control (Rx & Tx) is completely disabled by a
-		 * software over-ride.
-		 */
-		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
-		break;
-	case e1000_fc_rx_pause:
-		/*
-		 * Rx Flow control is enabled, and Tx Flow control is
-		 * disabled, by a software over-ride.
-		 *
-		 * Since there really isn't a way to advertise that we are
-		 * capable of Rx Pause ONLY, we will advertise that we
-		 * support both symmetric and asymmetric Rx PAUSE.  Later
-		 * (in e1000_config_fc_after_link_up) we will disable the
-		 * hw's ability to send PAUSE frames.
-		 */
-		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
-		break;
-	case e1000_fc_tx_pause:
-		/*
-		 * Tx Flow control is enabled, and Rx Flow control is
-		 * disabled, by a software over-ride.
-		 */
-		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
-		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
-		break;
-	case e1000_fc_full:
-		/*
-		 * Flow control (both Rx and Tx) is enabled by a software
-		 * over-ride.
-		 */
-		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
-		break;
-	default:
-		DEBUGOUT("Flow control param set incorrectly\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
-	if (ret_val)
-		goto out;
-
-	DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
-
-	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
-		ret_val = phy->ops.write_reg(hw,
-		                              PHY_1000T_CTRL,
-		                              mii_1000t_ctrl_reg);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_setup_copper_link_generic - Configure copper link settings
- *  @hw: pointer to the HW structure
- *
- *  Calls the appropriate function to configure the link for auto-neg or forced
- *  speed and duplex.  Then we check for link, once link is established calls
- *  to configure collision distance and flow control are called.  If link is
- *  not established, we return -E1000_ERR_PHY (-2).
- **/
-s32 e1000_setup_copper_link_generic(struct e1000_hw *hw)
-{
-	s32 ret_val;
-	bool link;
-
-	DEBUGFUNC("e1000_setup_copper_link_generic");
-
-	if (hw->mac.autoneg) {
-		/*
-		 * Setup autoneg and flow control advertisement and perform
-		 * autonegotiation.
-		 */
-		ret_val = e1000_copper_link_autoneg(hw);
-		if (ret_val)
-			goto out;
-	} else {
-#if 0
-		/*
-		 * PHY will be set to 10H, 10F, 100H or 100F
-		 * depending on user settings.
-		 */
-		DEBUGOUT("Forcing Speed and Duplex\n");
-		ret_val = hw->phy.ops.force_speed_duplex(hw);
-		if (ret_val) {
-			DEBUGOUT("Error Forcing Speed and Duplex\n");
-			goto out;
-		}
-#endif
-	}
-
-	/*
-	 * Check link status. Wait up to 100 microseconds for link to become
-	 * valid.
-	 */
-	ret_val = e1000_phy_has_link_generic(hw,
-	                                     COPPER_LINK_UP_LIMIT,
-	                                     10,
-	                                     &link);
-	if (ret_val)
-		goto out;
-
-	if (link) {
-		DEBUGOUT("Valid link established!!!\n");
-		e1000_config_collision_dist_generic(hw);
-		ret_val = e1000_config_fc_after_link_up_generic(hw);
-	} else {
-		DEBUGOUT("Unable to establish link!!!\n");
-	}
-
-out:
-	return ret_val;
-}
-
-#if 0
-/**
- *  e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
- *  @hw: pointer to the HW structure
- *
- *  Calls the PHY setup function to force speed and duplex.  Clears the
- *  auto-crossover to force MDI manually.  Waits for link and returns
- *  successful if link up is successful, else -E1000_ERR_PHY (-2).
- **/
-s32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data;
-	bool link;
-
-	DEBUGFUNC("e1000_phy_force_speed_duplex_igp");
-
-	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
-
-	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Clear Auto-Crossover to force MDI manually.  IGP requires MDI
-	 * forced whenever speed and duplex are forced.
-	 */
-	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
-	phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
-
-	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
-	if (ret_val)
-		goto out;
-
-	DEBUGOUT1("IGP PSCR: %X\n", phy_data);
-
-	usec_delay(1);
-
-	if (phy->autoneg_wait_to_complete) {
-		DEBUGOUT("Waiting for forced speed/duplex link on IGP phy.\n");
-
-		ret_val = e1000_phy_has_link_generic(hw,
-		                                     PHY_FORCE_LIMIT,
-		                                     100000,
-		                                     &link);
-		if (ret_val)
-			goto out;
-
-		if (!link)
-			DEBUGOUT("Link taking longer than expected.\n");
-
-		/* Try once more */
-		ret_val = e1000_phy_has_link_generic(hw,
-		                                     PHY_FORCE_LIMIT,
-		                                     100000,
-		                                     &link);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
- *  @hw: pointer to the HW structure
- *
- *  Calls the PHY setup function to force speed and duplex.  Clears the
- *  auto-crossover to force MDI manually.  Resets the PHY to commit the
- *  changes.  If time expires while waiting for link up, we reset the DSP.
- *  After reset, TX_CLK and CRS on Tx must be set.  Return successful upon
- *  successful completion, else return corresponding error code.
- **/
-s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data;
-	bool link;
-
-	DEBUGFUNC("e1000_phy_force_speed_duplex_m88");
-
-	/*
-	 * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
-	 * forced whenever speed and duplex are forced.
-	 */
-	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
-	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
-	if (ret_val)
-		goto out;
-
-	DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data);
-
-	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	e1000_phy_force_speed_duplex_setup(hw, &phy_data);
-
-	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
-	if (ret_val)
-		goto out;
-
-	/* Reset the phy to commit changes. */
-	ret_val = hw->phy.ops.commit(hw);
-	if (ret_val)
-		goto out;
-
-	if (phy->autoneg_wait_to_complete) {
-		DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n");
-
-		ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
-		                                     100000, &link);
-		if (ret_val)
-			goto out;
-
-		if (!link) {
-			/*
-			 * We didn't get link.
-			 * Reset the DSP and cross our fingers.
-			 */
-			ret_val = phy->ops.write_reg(hw,
-			                              M88E1000_PHY_PAGE_SELECT,
-			                              0x001d);
-			if (ret_val)
-				goto out;
-			ret_val = e1000_phy_reset_dsp_generic(hw);
-			if (ret_val)
-				goto out;
-		}
-
-		/* Try once more */
-		ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
-		                                     100000, &link);
-		if (ret_val)
-			goto out;
-	}
-
-	ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Resetting the phy means we need to re-force TX_CLK in the
-	 * Extended PHY Specific Control Register to 25MHz clock from
-	 * the reset value of 2.5MHz.
-	 */
-	phy_data |= M88E1000_EPSCR_TX_CLK_25;
-	ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * In addition, we must re-enable CRS on Tx for both half and full
-	 * duplex.
-	 */
-	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_phy_force_speed_duplex_ife - Force PHY speed & duplex
- *  @hw: pointer to the HW structure
- *
- *  Forces the speed and duplex settings of the PHY.
- *  This is a function pointer entry point only called by
- *  PHY setup routines.
- **/
-s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-	bool link;
-
-	DEBUGFUNC("e1000_phy_force_speed_duplex_ife");
-
-	if (phy->type != e1000_phy_ife) {
-		ret_val = e1000_phy_force_speed_duplex_igp(hw);
-		goto out;
-	}
-
-	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data);
-	if (ret_val)
-		goto out;
-
-	e1000_phy_force_speed_duplex_setup(hw, &data);
-
-	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data);
-	if (ret_val)
-		goto out;
-
-	/* Disable MDI-X support for 10/100 */
-	ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
-	if (ret_val)
-		goto out;
-
-	data &= ~IFE_PMC_AUTO_MDIX;
-	data &= ~IFE_PMC_FORCE_MDIX;
-
-	ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data);
-	if (ret_val)
-		goto out;
-
-	DEBUGOUT1("IFE PMC: %X\n", data);
-
-	usec_delay(1);
-
-	if (phy->autoneg_wait_to_complete) {
-		DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n");
-
-		ret_val = e1000_phy_has_link_generic(hw,
-		                                     PHY_FORCE_LIMIT,
-		                                     100000,
-		                                     &link);
-		if (ret_val)
-			goto out;
-
-		if (!link)
-			DEBUGOUT("Link taking longer than expected.\n");
-
-		/* Try once more */
-		ret_val = e1000_phy_has_link_generic(hw,
-		                                     PHY_FORCE_LIMIT,
-		                                     100000,
-		                                     &link);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
- *  @hw: pointer to the HW structure
- *  @phy_ctrl: pointer to current value of PHY_CONTROL
- *
- *  Forces speed and duplex on the PHY by doing the following: disable flow
- *  control, force speed/duplex on the MAC, disable auto speed detection,
- *  disable auto-negotiation, configure duplex, configure speed, configure
- *  the collision distance, write configuration to CTRL register.  The
- *  caller must write to the PHY_CONTROL register for these settings to
- *  take affect.
- **/
-void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 ctrl;
-
-	DEBUGFUNC("e1000_phy_force_speed_duplex_setup");
-
-	/* Turn off flow control when forcing speed/duplex */
-	hw->fc.current_mode = e1000_fc_none;
-
-	/* Force speed/duplex on the mac */
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-	ctrl &= ~E1000_CTRL_SPD_SEL;
-
-	/* Disable Auto Speed Detection */
-	ctrl &= ~E1000_CTRL_ASDE;
-
-	/* Disable autoneg on the phy */
-	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
-
-	/* Forcing Full or Half Duplex? */
-	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
-		ctrl &= ~E1000_CTRL_FD;
-		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;
-		DEBUGOUT("Half Duplex\n");
-	} else {
-		ctrl |= E1000_CTRL_FD;
-		*phy_ctrl |= MII_CR_FULL_DUPLEX;
-		DEBUGOUT("Full Duplex\n");
-	}
-
-	/* Forcing 10mb or 100mb? */
-	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
-		ctrl |= E1000_CTRL_SPD_100;
-		*phy_ctrl |= MII_CR_SPEED_100;
-		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
-		DEBUGOUT("Forcing 100mb\n");
-	} else {
-		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
-		*phy_ctrl |= MII_CR_SPEED_10;
-		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
-		DEBUGOUT("Forcing 10mb\n");
-	}
-
-	e1000_config_collision_dist_generic(hw);
-
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-}
-#endif
-
-/**
- *  e1000_set_d3_lplu_state_generic - Sets low power link up state for D3
- *  @hw: pointer to the HW structure
- *  @active: boolean used to enable/disable lplu
- *
- *  Success returns 0, Failure returns 1
- *
- *  The low power link up (lplu) state is set to the power management level D3
- *  and SmartSpeed is disabled when active is true, else clear lplu for D3
- *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
- *  is used during Dx states where the power conservation is most important.
- *  During driver activity, SmartSpeed should be enabled so performance is
- *  maintained.
- **/
-s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 data;
-
-	DEBUGFUNC("e1000_set_d3_lplu_state_generic");
-
-	if (!(hw->phy.ops.read_reg))
-		goto out;
-
-	ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
-	if (ret_val)
-		goto out;
-
-	if (!active) {
-		data &= ~IGP02E1000_PM_D3_LPLU;
-		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
-		                             data);
-		if (ret_val)
-			goto out;
-		/*
-		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
-		 * during Dx states where the power conservation is most
-		 * important.  During driver activity we should enable
-		 * SmartSpeed, so performance is maintained.
-		 */
-		if (phy->smart_speed == e1000_smart_speed_on) {
-			ret_val = phy->ops.read_reg(hw,
-			                            IGP01E1000_PHY_PORT_CONFIG,
-			                            &data);
-			if (ret_val)
-				goto out;
-
-			data |= IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = phy->ops.write_reg(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		} else if (phy->smart_speed == e1000_smart_speed_off) {
-			ret_val = phy->ops.read_reg(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             &data);
-			if (ret_val)
-				goto out;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = phy->ops.write_reg(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		}
-	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
-	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
-	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
-		data |= IGP02E1000_PM_D3_LPLU;
-		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
-		                              data);
-		if (ret_val)
-			goto out;
-
-		/* When LPLU is enabled, we should disable SmartSpeed */
-		ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-		                             &data);
-		if (ret_val)
-			goto out;
-
-		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-		ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-		                              data);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_check_downshift_generic - Checks whether a downshift in speed occurred
- *  @hw: pointer to the HW structure
- *
- *  Success returns 0, Failure returns 1
- *
- *  A downshift is detected by querying the PHY link health.
- **/
-s32 e1000_check_downshift_generic(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data, offset, mask;
-
-	DEBUGFUNC("e1000_check_downshift_generic");
-
-	switch (phy->type) {
-	case e1000_phy_m88:
-	case e1000_phy_gg82563:
-		offset	= M88E1000_PHY_SPEC_STATUS;
-		mask	= M88E1000_PSSR_DOWNSHIFT;
-		break;
-	case e1000_phy_igp_2:
-	case e1000_phy_igp:
-	case e1000_phy_igp_3:
-		offset	= IGP01E1000_PHY_LINK_HEALTH;
-		mask	= IGP01E1000_PLHR_SS_DOWNGRADE;
-		break;
-	default:
-		/* speed downshift not supported */
-		phy->speed_downgraded = false;
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
-
-	if (!ret_val)
-		phy->speed_downgraded = (phy_data & mask) ? true : false;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_check_polarity_m88 - Checks the polarity.
- *  @hw: pointer to the HW structure
- *
- *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
- *
- *  Polarity is determined based on the PHY specific status register.
- **/
-s32 e1000_check_polarity_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-
-	DEBUGFUNC("e1000_check_polarity_m88");
-
-	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);
-
-	if (!ret_val)
-		phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
-		                      ? e1000_rev_polarity_reversed
-		                      : e1000_rev_polarity_normal;
-
-	return ret_val;
-}
-
-/**
- *  e1000_check_polarity_igp - Checks the polarity.
- *  @hw: pointer to the HW structure
- *
- *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
- *
- *  Polarity is determined based on the PHY port status register, and the
- *  current speed (since there is no polarity at 100Mbps).
- **/
-s32 e1000_check_polarity_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data, offset, mask;
-
-	DEBUGFUNC("e1000_check_polarity_igp");
-
-	/*
-	 * Polarity is determined based on the speed of
-	 * our connection.
-	 */
-	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
-	if (ret_val)
-		goto out;
-
-	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
-	    IGP01E1000_PSSR_SPEED_1000MBPS) {
-		offset	= IGP01E1000_PHY_PCS_INIT_REG;
-		mask	= IGP01E1000_PHY_POLARITY_MASK;
-	} else {
-		/*
-		 * This really only applies to 10Mbps since
-		 * there is no polarity for 100Mbps (always 0).
-		 */
-		offset	= IGP01E1000_PHY_PORT_STATUS;
-		mask	= IGP01E1000_PSSR_POLARITY_REVERSED;
-	}
-
-	ret_val = phy->ops.read_reg(hw, offset, &data);
-
-	if (!ret_val)
-		phy->cable_polarity = (data & mask)
-		                      ? e1000_rev_polarity_reversed
-		                      : e1000_rev_polarity_normal;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_check_polarity_ife - Check cable polarity for IFE PHY
- *  @hw: pointer to the HW structure
- *
- *  Polarity is determined on the polarity reversal feature being enabled.
- **/
-s32 e1000_check_polarity_ife(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data, offset, mask;
-
-	DEBUGFUNC("e1000_check_polarity_ife");
-
-	/*
-	 * Polarity is determined based on the reversal feature being enabled.
-	 */
-	if (phy->polarity_correction) {
-		offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
-		mask = IFE_PESC_POLARITY_REVERSED;
-	} else {
-		offset = IFE_PHY_SPECIAL_CONTROL;
-		mask = IFE_PSC_FORCE_POLARITY;
-	}
-
-	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
-
-	if (!ret_val)
-		phy->cable_polarity = (phy_data & mask)
-		                       ? e1000_rev_polarity_reversed
-		                       : e1000_rev_polarity_normal;
-
-	return ret_val;
-}
-
-/**
- *  e1000_wait_autoneg_generic - Wait for auto-neg completion
- *  @hw: pointer to the HW structure
- *
- *  Waits for auto-negotiation to complete or for the auto-negotiation time
- *  limit to expire, which ever happens first.
- **/
-s32 e1000_wait_autoneg_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 i, phy_status;
-
-	DEBUGFUNC("e1000_wait_autoneg_generic");
-
-	if (!(hw->phy.ops.read_reg))
-		return E1000_SUCCESS;
-
-	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
-	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
-		if (ret_val)
-			break;
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
-		if (ret_val)
-			break;
-		if (phy_status & MII_SR_AUTONEG_COMPLETE)
-			break;
-		msec_delay(100);
-	}
-
-	/*
-	 * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
-	 * has completed.
-	 */
-	return ret_val;
-}
-
-/**
- *  e1000_phy_has_link_generic - Polls PHY for link
- *  @hw: pointer to the HW structure
- *  @iterations: number of times to poll for link
- *  @usec_interval: delay between polling attempts
- *  @success: pointer to whether polling was successful or not
- *
- *  Polls the PHY status register for link, 'iterations' number of times.
- **/
-s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
-                               u32 usec_interval, bool *success)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 i, phy_status;
-
-	DEBUGFUNC("e1000_phy_has_link_generic");
-
-	if (!(hw->phy.ops.read_reg))
-		return E1000_SUCCESS;
-
-	for (i = 0; i < iterations; i++) {
-		/*
-		 * Some PHYs require the PHY_STATUS register to be read
-		 * twice due to the link bit being sticky.  No harm doing
-		 * it across the board.
-		 */
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
-		if (ret_val) {
-			/*
-			 * If the first read fails, another entity may have
-			 * ownership of the resources, wait and try again to
-			 * see if they have relinquished the resources yet.
-			 */
-			usec_delay(usec_interval);
-		}
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
-		if (ret_val)
-			break;
-		if (phy_status & MII_SR_LINK_STATUS)
-			break;
-		if (usec_interval >= 1000)
-			msec_delay_irq(usec_interval/1000);
-		else
-			usec_delay(usec_interval);
-	}
-
-	*success = (i < iterations) ? true : false;
-
-	return ret_val;
-}
-
-#if 0
-/**
- *  e1000_get_cable_length_m88 - Determine cable length for m88 PHY
- *  @hw: pointer to the HW structure
- *
- *  Reads the PHY specific status register to retrieve the cable length
- *  information.  The cable length is determined by averaging the minimum and
- *  maximum values to get the "average" cable length.  The m88 PHY has four
- *  possible cable length values, which are:
- *	Register Value		Cable Length
- *	0			< 50 meters
- *	1			50 - 80 meters
- *	2			80 - 110 meters
- *	3			110 - 140 meters
- *	4			> 140 meters
- **/
-s32 e1000_get_cable_length_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data, index;
-
-	DEBUGFUNC("e1000_get_cable_length_m88");
-
-	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
-	if (ret_val)
-		goto out;
-
-	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
-	        M88E1000_PSSR_CABLE_LENGTH_SHIFT;
-	if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE + 1) {
-		ret_val = E1000_ERR_PHY;
-		goto out;
-	}
-
-	phy->min_cable_length = e1000_m88_cable_length_table[index];
-	phy->max_cable_length = e1000_m88_cable_length_table[index+1];
-
-	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY
- *  @hw: pointer to the HW structure
- *
- *  The automatic gain control (agc) normalizes the amplitude of the
- *  received signal, adjusting for the attenuation produced by the
- *  cable.  By reading the AGC registers, which represent the
- *  combination of coarse and fine gain value, the value can be put
- *  into a lookup table to obtain the approximate cable length
- *  for each channel.
- **/
-s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 phy_data, i, agc_value = 0;
-	u16 cur_agc_index, max_agc_index = 0;
-	u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
-	u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
-	                                                 {IGP02E1000_PHY_AGC_A,
-	                                                  IGP02E1000_PHY_AGC_B,
-	                                                  IGP02E1000_PHY_AGC_C,
-	                                                  IGP02E1000_PHY_AGC_D};
-
-	DEBUGFUNC("e1000_get_cable_length_igp_2");
-
-	/* Read the AGC registers for all channels */
-	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
-		ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data);
-		if (ret_val)
-			goto out;
-
-		/*
-		 * Getting bits 15:9, which represent the combination of
-		 * coarse and fine gain values.  The result is a number
-		 * that can be put into the lookup table to obtain the
-		 * approximate cable length.
-		 */
-		cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
-		                IGP02E1000_AGC_LENGTH_MASK;
-
-		/* Array index bound check. */
-		if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
-		    (cur_agc_index == 0)) {
-			ret_val = -E1000_ERR_PHY;
-			goto out;
-		}
-
-		/* Remove min & max AGC values from calculation. */
-		if (e1000_igp_2_cable_length_table[min_agc_index] >
-		    e1000_igp_2_cable_length_table[cur_agc_index])
-			min_agc_index = cur_agc_index;
-		if (e1000_igp_2_cable_length_table[max_agc_index] <
-		    e1000_igp_2_cable_length_table[cur_agc_index])
-			max_agc_index = cur_agc_index;
-
-		agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
-	}
-
-	agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
-	              e1000_igp_2_cable_length_table[max_agc_index]);
-	agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
-
-	/* Calculate cable length with the error range of +/- 10 meters. */
-	phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
-	                         (agc_value - IGP02E1000_AGC_RANGE) : 0;
-	phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
-
-	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
-
-out:
-	return ret_val;
-}
-#endif
-
-/**
- *  e1000_get_phy_info_m88 - Retrieve PHY information
- *  @hw: pointer to the HW structure
- *
- *  Valid for only copper links.  Read the PHY status register (sticky read)
- *  to verify that link is up.  Read the PHY special control register to
- *  determine the polarity and 10base-T extended distance.  Read the PHY
- *  special status register to determine MDI/MDIx and current speed.  If
- *  speed is 1000, then determine cable length, local and remote receiver.
- **/
-s32 e1000_get_phy_info_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32  ret_val;
-	u16 phy_data;
-	bool link;
-
-	DEBUGFUNC("e1000_get_phy_info_m88");
-
-	if (hw->phy.media_type != e1000_media_type_copper) {
-		DEBUGOUT("Phy info is only valid for copper media\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		goto out;
-
-	if (!link) {
-		DEBUGOUT("Phy info is only valid if link is up\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
-	                           ? true : false;
-
-	ret_val = e1000_check_polarity_m88(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false;
-
-	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
-#if 0
-		ret_val = hw->phy.ops.get_cable_length(hw);
-#endif
-		ret_val = -E1000_ERR_CONFIG;
-		if (ret_val)
-			goto out;
-
-		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
-		if (ret_val)
-			goto out;
-
-		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
-		                ? e1000_1000t_rx_status_ok
-		                : e1000_1000t_rx_status_not_ok;
-
-		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
-		                 ? e1000_1000t_rx_status_ok
-		                 : e1000_1000t_rx_status_not_ok;
-	} else {
-		/* Set values to "undefined" */
-		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
-		phy->local_rx = e1000_1000t_rx_status_undefined;
-		phy->remote_rx = e1000_1000t_rx_status_undefined;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_get_phy_info_igp - Retrieve igp PHY information
- *  @hw: pointer to the HW structure
- *
- *  Read PHY status to determine if link is up.  If link is up, then
- *  set/determine 10base-T extended distance and polarity correction.  Read
- *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
- *  determine on the cable length, local and remote receiver.
- **/
-s32 e1000_get_phy_info_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-	bool link;
-
-	DEBUGFUNC("e1000_get_phy_info_igp");
-
-	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		goto out;
-
-	if (!link) {
-		DEBUGOUT("Phy info is only valid if link is up\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	phy->polarity_correction = true;
-
-	ret_val = e1000_check_polarity_igp(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
-	if (ret_val)
-		goto out;
-
-	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false;
-
-#if 0
-	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
-	    IGP01E1000_PSSR_SPEED_1000MBPS) {
-		ret_val = hw->phy.ops.get_cable_length(hw);
-		if (ret_val)
-			goto out;
-
-		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
-		if (ret_val)
-			goto out;
-
-		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
-		                ? e1000_1000t_rx_status_ok
-		                : e1000_1000t_rx_status_not_ok;
-
-		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
-		                 ? e1000_1000t_rx_status_ok
-		                 : e1000_1000t_rx_status_not_ok;
-	} else {
-#endif
-		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
-		phy->local_rx = e1000_1000t_rx_status_undefined;
-		phy->remote_rx = e1000_1000t_rx_status_undefined;
-#if 0
-	}
-#endif
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_phy_sw_reset_generic - PHY software reset
- *  @hw: pointer to the HW structure
- *
- *  Does a software reset of the PHY by reading the PHY control register and
- *  setting/write the control register reset bit to the PHY.
- **/
-s32 e1000_phy_sw_reset_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 phy_ctrl;
-
-	DEBUGFUNC("e1000_phy_sw_reset_generic");
-
-	if (!(hw->phy.ops.read_reg))
-		goto out;
-
-	ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
-	if (ret_val)
-		goto out;
-
-	phy_ctrl |= MII_CR_RESET;
-	ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
-	if (ret_val)
-		goto out;
-
-	usec_delay(1);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_phy_hw_reset_generic - PHY hardware reset
- *  @hw: pointer to the HW structure
- *
- *  Verify the reset block is not blocking us from resetting.  Acquire
- *  semaphore (if necessary) and read/set/write the device control reset
- *  bit in the PHY.  Wait the appropriate delay time for the device to
- *  reset and release the semaphore (if necessary).
- **/
-s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u32 ctrl;
-
-	DEBUGFUNC("e1000_phy_hw_reset_generic");
-
-	ret_val = phy->ops.check_reset_block(hw);
-	if (ret_val) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	ret_val = phy->ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);
-	E1000_WRITE_FLUSH(hw);
-
-	usec_delay(phy->reset_delay_us);
-
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-	E1000_WRITE_FLUSH(hw);
-
-	usec_delay(150);
-
-	phy->ops.release(hw);
-
-	ret_val = phy->ops.get_cfg_done(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_get_cfg_done_generic - Generic configuration done
- *  @hw: pointer to the HW structure
- *
- *  Generic function to wait 10 milli-seconds for configuration to complete
- *  and return success.
- **/
-s32 e1000_get_cfg_done_generic(struct e1000_hw *hw __unused)
-{
-	DEBUGFUNC("e1000_get_cfg_done_generic");
-
-	msec_delay_irq(10);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_phy_init_script_igp3 - Inits the IGP3 PHY
- *  @hw: pointer to the HW structure
- *
- *  Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
- **/
-s32 e1000_phy_init_script_igp3(struct e1000_hw *hw)
-{
-	DEBUGOUT("Running IGP 3 PHY init script\n");
-
-	/* PHY init IGP 3 */
-	/* Enable rise/fall, 10-mode work in class-A */
-	hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018);
-	/* Remove all caps from Replica path filter */
-	hw->phy.ops.write_reg(hw, 0x2F52, 0x0000);
-	/* Bias trimming for ADC, AFE and Driver (Default) */
-	hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24);
-	/* Increase Hybrid poly bias */
-	hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0);
-	/* Add 4% to Tx amplitude in Gig mode */
-	hw->phy.ops.write_reg(hw, 0x2010, 0x10B0);
-	/* Disable trimming (TTT) */
-	hw->phy.ops.write_reg(hw, 0x2011, 0x0000);
-	/* Poly DC correction to 94.6% + 2% for all channels */
-	hw->phy.ops.write_reg(hw, 0x20DD, 0x249A);
-	/* ABS DC correction to 95.9% */
-	hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3);
-	/* BG temp curve trim */
-	hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE);
-	/* Increasing ADC OPAMP stage 1 currents to max */
-	hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4);
-	/* Force 1000 ( required for enabling PHY regs configuration) */
-	hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
-	/* Set upd_freq to 6 */
-	hw->phy.ops.write_reg(hw, 0x1F30, 0x1606);
-	/* Disable NPDFE */
-	hw->phy.ops.write_reg(hw, 0x1F31, 0xB814);
-	/* Disable adaptive fixed FFE (Default) */
-	hw->phy.ops.write_reg(hw, 0x1F35, 0x002A);
-	/* Enable FFE hysteresis */
-	hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067);
-	/* Fixed FFE for short cable lengths */
-	hw->phy.ops.write_reg(hw, 0x1F54, 0x0065);
-	/* Fixed FFE for medium cable lengths */
-	hw->phy.ops.write_reg(hw, 0x1F55, 0x002A);
-	/* Fixed FFE for long cable lengths */
-	hw->phy.ops.write_reg(hw, 0x1F56, 0x002A);
-	/* Enable Adaptive Clip Threshold */
-	hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0);
-	/* AHT reset limit to 1 */
-	hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF);
-	/* Set AHT master delay to 127 msec */
-	hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC);
-	/* Set scan bits for AHT */
-	hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF);
-	/* Set AHT Preset bits */
-	hw->phy.ops.write_reg(hw, 0x1F79, 0x0210);
-	/* Change integ_factor of channel A to 3 */
-	hw->phy.ops.write_reg(hw, 0x1895, 0x0003);
-	/* Change prop_factor of channels BCD to 8 */
-	hw->phy.ops.write_reg(hw, 0x1796, 0x0008);
-	/* Change cg_icount + enable integbp for channels BCD */
-	hw->phy.ops.write_reg(hw, 0x1798, 0xD008);
-	/*
-	 * Change cg_icount + enable integbp + change prop_factor_master
-	 * to 8 for channel A
-	 */
-	hw->phy.ops.write_reg(hw, 0x1898, 0xD918);
-	/* Disable AHT in Slave mode on channel A */
-	hw->phy.ops.write_reg(hw, 0x187A, 0x0800);
-	/*
-	 * Enable LPLU and disable AN to 1000 in non-D0a states,
-	 * Enable SPD+B2B
-	 */
-	hw->phy.ops.write_reg(hw, 0x0019, 0x008D);
-	/* Enable restart AN on an1000_dis change */
-	hw->phy.ops.write_reg(hw, 0x001B, 0x2080);
-	/* Enable wh_fifo read clock in 10/100 modes */
-	hw->phy.ops.write_reg(hw, 0x0014, 0x0045);
-	/* Restart AN, Speed selection is 1000 */
-	hw->phy.ops.write_reg(hw, 0x0000, 0x1340);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_get_phy_type_from_id - Get PHY type from id
- *  @phy_id: phy_id read from the phy
- *
- *  Returns the phy type from the id.
- **/
-enum e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id)
-{
-	enum e1000_phy_type phy_type = e1000_phy_unknown;
-
-	switch (phy_id)	{
-	case M88E1000_I_PHY_ID:
-	case M88E1000_E_PHY_ID:
-	case M88E1111_I_PHY_ID:
-	case M88E1011_I_PHY_ID:
-		phy_type = e1000_phy_m88;
-		break;
-	case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
-		phy_type = e1000_phy_igp_2;
-		break;
-	case GG82563_E_PHY_ID:
-		phy_type = e1000_phy_gg82563;
-		break;
-	case IGP03E1000_E_PHY_ID:
-		phy_type = e1000_phy_igp_3;
-		break;
-	case IFE_E_PHY_ID:
-	case IFE_PLUS_E_PHY_ID:
-	case IFE_C_E_PHY_ID:
-		phy_type = e1000_phy_ife;
-		break;
-	default:
-		phy_type = e1000_phy_unknown;
-		break;
-	}
-	return phy_type;
-}
-
-/**
- *  e1000_determine_phy_address - Determines PHY address.
- *  @hw: pointer to the HW structure
- *
- *  This uses a trial and error method to loop through possible PHY
- *  addresses. It tests each by reading the PHY ID registers and
- *  checking for a match.
- **/
-s32 e1000_determine_phy_address(struct e1000_hw *hw)
-{
-	s32 ret_val = -E1000_ERR_PHY_TYPE;
-	u32 phy_addr = 0;
-	u32 i;
-	enum e1000_phy_type phy_type = e1000_phy_unknown;
-
-	hw->phy.id = phy_type;
-
-	for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) {
-		hw->phy.addr = phy_addr;
-		i = 0;
-
-		do {
-			e1000_get_phy_id(hw);
-			phy_type = e1000_get_phy_type_from_id(hw->phy.id);
-
-			/*
-			 * If phy_type is valid, break - we found our
-			 * PHY address
-			 */
-			if (phy_type  != e1000_phy_unknown) {
-				ret_val = E1000_SUCCESS;
-				goto out;
-			}
-			msec_delay(1);
-			i++;
-		} while (i < 10);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- * e1000_power_up_phy_copper - Restore copper link in case of PHY power down
- * @hw: pointer to the HW structure
- *
- * In the case of a PHY power down to save power, or to turn off link during a
- * driver unload, or wake on lan is not enabled, restore the link to previous
- * settings.
- **/
-void e1000_power_up_phy_copper(struct e1000_hw *hw)
-{
-	u16 mii_reg = 0;
-
-	/* The PHY will retain its settings across a power down/up cycle */
-	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
-	mii_reg &= ~MII_CR_POWER_DOWN;
-	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
-}
-
-/**
- * e1000_power_down_phy_copper - Restore copper link in case of PHY power down
- * @hw: pointer to the HW structure
- *
- * In the case of a PHY power down to save power, or to turn off link during a
- * driver unload, or wake on lan is not enabled, restore the link to previous
- * settings.
- **/
-void e1000_power_down_phy_copper(struct e1000_hw *hw)
-{
-	u16 mii_reg = 0;
-
-	/* The PHY will retain its settings across a power down/up cycle */
-	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
-	mii_reg |= MII_CR_POWER_DOWN;
-	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
-	msec_delay(1);
-}
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_phy.h b/roms/ipxe/src/drivers/net/e1000/e1000_phy.h
deleted file mode 100644
index 93bd7a1b0842142499ecf861a00d0c0799d689f7..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_phy.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000_PHY_H_
-#define _E1000_PHY_H_
-
-void e1000_init_phy_ops_generic(struct e1000_hw *hw);
-s32  e1000_null_read_reg(struct e1000_hw *hw, u32 offset, u16 *data);
-void e1000_null_phy_generic(struct e1000_hw *hw);
-s32  e1000_null_lplu_state(struct e1000_hw *hw, bool active);
-s32  e1000_null_write_reg(struct e1000_hw *hw, u32 offset, u16 data);
-s32  e1000_check_downshift_generic(struct e1000_hw *hw);
-s32  e1000_check_polarity_m88(struct e1000_hw *hw);
-s32  e1000_check_polarity_igp(struct e1000_hw *hw);
-s32  e1000_check_polarity_ife(struct e1000_hw *hw);
-s32  e1000_check_reset_block_generic(struct e1000_hw *hw);
-s32  e1000_copper_link_autoneg(struct e1000_hw *hw);
-s32  e1000_copper_link_setup_igp(struct e1000_hw *hw);
-s32  e1000_copper_link_setup_m88(struct e1000_hw *hw);
-#if 0
-s32  e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw);
-s32  e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw);
-s32  e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw);
-#endif
-#if 0
-s32  e1000_get_cable_length_m88(struct e1000_hw *hw);
-s32  e1000_get_cable_length_igp_2(struct e1000_hw *hw);
-#endif
-s32  e1000_get_cfg_done_generic(struct e1000_hw *hw);
-s32  e1000_get_phy_id(struct e1000_hw *hw);
-s32  e1000_get_phy_info_igp(struct e1000_hw *hw);
-s32  e1000_get_phy_info_m88(struct e1000_hw *hw);
-s32  e1000_phy_sw_reset_generic(struct e1000_hw *hw);
-#if 0
-void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
-#endif
-s32  e1000_phy_hw_reset_generic(struct e1000_hw *hw);
-s32  e1000_phy_reset_dsp_generic(struct e1000_hw *hw);
-s32  e1000_phy_setup_autoneg(struct e1000_hw *hw);
-s32  e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active);
-s32  e1000_setup_copper_link_generic(struct e1000_hw *hw);
-s32  e1000_wait_autoneg_generic(struct e1000_hw *hw);
-s32  e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data);
-s32  e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
-s32  e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
-s32  e1000_phy_reset_dsp(struct e1000_hw *hw);
-s32  e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
-                                u32 usec_interval, bool *success);
-s32  e1000_phy_init_script_igp3(struct e1000_hw *hw);
-enum e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id);
-s32  e1000_determine_phy_address(struct e1000_hw *hw);
-void e1000_power_up_phy_copper(struct e1000_hw *hw);
-void e1000_power_down_phy_copper(struct e1000_hw *hw);
-s32  e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
-
-#define E1000_MAX_PHY_ADDR                4
-
-/* IGP01E1000 Specific Registers */
-#define IGP01E1000_PHY_PORT_CONFIG        0x10 /* Port Config */
-#define IGP01E1000_PHY_PORT_STATUS        0x11 /* Status */
-#define IGP01E1000_PHY_PORT_CTRL          0x12 /* Control */
-#define IGP01E1000_PHY_LINK_HEALTH        0x13 /* PHY Link Health */
-#define IGP01E1000_GMII_FIFO              0x14 /* GMII FIFO */
-#define IGP01E1000_PHY_CHANNEL_QUALITY    0x15 /* PHY Channel Quality */
-#define IGP02E1000_PHY_POWER_MGMT         0x19 /* Power Management */
-#define IGP01E1000_PHY_PAGE_SELECT        0x1F /* Page Select */
-#define BM_PHY_PAGE_SELECT                22   /* Page Select for BM */
-#define IGP_PAGE_SHIFT                    5
-#define PHY_REG_MASK                      0x1F
-
-#define IGP01E1000_PHY_PCS_INIT_REG       0x00B4
-#define IGP01E1000_PHY_POLARITY_MASK      0x0078
-
-#define IGP01E1000_PSCR_AUTO_MDIX         0x1000
-#define IGP01E1000_PSCR_FORCE_MDI_MDIX    0x2000 /* 0=MDI, 1=MDIX */
-
-#define IGP01E1000_PSCFR_SMART_SPEED      0x0080
-
-/* Enable flexible speed on link-up */
-#define IGP01E1000_GMII_FLEX_SPD          0x0010
-#define IGP01E1000_GMII_SPD               0x0020 /* Enable SPD */
-
-#define IGP02E1000_PM_SPD                 0x0001 /* Smart Power Down */
-#define IGP02E1000_PM_D0_LPLU             0x0002 /* For D0a states */
-#define IGP02E1000_PM_D3_LPLU             0x0004 /* For all other states */
-
-#define IGP01E1000_PLHR_SS_DOWNGRADE      0x8000
-
-#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
-#define IGP01E1000_PSSR_MDIX              0x0800
-#define IGP01E1000_PSSR_SPEED_MASK        0xC000
-#define IGP01E1000_PSSR_SPEED_1000MBPS    0xC000
-
-#define IGP02E1000_PHY_CHANNEL_NUM        4
-#define IGP02E1000_PHY_AGC_A              0x11B1
-#define IGP02E1000_PHY_AGC_B              0x12B1
-#define IGP02E1000_PHY_AGC_C              0x14B1
-#define IGP02E1000_PHY_AGC_D              0x18B1
-
-#define IGP02E1000_AGC_LENGTH_SHIFT       9   /* Course - 15:13, Fine - 12:9 */
-#define IGP02E1000_AGC_LENGTH_MASK        0x7F
-#define IGP02E1000_AGC_RANGE              15
-
-#define IGP03E1000_PHY_MISC_CTRL          0x1B
-#define IGP03E1000_PHY_MISC_DUPLEX_MANUAL_SET  0x1000 /* Manually Set Duplex */
-
-#define E1000_CABLE_LENGTH_UNDEFINED      0xFF
-
-#define E1000_KMRNCTRLSTA_OFFSET          0x001F0000
-#define E1000_KMRNCTRLSTA_OFFSET_SHIFT    16
-#define E1000_KMRNCTRLSTA_REN             0x00200000
-#define E1000_KMRNCTRLSTA_DIAG_OFFSET     0x3    /* Kumeran Diagnostic */
-#define E1000_KMRNCTRLSTA_TIMEOUTS        0x4    /* Kumeran Timeouts */
-#define E1000_KMRNCTRLSTA_INBAND_PARAM    0x9    /* Kumeran InBand Parameters */
-#define E1000_KMRNCTRLSTA_DIAG_NELPBK     0x1000 /* Nearend Loopback mode */
-
-#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
-#define IFE_PHY_SPECIAL_CONTROL     0x11 /* 100BaseTx PHY Special Control */
-#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */
-#define IFE_PHY_MDIX_CONTROL        0x1C /* MDI/MDI-X Control */
-
-/* IFE PHY Extended Status Control */
-#define IFE_PESC_POLARITY_REVERSED    0x0100
-
-/* IFE PHY Special Control */
-#define IFE_PSC_AUTO_POLARITY_DISABLE      0x0010
-#define IFE_PSC_FORCE_POLARITY             0x0020
-#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100
-
-/* IFE PHY Special Control and LED Control */
-#define IFE_PSCL_PROBE_MODE            0x0020
-#define IFE_PSCL_PROBE_LEDS_OFF        0x0006 /* Force LEDs 0 and 2 off */
-#define IFE_PSCL_PROBE_LEDS_ON         0x0007 /* Force LEDs 0 and 2 on */
-
-/* IFE PHY MDIX Control */
-#define IFE_PMC_MDIX_STATUS      0x0020 /* 1=MDI-X, 0=MDI */
-#define IFE_PMC_FORCE_MDIX       0x0040 /* 1=force MDI-X, 0=force MDI */
-#define IFE_PMC_AUTO_MDIX        0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000/e1000_regs.h b/roms/ipxe/src/drivers/net/e1000/e1000_regs.h
deleted file mode 100644
index 579c0707b0d8e188814bcfbd6c3c7e12bdf7d66b..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000/e1000_regs.h
+++ /dev/null
@@ -1,329 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000_REGS_H_
-#define _E1000_REGS_H_
-
-#define E1000_CTRL     0x00000  /* Device Control - RW */
-#define E1000_CTRL_DUP 0x00004  /* Device Control Duplicate (Shadow) - RW */
-#define E1000_STATUS   0x00008  /* Device Status - RO */
-#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
-#define E1000_EERD     0x00014  /* EEPROM Read - RW */
-#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
-#define E1000_FLA      0x0001C  /* Flash Access - RW */
-#define E1000_MDIC     0x00020  /* MDI Control - RW */
-#define E1000_SCTL     0x00024  /* SerDes Control - RW */
-#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
-#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
-#define E1000_FEXT     0x0002C  /* Future Extended - RW */
-#define E1000_FEXTNVM  0x00028  /* Future Extended NVM - RW */
-#define E1000_FCT      0x00030  /* Flow Control Type - RW */
-#define E1000_CONNSW   0x00034  /* Copper/Fiber switch control - RW */
-#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
-#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
-#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
-#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
-#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
-#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
-#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
-#define E1000_RCTL     0x00100  /* Rx Control - RW */
-#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
-#define E1000_TXCW     0x00178  /* Tx Configuration Word - RW */
-#define E1000_RXCW     0x00180  /* Rx Configuration Word - RO */
-#define E1000_TCTL     0x00400  /* Tx Control - RW */
-#define E1000_TCTL_EXT 0x00404  /* Extended Tx Control - RW */
-#define E1000_TIPG     0x00410  /* Tx Inter-packet gap -RW */
-#define E1000_TBT      0x00448  /* Tx Burst Timer - RW */
-#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
-#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
-#define E1000_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
-#define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
-#define E1000_PHY_CTRL     0x00F10  /* PHY Control Register in CSR */
-#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
-#define E1000_PBS      0x01008  /* Packet Buffer Size */
-#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
-#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
-#define E1000_FLASHT   0x01028  /* FLASH Timer Register */
-#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
-#define E1000_FLSWCTL  0x01030  /* FLASH control register */
-#define E1000_FLSWDATA 0x01034  /* FLASH data register */
-#define E1000_FLSWCNT  0x01038  /* FLASH Access Counter */
-#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
-#define E1000_I2CCMD   0x01028  /* SFPI2C Command Register - RW */
-#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */
-#define E1000_WDSTP    0x01040  /* Watchdog Setup - RW */
-#define E1000_SWDSTS   0x01044  /* SW Device Status - RW */
-#define E1000_FRTIMER  0x01048  /* Free Running Timer - RW */
-#define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
-#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
-#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
-#define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - RW */
-#define E1000_RDFPCQ(_n)  (0x02430 + (0x4 * (_n)))
-#define E1000_PBRTH    0x02458  /* PB Rx Arbitration Threshold - RW */
-#define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */
-/* Split and Replication Rx Control - RW */
-#define E1000_RDPUMB   0x025CC  /* DMA Rx Descriptor uC Mailbox - RW */
-#define E1000_RDPUAD   0x025D0  /* DMA Rx Descriptor uC Addr Command - RW */
-#define E1000_RDPUWD   0x025D4  /* DMA Rx Descriptor uC Data Write - RW */
-#define E1000_RDPURD   0x025D8  /* DMA Rx Descriptor uC Data Read - RW */
-#define E1000_RDPUCTL  0x025DC  /* DMA Rx Descriptor uC Control - RW */
-#define E1000_RXCTL(_n)   (0x0C014 + (0x40 * (_n)))
-#define E1000_RQDPC(_n)   (0x0C030 + (0x40 * (_n)))
-#define E1000_RDTR     0x02820  /* Rx Delay Timer - RW */
-#define E1000_RADV     0x0282C  /* Rx Interrupt Absolute Delay Timer - RW */
-/*
- * Convenience macros
- *
- * Note: "_n" is the queue number of the register to be written to.
- *
- * Example usage:
- * E1000_RDBAL_REG(current_rx_queue)
- */
-#define E1000_RDBAL(_n)      ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \
-                                         (0x0C000 + ((_n) * 0x40)))
-#define E1000_RDBAH(_n)      ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \
-                                         (0x0C004 + ((_n) * 0x40)))
-#define E1000_RDLEN(_n)      ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \
-                                         (0x0C008 + ((_n) * 0x40)))
-#define E1000_SRRCTL(_n)     ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \
-                                         (0x0C00C + ((_n) * 0x40)))
-#define E1000_RDH(_n)        ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \
-                                         (0x0C010 + ((_n) * 0x40)))
-#define E1000_RDT(_n)        ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \
-                                         (0x0C018 + ((_n) * 0x40)))
-#define E1000_RXDCTL(_n)     ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \
-                                         (0x0C028 + ((_n) * 0x40)))
-#define E1000_TDBAL(_n)      ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \
-                                         (0x0E000 + ((_n) * 0x40)))
-#define E1000_TDBAH(_n)      ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \
-                                         (0x0E004 + ((_n) * 0x40)))
-#define E1000_TDLEN(_n)      ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \
-                                         (0x0E008 + ((_n) * 0x40)))
-#define E1000_TDH(_n)        ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \
-                                         (0x0E010 + ((_n) * 0x40)))
-#define E1000_TDT(_n)        ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \
-                                         (0x0E018 + ((_n) * 0x40)))
-#define E1000_TXDCTL(_n)     ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \
-                                         (0x0E028 + ((_n) * 0x40)))
-#define E1000_TARC(_n)       (0x03840 + (_n << 8))
-#define E1000_DCA_TXCTRL(_n) (0x03814 + (_n << 8))
-#define E1000_DCA_RXCTRL(_n) (0x02814 + (_n << 8))
-#define E1000_TDWBAL(_n)     ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : \
-                                         (0x0E038 + ((_n) * 0x40)))
-#define E1000_TDWBAH(_n)     ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : \
-                                         (0x0E03C + ((_n) * 0x40)))
-#define E1000_RSRPD    0x02C00  /* Rx Small Packet Detect - RW */
-#define E1000_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
-#define E1000_TXDMAC   0x03000  /* Tx DMA Control - RW */
-#define E1000_KABGTXD  0x03004  /* AFE Band Gap Transmit Ref Data */
-#define E1000_PSRTYPE(_i)       (0x05480 + ((_i) * 4))
-#define E1000_RAL(_i)  (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
-                                       (0x054E0 + ((_i - 16) * 8)))
-#define E1000_RAH(_i)  (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
-                                       (0x054E4 + ((_i - 16) * 8)))
-#define E1000_IP4AT_REG(_i)     (0x05840 + ((_i) * 8))
-#define E1000_IP6AT_REG(_i)     (0x05880 + ((_i) * 4))
-#define E1000_WUPM_REG(_i)      (0x05A00 + ((_i) * 4))
-#define E1000_FFMT_REG(_i)      (0x09000 + ((_i) * 8))
-#define E1000_FFVT_REG(_i)      (0x09800 + ((_i) * 8))
-#define E1000_FFLT_REG(_i)      (0x05F00 + ((_i) * 8))
-#define E1000_TDFH     0x03410  /* Tx Data FIFO Head - RW */
-#define E1000_TDFT     0x03418  /* Tx Data FIFO Tail - RW */
-#define E1000_TDFHS    0x03420  /* Tx Data FIFO Head Saved - RW */
-#define E1000_TDFTS    0x03428  /* Tx Data FIFO Tail Saved - RW */
-#define E1000_TDFPC    0x03430  /* Tx Data FIFO Packet Count - RW */
-#define E1000_TDPUMB   0x0357C  /* DMA Tx Descriptor uC Mail Box - RW */
-#define E1000_TDPUAD   0x03580  /* DMA Tx Descriptor uC Addr Command - RW */
-#define E1000_TDPUWD   0x03584  /* DMA Tx Descriptor uC Data Write - RW */
-#define E1000_TDPURD   0x03588  /* DMA Tx Descriptor uC Data  Read  - RW */
-#define E1000_TDPUCTL  0x0358C  /* DMA Tx Descriptor uC Control - RW */
-#define E1000_DTXCTL   0x03590  /* DMA Tx Control - RW */
-#define E1000_TIDV     0x03820  /* Tx Interrupt Delay Value - RW */
-#define E1000_TADV     0x0382C  /* Tx Interrupt Absolute Delay Val - RW */
-#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
-#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
-#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
-#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
-#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
-#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
-#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
-#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
-#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
-#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
-#define E1000_COLC     0x04028  /* Collision Count - R/clr */
-#define E1000_DC       0x04030  /* Defer Count - R/clr */
-#define E1000_TNCRS    0x04034  /* Tx-No CRS - R/clr */
-#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
-#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
-#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
-#define E1000_XONRXC   0x04048  /* XON Rx Count - R/clr */
-#define E1000_XONTXC   0x0404C  /* XON Tx Count - R/clr */
-#define E1000_XOFFRXC  0x04050  /* XOFF Rx Count - R/clr */
-#define E1000_XOFFTXC  0x04054  /* XOFF Tx Count - R/clr */
-#define E1000_FCRUC    0x04058  /* Flow Control Rx Unsupported Count- R/clr */
-#define E1000_PRC64    0x0405C  /* Packets Rx (64 bytes) - R/clr */
-#define E1000_PRC127   0x04060  /* Packets Rx (65-127 bytes) - R/clr */
-#define E1000_PRC255   0x04064  /* Packets Rx (128-255 bytes) - R/clr */
-#define E1000_PRC511   0x04068  /* Packets Rx (255-511 bytes) - R/clr */
-#define E1000_PRC1023  0x0406C  /* Packets Rx (512-1023 bytes) - R/clr */
-#define E1000_PRC1522  0x04070  /* Packets Rx (1024-1522 bytes) - R/clr */
-#define E1000_GPRC     0x04074  /* Good Packets Rx Count - R/clr */
-#define E1000_BPRC     0x04078  /* Broadcast Packets Rx Count - R/clr */
-#define E1000_MPRC     0x0407C  /* Multicast Packets Rx Count - R/clr */
-#define E1000_GPTC     0x04080  /* Good Packets Tx Count - R/clr */
-#define E1000_GORCL    0x04088  /* Good Octets Rx Count Low - R/clr */
-#define E1000_GORCH    0x0408C  /* Good Octets Rx Count High - R/clr */
-#define E1000_GOTCL    0x04090  /* Good Octets Tx Count Low - R/clr */
-#define E1000_GOTCH    0x04094  /* Good Octets Tx Count High - R/clr */
-#define E1000_RNBC     0x040A0  /* Rx No Buffers Count - R/clr */
-#define E1000_RUC      0x040A4  /* Rx Undersize Count - R/clr */
-#define E1000_RFC      0x040A8  /* Rx Fragment Count - R/clr */
-#define E1000_ROC      0x040AC  /* Rx Oversize Count - R/clr */
-#define E1000_RJC      0x040B0  /* Rx Jabber Count - R/clr */
-#define E1000_MGTPRC   0x040B4  /* Management Packets Rx Count - R/clr */
-#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
-#define E1000_MGTPTC   0x040BC  /* Management Packets Tx Count - R/clr */
-#define E1000_TORL     0x040C0  /* Total Octets Rx Low - R/clr */
-#define E1000_TORH     0x040C4  /* Total Octets Rx High - R/clr */
-#define E1000_TOTL     0x040C8  /* Total Octets Tx Low - R/clr */
-#define E1000_TOTH     0x040CC  /* Total Octets Tx High - R/clr */
-#define E1000_TPR      0x040D0  /* Total Packets Rx - R/clr */
-#define E1000_TPT      0x040D4  /* Total Packets Tx - R/clr */
-#define E1000_PTC64    0x040D8  /* Packets Tx (64 bytes) - R/clr */
-#define E1000_PTC127   0x040DC  /* Packets Tx (65-127 bytes) - R/clr */
-#define E1000_PTC255   0x040E0  /* Packets Tx (128-255 bytes) - R/clr */
-#define E1000_PTC511   0x040E4  /* Packets Tx (256-511 bytes) - R/clr */
-#define E1000_PTC1023  0x040E8  /* Packets Tx (512-1023 bytes) - R/clr */
-#define E1000_PTC1522  0x040EC  /* Packets Tx (1024-1522 Bytes) - R/clr */
-#define E1000_MPTC     0x040F0  /* Multicast Packets Tx Count - R/clr */
-#define E1000_BPTC     0x040F4  /* Broadcast Packets Tx Count - R/clr */
-#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context Tx - R/clr */
-#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context Tx Fail - R/clr */
-#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
-#define E1000_ICRXPTC  0x04104  /* Interrupt Cause Rx Pkt Timer Expire Count */
-#define E1000_ICRXATC  0x04108  /* Interrupt Cause Rx Abs Timer Expire Count */
-#define E1000_ICTXPTC  0x0410C  /* Interrupt Cause Tx Pkt Timer Expire Count */
-#define E1000_ICTXATC  0x04110  /* Interrupt Cause Tx Abs Timer Expire Count */
-#define E1000_ICTXQEC  0x04118  /* Interrupt Cause Tx Queue Empty Count */
-#define E1000_ICTXQMTC 0x0411C  /* Interrupt Cause Tx Queue Min Thresh Count */
-#define E1000_ICRXDMTC 0x04120  /* Interrupt Cause Rx Desc Min Thresh Count */
-#define E1000_ICRXOC   0x04124  /* Interrupt Cause Receiver Overrun Count */
-
-#define E1000_PCS_CFG0    0x04200  /* PCS Configuration 0 - RW */
-#define E1000_PCS_LCTL    0x04208  /* PCS Link Control - RW */
-#define E1000_PCS_LSTAT   0x0420C  /* PCS Link Status - RO */
-#define E1000_CBTMPC      0x0402C  /* Circuit Breaker Tx Packet Count */
-#define E1000_HTDPMC      0x0403C  /* Host Transmit Discarded Packets */
-#define E1000_CBRDPC      0x04044  /* Circuit Breaker Rx Dropped Count */
-#define E1000_CBRMPC      0x040FC  /* Circuit Breaker Rx Packet Count */
-#define E1000_RPTHC       0x04104  /* Rx Packets To Host */
-#define E1000_HGPTC       0x04118  /* Host Good Packets Tx Count */
-#define E1000_HTCBDPC     0x04124  /* Host Tx Circuit Breaker Dropped Count */
-#define E1000_HGORCL      0x04128  /* Host Good Octets Received Count Low */
-#define E1000_HGORCH      0x0412C  /* Host Good Octets Received Count High */
-#define E1000_HGOTCL      0x04130  /* Host Good Octets Transmit Count Low */
-#define E1000_HGOTCH      0x04134  /* Host Good Octets Transmit Count High */
-#define E1000_LENERRS     0x04138  /* Length Errors Count */
-#define E1000_SCVPC       0x04228  /* SerDes/SGMII Code Violation Pkt Count */
-#define E1000_HRMPC       0x0A018  /* Header Redirection Missed Packet Count */
-#define E1000_PCS_ANADV   0x04218  /* AN advertisement - RW */
-#define E1000_PCS_LPAB    0x0421C  /* Link Partner Ability - RW */
-#define E1000_PCS_NPTX    0x04220  /* AN Next Page Transmit - RW */
-#define E1000_PCS_LPABNP  0x04224  /* Link Partner Ability Next Page - RW */
-#define E1000_1GSTAT_RCV  0x04228  /* 1GSTAT Code Violation Packet Count - RW */
-#define E1000_RXCSUM   0x05000  /* Rx Checksum Control - RW */
-#define E1000_RLPML    0x05004  /* Rx Long Packet Max Length */
-#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
-#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
-#define E1000_RA       0x05400  /* Receive Address - RW Array */
-#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
-#define E1000_VT_CTL   0x0581C  /* VMDq Control - RW */
-#define E1000_VFQA0    0x0B000  /* VLAN Filter Queue Array 0 - RW Array */
-#define E1000_VFQA1    0x0B200  /* VLAN Filter Queue Array 1 - RW Array */
-#define E1000_WUC      0x05800  /* Wakeup Control - RW */
-#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
-#define E1000_WUS      0x05810  /* Wakeup Status - RO */
-#define E1000_MANC     0x05820  /* Management Control - RW */
-#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
-#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
-#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
-#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
-#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
-#define E1000_PBACL    0x05B68  /* MSIx PBA Clear - Read/Write 1's to clear */
-#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
-#define E1000_HOST_IF  0x08800  /* Host Interface */
-#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
-#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
-
-#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */
-#define E1000_MDPHYA      0x0003C /* PHY address - RW */
-#define E1000_MANC2H      0x05860 /* Management Control To Host - RW */
-#define E1000_SW_FW_SYNC  0x05B5C /* Software-Firmware Synchronization - RW */
-#define E1000_CCMCTL      0x05B48 /* CCM Control Register */
-#define E1000_GIOCTL      0x05B44 /* GIO Analog Control Register */
-#define E1000_SCCTL       0x05B4C /* PCIc PLL Configuration Register */
-#define E1000_GCR         0x05B00 /* PCI-Ex Control */
-#define E1000_GCR2        0x05B64 /* PCI-Ex Control #2 */
-#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
-#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
-#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
-#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
-#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
-#define E1000_SWSM      0x05B50 /* SW Semaphore */
-#define E1000_FWSM      0x05B54 /* FW Semaphore */
-#define E1000_SWSM2     0x05B58 /* Driver-only SW semaphore (not used by BOOT agents) */
-#define E1000_DCA_ID    0x05B70 /* DCA Requester ID Information - RO */
-#define E1000_DCA_CTRL  0x05B74 /* DCA Control - RW */
-#define E1000_FFLT_DBG  0x05F04 /* Debug Register */
-#define E1000_HICR      0x08F00 /* Host Interface Control */
-
-/* RSS registers */
-#define E1000_CPUVEC    0x02C10 /* CPU Vector Register - RW */
-#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
-#define E1000_IMIR(_i)      (0x05A80 + ((_i) * 4))  /* Immediate Interrupt */
-#define E1000_IMIREXT(_i)   (0x05AA0 + ((_i) * 4))  /* Immediate Interrupt Ext*/
-#define E1000_IMIRVP    0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */
-#define E1000_MSIXBM(_i)    (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register
-                                                    * (_i) - RW */
-#define E1000_MSIXTADD(_i)  (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr
-                                                       * low reg - RW */
-#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr
-                                                       * upper reg - RW */
-#define E1000_MSIXTMSG(_i)  (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry
-                                                       * message reg - RW */
-#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry
-                                                       * vector ctrl reg - RW */
-#define E1000_MSIXPBA    0x0E000 /* MSI-X Pending bit array */
-#define E1000_RETA(_i)  (0x05C00 + ((_i) * 4)) /* Redirection Table - RW */
-#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW */
-#define E1000_RSSIM     0x05864 /* RSS Interrupt Mask */
-#define E1000_RSSIR     0x05868 /* RSS Interrupt Request */
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e.c b/roms/ipxe/src/drivers/net/e1000e/e1000e.c
deleted file mode 100644
index b7318b7db1b59025e503e389a271219a81e9622d..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-REQUIRE_OBJECT(e1000e_main);
-REQUIRE_OBJECT(e1000e_80003es2lan);
-REQUIRE_OBJECT(e1000e_82571);
-REQUIRE_OBJECT(e1000e_ich8lan);
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e.h b/roms/ipxe/src/drivers/net/e1000e/e1000e.h
deleted file mode 100644
index bc8e7b08328c52e7dd6b177b551efd2ae701302b..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e.h
+++ /dev/null
@@ -1,532 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/* Linux PRO/1000 Ethernet Driver main header file */
-
-#ifndef _E1000E_H_
-#define _E1000E_H_
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <ipxe/io.h>
-#include <errno.h>
-#include <byteswap.h>
-#include <ipxe/pci.h>
-#include <ipxe/malloc.h>
-#include <ipxe/if_ether.h>
-#include <ipxe/ethernet.h>
-#include <ipxe/iobuf.h>
-#include <ipxe/netdevice.h>
-
-/* Begin OS Dependencies */
-
-#define u8         unsigned char
-#define bool       boolean_t
-#define dma_addr_t unsigned long
-#define __le16     uint16_t
-#define __le32     uint32_t
-#define __le64     uint64_t
-
-#define __iomem
-
-#define msleep(x) mdelay(x)
-
-#define ETH_FCS_LEN 4
-
-typedef int spinlock_t;
-typedef enum {
-    false = 0,
-    true = 1
-} boolean_t;
-
-/* End OS Dependencies */
-
-#include "e1000e_hw.h"
-
-#define E1000_TX_FLAGS_CSUM		0x00000001
-#define E1000_TX_FLAGS_VLAN		0x00000002
-#define E1000_TX_FLAGS_TSO		0x00000004
-#define E1000_TX_FLAGS_IPV4		0x00000008
-#define E1000_TX_FLAGS_VLAN_MASK	0xffff0000
-#define E1000_TX_FLAGS_VLAN_SHIFT	16
-
-#define E1000_MAX_PER_TXD	8192
-#define E1000_MAX_TXD_PWR	12
-
-#define MINIMUM_DHCP_PACKET_SIZE 282
-
-struct e1000_info;
-
-#define e_dbg(arg...) if (0) { printf (arg); };
-
-#ifdef CONFIG_E1000E_MSIX
-/* Interrupt modes, as used by the IntMode paramter */
-#define E1000E_INT_MODE_LEGACY		0
-#define E1000E_INT_MODE_MSI		1
-#define E1000E_INT_MODE_MSIX		2
-
-#endif /* CONFIG_E1000E_MSIX */
-#ifndef CONFIG_E1000E_NAPI
-#define E1000_MAX_INTR 10
-
-#endif /* CONFIG_E1000E_NAPI */
-/* Tx/Rx descriptor defines */
-#define E1000_DEFAULT_TXD		256
-#define E1000_MAX_TXD			4096
-#define E1000_MIN_TXD			64
-
-#define E1000_DEFAULT_RXD		256
-#define E1000_MAX_RXD			4096
-#define E1000_MIN_RXD			64
-
-#define E1000_MIN_ITR_USECS		10 /* 100000 irq/sec */
-#define E1000_MAX_ITR_USECS		10000 /* 100    irq/sec */
-
-/* Early Receive defines */
-#define E1000_ERT_2048			0x100
-
-#define E1000_FC_PAUSE_TIME		0x0680 /* 858 usec */
-
-/* How many Tx Descriptors do we need to call netif_wake_queue ? */
-/* How many Rx Buffers do we bundle into one write to the hardware ? */
-#define E1000_RX_BUFFER_WRITE		16 /* Must be power of 2 */
-
-#define AUTO_ALL_MODES			0
-#define E1000_EEPROM_APME		0x0400
-
-#define E1000_MNG_VLAN_NONE		(-1)
-
-/* Number of packet split data buffers (not including the header buffer) */
-#define PS_PAGE_BUFFERS			(MAX_PS_BUFFERS - 1)
-
-#define MAXIMUM_ETHERNET_VLAN_SIZE 	1522
-
-#define DEFAULT_JUMBO			9234
-
-enum e1000_boards {
-	board_82571,
-	board_82572,
-	board_82573,
-	board_82574,
-	board_80003es2lan,
-	board_ich8lan,
-	board_ich9lan,
-	board_ich10lan,
-	board_pchlan,
-	board_82583,
-};
-
-/* board specific private data structure */
-struct e1000_adapter {
-	const struct e1000_info *ei;
-
-	/* OS defined structs */
-	struct net_device *netdev;
-	struct pci_device *pdev;
-	struct net_device_stats net_stats;
-
-	/* structs defined in e1000_hw.h */
-	struct e1000_hw hw;
-
-	struct e1000_phy_info phy_info;
-
-	u32 wol;
-	u32 pba;
-	u32 max_hw_frame_size;
-
-	bool fc_autoneg;
-
-	unsigned int flags;
-	unsigned int flags2;
-
-#define NUM_TX_DESC	8
-#define NUM_RX_DESC	8
-
-	struct io_buffer *tx_iobuf[NUM_TX_DESC];
-	struct io_buffer *rx_iobuf[NUM_RX_DESC];
-
-	struct e1000_tx_desc *tx_base;
-	struct e1000_rx_desc *rx_base;
-
-	uint32_t tx_ring_size;
-	uint32_t rx_ring_size;
-
-	uint32_t tx_head;
-	uint32_t tx_tail;
-	uint32_t tx_fill_ctr;
-
-	uint32_t rx_curr;
-
-	uint32_t ioaddr;
-	uint32_t irqno;
-
-        uint32_t tx_int_delay;
-        uint32_t tx_abs_int_delay;
-        uint32_t txd_cmd;
-};
-
-struct e1000_info {
-	enum e1000_mac_type	mac;
-	unsigned int		flags;
-	unsigned int		flags2;
-	u32			pba;
-	u32			max_hw_frame_size;
-	s32			(*get_variants)(struct e1000_adapter *);
-	void			(*init_ops)(struct e1000_hw *);
-};
-
-/* hardware capability, feature, and workaround flags */
-#define FLAG_HAS_AMT                      (1 << 0)
-#define FLAG_HAS_FLASH                    (1 << 1)
-#define FLAG_HAS_HW_VLAN_FILTER           (1 << 2)
-#define FLAG_HAS_WOL                      (1 << 3)
-#define FLAG_HAS_ERT                      (1 << 4)
-#define FLAG_HAS_CTRLEXT_ON_LOAD          (1 << 5)
-#define FLAG_HAS_SWSM_ON_LOAD             (1 << 6)
-#define FLAG_HAS_JUMBO_FRAMES             (1 << 7)
-#define FLAG_IS_ICH                       (1 << 9)
-#ifdef CONFIG_E1000E_MSIX
-#define FLAG_HAS_MSIX                     (1 << 10)
-#endif
-#define FLAG_HAS_SMART_POWER_DOWN         (1 << 11)
-#define FLAG_IS_QUAD_PORT_A               (1 << 12)
-#define FLAG_IS_QUAD_PORT                 (1 << 13)
-#define FLAG_TIPG_MEDIUM_FOR_80003ESLAN   (1 << 14)
-#define FLAG_APME_IN_WUC                  (1 << 15)
-#define FLAG_APME_IN_CTRL3                (1 << 16)
-#define FLAG_APME_CHECK_PORT_B            (1 << 17)
-#define FLAG_DISABLE_FC_PAUSE_TIME        (1 << 18)
-#define FLAG_NO_WAKE_UCAST                (1 << 19)
-#define FLAG_MNG_PT_ENABLED               (1 << 20)
-#define FLAG_RESET_OVERWRITES_LAA         (1 << 21)
-#define FLAG_TARC_SPEED_MODE_BIT          (1 << 22)
-#define FLAG_TARC_SET_BIT_ZERO            (1 << 23)
-#define FLAG_RX_NEEDS_RESTART             (1 << 24)
-#define FLAG_LSC_GIG_SPEED_DROP           (1 << 25)
-#define FLAG_SMART_POWER_DOWN             (1 << 26)
-#define FLAG_MSI_ENABLED                  (1 << 27)
-#define FLAG_RX_CSUM_ENABLED              (1 << 28)
-#define FLAG_TSO_FORCE                    (1 << 29)
-#define FLAG_RX_RESTART_NOW               (1 << 30)
-#define FLAG_MSI_TEST_FAILED              (1 << 31)
-
-/* CRC Stripping defines */
-#define FLAG2_CRC_STRIPPING               (1 << 0)
-#define FLAG2_HAS_PHY_WAKEUP              (1 << 1)
-
-#define E1000_RX_DESC_PS(R, i)	    \
-	(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
-#define E1000_GET_DESC(R, i, type)	(&(((struct type *)((R).desc))[i]))
-#define E1000_RX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_rx_desc)
-#define E1000_TX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_tx_desc)
-#define E1000_CONTEXT_DESC(R, i)	E1000_GET_DESC(R, i, e1000_context_desc)
-
-enum e1000_state_t {
-	__E1000E_TESTING,
-	__E1000E_RESETTING,
-	__E1000E_DOWN
-};
-
-enum latency_range {
-	lowest_latency = 0,
-	low_latency = 1,
-	bulk_latency = 2,
-	latency_invalid = 255
-};
-
-extern void e1000e_check_options(struct e1000_adapter *adapter);
-
-extern void e1000e_reset(struct e1000_adapter *adapter);
-extern void e1000e_power_up_phy(struct e1000_adapter *adapter);
-
-extern void e1000e_init_function_pointers_82571(struct e1000_hw *hw)
-						__attribute__((weak));
-extern void e1000e_init_function_pointers_80003es2lan(struct e1000_hw *hw)
-						__attribute__((weak));
-extern void e1000e_init_function_pointers_ich8lan(struct e1000_hw *hw)
-						__attribute__((weak));
-
-extern int e1000e_probe(struct pci_device *pdev);
-
-extern void e1000e_remove(struct pci_device *pdev);
-
-extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num);
-
-static inline s32 e1000e_commit_phy(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.commit)
-		return hw->phy.ops.commit(hw);
-
-	return 0;
-}
-
-extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw);
-
-extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
-extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
-
-extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
-						 bool state);
-extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
-extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
-extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw);
-
-extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
-extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
-extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw);
-extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw);
-extern s32 e1000e_led_on_generic(struct e1000_hw *hw);
-extern s32 e1000e_led_off_generic(struct e1000_hw *hw);
-extern s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw);
-extern s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex);
-extern s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex);
-extern s32 e1000e_disable_pcie_master(struct e1000_hw *hw);
-extern s32 e1000e_get_auto_rd_done(struct e1000_hw *hw);
-extern s32 e1000e_id_led_init(struct e1000_hw *hw);
-extern void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw);
-extern s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw);
-extern s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw);
-extern s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw);
-extern s32 e1000e_setup_link(struct e1000_hw *hw);
-static inline void e1000e_clear_vfta(struct e1000_hw *hw)
-{
-	hw->mac.ops.clear_vfta(hw);
-}
-extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
-extern void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
-					       u8 *mc_addr_list,
-					       u32 mc_addr_count);
-extern void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
-extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw);
-extern void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop);
-extern s32 e1000e_get_hw_semaphore(struct e1000_hw *hw);
-extern s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data);
-extern void e1000e_config_collision_dist(struct e1000_hw *hw);
-extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw);
-extern s32 e1000e_force_mac_fc(struct e1000_hw *hw);
-extern s32 e1000e_blink_led(struct e1000_hw *hw);
-extern void e1000e_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
-static inline void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
-{
-	if (hw->mac.ops.write_vfta)
-		hw->mac.ops.write_vfta(hw, offset, value);
-}
-extern void e1000e_reset_adaptive(struct e1000_hw *hw);
-extern void e1000e_update_adaptive(struct e1000_hw *hw);
-
-extern s32 e1000e_setup_copper_link(struct e1000_hw *hw);
-extern void e1000e_put_hw_semaphore(struct e1000_hw *hw);
-extern s32 e1000e_check_reset_block_generic(struct e1000_hw *hw);
-#if 0
-extern s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw);
-#endif
-#if 0
-extern s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw);
-#endif
-extern s32 e1000e_get_phy_info_igp(struct e1000_hw *hw);
-extern s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw);
-extern s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active);
-extern s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_phy_sw_reset(struct e1000_hw *hw);
-#if 0
-extern s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw);
-#endif
-extern s32 e1000e_get_cfg_done(struct e1000_hw *hw);
-#if 0
-extern s32 e1000e_get_cable_length_m88(struct e1000_hw *hw);
-#endif
-extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw);
-extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
-extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
-extern s32 e1000e_determine_phy_address(struct e1000_hw *hw);
-extern s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data);
-#if 0
-extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
-#endif
-extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
-			       u32 usec_interval, bool *success);
-extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw);
-extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
-extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
-extern s32 e1000e_check_downshift(struct e1000_hw *hw);
-
-static inline s32 e1000e_phy_hw_reset(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.reset)
-		return hw->phy.ops.reset(hw);
-
-	return 0;
-}
-
-static inline s32 e1000e_check_reset_block(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.check_reset_block)
-		return hw->phy.ops.check_reset_block(hw);
-
-	return 0;
-}
-
-static inline s32 e1e_rphy(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	if (hw->phy.ops.read_reg)
-		return hw->phy.ops.read_reg(hw, offset, data);
-
-	return 0;
-}
-
-static inline s32 e1e_wphy(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	if (hw->phy.ops.write_reg)
-		return hw->phy.ops.write_reg(hw, offset, data);
-
-	return 0;
-}
-
-#if 0
-static inline s32 e1000e_get_cable_length(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.get_cable_length)
-		return hw->phy.ops.get_cable_length(hw);
-
-	return 0;
-}
-#endif
-
-extern s32 e1000e_acquire_nvm(struct e1000_hw *hw);
-extern s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
-extern s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw);
-extern s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
-extern s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
-extern s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw);
-extern void e1000e_release_nvm(struct e1000_hw *hw);
-
-static inline s32 e1000e_read_mac_addr(struct e1000_hw *hw)
-{
-       if (hw->mac.ops.read_mac_addr)
-               return hw->mac.ops.read_mac_addr(hw);
-
-       return e1000e_read_mac_addr_generic(hw);
-}
-
-static inline s32 e1000e_validate_nvm_checksum(struct e1000_hw *hw)
-{
-	return hw->nvm.ops.validate(hw);
-}
-
-static inline s32 e1000e_update_nvm_checksum(struct e1000_hw *hw)
-{
-	return hw->nvm.ops.update(hw);
-}
-
-static inline s32 e1000e_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	return hw->nvm.ops.read(hw, offset, words, data);
-}
-
-static inline s32 e1000e_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	return hw->nvm.ops.write(hw, offset, words, data);
-}
-
-static inline s32 e1000e_get_phy_info(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.get_info)
-		return hw->phy.ops.get_info(hw);
-
-	return 0;
-}
-
-extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
-#if 0
-extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length);
-#endif
-
-static inline u32 __er32(struct e1000_hw *hw, unsigned long reg)
-{
-	return readl(hw->hw_addr + reg);
-}
-
-static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val)
-{
-	writel(val, hw->hw_addr + reg);
-}
-
-#define er32(reg)	__er32(hw, E1000_##reg)
-#define ew32(reg, val)	__ew32(hw, E1000_##reg, (val))
-#define e1e_flush()	er32(STATUS)
-
-#define E1000_WRITE_REG(a, reg, value)  \
-    writel((value), ((a)->hw_addr + reg))
-
-#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + reg))
-
-#define E1000_WRITE_REG_ARRAY(a, reg, offset, value)  \
-    writel((value), ((a)->hw_addr + reg + ((offset) << 2)))
-
-#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
-    readl((a)->hw_addr + reg + ((offset) << 2)))
-
-#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
-#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY
-
-static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
-{
-	return readw(hw->flash_address + reg);
-}
-
-static inline u32 __er32flash(struct e1000_hw *hw, unsigned long reg)
-{
-	return readl(hw->flash_address + reg);
-}
-
-static inline void __ew16flash(struct e1000_hw *hw, unsigned long reg, u16 val)
-{
-	writew(val, hw->flash_address + reg);
-}
-
-static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val)
-{
-	writel(val, hw->flash_address + reg);
-}
-
-#define er16flash(reg)		__er16flash(hw, (reg))
-#define er32flash(reg)		__er32flash(hw, (reg))
-#define ew16flash(reg, val)	__ew16flash(hw, (reg), (val))
-#define ew32flash(reg, val)	__ew32flash(hw, (reg), (val))
-
-#endif /* _E1000E_H_ */
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_80003es2lan.c b/roms/ipxe/src/drivers/net/e1000e/e1000e_80003es2lan.c
deleted file mode 100644
index a3eed9b731af6b79b0f90b6507e4964266c104e4..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_80003es2lan.c
+++ /dev/null
@@ -1,1533 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/*
- * 80003ES2LAN Gigabit Ethernet Controller (Copper)
- * 80003ES2LAN Gigabit Ethernet Controller (Serdes)
- */
-
-#include "e1000e.h"
-
-static s32  e1000e_init_phy_params_80003es2lan(struct e1000_hw *hw);
-static s32  e1000e_init_nvm_params_80003es2lan(struct e1000_hw *hw);
-static s32  e1000e_init_mac_params_80003es2lan(struct e1000_hw *hw);
-static s32  e1000e_acquire_phy_80003es2lan(struct e1000_hw *hw);
-static void e1000e_release_phy_80003es2lan(struct e1000_hw *hw);
-static s32  e1000e_acquire_nvm_80003es2lan(struct e1000_hw *hw);
-static void e1000e_release_nvm_80003es2lan(struct e1000_hw *hw);
-static s32  e1000e_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
-                                                   u32 offset,
-                                                   u16 *data);
-static s32  e1000e_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
-                                                    u32 offset,
-                                                    u16 data);
-static s32  e1000e_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset,
-                                        u16 words, u16 *data);
-static s32  e1000e_get_cfg_done_80003es2lan(struct e1000_hw *hw);
-#if 0
-static s32  e1000e_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw);
-#endif
-#if 0
-static s32  e1000e_get_cable_length_80003es2lan(struct e1000_hw *hw);
-#endif
-static s32  e1000e_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed,
-                                               u16 *duplex);
-static s32  e1000e_reset_hw_80003es2lan(struct e1000_hw *hw);
-static s32  e1000e_init_hw_80003es2lan(struct e1000_hw *hw);
-static s32  e1000e_setup_copper_link_80003es2lan(struct e1000_hw *hw);
-static void e1000e_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw);
-static s32  e1000e_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
-static s32  e1000e_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex);
-static s32  e1000e_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw);
-static s32  e1000e_cfg_on_link_up_80003es2lan(struct e1000_hw *hw);
-static s32  e1000e_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
-                                            u16 *data);
-static s32  e1000e_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
-                                             u16 data);
-static s32  e1000e_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw);
-static void e1000e_initialize_hw_bits_80003es2lan(struct e1000_hw *hw);
-static void e1000e_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
-static s32  e1000e_read_mac_addr_80003es2lan(struct e1000_hw *hw);
-static void e1000e_power_down_phy_copper_80003es2lan(struct e1000_hw *hw);
-
-#if 0
-/*
- * A table for the GG82563 cable length where the range is defined
- * with a lower bound at "index" and the upper bound at
- * "index + 5".
- */
-static const u16 e1000_gg82563_cable_length_table[] =
-         { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF };
-#define GG82563_CABLE_LENGTH_TABLE_SIZE \
-                (sizeof(e1000_gg82563_cable_length_table) / \
-                 sizeof(e1000_gg82563_cable_length_table[0]))
-#endif
-
-/**
- *  e1000e_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000e_init_phy_params_80003es2lan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->phy.media_type != e1000_media_type_copper) {
-		phy->type        = e1000_phy_none;
-		goto out;
-	} else {
-		phy->ops.power_up = e1000e_power_up_phy_copper;
-		phy->ops.power_down = e1000e_power_down_phy_copper_80003es2lan;
-	}
-
-	phy->addr                = 1;
-	phy->autoneg_mask        = AUTONEG_ADVERTISE_SPEED_DEFAULT;
-	phy->reset_delay_us      = 100;
-	phy->type                = e1000_phy_gg82563;
-
-	phy->ops.acquire            = e1000e_acquire_phy_80003es2lan;
-	phy->ops.check_polarity     = e1000e_check_polarity_m88;
-	phy->ops.check_reset_block  = e1000e_check_reset_block_generic;
-	phy->ops.commit             = e1000e_phy_sw_reset;
-	phy->ops.get_cfg_done       = e1000e_get_cfg_done_80003es2lan;
-	phy->ops.get_info           = e1000e_get_phy_info_m88;
-	phy->ops.release            = e1000e_release_phy_80003es2lan;
-	phy->ops.reset              = e1000e_phy_hw_reset_generic;
-	phy->ops.set_d3_lplu_state  = e1000e_set_d3_lplu_state;
-#if 0
-	phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_80003es2lan;
-#endif
-#if 0
-	phy->ops.get_cable_length   = e1000e_get_cable_length_80003es2lan;
-#endif
-	phy->ops.read_reg           = e1000e_read_phy_reg_gg82563_80003es2lan;
-	phy->ops.write_reg          = e1000e_write_phy_reg_gg82563_80003es2lan;
-
-	phy->ops.cfg_on_link_up    = e1000e_cfg_on_link_up_80003es2lan;
-
-	/* This can only be done after all function pointers are setup. */
-	ret_val = e1000e_get_phy_id(hw);
-
-	/* Verify phy id */
-	if (phy->id != GG82563_E_PHY_ID) {
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_init_nvm_params_80003es2lan - Init ESB2 NVM func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000e_init_nvm_params_80003es2lan(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = er32(EECD);
-	u16 size;
-
-	nvm->opcode_bits        = 8;
-	nvm->delay_usec         = 1;
-	switch (nvm->override) {
-	case e1000_nvm_override_spi_large:
-		nvm->page_size    = 32;
-		nvm->address_bits = 16;
-		break;
-	case e1000_nvm_override_spi_small:
-		nvm->page_size    = 8;
-		nvm->address_bits = 8;
-		break;
-	default:
-		nvm->page_size    = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
-		nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
-		break;
-	}
-
-	nvm->type               = e1000_nvm_eeprom_spi;
-
-	size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
-	                  E1000_EECD_SIZE_EX_SHIFT);
-
-	/*
-	 * Added to a constant, "size" becomes the left-shift value
-	 * for setting word_size.
-	 */
-	size += NVM_WORD_SIZE_BASE_SHIFT;
-
-	/* EEPROM access above 16k is unsupported */
-	if (size > 14)
-		size = 14;
-	nvm->word_size	= 1 << size;
-
-	/* Function Pointers */
-	nvm->ops.acquire           = e1000e_acquire_nvm_80003es2lan;
-	nvm->ops.read              = e1000e_read_nvm_eerd;
-	nvm->ops.release           = e1000e_release_nvm_80003es2lan;
-	nvm->ops.update            = e1000e_update_nvm_checksum_generic;
-	nvm->ops.valid_led_default = e1000e_valid_led_default;
-	nvm->ops.validate          = e1000e_validate_nvm_checksum_generic;
-	nvm->ops.write             = e1000e_write_nvm_80003es2lan;
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_init_mac_params_80003es2lan - Init ESB2 MAC func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000e_init_mac_params_80003es2lan(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val = E1000_SUCCESS;
-
-	/* Set media type */
-	switch (hw->device_id) {
-	case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
-		hw->phy.media_type = e1000_media_type_internal_serdes;
-		break;
-	default:
-		hw->phy.media_type = e1000_media_type_copper;
-		break;
-	}
-
-	/* Set mta register count */
-	mac->mta_reg_count = 128;
-	/* Set rar entry count */
-	mac->rar_entry_count = E1000_RAR_ENTRIES;
-	/* Set if part includes ASF firmware */
-	mac->asf_firmware_present = true;
-	/* Set if manageability features are enabled. */
-	mac->arc_subsystem_valid =
-	        (er32(FWSM) & E1000_FWSM_MODE_MASK)
-	                ? true : false;
-
-	/* Function pointers */
-
-	/* bus type/speed/width */
-	mac->ops.get_bus_info = e1000e_get_bus_info_pcie;
-	/* reset */
-	mac->ops.reset_hw = e1000e_reset_hw_80003es2lan;
-	/* hw initialization */
-	mac->ops.init_hw = e1000e_init_hw_80003es2lan;
-	/* link setup */
-	mac->ops.setup_link = e1000e_setup_link;
-	/* physical interface link setup */
-	mac->ops.setup_physical_interface =
-	        (hw->phy.media_type == e1000_media_type_copper)
-	                ? e1000e_setup_copper_link_80003es2lan
-	                : e1000e_setup_fiber_serdes_link;
-	/* check for link */
-	switch (hw->phy.media_type) {
-	case e1000_media_type_copper:
-		mac->ops.check_for_link = e1000e_check_for_copper_link;
-		break;
-	case e1000_media_type_fiber:
-		mac->ops.check_for_link = e1000e_check_for_fiber_link;
-		break;
-	case e1000_media_type_internal_serdes:
-		mac->ops.check_for_link = e1000e_check_for_serdes_link;
-		break;
-	default:
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-		break;
-	}
-	/* check management mode */
-#if 0
-	mac->ops.check_mng_mode = e1000e_check_mng_mode_generic;
-#endif
-	/* multicast address update */
-	mac->ops.update_mc_addr_list = e1000e_update_mc_addr_list_generic;
-	/* writing VFTA */
-	mac->ops.write_vfta = e1000e_write_vfta_generic;
-	/* clearing VFTA */
-	mac->ops.clear_vfta = e1000e_clear_vfta_generic;
-	/* setting MTA */
-	mac->ops.mta_set = e1000e_mta_set_generic;
-	/* read mac address */
-	mac->ops.read_mac_addr = e1000e_read_mac_addr_80003es2lan;
-	/* ID LED init */
-	mac->ops.id_led_init = e1000e_id_led_init;
-	/* blink LED */
-	mac->ops.blink_led = e1000e_blink_led;
-	/* setup LED */
-	mac->ops.setup_led = e1000e_setup_led_generic;
-	/* cleanup LED */
-	mac->ops.cleanup_led = e1000e_cleanup_led_generic;
-	/* turn on/off LED */
-	mac->ops.led_on = e1000e_led_on_generic;
-	mac->ops.led_off = e1000e_led_off_generic;
-	/* clear hardware counters */
-	mac->ops.clear_hw_cntrs = e1000e_clear_hw_cntrs_80003es2lan;
-	/* link info */
-	mac->ops.get_link_up_info = e1000e_get_link_up_info_80003es2lan;
-
-	/* set lan id for port to determine which phy lock to use */
-	hw->mac.ops.set_lan_id(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_init_function_pointers_80003es2lan - Init ESB2 func ptrs.
- *  @hw: pointer to the HW structure
- *
- *  Called to initialize all function pointers and parameters.
- **/
-void e1000e_init_function_pointers_80003es2lan(struct e1000_hw *hw)
-{
-	e1000e_init_mac_ops_generic(hw);
-	e1000e_init_nvm_ops_generic(hw);
-	hw->mac.ops.init_params = e1000e_init_mac_params_80003es2lan;
-	hw->nvm.ops.init_params = e1000e_init_nvm_params_80003es2lan;
-	hw->phy.ops.init_params = e1000e_init_phy_params_80003es2lan;
-}
-
-/**
- *  e1000e_acquire_phy_80003es2lan - Acquire rights to access PHY
- *  @hw: pointer to the HW structure
- *
- *  A wrapper to acquire access rights to the correct PHY.
- **/
-static s32 e1000e_acquire_phy_80003es2lan(struct e1000_hw *hw)
-{
-	u16 mask;
-
-	mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
-	return e1000e_acquire_swfw_sync_80003es2lan(hw, mask);
-}
-
-/**
- *  e1000e_release_phy_80003es2lan - Release rights to access PHY
- *  @hw: pointer to the HW structure
- *
- *  A wrapper to release access rights to the correct PHY.
- **/
-static void e1000e_release_phy_80003es2lan(struct e1000_hw *hw)
-{
-	u16 mask;
-
-	mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
-	e1000e_release_swfw_sync_80003es2lan(hw, mask);
-}
-
-/**
- *  e1000e_acquire_mac_csr_80003es2lan - Acquire rights to access Kumeran register
- *  @hw: pointer to the HW structure
- *
- *  Acquire the semaphore to access the Kumeran interface.
- *
- **/
-static s32 e1000e_acquire_mac_csr_80003es2lan(struct e1000_hw *hw)
-{
-	u16 mask;
-
-	mask = E1000_SWFW_CSR_SM;
-
-	return e1000e_acquire_swfw_sync_80003es2lan(hw, mask);
-}
-
-/**
- *  e1000e_release_mac_csr_80003es2lan - Release rights to access Kumeran Register
- *  @hw: pointer to the HW structure
- *
- *  Release the semaphore used to access the Kumeran interface
- **/
-static void e1000e_release_mac_csr_80003es2lan(struct e1000_hw *hw)
-{
-	u16 mask;
-
-	mask = E1000_SWFW_CSR_SM;
-
-	e1000e_release_swfw_sync_80003es2lan(hw, mask);
-}
-
-/**
- *  e1000e_acquire_nvm_80003es2lan - Acquire rights to access NVM
- *  @hw: pointer to the HW structure
- *
- *  Acquire the semaphore to access the EEPROM.
- **/
-static s32 e1000e_acquire_nvm_80003es2lan(struct e1000_hw *hw)
-{
-	s32 ret_val;
-
-	ret_val = e1000e_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000e_acquire_nvm(hw);
-
-	if (ret_val)
-		e1000e_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_release_nvm_80003es2lan - Relinquish rights to access NVM
- *  @hw: pointer to the HW structure
- *
- *  Release the semaphore used to access the EEPROM.
- **/
-static void e1000e_release_nvm_80003es2lan(struct e1000_hw *hw)
-{
-	e1000e_release_nvm(hw);
-	e1000e_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
-}
-
-/**
- *  e1000e_acquire_swfw_sync_80003es2lan - Acquire SW/FW semaphore
- *  @hw: pointer to the HW structure
- *  @mask: specifies which semaphore to acquire
- *
- *  Acquire the SW/FW semaphore to access the PHY or NVM.  The mask
- *  will also specify which port we're acquiring the lock for.
- **/
-static s32 e1000e_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
-{
-	u32 swfw_sync;
-	u32 swmask = mask;
-	u32 fwmask = mask << 16;
-	s32 ret_val = E1000_SUCCESS;
-	s32 i = 0, timeout = 50;
-
-	while (i < timeout) {
-		if (e1000e_get_hw_semaphore(hw)) {
-			ret_val = -E1000_ERR_SWFW_SYNC;
-			goto out;
-		}
-
-		swfw_sync = er32(SW_FW_SYNC);
-		if (!(swfw_sync & (fwmask | swmask)))
-			break;
-
-		/*
-		 * Firmware currently using resource (fwmask)
-		 * or other software thread using resource (swmask)
-		 */
-		e1000e_put_hw_semaphore(hw);
-		mdelay(5);
-		i++;
-	}
-
-	if (i == timeout) {
-		e_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n");
-		ret_val = -E1000_ERR_SWFW_SYNC;
-		goto out;
-	}
-
-	swfw_sync |= swmask;
-	ew32(SW_FW_SYNC, swfw_sync);
-
-	e1000e_put_hw_semaphore(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_release_swfw_sync_80003es2lan - Release SW/FW semaphore
- *  @hw: pointer to the HW structure
- *  @mask: specifies which semaphore to acquire
- *
- *  Release the SW/FW semaphore used to access the PHY or NVM.  The mask
- *  will also specify which port we're releasing the lock for.
- **/
-static void e1000e_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
-{
-	u32 swfw_sync;
-
-	while (e1000e_get_hw_semaphore(hw) != E1000_SUCCESS)
-		; /* Empty */
-
-	swfw_sync = er32(SW_FW_SYNC);
-	swfw_sync &= ~mask;
-	ew32(SW_FW_SYNC, swfw_sync);
-
-	e1000e_put_hw_semaphore(hw);
-}
-
-/**
- *  e1000e_read_phy_reg_gg82563_80003es2lan - Read GG82563 PHY register
- *  @hw: pointer to the HW structure
- *  @offset: offset of the register to read
- *  @data: pointer to the data returned from the operation
- *
- *  Read the GG82563 PHY register.
- **/
-static s32 e1000e_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
-                                                  u32 offset, u16 *data)
-{
-	s32 ret_val;
-	u32 page_select;
-	u16 temp;
-
-	ret_val = e1000e_acquire_phy_80003es2lan(hw);
-	if (ret_val)
-		goto out;
-
-	/* Select Configuration Page */
-	if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
-		page_select = GG82563_PHY_PAGE_SELECT;
-	} else {
-		/*
-		 * Use Alternative Page Select register to access
-		 * registers 30 and 31
-		 */
-		page_select = GG82563_PHY_PAGE_SELECT_ALT;
-	}
-
-	temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
-	ret_val = e1000e_write_phy_reg_mdic(hw, page_select, temp);
-	if (ret_val) {
-		e1000e_release_phy_80003es2lan(hw);
-		goto out;
-	}
-
-	if (hw->dev_spec._80003es2lan.mdic_wa_enable == true) {
-		/*
-		 * The "ready" bit in the MDIC register may be incorrectly set
-		 * before the device has completed the "Page Select" MDI
-		 * transaction.  So we wait 200us after each MDI command...
-		 */
-		udelay(200);
-
-		/* ...and verify the command was successful. */
-		ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp);
-
-		if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
-			ret_val = -E1000_ERR_PHY;
-			e1000e_release_phy_80003es2lan(hw);
-			goto out;
-		}
-
-		udelay(200);
-
-		ret_val = e1000e_read_phy_reg_mdic(hw,
-		                                  MAX_PHY_REG_ADDRESS & offset,
-		                                  data);
-
-		udelay(200);
-	} else
-		ret_val = e1000e_read_phy_reg_mdic(hw,
-		                                  MAX_PHY_REG_ADDRESS & offset,
-		                                  data);
-
-	e1000e_release_phy_80003es2lan(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_write_phy_reg_gg82563_80003es2lan - Write GG82563 PHY register
- *  @hw: pointer to the HW structure
- *  @offset: offset of the register to read
- *  @data: value to write to the register
- *
- *  Write to the GG82563 PHY register.
- **/
-static s32 e1000e_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
-                                                   u32 offset, u16 data)
-{
-	s32 ret_val;
-	u32 page_select;
-	u16 temp;
-
-	ret_val = e1000e_acquire_phy_80003es2lan(hw);
-	if (ret_val)
-		goto out;
-
-	/* Select Configuration Page */
-	if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
-		page_select = GG82563_PHY_PAGE_SELECT;
-	} else {
-		/*
-		 * Use Alternative Page Select register to access
-		 * registers 30 and 31
-		 */
-		page_select = GG82563_PHY_PAGE_SELECT_ALT;
-	}
-
-	temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
-	ret_val = e1000e_write_phy_reg_mdic(hw, page_select, temp);
-	if (ret_val) {
-		e1000e_release_phy_80003es2lan(hw);
-		goto out;
-	}
-
-	if (hw->dev_spec._80003es2lan.mdic_wa_enable == true) {
-		/*
-		 * The "ready" bit in the MDIC register may be incorrectly set
-		 * before the device has completed the "Page Select" MDI
-		 * transaction.  So we wait 200us after each MDI command...
-		 */
-		udelay(200);
-
-		/* ...and verify the command was successful. */
-		ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp);
-
-		if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
-			ret_val = -E1000_ERR_PHY;
-			e1000e_release_phy_80003es2lan(hw);
-			goto out;
-		}
-
-		udelay(200);
-
-		ret_val = e1000e_write_phy_reg_mdic(hw,
-		                                  MAX_PHY_REG_ADDRESS & offset,
-		                                  data);
-
-		udelay(200);
-	} else
-		ret_val = e1000e_write_phy_reg_mdic(hw,
-		                                  MAX_PHY_REG_ADDRESS & offset,
-		data);
-
-	e1000e_release_phy_80003es2lan(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_write_nvm_80003es2lan - Write to ESB2 NVM
- *  @hw: pointer to the HW structure
- *  @offset: offset of the register to read
- *  @words: number of words to write
- *  @data: buffer of data to write to the NVM
- *
- *  Write "words" of data to the ESB2 NVM.
- **/
-static s32 e1000e_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset,
-                            u16 words, u16 *data)
-{
-	return e1000e_write_nvm_spi(hw, offset, words, data);
-}
-
-/**
- *  e1000e_get_cfg_done_80003es2lan - Wait for configuration to complete
- *  @hw: pointer to the HW structure
- *
- *  Wait a specific amount of time for manageability processes to complete.
- *  This is a function pointer entry point called by the phy module.
- **/
-static s32 e1000e_get_cfg_done_80003es2lan(struct e1000_hw *hw)
-{
-	s32 timeout = PHY_CFG_TIMEOUT;
-	s32 ret_val = E1000_SUCCESS;
-	u32 mask = E1000_NVM_CFG_DONE_PORT_0;
-
-	if (hw->bus.func == 1)
-		mask = E1000_NVM_CFG_DONE_PORT_1;
-
-	while (timeout) {
-		if (er32(EEMNGCTL) & mask)
-			break;
-		msleep(1);
-		timeout--;
-	}
-	if (!timeout) {
-		e_dbg("MNG configuration cycle has not completed.\n");
-		ret_val = -E1000_ERR_RESET;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-#if 0
-/**
- *  e1000e_phy_force_speed_duplex_80003es2lan - Force PHY speed and duplex
- *  @hw: pointer to the HW structure
- *
- *  Force the speed and duplex settings onto the PHY.  This is a
- *  function pointer entry point called by the phy module.
- **/
-static s32 e1000e_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 phy_data;
-	bool link;
-
-	if (!(hw->phy.ops.read_reg))
-		goto out;
-
-	/*
-	 * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
-	 * forced whenever speed and duplex are forced.
-	 */
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_AUTO;
-	ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, phy_data);
-	if (ret_val)
-		goto out;
-
-	e_dbg("GG82563 PSCR: %X\n", phy_data);
-
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
-
-	/* Reset the phy to commit changes. */
-	phy_data |= MII_CR_RESET;
-
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
-	if (ret_val)
-		goto out;
-
-	udelay(1);
-
-	if (hw->phy.autoneg_wait_to_complete) {
-		e_dbg("Waiting for forced speed/duplex link "
-		         "on GG82563 phy.\n");
-
-		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
-		                                     100000, &link);
-		if (ret_val)
-			goto out;
-
-		if (!link) {
-			/*
-			 * We didn't get link.
-			 * Reset the DSP and cross our fingers.
-			 */
-			ret_val = e1000e_phy_reset_dsp(hw);
-			if (ret_val)
-				goto out;
-		}
-
-		/* Try once more */
-		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
-		                                     100000, &link);
-		if (ret_val)
-			goto out;
-	}
-
-	ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Resetting the phy means we need to verify the TX_CLK corresponds
-	 * to the link speed.  10Mbps -> 2.5MHz, else 25MHz.
-	 */
-	phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
-	if (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED)
-		phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5;
-	else
-		phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25;
-
-	/*
-	 * In addition, we must re-enable CRS on Tx for both half and full
-	 * duplex.
-	 */
-	phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
-	ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
-
-out:
-	return ret_val;
-}
-#endif
-
-#if 0
-/**
- *  e1000e_get_cable_length_80003es2lan - Set approximate cable length
- *  @hw: pointer to the HW structure
- *
- *  Find the approximate cable length as measured by the GG82563 PHY.
- *  This is a function pointer entry point called by the phy module.
- **/
-static s32 e1000e_get_cable_length_80003es2lan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 phy_data, index;
-
-	if (!(hw->phy.ops.read_reg))
-		goto out;
-
-	ret_val = e1e_rphy(hw, GG82563_PHY_DSP_DISTANCE, &phy_data);
-	if (ret_val)
-		goto out;
-
-	index = phy_data & GG82563_DSPD_CABLE_LENGTH;
-
-	if (index >= GG82563_CABLE_LENGTH_TABLE_SIZE - 5) {
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-
-	phy->min_cable_length = e1000_gg82563_cable_length_table[index];
-	phy->max_cable_length = e1000_gg82563_cable_length_table[index + 5];
-
-	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
-
-out:
-	return ret_val;
-}
-#endif
-
-/**
- *  e1000e_get_link_up_info_80003es2lan - Report speed and duplex
- *  @hw: pointer to the HW structure
- *  @speed: pointer to speed buffer
- *  @duplex: pointer to duplex buffer
- *
- *  Retrieve the current speed and duplex configuration.
- **/
-static s32 e1000e_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed,
-                                              u16 *duplex)
-{
-	s32 ret_val;
-
-	if (hw->phy.media_type == e1000_media_type_copper) {
-		ret_val = e1000e_get_speed_and_duplex_copper(hw,
-		                                                    speed,
-		                                                    duplex);
-		hw->phy.ops.cfg_on_link_up(hw);
-	} else {
-		ret_val = e1000e_get_speed_and_duplex_fiber_serdes(hw,
-		                                                  speed,
-		                                                  duplex);
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000e_reset_hw_80003es2lan - Reset the ESB2 controller
- *  @hw: pointer to the HW structure
- *
- *  Perform a global reset to the ESB2 controller.
- **/
-static s32 e1000e_reset_hw_80003es2lan(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val;
-
-	/*
-	 * Prevent the PCI-E bus from sticking if there is no TLP connection
-	 * on the last TLP read/write transaction when MAC is reset.
-	 */
-	ret_val = e1000e_disable_pcie_master(hw);
-	if (ret_val)
-		e_dbg("PCI-E Master disable polling has failed.\n");
-
-	e_dbg("Masking off all interrupts\n");
-	ew32(IMC, 0xffffffff);
-
-	ew32(RCTL, 0);
-	ew32(TCTL, E1000_TCTL_PSP);
-	e1e_flush();
-
-	msleep(10);
-
-	ctrl = er32(CTRL);
-
-	ret_val = e1000e_acquire_phy_80003es2lan(hw);
-	e_dbg("Issuing a global reset to MAC\n");
-	ew32(CTRL, ctrl | E1000_CTRL_RST);
-	e1000e_release_phy_80003es2lan(hw);
-
-	ret_val = e1000e_get_auto_rd_done(hw);
-	if (ret_val)
-		/* We don't want to continue accessing MAC registers. */
-		goto out;
-
-	/* Clear any pending interrupt events. */
-	ew32(IMC, 0xffffffff);
-	er32(ICR);
-
-	ret_val = e1000e_check_alt_mac_addr_generic(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_init_hw_80003es2lan - Initialize the ESB2 controller
- *  @hw: pointer to the HW structure
- *
- *  Initialize the hw bits, LED, VFTA, MTA, link and hw counters.
- **/
-static s32 e1000e_init_hw_80003es2lan(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 reg_data;
-	s32 ret_val;
-	u16 i;
-
-	e1000e_initialize_hw_bits_80003es2lan(hw);
-
-	/* Initialize identification LED */
-	ret_val = mac->ops.id_led_init(hw);
-	if (ret_val) {
-		e_dbg("Error initializing identification LED\n");
-		/* This is not fatal and we should not stop init due to this */
-	}
-
-	/* Disabling VLAN filtering */
-	e_dbg("Initializing the IEEE VLAN\n");
-	e1000e_clear_vfta(hw);
-
-	/* Setup the receive address. */
-	e1000e_init_rx_addrs(hw, mac->rar_entry_count);
-
-	/* Zero out the Multicast HASH table */
-	e_dbg("Zeroing the MTA\n");
-	for (i = 0; i < mac->mta_reg_count; i++)
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
-
-	/* Setup link and flow control */
-	ret_val = mac->ops.setup_link(hw);
-
-	/* Set the transmit descriptor write-back policy */
-	reg_data = er32(TXDCTL(0));
-	reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
-	           E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
-	ew32(TXDCTL(0), reg_data);
-
-	/* ...for both queues. */
-	reg_data = er32(TXDCTL(1));
-	reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
-	           E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
-	ew32(TXDCTL(1), reg_data);
-
-	/* Enable retransmit on late collisions */
-	reg_data = er32(TCTL);
-	reg_data |= E1000_TCTL_RTLC;
-	ew32(TCTL, reg_data);
-
-	/* Configure Gigabit Carry Extend Padding */
-	reg_data = er32(TCTL_EXT);
-	reg_data &= ~E1000_TCTL_EXT_GCEX_MASK;
-	reg_data |= DEFAULT_TCTL_EXT_GCEX_80003ES2LAN;
-	ew32(TCTL_EXT, reg_data);
-
-	/* Configure Transmit Inter-Packet Gap */
-	reg_data = er32(TIPG);
-	reg_data &= ~E1000_TIPG_IPGT_MASK;
-	reg_data |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
-	ew32(TIPG, reg_data);
-
-	reg_data = E1000_READ_REG_ARRAY(hw, E1000_FFLT, 0x0001);
-	reg_data &= ~0x00100000;
-	E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data);
-
-	/* default to true to enable the MDIC W/A */
-	hw->dev_spec._80003es2lan.mdic_wa_enable = true;
-
-	ret_val = e1000e_read_kmrn_reg_80003es2lan(hw,
-	                              E1000_KMRNCTRLSTA_OFFSET >>
-	                              E1000_KMRNCTRLSTA_OFFSET_SHIFT,
-	                              &i);
-	if (!ret_val) {
-		if ((i & E1000_KMRNCTRLSTA_OPMODE_MASK) ==
-		     E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO)
-			hw->dev_spec._80003es2lan.mdic_wa_enable = false;
-	}
-
-	/*
-	 * Clear all of the statistics registers (clear on read).  It is
-	 * important that we do this after we have tried to establish link
-	 * because the symbol error count will increment wildly if there
-	 * is no link.
-	 */
-	e1000e_clear_hw_cntrs_80003es2lan(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_initialize_hw_bits_80003es2lan - Init hw bits of ESB2
- *  @hw: pointer to the HW structure
- *
- *  Initializes required hardware-dependent bits needed for normal operation.
- **/
-static void e1000e_initialize_hw_bits_80003es2lan(struct e1000_hw *hw)
-{
-	u32 reg;
-
-	/* Transmit Descriptor Control 0 */
-	reg = er32(TXDCTL(0));
-	reg |= (1 << 22);
-	ew32(TXDCTL(0), reg);
-
-	/* Transmit Descriptor Control 1 */
-	reg = er32(TXDCTL(1));
-	reg |= (1 << 22);
-	ew32(TXDCTL(1), reg);
-
-	/* Transmit Arbitration Control 0 */
-	reg = er32(TARC(0));
-	reg &= ~(0xF << 27); /* 30:27 */
-	if (hw->phy.media_type != e1000_media_type_copper)
-		reg &= ~(1 << 20);
-	ew32(TARC(0), reg);
-
-	/* Transmit Arbitration Control 1 */
-	reg = er32(TARC(1));
-	if (er32(TCTL) & E1000_TCTL_MULR)
-		reg &= ~(1 << 28);
-	else
-		reg |= (1 << 28);
-	ew32(TARC(1), reg);
-
-	return;
-}
-
-/**
- *  e1000e_copper_link_setup_gg82563_80003es2lan - Configure GG82563 Link
- *  @hw: pointer to the HW structure
- *
- *  Setup some GG82563 PHY registers for obtaining link
- **/
-static s32 e1000e_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u32 ctrl_ext;
-	u16 data;
-
-	if (!phy->reset_disable) {
-		ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
-		                             &data);
-		if (ret_val)
-			goto out;
-
-		data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
-		/* Use 25MHz for both link down and 1000Base-T for Tx clock. */
-		data |= GG82563_MSCR_TX_CLK_1000MBPS_25;
-
-		ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
-		                              data);
-		if (ret_val)
-			goto out;
-
-		/*
-		 * Options:
-		 *   MDI/MDI-X = 0 (default)
-		 *   0 - Auto for all speeds
-		 *   1 - MDI mode
-		 *   2 - MDI-X mode
-		 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
-		 */
-		ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL, &data);
-		if (ret_val)
-			goto out;
-
-		data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
-
-		switch (phy->mdix) {
-		case 1:
-			data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
-			break;
-		case 2:
-			data |= GG82563_PSCR_CROSSOVER_MODE_MDIX;
-			break;
-		case 0:
-		default:
-			data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
-			break;
-		}
-
-		/*
-		 * Options:
-		 *   disable_polarity_correction = 0 (default)
-		 *       Automatic Correction for Reversed Cable Polarity
-		 *   0 - Disabled
-		 *   1 - Enabled
-		 */
-		data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
-		if (phy->disable_polarity_correction)
-			data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
-
-		ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, data);
-		if (ret_val)
-			goto out;
-
-		/* SW Reset the PHY so all changes take effect */
-		ret_val = e1000e_commit_phy(hw);
-		if (ret_val) {
-			e_dbg("Error Resetting the PHY\n");
-			goto out;
-		}
-
-	}
-
-	/* Bypass Rx and Tx FIFO's */
-	ret_val = e1000e_write_kmrn_reg_80003es2lan(hw,
-					E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL,
-					E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS |
-					E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000e_read_kmrn_reg_80003es2lan(hw,
-	                              E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
-	                              &data);
-	if (ret_val)
-		goto out;
-	data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE;
-	ret_val = e1000e_write_kmrn_reg_80003es2lan(hw,
-	                               E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
-	                               data);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL_2, &data);
-	if (ret_val)
-		goto out;
-
-	data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
-	ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL_2, data);
-	if (ret_val)
-		goto out;
-
-	ctrl_ext = er32(CTRL_EXT);
-	ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
-	ew32(CTRL_EXT, ctrl_ext);
-
-	ret_val = e1e_rphy(hw, GG82563_PHY_PWR_MGMT_CTRL, &data);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Do not init these registers when the HW is in IAMT mode, since the
-	 * firmware will have already initialized them.  We only initialize
-	 * them if the HW is not in IAMT mode.
-	 */
-	if (!(hw->mac.ops.check_mng_mode(hw))) {
-		/* Enable Electrical Idle on the PHY */
-		data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
-		ret_val = e1e_wphy(hw, GG82563_PHY_PWR_MGMT_CTRL,
-		                                data);
-		if (ret_val)
-			goto out;
-
-		ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
-		                               &data);
-		if (ret_val)
-			goto out;
-
-		data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
-		ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
-		                                data);
-		if (ret_val)
-			goto out;
-	}
-
-	/*
-	 * Workaround: Disable padding in Kumeran interface in the MAC
-	 * and in the PHY to avoid CRC errors.
-	 */
-	ret_val = e1e_rphy(hw, GG82563_PHY_INBAND_CTRL, &data);
-	if (ret_val)
-		goto out;
-
-	data |= GG82563_ICR_DIS_PADDING;
-	ret_val = e1e_wphy(hw, GG82563_PHY_INBAND_CTRL, data);
-	if (ret_val)
-		goto out;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_setup_copper_link_80003es2lan - Setup Copper Link for ESB2
- *  @hw: pointer to the HW structure
- *
- *  Essentially a wrapper for setting up all things "copper" related.
- *  This is a function pointer entry point called by the mac module.
- **/
-static s32 e1000e_setup_copper_link_80003es2lan(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val;
-	u16 reg_data;
-
-	ctrl = er32(CTRL);
-	ctrl |= E1000_CTRL_SLU;
-	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-	ew32(CTRL, ctrl);
-
-	/*
-	 * Set the mac to wait the maximum time between each
-	 * iteration and increase the max iterations when
-	 * polling the phy; this fixes erroneous timeouts at 10Mbps.
-	 */
-	ret_val = e1000e_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 4),
-	                                           0xFFFF);
-	if (ret_val)
-		goto out;
-	ret_val = e1000e_read_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
-	                                          &reg_data);
-	if (ret_val)
-		goto out;
-	reg_data |= 0x3F;
-	ret_val = e1000e_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
-	                                           reg_data);
-	if (ret_val)
-		goto out;
-	ret_val = e1000e_read_kmrn_reg_80003es2lan(hw,
-	                              E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
-	                              &reg_data);
-	if (ret_val)
-		goto out;
-	reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING;
-	ret_val = e1000e_write_kmrn_reg_80003es2lan(hw,
-	                               E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
-	                               reg_data);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000e_copper_link_setup_gg82563_80003es2lan(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000e_setup_copper_link(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_cfg_on_link_up_80003es2lan - es2 link configuration after link-up
- *  @hw: pointer to the HW structure
- *  @duplex: current duplex setting
- *
- *  Configure the KMRN interface by applying last minute quirks for
- *  10/100 operation.
- **/
-static s32 e1000e_cfg_on_link_up_80003es2lan(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 speed;
-	u16 duplex;
-
-	if (hw->phy.media_type == e1000_media_type_copper) {
-		ret_val = e1000e_get_speed_and_duplex_copper(hw,
-		                                                    &speed,
-		                                                    &duplex);
-		if (ret_val)
-			goto out;
-
-		if (speed == SPEED_1000)
-			ret_val = e1000e_cfg_kmrn_1000_80003es2lan(hw);
-		else
-			ret_val = e1000e_cfg_kmrn_10_100_80003es2lan(hw, duplex);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation
- *  @hw: pointer to the HW structure
- *  @duplex: current duplex setting
- *
- *  Configure the KMRN interface by applying last minute quirks for
- *  10/100 operation.
- **/
-static s32 e1000e_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u32 tipg;
-	u32 i = 0;
-	u16 reg_data, reg_data2;
-
-	reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT;
-	ret_val = e1000e_write_kmrn_reg_80003es2lan(hw,
-	                               E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
-	                               reg_data);
-	if (ret_val)
-		goto out;
-
-	/* Configure Transmit Inter-Packet Gap */
-	tipg = er32(TIPG);
-	tipg &= ~E1000_TIPG_IPGT_MASK;
-	tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN;
-	ew32(TIPG, tipg);
-
-
-	do {
-		ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
-		                               &reg_data);
-		if (ret_val)
-			goto out;
-
-		ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
-		                               &reg_data2);
-		if (ret_val)
-			goto out;
-		i++;
-	} while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));
-
-	if (duplex == HALF_DUPLEX)
-		reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
-	else
-		reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
-
-	ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_cfg_kmrn_1000_80003es2lan - Apply "quirks" for gigabit operation
- *  @hw: pointer to the HW structure
- *
- *  Configure the KMRN interface by applying last minute quirks for
- *  gigabit operation.
- **/
-static s32 e1000e_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 reg_data, reg_data2;
-	u32 tipg;
-	u32 i = 0;
-
-	reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT;
-	ret_val = e1000e_write_kmrn_reg_80003es2lan(hw,
-	                               E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
-	                               reg_data);
-	if (ret_val)
-		goto out;
-
-	/* Configure Transmit Inter-Packet Gap */
-	tipg = er32(TIPG);
-	tipg &= ~E1000_TIPG_IPGT_MASK;
-	tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
-	ew32(TIPG, tipg);
-
-
-	do {
-		ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
-		                               &reg_data);
-		if (ret_val)
-			goto out;
-
-		ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
-		                               &reg_data2);
-		if (ret_val)
-			goto out;
-		i++;
-	} while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));
-
-	reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
-	ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_read_kmrn_reg_80003es2lan - Read kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquire semaphore, then read the PHY register at offset
- *  using the kumeran interface.  The information retrieved is stored in data.
- *  Release the semaphore before exiting.
- **/
-static s32 e1000e_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
-                                           u16 *data)
-{
-	u32 kmrnctrlsta;
-	s32 ret_val = E1000_SUCCESS;
-
-	ret_val = e1000e_acquire_mac_csr_80003es2lan(hw);
-	if (ret_val)
-		goto out;
-
-	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
-	               E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
-	ew32(KMRNCTRLSTA, kmrnctrlsta);
-
-	udelay(2);
-
-	kmrnctrlsta = er32(KMRNCTRLSTA);
-	*data = (u16)kmrnctrlsta;
-
-	e1000e_release_mac_csr_80003es2lan(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_write_kmrn_reg_80003es2lan - Write kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquire semaphore, then write the data to PHY register
- *  at the offset using the kumeran interface.  Release semaphore
- *  before exiting.
- **/
-static s32 e1000e_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
-                                            u16 data)
-{
-	u32 kmrnctrlsta;
-	s32 ret_val = E1000_SUCCESS;
-
-	ret_val = e1000e_acquire_mac_csr_80003es2lan(hw);
-	if (ret_val)
-		goto out;
-
-	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
-	               E1000_KMRNCTRLSTA_OFFSET) | data;
-	ew32(KMRNCTRLSTA, kmrnctrlsta);
-
-	udelay(2);
-
-	e1000e_release_mac_csr_80003es2lan(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_read_mac_addr_80003es2lan - Read device MAC address
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000e_read_mac_addr_80003es2lan(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	/*
-	 * If there's an alternate MAC address place it in RAR0
-	 * so that it will override the Si installed default perm
-	 * address.
-	 */
-	ret_val = e1000e_check_alt_mac_addr_generic(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000e_read_mac_addr_generic(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- * e1000e_power_down_phy_copper_80003es2lan - Remove link during PHY power down
- * @hw: pointer to the HW structure
- *
- * In the case of a PHY power down to save power, or to turn off link during a
- * driver unload, or wake on lan is not enabled, remove the link.
- **/
-static void e1000e_power_down_phy_copper_80003es2lan(struct e1000_hw *hw)
-{
-	/* If the management interface is not enabled, then power down */
-	if (!(hw->mac.ops.check_mng_mode(hw) ||
-	      e1000e_check_reset_block(hw)))
-             e1000e_power_down_phy_copper(hw);
-
-	return;
-}
-
-/**
- *  e1000e_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters
- *  @hw: pointer to the HW structure
- *
- *  Clears the hardware counters by reading the counter registers.
- **/
-static void e1000e_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw __unused)
-{
-#if 0
-	e1000e_clear_hw_cntrs_base(hw);
-
-	er32(PRC64);
-	er32(PRC127);
-	er32(PRC255);
-	er32(PRC511);
-	er32(PRC1023);
-	er32(PRC1522);
-	er32(PTC64);
-	er32(PTC127);
-	er32(PTC255);
-	er32(PTC511);
-	er32(PTC1023);
-	er32(PTC1522);
-
-	er32(ALGNERRC);
-	er32(RXERRC);
-	er32(TNCRS);
-	er32(CEXTERR);
-	er32(TSCTC);
-	er32(TSCTFC);
-
-	er32(MGTPRC);
-	er32(MGTPDC);
-	er32(MGTPTC);
-
-	er32(IAC);
-	er32(ICRXOC);
-
-	er32(ICRXPTC);
-	er32(ICRXATC);
-	er32(ICTXPTC);
-	er32(ICTXATC);
-	er32(ICTXQEC);
-	er32(ICTXQMTC);
-	er32(ICRXDMTC);
-#endif
-}
-
-static struct pci_device_id e1000e_80003es2lan_nics[] = {
-     PCI_ROM(0x8086, 0x1096, "E1000_DEV_ID_80003ES2LAN_COPPER_DPT", "E1000_DEV_ID_80003ES2LAN_COPPER_DPT", board_80003es2lan),
-     PCI_ROM(0x8086, 0x10BA, "E1000_DEV_ID_80003ES2LAN_COPPER_SPT", "E1000_DEV_ID_80003ES2LAN_COPPER_SPT", board_80003es2lan),
-     PCI_ROM(0x8086, 0x1098, "E1000_DEV_ID_80003ES2LAN_SERDES_DPT", "E1000_DEV_ID_80003ES2LAN_SERDES_DPT", board_80003es2lan),
-     PCI_ROM(0x8086, 0x10BB, "E1000_DEV_ID_80003ES2LAN_SERDES_SPT", "E1000_DEV_ID_80003ES2LAN_SERDES_SPT", board_80003es2lan),
-};
-
-struct pci_driver e1000e_80003es2lan_driver __pci_driver = {
-	.ids = e1000e_80003es2lan_nics,
-	.id_count = (sizeof (e1000e_80003es2lan_nics) / sizeof (e1000e_80003es2lan_nics[0])),
-	.probe = e1000e_probe,
-	.remove = e1000e_remove,
-};
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_80003es2lan.h b/roms/ipxe/src/drivers/net/e1000e/e1000e_80003es2lan.h
deleted file mode 100644
index 93430a16ad9932813b520f74fb7128b796781a03..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_80003es2lan.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000E_80003ES2LAN_H_
-#define _E1000E_80003ES2LAN_H_
-
-#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL       0x00
-#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL        0x02
-#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL         0x10
-#define E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE  0x1F
-
-#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS    0x0008
-#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS    0x0800
-#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING   0x0010
-
-#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004
-#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT   0x0000
-#define E1000_KMRNCTRLSTA_OPMODE_E_IDLE          0x2000
-
-#define E1000_KMRNCTRLSTA_OPMODE_MASK            0x000C
-#define E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO     0x0004
-
-#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
-#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN        0x00010000
-
-#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN       0x8
-#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN     0x9
-
-/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
-#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE  0x0002 /* 1=Reversal Disabled */
-#define GG82563_PSCR_CROSSOVER_MODE_MASK        0x0060
-#define GG82563_PSCR_CROSSOVER_MODE_MDI         0x0000 /* 00=Manual MDI */
-#define GG82563_PSCR_CROSSOVER_MODE_MDIX        0x0020 /* 01=Manual MDIX */
-#define GG82563_PSCR_CROSSOVER_MODE_AUTO        0x0060 /* 11=Auto crossover */
-
-/* PHY Specific Control Register 2 (Page 0, Register 26) */
-#define GG82563_PSCR2_REVERSE_AUTO_NEG          0x2000
-                                               /* 1=Reverse Auto-Negotiation */
-
-/* MAC Specific Control Register (Page 2, Register 21) */
-/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
-#define GG82563_MSCR_TX_CLK_MASK                0x0007
-#define GG82563_MSCR_TX_CLK_10MBPS_2_5          0x0004
-#define GG82563_MSCR_TX_CLK_100MBPS_25          0x0005
-#define GG82563_MSCR_TX_CLK_1000MBPS_2_5        0x0006
-#define GG82563_MSCR_TX_CLK_1000MBPS_25         0x0007
-
-#define GG82563_MSCR_ASSERT_CRS_ON_TX           0x0010 /* 1=Assert */
-
-/* DSP Distance Register (Page 5, Register 26) */
-/*
- * 0 = <50M
- * 1 = 50-80M
- * 2 = 80-100M
- * 3 = 110-140M
- * 4 = >140M
- */
-#define GG82563_DSPD_CABLE_LENGTH               0x0007
-
-/* Kumeran Mode Control Register (Page 193, Register 16) */
-#define GG82563_KMCR_PASS_FALSE_CARRIER         0x0800
-
-/* Max number of times Kumeran read/write should be validated */
-#define GG82563_MAX_KMRN_RETRY                  0x5
-
-/* Power Management Control Register (Page 193, Register 20) */
-#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE     0x0001
-                                          /* 1=Enable SERDES Electrical Idle */
-
-/* In-Band Control Register (Page 194, Register 18) */
-#define GG82563_ICR_DIS_PADDING                 0x0010 /* Disable Padding */
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_82571.c b/roms/ipxe/src/drivers/net/e1000e/e1000e_82571.c
deleted file mode 100644
index a061d6d4959394f208bb73c566d38bf16c2f96be..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_82571.c
+++ /dev/null
@@ -1,1818 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/*
- * 82571EB Gigabit Ethernet Controller
- * 82571EB Gigabit Ethernet Controller (Copper)
- * 82571EB Gigabit Ethernet Controller (Fiber)
- * 82571EB Dual Port Gigabit Mezzanine Adapter
- * 82571EB Quad Port Gigabit Mezzanine Adapter
- * 82571PT Gigabit PT Quad Port Server ExpressModule
- * 82572EI Gigabit Ethernet Controller (Copper)
- * 82572EI Gigabit Ethernet Controller (Fiber)
- * 82572EI Gigabit Ethernet Controller
- * 82573V Gigabit Ethernet Controller (Copper)
- * 82573E Gigabit Ethernet Controller (Copper)
- * 82573L Gigabit Ethernet Controller
- * 82574L Gigabit Network Connection
- * 82574L Gigabit Network Connection
- * 82583V Gigabit Network Connection
- */
-
-#include "e1000e.h"
-
-static s32  e1000e_init_phy_params_82571(struct e1000_hw *hw);
-static s32  e1000e_init_nvm_params_82571(struct e1000_hw *hw);
-static s32  e1000e_init_mac_params_82571(struct e1000_hw *hw);
-static s32  e1000e_acquire_nvm_82571(struct e1000_hw *hw);
-static void e1000e_release_nvm_82571(struct e1000_hw *hw);
-static s32  e1000e_write_nvm_82571(struct e1000_hw *hw, u16 offset,
-                                  u16 words, u16 *data);
-static s32  e1000e_update_nvm_checksum_82571(struct e1000_hw *hw);
-static s32  e1000e_validate_nvm_checksum_82571(struct e1000_hw *hw);
-static s32  e1000e_get_cfg_done_82571(struct e1000_hw *hw);
-static s32  e1000e_set_d0_lplu_state_82571(struct e1000_hw *hw,
-                                          bool active);
-static s32  e1000e_reset_hw_82571(struct e1000_hw *hw);
-static s32  e1000e_init_hw_82571(struct e1000_hw *hw);
-static void e1000e_clear_vfta_82571(struct e1000_hw *hw);
-#if 0
-static bool e1000e_check_mng_mode_82574(struct e1000_hw *hw);
-#endif
-static s32  e1000e_led_on_82574(struct e1000_hw *hw);
-static s32  e1000e_setup_link_82571(struct e1000_hw *hw);
-static s32  e1000e_setup_copper_link_82571(struct e1000_hw *hw);
-static s32  e1000e_check_for_serdes_link_82571(struct e1000_hw *hw);
-static s32  e1000e_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
-static s32  e1000e_valid_led_default_82571(struct e1000_hw *hw, u16 *data);
-static void e1000e_clear_hw_cntrs_82571(struct e1000_hw *hw);
-static s32  e1000e_get_hw_semaphore_82571(struct e1000_hw *hw);
-static s32  e1000e_fix_nvm_checksum_82571(struct e1000_hw *hw);
-static s32  e1000e_get_phy_id_82571(struct e1000_hw *hw);
-static void e1000e_put_hw_semaphore_82571(struct e1000_hw *hw);
-static void e1000e_initialize_hw_bits_82571(struct e1000_hw *hw);
-static s32  e1000e_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
-                                       u16 words, u16 *data);
-static s32  e1000e_read_mac_addr_82571(struct e1000_hw *hw);
-static void e1000e_power_down_phy_copper_82571(struct e1000_hw *hw);
-
-/**
- *  e1000e_init_phy_params_82571 - Init PHY func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000e_init_phy_params_82571(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->phy.media_type != e1000_media_type_copper) {
-		phy->type = e1000_phy_none;
-		goto out;
-	}
-
-	phy->addr                        = 1;
-	phy->autoneg_mask                = AUTONEG_ADVERTISE_SPEED_DEFAULT;
-	phy->reset_delay_us              = 100;
-
-	phy->ops.acquire                 = e1000e_get_hw_semaphore_82571;
-	phy->ops.check_polarity          = e1000e_check_polarity_igp;
-	phy->ops.check_reset_block       = e1000e_check_reset_block_generic;
-	phy->ops.release                 = e1000e_put_hw_semaphore_82571;
-	phy->ops.reset                   = e1000e_phy_hw_reset_generic;
-	phy->ops.set_d0_lplu_state       = e1000e_set_d0_lplu_state_82571;
-	phy->ops.set_d3_lplu_state       = e1000e_set_d3_lplu_state;
-	phy->ops.power_up                = e1000e_power_up_phy_copper;
-	phy->ops.power_down              = e1000e_power_down_phy_copper_82571;
-
-	switch (hw->mac.type) {
-	case e1000_82571:
-	case e1000_82572:
-		phy->type                   = e1000_phy_igp_2;
-		phy->ops.get_cfg_done       = e1000e_get_cfg_done_82571;
-		phy->ops.get_info           = e1000e_get_phy_info_igp;
-#if 0
-		phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_igp;
-#endif
-#if 0
-		phy->ops.get_cable_length   = e1000e_get_cable_length_igp_2;
-#endif
-		phy->ops.read_reg           = e1000e_read_phy_reg_igp;
-		phy->ops.write_reg          = e1000e_write_phy_reg_igp;
-
-		/* This uses above function pointers */
-		ret_val = e1000e_get_phy_id_82571(hw);
-
-		/* Verify PHY ID */
-		if (phy->id != IGP01E1000_I_PHY_ID) {
-			ret_val = -E1000_ERR_PHY;
-			goto out;
-		}
-		break;
-	case e1000_82573:
-		phy->type                   = e1000_phy_m88;
-		phy->ops.get_cfg_done       = e1000e_get_cfg_done;
-		phy->ops.get_info           = e1000e_get_phy_info_m88;
-		phy->ops.commit             = e1000e_phy_sw_reset;
-#if 0
-		phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_m88;
-#endif
-#if 0
-		phy->ops.get_cable_length   = e1000e_get_cable_length_m88;
-#endif
-		phy->ops.read_reg           = e1000e_read_phy_reg_m88;
-		phy->ops.write_reg          = e1000e_write_phy_reg_m88;
-
-		/* This uses above function pointers */
-		ret_val = e1000e_get_phy_id_82571(hw);
-
-		/* Verify PHY ID */
-		if (phy->id != M88E1111_I_PHY_ID) {
-			ret_val = -E1000_ERR_PHY;
-			e_dbg("PHY ID unknown: type = 0x%08x\n", phy->id);
-			goto out;
-		}
-		break;
-	case e1000_82583:
-	case e1000_82574:
-		phy->type                   = e1000_phy_bm;
-		phy->ops.get_cfg_done       = e1000e_get_cfg_done;
-		phy->ops.get_info           = e1000e_get_phy_info_m88;
-		phy->ops.commit             = e1000e_phy_sw_reset;
-#if 0
-		phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_m88;
-#endif
-#if 0
-		phy->ops.get_cable_length   = e1000e_get_cable_length_m88;
-#endif
-		phy->ops.read_reg           = e1000e_read_phy_reg_bm2;
-		phy->ops.write_reg          = e1000e_write_phy_reg_bm2;
-
-		/* This uses above function pointers */
-		ret_val = e1000e_get_phy_id_82571(hw);
-		/* Verify PHY ID */
-		if (phy->id != BME1000_E_PHY_ID_R2) {
-			ret_val = -E1000_ERR_PHY;
-			e_dbg("PHY ID unknown: type = 0x%08x\n", phy->id);
-			goto out;
-		}
-		break;
-	default:
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-		break;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_init_nvm_params_82571 - Init NVM func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000e_init_nvm_params_82571(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = er32(EECD);
-	u16 size;
-
-	nvm->opcode_bits = 8;
-	nvm->delay_usec = 1;
-	switch (nvm->override) {
-	case e1000_nvm_override_spi_large:
-		nvm->page_size = 32;
-		nvm->address_bits = 16;
-		break;
-	case e1000_nvm_override_spi_small:
-		nvm->page_size = 8;
-		nvm->address_bits = 8;
-		break;
-	default:
-		nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
-		nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
-		break;
-	}
-
-	switch (hw->mac.type) {
-	case e1000_82573:
-	case e1000_82574:
-	case e1000_82583:
-		if (((eecd >> 15) & 0x3) == 0x3) {
-			nvm->type = e1000_nvm_flash_hw;
-			nvm->word_size = 2048;
-			/*
-			 * Autonomous Flash update bit must be cleared due
-			 * to Flash update issue.
-			 */
-			eecd &= ~E1000_EECD_AUPDEN;
-			ew32(EECD, eecd);
-			break;
-		}
-		/* Fall Through */
-	default:
-		nvm->type = e1000_nvm_eeprom_spi;
-		size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
-		                  E1000_EECD_SIZE_EX_SHIFT);
-		/*
-		 * Added to a constant, "size" becomes the left-shift value
-		 * for setting word_size.
-		 */
-		size += NVM_WORD_SIZE_BASE_SHIFT;
-
-		/* EEPROM access above 16k is unsupported */
-		if (size > 14)
-			size = 14;
-		nvm->word_size	= 1 << size;
-		break;
-	}
-
-	/* Function Pointers */
-	nvm->ops.acquire       = e1000e_acquire_nvm_82571;
-	nvm->ops.read          = e1000e_read_nvm_eerd;
-	nvm->ops.release       = e1000e_release_nvm_82571;
-	nvm->ops.update        = e1000e_update_nvm_checksum_82571;
-	nvm->ops.validate      = e1000e_validate_nvm_checksum_82571;
-	nvm->ops.valid_led_default = e1000e_valid_led_default_82571;
-	nvm->ops.write         = e1000e_write_nvm_82571;
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_init_mac_params_82571 - Init MAC func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000e_init_mac_params_82571(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val = E1000_SUCCESS;
-	u32 swsm = 0;
-	u32 swsm2 = 0;
-	bool force_clear_smbi = false;
-
-	/* Set media type */
-	switch (hw->device_id) {
-	case E1000_DEV_ID_82571EB_FIBER:
-	case E1000_DEV_ID_82572EI_FIBER:
-	case E1000_DEV_ID_82571EB_QUAD_FIBER:
-		hw->phy.media_type = e1000_media_type_fiber;
-		break;
-	case E1000_DEV_ID_82571EB_SERDES:
-	case E1000_DEV_ID_82571EB_SERDES_DUAL:
-	case E1000_DEV_ID_82571EB_SERDES_QUAD:
-	case E1000_DEV_ID_82572EI_SERDES:
-		hw->phy.media_type = e1000_media_type_internal_serdes;
-		break;
-	default:
-		hw->phy.media_type = e1000_media_type_copper;
-		break;
-	}
-
-	/* Set mta register count */
-	mac->mta_reg_count = 128;
-	/* Set rar entry count */
-	mac->rar_entry_count = E1000_RAR_ENTRIES;
-	/* Set if part includes ASF firmware */
-	mac->asf_firmware_present = true;
-	/* Set if manageability features are enabled. */
-	mac->arc_subsystem_valid =
-	        (er32(FWSM) & E1000_FWSM_MODE_MASK)
-	                ? true : false;
-
-	/* Function pointers */
-
-	/* bus type/speed/width */
-	mac->ops.get_bus_info = e1000e_get_bus_info_pcie;
-	/* function id */
-	switch (hw->mac.type) {
-	case e1000_82573:
-	case e1000_82574:
-	case e1000_82583:
-		mac->ops.set_lan_id = e1000e_set_lan_id_single_port;
-		break;
-	default:
-		break;
-	}
-	/* reset */
-	mac->ops.reset_hw = e1000e_reset_hw_82571;
-	/* hw initialization */
-	mac->ops.init_hw = e1000e_init_hw_82571;
-	/* link setup */
-	mac->ops.setup_link = e1000e_setup_link_82571;
-	/* physical interface link setup */
-	mac->ops.setup_physical_interface =
-	        (hw->phy.media_type == e1000_media_type_copper)
-	                ? e1000e_setup_copper_link_82571
-	                : e1000e_setup_fiber_serdes_link_82571;
-	/* check for link */
-	switch (hw->phy.media_type) {
-	case e1000_media_type_copper:
-		mac->ops.check_for_link = e1000e_check_for_copper_link;
-		break;
-	case e1000_media_type_fiber:
-		mac->ops.check_for_link = e1000e_check_for_fiber_link;
-		break;
-	case e1000_media_type_internal_serdes:
-		mac->ops.check_for_link = e1000e_check_for_serdes_link_82571;
-		break;
-	default:
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-		break;
-	}
-	/* check management mode */
-#if 0
-	switch (hw->mac.type) {
-	case e1000_82574:
-	case e1000_82583:
-		mac->ops.check_mng_mode = e1000e_check_mng_mode_82574;
-		break;
-	default:
-		mac->ops.check_mng_mode = e1000e_check_mng_mode_generic;
-		break;
-	}
-#endif
-	/* multicast address update */
-	mac->ops.update_mc_addr_list = e1000e_update_mc_addr_list_generic;
-	/* writing VFTA */
-	mac->ops.write_vfta = e1000e_write_vfta_generic;
-	/* clearing VFTA */
-	mac->ops.clear_vfta = e1000e_clear_vfta_82571;
-	/* setting MTA */
-	mac->ops.mta_set = e1000e_mta_set_generic;
-	/* read mac address */
-	mac->ops.read_mac_addr = e1000e_read_mac_addr_82571;
-	/* ID LED init */
-	mac->ops.id_led_init = e1000e_id_led_init;
-	/* blink LED */
-	mac->ops.blink_led = e1000e_blink_led;
-	/* setup LED */
-	mac->ops.setup_led = e1000e_setup_led_generic;
-	/* cleanup LED */
-	mac->ops.cleanup_led = e1000e_cleanup_led_generic;
-	/* turn on/off LED */
-	switch (hw->mac.type) {
-	case e1000_82574:
-	case e1000_82583:
-		mac->ops.led_on = e1000e_led_on_82574;
-		break;
-	default:
-		mac->ops.led_on = e1000e_led_on_generic;
-		break;
-	}
-	mac->ops.led_off = e1000e_led_off_generic;
-	/* clear hardware counters */
-	mac->ops.clear_hw_cntrs = e1000e_clear_hw_cntrs_82571;
-	/* link info */
-	mac->ops.get_link_up_info =
-	        (hw->phy.media_type == e1000_media_type_copper)
-	                ? e1000e_get_speed_and_duplex_copper
-	                : e1000e_get_speed_and_duplex_fiber_serdes;
-
-	/*
-	 * Ensure that the inter-port SWSM.SMBI lock bit is clear before
-	 * first NVM or PHY acess. This should be done for single-port
-	 * devices, and for one port only on dual-port devices so that
-	 * for those devices we can still use the SMBI lock to synchronize
-	 * inter-port accesses to the PHY & NVM.
-	 */
-	switch (hw->mac.type) {
-	case e1000_82571:
-	case e1000_82572:
-		swsm2 = er32(SWSM2);
-
-		if (!(swsm2 & E1000_SWSM2_LOCK)) {
-			/* Only do this for the first interface on this card */
-			ew32(SWSM2,
-			    swsm2 | E1000_SWSM2_LOCK);
-			force_clear_smbi = true;
-		} else
-			force_clear_smbi = false;
-		break;
-	default:
-		force_clear_smbi = true;
-		break;
-	}
-
-	if (force_clear_smbi) {
-		/* Make sure SWSM.SMBI is clear */
-		swsm = er32(SWSM);
-		if (swsm & E1000_SWSM_SMBI) {
-			/* This bit should not be set on a first interface, and
-			 * indicates that the bootagent or EFI code has
-			 * improperly left this bit enabled
-			 */
-			e_dbg("Please update your 82571 Bootagent\n");
-		}
-		ew32(SWSM, swsm & ~E1000_SWSM_SMBI);
-	}
-
-	/*
-	 * Initialze device specific counter of SMBI acquisition
-	 * timeouts.
-	 */
-	 hw->dev_spec._82571.smb_counter = 0;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_init_function_pointers_82571 - Init func ptrs.
- *  @hw: pointer to the HW structure
- *
- *  Called to initialize all function pointers and parameters.
- **/
-void e1000e_init_function_pointers_82571(struct e1000_hw *hw)
-{
-	e1000e_init_mac_ops_generic(hw);
-	e1000e_init_nvm_ops_generic(hw);
-	hw->mac.ops.init_params = e1000e_init_mac_params_82571;
-	hw->nvm.ops.init_params = e1000e_init_nvm_params_82571;
-	hw->phy.ops.init_params = e1000e_init_phy_params_82571;
-}
-
-/**
- *  e1000e_get_phy_id_82571 - Retrieve the PHY ID and revision
- *  @hw: pointer to the HW structure
- *
- *  Reads the PHY registers and stores the PHY ID and possibly the PHY
- *  revision in the hardware structure.
- **/
-static s32 e1000e_get_phy_id_82571(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 phy_id = 0;
-
-	switch (hw->mac.type) {
-	case e1000_82571:
-	case e1000_82572:
-		/*
-		 * The 82571 firmware may still be configuring the PHY.
-		 * In this case, we cannot access the PHY until the
-		 * configuration is done.  So we explicitly set the
-		 * PHY ID.
-		 */
-		phy->id = IGP01E1000_I_PHY_ID;
-		break;
-	case e1000_82573:
-		ret_val = e1000e_get_phy_id(hw);
-		break;
-	case e1000_82574:
-	case e1000_82583:
-		ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
-		if (ret_val)
-			goto out;
-
-		phy->id = (u32)(phy_id << 16);
-		udelay(20);
-		ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
-		if (ret_val)
-			goto out;
-
-		phy->id |= (u32)(phy_id);
-		phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
-		break;
-	default:
-		ret_val = -E1000_ERR_PHY;
-		break;
-	}
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_get_hw_semaphore_82571 - Acquire hardware semaphore
- *  @hw: pointer to the HW structure
- *
- *  Acquire the HW semaphore to access the PHY or NVM
- **/
-s32 e1000e_get_hw_semaphore_82571(struct e1000_hw *hw)
-{
-	u32 swsm;
-	s32 ret_val = E1000_SUCCESS;
-	s32 sw_timeout = hw->nvm.word_size + 1;
-	s32 fw_timeout = hw->nvm.word_size + 1;
-	s32 i = 0;
-
-	/*
-	 * If we have timedout 3 times on trying to acquire
-	 * the inter-port SMBI semaphore, there is old code
-	 * operating on the other port, and it is not
-	 * releasing SMBI. Modify the number of times that
-	 * we try for the semaphore to interwork with this
-	 * older code.
-	 */
-	if (hw->dev_spec._82571.smb_counter > 2)
-		sw_timeout = 1;
-
-	/* Get the SW semaphore */
-	while (i < sw_timeout) {
-		swsm = er32(SWSM);
-		if (!(swsm & E1000_SWSM_SMBI))
-			break;
-
-		udelay(50);
-		i++;
-	}
-
-	if (i == sw_timeout) {
-		e_dbg("Driver can't access device - SMBI bit is set.\n");
-		hw->dev_spec._82571.smb_counter++;
-	}
-	/* Get the FW semaphore. */
-	for (i = 0; i < fw_timeout; i++) {
-		swsm = er32(SWSM);
-		ew32(SWSM, swsm | E1000_SWSM_SWESMBI);
-
-		/* Semaphore acquired if bit latched */
-		if (er32(SWSM) & E1000_SWSM_SWESMBI)
-			break;
-
-		udelay(50);
-	}
-
-	if (i == fw_timeout) {
-		/* Release semaphores */
-		e1000e_put_hw_semaphore_82571(hw);
-		e_dbg("Driver can't access the NVM\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_put_hw_semaphore_82571 - Release hardware semaphore
- *  @hw: pointer to the HW structure
- *
- *  Release hardware semaphore used to access the PHY or NVM
- **/
-void e1000e_put_hw_semaphore_82571(struct e1000_hw *hw)
-{
-	u32 swsm;
-
-	swsm = er32(SWSM);
-	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
-	ew32(SWSM, swsm);
-}
-
-/**
- *  e1000e_acquire_nvm_82571 - Request for access to the EEPROM
- *  @hw: pointer to the HW structure
- *
- *  To gain access to the EEPROM, first we must obtain a hardware semaphore.
- *  Then for non-82573 hardware, set the EEPROM access request bit and wait
- *  for EEPROM access grant bit.  If the access grant bit is not set, release
- *  hardware semaphore.
- **/
-static s32 e1000e_acquire_nvm_82571(struct e1000_hw *hw)
-{
-	s32 ret_val;
-
-	ret_val = e1000e_get_hw_semaphore_82571(hw);
-	if (ret_val)
-		goto out;
-
-	switch (hw->mac.type) {
-	case e1000_82574:
-	case e1000_82583:
-	case e1000_82573:
-		break;
-	default:
-		ret_val = e1000e_acquire_nvm(hw);
-		break;
-	}
-
-	if (ret_val)
-		e1000e_put_hw_semaphore_82571(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_release_nvm_82571 - Release exclusive access to EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
- **/
-static void e1000e_release_nvm_82571(struct e1000_hw *hw)
-{
-	e1000e_release_nvm(hw);
-	e1000e_put_hw_semaphore_82571(hw);
-}
-
-/**
- *  e1000e_write_nvm_82571 - Write to EEPROM using appropriate interface
- *  @hw: pointer to the HW structure
- *  @offset: offset within the EEPROM to be written to
- *  @words: number of words to write
- *  @data: 16 bit word(s) to be written to the EEPROM
- *
- *  For non-82573 silicon, write data to EEPROM at offset using SPI interface.
- *
- *  If e1000e_update_nvm_checksum is not called after this function, the
- *  EEPROM will most likely contain an invalid checksum.
- **/
-static s32 e1000e_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words,
-                                 u16 *data)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	switch (hw->mac.type) {
-	case e1000_82573:
-	case e1000_82574:
-	case e1000_82583:
-		ret_val = e1000e_write_nvm_eewr_82571(hw, offset, words, data);
-		break;
-	case e1000_82571:
-	case e1000_82572:
-		ret_val = e1000e_write_nvm_spi(hw, offset, words, data);
-		break;
-	default:
-		ret_val = -E1000_ERR_NVM;
-		break;
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000e_update_nvm_checksum_82571 - Update EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
- *  up to the checksum.  Then calculates the EEPROM checksum and writes the
- *  value to the EEPROM.
- **/
-static s32 e1000e_update_nvm_checksum_82571(struct e1000_hw *hw)
-{
-	u32 eecd;
-	s32 ret_val;
-	u16 i;
-
-	ret_val = e1000e_update_nvm_checksum_generic(hw);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * If our nvm is an EEPROM, then we're done
-	 * otherwise, commit the checksum to the flash NVM.
-	 */
-	if (hw->nvm.type != e1000_nvm_flash_hw)
-		goto out;
-
-	/* Check for pending operations. */
-	for (i = 0; i < E1000_FLASH_UPDATES; i++) {
-		msleep(1);
-		if ((er32(EECD) & E1000_EECD_FLUPD) == 0)
-			break;
-	}
-
-	if (i == E1000_FLASH_UPDATES) {
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	/* Reset the firmware if using STM opcode. */
-	if ((er32(FLOP) & 0xFF00) == E1000_STM_OPCODE) {
-		/*
-		 * The enabling of and the actual reset must be done
-		 * in two write cycles.
-		 */
-		ew32(HICR, E1000_HICR_FW_RESET_ENABLE);
-		e1e_flush();
-		ew32(HICR, E1000_HICR_FW_RESET);
-	}
-
-	/* Commit the write to flash */
-	eecd = er32(EECD) | E1000_EECD_FLUPD;
-	ew32(EECD, eecd);
-
-	for (i = 0; i < E1000_FLASH_UPDATES; i++) {
-		msleep(1);
-		if ((er32(EECD) & E1000_EECD_FLUPD) == 0)
-			break;
-	}
-
-	if (i == E1000_FLASH_UPDATES) {
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_validate_nvm_checksum_82571 - Validate EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
- *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
- **/
-static s32 e1000e_validate_nvm_checksum_82571(struct e1000_hw *hw)
-{
-	if (hw->nvm.type == e1000_nvm_flash_hw)
-		e1000e_fix_nvm_checksum_82571(hw);
-
-	return e1000e_validate_nvm_checksum_generic(hw);
-}
-
-/**
- *  e1000e_write_nvm_eewr_82571 - Write to EEPROM for 82573 silicon
- *  @hw: pointer to the HW structure
- *  @offset: offset within the EEPROM to be written to
- *  @words: number of words to write
- *  @data: 16 bit word(s) to be written to the EEPROM
- *
- *  After checking for invalid values, poll the EEPROM to ensure the previous
- *  command has completed before trying to write the next word.  After write
- *  poll for completion.
- *
- *  If e1000e_update_nvm_checksum is not called after this function, the
- *  EEPROM will most likely contain an invalid checksum.
- **/
-static s32 e1000e_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
-                                      u16 words, u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 i, eewr = 0;
-	s32 ret_val = 0;
-
-	/*
-	 * A check for invalid values:  offset too large, too many words,
-	 * and not enough words.
-	 */
-	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
-	    (words == 0)) {
-		e_dbg("nvm parameter(s) out of bounds\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	for (i = 0; i < words; i++) {
-		eewr = (data[i] << E1000_NVM_RW_REG_DATA) |
-		       ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) |
-		       E1000_NVM_RW_REG_START;
-
-		ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
-		if (ret_val)
-			break;
-
-		ew32(EEWR, eewr);
-
-		ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
-		if (ret_val)
-			break;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_get_cfg_done_82571 - Poll for configuration done
- *  @hw: pointer to the HW structure
- *
- *  Reads the management control register for the config done bit to be set.
- **/
-static s32 e1000e_get_cfg_done_82571(struct e1000_hw *hw)
-{
-	s32 timeout = PHY_CFG_TIMEOUT;
-	s32 ret_val = E1000_SUCCESS;
-
-	while (timeout) {
-		if (er32(EEMNGCTL) & E1000_NVM_CFG_DONE_PORT_0)
-			break;
-		msleep(1);
-		timeout--;
-	}
-	if (!timeout) {
-		e_dbg("MNG configuration cycle has not completed.\n");
-		ret_val = -E1000_ERR_RESET;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_set_d0_lplu_state_82571 - Set Low Power Linkup D0 state
- *  @hw: pointer to the HW structure
- *  @active: true to enable LPLU, false to disable
- *
- *  Sets the LPLU D0 state according to the active flag.  When activating LPLU
- *  this function also disables smart speed and vice versa.  LPLU will not be
- *  activated unless the device autonegotiation advertisement meets standards
- *  of either 10 or 10/100 or 10/100/1000 at all duplexes.  This is a function
- *  pointer entry point only called by PHY setup routines.
- **/
-static s32 e1000e_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 data;
-
-	if (!(phy->ops.read_reg))
-		goto out;
-
-	ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data);
-	if (ret_val)
-		goto out;
-
-	if (active) {
-		data |= IGP02E1000_PM_D0_LPLU;
-		ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT,
-		                             data);
-		if (ret_val)
-			goto out;
-
-		/* When LPLU is enabled, we should disable SmartSpeed */
-		ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-		                            &data);
-		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-		ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-		                             data);
-		if (ret_val)
-			goto out;
-	} else {
-		data &= ~IGP02E1000_PM_D0_LPLU;
-		ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT,
-		                             data);
-		/*
-		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
-		 * during Dx states where the power conservation is most
-		 * important.  During driver activity we should enable
-		 * SmartSpeed, so performance is maintained.
-		 */
-		if (phy->smart_speed == e1000_smart_speed_on) {
-			ret_val = e1e_rphy(hw,
-			                            IGP01E1000_PHY_PORT_CONFIG,
-			                            &data);
-			if (ret_val)
-				goto out;
-
-			data |= IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		} else if (phy->smart_speed == e1000_smart_speed_off) {
-			ret_val = e1e_rphy(hw,
-			                            IGP01E1000_PHY_PORT_CONFIG,
-			                            &data);
-			if (ret_val)
-				goto out;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_reset_hw_82571 - Reset hardware
- *  @hw: pointer to the HW structure
- *
- *  This resets the hardware into a known state.
- **/
-static s32 e1000e_reset_hw_82571(struct e1000_hw *hw)
-{
-	u32 ctrl, extcnf_ctrl, ctrl_ext;
-	s32 ret_val;
-	u16 i = 0;
-
-	/*
-	 * Prevent the PCI-E bus from sticking if there is no TLP connection
-	 * on the last TLP read/write transaction when MAC is reset.
-	 */
-	ret_val = e1000e_disable_pcie_master(hw);
-	if (ret_val)
-		e_dbg("PCI-E Master disable polling has failed.\n");
-
-	e_dbg("Masking off all interrupts\n");
-	ew32(IMC, 0xffffffff);
-
-	ew32(RCTL, 0);
-	ew32(TCTL, E1000_TCTL_PSP);
-	e1e_flush();
-
-	msleep(10);
-
-	/*
-	 * Must acquire the MDIO ownership before MAC reset.
-	 * Ownership defaults to firmware after a reset.
-	 */
-	switch (hw->mac.type) {
-	case e1000_82574:
-	case e1000_82583:
-	case e1000_82573:
-		extcnf_ctrl = er32(EXTCNF_CTRL);
-		extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
-
-		do {
-			ew32(EXTCNF_CTRL, extcnf_ctrl);
-			extcnf_ctrl = er32(EXTCNF_CTRL);
-
-			if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
-				break;
-
-			extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
-
-			msleep(2);
-			i++;
-		} while (i < MDIO_OWNERSHIP_TIMEOUT);
-		break;
-	default:
-		break;
-	}
-
-	ctrl = er32(CTRL);
-
-	e_dbg("Issuing a global reset to MAC\n");
-	ew32(CTRL, ctrl | E1000_CTRL_RST);
-
-	if (hw->nvm.type == e1000_nvm_flash_hw) {
-		udelay(10);
-		ctrl_ext = er32(CTRL_EXT);
-		ctrl_ext |= E1000_CTRL_EXT_EE_RST;
-		ew32(CTRL_EXT, ctrl_ext);
-		e1e_flush();
-	}
-
-	ret_val = e1000e_get_auto_rd_done(hw);
-	if (ret_val)
-		/* We don't want to continue accessing MAC registers. */
-		goto out;
-
-	/*
-	 * Phy configuration from NVM just starts after EECD_AUTO_RD is set.
-	 * Need to wait for Phy configuration completion before accessing
-	 * NVM and Phy.
-	 */
-
-	switch (hw->mac.type) {
-	case e1000_82574:
-	case e1000_82583:
-	case e1000_82573:
-		msleep(25);
-		break;
-	default:
-		break;
-	}
-
-	/* Clear any pending interrupt events. */
-	ew32(IMC, 0xffffffff);
-	er32(ICR);
-
-	/* Install any alternate MAC address into RAR0 */
-	ret_val = e1000e_check_alt_mac_addr_generic(hw);
-	if (ret_val)
-		goto out;
-
-	e1000e_set_laa_state_82571(hw, true);
-
-	/* Reinitialize the 82571 serdes link state machine */
-	if (hw->phy.media_type == e1000_media_type_internal_serdes)
-		hw->mac.serdes_link_state = e1000_serdes_link_down;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_init_hw_82571 - Initialize hardware
- *  @hw: pointer to the HW structure
- *
- *  This inits the hardware readying it for operation.
- **/
-static s32 e1000e_init_hw_82571(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 reg_data;
-	s32 ret_val;
-	u16 i, rar_count = mac->rar_entry_count;
-
-	e1000e_initialize_hw_bits_82571(hw);
-
-	/* Initialize identification LED */
-	ret_val = mac->ops.id_led_init(hw);
-	if (ret_val) {
-		e_dbg("Error initializing identification LED\n");
-		/* This is not fatal and we should not stop init due to this */
-	}
-
-	/* Disabling VLAN filtering */
-	e_dbg("Initializing the IEEE VLAN\n");
-	e1000e_clear_vfta(hw);
-
-	/* Setup the receive address. */
-	/*
-	 * If, however, a locally administered address was assigned to the
-	 * 82571, we must reserve a RAR for it to work around an issue where
-	 * resetting one port will reload the MAC on the other port.
-	 */
-	if (e1000e_get_laa_state_82571(hw))
-		rar_count--;
-	e1000e_init_rx_addrs(hw, rar_count);
-
-	/* Zero out the Multicast HASH table */
-	e_dbg("Zeroing the MTA\n");
-	for (i = 0; i < mac->mta_reg_count; i++)
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
-
-	/* Setup link and flow control */
-	ret_val = mac->ops.setup_link(hw);
-
-	/* Set the transmit descriptor write-back policy */
-	reg_data = er32(TXDCTL(0));
-	reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
-	           E1000_TXDCTL_FULL_TX_DESC_WB |
-	           E1000_TXDCTL_COUNT_DESC;
-	ew32(TXDCTL(0), reg_data);
-
-	/* ...for both queues. */
-	switch (mac->type) {
-	case e1000_82574:
-	case e1000_82583:
-	case e1000_82573:
-#if 0
-		e1000e_enable_tx_pkt_filtering(hw);
-#endif
-		reg_data = er32(GCR);
-		reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
-		ew32(GCR, reg_data);
-		break;
-	default:
-		reg_data = er32(TXDCTL(1));
-		reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
-					E1000_TXDCTL_FULL_TX_DESC_WB |
-					E1000_TXDCTL_COUNT_DESC;
-		ew32(TXDCTL(1), reg_data);
-		break;
-	}
-
-	/*
-	 * Clear all of the statistics registers (clear on read).  It is
-	 * important that we do this after we have tried to establish link
-	 * because the symbol error count will increment wildly if there
-	 * is no link.
-	 */
-	e1000e_clear_hw_cntrs_82571(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_initialize_hw_bits_82571 - Initialize hardware-dependent bits
- *  @hw: pointer to the HW structure
- *
- *  Initializes required hardware-dependent bits needed for normal operation.
- **/
-static void e1000e_initialize_hw_bits_82571(struct e1000_hw *hw)
-{
-	u32 reg;
-
-	/* Transmit Descriptor Control 0 */
-	reg = er32(TXDCTL(0));
-	reg |= (1 << 22);
-	ew32(TXDCTL(0), reg);
-
-	/* Transmit Descriptor Control 1 */
-	reg = er32(TXDCTL(1));
-	reg |= (1 << 22);
-	ew32(TXDCTL(1), reg);
-
-	/* Transmit Arbitration Control 0 */
-	reg = er32(TARC(0));
-	reg &= ~(0xF << 27); /* 30:27 */
-	switch (hw->mac.type) {
-	case e1000_82571:
-	case e1000_82572:
-		reg |= (1 << 23) | (1 << 24) | (1 << 25) | (1 << 26);
-		break;
-	default:
-		break;
-	}
-	ew32(TARC(0), reg);
-
-	/* Transmit Arbitration Control 1 */
-	reg = er32(TARC(1));
-	switch (hw->mac.type) {
-	case e1000_82571:
-	case e1000_82572:
-		reg &= ~((1 << 29) | (1 << 30));
-		reg |= (1 << 22) | (1 << 24) | (1 << 25) | (1 << 26);
-		if (er32(TCTL) & E1000_TCTL_MULR)
-			reg &= ~(1 << 28);
-		else
-			reg |= (1 << 28);
-		ew32(TARC(1), reg);
-		break;
-	default:
-		break;
-	}
-
-	/* Device Control */
-
-	switch (hw->mac.type) {
-	case e1000_82574:
-	case e1000_82583:
-	case e1000_82573:
-		reg = er32(CTRL);
-		reg &= ~(1 << 29);
-		ew32(CTRL, reg);
-		break;
-	default:
-		break;
-	}
-
-	/* Extended Device Control */
-	switch (hw->mac.type) {
-	case e1000_82574:
-	case e1000_82583:
-	case e1000_82573:
-		reg = er32(CTRL_EXT);
-		reg &= ~(1 << 23);
-		reg |= (1 << 22);
-		ew32(CTRL_EXT, reg);
-		break;
-	default:
-		break;
-	}
-
-
-	if (hw->mac.type == e1000_82571) {
-		reg = er32(PBA_ECC);
-		reg |= E1000_PBA_ECC_CORR_EN;
-		ew32(PBA_ECC, reg);
-	}
-
-	/*
-	 * Workaround for hardware errata.
-	 * Ensure that DMA Dynamic Clock gating is disabled on 82571 and 82572
-	 */
-
-	if ((hw->mac.type == e1000_82571) ||
-	   (hw->mac.type == e1000_82572)) {
-		reg = er32(CTRL_EXT);
-		reg &= ~E1000_CTRL_EXT_DMA_DYN_CLK_EN;
-		ew32(CTRL_EXT, reg);
-	}
-
-	/* PCI-Ex Control Registers */
-
-	switch (hw->mac.type) {
-	case e1000_82574:
-	case e1000_82583:
-		reg = er32(GCR);
-		reg |= (1 << 22);
-		ew32(GCR, reg);
-		/*
-		 * Workaround for hardware errata.
-		 * apply workaround for hardware errata documented in errata
-		 * docs Fixes issue where some error prone or unreliable PCIe
-		 * completions are occurring, particularly with ASPM enabled.
-		 * Without fix, issue can cause tx timeouts.
-		 */
-		reg = er32(GCR2);
-		reg |= 1;
-		ew32(GCR2, reg);
-		break;
-	default:
-		break;
-	}
-	return;
-}
-
-/**
- *  e1000e_clear_vfta_82571 - Clear VLAN filter table
- *  @hw: pointer to the HW structure
- *
- *  Clears the register array which contains the VLAN filter table by
- *  setting all the values to 0.
- **/
-static void e1000e_clear_vfta_82571(struct e1000_hw *hw)
-{
-	u32 offset;
-	u32 vfta_value = 0;
-	u32 vfta_offset = 0;
-	u32 vfta_bit_in_reg = 0;
-
-	switch (hw->mac.type) {
-	case e1000_82574:
-	case e1000_82583:
-	case e1000_82573:
-		if (hw->mng_cookie.vlan_id != 0) {
-			/*
-			*The VFTA is a 4096b bit-field, each identifying
-			*a single VLAN ID.  The following operations
-			*determine which 32b entry (i.e. offset) into the
-			*array we want to set the VLAN ID (i.e. bit) of
-			*the manageability unit.
-			*/
-			vfta_offset = (hw->mng_cookie.vlan_id >>
-				E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK;
-			vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
-				E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
-		}
-
-		for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
-			/*
-			*If the offset we want to clear is the same offset of
-			*the manageability VLAN ID, then clear all bits except
-			*that of the manageability unit
-			*/
-			vfta_value = (offset == vfta_offset) ?
-							vfta_bit_in_reg : 0;
-			E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset,
-				vfta_value);
-			e1e_flush();
-		}
-		break;
-	default:
-		break;
-	}
-}
-
-#if 0
-/**
- *  e1000e_check_mng_mode_82574 - Check manageability is enabled
- *  @hw: pointer to the HW structure
- *
- *  Reads the NVM Initialization Control Word 2 and returns true
- *  (>0) if any manageability is enabled, else false (0).
- **/
-static bool e1000e_check_mng_mode_82574(struct e1000_hw *hw)
-{
-	u16 data;
-
-	e1000e_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data);
-	return (data & E1000_NVM_INIT_CTRL2_MNGM) != 0;
-}
-#endif
-
-/**
- *  e1000e_led_on_82574 - Turn LED on
- *  @hw: pointer to the HW structure
- *
- *  Turn LED on.
- **/
-static s32 e1000e_led_on_82574(struct e1000_hw *hw __unused)
-{
-#if 0
-	u32 ctrl;
-	u32 i;
-
-	ctrl = hw->mac.ledctl_mode2;
-	if (!(E1000_STATUS_LU & er32(STATUS))) {
-		/*
-		 * If no link, then turn LED on by setting the invert bit
-		 * for each LED that's "on" (0x0E) in ledctl_mode2.
-		 */
-		for (i = 0; i < 4; i++)
-			if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
-			    E1000_LEDCTL_MODE_LED_ON)
-				ctrl |= (E1000_LEDCTL_LED0_IVRT << (i * 8));
-	}
-	ew32(LEDCTL, ctrl);
-#endif
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_setup_link_82571 - Setup flow control and link settings
- *  @hw: pointer to the HW structure
- *
- *  Determines which flow control settings to use, then configures flow
- *  control.  Calls the appropriate media-specific link configuration
- *  function.  Assuming the adapter has a valid link partner, a valid link
- *  should be established.  Assumes the hardware has previously been reset
- *  and the transmitter and receiver are not enabled.
- **/
-static s32 e1000e_setup_link_82571(struct e1000_hw *hw)
-{
-	/*
-	 * 82573 does not have a word in the NVM to determine
-	 * the default flow control setting, so we explicitly
-	 * set it to full.
-	 */
-	switch (hw->mac.type) {
-	case e1000_82574:
-	case e1000_82583:
-	case e1000_82573:
-		if (hw->fc.requested_mode == e1000_fc_default)
-			hw->fc.requested_mode = e1000_fc_full;
-		break;
-	default:
-		break;
-	}
-	return e1000e_setup_link(hw);
-}
-
-/**
- *  e1000e_setup_copper_link_82571 - Configure copper link settings
- *  @hw: pointer to the HW structure
- *
- *  Configures the link for auto-neg or forced speed and duplex.  Then we check
- *  for link, once link is established calls to configure collision distance
- *  and flow control are called.
- **/
-static s32 e1000e_setup_copper_link_82571(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32  ret_val;
-
-	ctrl = er32(CTRL);
-	ctrl |= E1000_CTRL_SLU;
-	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-	ew32(CTRL, ctrl);
-
-	switch (hw->phy.type) {
-	case e1000_phy_m88:
-	case e1000_phy_bm:
-		ret_val = e1000e_copper_link_setup_m88(hw);
-		break;
-	case e1000_phy_igp_2:
-		ret_val = e1000e_copper_link_setup_igp(hw);
-		break;
-	default:
-		ret_val = -E1000_ERR_PHY;
-		break;
-	}
-
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000e_setup_copper_link(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_setup_fiber_serdes_link_82571 - Setup link for fiber/serdes
- *  @hw: pointer to the HW structure
- *
- *  Configures collision distance and flow control for fiber and serdes links.
- *  Upon successful setup, poll for link.
- **/
-static s32 e1000e_setup_fiber_serdes_link_82571(struct e1000_hw *hw)
-{
-	switch (hw->mac.type) {
-	case e1000_82571:
-	case e1000_82572:
-		/*
-		 * If SerDes loopback mode is entered, there is no form
-		 * of reset to take the adapter out of that mode.  So we
-		 * have to explicitly take the adapter out of loopback
-		 * mode.  This prevents drivers from twiddling their thumbs
-		 * if another tool failed to take it out of loopback mode.
-		 */
-		ew32(SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
-		break;
-	default:
-		break;
-	}
-
-	return e1000e_setup_fiber_serdes_link(hw);
-}
-
-/**
- *  e1000e_check_for_serdes_link_82571 - Check for link (Serdes)
- *  @hw: pointer to the HW structure
- *
- *  Reports the link state as up or down.
- *
- *  If autonegotiation is supported by the link partner, the link state is
- *  determined by the result of autongotiation. This is the most likely case.
- *  If autonegotiation is not supported by the link partner, and the link
- *  has a valid signal, force the link up.
- *
- *  The link state is represented internally here by 4 states:
- *
- *  1) down
- *  2) autoneg_progress
- *  3) autoneg_complete (the link sucessfully autonegotiated)
- *  4) forced_up (the link has been forced up, it did not autonegotiate)
- *
- **/
-s32 e1000e_check_for_serdes_link_82571(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 rxcw;
-	u32 ctrl;
-	u32 status;
-	s32 ret_val = E1000_SUCCESS;
-
-	ctrl = er32(CTRL);
-	status = er32(STATUS);
-	rxcw = er32(RXCW);
-
-	if ((rxcw & E1000_RXCW_SYNCH) && !(rxcw & E1000_RXCW_IV)) {
-
-		/* Receiver is synchronized with no invalid bits.  */
-		switch (mac->serdes_link_state) {
-		case e1000_serdes_link_autoneg_complete:
-			if (!(status & E1000_STATUS_LU)) {
-				/*
-				 * We have lost link, retry autoneg before
-				 * reporting link failure
-				 */
-				mac->serdes_link_state =
-				    e1000_serdes_link_autoneg_progress;
-				mac->serdes_has_link = false;
-				e_dbg("AN_UP     -> AN_PROG\n");
-			}
-		break;
-
-		case e1000_serdes_link_forced_up:
-			/*
-			 * If we are receiving /C/ ordered sets, re-enable
-			 * auto-negotiation in the TXCW register and disable
-			 * forced link in the Device Control register in an
-			 * attempt to auto-negotiate with our link partner.
-			 */
-			if (rxcw & E1000_RXCW_C) {
-				/* Enable autoneg, and unforce link up */
-				ew32(TXCW, mac->txcw);
-				ew32(CTRL,
-				    (ctrl & ~E1000_CTRL_SLU));
-				mac->serdes_link_state =
-				    e1000_serdes_link_autoneg_progress;
-				mac->serdes_has_link = false;
-				e_dbg("FORCED_UP -> AN_PROG\n");
-			}
-			break;
-
-		case e1000_serdes_link_autoneg_progress:
-			if (rxcw & E1000_RXCW_C) {
-				/* We received /C/ ordered sets, meaning the
-				 * link partner has autonegotiated, and we can
-				 * trust the Link Up (LU) status bit
-				 */
-				if (status & E1000_STATUS_LU) {
-					mac->serdes_link_state =
-					    e1000_serdes_link_autoneg_complete;
-					e_dbg("AN_PROG   -> AN_UP\n");
-					mac->serdes_has_link = true;
-				} else {
-					/* Autoneg completed, but failed */
-					mac->serdes_link_state =
-					    e1000_serdes_link_down;
-					e_dbg("AN_PROG   -> DOWN\n");
-				}
-			} else {
-				/* The link partner did not autoneg.
-				 * Force link up and full duplex, and change
-				 * state to forced.
-				 */
-				ew32(TXCW,
-				(mac->txcw & ~E1000_TXCW_ANE));
-				ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
-				ew32(CTRL, ctrl);
-
-				/* Configure Flow Control after link up. */
-				ret_val =
-				    e1000e_config_fc_after_link_up(hw);
-				if (ret_val) {
-					e_dbg("Error config flow control\n");
-					break;
-				}
-				mac->serdes_link_state =
-				e1000_serdes_link_forced_up;
-				mac->serdes_has_link = true;
-				e_dbg("AN_PROG   -> FORCED_UP\n");
-			}
-			break;
-
-		case e1000_serdes_link_down:
-		default:
-			/* The link was down but the receiver has now gained
-			 * valid sync, so lets see if we can bring the link
-			 * up. */
-			ew32(TXCW, mac->txcw);
-			ew32(CTRL,
-			    (ctrl & ~E1000_CTRL_SLU));
-			mac->serdes_link_state =
-			    e1000_serdes_link_autoneg_progress;
-			e_dbg("DOWN      -> AN_PROG\n");
-			break;
-		}
-	} else {
-		if (!(rxcw & E1000_RXCW_SYNCH)) {
-			mac->serdes_has_link = false;
-			mac->serdes_link_state = e1000_serdes_link_down;
-			e_dbg("ANYSTATE  -> DOWN\n");
-		} else {
-			/*
-			 * We have sync, and can tolerate one
-			 * invalid (IV) codeword before declaring
-			 * link down, so reread to look again
-			 */
-			udelay(10);
-			rxcw = er32(RXCW);
-			if (rxcw & E1000_RXCW_IV) {
-				mac->serdes_link_state = e1000_serdes_link_down;
-				mac->serdes_has_link = false;
-				e_dbg("ANYSTATE  -> DOWN\n");
-			}
-		}
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000e_valid_led_default_82571 - Verify a valid default LED config
- *  @hw: pointer to the HW structure
- *  @data: pointer to the NVM (EEPROM)
- *
- *  Read the EEPROM for the current default LED configuration.  If the
- *  LED configuration is not valid, set to a valid LED configuration.
- **/
-static s32 e1000e_valid_led_default_82571(struct e1000_hw *hw, u16 *data)
-{
-	s32 ret_val;
-
-	ret_val = e1000e_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
-	if (ret_val) {
-		e_dbg("NVM Read Error\n");
-		goto out;
-	}
-
-	switch (hw->mac.type) {
-	case e1000_82574:
-	case e1000_82583:
-	case e1000_82573:
-		if(*data == ID_LED_RESERVED_F746)
-			*data = ID_LED_DEFAULT_82573;
-		break;
-	default:
-		if (*data == ID_LED_RESERVED_0000 ||
-			*data == ID_LED_RESERVED_FFFF)
-			*data = ID_LED_DEFAULT;
-		break;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_get_laa_state_82571 - Get locally administered address state
- *  @hw: pointer to the HW structure
- *
- *  Retrieve and return the current locally administered address state.
- **/
-bool e1000e_get_laa_state_82571(struct e1000_hw *hw)
-{
-	if (hw->mac.type != e1000_82571)
-		return false;
-
-	return hw->dev_spec._82571.laa_is_present;
-}
-
-/**
- *  e1000e_set_laa_state_82571 - Set locally administered address state
- *  @hw: pointer to the HW structure
- *  @state: enable/disable locally administered address
- *
- *  Enable/Disable the current locally administered address state.
- **/
-void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state)
-{
-	if (hw->mac.type != e1000_82571)
-		return;
-
-	hw->dev_spec._82571.laa_is_present = state;
-
-	/* If workaround is activated... */
-	if (state)
-		/*
-		 * Hold a copy of the LAA in RAR[14] This is done so that
-		 * between the time RAR[0] gets clobbered and the time it
-		 * gets fixed, the actual LAA is in one of the RARs and no
-		 * incoming packets directed to this port are dropped.
-		 * Eventually the LAA will be in RAR[0] and RAR[14].
-		 */
-		e1000e_rar_set(hw, hw->mac.addr,
-		                      hw->mac.rar_entry_count - 1);
-	return;
-}
-
-/**
- *  e1000e_fix_nvm_checksum_82571 - Fix EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Verifies that the EEPROM has completed the update.  After updating the
- *  EEPROM, we need to check bit 15 in work 0x23 for the checksum fix.  If
- *  the checksum fix is not implemented, we need to set the bit and update
- *  the checksum.  Otherwise, if bit 15 is set and the checksum is incorrect,
- *  we need to return bad checksum.
- **/
-static s32 e1000e_fix_nvm_checksum_82571(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	s32 ret_val = E1000_SUCCESS;
-	u16 data;
-
-	if (nvm->type != e1000_nvm_flash_hw)
-		goto out;
-
-	/*
-	 * Check bit 4 of word 10h.  If it is 0, firmware is done updating
-	 * 10h-12h.  Checksum may need to be fixed.
-	 */
-	ret_val = e1000e_read_nvm(hw, 0x10, 1, &data);
-	if (ret_val)
-		goto out;
-
-	if (!(data & 0x10)) {
-		/*
-		 * Read 0x23 and check bit 15.  This bit is a 1
-		 * when the checksum has already been fixed.  If
-		 * the checksum is still wrong and this bit is a
-		 * 1, we need to return bad checksum.  Otherwise,
-		 * we need to set this bit to a 1 and update the
-		 * checksum.
-		 */
-		ret_val = e1000e_read_nvm(hw, 0x23, 1, &data);
-		if (ret_val)
-			goto out;
-
-		if (!(data & 0x8000)) {
-			data |= 0x8000;
-			ret_val = e1000e_write_nvm(hw, 0x23, 1, &data);
-			if (ret_val)
-				goto out;
-			ret_val = e1000e_update_nvm_checksum(hw);
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_read_mac_addr_82571 - Read device MAC address
- *  @hw: pointer to the HW structure
- **/
-static s32 e1000e_read_mac_addr_82571(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	/*
-	 * If there's an alternate MAC address place it in RAR0
-	 * so that it will override the Si installed default perm
-	 * address.
-	 */
-	ret_val = e1000e_check_alt_mac_addr_generic(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000e_read_mac_addr_generic(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- * e1000e_power_down_phy_copper_82571 - Remove link during PHY power down
- * @hw: pointer to the HW structure
- *
- * In the case of a PHY power down to save power, or to turn off link during a
- * driver unload, or wake on lan is not enabled, remove the link.
- **/
-static void e1000e_power_down_phy_copper_82571(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	struct e1000_mac_info *mac = &hw->mac;
-
-	if (!(phy->ops.check_reset_block))
-		return;
-
-	/* If the management interface is not enabled, then power down */
-	if (!(mac->ops.check_mng_mode(hw) || e1000e_check_reset_block(hw)))
-		e1000e_power_down_phy_copper(hw);
-
-	return;
-}
-
-/**
- *  e1000e_clear_hw_cntrs_82571 - Clear device specific hardware counters
- *  @hw: pointer to the HW structure
- *
- *  Clears the hardware counters by reading the counter registers.
- **/
-static void e1000e_clear_hw_cntrs_82571(struct e1000_hw *hw __unused)
-{
-#if 0
-	e1000e_clear_hw_cntrs_base(hw);
-
-	er32(PRC64);
-	er32(PRC127);
-	er32(PRC255);
-	er32(PRC511);
-	er32(PRC1023);
-	er32(PRC1522);
-	er32(PTC64);
-	er32(PTC127);
-	er32(PTC255);
-	er32(PTC511);
-	er32(PTC1023);
-	er32(PTC1522);
-
-	er32(ALGNERRC);
-	er32(RXERRC);
-	er32(TNCRS);
-	er32(CEXTERR);
-	er32(TSCTC);
-	er32(TSCTFC);
-
-	er32(MGTPRC);
-	er32(MGTPDC);
-	er32(MGTPTC);
-
-	er32(IAC);
-	er32(ICRXOC);
-
-	er32(ICRXPTC);
-	er32(ICRXATC);
-	er32(ICTXPTC);
-	er32(ICTXATC);
-	er32(ICTXQEC);
-	er32(ICTXQMTC);
-	er32(ICRXDMTC);
-#endif
-}
-
-static struct pci_device_id e1000e_82571_nics[] = {
-     PCI_ROM(0x8086, 0x105E, "E1000_DEV_ID_82571EB_COPPER", "E1000_DEV_ID_82571EB_COPPER", board_82571),
-     PCI_ROM(0x8086, 0x105F, "E1000_DEV_ID_82571EB_FIBER", "E1000_DEV_ID_82571EB_FIBER", board_82571),
-     PCI_ROM(0x8086, 0x10A4, "E1000_DEV_ID_82571EB_QUAD_COPPER", "E1000_DEV_ID_82571EB_QUAD_COPPER", board_82571),
-     PCI_ROM(0x8086, 0x10BC, "E1000_DEV_ID_82571EB_QUAD_COPPER_LP", "E1000_DEV_ID_82571EB_QUAD_COPPER_LP", board_82571),
-     PCI_ROM(0x8086, 0x10A5, "E1000_DEV_ID_82571EB_QUAD_FIBER", "E1000_DEV_ID_82571EB_QUAD_FIBER", board_82571),
-     PCI_ROM(0x8086, 0x1060, "E1000_DEV_ID_82571EB_SERDES", "E1000_DEV_ID_82571EB_SERDES", board_82571),
-     PCI_ROM(0x8086, 0x10D9, "E1000_DEV_ID_82571EB_SERDES_DUAL", "E1000_DEV_ID_82571EB_SERDES_DUAL", board_82571),
-     PCI_ROM(0x8086, 0x10DA, "E1000_DEV_ID_82571EB_SERDES_QUAD", "E1000_DEV_ID_82571EB_SERDES_QUAD", board_82571),
-     PCI_ROM(0x8086, 0x10D5, "E1000_DEV_ID_82571PT_QUAD_COPPER", "E1000_DEV_ID_82571PT_QUAD_COPPER", board_82571),
-     PCI_ROM(0x8086, 0x10B9, "E1000_DEV_ID_82572EI", "E1000_DEV_ID_82572EI", board_82572),
-     PCI_ROM(0x8086, 0x107D, "E1000_DEV_ID_82572EI_COPPER", "E1000_DEV_ID_82572EI_COPPER", board_82572),
-     PCI_ROM(0x8086, 0x107E, "E1000_DEV_ID_82572EI_FIBER", "E1000_DEV_ID_82572EI_FIBER", board_82572),
-     PCI_ROM(0x8086, 0x107F, "E1000_DEV_ID_82572EI_SERDES", "E1000_DEV_ID_82572EI_SERDES", board_82572),
-     PCI_ROM(0x8086, 0x108B, "E1000_DEV_ID_82573E", "E1000_DEV_ID_82573E", board_82573),
-     PCI_ROM(0x8086, 0x108C, "E1000_DEV_ID_82573E_IAMT", "E1000_DEV_ID_82573E_IAMT", board_82573),
-     PCI_ROM(0x8086, 0x109A, "E1000_DEV_ID_82573L", "E1000_DEV_ID_82573L", board_82573),
-     PCI_ROM(0x8086, 0x10D3, "E1000_DEV_ID_82574L", "E1000_DEV_ID_82574L", board_82574),
-     PCI_ROM(0x8086, 0x10F6, "E1000_DEV_ID_82574LA", "E1000_DEV_ID_82574LA", board_82574),
-     PCI_ROM(0x8086, 0x150C, "E1000_DEV_ID_82583V", "E1000_DEV_ID_82583V", board_82583),
-};
-
-struct pci_driver e1000e_82571_driver __pci_driver = {
-	.ids = e1000e_82571_nics,
-	.id_count = (sizeof (e1000e_82571_nics) / sizeof (e1000e_82571_nics[0])),
-	.probe = e1000e_probe,
-	.remove = e1000e_remove,
-};
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_82571.h b/roms/ipxe/src/drivers/net/e1000e/e1000e_82571.h
deleted file mode 100644
index c645e25ab372965a84f738f44d7b939e88d5ef09..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_82571.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000E_82571_H_
-#define _E1000E_82571_H_
-
-#define ID_LED_RESERVED_F746 0xF746
-#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \
-                              (ID_LED_OFF1_ON2  <<  8) | \
-                              (ID_LED_DEF1_DEF2 <<  4) | \
-                              (ID_LED_DEF1_DEF2))
-
-#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
-
-/* Intr Throttling - RW */
-#define E1000_EITR_82574(_n)    (0x000E8 + (0x4 * (_n)))
-
-#define E1000_EIAC_82574        0x000DC /* Ext. Interrupt Auto Clear - RW */
-#define E1000_EIAC_MASK_82574   0x01F00000
-
-#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */
-
-#define E1000_RXCFGL    0x0B634 /* TimeSync Rx EtherType & Msg Type Reg - RW */
-
-bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
-void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_defines.h b/roms/ipxe/src/drivers/net/e1000e/e1000e_defines.h
deleted file mode 100644
index da135d918bffb16c96005f4d8f55beac8efd0cb5..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_defines.h
+++ /dev/null
@@ -1,1469 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000E_DEFINES_H_
-#define _E1000E_DEFINES_H_
-
-/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
-#define REQ_TX_DESCRIPTOR_MULTIPLE  8
-#define REQ_RX_DESCRIPTOR_MULTIPLE  8
-
-/* Definitions for power management and wakeup registers */
-/* Wake Up Control */
-#define E1000_WUC_APME       0x00000001 /* APM Enable */
-#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
-#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
-#define E1000_WUC_APMPME     0x00000008 /* Assert PME on APM Wakeup */
-#define E1000_WUC_LSCWE      0x00000010 /* Link Status wake up enable */
-#define E1000_WUC_LSCWO      0x00000020 /* Link Status wake up override */
-#define E1000_WUC_SPM        0x80000000 /* Enable SPM */
-#define E1000_WUC_PHY_WAKE   0x00000100 /* if PHY supports wakeup */
-
-/* Wake Up Filter Control */
-#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
-#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
-#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
-#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
-#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
-#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
-#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
-#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
-#define E1000_WUFC_IGNORE_TCO_PHY 0x00000800 /* Ignore WakeOn TCO packets */
-#define E1000_WUFC_FLX0_PHY      0x00001000 /* Flexible Filter 0 Enable */
-#define E1000_WUFC_FLX1_PHY      0x00002000 /* Flexible Filter 1 Enable */
-#define E1000_WUFC_FLX2_PHY      0x00004000 /* Flexible Filter 2 Enable */
-#define E1000_WUFC_FLX3_PHY      0x00008000 /* Flexible Filter 3 Enable */
-#define E1000_WUFC_FLX4_PHY      0x00000200 /* Flexible Filter 4 Enable */
-#define E1000_WUFC_FLX5_PHY      0x00000400 /* Flexible Filter 5 Enable */
-#define E1000_WUFC_IGNORE_TCO   0x00008000 /* Ignore WakeOn TCO packets */
-#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
-#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
-#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
-#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
-#define E1000_WUFC_FLX4 0x00100000 /* Flexible Filter 4 Enable */
-#define E1000_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */
-#define E1000_WUFC_ALL_FILTERS_PHY_4 0x0000F0FF /*Mask for all wakeup filters*/
-#define E1000_WUFC_FLX_OFFSET_PHY 12 /* Offset to the Flexible Filters bits */
-#define E1000_WUFC_FLX_FILTERS_PHY_4 0x0000F000 /*Mask for 4 flexible filters*/
-#define E1000_WUFC_ALL_FILTERS_PHY_6 0x0000F6FF /*Mask for 6 wakeup filters */
-#define E1000_WUFC_FLX_FILTERS_PHY_6 0x0000F600 /*Mask for 6 flexible filters*/
-#define E1000_WUFC_ALL_FILTERS  0x000F00FF /* Mask for all wakeup filters */
-#define E1000_WUFC_ALL_FILTERS_6  0x003F00FF /* Mask for all 6 wakeup filters*/
-#define E1000_WUFC_FLX_OFFSET   16 /* Offset to the Flexible Filters bits */
-#define E1000_WUFC_FLX_FILTERS  0x000F0000 /*Mask for the 4 flexible filters */
-#define E1000_WUFC_FLX_FILTERS_6  0x003F0000 /* Mask for 6 flexible filters */
-
-/* Wake Up Status */
-#define E1000_WUS_LNKC         E1000_WUFC_LNKC
-#define E1000_WUS_MAG          E1000_WUFC_MAG
-#define E1000_WUS_EX           E1000_WUFC_EX
-#define E1000_WUS_MC           E1000_WUFC_MC
-#define E1000_WUS_BC           E1000_WUFC_BC
-#define E1000_WUS_ARP          E1000_WUFC_ARP
-#define E1000_WUS_IPV4         E1000_WUFC_IPV4
-#define E1000_WUS_IPV6         E1000_WUFC_IPV6
-#define E1000_WUS_FLX0_PHY      E1000_WUFC_FLX0_PHY
-#define E1000_WUS_FLX1_PHY      E1000_WUFC_FLX1_PHY
-#define E1000_WUS_FLX2_PHY      E1000_WUFC_FLX2_PHY
-#define E1000_WUS_FLX3_PHY      E1000_WUFC_FLX3_PHY
-#define E1000_WUS_FLX_FILTERS_PHY_4        E1000_WUFC_FLX_FILTERS_PHY_4
-#define E1000_WUS_FLX0         E1000_WUFC_FLX0
-#define E1000_WUS_FLX1         E1000_WUFC_FLX1
-#define E1000_WUS_FLX2         E1000_WUFC_FLX2
-#define E1000_WUS_FLX3         E1000_WUFC_FLX3
-#define E1000_WUS_FLX4         E1000_WUFC_FLX4
-#define E1000_WUS_FLX5         E1000_WUFC_FLX5
-#define E1000_WUS_FLX4_PHY         E1000_WUFC_FLX4_PHY
-#define E1000_WUS_FLX5_PHY         E1000_WUFC_FLX5_PHY
-#define E1000_WUS_FLX_FILTERS  E1000_WUFC_FLX_FILTERS
-#define E1000_WUS_FLX_FILTERS_6  E1000_WUFC_FLX_FILTERS_6
-#define E1000_WUS_FLX_FILTERS_PHY_6  E1000_WUFC_FLX_FILTERS_PHY_6
-
-/* Wake Up Packet Length */
-#define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
-
-/* Four Flexible Filters are supported */
-#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
-/* Six Flexible Filters are supported */
-#define E1000_FLEXIBLE_FILTER_COUNT_MAX_6   6
-
-/* Each Flexible Filter is at most 128 (0x80) bytes in length */
-#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
-
-#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
-#define E1000_FFLT_SIZE_6 E1000_FLEXIBLE_FILTER_COUNT_MAX_6
-#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
-#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
-
-/* Extended Device Control */
-#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */
-#define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
-#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
-#define E1000_CTRL_EXT_GPI2_EN   0x00000004 /* Maps SDP6 to GPI2 */
-#define E1000_CTRL_EXT_GPI3_EN   0x00000008 /* Maps SDP7 to GPI3 */
-/* Reserved (bits 4,5) in >= 82575 */
-#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Definable Pin 4 */
-#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */
-#define E1000_CTRL_EXT_PHY_INT   E1000_CTRL_EXT_SDP5_DATA
-#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */
-#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */
-/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */
-#define E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
-#define E1000_CTRL_EXT_SDP5_DIR  0x00000200 /* Direction of SDP5 0=in 1=out */
-#define E1000_CTRL_EXT_SDP6_DIR  0x00000400 /* Direction of SDP6 0=in 1=out */
-#define E1000_CTRL_EXT_SDP3_DIR  0x00000800 /* Direction of SDP3 0=in 1=out */
-#define E1000_CTRL_EXT_ASDCHK    0x00001000 /* Initiate an ASD sequence */
-#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
-#define E1000_CTRL_EXT_IPS       0x00004000 /* Invert Power State */
-#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
-#define E1000_CTRL_EXT_RO_DIS    0x00020000 /* Relaxed Ordering disable */
-#define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 /* DMA Dynamic Clock Gating */
-#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
-#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
-#define E1000_CTRL_EXT_LINK_MODE_TBI  0x00C00000
-#define E1000_CTRL_EXT_LINK_MODE_KMRN    0x00000000
-#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
-#define E1000_CTRL_EXT_LINK_MODE_PCIX_SERDES  0x00800000
-#define E1000_CTRL_EXT_LINK_MODE_SGMII   0x00800000
-#define E1000_CTRL_EXT_EIAME          0x01000000
-#define E1000_CTRL_EXT_IRCA           0x00000001
-#define E1000_CTRL_EXT_WR_WMARK_MASK  0x03000000
-#define E1000_CTRL_EXT_WR_WMARK_256   0x00000000
-#define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
-#define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
-#define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
-#define E1000_CTRL_EXT_CANC           0x04000000 /* Int delay cancellation */
-#define E1000_CTRL_EXT_DRV_LOAD       0x10000000 /* Driver loaded bit for FW */
-/* IAME enable bit (27) was removed in >= 82575 */
-#define E1000_CTRL_EXT_IAME          0x08000000 /* Int acknowledge Auto-mask */
-#define E1000_CRTL_EXT_PB_PAREN       0x01000000 /* packet buffer parity error
-                                                  * detection enabled */
-#define E1000_CTRL_EXT_DF_PAREN       0x02000000 /* descriptor FIFO parity
-                                                  * error detection enable */
-#define E1000_CTRL_EXT_GHOST_PAREN    0x40000000
-#define E1000_CTRL_EXT_PBA_CLR        0x80000000 /* PBA Clear */
-#define E1000_CTRL_EXT_LSECCK         0x00001000
-#define E1000_CTRL_EXT_PHYPDEN        0x00100000
-#define E1000_I2CCMD_REG_ADDR_SHIFT   16
-#define E1000_I2CCMD_REG_ADDR         0x00FF0000
-#define E1000_I2CCMD_PHY_ADDR_SHIFT   24
-#define E1000_I2CCMD_PHY_ADDR         0x07000000
-#define E1000_I2CCMD_OPCODE_READ      0x08000000
-#define E1000_I2CCMD_OPCODE_WRITE     0x00000000
-#define E1000_I2CCMD_RESET            0x10000000
-#define E1000_I2CCMD_READY            0x20000000
-#define E1000_I2CCMD_INTERRUPT_ENA    0x40000000
-#define E1000_I2CCMD_ERROR            0x80000000
-#define E1000_MAX_SGMII_PHY_REG_ADDR  255
-#define E1000_I2CCMD_PHY_TIMEOUT      200
-
-/* Receive Descriptor bit definitions */
-#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
-#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
-#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
-#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
-#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum calculated */
-#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
-#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
-#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
-#define E1000_RXD_STAT_CRCV     0x100   /* Speculative CRC Valid */
-#define E1000_RXD_STAT_IPIDV    0x200   /* IP identification valid */
-#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
-#define E1000_RXD_STAT_DYNINT   0x800   /* Pkt caused INT via DYNINT */
-#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
-#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
-#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
-#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
-#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
-#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
-#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
-#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
-#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
-#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
-#define E1000_RXD_SPC_PRI_SHIFT 13
-#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
-#define E1000_RXD_SPC_CFI_SHIFT 12
-
-#define E1000_RXDEXT_STATERR_CE    0x01000000
-#define E1000_RXDEXT_STATERR_SE    0x02000000
-#define E1000_RXDEXT_STATERR_SEQ   0x04000000
-#define E1000_RXDEXT_STATERR_CXE   0x10000000
-#define E1000_RXDEXT_STATERR_TCPE  0x20000000
-#define E1000_RXDEXT_STATERR_IPE   0x40000000
-#define E1000_RXDEXT_STATERR_RXE   0x80000000
-
-#define E1000_RXDEXT_LSECH                0x01000000
-#define E1000_RXDEXT_LSECE_MASK           0x60000000
-#define E1000_RXDEXT_LSECE_NO_ERROR       0x00000000
-#define E1000_RXDEXT_LSECE_NO_SA_MATCH    0x20000000
-#define E1000_RXDEXT_LSECE_REPLAY_DETECT  0x40000000
-#define E1000_RXDEXT_LSECE_BAD_SIG        0x60000000
-
-/* mask to determine if packets should be dropped due to frame errors */
-#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
-    E1000_RXD_ERR_CE  |                \
-    E1000_RXD_ERR_SE  |                \
-    E1000_RXD_ERR_SEQ |                \
-    E1000_RXD_ERR_CXE |                \
-    E1000_RXD_ERR_RXE)
-
-/* Same mask, but for extended and packet split descriptors */
-#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
-    E1000_RXDEXT_STATERR_CE  |            \
-    E1000_RXDEXT_STATERR_SE  |            \
-    E1000_RXDEXT_STATERR_SEQ |            \
-    E1000_RXDEXT_STATERR_CXE |            \
-    E1000_RXDEXT_STATERR_RXE)
-
-#define E1000_MRQC_ENABLE_MASK                 0x00000007
-#define E1000_MRQC_ENABLE_RSS_2Q               0x00000001
-#define E1000_MRQC_ENABLE_RSS_INT              0x00000004
-#define E1000_MRQC_RSS_FIELD_MASK              0xFFFF0000
-#define E1000_MRQC_RSS_FIELD_IPV4_TCP          0x00010000
-#define E1000_MRQC_RSS_FIELD_IPV4              0x00020000
-#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX       0x00040000
-#define E1000_MRQC_RSS_FIELD_IPV6_EX           0x00080000
-#define E1000_MRQC_RSS_FIELD_IPV6              0x00100000
-#define E1000_MRQC_RSS_FIELD_IPV6_TCP          0x00200000
-
-#define E1000_RXDPS_HDRSTAT_HDRSP              0x00008000
-#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK        0x000003FF
-
-/* Management Control */
-#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
-#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
-#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
-#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
-#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
-#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
-#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
-#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
-#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
-/* Enable Neighbor Discovery Filtering */
-#define E1000_MANC_NEIGHBOR_EN   0x00004000
-#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response Filtering */
-#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
-#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
-#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
-#define E1000_MANC_RCV_ALL       0x00080000 /* Receive All Enabled */
-#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
-/* Enable MAC address filtering */
-#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000
-/* Enable MNG packets to host memory */
-#define E1000_MANC_EN_MNG2HOST   0x00200000
-/* Enable IP address filtering */
-#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000
-#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
-#define E1000_MANC_BR_EN            0x01000000 /* Enable broadcast filtering */
-#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
-#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
-#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
-#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
-#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
-#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
-
-#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
-#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
-
-/* Receive Control */
-#define E1000_RCTL_RST            0x00000001    /* Software reset */
-#define E1000_RCTL_EN             0x00000002    /* enable */
-#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
-#define E1000_RCTL_UPE            0x00000008    /* unicast promisc enable */
-#define E1000_RCTL_MPE            0x00000010    /* multicast promisc enable */
-#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
-#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
-#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
-#define E1000_RCTL_LBM_SLP        0x00000080    /* serial link loopback mode */
-#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
-#define E1000_RCTL_DTYP_MASK      0x00000C00    /* Descriptor type mask */
-#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
-#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min thresh size */
-#define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min thresh size */
-#define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min thresh size */
-#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
-#define E1000_RCTL_MO_0           0x00000000    /* multicast offset 11:0 */
-#define E1000_RCTL_MO_1           0x00001000    /* multicast offset 12:1 */
-#define E1000_RCTL_MO_2           0x00002000    /* multicast offset 13:2 */
-#define E1000_RCTL_MO_3           0x00003000    /* multicast offset 15:4 */
-#define E1000_RCTL_MDR            0x00004000    /* multicast desc ring 0 */
-#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
-#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
-#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
-#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
-#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
-#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
-#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
-#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
-#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
-#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
-#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
-#define E1000_RCTL_DPF            0x00400000    /* discard pause frames */
-#define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
-#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
-#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
-#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
-#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
-
-/*
- * Use byte values for the following shift parameters
- * Usage:
- *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
- *                  E1000_PSRCTL_BSIZE0_MASK) |
- *                ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
- *                  E1000_PSRCTL_BSIZE1_MASK) |
- *                ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
- *                  E1000_PSRCTL_BSIZE2_MASK) |
- *                ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
- *                  E1000_PSRCTL_BSIZE3_MASK))
- * where value0 = [128..16256],  default=256
- *       value1 = [1024..64512], default=4096
- *       value2 = [0..64512],    default=4096
- *       value3 = [0..64512],    default=0
- */
-
-#define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
-#define E1000_PSRCTL_BSIZE1_MASK   0x00003F00
-#define E1000_PSRCTL_BSIZE2_MASK   0x003F0000
-#define E1000_PSRCTL_BSIZE3_MASK   0x3F000000
-
-#define E1000_PSRCTL_BSIZE0_SHIFT  7            /* Shift _right_ 7 */
-#define E1000_PSRCTL_BSIZE1_SHIFT  2            /* Shift _right_ 2 */
-#define E1000_PSRCTL_BSIZE2_SHIFT  6            /* Shift _left_ 6 */
-#define E1000_PSRCTL_BSIZE3_SHIFT 14            /* Shift _left_ 14 */
-
-/* SWFW_SYNC Definitions */
-#define E1000_SWFW_EEP_SM   0x01
-#define E1000_SWFW_PHY0_SM  0x02
-#define E1000_SWFW_PHY1_SM  0x04
-#define E1000_SWFW_CSR_SM   0x08
-
-/* FACTPS Definitions */
-#define E1000_FACTPS_LFS    0x40000000  /* LAN Function Select */
-/* Device Control */
-#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
-#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
-#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
-#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master reqs */
-#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
-#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
-#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
-#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
-#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
-#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
-#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
-#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
-#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
-#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
-#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
-#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
-#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
-#define E1000_CTRL_D_UD_EN  0x00002000  /* Dock/Undock enable */
-#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock
-                                             * indication in SDP[0] */
-#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through
-                                               * PHYRST_N pin */
-#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external
-                                           * LINK_0 and LINK_1 pins */
-#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
-#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
-#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
-#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
-#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
-#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
-#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
-#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
-#define E1000_CTRL_RST      0x04000000  /* Global reset */
-#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
-#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
-#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
-#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
-#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
-#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to ME */
-#define E1000_CTRL_I2C_ENA  0x02000000  /* I2C enable */
-
-/*
- * Bit definitions for the Management Data IO (MDIO) and Management Data
- * Clock (MDC) pins in the Device Control Register.
- */
-#define E1000_CTRL_PHY_RESET_DIR  E1000_CTRL_SWDPIO0
-#define E1000_CTRL_PHY_RESET      E1000_CTRL_SWDPIN0
-#define E1000_CTRL_MDIO_DIR       E1000_CTRL_SWDPIO2
-#define E1000_CTRL_MDIO           E1000_CTRL_SWDPIN2
-#define E1000_CTRL_MDC_DIR        E1000_CTRL_SWDPIO3
-#define E1000_CTRL_MDC            E1000_CTRL_SWDPIN3
-#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
-#define E1000_CTRL_PHY_RESET4     E1000_CTRL_EXT_SDP4_DATA
-
-#define E1000_CONNSW_ENRGSRC             0x4
-#define E1000_PCS_CFG_PCS_EN             8
-#define E1000_PCS_LCTL_FLV_LINK_UP       1
-#define E1000_PCS_LCTL_FSV_10            0
-#define E1000_PCS_LCTL_FSV_100           2
-#define E1000_PCS_LCTL_FSV_1000          4
-#define E1000_PCS_LCTL_FDV_FULL          8
-#define E1000_PCS_LCTL_FSD               0x10
-#define E1000_PCS_LCTL_FORCE_LINK        0x20
-#define E1000_PCS_LCTL_LOW_LINK_LATCH    0x40
-#define E1000_PCS_LCTL_FORCE_FCTRL       0x80
-#define E1000_PCS_LCTL_AN_ENABLE         0x10000
-#define E1000_PCS_LCTL_AN_RESTART        0x20000
-#define E1000_PCS_LCTL_AN_TIMEOUT        0x40000
-#define E1000_PCS_LCTL_AN_SGMII_BYPASS   0x80000
-#define E1000_PCS_LCTL_AN_SGMII_TRIGGER  0x100000
-#define E1000_PCS_LCTL_FAST_LINK_TIMER   0x1000000
-#define E1000_PCS_LCTL_LINK_OK_FIX       0x2000000
-#define E1000_PCS_LCTL_CRS_ON_NI         0x4000000
-#define E1000_ENABLE_SERDES_LOOPBACK     0x0410
-
-#define E1000_PCS_LSTS_LINK_OK           1
-#define E1000_PCS_LSTS_SPEED_10          0
-#define E1000_PCS_LSTS_SPEED_100         2
-#define E1000_PCS_LSTS_SPEED_1000        4
-#define E1000_PCS_LSTS_DUPLEX_FULL       8
-#define E1000_PCS_LSTS_SYNK_OK           0x10
-#define E1000_PCS_LSTS_AN_COMPLETE       0x10000
-#define E1000_PCS_LSTS_AN_PAGE_RX        0x20000
-#define E1000_PCS_LSTS_AN_TIMED_OUT      0x40000
-#define E1000_PCS_LSTS_AN_REMOTE_FAULT   0x80000
-#define E1000_PCS_LSTS_AN_ERROR_RWS      0x100000
-
-/* Device Status */
-#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
-#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
-#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
-#define E1000_STATUS_FUNC_SHIFT 2
-#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
-#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
-#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
-#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
-#define E1000_STATUS_SPEED_MASK 0x000000C0
-#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
-#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
-#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
-#define E1000_STATUS_LAN_INIT_DONE 0x00000200  /* Lan Init Completion by NVM */
-#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
-#define E1000_STATUS_PHYRA      0x00000400      /* PHY Reset Asserted */
-#define E1000_STATUS_DOCK_CI    0x00000800      /* Change in Dock/Undock state.
-                                                 * Clear on write '0'. */
-#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Master request status */
-#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
-#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
-#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
-#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
-#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
-#define E1000_STATUS_BMC_SKU_0  0x00100000 /* BMC USB redirect disabled */
-#define E1000_STATUS_BMC_SKU_1  0x00200000 /* BMC SRAM disabled */
-#define E1000_STATUS_BMC_SKU_2  0x00400000 /* BMC SDRAM disabled */
-#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
-#define E1000_STATUS_BMC_LITE   0x01000000 /* BMC external code execution
-                                            * disabled */
-#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */
-#define E1000_STATUS_FUSE_8       0x04000000
-#define E1000_STATUS_FUSE_9       0x08000000
-#define E1000_STATUS_SERDES0_DIS  0x10000000 /* SERDES disabled on port 0 */
-#define E1000_STATUS_SERDES1_DIS  0x20000000 /* SERDES disabled on port 1 */
-
-/* Constants used to interpret the masked PCI-X bus speed. */
-#define E1000_STATUS_PCIX_SPEED_66  0x00000000 /* PCI-X bus speed 50-66 MHz */
-#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */
-#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /*PCI-X bus speed 100-133 MHz*/
-
-#define SPEED_10    10
-#define SPEED_100   100
-#define SPEED_1000  1000
-#define HALF_DUPLEX 1
-#define FULL_DUPLEX 2
-
-#define PHY_FORCE_TIME   20
-
-#define ADVERTISE_10_HALF                 0x0001
-#define ADVERTISE_10_FULL                 0x0002
-#define ADVERTISE_100_HALF                0x0004
-#define ADVERTISE_100_FULL                0x0008
-#define ADVERTISE_1000_HALF               0x0010 /* Not used, just FYI */
-#define ADVERTISE_1000_FULL               0x0020
-
-/* 1000/H is not supported, nor spec-compliant. */
-#define E1000_ALL_SPEED_DUPLEX  (ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
-                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL | \
-                                                     ADVERTISE_1000_FULL)
-#define E1000_ALL_NOT_GIG       (ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
-                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
-#define E1000_ALL_100_SPEED    (ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
-#define E1000_ALL_10_SPEED      (ADVERTISE_10_HALF |   ADVERTISE_10_FULL)
-#define E1000_ALL_FULL_DUPLEX   (ADVERTISE_10_FULL |  ADVERTISE_100_FULL | \
-                                                     ADVERTISE_1000_FULL)
-#define E1000_ALL_HALF_DUPLEX   (ADVERTISE_10_HALF |  ADVERTISE_100_HALF)
-
-#define AUTONEG_ADVERTISE_SPEED_DEFAULT   E1000_ALL_SPEED_DUPLEX
-
-/* LED Control */
-#define E1000_PHY_LED0_MODE_MASK          0x00000007
-#define E1000_PHY_LED0_IVRT               0x00000008
-#define E1000_PHY_LED0_BLINK              0x00000010
-#define E1000_PHY_LED0_MASK               0x0000001F
-
-#define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
-#define E1000_LEDCTL_LED0_MODE_SHIFT      0
-#define E1000_LEDCTL_LED0_BLINK_RATE      0x00000020
-#define E1000_LEDCTL_LED0_IVRT            0x00000040
-#define E1000_LEDCTL_LED0_BLINK           0x00000080
-#define E1000_LEDCTL_LED1_MODE_MASK       0x00000F00
-#define E1000_LEDCTL_LED1_MODE_SHIFT      8
-#define E1000_LEDCTL_LED1_BLINK_RATE      0x00002000
-#define E1000_LEDCTL_LED1_IVRT            0x00004000
-#define E1000_LEDCTL_LED1_BLINK           0x00008000
-#define E1000_LEDCTL_LED2_MODE_MASK       0x000F0000
-#define E1000_LEDCTL_LED2_MODE_SHIFT      16
-#define E1000_LEDCTL_LED2_BLINK_RATE      0x00200000
-#define E1000_LEDCTL_LED2_IVRT            0x00400000
-#define E1000_LEDCTL_LED2_BLINK           0x00800000
-#define E1000_LEDCTL_LED3_MODE_MASK       0x0F000000
-#define E1000_LEDCTL_LED3_MODE_SHIFT      24
-#define E1000_LEDCTL_LED3_BLINK_RATE      0x20000000
-#define E1000_LEDCTL_LED3_IVRT            0x40000000
-#define E1000_LEDCTL_LED3_BLINK           0x80000000
-
-#define E1000_LEDCTL_MODE_LINK_10_1000  0x0
-#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
-#define E1000_LEDCTL_MODE_LINK_UP       0x2
-#define E1000_LEDCTL_MODE_ACTIVITY      0x3
-#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
-#define E1000_LEDCTL_MODE_LINK_10       0x5
-#define E1000_LEDCTL_MODE_LINK_100      0x6
-#define E1000_LEDCTL_MODE_LINK_1000     0x7
-#define E1000_LEDCTL_MODE_PCIX_MODE     0x8
-#define E1000_LEDCTL_MODE_FULL_DUPLEX   0x9
-#define E1000_LEDCTL_MODE_COLLISION     0xA
-#define E1000_LEDCTL_MODE_BUS_SPEED     0xB
-#define E1000_LEDCTL_MODE_BUS_SIZE      0xC
-#define E1000_LEDCTL_MODE_PAUSED        0xD
-#define E1000_LEDCTL_MODE_LED_ON        0xE
-#define E1000_LEDCTL_MODE_LED_OFF       0xF
-
-/* Transmit Descriptor bit definitions */
-#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
-#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
-#define E1000_TXD_POPTS_SHIFT 8         /* POPTS shift */
-#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
-#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
-#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
-#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
-#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
-#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
-#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
-#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
-#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
-#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
-#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
-#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
-#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
-#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
-#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
-#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
-#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
-#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
-/* Extended desc bits for Linksec and timesync */
-#define E1000_TXD_CMD_LINKSEC     0x10000000 /* Apply LinkSec on packet */
-#define E1000_TXD_EXTCMD_TSTAMP   0x00000010 /* IEEE1588 Timestamp packet */
-
-/* Transmit Control */
-#define E1000_TCTL_RST    0x00000001    /* software reset */
-#define E1000_TCTL_EN     0x00000002    /* enable tx */
-#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
-#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
-#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
-#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
-#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
-#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
-#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
-#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
-#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
-
-/* Transmit Arbitration Count */
-#define E1000_TARC0_ENABLE     0x00000400   /* Enable Tx Queue 0 */
-
-/* SerDes Control */
-#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
-
-/* Receive Checksum Control */
-#define E1000_RXCSUM_PCSS_MASK 0x000000FF   /* Packet Checksum Start */
-#define E1000_RXCSUM_IPOFL     0x00000100   /* IPv4 checksum offload */
-#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
-#define E1000_RXCSUM_IPV6OFL   0x00000400   /* IPv6 checksum offload */
-#define E1000_RXCSUM_CRCOFL    0x00000800   /* CRC32 offload enable */
-#define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
-#define E1000_RXCSUM_PCSD      0x00002000   /* packet checksum disabled */
-
-/* Header split receive */
-#define E1000_RFCTL_ISCSI_DIS           0x00000001
-#define E1000_RFCTL_ISCSI_DWC_MASK      0x0000003E
-#define E1000_RFCTL_ISCSI_DWC_SHIFT     1
-#define E1000_RFCTL_NFSW_DIS            0x00000040
-#define E1000_RFCTL_NFSR_DIS            0x00000080
-#define E1000_RFCTL_NFS_VER_MASK        0x00000300
-#define E1000_RFCTL_NFS_VER_SHIFT       8
-#define E1000_RFCTL_IPV6_DIS            0x00000400
-#define E1000_RFCTL_IPV6_XSUM_DIS       0x00000800
-#define E1000_RFCTL_ACK_DIS             0x00001000
-#define E1000_RFCTL_ACKD_DIS            0x00002000
-#define E1000_RFCTL_IPFRSP_DIS          0x00004000
-#define E1000_RFCTL_EXTEN               0x00008000
-#define E1000_RFCTL_IPV6_EX_DIS         0x00010000
-#define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
-#define E1000_RFCTL_LEF                 0x00040000
-
-/* Collision related configuration parameters */
-#define E1000_COLLISION_THRESHOLD       15
-#define E1000_CT_SHIFT                  4
-#define E1000_COLLISION_DISTANCE        63
-#define E1000_COLD_SHIFT                12
-
-/* Default values for the transmit IPG register */
-#define DEFAULT_82543_TIPG_IPGT_FIBER  9
-#define DEFAULT_82543_TIPG_IPGT_COPPER 8
-
-#define E1000_TIPG_IPGT_MASK  0x000003FF
-#define E1000_TIPG_IPGR1_MASK 0x000FFC00
-#define E1000_TIPG_IPGR2_MASK 0x3FF00000
-
-#define DEFAULT_82543_TIPG_IPGR1 8
-#define E1000_TIPG_IPGR1_SHIFT  10
-
-#define DEFAULT_82543_TIPG_IPGR2 6
-#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
-#define E1000_TIPG_IPGR2_SHIFT  20
-
-/* Ethertype field values */
-#define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
-
-#define ETHERNET_FCS_SIZE       4
-#define MAX_JUMBO_FRAME_SIZE    0x3F00
-
-/* Extended Configuration Control and Size */
-#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP      0x00000020
-#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE       0x00000001
-#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE       0x00000008
-#define E1000_EXTCNF_CTRL_SWFLAG                 0x00000020
-#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK   0x00FF0000
-#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT          16
-#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK   0x0FFF0000
-#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT          16
-
-#define E1000_PHY_CTRL_SPD_EN             0x00000001
-#define E1000_PHY_CTRL_D0A_LPLU           0x00000002
-#define E1000_PHY_CTRL_NOND0A_LPLU        0x00000004
-#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
-#define E1000_PHY_CTRL_GBE_DISABLE        0x00000040
-
-#define E1000_KABGTXD_BGSQLBIAS           0x00050000
-
-/* PBA constants */
-#define E1000_PBA_6K  0x0006    /* 6KB */
-#define E1000_PBA_8K  0x0008    /* 8KB */
-#define E1000_PBA_10K 0x000A    /* 10KB */
-#define E1000_PBA_12K 0x000C    /* 12KB */
-#define E1000_PBA_14K 0x000E    /* 14KB */
-#define E1000_PBA_16K 0x0010    /* 16KB */
-#define E1000_PBA_18K 0x0012
-#define E1000_PBA_20K 0x0014
-#define E1000_PBA_22K 0x0016
-#define E1000_PBA_24K 0x0018
-#define E1000_PBA_26K 0x001A
-#define E1000_PBA_30K 0x001E
-#define E1000_PBA_32K 0x0020
-#define E1000_PBA_34K 0x0022
-#define E1000_PBA_35K 0x0023
-#define E1000_PBA_38K 0x0026
-#define E1000_PBA_40K 0x0028
-#define E1000_PBA_48K 0x0030    /* 48KB */
-#define E1000_PBA_64K 0x0040    /* 64KB */
-
-#define E1000_PBS_16K E1000_PBA_16K
-#define E1000_PBS_24K E1000_PBA_24K
-
-#define IFS_MAX       80
-#define IFS_MIN       40
-#define IFS_RATIO     4
-#define IFS_STEP      10
-#define MIN_NUM_XMITS 1000
-
-/* SW Semaphore Register */
-#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
-#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
-#define E1000_SWSM_WMNG         0x00000004 /* Wake MNG Clock */
-#define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
-
-#define E1000_SWSM2_LOCK        0x00000002 /* Secondary driver semaphore bit */
-
-/* Interrupt Cause Read */
-#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
-#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
-#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
-#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
-#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
-#define E1000_ICR_RXO           0x00000040 /* rx overrun */
-#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
-#define E1000_ICR_VMMB          0x00000100 /* VM MB event */
-#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
-#define E1000_ICR_RXCFG         0x00000400 /* Rx /c/ ordered set */
-#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
-#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
-#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
-#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
-#define E1000_ICR_TXD_LOW       0x00008000
-#define E1000_ICR_SRPD          0x00010000
-#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
-#define E1000_ICR_MNG           0x00040000 /* Manageability event */
-#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
-#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver
-                                            * should claim the interrupt */
-#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* Q0 Rx desc FIFO parity error */
-#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* Q0 Tx desc FIFO parity error */
-#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity err */
-#define E1000_ICR_PB_PAR        0x00800000 /* packet buffer parity error */
-#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* Q1 Rx desc FIFO parity error */
-#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* Q1 Tx desc FIFO parity error */
-#define E1000_ICR_ALL_PARITY    0x03F00000 /* all parity error bits */
-#define E1000_ICR_DSW           0x00000020 /* FW changed the status of DISSW
-                                            * bit in the FWSM */
-#define E1000_ICR_PHYINT        0x00001000 /* LAN connected device generates
-                                            * an interrupt */
-#define E1000_ICR_DOUTSYNC      0x10000000 /* NIC DMA out of sync */
-#define E1000_ICR_EPRST         0x00100000 /* ME hardware reset occurs */
-#define E1000_ICR_RXQ0          0x00100000 /* Rx Queue 0 Interrupt */
-#define E1000_ICR_RXQ1          0x00200000 /* Rx Queue 1 Interrupt */
-#define E1000_ICR_TXQ0          0x00400000 /* Tx Queue 0 Interrupt */
-#define E1000_ICR_TXQ1          0x00800000 /* Tx Queue 1 Interrupt */
-#define E1000_ICR_OTHER         0x01000000 /* Other Interrupts */
-
-/* PBA ECC Register */
-#define E1000_PBA_ECC_COUNTER_MASK  0xFFF00000 /* ECC counter mask */
-#define E1000_PBA_ECC_COUNTER_SHIFT 20         /* ECC counter shift value */
-#define E1000_PBA_ECC_CORR_EN      0x00000001 /* Enable ECC error correction */
-#define E1000_PBA_ECC_STAT_CLR      0x00000002 /* Clear ECC error counter */
-#define E1000_PBA_ECC_INT_EN     0x00000004 /* Enable ICR bit 5 on ECC error */
-
-/*
- * This defines the bits that are set in the Interrupt Mask
- * Set/Read Register.  Each bit is documented below:
- *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
- *   o RXSEQ  = Receive Sequence Error
- */
-#define POLL_IMS_ENABLE_MASK ( \
-    E1000_IMS_RXDMT0 |    \
-    E1000_IMS_RXSEQ)
-
-/*
- * This defines the bits that are set in the Interrupt Mask
- * Set/Read Register.  Each bit is documented below:
- *   o RXT0   = Receiver Timer Interrupt (ring 0)
- *   o TXDW   = Transmit Descriptor Written Back
- *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
- *   o RXSEQ  = Receive Sequence Error
- *   o LSC    = Link Status Change
- */
-#define IMS_ENABLE_MASK ( \
-    E1000_IMS_RXT0   |    \
-    E1000_IMS_TXDW   |    \
-    E1000_IMS_RXDMT0 |    \
-    E1000_IMS_RXSEQ  |    \
-    E1000_IMS_LSC)
-
-/* Interrupt Mask Set */
-#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Tx desc written back */
-#define E1000_IMS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
-#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
-#define E1000_IMS_VMMB      E1000_ICR_VMMB      /* Mail box activity */
-#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
-#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
-#define E1000_IMS_RXO       E1000_ICR_RXO       /* rx overrun */
-#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
-#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
-#define E1000_IMS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
-#define E1000_IMS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
-#define E1000_IMS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
-#define E1000_IMS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
-#define E1000_IMS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
-#define E1000_IMS_TXD_LOW   E1000_ICR_TXD_LOW
-#define E1000_IMS_SRPD      E1000_ICR_SRPD
-#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
-#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
-#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
-#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
-                                                         * parity error */
-#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
-                                                         * parity error */
-#define E1000_IMS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer
-                                                         * parity error */
-#define E1000_IMS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity
-                                                         * error */
-#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
-                                                         * parity error */
-#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
-                                                         * parity error */
-#define E1000_IMS_DSW       E1000_ICR_DSW
-#define E1000_IMS_PHYINT    E1000_ICR_PHYINT
-#define E1000_IMS_DOUTSYNC  E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
-#define E1000_IMS_EPRST     E1000_ICR_EPRST
-#define E1000_IMS_RXQ0          E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */
-#define E1000_IMS_RXQ1          E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */
-#define E1000_IMS_TXQ0          E1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */
-#define E1000_IMS_TXQ1          E1000_ICR_TXQ1 /* Tx Queue 1 Interrupt */
-#define E1000_IMS_OTHER         E1000_ICR_OTHER /* Other Interrupts */
-
-/* Interrupt Cause Set */
-#define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Tx desc written back */
-#define E1000_ICS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
-#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
-#define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
-#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
-#define E1000_ICS_RXO       E1000_ICR_RXO       /* rx overrun */
-#define E1000_ICS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
-#define E1000_ICS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
-#define E1000_ICS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
-#define E1000_ICS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
-#define E1000_ICS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
-#define E1000_ICS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
-#define E1000_ICS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
-#define E1000_ICS_TXD_LOW   E1000_ICR_TXD_LOW
-#define E1000_ICS_SRPD      E1000_ICR_SRPD
-#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
-#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
-#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
-#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
-                                                         * parity error */
-#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
-                                                         * parity error */
-#define E1000_ICS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer
-                                                         * parity error */
-#define E1000_ICS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity
-                                                         * error */
-#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
-                                                         * parity error */
-#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
-                                                         * parity error */
-#define E1000_ICS_DSW       E1000_ICR_DSW
-#define E1000_ICS_DOUTSYNC  E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
-#define E1000_ICS_PHYINT    E1000_ICR_PHYINT
-#define E1000_ICS_EPRST     E1000_ICR_EPRST
-
-/* Transmit Descriptor Control */
-#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
-#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */
-#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
-#define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
-#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
-#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
-#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */
-/* Enable the counting of descriptors still to be processed. */
-#define E1000_TXDCTL_COUNT_DESC 0x00400000
-
-/* Flow Control Constants */
-#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
-#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
-#define FLOW_CONTROL_TYPE         0x8808
-
-/* 802.1q VLAN Packet Size */
-#define VLAN_TAG_SIZE              4    /* 802.3ac tag (not DMA'd) */
-#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
-
-/* Receive Address */
-/*
- * Number of high/low register pairs in the RAR. The RAR (Receive Address
- * Registers) holds the directed and multicast addresses that we monitor.
- * Technically, we have 16 spots.  However, we reserve one of these spots
- * (RAR[15]) for our directed address used by controllers with
- * manageability enabled, allowing us room for 15 multicast addresses.
- */
-#define E1000_RAR_ENTRIES     15
-#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
-#define E1000_RAL_MAC_ADDR_LEN 4
-#define E1000_RAH_MAC_ADDR_LEN 2
-#define E1000_RAH_POOL_MASK 0x03FC0000
-#define E1000_RAH_POOL_1 0x00040000
-
-/* Error Codes */
-#define E1000_SUCCESS      0
-#define E1000_ERR_NVM      1
-#define E1000_ERR_PHY      2
-#define E1000_ERR_CONFIG   3
-#define E1000_ERR_PARAM    4
-#define E1000_ERR_MAC_INIT 5
-#define E1000_ERR_PHY_TYPE 6
-#define E1000_ERR_RESET   9
-#define E1000_ERR_MASTER_REQUESTS_PENDING 10
-#define E1000_ERR_HOST_INTERFACE_COMMAND 11
-#define E1000_BLK_PHY_RESET   12
-#define E1000_ERR_SWFW_SYNC 13
-#define E1000_NOT_IMPLEMENTED 14
-#define E1000_ERR_MBX      15
-
-/* Loop limit on how long we wait for auto-negotiation to complete */
-#define FIBER_LINK_UP_LIMIT               50
-#define COPPER_LINK_UP_LIMIT              10
-#define PHY_AUTO_NEG_LIMIT                45
-#define PHY_FORCE_LIMIT                   20
-/* Number of 100 microseconds we wait for PCI Express master disable */
-#define MASTER_DISABLE_TIMEOUT      800
-/* Number of milliseconds we wait for PHY configuration done after MAC reset */
-#define PHY_CFG_TIMEOUT             100
-/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
-#define MDIO_OWNERSHIP_TIMEOUT      10
-/* Number of milliseconds for NVM auto read done after MAC reset. */
-#define AUTO_READ_DONE_TIMEOUT      10
-
-/* Flow Control */
-#define E1000_FCRTH_RTH  0x0000FFF8     /* Mask Bits[15:3] for RTH */
-#define E1000_FCRTH_XFCE 0x80000000     /* External Flow Control Enable */
-#define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
-#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
-
-/* Transmit Configuration Word */
-#define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
-#define E1000_TXCW_HD         0x00000040        /* TXCW half duplex */
-#define E1000_TXCW_PAUSE      0x00000080        /* TXCW sym pause request */
-#define E1000_TXCW_ASM_DIR    0x00000100        /* TXCW astm pause direction */
-#define E1000_TXCW_PAUSE_MASK 0x00000180        /* TXCW pause request mask */
-#define E1000_TXCW_RF         0x00003000        /* TXCW remote fault */
-#define E1000_TXCW_NP         0x00008000        /* TXCW next page */
-#define E1000_TXCW_CW         0x0000ffff        /* TxConfigWord mask */
-#define E1000_TXCW_TXC        0x40000000        /* Transmit Config control */
-#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
-
-/* Receive Configuration Word */
-#define E1000_RXCW_CW         0x0000ffff        /* RxConfigWord mask */
-#define E1000_RXCW_NC         0x04000000        /* Receive config no carrier */
-#define E1000_RXCW_IV         0x08000000        /* Receive config invalid */
-#define E1000_RXCW_CC         0x10000000        /* Receive config change */
-#define E1000_RXCW_C          0x20000000        /* Receive config */
-#define E1000_RXCW_SYNCH      0x40000000        /* Receive config synch */
-#define E1000_RXCW_ANC        0x80000000        /* Auto-neg complete */
-
-
-/* PCI Express Control */
-#define E1000_GCR_RXD_NO_SNOOP          0x00000001
-#define E1000_GCR_RXDSCW_NO_SNOOP       0x00000002
-#define E1000_GCR_RXDSCR_NO_SNOOP       0x00000004
-#define E1000_GCR_TXD_NO_SNOOP          0x00000008
-#define E1000_GCR_TXDSCW_NO_SNOOP       0x00000010
-#define E1000_GCR_TXDSCR_NO_SNOOP       0x00000020
-#define E1000_GCR_CMPL_TMOUT_MASK       0x0000F000
-#define E1000_GCR_CMPL_TMOUT_10ms       0x00001000
-#define E1000_GCR_CMPL_TMOUT_RESEND     0x00010000
-#define E1000_GCR_CAP_VER2              0x00040000
-
-#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP         | \
-                           E1000_GCR_RXDSCW_NO_SNOOP      | \
-                           E1000_GCR_RXDSCR_NO_SNOOP      | \
-                           E1000_GCR_TXD_NO_SNOOP         | \
-                           E1000_GCR_TXDSCW_NO_SNOOP      | \
-                           E1000_GCR_TXDSCR_NO_SNOOP)
-
-/* PHY Control Register */
-#define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
-#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
-#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
-#define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */
-#define MII_CR_POWER_DOWN       0x0800  /* Power down */
-#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
-#define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
-#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
-#define MII_CR_SPEED_1000       0x0040
-#define MII_CR_SPEED_100        0x2000
-#define MII_CR_SPEED_10         0x0000
-
-/* PHY Status Register */
-#define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */
-#define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */
-#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
-#define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */
-#define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */
-#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
-#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
-#define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */
-#define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */
-#define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */
-#define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */
-#define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */
-#define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */
-#define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */
-#define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */
-
-/* Autoneg Advertisement Register */
-#define NWAY_AR_SELECTOR_FIELD   0x0001   /* indicates IEEE 802.3 CSMA/CD */
-#define NWAY_AR_10T_HD_CAPS      0x0020   /* 10T   Half Duplex Capable */
-#define NWAY_AR_10T_FD_CAPS      0x0040   /* 10T   Full Duplex Capable */
-#define NWAY_AR_100TX_HD_CAPS    0x0080   /* 100TX Half Duplex Capable */
-#define NWAY_AR_100TX_FD_CAPS    0x0100   /* 100TX Full Duplex Capable */
-#define NWAY_AR_100T4_CAPS       0x0200   /* 100T4 Capable */
-#define NWAY_AR_PAUSE            0x0400   /* Pause operation desired */
-#define NWAY_AR_ASM_DIR          0x0800   /* Asymmetric Pause Direction bit */
-#define NWAY_AR_REMOTE_FAULT     0x2000   /* Remote Fault detected */
-#define NWAY_AR_NEXT_PAGE        0x8000   /* Next Page ability supported */
-
-/* Link Partner Ability Register (Base Page) */
-#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
-#define NWAY_LPAR_10T_HD_CAPS    0x0020 /* LP is 10T   Half Duplex Capable */
-#define NWAY_LPAR_10T_FD_CAPS    0x0040 /* LP is 10T   Full Duplex Capable */
-#define NWAY_LPAR_100TX_HD_CAPS  0x0080 /* LP is 100TX Half Duplex Capable */
-#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP is 100TX Full Duplex Capable */
-#define NWAY_LPAR_100T4_CAPS     0x0200 /* LP is 100T4 Capable */
-#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
-#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
-#define NWAY_LPAR_REMOTE_FAULT   0x2000 /* LP has detected Remote Fault */
-#define NWAY_LPAR_ACKNOWLEDGE    0x4000 /* LP has rx'd link code word */
-#define NWAY_LPAR_NEXT_PAGE      0x8000 /* Next Page ability supported */
-
-/* Autoneg Expansion Register */
-#define NWAY_ER_LP_NWAY_CAPS      0x0001 /* LP has Auto Neg Capability */
-#define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */
-#define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */
-#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
-#define NWAY_ER_PAR_DETECT_FAULT  0x0010 /* LP is 100TX Full Duplex Capable */
-
-/* 1000BASE-T Control Register */
-#define CR_1000T_ASYM_PAUSE      0x0080 /* Advertise asymmetric pause bit */
-#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
-#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
-#define CR_1000T_REPEATER_DTE    0x0400 /* 1=Repeater/switch device port */
-                                        /* 0=DTE device */
-#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
-                                        /* 0=Configure PHY as Slave */
-#define CR_1000T_MS_ENABLE      0x1000 /* 1=Master/Slave manual config value */
-                                        /* 0=Automatic Master/Slave config */
-#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
-#define CR_1000T_TEST_MODE_1     0x2000 /* Transmit Waveform test */
-#define CR_1000T_TEST_MODE_2     0x4000 /* Master Transmit Jitter test */
-#define CR_1000T_TEST_MODE_3     0x6000 /* Slave Transmit Jitter test */
-#define CR_1000T_TEST_MODE_4     0x8000 /* Transmitter Distortion test */
-
-/* 1000BASE-T Status Register */
-#define SR_1000T_IDLE_ERROR_CNT   0x00FF /* Num idle errors since last read */
-#define SR_1000T_ASYM_PAUSE_DIR  0x0100 /* LP asymmetric pause direction bit */
-#define SR_1000T_LP_HD_CAPS       0x0400 /* LP is 1000T HD capable */
-#define SR_1000T_LP_FD_CAPS       0x0800 /* LP is 1000T FD capable */
-#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
-#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
-#define SR_1000T_MS_CONFIG_RES    0x4000 /* 1=Local Tx is Master, 0=Slave */
-#define SR_1000T_MS_CONFIG_FAULT  0x8000 /* Master/Slave config fault */
-
-#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5
-
-/* PHY 1000 MII Register/Bit Definitions */
-/* PHY Registers defined by IEEE */
-#define PHY_CONTROL      0x00 /* Control Register */
-#define PHY_STATUS       0x01 /* Status Register */
-#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
-#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
-#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
-#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
-#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
-#define PHY_NEXT_PAGE_TX 0x07 /* Next Page Tx */
-#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
-#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
-#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
-#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
-
-#define PHY_CONTROL_LB   0x4000 /* PHY Loopback bit */
-
-/* NVM Control */
-#define E1000_EECD_SK        0x00000001 /* NVM Clock */
-#define E1000_EECD_CS        0x00000002 /* NVM Chip Select */
-#define E1000_EECD_DI        0x00000004 /* NVM Data In */
-#define E1000_EECD_DO        0x00000008 /* NVM Data Out */
-#define E1000_EECD_FWE_MASK  0x00000030
-#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
-#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
-#define E1000_EECD_FWE_SHIFT 4
-#define E1000_EECD_REQ       0x00000040 /* NVM Access Request */
-#define E1000_EECD_GNT       0x00000080 /* NVM Access Grant */
-#define E1000_EECD_PRES      0x00000100 /* NVM Present */
-#define E1000_EECD_SIZE      0x00000200 /* NVM Size (0=64 word 1=256 word) */
-/* NVM Addressing bits based on type 0=small, 1=large */
-#define E1000_EECD_ADDR_BITS 0x00000400
-#define E1000_EECD_TYPE      0x00002000 /* NVM Type (1-SPI, 0-Microwire) */
-#define E1000_NVM_GRANT_ATTEMPTS   1000 /* NVM # attempts to gain grant */
-#define E1000_EECD_AUTO_RD          0x00000200  /* NVM Auto Read done */
-#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* NVM Size */
-#define E1000_EECD_SIZE_EX_SHIFT     11
-#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
-#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
-#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
-#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
-#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
-#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
-#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
-#define E1000_EECD_SECVAL_SHIFT      22
-#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES)
-
-#define E1000_NVM_SWDPIN0   0x0001   /* SWDPIN 0 NVM Value */
-#define E1000_NVM_LED_LOGIC 0x0020   /* Led Logic Word */
-#define E1000_NVM_RW_REG_DATA   16  /* Offset to data in NVM read/write regs */
-#define E1000_NVM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
-#define E1000_NVM_RW_REG_START  1    /* Start operation */
-#define E1000_NVM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
-#define E1000_NVM_POLL_WRITE    1    /* Flag for polling for write complete */
-#define E1000_NVM_POLL_READ     0    /* Flag for polling for read complete */
-#define E1000_FLASH_UPDATES  2000
-
-/* NVM Word Offsets */
-#define NVM_COMPAT                 0x0003
-#define NVM_ID_LED_SETTINGS        0x0004
-#define NVM_VERSION                0x0005
-#define NVM_SERDES_AMPLITUDE       0x0006 /* SERDES output amplitude */
-#define NVM_PHY_CLASS_WORD         0x0007
-#define NVM_INIT_CONTROL1_REG      0x000A
-#define NVM_INIT_CONTROL2_REG      0x000F
-#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010
-#define NVM_INIT_CONTROL3_PORT_B   0x0014
-#define NVM_INIT_3GIO_3            0x001A
-#define NVM_SWDEF_PINS_CTRL_PORT_0 0x0020
-#define NVM_INIT_CONTROL3_PORT_A   0x0024
-#define NVM_CFG                    0x0012
-#define NVM_FLASH_VERSION          0x0032
-#define NVM_ALT_MAC_ADDR_PTR       0x0037
-#define NVM_CHECKSUM_REG           0x003F
-
-#define E1000_NVM_CFG_DONE_PORT_0  0x040000 /* MNG config cycle done */
-#define E1000_NVM_CFG_DONE_PORT_1  0x080000 /* ...for second port */
-
-/* Mask bits for fields in Word 0x0f of the NVM */
-#define NVM_WORD0F_PAUSE_MASK       0x3000
-#define NVM_WORD0F_PAUSE            0x1000
-#define NVM_WORD0F_ASM_DIR          0x2000
-#define NVM_WORD0F_ANE              0x0800
-#define NVM_WORD0F_SWPDIO_EXT_MASK  0x00F0
-#define NVM_WORD0F_LPLU             0x0001
-
-/* Mask bits for fields in Word 0x1a of the NVM */
-#define NVM_WORD1A_ASPM_MASK  0x000C
-
-/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
-#define NVM_SUM                    0xBABA
-
-#define NVM_MAC_ADDR_OFFSET        0
-#define NVM_PBA_OFFSET_0           8
-#define NVM_PBA_OFFSET_1           9
-#define NVM_RESERVED_WORD          0xFFFF
-#define NVM_PHY_CLASS_A            0x8000
-#define NVM_SERDES_AMPLITUDE_MASK  0x000F
-#define NVM_SIZE_MASK              0x1C00
-#define NVM_SIZE_SHIFT             10
-#define NVM_WORD_SIZE_BASE_SHIFT   6
-#define NVM_SWDPIO_EXT_SHIFT       4
-
-/* NVM Commands - SPI */
-#define NVM_MAX_RETRY_SPI          5000 /* Max wait of 5ms, for RDY signal */
-#define NVM_READ_OPCODE_SPI        0x03 /* NVM read opcode */
-#define NVM_WRITE_OPCODE_SPI       0x02 /* NVM write opcode */
-#define NVM_A8_OPCODE_SPI          0x08 /* opcode bit-3 = address bit-8 */
-#define NVM_WREN_OPCODE_SPI        0x06 /* NVM set Write Enable latch */
-#define NVM_WRDI_OPCODE_SPI        0x04 /* NVM reset Write Enable latch */
-#define NVM_RDSR_OPCODE_SPI        0x05 /* NVM read Status register */
-#define NVM_WRSR_OPCODE_SPI        0x01 /* NVM write Status register */
-
-/* SPI NVM Status Register */
-#define NVM_STATUS_RDY_SPI         0x01
-#define NVM_STATUS_WEN_SPI         0x02
-#define NVM_STATUS_BP0_SPI         0x04
-#define NVM_STATUS_BP1_SPI         0x08
-#define NVM_STATUS_WPEN_SPI        0x80
-
-/* Word definitions for ID LED Settings */
-#define ID_LED_RESERVED_0000 0x0000
-#define ID_LED_RESERVED_FFFF 0xFFFF
-#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2  << 12) | \
-                              (ID_LED_OFF1_OFF2 <<  8) | \
-                              (ID_LED_DEF1_DEF2 <<  4) | \
-                              (ID_LED_DEF1_DEF2))
-#define ID_LED_DEF1_DEF2     0x1
-#define ID_LED_DEF1_ON2      0x2
-#define ID_LED_DEF1_OFF2     0x3
-#define ID_LED_ON1_DEF2      0x4
-#define ID_LED_ON1_ON2       0x5
-#define ID_LED_ON1_OFF2      0x6
-#define ID_LED_OFF1_DEF2     0x7
-#define ID_LED_OFF1_ON2      0x8
-#define ID_LED_OFF1_OFF2     0x9
-
-#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
-#define IGP_ACTIVITY_LED_ENABLE 0x0300
-#define IGP_LED3_MODE           0x07000000
-
-/* PCI/PCI-X/PCI-EX Config space */
-#define PCI_HEADER_TYPE_REGISTER     0x0E
-#define PCIE_LINK_STATUS             0x12
-#define PCIE_DEVICE_CONTROL2         0x28
-
-#define PCI_HEADER_TYPE_MULTIFUNC    0x80
-#define PCIE_LINK_WIDTH_MASK         0x3F0
-#define PCIE_LINK_WIDTH_SHIFT        4
-#define PCIE_DEVICE_CONTROL2_16ms    0x0005
-
-#ifndef ETH_ADDR_LEN
-#define ETH_ADDR_LEN                 6
-#endif
-
-#define PHY_REVISION_MASK      0xFFFFFFF0
-#define MAX_PHY_REG_ADDRESS    0x1F  /* 5 bit address bus (0-0x1F) */
-#define MAX_PHY_MULTI_PAGE_REG 0xF
-
-/* Bit definitions for valid PHY IDs. */
-/*
- * I = Integrated
- * E = External
- */
-#define M88E1000_E_PHY_ID    0x01410C50
-#define M88E1000_I_PHY_ID    0x01410C30
-#define M88E1011_I_PHY_ID    0x01410C20
-#define IGP01E1000_I_PHY_ID  0x02A80380
-#define M88E1011_I_REV_4     0x04
-#define M88E1111_I_PHY_ID    0x01410CC0
-#define GG82563_E_PHY_ID     0x01410CA0
-#define IGP03E1000_E_PHY_ID  0x02A80390
-#define IFE_E_PHY_ID         0x02A80330
-#define IFE_PLUS_E_PHY_ID    0x02A80320
-#define IFE_C_E_PHY_ID       0x02A80310
-#define BME1000_E_PHY_ID     0x01410CB0
-#define BME1000_E_PHY_ID_R2  0x01410CB1
-#define I82577_E_PHY_ID 0x01540050
-#define I82578_E_PHY_ID 0x004DD040
-#define M88_VENDOR           0x0141
-
-/* M88E1000 Specific Registers */
-#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
-#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
-#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
-#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
-#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
-#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
-
-#define M88E1000_PHY_EXT_CTRL      0x1A  /* PHY extend control register */
-#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
-#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
-#define M88E1000_PHY_VCO_REG_BIT8  0x100 /* Bits 8 & 11 are adjusted for */
-#define M88E1000_PHY_VCO_REG_BIT11 0x800    /* improved BER performance */
-
-/* M88E1000 PHY Specific Control Register */
-#define M88E1000_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
-#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reverse enabled */
-#define M88E1000_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
-/* 1=CLK125 low, 0=CLK125 toggling */
-#define M88E1000_PSCR_CLK125_DISABLE    0x0010
-#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000 /* MDI Crossover Mode bits 6:5 */
-                                               /* Manual MDI configuration */
-#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
-/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
-#define M88E1000_PSCR_AUTO_X_1000T     0x0040
-/* Auto crossover enabled all speeds */
-#define M88E1000_PSCR_AUTO_X_MODE      0x0060
-/*
- * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold
- * 0=Normal 10BASE-T Rx Threshold
- */
-#define M88E1000_PSCR_EN_10BT_EXT_DIST 0x0080
-/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
-#define M88E1000_PSCR_MII_5BIT_ENABLE      0x0100
-#define M88E1000_PSCR_SCRAMBLER_DISABLE    0x0200 /* 1=Scrambler disable */
-#define M88E1000_PSCR_FORCE_LINK_GOOD      0x0400 /* 1=Force link good */
-#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Tx */
-
-/* M88E1000 PHY Specific Status Register */
-#define M88E1000_PSSR_JABBER             0x0001 /* 1=Jabber */
-#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
-#define M88E1000_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
-#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
-/*
- * 0 = <50M
- * 1 = 50-80M
- * 2 = 80-110M
- * 3 = 110-140M
- * 4 = >140M
- */
-#define M88E1000_PSSR_CABLE_LENGTH       0x0380
-#define M88E1000_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
-#define M88E1000_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
-#define M88E1000_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
-#define M88E1000_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
-#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
-#define M88E1000_PSSR_10MBS              0x0000 /* 00=10Mbs */
-#define M88E1000_PSSR_100MBS             0x4000 /* 01=100Mbs */
-#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
-
-#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
-
-/* M88E1000 Extended PHY Specific Control Register */
-#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
-/*
- * 1 = Lost lock detect enabled.
- * Will assert lost lock and bring
- * link down if idle not seen
- * within 1ms in 1000BASE-T
- */
-#define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000
-/*
- * Number of times we will attempt to autonegotiate before downshifting if we
- * are the master
- */
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X   0x0400
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X   0x0800
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X   0x0C00
-/*
- * Number of times we will attempt to autonegotiate before downshifting if we
- * are the slave
- */
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS   0x0000
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X    0x0200
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X    0x0300
-#define M88E1000_EPSCR_TX_CLK_2_5     0x0060 /* 2.5 MHz TX_CLK */
-#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
-#define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
-
-/* M88EC018 Rev 2 specific DownShift settings */
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK  0x0E00
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X    0x0000
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X    0x0200
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X    0x0400
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X    0x0600
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X    0x0800
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X    0x0A00
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X    0x0C00
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X    0x0E00
-
-#define I82578_EPSCR_DOWNSHIFT_ENABLE          0x0020
-#define I82578_EPSCR_DOWNSHIFT_COUNTER_MASK    0x001C
-
-/* BME1000 PHY Specific Control Register */
-#define BME1000_PSCR_ENABLE_DOWNSHIFT   0x0800 /* 1 = enable downshift */
-
-/*
- * Bits...
- * 15-5: page
- * 4-0: register offset
- */
-#define GG82563_PAGE_SHIFT        5
-#define GG82563_REG(page, reg)    \
-        (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
-#define GG82563_MIN_ALT_REG       30
-
-/* GG82563 Specific Registers */
-#define GG82563_PHY_SPEC_CTRL           \
-        GG82563_REG(0, 16) /* PHY Specific Control */
-#define GG82563_PHY_SPEC_STATUS         \
-        GG82563_REG(0, 17) /* PHY Specific Status */
-#define GG82563_PHY_INT_ENABLE          \
-        GG82563_REG(0, 18) /* Interrupt Enable */
-#define GG82563_PHY_SPEC_STATUS_2       \
-        GG82563_REG(0, 19) /* PHY Specific Status 2 */
-#define GG82563_PHY_RX_ERR_CNTR         \
-        GG82563_REG(0, 21) /* Receive Error Counter */
-#define GG82563_PHY_PAGE_SELECT         \
-        GG82563_REG(0, 22) /* Page Select */
-#define GG82563_PHY_SPEC_CTRL_2         \
-        GG82563_REG(0, 26) /* PHY Specific Control 2 */
-#define GG82563_PHY_PAGE_SELECT_ALT     \
-        GG82563_REG(0, 29) /* Alternate Page Select */
-#define GG82563_PHY_TEST_CLK_CTRL       \
-        GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */
-
-#define GG82563_PHY_MAC_SPEC_CTRL       \
-        GG82563_REG(2, 21) /* MAC Specific Control Register */
-#define GG82563_PHY_MAC_SPEC_CTRL_2     \
-        GG82563_REG(2, 26) /* MAC Specific Control 2 */
-
-#define GG82563_PHY_DSP_DISTANCE    \
-        GG82563_REG(5, 26) /* DSP Distance */
-
-/* Page 193 - Port Control Registers */
-#define GG82563_PHY_KMRN_MODE_CTRL   \
-        GG82563_REG(193, 16) /* Kumeran Mode Control */
-#define GG82563_PHY_PORT_RESET          \
-        GG82563_REG(193, 17) /* Port Reset */
-#define GG82563_PHY_REVISION_ID         \
-        GG82563_REG(193, 18) /* Revision ID */
-#define GG82563_PHY_DEVICE_ID           \
-        GG82563_REG(193, 19) /* Device ID */
-#define GG82563_PHY_PWR_MGMT_CTRL       \
-        GG82563_REG(193, 20) /* Power Management Control */
-#define GG82563_PHY_RATE_ADAPT_CTRL     \
-        GG82563_REG(193, 25) /* Rate Adaptation Control */
-
-/* Page 194 - KMRN Registers */
-#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \
-        GG82563_REG(194, 16) /* FIFO's Control/Status */
-#define GG82563_PHY_KMRN_CTRL           \
-        GG82563_REG(194, 17) /* Control */
-#define GG82563_PHY_INBAND_CTRL         \
-        GG82563_REG(194, 18) /* Inband Control */
-#define GG82563_PHY_KMRN_DIAGNOSTIC     \
-        GG82563_REG(194, 19) /* Diagnostic */
-#define GG82563_PHY_ACK_TIMEOUTS        \
-        GG82563_REG(194, 20) /* Acknowledge Timeouts */
-#define GG82563_PHY_ADV_ABILITY         \
-        GG82563_REG(194, 21) /* Advertised Ability */
-#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \
-        GG82563_REG(194, 23) /* Link Partner Advertised Ability */
-#define GG82563_PHY_ADV_NEXT_PAGE       \
-        GG82563_REG(194, 24) /* Advertised Next Page */
-#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \
-        GG82563_REG(194, 25) /* Link Partner Advertised Next page */
-#define GG82563_PHY_KMRN_MISC           \
-        GG82563_REG(194, 26) /* Misc. */
-
-/* MDI Control */
-#define E1000_MDIC_DATA_MASK 0x0000FFFF
-#define E1000_MDIC_REG_MASK  0x001F0000
-#define E1000_MDIC_REG_SHIFT 16
-#define E1000_MDIC_PHY_MASK  0x03E00000
-#define E1000_MDIC_PHY_SHIFT 21
-#define E1000_MDIC_OP_WRITE  0x04000000
-#define E1000_MDIC_OP_READ   0x08000000
-#define E1000_MDIC_READY     0x10000000
-#define E1000_MDIC_INT_EN    0x20000000
-#define E1000_MDIC_ERROR     0x40000000
-
-/* SerDes Control */
-#define E1000_GEN_CTL_READY             0x80000000
-#define E1000_GEN_CTL_ADDRESS_SHIFT     8
-#define E1000_GEN_POLL_TIMEOUT          640
-
-
-
-#endif /* _E1000E_DEFINES_H_ */
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_hw.h b/roms/ipxe/src/drivers/net/e1000e/e1000e_hw.h
deleted file mode 100644
index 03ed35c92761808ac2f6c785b5cc293bc29ebf82..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_hw.h
+++ /dev/null
@@ -1,719 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000E_HW_H_
-#define _E1000E_HW_H_
-
-#include "e1000e_regs.h"
-#include "e1000e_defines.h"
-
-struct e1000_hw;
-
-#define E1000_DEV_ID_82571EB_COPPER           0x105E
-#define E1000_DEV_ID_82571EB_FIBER            0x105F
-#define E1000_DEV_ID_82571EB_SERDES           0x1060
-#define E1000_DEV_ID_82571EB_SERDES_DUAL      0x10D9
-#define E1000_DEV_ID_82571EB_SERDES_QUAD      0x10DA
-#define E1000_DEV_ID_82571EB_QUAD_COPPER      0x10A4
-#define E1000_DEV_ID_82571PT_QUAD_COPPER      0x10D5
-#define E1000_DEV_ID_82571EB_QUAD_FIBER       0x10A5
-#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP   0x10BC
-#define E1000_DEV_ID_82572EI_COPPER           0x107D
-#define E1000_DEV_ID_82572EI_FIBER            0x107E
-#define E1000_DEV_ID_82572EI_SERDES           0x107F
-#define E1000_DEV_ID_82572EI                  0x10B9
-#define E1000_DEV_ID_82573E                   0x108B
-#define E1000_DEV_ID_82573E_IAMT              0x108C
-#define E1000_DEV_ID_82573L                   0x109A
-#define E1000_DEV_ID_82574L                   0x10D3
-#define E1000_DEV_ID_82574LA                  0x10F6
-#define E1000_DEV_ID_82583V                   0x150C
-#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT   0x1096
-#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT   0x1098
-#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT   0x10BA
-#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT   0x10BB
-#define E1000_DEV_ID_ICH8_82567V_3            0x1501
-#define E1000_DEV_ID_ICH8_IGP_M_AMT           0x1049
-#define E1000_DEV_ID_ICH8_IGP_AMT             0x104A
-#define E1000_DEV_ID_ICH8_IGP_C               0x104B
-#define E1000_DEV_ID_ICH8_IFE                 0x104C
-#define E1000_DEV_ID_ICH8_IFE_GT              0x10C4
-#define E1000_DEV_ID_ICH8_IFE_G               0x10C5
-#define E1000_DEV_ID_ICH8_IGP_M               0x104D
-#define E1000_DEV_ID_ICH9_IGP_M               0x10BF
-#define E1000_DEV_ID_ICH9_IGP_M_AMT           0x10F5
-#define E1000_DEV_ID_ICH9_IGP_M_V             0x10CB
-#define E1000_DEV_ID_ICH9_IGP_AMT             0x10BD
-#define E1000_DEV_ID_ICH9_BM                  0x10E5
-#define E1000_DEV_ID_ICH9_IGP_C               0x294C
-#define E1000_DEV_ID_ICH9_IFE                 0x10C0
-#define E1000_DEV_ID_ICH9_IFE_GT              0x10C3
-#define E1000_DEV_ID_ICH9_IFE_G               0x10C2
-#define E1000_DEV_ID_ICH10_R_BM_LM            0x10CC
-#define E1000_DEV_ID_ICH10_R_BM_LF            0x10CD
-#define E1000_DEV_ID_ICH10_R_BM_V             0x10CE
-#define E1000_DEV_ID_ICH10_D_BM_LM            0x10DE
-#define E1000_DEV_ID_ICH10_D_BM_LF            0x10DF
-#define E1000_DEV_ID_PCH_M_HV_LM              0x10EA
-#define E1000_DEV_ID_PCH_M_HV_LC              0x10EB
-#define E1000_DEV_ID_PCH_D_HV_DM              0x10EF
-#define E1000_DEV_ID_PCH_D_HV_DC              0x10F0
-#define E1000_REVISION_0 0
-#define E1000_REVISION_1 1
-#define E1000_REVISION_2 2
-#define E1000_REVISION_3 3
-#define E1000_REVISION_4 4
-
-#define E1000_FUNC_0     0
-#define E1000_FUNC_1     1
-
-#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0   0
-#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1   3
-
-enum e1000_mac_type {
-	e1000_undefined = 0,
-	e1000_82571,
-	e1000_82572,
-	e1000_82573,
-	e1000_82574,
-	e1000_82583,
-	e1000_80003es2lan,
-	e1000_ich8lan,
-	e1000_ich9lan,
-	e1000_ich10lan,
-	e1000_pchlan,
-	e1000_num_macs  /* List is 1-based, so subtract 1 for true count. */
-};
-
-enum e1000_media_type {
-	e1000_media_type_unknown = 0,
-	e1000_media_type_copper = 1,
-	e1000_media_type_fiber = 2,
-	e1000_media_type_internal_serdes = 3,
-	e1000_num_media_types
-};
-
-enum e1000_nvm_type {
-	e1000_nvm_unknown = 0,
-	e1000_nvm_none,
-	e1000_nvm_eeprom_spi,
-	e1000_nvm_flash_hw,
-	e1000_nvm_flash_sw
-};
-
-enum e1000_nvm_override {
-	e1000_nvm_override_none = 0,
-	e1000_nvm_override_spi_small,
-	e1000_nvm_override_spi_large,
-};
-
-enum e1000_phy_type {
-	e1000_phy_unknown = 0,
-	e1000_phy_none,
-	e1000_phy_m88,
-	e1000_phy_igp,
-	e1000_phy_igp_2,
-	e1000_phy_gg82563,
-	e1000_phy_igp_3,
-	e1000_phy_ife,
-	e1000_phy_bm,
-	e1000_phy_82578,
-	e1000_phy_82577,
-};
-
-enum e1000_bus_type {
-	e1000_bus_type_unknown = 0,
-	e1000_bus_type_pci,
-	e1000_bus_type_pcix,
-	e1000_bus_type_pci_express,
-	e1000_bus_type_reserved
-};
-
-enum e1000_bus_speed {
-	e1000_bus_speed_unknown = 0,
-	e1000_bus_speed_33,
-	e1000_bus_speed_66,
-	e1000_bus_speed_100,
-	e1000_bus_speed_120,
-	e1000_bus_speed_133,
-	e1000_bus_speed_2500,
-	e1000_bus_speed_5000,
-	e1000_bus_speed_reserved
-};
-
-enum e1000_bus_width {
-	e1000_bus_width_unknown = 0,
-	e1000_bus_width_pcie_x1,
-	e1000_bus_width_pcie_x2,
-	e1000_bus_width_pcie_x4 = 4,
-	e1000_bus_width_pcie_x8 = 8,
-	e1000_bus_width_32,
-	e1000_bus_width_64,
-	e1000_bus_width_reserved
-};
-
-enum e1000_1000t_rx_status {
-	e1000_1000t_rx_status_not_ok = 0,
-	e1000_1000t_rx_status_ok,
-	e1000_1000t_rx_status_undefined = 0xFF
-};
-
-enum e1000_rev_polarity {
-	e1000_rev_polarity_normal = 0,
-	e1000_rev_polarity_reversed,
-	e1000_rev_polarity_undefined = 0xFF
-};
-
-enum e1000_fc_mode {
-	e1000_fc_none = 0,
-	e1000_fc_rx_pause,
-	e1000_fc_tx_pause,
-	e1000_fc_full,
-	e1000_fc_default = 0xFF
-};
-
-enum e1000_ms_type {
-	e1000_ms_hw_default = 0,
-	e1000_ms_force_master,
-	e1000_ms_force_slave,
-	e1000_ms_auto
-};
-
-enum e1000_smart_speed {
-	e1000_smart_speed_default = 0,
-	e1000_smart_speed_on,
-	e1000_smart_speed_off
-};
-
-enum e1000_serdes_link_state {
-	e1000_serdes_link_down = 0,
-	e1000_serdes_link_autoneg_progress,
-	e1000_serdes_link_autoneg_complete,
-	e1000_serdes_link_forced_up
-};
-
-/* Receive Descriptor */
-struct e1000_rx_desc {
-	__le64 buffer_addr; /* Address of the descriptor's data buffer */
-	__le16 length;      /* Length of data DMAed into data buffer */
-	__le16 csum;        /* Packet checksum */
-	u8  status;         /* Descriptor status */
-	u8  errors;         /* Descriptor Errors */
-	__le16 special;
-};
-
-/* Receive Descriptor - Extended */
-union e1000_rx_desc_extended {
-	struct {
-		__le64 buffer_addr;
-		__le64 reserved;
-	} read;
-	struct {
-		struct {
-			__le32 mrq;           /* Multiple Rx Queues */
-			union {
-				__le32 rss;         /* RSS Hash */
-				struct {
-					__le16 ip_id;  /* IP id */
-					__le16 csum;   /* Packet Checksum */
-				} csum_ip;
-			} hi_dword;
-		} lower;
-		struct {
-			__le32 status_error;  /* ext status/error */
-			__le16 length;
-			__le16 vlan;          /* VLAN tag */
-		} upper;
-	} wb;  /* writeback */
-};
-
-#define MAX_PS_BUFFERS 4
-/* Receive Descriptor - Packet Split */
-union e1000_rx_desc_packet_split {
-	struct {
-		/* one buffer for protocol header(s), three data buffers */
-		__le64 buffer_addr[MAX_PS_BUFFERS];
-	} read;
-	struct {
-		struct {
-			__le32 mrq;           /* Multiple Rx Queues */
-			union {
-				__le32 rss;           /* RSS Hash */
-				struct {
-					__le16 ip_id;    /* IP id */
-					__le16 csum;     /* Packet Checksum */
-				} csum_ip;
-			} hi_dword;
-		} lower;
-		struct {
-			__le32 status_error;  /* ext status/error */
-			__le16 length0;       /* length of buffer 0 */
-			__le16 vlan;          /* VLAN tag */
-		} middle;
-		struct {
-			__le16 header_status;
-			__le16 length[3];     /* length of buffers 1-3 */
-		} upper;
-		__le64 reserved;
-	} wb; /* writeback */
-};
-
-/* Transmit Descriptor */
-struct e1000_tx_desc {
-	__le64 buffer_addr;   /* Address of the descriptor's data buffer */
-	union {
-		__le32 data;
-		struct {
-			__le16 length;    /* Data buffer length */
-			u8 cso;           /* Checksum offset */
-			u8 cmd;           /* Descriptor control */
-		} flags;
-	} lower;
-	union {
-		__le32 data;
-		struct {
-			u8 status;        /* Descriptor status */
-			u8 css;           /* Checksum start */
-			__le16 special;
-		} fields;
-	} upper;
-};
-
-/* Offload Context Descriptor */
-struct e1000_context_desc {
-	union {
-		__le32 ip_config;
-		struct {
-			u8 ipcss;         /* IP checksum start */
-			u8 ipcso;         /* IP checksum offset */
-			__le16 ipcse;     /* IP checksum end */
-		} ip_fields;
-	} lower_setup;
-	union {
-		__le32 tcp_config;
-		struct {
-			u8 tucss;         /* TCP checksum start */
-			u8 tucso;         /* TCP checksum offset */
-			__le16 tucse;     /* TCP checksum end */
-		} tcp_fields;
-	} upper_setup;
-	__le32 cmd_and_length;
-	union {
-		__le32 data;
-		struct {
-			u8 status;        /* Descriptor status */
-			u8 hdr_len;       /* Header length */
-			__le16 mss;       /* Maximum segment size */
-		} fields;
-	} tcp_seg_setup;
-};
-
-/* Offload data descriptor */
-struct e1000_data_desc {
-	__le64 buffer_addr;   /* Address of the descriptor's buffer address */
-	union {
-		__le32 data;
-		struct {
-			__le16 length;    /* Data buffer length */
-			u8 typ_len_ext;
-			u8 cmd;
-		} flags;
-	} lower;
-	union {
-		__le32 data;
-		struct {
-			u8 status;        /* Descriptor status */
-			u8 popts;         /* Packet Options */
-			__le16 special;
-		} fields;
-	} upper;
-};
-
-/* Statistics counters collected by the MAC */
-struct e1000_hw_stats {
-	u64 crcerrs;
-	u64 algnerrc;
-	u64 symerrs;
-	u64 rxerrc;
-	u64 mpc;
-	u64 scc;
-	u64 ecol;
-	u64 mcc;
-	u64 latecol;
-	u64 colc;
-	u64 dc;
-	u64 tncrs;
-	u64 sec;
-	u64 cexterr;
-	u64 rlec;
-	u64 xonrxc;
-	u64 xontxc;
-	u64 xoffrxc;
-	u64 xofftxc;
-	u64 fcruc;
-	u64 prc64;
-	u64 prc127;
-	u64 prc255;
-	u64 prc511;
-	u64 prc1023;
-	u64 prc1522;
-	u64 gprc;
-	u64 bprc;
-	u64 mprc;
-	u64 gptc;
-	u64 gorc;
-	u64 gotc;
-	u64 rnbc;
-	u64 ruc;
-	u64 rfc;
-	u64 roc;
-	u64 rjc;
-	u64 mgprc;
-	u64 mgpdc;
-	u64 mgptc;
-	u64 tor;
-	u64 tot;
-	u64 tpr;
-	u64 tpt;
-	u64 ptc64;
-	u64 ptc127;
-	u64 ptc255;
-	u64 ptc511;
-	u64 ptc1023;
-	u64 ptc1522;
-	u64 mptc;
-	u64 bptc;
-	u64 tsctc;
-	u64 tsctfc;
-	u64 iac;
-	u64 icrxptc;
-	u64 icrxatc;
-	u64 ictxptc;
-	u64 ictxatc;
-	u64 ictxqec;
-	u64 ictxqmtc;
-	u64 icrxdmtc;
-	u64 icrxoc;
-	u64 doosync;
-};
-
-
-struct e1000_phy_stats {
-	u32 idle_errors;
-	u32 receive_errors;
-};
-
-struct e1000_host_mng_dhcp_cookie {
-	u32 signature;
-	u8  status;
-	u8  reserved0;
-	u16 vlan_id;
-	u32 reserved1;
-	u16 reserved2;
-	u8  reserved3;
-	u8  checksum;
-};
-
-/* Host Interface "Rev 1" */
-struct e1000_host_command_header {
-	u8 command_id;
-	u8 command_length;
-	u8 command_options;
-	u8 checksum;
-};
-
-#define E1000_HI_MAX_DATA_LENGTH     252
-struct e1000_host_command_info {
-	struct e1000_host_command_header command_header;
-	u8 command_data[E1000_HI_MAX_DATA_LENGTH];
-};
-
-/* Host Interface "Rev 2" */
-struct e1000_host_mng_command_header {
-	u8  command_id;
-	u8  checksum;
-	u16 reserved1;
-	u16 reserved2;
-	u16 command_length;
-};
-
-#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
-struct e1000_host_mng_command_info {
-	struct e1000_host_mng_command_header command_header;
-	u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
-};
-
-#include "e1000e_mac.h"
-#include "e1000e_phy.h"
-#include "e1000e_nvm.h"
-#include "e1000e_manage.h"
-
-struct e1000_mac_operations {
-	/* Function pointers for the MAC. */
-	s32  (*init_params)(struct e1000_hw *);
-	s32  (*id_led_init)(struct e1000_hw *);
-	s32  (*blink_led)(struct e1000_hw *);
-	s32  (*check_for_link)(struct e1000_hw *);
-	bool (*check_mng_mode)(struct e1000_hw *hw);
-	s32  (*cleanup_led)(struct e1000_hw *);
-	void (*clear_hw_cntrs)(struct e1000_hw *);
-	void (*clear_vfta)(struct e1000_hw *);
-	s32  (*get_bus_info)(struct e1000_hw *);
-	void (*set_lan_id)(struct e1000_hw *);
-	s32  (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
-	s32  (*led_on)(struct e1000_hw *);
-	s32  (*led_off)(struct e1000_hw *);
-	void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32);
-	s32  (*reset_hw)(struct e1000_hw *);
-	s32  (*init_hw)(struct e1000_hw *);
-	s32  (*setup_link)(struct e1000_hw *);
-	s32  (*setup_physical_interface)(struct e1000_hw *);
-	s32  (*setup_led)(struct e1000_hw *);
-	void (*write_vfta)(struct e1000_hw *, u32, u32);
-	void (*mta_set)(struct e1000_hw *, u32);
-	void (*config_collision_dist)(struct e1000_hw *);
-	void (*rar_set)(struct e1000_hw *, u8*, u32);
-	s32  (*read_mac_addr)(struct e1000_hw *);
-	s32  (*validate_mdi_setting)(struct e1000_hw *);
-	s32  (*mng_host_if_write)(struct e1000_hw *, u8*, u16, u16, u8*);
-	s32  (*mng_write_cmd_header)(struct e1000_hw *hw,
-                      struct e1000_host_mng_command_header*);
-	s32  (*mng_enable_host_if)(struct e1000_hw *);
-	s32  (*wait_autoneg)(struct e1000_hw *);
-};
-
-struct e1000_phy_operations {
-	s32  (*init_params)(struct e1000_hw *);
-	s32  (*acquire)(struct e1000_hw *);
-	s32  (*cfg_on_link_up)(struct e1000_hw *);
-	s32  (*check_polarity)(struct e1000_hw *);
-	s32  (*check_reset_block)(struct e1000_hw *);
-	s32  (*commit)(struct e1000_hw *);
-#if 0
-	s32  (*force_speed_duplex)(struct e1000_hw *);
-#endif
-	s32  (*get_cfg_done)(struct e1000_hw *hw);
-#if 0
-	s32  (*get_cable_length)(struct e1000_hw *);
-#endif
-	s32  (*get_info)(struct e1000_hw *);
-	s32  (*read_reg)(struct e1000_hw *, u32, u16 *);
-	s32  (*read_reg_locked)(struct e1000_hw *, u32, u16 *);
-	void (*release)(struct e1000_hw *);
-	s32  (*reset)(struct e1000_hw *);
-	s32  (*set_d0_lplu_state)(struct e1000_hw *, bool);
-	s32  (*set_d3_lplu_state)(struct e1000_hw *, bool);
-	s32  (*write_reg)(struct e1000_hw *, u32, u16);
-	s32  (*write_reg_locked)(struct e1000_hw *, u32, u16);
-	void (*power_up)(struct e1000_hw *);
-	void (*power_down)(struct e1000_hw *);
-};
-
-struct e1000_nvm_operations {
-	s32  (*init_params)(struct e1000_hw *);
-	s32  (*acquire)(struct e1000_hw *);
-	s32  (*read)(struct e1000_hw *, u16, u16, u16 *);
-	void (*release)(struct e1000_hw *);
-	void (*reload)(struct e1000_hw *);
-	s32  (*update)(struct e1000_hw *);
-	s32  (*valid_led_default)(struct e1000_hw *, u16 *);
-	s32  (*validate)(struct e1000_hw *);
-	s32  (*write)(struct e1000_hw *, u16, u16, u16 *);
-};
-
-struct e1000_mac_info {
-	struct e1000_mac_operations ops;
-	u8 addr[6];
-	u8 perm_addr[6];
-
-	enum e1000_mac_type type;
-
-	u32 collision_delta;
-	u32 ledctl_default;
-	u32 ledctl_mode1;
-	u32 ledctl_mode2;
-	u32 mc_filter_type;
-	u32 tx_packet_delta;
-	u32 txcw;
-
-	u16 current_ifs_val;
-	u16 ifs_max_val;
-	u16 ifs_min_val;
-	u16 ifs_ratio;
-	u16 ifs_step_size;
-	u16 mta_reg_count;
-
-	/* Maximum size of the MTA register table in all supported adapters */
-	#define MAX_MTA_REG 128
-	u32 mta_shadow[MAX_MTA_REG];
-	u16 rar_entry_count;
-
-	u8  forced_speed_duplex;
-
-	bool adaptive_ifs;
-	bool arc_subsystem_valid;
-	bool asf_firmware_present;
-	bool autoneg;
-	bool autoneg_failed;
-	bool get_link_status;
-	bool in_ifs_mode;
-	enum e1000_serdes_link_state serdes_link_state;
-	bool serdes_has_link;
-	bool tx_pkt_filtering;
-};
-
-struct e1000_phy_info {
-	struct e1000_phy_operations ops;
-	enum e1000_phy_type type;
-
-	enum e1000_1000t_rx_status local_rx;
-	enum e1000_1000t_rx_status remote_rx;
-	enum e1000_ms_type ms_type;
-	enum e1000_ms_type original_ms_type;
-	enum e1000_rev_polarity cable_polarity;
-	enum e1000_smart_speed smart_speed;
-
-	u32 addr;
-	u32 id;
-	u32 reset_delay_us; /* in usec */
-	u32 revision;
-
-	enum e1000_media_type media_type;
-
-	u16 autoneg_advertised;
-	u16 autoneg_mask;
-	u16 cable_length;
-	u16 max_cable_length;
-	u16 min_cable_length;
-
-	u8 mdix;
-
-	bool disable_polarity_correction;
-	bool is_mdix;
-	bool polarity_correction;
-	bool reset_disable;
-	bool speed_downgraded;
-	bool autoneg_wait_to_complete;
-};
-
-struct e1000_nvm_info {
-	struct e1000_nvm_operations ops;
-	enum e1000_nvm_type type;
-	enum e1000_nvm_override override;
-
-	u32 flash_bank_size;
-	u32 flash_base_addr;
-
-	u16 word_size;
-	u16 delay_usec;
-	u16 address_bits;
-	u16 opcode_bits;
-	u16 page_size;
-};
-
-struct e1000_bus_info {
-	enum e1000_bus_type type;
-	enum e1000_bus_speed speed;
-	enum e1000_bus_width width;
-
-	u16 func;
-	u16 pci_cmd_word;
-};
-
-struct e1000_fc_info {
-	u32 high_water;          /* Flow control high-water mark */
-	u32 low_water;           /* Flow control low-water mark */
-	u16 pause_time;          /* Flow control pause timer */
-	bool send_xon;           /* Flow control send XON */
-	bool strict_ieee;        /* Strict IEEE mode */
-	enum e1000_fc_mode current_mode; /* FC mode in effect */
-	enum e1000_fc_mode requested_mode; /* FC mode requested by caller */
-};
-
-struct e1000_dev_spec_82571 {
-	bool laa_is_present;
-	u32 smb_counter;
-};
-
-struct e1000_dev_spec_80003es2lan {
-	bool  mdic_wa_enable;
-};
-
-struct e1000_shadow_ram {
-	u16  value;
-	bool modified;
-};
-
-#define E1000_ICH8_SHADOW_RAM_WORDS		2048
-
-struct e1000_dev_spec_ich8lan {
-	bool kmrn_lock_loss_workaround_enabled;
-	struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS];
-	bool nvm_k1_enabled;
-};
-
-struct e1000_hw {
-	struct e1000_adapter *adapter;
-
-	u8 __iomem *hw_addr;
-	u8 __iomem *flash_address;
-
-	void *back;
-	unsigned long io_base;
-
-	struct e1000_mac_info  mac;
-	struct e1000_fc_info   fc;
-	struct e1000_phy_info  phy;
-	struct e1000_nvm_info  nvm;
-	struct e1000_bus_info  bus;
-	struct e1000_host_mng_dhcp_cookie mng_cookie;
-
-	union {
-		struct e1000_dev_spec_82571	_82571;
-		struct e1000_dev_spec_80003es2lan _80003es2lan;
-		struct e1000_dev_spec_ich8lan	ich8lan;
-	} dev_spec;
-
-	u16 device_id;
-	u16 subsystem_vendor_id;
-	u16 subsystem_device_id;
-	u16 vendor_id;
-
-	u8  revision_id;
-};
-
-#include "e1000e_82571.h"
-#include "e1000e_80003es2lan.h"
-#include "e1000e_ich8lan.h"
-
-/* These functions must be implemented by drivers */
-s32  e1000e_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_ich8lan.c b/roms/ipxe/src/drivers/net/e1000e/e1000e_ich8lan.c
deleted file mode 100644
index 7b9a49b98f1ed9585308730efbd67994efd19968..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_ich8lan.c
+++ /dev/null
@@ -1,3444 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/*
- * 82562G 10/100 Network Connection
- * 82562G-2 10/100 Network Connection
- * 82562GT 10/100 Network Connection
- * 82562GT-2 10/100 Network Connection
- * 82562V 10/100 Network Connection
- * 82562V-2 10/100 Network Connection
- * 82566DC-2 Gigabit Network Connection
- * 82566DC Gigabit Network Connection
- * 82566DM-2 Gigabit Network Connection
- * 82566DM Gigabit Network Connection
- * 82566MC Gigabit Network Connection
- * 82566MM Gigabit Network Connection
- * 82567LM Gigabit Network Connection
- * 82567LF Gigabit Network Connection
- * 82567V Gigabit Network Connection
- * 82567LM-2 Gigabit Network Connection
- * 82567LF-2 Gigabit Network Connection
- * 82567V-2 Gigabit Network Connection
- * 82567LF-3 Gigabit Network Connection
- * 82567LM-3 Gigabit Network Connection
- * 82567LM-4 Gigabit Network Connection
- * 82577LM Gigabit Network Connection
- * 82577LC Gigabit Network Connection
- * 82578DM Gigabit Network Connection
- * 82578DC Gigabit Network Connection
- */
-
-#include "e1000e.h"
-
-static s32  e1000e_init_phy_params_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_init_phy_params_pchlan(struct e1000_hw *hw);
-static s32  e1000e_init_nvm_params_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_init_mac_params_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_acquire_swflag_ich8lan(struct e1000_hw *hw);
-static void e1000e_release_swflag_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_acquire_nvm_ich8lan(struct e1000_hw *hw);
-static void e1000e_release_nvm_ich8lan(struct e1000_hw *hw);
-static bool e1000e_check_mng_mode_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_check_reset_block_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_phy_hw_reset_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_get_phy_info_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_set_lplu_state_pchlan(struct e1000_hw *hw, bool active);
-static s32  e1000e_set_d0_lplu_state_ich8lan(struct e1000_hw *hw,
-                                            bool active);
-static s32  e1000e_set_d3_lplu_state_ich8lan(struct e1000_hw *hw,
-                                            bool active);
-static s32  e1000e_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
-                                   u16 words, u16 *data);
-static s32  e1000e_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
-                                    u16 words, u16 *data);
-static s32  e1000e_validate_nvm_checksum_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_update_nvm_checksum_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_valid_led_default_ich8lan(struct e1000_hw *hw,
-                                            u16 *data);
-static s32  e1000e_id_led_init_pchlan(struct e1000_hw *hw);
-static s32  e1000e_get_bus_info_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_reset_hw_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_init_hw_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_setup_link_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_setup_copper_link_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_get_link_up_info_ich8lan(struct e1000_hw *hw,
-                                           u16 *speed, u16 *duplex);
-static s32  e1000e_cleanup_led_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_led_on_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_led_off_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
-static s32  e1000e_setup_led_pchlan(struct e1000_hw *hw);
-static s32  e1000e_cleanup_led_pchlan(struct e1000_hw *hw);
-static s32  e1000e_led_on_pchlan(struct e1000_hw *hw);
-static s32  e1000e_led_off_pchlan(struct e1000_hw *hw);
-static void e1000e_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
-static s32  e1000e_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout);
-static s32  e1000e_flash_cycle_init_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_get_phy_info_ife_ich8lan(struct e1000_hw *hw);
-static void e1000e_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_read_flash_byte_ich8lan(struct e1000_hw *hw,
-                                          u32 offset, u8 *data);
-static s32  e1000e_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
-                                          u8 size, u16 *data);
-static s32  e1000e_read_flash_word_ich8lan(struct e1000_hw *hw,
-                                          u32 offset, u16 *data);
-static s32  e1000e_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
-                                                 u32 offset, u8 byte);
-static s32  e1000e_write_flash_byte_ich8lan(struct e1000_hw *hw,
-                                           u32 offset, u8 data);
-static s32  e1000e_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
-                                           u8 size, u16 data);
-static s32  e1000e_get_cfg_done_ich8lan(struct e1000_hw *hw);
-static void e1000e_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_check_for_copper_link_ich8lan(struct e1000_hw *hw);
-static void e1000e_lan_init_done_ich8lan(struct e1000_hw *hw);
-static s32  e1000e_sw_lcd_config_ich8lan(struct e1000_hw *hw);
-
-/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
-/* Offset 04h HSFSTS */
-union ich8_hws_flash_status {
-	struct ich8_hsfsts {
-		u16 flcdone    :1; /* bit 0 Flash Cycle Done */
-		u16 flcerr     :1; /* bit 1 Flash Cycle Error */
-		u16 dael       :1; /* bit 2 Direct Access error Log */
-		u16 berasesz   :2; /* bit 4:3 Sector Erase Size */
-		u16 flcinprog  :1; /* bit 5 flash cycle in Progress */
-		u16 reserved1  :2; /* bit 13:6 Reserved */
-		u16 reserved2  :6; /* bit 13:6 Reserved */
-		u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */
-		u16 flockdn    :1; /* bit 15 Flash Config Lock-Down */
-	} hsf_status;
-	u16 regval;
-};
-
-/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
-/* Offset 06h FLCTL */
-union ich8_hws_flash_ctrl {
-	struct ich8_hsflctl {
-		u16 flcgo      :1;   /* 0 Flash Cycle Go */
-		u16 flcycle    :2;   /* 2:1 Flash Cycle */
-		u16 reserved   :5;   /* 7:3 Reserved  */
-		u16 fldbcount  :2;   /* 9:8 Flash Data Byte Count */
-		u16 flockdn    :6;   /* 15:10 Reserved */
-	} hsf_ctrl;
-	u16 regval;
-};
-
-/* ICH Flash Region Access Permissions */
-union ich8_hws_flash_regacc {
-	struct ich8_flracc {
-		u32 grra      :8; /* 0:7 GbE region Read Access */
-		u32 grwa      :8; /* 8:15 GbE region Write Access */
-		u32 gmrag     :8; /* 23:16 GbE Master Read Access Grant */
-		u32 gmwag     :8; /* 31:24 GbE Master Write Access Grant */
-	} hsf_flregacc;
-	u16 regval;
-};
-
-/**
- *  e1000e_init_phy_params_pchlan - Initialize PHY function pointers
- *  @hw: pointer to the HW structure
- *
- *  Initialize family-specific PHY parameters and function pointers.
- **/
-static s32 e1000e_init_phy_params_pchlan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-
-	phy->addr                     = 1;
-	phy->reset_delay_us           = 100;
-
-	phy->ops.acquire              = e1000e_acquire_swflag_ich8lan;
-	phy->ops.check_polarity       = e1000e_check_polarity_ife;
-	phy->ops.check_reset_block    = e1000e_check_reset_block_ich8lan;
-#if 0
-	phy->ops.force_speed_duplex   = e1000e_phy_force_speed_duplex_ife;
-#endif
-#if 0
-	phy->ops.get_cable_length     = e1000e_get_cable_length_igp_2;
-#endif
-	phy->ops.get_cfg_done         = e1000e_get_cfg_done_ich8lan;
-	phy->ops.get_info             = e1000e_get_phy_info_ich8lan;
-	phy->ops.read_reg             = e1000e_read_phy_reg_hv;
-	phy->ops.read_reg_locked      = e1000e_read_phy_reg_hv_locked;
-	phy->ops.release              = e1000e_release_swflag_ich8lan;
-	phy->ops.reset                = e1000e_phy_hw_reset_ich8lan;
-	phy->ops.set_d0_lplu_state    = e1000e_set_lplu_state_pchlan;
-	phy->ops.set_d3_lplu_state    = e1000e_set_lplu_state_pchlan;
-	phy->ops.write_reg            = e1000e_write_phy_reg_hv;
-	phy->ops.write_reg_locked     = e1000e_write_phy_reg_hv_locked;
-	phy->ops.power_up             = e1000e_power_up_phy_copper;
-	phy->ops.power_down           = e1000e_power_down_phy_copper_ich8lan;
-	phy->autoneg_mask             = AUTONEG_ADVERTISE_SPEED_DEFAULT;
-
-	phy->id = e1000_phy_unknown;
-	e1000e_get_phy_id(hw);
-	phy->type = e1000e_get_phy_type_from_id(phy->id);
-
-	if (phy->type == e1000_phy_82577) {
-		phy->ops.check_polarity = e1000e_check_polarity_82577;
-#if 0
-		phy->ops.force_speed_duplex =
-			e1000e_phy_force_speed_duplex_82577;
-#endif
-#if 0
-		phy->ops.get_cable_length   = e1000e_get_cable_length_82577;
-#endif
-		phy->ops.get_info = e1000e_get_phy_info_82577;
-		phy->ops.commit = e1000e_phy_sw_reset;
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000e_init_phy_params_ich8lan - Initialize PHY function pointers
- *  @hw: pointer to the HW structure
- *
- *  Initialize family-specific PHY parameters and function pointers.
- **/
-static s32 e1000e_init_phy_params_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 i = 0;
-
-	phy->addr                     = 1;
-	phy->reset_delay_us           = 100;
-
-	phy->ops.acquire              = e1000e_acquire_swflag_ich8lan;
-	phy->ops.check_polarity       = e1000e_check_polarity_ife;
-	phy->ops.check_reset_block    = e1000e_check_reset_block_ich8lan;
-#if 0
-	phy->ops.force_speed_duplex   = e1000e_phy_force_speed_duplex_ife;
-#endif
-#if 0
-	phy->ops.get_cable_length     = e1000e_get_cable_length_igp_2;
-#endif
-	phy->ops.get_cfg_done         = e1000e_get_cfg_done_ich8lan;
-	phy->ops.get_info             = e1000e_get_phy_info_ich8lan;
-	phy->ops.read_reg             = e1000e_read_phy_reg_igp;
-	phy->ops.release              = e1000e_release_swflag_ich8lan;
-	phy->ops.reset                = e1000e_phy_hw_reset_ich8lan;
-	phy->ops.set_d0_lplu_state    = e1000e_set_d0_lplu_state_ich8lan;
-	phy->ops.set_d3_lplu_state    = e1000e_set_d3_lplu_state_ich8lan;
-	phy->ops.write_reg            = e1000e_write_phy_reg_igp;
-	phy->ops.power_up             = e1000e_power_up_phy_copper;
-	phy->ops.power_down           = e1000e_power_down_phy_copper_ich8lan;
-
-	/*
-	 * We may need to do this twice - once for IGP and if that fails,
-	 * we'll set BM func pointers and try again
-	 */
-	ret_val = e1000e_determine_phy_address(hw);
-	if (ret_val) {
-		phy->ops.write_reg = e1000e_write_phy_reg_bm;
-		phy->ops.read_reg  = e1000e_read_phy_reg_bm;
-		ret_val = e1000e_determine_phy_address(hw);
-		if (ret_val) {
-			DBG("Cannot determine PHY addr. Erroring out\n");
-			goto out;
-		}
-	}
-
-	phy->id = 0;
-	while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) &&
-	       (i++ < 100)) {
-		msleep(1);
-		ret_val = e1000e_get_phy_id(hw);
-		if (ret_val)
-			goto out;
-	}
-
-	/* Verify phy id */
-	switch (phy->id) {
-	case IGP03E1000_E_PHY_ID:
-		phy->type = e1000_phy_igp_3;
-		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
-		phy->ops.read_reg_locked = e1000e_read_phy_reg_igp_locked;
-		phy->ops.write_reg_locked = e1000e_write_phy_reg_igp_locked;
-		break;
-	case IFE_E_PHY_ID:
-	case IFE_PLUS_E_PHY_ID:
-	case IFE_C_E_PHY_ID:
-		phy->type = e1000_phy_ife;
-		phy->autoneg_mask = E1000_ALL_NOT_GIG;
-		break;
-	case BME1000_E_PHY_ID:
-		phy->type = e1000_phy_bm;
-		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
-		phy->ops.read_reg = e1000e_read_phy_reg_bm;
-		phy->ops.write_reg = e1000e_write_phy_reg_bm;
-		phy->ops.commit = e1000e_phy_sw_reset;
-		break;
-	default:
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_init_nvm_params_ich8lan - Initialize NVM function pointers
- *  @hw: pointer to the HW structure
- *
- *  Initialize family-specific NVM parameters and function
- *  pointers.
- **/
-static s32 e1000e_init_nvm_params_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-	u32 gfpreg, sector_base_addr, sector_end_addr;
-	s32 ret_val = E1000_SUCCESS;
-	u16 i;
-
-	/* Can't read flash registers if the register set isn't mapped. */
-	if (!hw->flash_address) {
-		e_dbg("ERROR: Flash registers not mapped\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	nvm->type = e1000_nvm_flash_sw;
-
-	gfpreg = er32flash(ICH_FLASH_GFPREG);
-
-	/*
-	 * sector_X_addr is a "sector"-aligned address (4096 bytes)
-	 * Add 1 to sector_end_addr since this sector is included in
-	 * the overall size.
-	 */
-	sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
-	sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
-
-	/* flash_base_addr is byte-aligned */
-	nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
-
-	/*
-	 * find total size of the NVM, then cut in half since the total
-	 * size represents two separate NVM banks.
-	 */
-	nvm->flash_bank_size = (sector_end_addr - sector_base_addr)
-	                          << FLASH_SECTOR_ADDR_SHIFT;
-	nvm->flash_bank_size /= 2;
-	/* Adjust to word count */
-	nvm->flash_bank_size /= sizeof(u16);
-
-	nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS;
-
-	/* Clear shadow ram */
-	for (i = 0; i < nvm->word_size; i++) {
-		dev_spec->shadow_ram[i].modified = false;
-		dev_spec->shadow_ram[i].value    = 0xFFFF;
-	}
-
-	/* Function Pointers */
-	nvm->ops.acquire       = e1000e_acquire_nvm_ich8lan;
-	nvm->ops.release       = e1000e_release_nvm_ich8lan;
-	nvm->ops.read          = e1000e_read_nvm_ich8lan;
-	nvm->ops.update        = e1000e_update_nvm_checksum_ich8lan;
-	nvm->ops.valid_led_default = e1000e_valid_led_default_ich8lan;
-	nvm->ops.validate      = e1000e_validate_nvm_checksum_ich8lan;
-	nvm->ops.write         = e1000e_write_nvm_ich8lan;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_init_mac_params_ich8lan - Initialize MAC function pointers
- *  @hw: pointer to the HW structure
- *
- *  Initialize family-specific MAC parameters and function
- *  pointers.
- **/
-static s32 e1000e_init_mac_params_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-
-	/* Set media type function pointer */
-	hw->phy.media_type = e1000_media_type_copper;
-
-	/* Set mta register count */
-	mac->mta_reg_count = 32;
-	/* Set rar entry count */
-	mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
-	if (mac->type == e1000_ich8lan)
-		mac->rar_entry_count--;
-	/* Set if part includes ASF firmware */
-	mac->asf_firmware_present = true;
-	/* Set if manageability features are enabled. */
-	mac->arc_subsystem_valid = true;
-
-	/* Function pointers */
-
-	/* bus type/speed/width */
-	mac->ops.get_bus_info = e1000e_get_bus_info_ich8lan;
-	/* function id */
-	mac->ops.set_lan_id = e1000e_set_lan_id_single_port;
-	/* reset */
-	mac->ops.reset_hw = e1000e_reset_hw_ich8lan;
-	/* hw initialization */
-	mac->ops.init_hw = e1000e_init_hw_ich8lan;
-	/* link setup */
-	mac->ops.setup_link = e1000e_setup_link_ich8lan;
-	/* physical interface setup */
-	mac->ops.setup_physical_interface = e1000e_setup_copper_link_ich8lan;
-	/* check for link */
-	mac->ops.check_for_link = e1000e_check_for_copper_link_ich8lan;
-	/* check management mode */
-	mac->ops.check_mng_mode = e1000e_check_mng_mode_ich8lan;
-	/* link info */
-	mac->ops.get_link_up_info = e1000e_get_link_up_info_ich8lan;
-	/* multicast address update */
-	mac->ops.update_mc_addr_list = e1000e_update_mc_addr_list_generic;
-	/* setting MTA */
-	mac->ops.mta_set = e1000e_mta_set_generic;
-	/* clear hardware counters */
-	mac->ops.clear_hw_cntrs = e1000e_clear_hw_cntrs_ich8lan;
-
-	/* LED operations */
-	switch (mac->type) {
-	case e1000_ich8lan:
-	case e1000_ich9lan:
-	case e1000_ich10lan:
-		/* ID LED init */
-		mac->ops.id_led_init = e1000e_id_led_init;
-		/* blink LED */
-		mac->ops.blink_led = e1000e_blink_led;
-		/* setup LED */
-		mac->ops.setup_led = e1000e_setup_led_generic;
-		/* cleanup LED */
-		mac->ops.cleanup_led = e1000e_cleanup_led_ich8lan;
-		/* turn on/off LED */
-		mac->ops.led_on = e1000e_led_on_ich8lan;
-		mac->ops.led_off = e1000e_led_off_ich8lan;
-		break;
-	case e1000_pchlan:
-		/* ID LED init */
-		mac->ops.id_led_init = e1000e_id_led_init_pchlan;
-		/* setup LED */
-		mac->ops.setup_led = e1000e_setup_led_pchlan;
-		/* cleanup LED */
-		mac->ops.cleanup_led = e1000e_cleanup_led_pchlan;
-		/* turn on/off LED */
-		mac->ops.led_on = e1000e_led_on_pchlan;
-		mac->ops.led_off = e1000e_led_off_pchlan;
-		break;
-	default:
-		break;
-	}
-
-	/* Enable PCS Lock-loss workaround for ICH8 */
-	if (mac->type == e1000_ich8lan)
-		e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
-
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_check_for_copper_link_ich8lan - Check for link (Copper)
- *  @hw: pointer to the HW structure
- *
- *  Checks to see of the link status of the hardware has changed.  If a
- *  change in link status has been detected, then we read the PHY registers
- *  to get the current speed/duplex if link exists.
- **/
-static s32 e1000e_check_for_copper_link_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val;
-	bool link;
-
-	/*
-	 * We only want to go out to the PHY registers to see if Auto-Neg
-	 * has completed and/or if our link status has changed.  The
-	 * get_link_status flag is set upon receiving a Link Status
-	 * Change or Rx Sequence Error interrupt.
-	 */
-	if (!mac->get_link_status) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	/*
-	 * First we want to see if the MII Status Register reports
-	 * link.  If so, then we want to get the current speed/duplex
-	 * of the PHY.
-	 */
-	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		goto out;
-
-	if (hw->mac.type == e1000_pchlan) {
-		ret_val = e1000e_k1_gig_workaround_hv(hw, link);
-		if (ret_val)
-			goto out;
-	}
-
-	if (!link)
-		goto out; /* No link detected */
-
-	mac->get_link_status = false;
-
-	if (hw->phy.type == e1000_phy_82578) {
-		ret_val = e1000e_link_stall_workaround_hv(hw);
-		if (ret_val)
-			goto out;
-	}
-
-	/*
-	 * Check if there was DownShift, must be checked
-	 * immediately after link-up
-	 */
-	e1000e_check_downshift(hw);
-
-	/*
-	 * If we are forcing speed/duplex, then we simply return since
-	 * we have already determined whether we have link or not.
-	 */
-	if (!mac->autoneg) {
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	/*
-	 * Auto-Neg is enabled.  Auto Speed Detection takes care
-	 * of MAC speed/duplex configuration.  So we only need to
-	 * configure Collision Distance in the MAC.
-	 */
-	e1000e_config_collision_dist(hw);
-
-	/*
-	 * Configure Flow Control now that Auto-Neg has completed.
-	 * First, we need to restore the desired flow control
-	 * settings because we may have had to re-autoneg with a
-	 * different link partner.
-	 */
-	ret_val = e1000e_config_fc_after_link_up(hw);
-	if (ret_val)
-		e_dbg("Error configuring flow control\n");
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_init_function_pointers_ich8lan - Initialize ICH8 function pointers
- *  @hw: pointer to the HW structure
- *
- *  Initialize family-specific function pointers for PHY, MAC, and NVM.
- **/
-void e1000e_init_function_pointers_ich8lan(struct e1000_hw *hw)
-{
-	e1000e_init_mac_ops_generic(hw);
-	e1000e_init_nvm_ops_generic(hw);
-	hw->mac.ops.init_params = e1000e_init_mac_params_ich8lan;
-	hw->nvm.ops.init_params = e1000e_init_nvm_params_ich8lan;
-	switch (hw->mac.type) {
-	case e1000_ich8lan:
-	case e1000_ich9lan:
-	case e1000_ich10lan:
-		hw->phy.ops.init_params = e1000e_init_phy_params_ich8lan;
-		break;
-	case e1000_pchlan:
-		hw->phy.ops.init_params = e1000e_init_phy_params_pchlan;
-		break;
-	default:
-		break;
-	}
-}
-
-#if 0
-static DEFINE_MUTEX(nvm_mutex);
-#endif
-
-/**
- *  e1000e_acquire_nvm_ich8lan - Acquire NVM mutex
- *  @hw: pointer to the HW structure
- *
- *  Acquires the mutex for performing NVM operations.
- **/
-static s32 e1000e_acquire_nvm_ich8lan(struct e1000_hw *hw __unused)
-{
-#if 0
-	mutex_lock(&nvm_mutex);
-#endif
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_release_nvm_ich8lan - Release NVM mutex
- *  @hw: pointer to the HW structure
- *
- *  Releases the mutex used while performing NVM operations.
- **/
-static void e1000e_release_nvm_ich8lan(struct e1000_hw *hw __unused)
-{
-#if 0
-	mutex_unlock(&nvm_mutex);
-#endif
-	return;
-}
-
-#if 0
-static DEFINE_MUTEX(swflag_mutex);
-#endif
-
-/**
- *  e1000e_acquire_swflag_ich8lan - Acquire software control flag
- *  @hw: pointer to the HW structure
- *
- *  Acquires the software control flag for performing PHY and select
- *  MAC CSR accesses.
- **/
-static s32 e1000e_acquire_swflag_ich8lan(struct e1000_hw *hw)
-{
-	u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT;
-	s32 ret_val = E1000_SUCCESS;
-
-#if 0
-	mutex_lock(&swflag_mutex);
-#endif
-
-	while (timeout) {
-		extcnf_ctrl = er32(EXTCNF_CTRL);
-		if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG))
-			break;
-
-		mdelay(1);
-		timeout--;
-	}
-
-	if (!timeout) {
-		e_dbg("SW/FW/HW has locked the resource for too long.\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	timeout = SW_FLAG_TIMEOUT;
-
-	extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
-	ew32(EXTCNF_CTRL, extcnf_ctrl);
-
-	while (timeout) {
-		extcnf_ctrl = er32(EXTCNF_CTRL);
-		if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
-			break;
-
-		mdelay(1);
-		timeout--;
-	}
-
-	if (!timeout) {
-		e_dbg("Failed to acquire the semaphore.\n");
-		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
-		ew32(EXTCNF_CTRL, extcnf_ctrl);
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-out:
-#if 0
-	if (ret_val)
-		mutex_unlock(&swflag_mutex);
-#endif
-	return ret_val;
-}
-
-/**
- *  e1000e_release_swflag_ich8lan - Release software control flag
- *  @hw: pointer to the HW structure
- *
- *  Releases the software control flag for performing PHY and select
- *  MAC CSR accesses.
- **/
-static void e1000e_release_swflag_ich8lan(struct e1000_hw *hw)
-{
-	u32 extcnf_ctrl;
-
-	extcnf_ctrl = er32(EXTCNF_CTRL);
-	extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
-	ew32(EXTCNF_CTRL, extcnf_ctrl);
-
-#if 0
-	mutex_unlock(&swflag_mutex);
-#endif
-	return;
-}
-
-/**
- *  e1000e_check_mng_mode_ich8lan - Checks management mode
- *  @hw: pointer to the HW structure
- *
- *  This checks if the adapter has manageability enabled.
- *  This is a function pointer entry point only called by read/write
- *  routines for the PHY and NVM parts.
- **/
-static bool e1000e_check_mng_mode_ich8lan(struct e1000_hw *hw)
-{
-	u32 fwsm;
-
-	fwsm = er32(FWSM);
-	return (fwsm & E1000_FWSM_MODE_MASK) ==
-	        (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
-}
-/**
- *  e1000e_check_reset_block_ich8lan - Check if PHY reset is blocked
- *  @hw: pointer to the HW structure
- *
- *  Checks if firmware is blocking the reset of the PHY.
- *  This is a function pointer entry point only called by
- *  reset routines.
- **/
-static s32 e1000e_check_reset_block_ich8lan(struct e1000_hw *hw)
-{
-	u32 fwsm;
-
-	fwsm = er32(FWSM);
-	return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS
-	                                        : E1000_BLK_PHY_RESET;
-}
-
-/**
- *  e1000e_sw_lcd_config_ich8lan - SW-based LCD Configuration
- *  @hw:   pointer to the HW structure
- *
- *  SW should configure the LCD from the NVM extended configuration region
- *  as a workaround for certain parts.
- **/
-static s32 e1000e_sw_lcd_config_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
-	s32 ret_val;
-	u16 word_addr, reg_data, reg_addr, phy_page = 0;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		return ret_val;
-
-	/*
-	 * Initialize the PHY from the NVM on ICH platforms.  This
-	 * is needed due to an issue where the NVM configuration is
-	 * not properly autoloaded after power transitions.
-	 * Therefore, after each PHY reset, we will load the
-	 * configuration data out of the NVM manually.
-	 */
-	if ((hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) ||
-		(hw->mac.type == e1000_pchlan)) {
-		/* Check if SW needs to configure the PHY */
-		if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
-		    (hw->device_id == E1000_DEV_ID_ICH8_IGP_M) ||
-		    (hw->mac.type == e1000_pchlan))
-			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
-		else
-			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
-
-		data = er32(FEXTNVM);
-		if (!(data & sw_cfg_mask))
-			goto out;
-
-		/* Wait for basic configuration completes before proceeding */
-		e1000e_lan_init_done_ich8lan(hw);
-
-		/*
-		 * Make sure HW does not configure LCD from PHY
-		 * extended configuration before SW configuration
-		 */
-		data = er32(EXTCNF_CTRL);
-		if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
-			goto out;
-
-		cnf_size = er32(EXTCNF_SIZE);
-		cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
-		cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
-		if (!cnf_size)
-			goto out;
-
-		cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
-		cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
-
-		if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
-		    (hw->mac.type == e1000_pchlan)) {
-			/*
-			 * HW configures the SMBus address and LEDs when the
-			 * OEM and LCD Write Enable bits are set in the NVM.
-			 * When both NVM bits are cleared, SW will configure
-			 * them instead.
-			 */
-			data = er32(STRAP);
-			data &= E1000_STRAP_SMBUS_ADDRESS_MASK;
-			reg_data = data >> E1000_STRAP_SMBUS_ADDRESS_SHIFT;
-			reg_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
-			ret_val = e1000e_write_phy_reg_hv_locked(hw, HV_SMB_ADDR,
-			                                        reg_data);
-			if (ret_val)
-				goto out;
-
-			data = er32(LEDCTL);
-			ret_val = e1000e_write_phy_reg_hv_locked(hw,
-			                                        HV_LED_CONFIG,
-			                                        (u16)data);
-			if (ret_val)
-				goto out;
-		}
-
-		/* Configure LCD from extended configuration region. */
-
-		/* cnf_base_addr is in DWORD */
-		word_addr = (u16)(cnf_base_addr << 1);
-
-		for (i = 0; i < cnf_size; i++) {
-			ret_val = e1000e_read_nvm(hw, (word_addr + i * 2), 1,
-			                           &reg_data);
-			if (ret_val)
-				goto out;
-
-			ret_val = e1000e_read_nvm(hw, (word_addr + i * 2 + 1),
-			                           1, &reg_addr);
-			if (ret_val)
-				goto out;
-
-			/* Save off the PHY page for future writes. */
-			if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
-				phy_page = reg_data;
-				continue;
-			}
-
-			reg_addr &= PHY_REG_MASK;
-			reg_addr |= phy_page;
-
-			ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr,
-			                                    reg_data);
-			if (ret_val)
-				goto out;
-		}
-	}
-
-out:
-	hw->phy.ops.release(hw);
-	return ret_val;
-}
-
-/**
- *  e1000e_k1_gig_workaround_hv - K1 Si workaround
- *  @hw:   pointer to the HW structure
- *  @link: link up bool flag
- *
- *  If K1 is enabled for 1Gbps, the MAC might stall when transitioning
- *  from a lower speed.  This workaround disables K1 whenever link is at 1Gig
- *  If link is down, the function will restore the default K1 setting located
- *  in the NVM.
- **/
-static s32 e1000e_k1_gig_workaround_hv(struct e1000_hw *hw, bool link)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 status_reg = 0;
-	bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled;
-
-	if (hw->mac.type != e1000_pchlan)
-		goto out;
-
-	/* Wrap the whole flow with the sw flag */
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	/* Disable K1 when link is 1Gbps, otherwise use the NVM setting */
-	if (link) {
-		if (hw->phy.type == e1000_phy_82578) {
-			ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS,
-			                                      &status_reg);
-			if (ret_val)
-				goto release;
-
-			status_reg &= BM_CS_STATUS_LINK_UP |
-			              BM_CS_STATUS_RESOLVED |
-			              BM_CS_STATUS_SPEED_MASK;
-
-			if (status_reg == (BM_CS_STATUS_LINK_UP |
-			                   BM_CS_STATUS_RESOLVED |
-			                   BM_CS_STATUS_SPEED_1000))
-				k1_enable = false;
-		}
-
-		if (hw->phy.type == e1000_phy_82577) {
-			ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS,
-			                                      &status_reg);
-			if (ret_val)
-				goto release;
-
-			status_reg &= HV_M_STATUS_LINK_UP |
-			              HV_M_STATUS_AUTONEG_COMPLETE |
-			              HV_M_STATUS_SPEED_MASK;
-
-			if (status_reg == (HV_M_STATUS_LINK_UP |
-			                   HV_M_STATUS_AUTONEG_COMPLETE |
-			                   HV_M_STATUS_SPEED_1000))
-				k1_enable = false;
-		}
-
-		/* Link stall fix for link up */
-		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
-		                                       0x0100);
-		if (ret_val)
-			goto release;
-
-	} else {
-		/* Link stall fix for link down */
-		ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
-		                                       0x4100);
-		if (ret_val)
-			goto release;
-	}
-
-	ret_val = e1000e_configure_k1_ich8lan(hw, k1_enable);
-
-release:
-	hw->phy.ops.release(hw);
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_configure_k1_ich8lan - Configure K1 power state
- *  @hw: pointer to the HW structure
- *  @enable: K1 state to configure
- *
- *  Configure the K1 power state based on the provided parameter.
- *  Assumes semaphore already acquired.
- *
- *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
- **/
-s32 e1000e_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u32 ctrl_reg = 0;
-	u32 ctrl_ext = 0;
-	u32 reg = 0;
-	u16 kmrn_reg = 0;
-
-	ret_val = e1000e_read_kmrn_reg_locked(hw,
-	                                     E1000_KMRNCTRLSTA_K1_CONFIG,
-	                                     &kmrn_reg);
-	if (ret_val)
-		goto out;
-
-	if (k1_enable)
-		kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE;
-	else
-		kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE;
-
-	ret_val = e1000e_write_kmrn_reg_locked(hw,
-	                                      E1000_KMRNCTRLSTA_K1_CONFIG,
-	                                      kmrn_reg);
-	if (ret_val)
-		goto out;
-
-	udelay(20);
-	ctrl_ext = er32(CTRL_EXT);
-	ctrl_reg = er32(CTRL);
-
-	reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
-	reg |= E1000_CTRL_FRCSPD;
-	ew32(CTRL, reg);
-
-	E1000_WRITE_REG(hw,
-	                E1000_CTRL_EXT,
-	                ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
-	udelay(20);
-	ew32(CTRL, ctrl_reg);
-	ew32(CTRL_EXT, ctrl_ext);
-	udelay(20);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_oem_bits_config_ich8lan - SW-based LCD Configuration
- *  @hw:       pointer to the HW structure
- *  @d0_state: boolean if entering d0 or d3 device state
- *
- *  SW will configure Gbe Disable and LPLU based on the NVM. The four bits are
- *  collectively called OEM bits.  The OEM Write Enable bit and SW Config bit
- *  in NVM determines whether HW should configure LPLU and Gbe Disable.
- **/
-s32 e1000e_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
-{
-	s32 ret_val = 0;
-	u32 mac_reg;
-	u16 oem_reg;
-
-	if (hw->mac.type != e1000_pchlan)
-		return ret_val;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		return ret_val;
-
-	mac_reg = er32(EXTCNF_CTRL);
-	if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
-		goto out;
-
-	mac_reg = er32(FEXTNVM);
-	if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
-		goto out;
-
-	mac_reg = er32(PHY_CTRL);
-
-	ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg);
-	if (ret_val)
-		goto out;
-
-	oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU);
-
-	if (d0_state) {
-		if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE)
-			oem_reg |= HV_OEM_BITS_GBE_DIS;
-
-		if (mac_reg & E1000_PHY_CTRL_D0A_LPLU)
-			oem_reg |= HV_OEM_BITS_LPLU;
-	} else {
-		if (mac_reg & E1000_PHY_CTRL_NOND0A_GBE_DISABLE)
-			oem_reg |= HV_OEM_BITS_GBE_DIS;
-
-		if (mac_reg & E1000_PHY_CTRL_NOND0A_LPLU)
-			oem_reg |= HV_OEM_BITS_LPLU;
-	}
-	/* Restart auto-neg to activate the bits */
-	if (!e1000e_check_reset_block(hw))
-		oem_reg |= HV_OEM_BITS_RESTART_AN;
-	ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg);
-
-out:
-	hw->phy.ops.release(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
- *  done after every PHY reset.
- **/
-static s32 e1000e_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->mac.type != e1000_pchlan)
-		goto out;
-
-	if (((hw->phy.type == e1000_phy_82577) &&
-	     ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
-	    ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) {
-		/* Disable generation of early preamble */
-		ret_val = e1e_wphy(hw, PHY_REG(769, 25), 0x4431);
-		if (ret_val)
-			goto out;
-
-		/* Preamble tuning for SSC */
-		ret_val = e1e_wphy(hw, PHY_REG(770, 16), 0xA204);
-		if (ret_val)
-			goto out;
-	}
-
-	if (hw->phy.type == e1000_phy_82578) {
-		/*
-		 * Return registers to default by doing a soft reset then
-		 * writing 0x3140 to the control register.
-		 */
-		if (hw->phy.revision < 2) {
-			e1000e_phy_sw_reset(hw);
-			ret_val = e1e_wphy(hw, PHY_CONTROL,
-			                                0x3140);
-		}
-	}
-
-	/* Select page 0 */
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	hw->phy.addr = 1;
-	ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
-	if (ret_val)
-		goto out;
-	hw->phy.ops.release(hw);
-
-	/*
-	 * Configure the K1 Si workaround during phy reset assuming there is
-	 * link so that it disables K1 if link is in 1Gbps.
-	 */
-	ret_val = e1000e_k1_gig_workaround_hv(hw, true);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_lan_init_done_ich8lan - Check for PHY config completion
- *  @hw: pointer to the HW structure
- *
- *  Check the appropriate indication the MAC has finished configuring the
- *  PHY after a software reset.
- **/
-static void e1000e_lan_init_done_ich8lan(struct e1000_hw *hw)
-{
-	u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT;
-
-	/* Wait for basic configuration completes before proceeding */
-	do {
-		data = er32(STATUS);
-		data &= E1000_STATUS_LAN_INIT_DONE;
-		udelay(100);
-	} while ((!data) && --loop);
-
-	/*
-	 * If basic configuration is incomplete before the above loop
-	 * count reaches 0, loading the configuration from NVM will
-	 * leave the PHY in a bad state possibly resulting in no link.
-	 */
-	if (loop == 0)
-		e_dbg("LAN_INIT_DONE not set, increase timeout\n");
-
-	/* Clear the Init Done bit for the next init event */
-	data = er32(STATUS);
-	data &= ~E1000_STATUS_LAN_INIT_DONE;
-	ew32(STATUS, data);
-}
-
-/**
- *  e1000e_phy_hw_reset_ich8lan - Performs a PHY reset
- *  @hw: pointer to the HW structure
- *
- *  Resets the PHY
- *  This is a function pointer entry point called by drivers
- *  or other shared routines.
- **/
-static s32 e1000e_phy_hw_reset_ich8lan(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 reg;
-
-	ret_val = e1000e_phy_hw_reset_generic(hw);
-	if (ret_val)
-		goto out;
-
-	/* Allow time for h/w to get to a quiescent state after reset */
-	msleep(10);
-
-	if (hw->mac.type == e1000_pchlan) {
-		ret_val = e1000e_hv_phy_workarounds_ich8lan(hw);
-		if (ret_val)
-			goto out;
-	}
-
-	/* Dummy read to clear the phy wakeup bit after lcd reset */
-	if (hw->mac.type == e1000_pchlan)
-		e1e_rphy(hw, BM_WUC, &reg);
-
-	/* Configure the LCD with the extended configuration region in NVM */
-	ret_val = e1000e_sw_lcd_config_ich8lan(hw);
-	if (ret_val)
-		goto out;
-
-	/* Configure the LCD with the OEM bits in NVM */
-	if (hw->mac.type == e1000_pchlan)
-		ret_val = e1000e_oem_bits_config_ich8lan(hw, true);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info
- *  @hw: pointer to the HW structure
- *
- *  Wrapper for calling the get_phy_info routines for the appropriate phy type.
- **/
-static s32 e1000e_get_phy_info_ich8lan(struct e1000_hw *hw)
-{
-	s32 ret_val = -E1000_ERR_PHY_TYPE;
-
-	switch (hw->phy.type) {
-	case e1000_phy_ife:
-		ret_val = e1000e_get_phy_info_ife_ich8lan(hw);
-		break;
-	case e1000_phy_igp_3:
-	case e1000_phy_bm:
-	case e1000_phy_82578:
-	case e1000_phy_82577:
-		ret_val = e1000e_get_phy_info_igp(hw);
-		break;
-	default:
-		break;
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000e_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states
- *  @hw: pointer to the HW structure
- *
- *  Populates "phy" structure with various feature states.
- *  This function is only called by other family-specific
- *  routines.
- **/
-static s32 e1000e_get_phy_info_ife_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-	bool link;
-
-	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		goto out;
-
-	if (!link) {
-		e_dbg("Phy info is only valid if link is up\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	ret_val = e1e_rphy(hw, IFE_PHY_SPECIAL_CONTROL, &data);
-	if (ret_val)
-		goto out;
-	phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE)
-	                           ? false : true;
-
-	if (phy->polarity_correction) {
-		ret_val = e1000e_check_polarity_ife(hw);
-		if (ret_val)
-			goto out;
-	} else {
-		/* Polarity is forced */
-		phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
-		                      ? e1000_rev_polarity_reversed
-		                      : e1000_rev_polarity_normal;
-	}
-
-	ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
-	if (ret_val)
-		goto out;
-
-	phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? true : false;
-
-	/* The following parameters are undefined for 10/100 operation. */
-	phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
-	phy->local_rx = e1000_1000t_rx_status_undefined;
-	phy->remote_rx = e1000_1000t_rx_status_undefined;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_set_lplu_state_pchlan - Set Low Power Link Up state
- *  @hw: pointer to the HW structure
- *  @active: true to enable LPLU, false to disable
- *
- *  Sets the LPLU state according to the active flag.  For PCH, if OEM write
- *  bit are disabled in the NVM, writing the LPLU bits in the MAC will not set
- *  the phy speed. This function will manually set the LPLU bit and restart
- *  auto-neg as hw would do. D3 and D0 LPLU will call the same function
- *  since it configures the same bit.
- **/
-static s32 e1000e_set_lplu_state_pchlan(struct e1000_hw *hw, bool active)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 oem_reg;
-
-	ret_val = e1e_rphy(hw, HV_OEM_BITS, &oem_reg);
-	if (ret_val)
-		goto out;
-
-	if (active)
-		oem_reg |= HV_OEM_BITS_LPLU;
-	else
-		oem_reg &= ~HV_OEM_BITS_LPLU;
-
-	oem_reg |= HV_OEM_BITS_RESTART_AN;
-	ret_val = e1e_wphy(hw, HV_OEM_BITS, oem_reg);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
- *  @hw: pointer to the HW structure
- *  @active: true to enable LPLU, false to disable
- *
- *  Sets the LPLU D0 state according to the active flag.  When
- *  activating LPLU this function also disables smart speed
- *  and vice versa.  LPLU will not be activated unless the
- *  device autonegotiation advertisement meets standards of
- *  either 10 or 10/100 or 10/100/1000 at all duplexes.
- *  This is a function pointer entry point only called by
- *  PHY setup routines.
- **/
-static s32 e1000e_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 phy_ctrl;
-	s32 ret_val = E1000_SUCCESS;
-	u16 data;
-
-	if (phy->type == e1000_phy_ife)
-		goto out;
-
-	phy_ctrl = er32(PHY_CTRL);
-
-	if (active) {
-		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
-		ew32(PHY_CTRL, phy_ctrl);
-
-		if (phy->type != e1000_phy_igp_3)
-			goto out;
-
-		/*
-		 * Call gig speed drop workaround on LPLU before accessing
-		 * any PHY registers
-		 */
-		if (hw->mac.type == e1000_ich8lan)
-			e1000e_gig_downshift_workaround_ich8lan(hw);
-
-		/* When LPLU is enabled, we should disable SmartSpeed */
-		ret_val = e1e_rphy(hw,
-		                            IGP01E1000_PHY_PORT_CONFIG,
-		                            &data);
-		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-		ret_val = e1e_wphy(hw,
-		                             IGP01E1000_PHY_PORT_CONFIG,
-		                             data);
-		if (ret_val)
-			goto out;
-	} else {
-		phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
-		ew32(PHY_CTRL, phy_ctrl);
-
-		if (phy->type != e1000_phy_igp_3)
-			goto out;
-
-		/*
-		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
-		 * during Dx states where the power conservation is most
-		 * important.  During driver activity we should enable
-		 * SmartSpeed, so performance is maintained.
-		 */
-		if (phy->smart_speed == e1000_smart_speed_on) {
-			ret_val = e1e_rphy(hw,
-			                            IGP01E1000_PHY_PORT_CONFIG,
-			                            &data);
-			if (ret_val)
-				goto out;
-
-			data |= IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		} else if (phy->smart_speed == e1000_smart_speed_off) {
-			ret_val = e1e_rphy(hw,
-			                            IGP01E1000_PHY_PORT_CONFIG,
-			                            &data);
-			if (ret_val)
-				goto out;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
- *  @hw: pointer to the HW structure
- *  @active: true to enable LPLU, false to disable
- *
- *  Sets the LPLU D3 state according to the active flag.  When
- *  activating LPLU this function also disables smart speed
- *  and vice versa.  LPLU will not be activated unless the
- *  device autonegotiation advertisement meets standards of
- *  either 10 or 10/100 or 10/100/1000 at all duplexes.
- *  This is a function pointer entry point only called by
- *  PHY setup routines.
- **/
-static s32 e1000e_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 phy_ctrl;
-	s32 ret_val = E1000_SUCCESS;
-	u16 data;
-
-	phy_ctrl = er32(PHY_CTRL);
-
-	if (!active) {
-		phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
-		ew32(PHY_CTRL, phy_ctrl);
-
-		if (phy->type != e1000_phy_igp_3)
-			goto out;
-
-		/*
-		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
-		 * during Dx states where the power conservation is most
-		 * important.  During driver activity we should enable
-		 * SmartSpeed, so performance is maintained.
-		 */
-		if (phy->smart_speed == e1000_smart_speed_on) {
-			ret_val = e1e_rphy(hw,
-			                            IGP01E1000_PHY_PORT_CONFIG,
-			                            &data);
-			if (ret_val)
-				goto out;
-
-			data |= IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		} else if (phy->smart_speed == e1000_smart_speed_off) {
-			ret_val = e1e_rphy(hw,
-			                            IGP01E1000_PHY_PORT_CONFIG,
-			                            &data);
-			if (ret_val)
-				goto out;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		}
-	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
-	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
-	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
-		phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
-		ew32(PHY_CTRL, phy_ctrl);
-
-		if (phy->type != e1000_phy_igp_3)
-			goto out;
-
-		/*
-		 * Call gig speed drop workaround on LPLU before accessing
-		 * any PHY registers
-		 */
-		if (hw->mac.type == e1000_ich8lan)
-			e1000e_gig_downshift_workaround_ich8lan(hw);
-
-		/* When LPLU is enabled, we should disable SmartSpeed */
-		ret_val = e1e_rphy(hw,
-		                            IGP01E1000_PHY_PORT_CONFIG,
-		                            &data);
-		if (ret_val)
-			goto out;
-
-		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-		ret_val = e1e_wphy(hw,
-		                             IGP01E1000_PHY_PORT_CONFIG,
-		                             data);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
- *  @hw: pointer to the HW structure
- *  @bank:  pointer to the variable that returns the active bank
- *
- *  Reads signature byte from the NVM using the flash access registers.
- *  Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
- **/
-static s32 e1000e_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
-{
-	u32 eecd;
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
-	u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
-	u8 sig_byte = 0;
-	s32 ret_val = E1000_SUCCESS;
-
-	switch (hw->mac.type) {
-	case e1000_ich8lan:
-	case e1000_ich9lan:
-		eecd = er32(EECD);
-		if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
-		    E1000_EECD_SEC1VAL_VALID_MASK) {
-			if (eecd & E1000_EECD_SEC1VAL)
-				*bank = 1;
-			else
-				*bank = 0;
-
-			goto out;
-		}
-		e_dbg("Unable to determine valid NVM bank via EEC - "
-		         "reading flash signature\n");
-		/* fall-thru */
-	default:
-		/* set bank to 0 in case flash read fails */
-		*bank = 0;
-
-		/* Check bank 0 */
-		ret_val = e1000e_read_flash_byte_ich8lan(hw, act_offset,
-		                                        &sig_byte);
-		if (ret_val)
-			goto out;
-		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
-		    E1000_ICH_NVM_SIG_VALUE) {
-			*bank = 0;
-			goto out;
-		}
-
-		/* Check bank 1 */
-		ret_val = e1000e_read_flash_byte_ich8lan(hw, act_offset +
-		                                        bank1_offset,
-		                                        &sig_byte);
-		if (ret_val)
-			goto out;
-		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
-		    E1000_ICH_NVM_SIG_VALUE) {
-			*bank = 1;
-			goto out;
-		}
-
-		e_dbg("ERROR: No valid NVM bank present\n");
-		ret_val = -E1000_ERR_NVM;
-		break;
-	}
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_read_nvm_ich8lan - Read word(s) from the NVM
- *  @hw: pointer to the HW structure
- *  @offset: The offset (in bytes) of the word(s) to read.
- *  @words: Size of data to read in words
- *  @data: Pointer to the word(s) to read at offset.
- *
- *  Reads a word(s) from the NVM using the flash access registers.
- **/
-static s32 e1000e_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
-                                  u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-	u32 act_offset;
-	s32 ret_val = E1000_SUCCESS;
-	u32 bank = 0;
-	u16 i, word;
-
-	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
-	    (words == 0)) {
-		e_dbg("nvm parameter(s) out of bounds\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	nvm->ops.acquire(hw);
-
-	ret_val = e1000e_valid_nvm_bank_detect_ich8lan(hw, &bank);
-	if (ret_val != E1000_SUCCESS) {
-		e_dbg("Could not detect valid bank, assuming bank 0\n");
-		bank = 0;
-	}
-
-	act_offset = (bank) ? nvm->flash_bank_size : 0;
-	act_offset += offset;
-
-	ret_val = E1000_SUCCESS;
-	for (i = 0; i < words; i++) {
-		if ((dev_spec->shadow_ram) &&
-		    (dev_spec->shadow_ram[offset+i].modified)) {
-			data[i] = dev_spec->shadow_ram[offset+i].value;
-		} else {
-			ret_val = e1000e_read_flash_word_ich8lan(hw,
-			                                        act_offset + i,
-			                                        &word);
-			if (ret_val)
-				break;
-			data[i] = word;
-		}
-	}
-
-	nvm->ops.release(hw);
-
-out:
-	if (ret_val)
-		e_dbg("NVM read error: %d\n", ret_val);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_flash_cycle_init_ich8lan - Initialize flash
- *  @hw: pointer to the HW structure
- *
- *  This function does initial flash setup so that a new read/write/erase cycle
- *  can be started.
- **/
-static s32 e1000e_flash_cycle_init_ich8lan(struct e1000_hw *hw)
-{
-	union ich8_hws_flash_status hsfsts;
-	s32 ret_val = -E1000_ERR_NVM;
-	s32 i = 0;
-
-	hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
-
-	/* Check if the flash descriptor is valid */
-	if (hsfsts.hsf_status.fldesvalid == 0) {
-		e_dbg("Flash descriptor invalid.  "
-		         "SW Sequencing must be used.");
-		goto out;
-	}
-
-	/* Clear FCERR and DAEL in hw status by writing 1 */
-	hsfsts.hsf_status.flcerr = 1;
-	hsfsts.hsf_status.dael = 1;
-
-	ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
-
-	/*
-	 * Either we should have a hardware SPI cycle in progress
-	 * bit to check against, in order to start a new cycle or
-	 * FDONE bit should be changed in the hardware so that it
-	 * is 1 after hardware reset, which can then be used as an
-	 * indication whether a cycle is in progress or has been
-	 * completed.
-	 */
-
-	if (hsfsts.hsf_status.flcinprog == 0) {
-		/*
-		 * There is no cycle running at present,
-		 * so we can start a cycle.
-		 * Begin by setting Flash Cycle Done.
-		 */
-		hsfsts.hsf_status.flcdone = 1;
-		ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
-		ret_val = E1000_SUCCESS;
-	} else {
-		/*
-		 * Otherwise poll for sometime so the current
-		 * cycle has a chance to end before giving up.
-		 */
-		for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
-			hsfsts.regval = er16flash(
-			                                      ICH_FLASH_HSFSTS);
-			if (hsfsts.hsf_status.flcinprog == 0) {
-				ret_val = E1000_SUCCESS;
-				break;
-			}
-			udelay(1);
-		}
-		if (ret_val == E1000_SUCCESS) {
-			/*
-			 * Successful in waiting for previous cycle to timeout,
-			 * now set the Flash Cycle Done.
-			 */
-			hsfsts.hsf_status.flcdone = 1;
-			ew16flash(ICH_FLASH_HSFSTS,
-			                        hsfsts.regval);
-		} else {
-			e_dbg("Flash controller busy, cannot get access");
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
- *  @hw: pointer to the HW structure
- *  @timeout: maximum time to wait for completion
- *
- *  This function starts a flash cycle and waits for its completion.
- **/
-static s32 e1000e_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
-{
-	union ich8_hws_flash_ctrl hsflctl;
-	union ich8_hws_flash_status hsfsts;
-	s32 ret_val = -E1000_ERR_NVM;
-	u32 i = 0;
-
-	/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
-	hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
-	hsflctl.hsf_ctrl.flcgo = 1;
-	ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
-
-	/* wait till FDONE bit is set to 1 */
-	do {
-		hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
-		if (hsfsts.hsf_status.flcdone == 1)
-			break;
-		udelay(1);
-	} while (i++ < timeout);
-
-	if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0)
-		ret_val = E1000_SUCCESS;
-
-	return ret_val;
-}
-
-/**
- *  e1000e_read_flash_word_ich8lan - Read word from flash
- *  @hw: pointer to the HW structure
- *  @offset: offset to data location
- *  @data: pointer to the location for storing the data
- *
- *  Reads the flash word at offset into data.  Offset is converted
- *  to bytes before read.
- **/
-static s32 e1000e_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
-                                         u16 *data)
-{
-	s32 ret_val;
-
-	if (!data) {
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	/* Must convert offset into bytes. */
-	offset <<= 1;
-
-	ret_val = e1000e_read_flash_data_ich8lan(hw, offset, 2, data);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_read_flash_byte_ich8lan - Read byte from flash
- *  @hw: pointer to the HW structure
- *  @offset: The offset of the byte to read.
- *  @data: Pointer to a byte to store the value read.
- *
- *  Reads a single byte from the NVM using the flash access registers.
- **/
-static s32 e1000e_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
-                                         u8 *data)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 word = 0;
-
-	ret_val = e1000e_read_flash_data_ich8lan(hw, offset, 1, &word);
-	if (ret_val)
-		goto out;
-
-	*data = (u8)word;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_read_flash_data_ich8lan - Read byte or word from NVM
- *  @hw: pointer to the HW structure
- *  @offset: The offset (in bytes) of the byte or word to read.
- *  @size: Size of data to read, 1=byte 2=word
- *  @data: Pointer to the word to store the value read.
- *
- *  Reads a byte or word from the NVM using the flash access registers.
- **/
-static s32 e1000e_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
-                                         u8 size, u16 *data)
-{
-	union ich8_hws_flash_status hsfsts;
-	union ich8_hws_flash_ctrl hsflctl;
-	u32 flash_linear_addr;
-	u32 flash_data = 0;
-	s32 ret_val = -E1000_ERR_NVM;
-	u8 count = 0;
-
-	if (size < 1  || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
-		goto out;
-	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
-	                    hw->nvm.flash_base_addr;
-
-	do {
-		udelay(1);
-		/* Steps */
-		ret_val = e1000e_flash_cycle_init_ich8lan(hw);
-		if (ret_val != E1000_SUCCESS)
-			break;
-
-		hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
-		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
-		hsflctl.hsf_ctrl.fldbcount = size - 1;
-		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
-		ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
-
-		ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
-
-		ret_val = e1000e_flash_cycle_ich8lan(hw,
-		                                ICH_FLASH_READ_COMMAND_TIMEOUT);
-
-		/*
-		 * Check if FCERR is set to 1, if set to 1, clear it
-		 * and try the whole sequence a few more times, else
-		 * read in (shift in) the Flash Data0, the order is
-		 * least significant byte first msb to lsb
-		 */
-		if (ret_val == E1000_SUCCESS) {
-			flash_data = er32flash(ICH_FLASH_FDATA0);
-			if (size == 1)
-				*data = (u8)(flash_data & 0x000000FF);
-			else if (size == 2)
-				*data = (u16)(flash_data & 0x0000FFFF);
-			break;
-		} else {
-			/*
-			 * If we've gotten here, then things are probably
-			 * completely hosed, but if the error condition is
-			 * detected, it won't hurt to give it another try...
-			 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
-			 */
-			hsfsts.regval = er16flash(
-			                                      ICH_FLASH_HSFSTS);
-			if (hsfsts.hsf_status.flcerr == 1) {
-				/* Repeat for some time before giving up. */
-				continue;
-			} else if (hsfsts.hsf_status.flcdone == 0) {
-				e_dbg("Timeout error - flash cycle "
-				         "did not complete.");
-				break;
-			}
-		}
-	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_write_nvm_ich8lan - Write word(s) to the NVM
- *  @hw: pointer to the HW structure
- *  @offset: The offset (in bytes) of the word(s) to write.
- *  @words: Size of data to write in words
- *  @data: Pointer to the word(s) to write at offset.
- *
- *  Writes a byte or word to the NVM using the flash access registers.
- **/
-static s32 e1000e_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
-                                   u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-	s32 ret_val = E1000_SUCCESS;
-	u16 i;
-
-	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
-	    (words == 0)) {
-		e_dbg("nvm parameter(s) out of bounds\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	nvm->ops.acquire(hw);
-
-	for (i = 0; i < words; i++) {
-		dev_spec->shadow_ram[offset+i].modified = true;
-		dev_spec->shadow_ram[offset+i].value = data[i];
-	}
-
-	nvm->ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_update_nvm_checksum_ich8lan - Update the checksum for NVM
- *  @hw: pointer to the HW structure
- *
- *  The NVM checksum is updated by calling the generic update_nvm_checksum,
- *  which writes the checksum to the shadow ram.  The changes in the shadow
- *  ram are then committed to the EEPROM by processing each bank at a time
- *  checking for the modified bit and writing only the pending changes.
- *  After a successful commit, the shadow ram is cleared and is ready for
- *  future writes.
- **/
-static s32 e1000e_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-	u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
-	s32 ret_val;
-	u16 data;
-
-	ret_val = e1000e_update_nvm_checksum_generic(hw);
-	if (ret_val)
-		goto out;
-
-	if (nvm->type != e1000_nvm_flash_sw)
-		goto out;
-
-	nvm->ops.acquire(hw);
-
-	/*
-	 * We're writing to the opposite bank so if we're on bank 1,
-	 * write to bank 0 etc.  We also need to erase the segment that
-	 * is going to be written
-	 */
-	ret_val =  e1000e_valid_nvm_bank_detect_ich8lan(hw, &bank);
-	if (ret_val != E1000_SUCCESS) {
-		e_dbg("Could not detect valid bank, assuming bank 0\n");
-		bank = 0;
-	}
-
-	if (bank == 0) {
-		new_bank_offset = nvm->flash_bank_size;
-		old_bank_offset = 0;
-		ret_val = e1000e_erase_flash_bank_ich8lan(hw, 1);
-		if (ret_val) {
-			nvm->ops.release(hw);
-			goto out;
-		}
-	} else {
-		old_bank_offset = nvm->flash_bank_size;
-		new_bank_offset = 0;
-		ret_val = e1000e_erase_flash_bank_ich8lan(hw, 0);
-		if (ret_val) {
-			nvm->ops.release(hw);
-			goto out;
-		}
-	}
-
-	for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
-		/*
-		 * Determine whether to write the value stored
-		 * in the other NVM bank or a modified value stored
-		 * in the shadow RAM
-		 */
-		if (dev_spec->shadow_ram[i].modified) {
-			data = dev_spec->shadow_ram[i].value;
-		} else {
-			ret_val = e1000e_read_flash_word_ich8lan(hw, i +
-			                                        old_bank_offset,
-			                                        &data);
-			if (ret_val)
-				break;
-		}
-
-		/*
-		 * If the word is 0x13, then make sure the signature bits
-		 * (15:14) are 11b until the commit has completed.
-		 * This will allow us to write 10b which indicates the
-		 * signature is valid.  We want to do this after the write
-		 * has completed so that we don't mark the segment valid
-		 * while the write is still in progress
-		 */
-		if (i == E1000_ICH_NVM_SIG_WORD)
-			data |= E1000_ICH_NVM_SIG_MASK;
-
-		/* Convert offset to bytes. */
-		act_offset = (i + new_bank_offset) << 1;
-
-		udelay(100);
-		/* Write the bytes to the new bank. */
-		ret_val = e1000e_retry_write_flash_byte_ich8lan(hw,
-		                                               act_offset,
-		                                               (u8)data);
-		if (ret_val)
-			break;
-
-		udelay(100);
-		ret_val = e1000e_retry_write_flash_byte_ich8lan(hw,
-		                                          act_offset + 1,
-		                                          (u8)(data >> 8));
-		if (ret_val)
-			break;
-	}
-
-	/*
-	 * Don't bother writing the segment valid bits if sector
-	 * programming failed.
-	 */
-	if (ret_val) {
-		e_dbg("Flash commit failed.\n");
-		nvm->ops.release(hw);
-		goto out;
-	}
-
-	/*
-	 * Finally validate the new segment by setting bit 15:14
-	 * to 10b in word 0x13 , this can be done without an
-	 * erase as well since these bits are 11 to start with
-	 * and we need to change bit 14 to 0b
-	 */
-	act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
-	ret_val = e1000e_read_flash_word_ich8lan(hw, act_offset, &data);
-	if (ret_val) {
-		nvm->ops.release(hw);
-		goto out;
-	}
-
-	data &= 0xBFFF;
-	ret_val = e1000e_retry_write_flash_byte_ich8lan(hw,
-	                                               act_offset * 2 + 1,
-	                                               (u8)(data >> 8));
-	if (ret_val) {
-		nvm->ops.release(hw);
-		goto out;
-	}
-
-	/*
-	 * And invalidate the previously valid segment by setting
-	 * its signature word (0x13) high_byte to 0b. This can be
-	 * done without an erase because flash erase sets all bits
-	 * to 1's. We can write 1's to 0's without an erase
-	 */
-	act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
-	ret_val = e1000e_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
-	if (ret_val) {
-		nvm->ops.release(hw);
-		goto out;
-	}
-
-	/* Great!  Everything worked, we can now clear the cached entries. */
-	for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
-		dev_spec->shadow_ram[i].modified = false;
-		dev_spec->shadow_ram[i].value = 0xFFFF;
-	}
-
-	nvm->ops.release(hw);
-
-	/*
-	 * Reload the EEPROM, or else modifications will not appear
-	 * until after the next adapter reset.
-	 */
-	nvm->ops.reload(hw);
-	msleep(10);
-
-out:
-	if (ret_val)
-		e_dbg("NVM update error: %d\n", ret_val);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
- *  If the bit is 0, that the EEPROM had been modified, but the checksum was not
- *  calculated, in which case we need to calculate the checksum and set bit 6.
- **/
-static s32 e1000e_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 data;
-
-	/*
-	 * Read 0x19 and check bit 6.  If this bit is 0, the checksum
-	 * needs to be fixed.  This bit is an indication that the NVM
-	 * was prepared by OEM software and did not calculate the
-	 * checksum...a likely scenario.
-	 */
-	ret_val = e1000e_read_nvm(hw, 0x19, 1, &data);
-	if (ret_val)
-		goto out;
-
-	if ((data & 0x40) == 0) {
-		data |= 0x40;
-		ret_val = e1000e_write_nvm(hw, 0x19, 1, &data);
-		if (ret_val)
-			goto out;
-		ret_val = e1000e_update_nvm_checksum(hw);
-		if (ret_val)
-			goto out;
-	}
-
-	ret_val = e1000e_validate_nvm_checksum_generic(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_write_flash_data_ich8lan - Writes bytes to the NVM
- *  @hw: pointer to the HW structure
- *  @offset: The offset (in bytes) of the byte/word to read.
- *  @size: Size of data to read, 1=byte 2=word
- *  @data: The byte(s) to write to the NVM.
- *
- *  Writes one/two bytes to the NVM using the flash access registers.
- **/
-static s32 e1000e_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
-                                          u8 size, u16 data)
-{
-	union ich8_hws_flash_status hsfsts;
-	union ich8_hws_flash_ctrl hsflctl;
-	u32 flash_linear_addr;
-	u32 flash_data = 0;
-	s32 ret_val = -E1000_ERR_NVM;
-	u8 count = 0;
-
-	if (size < 1 || size > 2 || data > size * 0xff ||
-	    offset > ICH_FLASH_LINEAR_ADDR_MASK)
-		goto out;
-
-	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
-	                    hw->nvm.flash_base_addr;
-
-	do {
-		udelay(1);
-		/* Steps */
-		ret_val = e1000e_flash_cycle_init_ich8lan(hw);
-		if (ret_val != E1000_SUCCESS)
-			break;
-
-		hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
-		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
-		hsflctl.hsf_ctrl.fldbcount = size - 1;
-		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
-		ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
-
-		ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
-
-		if (size == 1)
-			flash_data = (u32)data & 0x00FF;
-		else
-			flash_data = (u32)data;
-
-		ew32flash(ICH_FLASH_FDATA0, flash_data);
-
-		/*
-		 * check if FCERR is set to 1 , if set to 1, clear it
-		 * and try the whole sequence a few more times else done
-		 */
-		ret_val = e1000e_flash_cycle_ich8lan(hw,
-		                               ICH_FLASH_WRITE_COMMAND_TIMEOUT);
-		if (ret_val == E1000_SUCCESS)
-			break;
-
-		/*
-		 * If we're here, then things are most likely
-		 * completely hosed, but if the error condition
-		 * is detected, it won't hurt to give it another
-		 * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
-		 */
-		hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
-		if (hsfsts.hsf_status.flcerr == 1) {
-			/* Repeat for some time before giving up. */
-			continue;
-		} else if (hsfsts.hsf_status.flcdone == 0) {
-			e_dbg("Timeout error - flash cycle "
-				 "did not complete.");
-			break;
-		}
-	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_write_flash_byte_ich8lan - Write a single byte to NVM
- *  @hw: pointer to the HW structure
- *  @offset: The index of the byte to read.
- *  @data: The byte to write to the NVM.
- *
- *  Writes a single byte to the NVM using the flash access registers.
- **/
-static s32 e1000e_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
-                                          u8 data)
-{
-	u16 word = (u16)data;
-
-	return e1000e_write_flash_data_ich8lan(hw, offset, 1, word);
-}
-
-/**
- *  e1000e_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
- *  @hw: pointer to the HW structure
- *  @offset: The offset of the byte to write.
- *  @byte: The byte to write to the NVM.
- *
- *  Writes a single byte to the NVM using the flash access registers.
- *  Goes through a retry algorithm before giving up.
- **/
-static s32 e1000e_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
-                                                u32 offset, u8 byte)
-{
-	s32 ret_val;
-	u16 program_retries;
-
-	ret_val = e1000e_write_flash_byte_ich8lan(hw, offset, byte);
-	if (ret_val == E1000_SUCCESS)
-		goto out;
-
-	for (program_retries = 0; program_retries < 100; program_retries++) {
-		e_dbg("Retrying Byte %2.2X at offset %u\n", byte, offset);
-		udelay(100);
-		ret_val = e1000e_write_flash_byte_ich8lan(hw, offset, byte);
-		if (ret_val == E1000_SUCCESS)
-			break;
-	}
-	if (program_retries == 100) {
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
- *  @hw: pointer to the HW structure
- *  @bank: 0 for first bank, 1 for second bank, etc.
- *
- *  Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
- *  bank N is 4096 * N + flash_reg_addr.
- **/
-static s32 e1000e_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	union ich8_hws_flash_status hsfsts;
-	union ich8_hws_flash_ctrl hsflctl;
-	u32 flash_linear_addr;
-	/* bank size is in 16bit words - adjust to bytes */
-	u32 flash_bank_size = nvm->flash_bank_size * 2;
-	s32 ret_val = E1000_SUCCESS;
-	s32 count = 0;
-	s32 j, iteration, sector_size;
-
-	hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
-
-	/*
-	 * Determine HW Sector size: Read BERASE bits of hw flash status
-	 * register
-	 * 00: The Hw sector is 256 bytes, hence we need to erase 16
-	 *     consecutive sectors.  The start index for the nth Hw sector
-	 *     can be calculated as = bank * 4096 + n * 256
-	 * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
-	 *     The start index for the nth Hw sector can be calculated
-	 *     as = bank * 4096
-	 * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
-	 *     (ich9 only, otherwise error condition)
-	 * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
-	 */
-	switch (hsfsts.hsf_status.berasesz) {
-	case 0:
-		/* Hw sector size 256 */
-		sector_size = ICH_FLASH_SEG_SIZE_256;
-		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
-		break;
-	case 1:
-		sector_size = ICH_FLASH_SEG_SIZE_4K;
-		iteration = 1;
-		break;
-	case 2:
-		sector_size = ICH_FLASH_SEG_SIZE_8K;
-		iteration = 1;
-		break;
-	case 3:
-		sector_size = ICH_FLASH_SEG_SIZE_64K;
-		iteration = 1;
-		break;
-	default:
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	/* Start with the base address, then add the sector offset. */
-	flash_linear_addr = hw->nvm.flash_base_addr;
-	flash_linear_addr += (bank) ? flash_bank_size : 0;
-
-	for (j = 0; j < iteration ; j++) {
-		do {
-			/* Steps */
-			ret_val = e1000e_flash_cycle_init_ich8lan(hw);
-			if (ret_val)
-				goto out;
-
-			/*
-			 * Write a value 11 (block Erase) in Flash
-			 * Cycle field in hw flash control
-			 */
-			hsflctl.regval = er16flash(
-			                                      ICH_FLASH_HSFCTL);
-			hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
-			ew16flash(ICH_FLASH_HSFCTL,
-			                        hsflctl.regval);
-
-			/*
-			 * Write the last 24 bits of an index within the
-			 * block into Flash Linear address field in Flash
-			 * Address.
-			 */
-			flash_linear_addr += (j * sector_size);
-			ew32flash(ICH_FLASH_FADDR,
-			                      flash_linear_addr);
-
-			ret_val = e1000e_flash_cycle_ich8lan(hw,
-			                       ICH_FLASH_ERASE_COMMAND_TIMEOUT);
-			if (ret_val == E1000_SUCCESS)
-				break;
-
-			/*
-			 * Check if FCERR is set to 1.  If 1,
-			 * clear it and try the whole sequence
-			 * a few more times else Done
-			 */
-			hsfsts.regval = er16flash(
-						      ICH_FLASH_HSFSTS);
-			if (hsfsts.hsf_status.flcerr == 1)
-				/* repeat for some time before giving up */
-				continue;
-			else if (hsfsts.hsf_status.flcdone == 0)
-				goto out;
-		} while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_valid_led_default_ich8lan - Set the default LED settings
- *  @hw: pointer to the HW structure
- *  @data: Pointer to the LED settings
- *
- *  Reads the LED default settings from the NVM to data.  If the NVM LED
- *  settings is all 0's or F's, set the LED default to a valid LED default
- *  setting.
- **/
-static s32 e1000e_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
-{
-	s32 ret_val;
-
-	ret_val = e1000e_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
-	if (ret_val) {
-		e_dbg("NVM Read Error\n");
-		goto out;
-	}
-
-	if (*data == ID_LED_RESERVED_0000 ||
-	    *data == ID_LED_RESERVED_FFFF)
-		*data = ID_LED_DEFAULT_ICH8LAN;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_id_led_init_pchlan - store LED configurations
- *  @hw: pointer to the HW structure
- *
- *  PCH does not control LEDs via the LEDCTL register, rather it uses
- *  the PHY LED configuration register.
- *
- *  PCH also does not have an "always on" or "always off" mode which
- *  complicates the ID feature.  Instead of using the "on" mode to indicate
- *  in ledctl_mode2 the LEDs to use for ID (see e1000e_id_led_init()),
- *  use "link_up" mode.  The LEDs will still ID on request if there is no
- *  link based on logic in e1000e_led_[on|off]_pchlan().
- **/
-static s32 e1000e_id_led_init_pchlan(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val;
-	const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP;
-	const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT;
-	u16 data, i, temp, shift;
-
-	/* Get default ID LED modes */
-	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
-	if (ret_val)
-		goto out;
-
-	mac->ledctl_default = er32(LEDCTL);
-	mac->ledctl_mode1 = mac->ledctl_default;
-	mac->ledctl_mode2 = mac->ledctl_default;
-
-	for (i = 0; i < 4; i++) {
-		temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK;
-		shift = (i * 5);
-		switch (temp) {
-		case ID_LED_ON1_DEF2:
-		case ID_LED_ON1_ON2:
-		case ID_LED_ON1_OFF2:
-			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
-			mac->ledctl_mode1 |= (ledctl_on << shift);
-			break;
-		case ID_LED_OFF1_DEF2:
-		case ID_LED_OFF1_ON2:
-		case ID_LED_OFF1_OFF2:
-			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
-			mac->ledctl_mode1 |= (ledctl_off << shift);
-			break;
-		default:
-			/* Do nothing */
-			break;
-		}
-		switch (temp) {
-		case ID_LED_DEF1_ON2:
-		case ID_LED_ON1_ON2:
-		case ID_LED_OFF1_ON2:
-			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
-			mac->ledctl_mode2 |= (ledctl_on << shift);
-			break;
-		case ID_LED_DEF1_OFF2:
-		case ID_LED_ON1_OFF2:
-		case ID_LED_OFF1_OFF2:
-			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
-			mac->ledctl_mode2 |= (ledctl_off << shift);
-			break;
-		default:
-			/* Do nothing */
-			break;
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_get_bus_info_ich8lan - Get/Set the bus type and width
- *  @hw: pointer to the HW structure
- *
- *  ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
- *  register, so the the bus width is hard coded.
- **/
-static s32 e1000e_get_bus_info_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_bus_info *bus = &hw->bus;
-	s32 ret_val;
-
-	ret_val = e1000e_get_bus_info_pcie(hw);
-
-	/*
-	 * ICH devices are "PCI Express"-ish.  They have
-	 * a configuration space, but do not contain
-	 * PCI Express Capability registers, so bus width
-	 * must be hardcoded.
-	 */
-	if (bus->width == e1000_bus_width_unknown)
-		bus->width = e1000_bus_width_pcie_x1;
-
-	return ret_val;
-}
-
-/**
- *  e1000e_reset_hw_ich8lan - Reset the hardware
- *  @hw: pointer to the HW structure
- *
- *  Does a full reset of the hardware which includes a reset of the PHY and
- *  MAC.
- **/
-static s32 e1000e_reset_hw_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-	u16 reg;
-	u32 ctrl, kab;
-	s32 ret_val;
-
-	/*
-	 * Prevent the PCI-E bus from sticking if there is no TLP connection
-	 * on the last TLP read/write transaction when MAC is reset.
-	 */
-	ret_val = e1000e_disable_pcie_master(hw);
-	if (ret_val)
-		e_dbg("PCI-E Master disable polling has failed.\n");
-
-	e_dbg("Masking off all interrupts\n");
-	ew32(IMC, 0xffffffff);
-
-	/*
-	 * Disable the Transmit and Receive units.  Then delay to allow
-	 * any pending transactions to complete before we hit the MAC
-	 * with the global reset.
-	 */
-	ew32(RCTL, 0);
-	ew32(TCTL, E1000_TCTL_PSP);
-	e1e_flush();
-
-	msleep(10);
-
-	/* Workaround for ICH8 bit corruption issue in FIFO memory */
-	if (hw->mac.type == e1000_ich8lan) {
-		/* Set Tx and Rx buffer allocation to 8k apiece. */
-		ew32(PBA, E1000_PBA_8K);
-		/* Set Packet Buffer Size to 16k. */
-		ew32(PBS, E1000_PBS_16K);
-	}
-
-	if (hw->mac.type == e1000_pchlan) {
-		/* Save the NVM K1 bit setting*/
-		ret_val = e1000e_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, &reg);
-		if (ret_val)
-			return ret_val;
-
-		if (reg & E1000_NVM_K1_ENABLE)
-			dev_spec->nvm_k1_enabled = true;
-		else
-			dev_spec->nvm_k1_enabled = false;
-	}
-
-	ctrl = er32(CTRL);
-
-	if (!e1000e_check_reset_block(hw) && !hw->phy.reset_disable) {
-		/* Clear PHY Reset Asserted bit */
-		if (hw->mac.type >= e1000_pchlan) {
-			u32 status = er32(STATUS);
-			ew32(STATUS, status &
-			                ~E1000_STATUS_PHYRA);
-		}
-
-		/*
-		 * PHY HW reset requires MAC CORE reset at the same
-		 * time to make sure the interface between MAC and the
-		 * external PHY is reset.
-		 */
-		ctrl |= E1000_CTRL_PHY_RST;
-	}
-	ret_val = e1000e_acquire_swflag_ich8lan(hw);
-	e_dbg("Issuing a global reset to ich8lan\n");
-	ew32(CTRL, (ctrl | E1000_CTRL_RST));
-	msleep(20);
-
-	if (!ret_val)
-		e1000e_release_swflag_ich8lan(hw);
-
-	if (ctrl & E1000_CTRL_PHY_RST)
-		ret_val = hw->phy.ops.get_cfg_done(hw);
-
-	if (hw->mac.type >= e1000_ich10lan) {
-		e1000e_lan_init_done_ich8lan(hw);
-	} else {
-		ret_val = e1000e_get_auto_rd_done(hw);
-		if (ret_val) {
-			/*
-			 * When auto config read does not complete, do not
-			 * return with an error. This can happen in situations
-			 * where there is no eeprom and prevents getting link.
-			 */
-			e_dbg("Auto Read Done did not complete\n");
-		}
-	}
-	/* Dummy read to clear the phy wakeup bit after lcd reset */
-	if (hw->mac.type == e1000_pchlan)
-		e1e_rphy(hw, BM_WUC, &reg);
-
-	ret_val = e1000e_sw_lcd_config_ich8lan(hw);
-	if (ret_val)
-		goto out;
-
-	if (hw->mac.type == e1000_pchlan) {
-		ret_val = e1000e_oem_bits_config_ich8lan(hw, true);
-		if (ret_val)
-			goto out;
-	}
-	/*
-	 * For PCH, this write will make sure that any noise
-	 * will be detected as a CRC error and be dropped rather than show up
-	 * as a bad packet to the DMA engine.
-	 */
-	if (hw->mac.type == e1000_pchlan)
-		ew32(CRC_OFFSET, 0x65656565);
-
-	ew32(IMC, 0xffffffff);
-	er32(ICR);
-
-	kab = er32(KABGTXD);
-	kab |= E1000_KABGTXD_BGSQLBIAS;
-	ew32(KABGTXD, kab);
-
-	if (hw->mac.type == e1000_pchlan)
-		ret_val = e1000e_hv_phy_workarounds_ich8lan(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_init_hw_ich8lan - Initialize the hardware
- *  @hw: pointer to the HW structure
- *
- *  Prepares the hardware for transmit and receive by doing the following:
- *   - initialize hardware bits
- *   - initialize LED identification
- *   - setup receive address registers
- *   - setup flow control
- *   - setup transmit descriptors
- *   - clear statistics
- **/
-static s32 e1000e_init_hw_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 ctrl_ext, txdctl, snoop;
-	s32 ret_val;
-	u16 i;
-
-	e1000e_initialize_hw_bits_ich8lan(hw);
-
-	/* Initialize identification LED */
-	ret_val = mac->ops.id_led_init(hw);
-	if (ret_val)
-		/* This is not fatal and we should not stop init due to this */
-		e_dbg("Error initializing identification LED\n");
-
-	/* Setup the receive address. */
-	e1000e_init_rx_addrs(hw, mac->rar_entry_count);
-
-	/* Zero out the Multicast HASH table */
-	e_dbg("Zeroing the MTA\n");
-	for (i = 0; i < mac->mta_reg_count; i++)
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
-
-	/*
-	 * The 82578 Rx buffer will stall if wakeup is enabled in host and
-	 * the ME.  Reading the BM_WUC register will clear the host wakeup bit.
-	 * Reset the phy after disabling host wakeup to reset the Rx buffer.
-	 */
-	if (hw->phy.type == e1000_phy_82578) {
-		e1e_rphy(hw, BM_WUC, &i);
-		ret_val = e1000e_phy_hw_reset_ich8lan(hw);
-		if (ret_val)
-			return ret_val;
-	}
-
-	/* Setup link and flow control */
-	ret_val = mac->ops.setup_link(hw);
-
-	/* Set the transmit descriptor write-back policy for both queues */
-	txdctl = er32(TXDCTL(0));
-	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
-		 E1000_TXDCTL_FULL_TX_DESC_WB;
-	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
-	         E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
-	ew32(TXDCTL(0), txdctl);
-	txdctl = er32(TXDCTL(1));
-	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
-		 E1000_TXDCTL_FULL_TX_DESC_WB;
-	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
-	         E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
-	ew32(TXDCTL(1), txdctl);
-
-	/*
-	 * ICH8 has opposite polarity of no_snoop bits.
-	 * By default, we should use snoop behavior.
-	 */
-	if (mac->type == e1000_ich8lan)
-		snoop = PCIE_ICH8_SNOOP_ALL;
-	else
-		snoop = (u32)~(PCIE_NO_SNOOP_ALL);
-	e1000e_set_pcie_no_snoop(hw, snoop);
-
-	ctrl_ext = er32(CTRL_EXT);
-	ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
-	ew32(CTRL_EXT, ctrl_ext);
-
-	/*
-	 * Clear all of the statistics registers (clear on read).  It is
-	 * important that we do this after we have tried to establish link
-	 * because the symbol error count will increment wildly if there
-	 * is no link.
-	 */
-	e1000e_clear_hw_cntrs_ich8lan(hw);
-
-	return ret_val;
-}
-/**
- *  e1000e_initialize_hw_bits_ich8lan - Initialize required hardware bits
- *  @hw: pointer to the HW structure
- *
- *  Sets/Clears required hardware bits necessary for correctly setting up the
- *  hardware for transmit and receive.
- **/
-static void e1000e_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
-{
-	u32 reg;
-
-	/* Extended Device Control */
-	reg = er32(CTRL_EXT);
-	reg |= (1 << 22);
-	/* Enable PHY low-power state when MAC is at D3 w/o WoL */
-	if (hw->mac.type >= e1000_pchlan)
-		reg |= E1000_CTRL_EXT_PHYPDEN;
-	ew32(CTRL_EXT, reg);
-
-	/* Transmit Descriptor Control 0 */
-	reg = er32(TXDCTL(0));
-	reg |= (1 << 22);
-	ew32(TXDCTL(0), reg);
-
-	/* Transmit Descriptor Control 1 */
-	reg = er32(TXDCTL(1));
-	reg |= (1 << 22);
-	ew32(TXDCTL(1), reg);
-
-	/* Transmit Arbitration Control 0 */
-	reg = er32(TARC(0));
-	if (hw->mac.type == e1000_ich8lan)
-		reg |= (1 << 28) | (1 << 29);
-	reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
-	ew32(TARC(0), reg);
-
-	/* Transmit Arbitration Control 1 */
-	reg = er32(TARC(1));
-	if (er32(TCTL) & E1000_TCTL_MULR)
-		reg &= ~(1 << 28);
-	else
-		reg |= (1 << 28);
-	reg |= (1 << 24) | (1 << 26) | (1 << 30);
-	ew32(TARC(1), reg);
-
-	/* Device Status */
-	if (hw->mac.type == e1000_ich8lan) {
-		reg = er32(STATUS);
-		reg &= ~(1 << 31);
-		ew32(STATUS, reg);
-	}
-
-	return;
-}
-
-/**
- *  e1000e_setup_link_ich8lan - Setup flow control and link settings
- *  @hw: pointer to the HW structure
- *
- *  Determines which flow control settings to use, then configures flow
- *  control.  Calls the appropriate media-specific link configuration
- *  function.  Assuming the adapter has a valid link partner, a valid link
- *  should be established.  Assumes the hardware has previously been reset
- *  and the transmitter and receiver are not enabled.
- **/
-static s32 e1000e_setup_link_ich8lan(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (e1000e_check_reset_block(hw))
-		goto out;
-
-	/*
-	 * ICH parts do not have a word in the NVM to determine
-	 * the default flow control setting, so we explicitly
-	 * set it to full.
-	 */
-	if (hw->fc.requested_mode == e1000_fc_default)
-		hw->fc.requested_mode = e1000_fc_full;
-
-	/*
-	 * Save off the requested flow control mode for use later.  Depending
-	 * on the link partner's capabilities, we may or may not use this mode.
-	 */
-	hw->fc.current_mode = hw->fc.requested_mode;
-
-	e_dbg("After fix-ups FlowControl is now = %x\n",
-		hw->fc.current_mode);
-
-	/* Continue to configure the copper link. */
-	ret_val = hw->mac.ops.setup_physical_interface(hw);
-	if (ret_val)
-		goto out;
-
-	ew32(FCTTV, hw->fc.pause_time);
-	if ((hw->phy.type == e1000_phy_82578) ||
-	    (hw->phy.type == e1000_phy_82577)) {
-		ret_val = e1e_wphy(hw,
-		                             PHY_REG(BM_PORT_CTRL_PAGE, 27),
-		                             hw->fc.pause_time);
-		if (ret_val)
-			goto out;
-	}
-
-	ret_val = e1000e_set_fc_watermarks(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_setup_copper_link_ich8lan - Configure MAC/PHY interface
- *  @hw: pointer to the HW structure
- *
- *  Configures the kumeran interface to the PHY to wait the appropriate time
- *  when polling the PHY, then call the generic setup_copper_link to finish
- *  configuring the copper link.
- **/
-static s32 e1000e_setup_copper_link_ich8lan(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val;
-	u16 reg_data;
-
-	ctrl = er32(CTRL);
-	ctrl |= E1000_CTRL_SLU;
-	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-	ew32(CTRL, ctrl);
-
-	/*
-	 * Set the mac to wait the maximum time between each iteration
-	 * and increase the max iterations when polling the phy;
-	 * this fixes erroneous timeouts at 10Mbps.
-	 */
-	ret_val = e1000e_write_kmrn_reg(hw,
-	                                       E1000_KMRNCTRLSTA_TIMEOUTS,
-	                                       0xFFFF);
-	if (ret_val)
-		goto out;
-	ret_val = e1000e_read_kmrn_reg(hw,
-	                                      E1000_KMRNCTRLSTA_INBAND_PARAM,
-	                                      &reg_data);
-	if (ret_val)
-		goto out;
-	reg_data |= 0x3F;
-	ret_val = e1000e_write_kmrn_reg(hw,
-	                                       E1000_KMRNCTRLSTA_INBAND_PARAM,
-	                                       reg_data);
-	if (ret_val)
-		goto out;
-
-	switch (hw->phy.type) {
-	case e1000_phy_igp_3:
-		ret_val = e1000e_copper_link_setup_igp(hw);
-		if (ret_val)
-			goto out;
-		break;
-	case e1000_phy_bm:
-	case e1000_phy_82578:
-		ret_val = e1000e_copper_link_setup_m88(hw);
-		if (ret_val)
-			goto out;
-		break;
-	case e1000_phy_82577:
-		ret_val = e1000e_copper_link_setup_82577(hw);
-		if (ret_val)
-			goto out;
-		break;
-	case e1000_phy_ife:
-		ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL,
-		                               &reg_data);
-		if (ret_val)
-			goto out;
-
-		reg_data &= ~IFE_PMC_AUTO_MDIX;
-
-		switch (hw->phy.mdix) {
-		case 1:
-			reg_data &= ~IFE_PMC_FORCE_MDIX;
-			break;
-		case 2:
-			reg_data |= IFE_PMC_FORCE_MDIX;
-			break;
-		case 0:
-		default:
-			reg_data |= IFE_PMC_AUTO_MDIX;
-			break;
-		}
-		ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL,
-		                                reg_data);
-		if (ret_val)
-			goto out;
-		break;
-	default:
-		break;
-	}
-	ret_val = e1000e_setup_copper_link(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_get_link_up_info_ich8lan - Get current link speed and duplex
- *  @hw: pointer to the HW structure
- *  @speed: pointer to store current link speed
- *  @duplex: pointer to store the current link duplex
- *
- *  Calls the generic get_speed_and_duplex to retrieve the current link
- *  information and then calls the Kumeran lock loss workaround for links at
- *  gigabit speeds.
- **/
-static s32 e1000e_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
-                                          u16 *duplex)
-{
-	s32 ret_val;
-
-	ret_val = e1000e_get_speed_and_duplex_copper(hw, speed, duplex);
-	if (ret_val)
-		goto out;
-
-	if ((hw->mac.type == e1000_ich8lan) &&
-	    (hw->phy.type == e1000_phy_igp_3) &&
-	    (*speed == SPEED_1000)) {
-		ret_val = e1000e_kmrn_lock_loss_workaround_ich8lan(hw);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
- *  @hw: pointer to the HW structure
- *
- *  Work-around for 82566 Kumeran PCS lock loss:
- *  On link status change (i.e. PCI reset, speed change) and link is up and
- *  speed is gigabit-
- *    0) if workaround is optionally disabled do nothing
- *    1) wait 1ms for Kumeran link to come up
- *    2) check Kumeran Diagnostic register PCS lock loss bit
- *    3) if not set the link is locked (all is good), otherwise...
- *    4) reset the PHY
- *    5) repeat up to 10 times
- *  Note: this is only called for IGP3 copper when speed is 1gb.
- **/
-static s32 e1000e_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
-{
-	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-	u32 phy_ctrl;
-	s32 ret_val = E1000_SUCCESS;
-	u16 i, data;
-	bool link;
-
-	if (!(dev_spec->kmrn_lock_loss_workaround_enabled))
-		goto out;
-
-	/*
-	 * Make sure link is up before proceeding.  If not just return.
-	 * Attempting this while link is negotiating fouled up link
-	 * stability
-	 */
-	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
-	if (!link) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	for (i = 0; i < 10; i++) {
-		/* read once to clear */
-		ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data);
-		if (ret_val)
-			goto out;
-		/* and again to get new status */
-		ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data);
-		if (ret_val)
-			goto out;
-
-		/* check for PCS lock */
-		if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) {
-			ret_val = E1000_SUCCESS;
-			goto out;
-		}
-
-		/* Issue PHY reset */
-		e1000e_phy_hw_reset(hw);
-		mdelay(5);
-	}
-	/* Disable GigE link negotiation */
-	phy_ctrl = er32(PHY_CTRL);
-	phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
-	             E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
-	ew32(PHY_CTRL, phy_ctrl);
-
-	/*
-	 * Call gig speed drop workaround on Gig disable before accessing
-	 * any PHY registers
-	 */
-	e1000e_gig_downshift_workaround_ich8lan(hw);
-
-	/* unable to acquire PCS lock */
-	ret_val = -E1000_ERR_PHY;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state
- *  @hw: pointer to the HW structure
- *  @state: boolean value used to set the current Kumeran workaround state
- *
- *  If ICH8, set the current Kumeran workaround state (enabled - true
- *  /disabled - false).
- **/
-void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
-                                                 bool state)
-{
-	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
-
-	if (hw->mac.type != e1000_ich8lan) {
-		e_dbg("Workaround applies to ICH8 only.\n");
-		return;
-	}
-
-	dev_spec->kmrn_lock_loss_workaround_enabled = state;
-
-	return;
-}
-
-/**
- *  e1000e_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
- *  @hw: pointer to the HW structure
- *
- *  Workaround for 82566 power-down on D3 entry:
- *    1) disable gigabit link
- *    2) write VR power-down enable
- *    3) read it back
- *  Continue if successful, else issue LCD reset and repeat
- **/
-void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
-{
-	u32 reg;
-	u16 data;
-	u8  retry = 0;
-
-	if (hw->phy.type != e1000_phy_igp_3)
-		goto out;
-
-	/* Try the workaround twice (if needed) */
-	do {
-		/* Disable link */
-		reg = er32(PHY_CTRL);
-		reg |= (E1000_PHY_CTRL_GBE_DISABLE |
-		        E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
-		ew32(PHY_CTRL, reg);
-
-		/*
-		 * Call gig speed drop workaround on Gig disable before
-		 * accessing any PHY registers
-		 */
-		if (hw->mac.type == e1000_ich8lan)
-			e1000e_gig_downshift_workaround_ich8lan(hw);
-
-		/* Write VR power-down enable */
-		e1e_rphy(hw, IGP3_VR_CTRL, &data);
-		data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
-		e1e_wphy(hw, IGP3_VR_CTRL,
-		                   data | IGP3_VR_CTRL_MODE_SHUTDOWN);
-
-		/* Read it back and test */
-		e1e_rphy(hw, IGP3_VR_CTRL, &data);
-		data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
-		if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
-			break;
-
-		/* Issue PHY reset and repeat at most one more time */
-		reg = er32(CTRL);
-		ew32(CTRL, reg | E1000_CTRL_PHY_RST);
-		retry++;
-	} while (retry);
-
-out:
-	return;
-}
-
-/**
- *  e1000e_gig_downshift_workaround_ich8lan - WoL from S5 stops working
- *  @hw: pointer to the HW structure
- *
- *  Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
- *  LPLU, Gig disable, MDIC PHY reset):
- *    1) Set Kumeran Near-end loopback
- *    2) Clear Kumeran Near-end loopback
- *  Should only be called for ICH8[m] devices with IGP_3 Phy.
- **/
-void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 reg_data;
-
-	if ((hw->mac.type != e1000_ich8lan) ||
-	    (hw->phy.type != e1000_phy_igp_3))
-		goto out;
-
-	ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
-	                                      &reg_data);
-	if (ret_val)
-		goto out;
-	reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
-	ret_val = e1000e_write_kmrn_reg(hw,
-	                                       E1000_KMRNCTRLSTA_DIAG_OFFSET,
-	                                       reg_data);
-	if (ret_val)
-		goto out;
-	reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
-	ret_val = e1000e_write_kmrn_reg(hw,
-	                                       E1000_KMRNCTRLSTA_DIAG_OFFSET,
-	                                       reg_data);
-out:
-	return;
-}
-
-/**
- *  e1000e_disable_gig_wol_ich8lan - disable gig during WoL
- *  @hw: pointer to the HW structure
- *
- *  During S0 to Sx transition, it is possible the link remains at gig
- *  instead of negotiating to a lower speed.  Before going to Sx, set
- *  'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
- *  to a lower speed.
- *
- *  Should only be called for applicable parts.
- **/
-void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw)
-{
-	u32 phy_ctrl;
-
-	switch (hw->mac.type) {
-	case e1000_ich8lan:
-	case e1000_ich9lan:
-	case e1000_ich10lan:
-	case e1000_pchlan:
-		phy_ctrl = er32(PHY_CTRL);
-		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
-		            E1000_PHY_CTRL_GBE_DISABLE;
-		ew32(PHY_CTRL, phy_ctrl);
-
-		if (hw->mac.type == e1000_pchlan)
-			e1000e_phy_hw_reset_ich8lan(hw);
-	default:
-		break;
-	}
-
-	return;
-}
-
-/**
- *  e1000e_cleanup_led_ich8lan - Restore the default LED operation
- *  @hw: pointer to the HW structure
- *
- *  Return the LED back to the default configuration.
- **/
-static s32 e1000e_cleanup_led_ich8lan(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->phy.type == e1000_phy_ife)
-		ret_val = e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED,
-		                              0);
-	else
-		ew32(LEDCTL, hw->mac.ledctl_default);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_led_on_ich8lan - Turn LEDs on
- *  @hw: pointer to the HW structure
- *
- *  Turn on the LEDs.
- **/
-static s32 e1000e_led_on_ich8lan(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->phy.type == e1000_phy_ife)
-		ret_val = e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED,
-		                (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
-	else
-		ew32(LEDCTL, hw->mac.ledctl_mode2);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_led_off_ich8lan - Turn LEDs off
- *  @hw: pointer to the HW structure
- *
- *  Turn off the LEDs.
- **/
-static s32 e1000e_led_off_ich8lan(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->phy.type == e1000_phy_ife)
-		ret_val = e1e_wphy(hw,
-		               IFE_PHY_SPECIAL_CONTROL_LED,
-		               (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
-	else
-		ew32(LEDCTL, hw->mac.ledctl_mode1);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_setup_led_pchlan - Configures SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  This prepares the SW controllable LED for use.
- **/
-static s32 e1000e_setup_led_pchlan(struct e1000_hw *hw)
-{
-	return e1e_wphy(hw, HV_LED_CONFIG,
-					(u16)hw->mac.ledctl_mode1);
-}
-
-/**
- *  e1000e_cleanup_led_pchlan - Restore the default LED operation
- *  @hw: pointer to the HW structure
- *
- *  Return the LED back to the default configuration.
- **/
-static s32 e1000e_cleanup_led_pchlan(struct e1000_hw *hw)
-{
-	return e1e_wphy(hw, HV_LED_CONFIG,
-					(u16)hw->mac.ledctl_default);
-}
-
-/**
- *  e1000e_led_on_pchlan - Turn LEDs on
- *  @hw: pointer to the HW structure
- *
- *  Turn on the LEDs.
- **/
-static s32 e1000e_led_on_pchlan(struct e1000_hw *hw)
-{
-	u16 data = (u16)hw->mac.ledctl_mode2;
-	u32 i, led;
-
-	/*
-	 * If no link, then turn LED on by setting the invert bit
-	 * for each LED that's mode is "link_up" in ledctl_mode2.
-	 */
-	if (!(er32(STATUS) & E1000_STATUS_LU)) {
-		for (i = 0; i < 3; i++) {
-			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
-			if ((led & E1000_PHY_LED0_MODE_MASK) !=
-			    E1000_LEDCTL_MODE_LINK_UP)
-				continue;
-			if (led & E1000_PHY_LED0_IVRT)
-				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
-			else
-				data |= (E1000_PHY_LED0_IVRT << (i * 5));
-		}
-	}
-
-	return e1e_wphy(hw, HV_LED_CONFIG, data);
-}
-
-/**
- *  e1000e_led_off_pchlan - Turn LEDs off
- *  @hw: pointer to the HW structure
- *
- *  Turn off the LEDs.
- **/
-static s32 e1000e_led_off_pchlan(struct e1000_hw *hw)
-{
-	u16 data = (u16)hw->mac.ledctl_mode1;
-	u32 i, led;
-
-	/*
-	 * If no link, then turn LED off by clearing the invert bit
-	 * for each LED that's mode is "link_up" in ledctl_mode1.
-	 */
-	if (!(er32(STATUS) & E1000_STATUS_LU)) {
-		for (i = 0; i < 3; i++) {
-			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
-			if ((led & E1000_PHY_LED0_MODE_MASK) !=
-			    E1000_LEDCTL_MODE_LINK_UP)
-				continue;
-			if (led & E1000_PHY_LED0_IVRT)
-				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
-			else
-				data |= (E1000_PHY_LED0_IVRT << (i * 5));
-		}
-	}
-
-	return e1e_wphy(hw, HV_LED_CONFIG, data);
-}
-
-/**
- *  e1000e_get_cfg_done_ich8lan - Read config done bit
- *  @hw: pointer to the HW structure
- *
- *  Read the management control register for the config done bit for
- *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
- *  to read the config done bit, so an error is *ONLY* logged and returns
- *  E1000_SUCCESS.  If we were to return with error, EEPROM-less silicon
- *  would not be able to be reset or change link.
- **/
-static s32 e1000e_get_cfg_done_ich8lan(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u32 bank = 0;
-
-	if (hw->mac.type >= e1000_pchlan) {
-		u32 status = er32(STATUS);
-
-		if (status & E1000_STATUS_PHYRA) {
-			ew32(STATUS, status &
-			                ~E1000_STATUS_PHYRA);
-		} else
-			e_dbg("PHY Reset Asserted not set - needs delay\n");
-	}
-
-	e1000e_get_cfg_done(hw);
-
-	/* If EEPROM is not marked present, init the IGP 3 PHY manually */
-	if ((hw->mac.type != e1000_ich10lan) &&
-	    (hw->mac.type != e1000_pchlan)) {
-		if (((er32(EECD) & E1000_EECD_PRES) == 0) &&
-		    (hw->phy.type == e1000_phy_igp_3)) {
-			e1000e_phy_init_script_igp3(hw);
-		}
-	} else {
-		if (e1000e_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
-			/* Maybe we should do a basic PHY config */
-			e_dbg("EEPROM not present\n");
-			ret_val = -E1000_ERR_CONFIG;
-		}
-	}
-
-	return ret_val;
-}
-
-/**
- * e1000e_power_down_phy_copper_ich8lan - Remove link during PHY power down
- * @hw: pointer to the HW structure
- *
- * In the case of a PHY power down to save power, or to turn off link during a
- * driver unload, or wake on lan is not enabled, remove the link.
- **/
-static void e1000e_power_down_phy_copper_ich8lan(struct e1000_hw *hw)
-{
-	/* If the management interface is not enabled, then power down */
-	if (!(hw->mac.ops.check_mng_mode(hw) ||
-	      e1000e_check_reset_block(hw)))
-		e1000e_power_down_phy_copper(hw);
-
-	return;
-}
-
-/**
- *  e1000e_clear_hw_cntrs_ich8lan - Clear statistical counters
- *  @hw: pointer to the HW structure
- *
- *  Clears hardware counters specific to the silicon family and calls
- *  clear_hw_cntrs_generic to clear all general purpose counters.
- **/
-static void e1000e_clear_hw_cntrs_ich8lan(struct e1000_hw *hw __unused)
-{
-#if 0
-	u16 phy_data;
-
-	e1000e_clear_hw_cntrs_base(hw);
-
-	er32(ALGNERRC);
-	er32(RXERRC);
-	er32(TNCRS);
-	er32(CEXTERR);
-	er32(TSCTC);
-	er32(TSCTFC);
-
-	er32(MGTPRC);
-	er32(MGTPDC);
-	er32(MGTPTC);
-
-	er32(IAC);
-	er32(ICRXOC);
-
-	/* Clear PHY statistics registers */
-	if ((hw->phy.type == e1000_phy_82578) ||
-	    (hw->phy.type == e1000_phy_82577)) {
-		e1e_rphy(hw, HV_SCC_UPPER, &phy_data);
-		e1e_rphy(hw, HV_SCC_LOWER, &phy_data);
-		e1e_rphy(hw, HV_ECOL_UPPER, &phy_data);
-		e1e_rphy(hw, HV_ECOL_LOWER, &phy_data);
-		e1e_rphy(hw, HV_MCC_UPPER, &phy_data);
-		e1e_rphy(hw, HV_MCC_LOWER, &phy_data);
-		e1e_rphy(hw, HV_LATECOL_UPPER, &phy_data);
-		e1e_rphy(hw, HV_LATECOL_LOWER, &phy_data);
-		e1e_rphy(hw, HV_COLC_UPPER, &phy_data);
-		e1e_rphy(hw, HV_COLC_LOWER, &phy_data);
-		e1e_rphy(hw, HV_DC_UPPER, &phy_data);
-		e1e_rphy(hw, HV_DC_LOWER, &phy_data);
-		e1e_rphy(hw, HV_TNCRS_UPPER, &phy_data);
-		e1e_rphy(hw, HV_TNCRS_LOWER, &phy_data);
-	}
-#endif
-}
-
-static struct pci_device_id e1000e_ich8lan_nics[] = {
-     PCI_ROM(0x8086, 0x104C, "E1000_DEV_ID_ICH8_IFE", "E1000_DEV_ID_ICH8_IFE", board_ich8lan),
-     PCI_ROM(0x8086, 0x10C5, "E1000_DEV_ID_ICH8_IFE_G", "E1000_DEV_ID_ICH8_IFE_G", board_ich8lan),
-     PCI_ROM(0x8086, 0x10C4, "E1000_DEV_ID_ICH8_IFE_GT", "E1000_DEV_ID_ICH8_IFE_GT", board_ich8lan),
-     PCI_ROM(0x8086, 0x104A, "E1000_DEV_ID_ICH8_IGP_AMT", "E1000_DEV_ID_ICH8_IGP_AMT", board_ich8lan),
-     PCI_ROM(0x8086, 0x104B, "E1000_DEV_ID_ICH8_IGP_C", "E1000_DEV_ID_ICH8_IGP_C", board_ich8lan),
-     PCI_ROM(0x8086, 0x104D, "E1000_DEV_ID_ICH8_IGP_M", "E1000_DEV_ID_ICH8_IGP_M", board_ich8lan),
-     PCI_ROM(0x8086, 0x1049, "E1000_DEV_ID_ICH8_IGP_M_AMT", "E1000_DEV_ID_ICH8_IGP_M_AMT", board_ich8lan),
-     PCI_ROM(0x8086, 0x1501, "E1000_DEV_ID_ICH8_82567V_3", "E1000_DEV_ID_ICH8_82567V_3", board_ich8lan),
-     PCI_ROM(0x8086, 0x10C0, "E1000_DEV_ID_ICH9_IFE", "E1000_DEV_ID_ICH9_IFE", board_ich9lan),
-     PCI_ROM(0x8086, 0x10C2, "E1000_DEV_ID_ICH9_IFE_G", "E1000_DEV_ID_ICH9_IFE_G", board_ich9lan),
-     PCI_ROM(0x8086, 0x10C3, "E1000_DEV_ID_ICH9_IFE_GT", "E1000_DEV_ID_ICH9_IFE_GT", board_ich9lan),
-     PCI_ROM(0x8086, 0x10BD, "E1000_DEV_ID_ICH9_IGP_AMT", "E1000_DEV_ID_ICH9_IGP_AMT", board_ich9lan),
-     PCI_ROM(0x8086, 0x294C, "E1000_DEV_ID_ICH9_IGP_C", "E1000_DEV_ID_ICH9_IGP_C", board_ich9lan),
-     PCI_ROM(0x8086, 0x10E5, "E1000_DEV_ID_ICH9_BM", "E1000_DEV_ID_ICH9_BM", board_ich9lan),
-     PCI_ROM(0x8086, 0x10BF, "E1000_DEV_ID_ICH9_IGP_M", "E1000_DEV_ID_ICH9_IGP_M", board_ich9lan),
-     PCI_ROM(0x8086, 0x10F5, "E1000_DEV_ID_ICH9_IGP_M_AMT", "E1000_DEV_ID_ICH9_IGP_M_AMT", board_ich9lan),
-     PCI_ROM(0x8086, 0x10CB, "E1000_DEV_ID_ICH9_IGP_M_V", "E1000_DEV_ID_ICH9_IGP_M_V", board_ich9lan),
-     PCI_ROM(0x8086, 0x10CC, "E1000_DEV_ID_ICH10_R_BM_LM", "E1000_DEV_ID_ICH10_R_BM_LM", board_ich9lan),
-     PCI_ROM(0x8086, 0x10CD, "E1000_DEV_ID_ICH10_R_BM_LF", "E1000_DEV_ID_ICH10_R_BM_LF", board_ich9lan),
-     PCI_ROM(0x8086, 0x10CE, "E1000_DEV_ID_ICH10_R_BM_V", "E1000_DEV_ID_ICH10_R_BM_V", board_ich9lan),
-     PCI_ROM(0x8086, 0x10DE, "E1000_DEV_ID_ICH10_D_BM_LM", "E1000_DEV_ID_ICH10_D_BM_LM", board_ich10lan),
-     PCI_ROM(0x8086, 0x10DF, "E1000_DEV_ID_ICH10_D_BM_LF", "E1000_DEV_ID_ICH10_D_BM_LF", board_ich10lan),
-     PCI_ROM(0x8086, 0x10EA, "E1000_DEV_ID_PCH_M_HV_LM", "E1000_DEV_ID_PCH_M_HV_LM", board_pchlan),
-     PCI_ROM(0x8086, 0x10EB, "E1000_DEV_ID_PCH_M_HV_LC", "E1000_DEV_ID_PCH_M_HV_LC", board_pchlan),
-     PCI_ROM(0x8086, 0x10EF, "E1000_DEV_ID_PCH_D_HV_DM", "E1000_DEV_ID_PCH_D_HV_DM", board_pchlan),
-     PCI_ROM(0x8086, 0x10F0, "E1000_DEV_ID_PCH_D_HV_DC", "E1000_DEV_ID_PCH_D_HV_DC", board_pchlan),
-};
-
-struct pci_driver e1000e_ich8lan_driver __pci_driver = {
-	.ids = e1000e_ich8lan_nics,
-	.id_count = (sizeof (e1000e_ich8lan_nics) / sizeof (e1000e_ich8lan_nics[0])),
-	.probe = e1000e_probe,
-	.remove = e1000e_remove,
-};
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_ich8lan.h b/roms/ipxe/src/drivers/net/e1000e/e1000e_ich8lan.h
deleted file mode 100644
index af3447829288a54f0d8969fff19c9cb42ab2b721..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_ich8lan.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000E_ICH8LAN_H_
-#define _E1000E_ICH8LAN_H_
-
-#define ICH_FLASH_GFPREG                 0x0000
-#define ICH_FLASH_HSFSTS                 0x0004
-#define ICH_FLASH_HSFCTL                 0x0006
-#define ICH_FLASH_FADDR                  0x0008
-#define ICH_FLASH_FDATA0                 0x0010
-
-/* Requires up to 10 seconds when MNG might be accessing part. */
-#define ICH_FLASH_READ_COMMAND_TIMEOUT   10000000
-#define ICH_FLASH_WRITE_COMMAND_TIMEOUT  10000000
-#define ICH_FLASH_ERASE_COMMAND_TIMEOUT  10000000
-#define ICH_FLASH_LINEAR_ADDR_MASK       0x00FFFFFF
-#define ICH_FLASH_CYCLE_REPEAT_COUNT     10
-
-#define ICH_CYCLE_READ                   0
-#define ICH_CYCLE_WRITE                  2
-#define ICH_CYCLE_ERASE                  3
-
-#define FLASH_GFPREG_BASE_MASK           0x1FFF
-#define FLASH_SECTOR_ADDR_SHIFT          12
-
-#define ICH_FLASH_SEG_SIZE_256           256
-#define ICH_FLASH_SEG_SIZE_4K            4096
-#define ICH_FLASH_SEG_SIZE_8K            8192
-#define ICH_FLASH_SEG_SIZE_64K           65536
-#define ICH_FLASH_SECTOR_SIZE            4096
-
-#define ICH_FLASH_REG_MAPSIZE            0x00A0
-
-#define E1000_ICH_FWSM_RSPCIPHY          0x00000040 /* Reset PHY on PCI Reset */
-#define E1000_ICH_FWSM_DISSW             0x10000000 /* FW Disables SW Writes */
-/* FW established a valid mode */
-#define E1000_ICH_FWSM_FW_VALID          0x00008000
-
-#define E1000_ICH_MNG_IAMT_MODE          0x2
-
-#define ID_LED_DEFAULT_ICH8LAN  ((ID_LED_DEF1_DEF2 << 12) | \
-                                 (ID_LED_OFF1_OFF2 <<  8) | \
-                                 (ID_LED_OFF1_ON2  <<  4) | \
-                                 (ID_LED_DEF1_DEF2))
-
-#define E1000_ICH_NVM_SIG_WORD           0x13
-#define E1000_ICH_NVM_SIG_MASK           0xC000
-#define E1000_ICH_NVM_VALID_SIG_MASK     0xC0
-#define E1000_ICH_NVM_SIG_VALUE          0x80
-
-#define E1000_ICH8_LAN_INIT_TIMEOUT      1500
-
-#define E1000_FEXTNVM_SW_CONFIG        1
-#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M */
-
-#define PCIE_ICH8_SNOOP_ALL   PCIE_NO_SNOOP_ALL
-
-#define E1000_ICH_RAR_ENTRIES            7
-
-#define PHY_PAGE_SHIFT 5
-#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
-                           ((reg) & MAX_PHY_REG_ADDRESS))
-#define IGP3_KMRN_DIAG  PHY_REG(770, 19) /* KMRN Diagnostic */
-#define IGP3_VR_CTRL    PHY_REG(776, 18) /* Voltage Regulator Control */
-#define IGP3_CAPABILITY PHY_REG(776, 19) /* Capability */
-#define IGP3_PM_CTRL    PHY_REG(769, 20) /* Power Management Control */
-
-#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS         0x0002
-#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300
-#define IGP3_VR_CTRL_MODE_SHUTDOWN           0x0200
-#define IGP3_PM_CTRL_FORCE_PWR_DOWN          0x0020
-
-/* PHY Wakeup Registers and defines */
-#define BM_RCTL         PHY_REG(BM_WUC_PAGE, 0)
-#define BM_WUC          PHY_REG(BM_WUC_PAGE, 1)
-#define BM_WUFC         PHY_REG(BM_WUC_PAGE, 2)
-#define BM_WUS          PHY_REG(BM_WUC_PAGE, 3)
-#define BM_RAR_L(_i)    (BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2)))
-#define BM_RAR_M(_i)    (BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2)))
-#define BM_RAR_H(_i)    (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2)))
-#define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2)))
-#define BM_MTA(_i)      (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1)))
-
-#define BM_RCTL_UPE           0x0001          /* Unicast Promiscuous Mode */
-#define BM_RCTL_MPE           0x0002          /* Multicast Promiscuous Mode */
-#define BM_RCTL_MO_SHIFT      3               /* Multicast Offset Shift */
-#define BM_RCTL_MO_MASK       (3 << 3)        /* Multicast Offset Mask */
-#define BM_RCTL_BAM           0x0020          /* Broadcast Accept Mode */
-#define BM_RCTL_PMCF          0x0040          /* Pass MAC Control Frames */
-#define BM_RCTL_RFCE          0x0080          /* Rx Flow Control Enable */
-
-#define HV_LED_CONFIG		PHY_REG(768, 30) /* LED Configuration */
-#define HV_MUX_DATA_CTRL               PHY_REG(776, 16)
-#define HV_MUX_DATA_CTRL_GEN_TO_MAC    0x0400
-#define HV_MUX_DATA_CTRL_FORCE_SPEED   0x0004
-#define HV_SCC_UPPER		PHY_REG(778, 16) /* Single Collision Count */
-#define HV_SCC_LOWER		PHY_REG(778, 17)
-#define HV_ECOL_UPPER		PHY_REG(778, 18) /* Excessive Collision Count */
-#define HV_ECOL_LOWER		PHY_REG(778, 19)
-#define HV_MCC_UPPER		PHY_REG(778, 20) /* Multiple Collision Count */
-#define HV_MCC_LOWER		PHY_REG(778, 21)
-#define HV_LATECOL_UPPER	PHY_REG(778, 23) /* Late Collision Count */
-#define HV_LATECOL_LOWER	PHY_REG(778, 24)
-#define HV_COLC_UPPER		PHY_REG(778, 25) /* Collision Count */
-#define HV_COLC_LOWER		PHY_REG(778, 26)
-#define HV_DC_UPPER		PHY_REG(778, 27) /* Defer Count */
-#define HV_DC_LOWER		PHY_REG(778, 28)
-#define HV_TNCRS_UPPER		PHY_REG(778, 29) /* Transmit with no CRS */
-#define HV_TNCRS_LOWER		PHY_REG(778, 30)
-
-#define E1000_FCRTV_PCH     0x05F40 /* PCH Flow Control Refresh Timer Value */
-
-#define E1000_NVM_K1_CONFIG 0x1B /* NVM K1 Config Word */
-#define E1000_NVM_K1_ENABLE 0x1  /* NVM Enable K1 bit */
-
-/* SMBus Address Phy Register */
-#define HV_SMB_ADDR            PHY_REG(768, 26)
-#define HV_SMB_ADDR_PEC_EN     0x0200
-#define HV_SMB_ADDR_VALID      0x0080
-
-/* Strapping Option Register - RO */
-#define E1000_STRAP                     0x0000C
-#define E1000_STRAP_SMBUS_ADDRESS_MASK  0x00FE0000
-#define E1000_STRAP_SMBUS_ADDRESS_SHIFT 17
-
-/* OEM Bits Phy Register */
-#define HV_OEM_BITS            PHY_REG(768, 25)
-#define HV_OEM_BITS_LPLU       0x0004 /* Low Power Link Up */
-#define HV_OEM_BITS_GBE_DIS    0x0040 /* Gigabit Disable */
-#define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */
-
-#define LCD_CFG_PHY_ADDR_BIT   0x0020 /* Phy address bit from LCD Config word */
-
-#define SW_FLAG_TIMEOUT    1000 /* SW Semaphore flag timeout in milliseconds */
-
-/*
- * Additional interrupts need to be handled for ICH family:
- *  DSW = The FW changed the status of the DISSW bit in FWSM
- *  PHYINT = The LAN connected device generates an interrupt
- *  EPRST = Manageability reset event
- */
-#define IMS_ICH_ENABLE_MASK (\
-    E1000_IMS_DSW   | \
-    E1000_IMS_PHYINT | \
-    E1000_IMS_EPRST)
-
-/* Additional interrupt register bit definitions */
-#define E1000_ICR_LSECPNC       0x00004000          /* PN threshold - client */
-#define E1000_IMS_LSECPNC       E1000_ICR_LSECPNC   /* PN threshold - client */
-#define E1000_ICS_LSECPNC       E1000_ICR_LSECPNC   /* PN threshold - client */
-
-/* Security Processing bit Indication */
-#define E1000_RXDEXT_LINKSEC_STATUS_LSECH       0x01000000
-#define E1000_RXDEXT_LINKSEC_ERROR_BIT_MASK     0x60000000
-#define E1000_RXDEXT_LINKSEC_ERROR_NO_SA_MATCH  0x20000000
-#define E1000_RXDEXT_LINKSEC_ERROR_REPLAY_ERROR 0x40000000
-#define E1000_RXDEXT_LINKSEC_ERROR_BAD_SIG      0x60000000
-
-
-void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
-                                                 bool state);
-void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
-void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
-void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw);
-s32 e1000e_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable);
-s32 e1000e_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_config);
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_mac.c b/roms/ipxe/src/drivers/net/e1000e/e1000e_mac.c
deleted file mode 100644
index d96b279f796d0206a8f09905702c2f2eb45429cb..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_mac.c
+++ /dev/null
@@ -1,1883 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include "e1000e.h"
-
-static u32 e1000e_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr);
-static s32 e1000e_set_default_fc_generic(struct e1000_hw *hw);
-static s32 e1000e_commit_fc_settings_generic(struct e1000_hw *hw);
-static s32 e1000e_poll_fiber_serdes_link_generic(struct e1000_hw *hw);
-static s32 e1000e_validate_mdi_setting_generic(struct e1000_hw *hw);
-static void e1000e_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
-
-/**
- *  e1000e_init_mac_ops_generic - Initialize MAC function pointers
- *  @hw: pointer to the HW structure
- *
- *  Setups up the function pointers to no-op functions
- **/
-void e1000e_init_mac_ops_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	/* General Setup */
-	mac->ops.set_lan_id = e1000e_set_lan_id_multi_port_pcie;
-	mac->ops.read_mac_addr = e1000e_read_mac_addr_generic;
-	mac->ops.config_collision_dist = e1000e_config_collision_dist;
-	/* LINK */
-	mac->ops.wait_autoneg = e1000e_wait_autoneg;
-	/* Management */
-#if 0
-	mac->ops.mng_host_if_write = e1000e_mng_host_if_write_generic;
-	mac->ops.mng_write_cmd_header = e1000e_mng_write_cmd_header_generic;
-	mac->ops.mng_enable_host_if = e1000e_mng_enable_host_if_generic;
-#endif
-	/* VLAN, MC, etc. */
-	mac->ops.rar_set = e1000e_rar_set;
-	mac->ops.validate_mdi_setting = e1000e_validate_mdi_setting_generic;
-}
-
-/**
- *  e1000e_get_bus_info_pcie - Get PCIe bus information
- *  @hw: pointer to the HW structure
- *
- *  Determines and stores the system bus information for a particular
- *  network interface.  The following bus information is determined and stored:
- *  bus speed, bus width, type (PCIe), and PCIe function.
- **/
-s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	struct e1000_bus_info *bus = &hw->bus;
-
-	s32 ret_val;
-	u16 pcie_link_status;
-
-	bus->type = e1000_bus_type_pci_express;
-	bus->speed = e1000_bus_speed_2500;
-
-	ret_val = e1000e_read_pcie_cap_reg(hw,
-	                                  PCIE_LINK_STATUS,
-	                                  &pcie_link_status);
-	if (ret_val)
-		bus->width = e1000_bus_width_unknown;
-	else
-		bus->width = (enum e1000_bus_width)((pcie_link_status &
-		                                PCIE_LINK_WIDTH_MASK) >>
-		                               PCIE_LINK_WIDTH_SHIFT);
-
-	mac->ops.set_lan_id(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices
- *
- *  @hw: pointer to the HW structure
- *
- *  Determines the LAN function id by reading memory-mapped registers
- *  and swaps the port value if requested.
- **/
-static void e1000e_set_lan_id_multi_port_pcie(struct e1000_hw *hw)
-{
-	struct e1000_bus_info *bus = &hw->bus;
-	u32 reg;
-
-	/*
-	 * The status register reports the correct function number
-	 * for the device regardless of function swap state.
-	 */
-	reg = er32(STATUS);
-	bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
-}
-
-/**
- *  e1000e_set_lan_id_single_port - Set LAN id for a single port device
- *  @hw: pointer to the HW structure
- *
- *  Sets the LAN function id to zero for a single port device.
- **/
-void e1000e_set_lan_id_single_port(struct e1000_hw *hw)
-{
-	struct e1000_bus_info *bus = &hw->bus;
-
-	bus->func = 0;
-}
-
-/**
- *  e1000e_clear_vfta_generic - Clear VLAN filter table
- *  @hw: pointer to the HW structure
- *
- *  Clears the register array which contains the VLAN filter table by
- *  setting all the values to 0.
- **/
-void e1000e_clear_vfta_generic(struct e1000_hw *hw)
-{
-	u32 offset;
-
-	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
-		E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0);
-		e1e_flush();
-	}
-}
-
-/**
- *  e1000e_write_vfta_generic - Write value to VLAN filter table
- *  @hw: pointer to the HW structure
- *  @offset: register offset in VLAN filter table
- *  @value: register value written to VLAN filter table
- *
- *  Writes value at the given offset in the register array which stores
- *  the VLAN filter table.
- **/
-void e1000e_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value)
-{
-	E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
-	e1e_flush();
-}
-
-/**
- *  e1000e_init_rx_addrs - Initialize receive address's
- *  @hw: pointer to the HW structure
- *  @rar_count: receive address registers
- *
- *  Setups the receive address registers by setting the base receive address
- *  register to the devices MAC address and clearing all the other receive
- *  address registers to 0.
- **/
-void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
-{
-	u32 i;
-	u8 mac_addr[ETH_ADDR_LEN] = {0};
-
-	/* Setup the receive address */
-	e_dbg("Programming MAC Address into RAR[0]\n");
-
-	hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
-
-	/* Zero out the other (rar_entry_count - 1) receive addresses */
-	e_dbg("Clearing RAR[1-%u]\n", rar_count-1);
-	for (i = 1; i < rar_count; i++)
-		hw->mac.ops.rar_set(hw, mac_addr, i);
-}
-
-/**
- *  e1000e_check_alt_mac_addr_generic - Check for alternate MAC addr
- *  @hw: pointer to the HW structure
- *
- *  Checks the nvm for an alternate MAC address.  An alternate MAC address
- *  can be setup by pre-boot software and must be treated like a permanent
- *  address and must override the actual permanent MAC address. If an
- *  alternate MAC address is found it is programmed into RAR0, replacing
- *  the permanent address that was installed into RAR0 by the Si on reset.
- *  This function will return SUCCESS unless it encounters an error while
- *  reading the EEPROM.
- **/
-s32 e1000e_check_alt_mac_addr_generic(struct e1000_hw *hw)
-{
-	u32 i;
-	s32 ret_val = E1000_SUCCESS;
-	u16 offset, nvm_alt_mac_addr_offset, nvm_data;
-	u8 alt_mac_addr[ETH_ADDR_LEN];
-
-	ret_val = e1000e_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1,
-	                         &nvm_alt_mac_addr_offset);
-	if (ret_val) {
-		e_dbg("NVM Read Error\n");
-		goto out;
-	}
-
-	if (nvm_alt_mac_addr_offset == 0xFFFF) {
-		/* There is no Alternate MAC Address */
-		goto out;
-	}
-
-	if (hw->bus.func == E1000_FUNC_1)
-		nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
-	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
-		offset = nvm_alt_mac_addr_offset + (i >> 1);
-		ret_val = e1000e_read_nvm(hw, offset, 1, &nvm_data);
-		if (ret_val) {
-			e_dbg("NVM Read Error\n");
-			goto out;
-		}
-
-		alt_mac_addr[i] = (u8)(nvm_data & 0xFF);
-		alt_mac_addr[i + 1] = (u8)(nvm_data >> 8);
-	}
-
-	/* if multicast bit is set, the alternate address will not be used */
-	if (alt_mac_addr[0] & 0x01) {
-		e_dbg("Ignoring Alternate Mac Address with MC bit set\n");
-		goto out;
-	}
-
-	/*
-	 * We have a valid alternate MAC address, and we want to treat it the
-	 * same as the normal permanent MAC address stored by the HW into the
-	 * RAR. Do this by mapping this address into RAR0.
-	 */
-	hw->mac.ops.rar_set(hw, alt_mac_addr, 0);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_rar_set - Set receive address register
- *  @hw: pointer to the HW structure
- *  @addr: pointer to the receive address
- *  @index: receive address array register
- *
- *  Sets the receive address array register at index to the address passed
- *  in by addr.
- **/
-void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
-{
-	u32 rar_low, rar_high;
-
-	/*
-	 * HW expects these in little endian so we reverse the byte order
-	 * from network order (big endian) to little endian
-	 */
-	rar_low = ((u32) addr[0] |
-	           ((u32) addr[1] << 8) |
-	           ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
-
-	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
-
-	/* If MAC address zero, no need to set the AV bit */
-	if (rar_low || rar_high)
-		rar_high |= E1000_RAH_AV;
-
-	/*
-	 * Some bridges will combine consecutive 32-bit writes into
-	 * a single burst write, which will malfunction on some parts.
-	 * The flushes avoid this.
-	 */
-	ew32(RAL(index), rar_low);
-	e1e_flush();
-	ew32(RAH(index), rar_high);
-	e1e_flush();
-}
-
-/**
- *  e1000e_mta_set_generic - Set multicast filter table address
- *  @hw: pointer to the HW structure
- *  @hash_value: determines the MTA register and bit to set
- *
- *  The multicast table address is a register array of 32-bit registers.
- *  The hash_value is used to determine what register the bit is in, the
- *  current value is read, the new bit is OR'd in and the new value is
- *  written back into the register.
- **/
-void e1000e_mta_set_generic(struct e1000_hw *hw, u32 hash_value)
-{
-	u32 hash_bit, hash_reg, mta;
-
-	/*
-	 * The MTA is a register array of 32-bit registers. It is
-	 * treated like an array of (32*mta_reg_count) bits.  We want to
-	 * set bit BitArray[hash_value]. So we figure out what register
-	 * the bit is in, read it, OR in the new bit, then write
-	 * back the new value.  The (hw->mac.mta_reg_count - 1) serves as a
-	 * mask to bits 31:5 of the hash value which gives us the
-	 * register we're modifying.  The hash bit within that register
-	 * is determined by the lower 5 bits of the hash value.
-	 */
-	hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
-	hash_bit = hash_value & 0x1F;
-
-	mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg);
-
-	mta |= (1 << hash_bit);
-
-	E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta);
-	e1e_flush();
-}
-
-/**
- *  e1000e_update_mc_addr_list_generic - Update Multicast addresses
- *  @hw: pointer to the HW structure
- *  @mc_addr_list: array of multicast addresses to program
- *  @mc_addr_count: number of multicast addresses to program
- *
- *  Updates entire Multicast Table Array.
- *  The caller must have a packed mc_addr_list of multicast addresses.
- **/
-void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
-                                       u8 *mc_addr_list, u32 mc_addr_count)
-{
-	u32 hash_value, hash_bit, hash_reg;
-	int i;
-
-	/* clear mta_shadow */
-	memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
-
-	/* update mta_shadow from mc_addr_list */
-	for (i = 0; (u32) i < mc_addr_count; i++) {
-		hash_value = e1000e_hash_mc_addr_generic(hw, mc_addr_list);
-
-		hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
-		hash_bit = hash_value & 0x1F;
-
-		hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
-		mc_addr_list += (ETH_ADDR_LEN);
-	}
-
-	/* replace the entire MTA table */
-	for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]);
-	e1e_flush();
-}
-
-/**
- *  e1000e_hash_mc_addr_generic - Generate a multicast hash value
- *  @hw: pointer to the HW structure
- *  @mc_addr: pointer to a multicast address
- *
- *  Generates a multicast address hash value which is used to determine
- *  the multicast filter table array address and new table value.  See
- *  e1000e_mta_set_generic()
- **/
-static u32 e1000e_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr)
-{
-	u32 hash_value, hash_mask;
-	u8 bit_shift = 0;
-
-	/* Register count multiplied by bits per register */
-	hash_mask = (hw->mac.mta_reg_count * 32) - 1;
-
-	/*
-	 * For a mc_filter_type of 0, bit_shift is the number of left-shifts
-	 * where 0xFF would still fall within the hash mask.
-	 */
-	while (hash_mask >> bit_shift != 0xFF)
-		bit_shift++;
-
-	/*
-	 * The portion of the address that is used for the hash table
-	 * is determined by the mc_filter_type setting.
-	 * The algorithm is such that there is a total of 8 bits of shifting.
-	 * The bit_shift for a mc_filter_type of 0 represents the number of
-	 * left-shifts where the MSB of mc_addr[5] would still fall within
-	 * the hash_mask.  Case 0 does this exactly.  Since there are a total
-	 * of 8 bits of shifting, then mc_addr[4] will shift right the
-	 * remaining number of bits. Thus 8 - bit_shift.  The rest of the
-	 * cases are a variation of this algorithm...essentially raising the
-	 * number of bits to shift mc_addr[5] left, while still keeping the
-	 * 8-bit shifting total.
-	 *
-	 * For example, given the following Destination MAC Address and an
-	 * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
-	 * we can see that the bit_shift for case 0 is 4.  These are the hash
-	 * values resulting from each mc_filter_type...
-	 * [0] [1] [2] [3] [4] [5]
-	 * 01  AA  00  12  34  56
-	 * LSB                 MSB
-	 *
-	 * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
-	 * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
-	 * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
-	 * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
-	 */
-	switch (hw->mac.mc_filter_type) {
-	default:
-	case 0:
-		break;
-	case 1:
-		bit_shift += 1;
-		break;
-	case 2:
-		bit_shift += 2;
-		break;
-	case 3:
-		bit_shift += 4;
-		break;
-	}
-
-	hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
-	                          (((u16) mc_addr[5]) << bit_shift)));
-
-	return hash_value;
-}
-
-/**
- *  e1000e_clear_hw_cntrs_base - Clear base hardware counters
- *  @hw: pointer to the HW structure
- *
- *  Clears the base hardware counters by reading the counter registers.
- **/
-void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw __unused)
-{
-#if 0
-	er32(CRCERRS);
-	er32(SYMERRS);
-	er32(MPC);
-	er32(SCC);
-	er32(ECOL);
-	er32(MCC);
-	er32(LATECOL);
-	er32(COLC);
-	er32(DC);
-	er32(SEC);
-	er32(RLEC);
-	er32(XONRXC);
-	er32(XONTXC);
-	er32(XOFFRXC);
-	er32(XOFFTXC);
-	er32(FCRUC);
-	er32(GPRC);
-	er32(BPRC);
-	er32(MPRC);
-	er32(GPTC);
-	er32(GORCL);
-	er32(GORCH);
-	er32(GOTCL);
-	er32(GOTCH);
-	er32(RNBC);
-	er32(RUC);
-	er32(RFC);
-	er32(ROC);
-	er32(RJC);
-	er32(TORL);
-	er32(TORH);
-	er32(TOTL);
-	er32(TOTH);
-	er32(TPR);
-	er32(TPT);
-	er32(MPTC);
-	er32(BPTC);
-#endif
-}
-
-/**
- *  e1000e_check_for_copper_link - Check for link (Copper)
- *  @hw: pointer to the HW structure
- *
- *  Checks to see of the link status of the hardware has changed.  If a
- *  change in link status has been detected, then we read the PHY registers
- *  to get the current speed/duplex if link exists.
- **/
-s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val;
-	bool link;
-
-	/*
-	 * We only want to go out to the PHY registers to see if Auto-Neg
-	 * has completed and/or if our link status has changed.  The
-	 * get_link_status flag is set upon receiving a Link Status
-	 * Change or Rx Sequence Error interrupt.
-	 */
-	if (!mac->get_link_status) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	/*
-	 * First we want to see if the MII Status Register reports
-	 * link.  If so, then we want to get the current speed/duplex
-	 * of the PHY.
-	 */
-	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		goto out;
-
-	if (!link)
-		goto out; /* No link detected */
-
-	mac->get_link_status = false;
-
-	/*
-	 * Check if there was DownShift, must be checked
-	 * immediately after link-up
-	 */
-	e1000e_check_downshift(hw);
-
-	/*
-	 * If we are forcing speed/duplex, then we simply return since
-	 * we have already determined whether we have link or not.
-	 */
-	if (!mac->autoneg) {
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	/*
-	 * Auto-Neg is enabled.  Auto Speed Detection takes care
-	 * of MAC speed/duplex configuration.  So we only need to
-	 * configure Collision Distance in the MAC.
-	 */
-	e1000e_config_collision_dist(hw);
-
-	/*
-	 * Configure Flow Control now that Auto-Neg has completed.
-	 * First, we need to restore the desired flow control
-	 * settings because we may have had to re-autoneg with a
-	 * different link partner.
-	 */
-	ret_val = e1000e_config_fc_after_link_up(hw);
-	if (ret_val)
-		e_dbg("Error configuring flow control\n");
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_check_for_fiber_link - Check for link (Fiber)
- *  @hw: pointer to the HW structure
- *
- *  Checks for link up on the hardware.  If link is not up and we have
- *  a signal, then we need to force link up.
- **/
-s32 e1000e_check_for_fiber_link(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 rxcw;
-	u32 ctrl;
-	u32 status;
-	s32 ret_val = E1000_SUCCESS;
-
-	ctrl = er32(CTRL);
-	status = er32(STATUS);
-	rxcw = er32(RXCW);
-
-	/*
-	 * If we don't have link (auto-negotiation failed or link partner
-	 * cannot auto-negotiate), the cable is plugged in (we have signal),
-	 * and our link partner is not trying to auto-negotiate with us (we
-	 * are receiving idles or data), we need to force link up. We also
-	 * need to give auto-negotiation time to complete, in case the cable
-	 * was just plugged in. The autoneg_failed flag does this.
-	 */
-	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
-	if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) &&
-	    (!(rxcw & E1000_RXCW_C))) {
-		if (mac->autoneg_failed == 0) {
-			mac->autoneg_failed = 1;
-			goto out;
-		}
-		e_dbg("NOT RXing /C/, disable AutoNeg and force link.\n");
-
-		/* Disable auto-negotiation in the TXCW register */
-		ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
-
-		/* Force link-up and also force full-duplex. */
-		ctrl = er32(CTRL);
-		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
-		ew32(CTRL, ctrl);
-
-		/* Configure Flow Control after forcing link up. */
-		ret_val = e1000e_config_fc_after_link_up(hw);
-		if (ret_val) {
-			e_dbg("Error configuring flow control\n");
-			goto out;
-		}
-	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
-		/*
-		 * If we are forcing link and we are receiving /C/ ordered
-		 * sets, re-enable auto-negotiation in the TXCW register
-		 * and disable forced link in the Device Control register
-		 * in an attempt to auto-negotiate with our link partner.
-		 */
-		e_dbg("RXing /C/, enable AutoNeg and stop forcing link.\n");
-		ew32(TXCW, mac->txcw);
-		ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
-
-		mac->serdes_has_link = true;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_check_for_serdes_link - Check for link (Serdes)
- *  @hw: pointer to the HW structure
- *
- *  Checks for link up on the hardware.  If link is not up and we have
- *  a signal, then we need to force link up.
- **/
-s32 e1000e_check_for_serdes_link(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 rxcw;
-	u32 ctrl;
-	u32 status;
-	s32 ret_val = E1000_SUCCESS;
-
-	ctrl = er32(CTRL);
-	status = er32(STATUS);
-	rxcw = er32(RXCW);
-
-	/*
-	 * If we don't have link (auto-negotiation failed or link partner
-	 * cannot auto-negotiate), and our link partner is not trying to
-	 * auto-negotiate with us (we are receiving idles or data),
-	 * we need to force link up. We also need to give auto-negotiation
-	 * time to complete.
-	 */
-	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
-	if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) {
-		if (mac->autoneg_failed == 0) {
-			mac->autoneg_failed = 1;
-			goto out;
-		}
-		e_dbg("NOT RXing /C/, disable AutoNeg and force link.\n");
-
-		/* Disable auto-negotiation in the TXCW register */
-		ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
-
-		/* Force link-up and also force full-duplex. */
-		ctrl = er32(CTRL);
-		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
-		ew32(CTRL, ctrl);
-
-		/* Configure Flow Control after forcing link up. */
-		ret_val = e1000e_config_fc_after_link_up(hw);
-		if (ret_val) {
-			e_dbg("Error configuring flow control\n");
-			goto out;
-		}
-	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
-		/*
-		 * If we are forcing link and we are receiving /C/ ordered
-		 * sets, re-enable auto-negotiation in the TXCW register
-		 * and disable forced link in the Device Control register
-		 * in an attempt to auto-negotiate with our link partner.
-		 */
-		e_dbg("RXing /C/, enable AutoNeg and stop forcing link.\n");
-		ew32(TXCW, mac->txcw);
-		ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
-
-		mac->serdes_has_link = true;
-	} else if (!(E1000_TXCW_ANE & er32(TXCW))) {
-		/*
-		 * If we force link for non-auto-negotiation switch, check
-		 * link status based on MAC synchronization for internal
-		 * serdes media type.
-		 */
-		/* SYNCH bit and IV bit are sticky. */
-		udelay(10);
-		rxcw = er32(RXCW);
-		if (rxcw & E1000_RXCW_SYNCH) {
-			if (!(rxcw & E1000_RXCW_IV)) {
-				mac->serdes_has_link = true;
-				e_dbg("SERDES: Link up - forced.\n");
-			}
-		} else {
-			mac->serdes_has_link = false;
-			e_dbg("SERDES: Link down - force failed.\n");
-		}
-	}
-
-	if (E1000_TXCW_ANE & er32(TXCW)) {
-		status = er32(STATUS);
-		if (status & E1000_STATUS_LU) {
-			/* SYNCH bit and IV bit are sticky, so reread rxcw. */
-			udelay(10);
-			rxcw = er32(RXCW);
-			if (rxcw & E1000_RXCW_SYNCH) {
-				if (!(rxcw & E1000_RXCW_IV)) {
-					mac->serdes_has_link = true;
-					e_dbg("SERDES: Link up - autoneg "
-					   "completed sucessfully.\n");
-				} else {
-					mac->serdes_has_link = false;
-					e_dbg("SERDES: Link down - invalid"
-					   "codewords detected in autoneg.\n");
-				}
-			} else {
-				mac->serdes_has_link = false;
-				e_dbg("SERDES: Link down - no sync.\n");
-			}
-		} else {
-			mac->serdes_has_link = false;
-			e_dbg("SERDES: Link down - autoneg failed\n");
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_setup_link - Setup flow control and link settings
- *  @hw: pointer to the HW structure
- *
- *  Determines which flow control settings to use, then configures flow
- *  control.  Calls the appropriate media-specific link configuration
- *  function.  Assuming the adapter has a valid link partner, a valid link
- *  should be established.  Assumes the hardware has previously been reset
- *  and the transmitter and receiver are not enabled.
- **/
-s32 e1000e_setup_link(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	/*
-	 * In the case of the phy reset being blocked, we already have a link.
-	 * We do not need to set it up again.
-	 */
-	if (hw->phy.ops.check_reset_block)
-		if (e1000e_check_reset_block(hw))
-			goto out;
-
-	/*
-	 * If requested flow control is set to default, set flow control
-	 * based on the EEPROM flow control settings.
-	 */
-	if (hw->fc.requested_mode == e1000_fc_default) {
-		ret_val = e1000e_set_default_fc_generic(hw);
-		if (ret_val)
-			goto out;
-	}
-
-	/*
-	 * Save off the requested flow control mode for use later.  Depending
-	 * on the link partner's capabilities, we may or may not use this mode.
-	 */
-	hw->fc.current_mode = hw->fc.requested_mode;
-
-	e_dbg("After fix-ups FlowControl is now = %x\n",
-		hw->fc.current_mode);
-
-	/* Call the necessary media_type subroutine to configure the link. */
-	ret_val = hw->mac.ops.setup_physical_interface(hw);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Initialize the flow control address, type, and PAUSE timer
-	 * registers to their default values.  This is done even if flow
-	 * control is disabled, because it does not hurt anything to
-	 * initialize these registers.
-	 */
-	e_dbg("Initializing the Flow Control address, type and timer regs\n");
-	ew32(FCT, FLOW_CONTROL_TYPE);
-	ew32(FCAH, FLOW_CONTROL_ADDRESS_HIGH);
-	ew32(FCAL, FLOW_CONTROL_ADDRESS_LOW);
-
-	ew32(FCTTV, hw->fc.pause_time);
-
-	ret_val = e1000e_set_fc_watermarks(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_setup_fiber_serdes_link - Setup link for fiber/serdes
- *  @hw: pointer to the HW structure
- *
- *  Configures collision distance and flow control for fiber and serdes
- *  links.  Upon successful setup, poll for link.
- **/
-s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val = E1000_SUCCESS;
-
-	ctrl = er32(CTRL);
-
-	/* Take the link out of reset */
-	ctrl &= ~E1000_CTRL_LRST;
-
-	e1000e_config_collision_dist(hw);
-
-	ret_val = e1000e_commit_fc_settings_generic(hw);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Since auto-negotiation is enabled, take the link out of reset (the
-	 * link will be in reset, because we previously reset the chip). This
-	 * will restart auto-negotiation.  If auto-negotiation is successful
-	 * then the link-up status bit will be set and the flow control enable
-	 * bits (RFCE and TFCE) will be set according to their negotiated value.
-	 */
-	e_dbg("Auto-negotiation enabled\n");
-
-	ew32(CTRL, ctrl);
-	e1e_flush();
-	msleep(1);
-
-	/*
-	 * For these adapters, the SW definable pin 1 is set when the optics
-	 * detect a signal.  If we have a signal, then poll for a "Link-Up"
-	 * indication.
-	 */
-	if (hw->phy.media_type == e1000_media_type_internal_serdes ||
-	    (er32(CTRL) & E1000_CTRL_SWDPIN1)) {
-		ret_val = e1000e_poll_fiber_serdes_link_generic(hw);
-	} else {
-		e_dbg("No signal detected\n");
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_config_collision_dist - Configure collision distance
- *  @hw: pointer to the HW structure
- *
- *  Configures the collision distance to the default value and is used
- *  during link setup. Currently no func pointer exists and all
- *  implementations are handled in the generic version of this function.
- **/
-void e1000e_config_collision_dist(struct e1000_hw *hw)
-{
-	u32 tctl;
-
-	tctl = er32(TCTL);
-
-	tctl &= ~E1000_TCTL_COLD;
-	tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
-
-	ew32(TCTL, tctl);
-	e1e_flush();
-}
-
-/**
- *  e1000e_poll_fiber_serdes_link_generic - Poll for link up
- *  @hw: pointer to the HW structure
- *
- *  Polls for link up by reading the status register, if link fails to come
- *  up with auto-negotiation, then the link is forced if a signal is detected.
- **/
-static s32 e1000e_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 i, status;
-	s32 ret_val = E1000_SUCCESS;
-
-	/*
-	 * If we have a signal (the cable is plugged in, or assumed true for
-	 * serdes media) then poll for a "Link-Up" indication in the Device
-	 * Status Register.  Time-out if a link isn't seen in 500 milliseconds
-	 * seconds (Auto-negotiation should complete in less than 500
-	 * milliseconds even if the other end is doing it in SW).
-	 */
-	for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
-		msleep(10);
-		status = er32(STATUS);
-		if (status & E1000_STATUS_LU)
-			break;
-	}
-	if (i == FIBER_LINK_UP_LIMIT) {
-		e_dbg("Never got a valid link from auto-neg!!!\n");
-		mac->autoneg_failed = 1;
-		/*
-		 * AutoNeg failed to achieve a link, so we'll call
-		 * mac->check_for_link. This routine will force the
-		 * link up if we detect a signal. This will allow us to
-		 * communicate with non-autonegotiating link partners.
-		 */
-		ret_val = hw->mac.ops.check_for_link(hw);
-		if (ret_val) {
-			e_dbg("Error while checking for link\n");
-			goto out;
-		}
-		mac->autoneg_failed = 0;
-	} else {
-		mac->autoneg_failed = 0;
-		e_dbg("Valid Link Found\n");
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_commit_fc_settings_generic - Configure flow control
- *  @hw: pointer to the HW structure
- *
- *  Write the flow control settings to the Transmit Config Word Register (TXCW)
- *  base on the flow control settings in e1000_mac_info.
- **/
-static s32 e1000e_commit_fc_settings_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 txcw;
-	s32 ret_val = E1000_SUCCESS;
-
-	/*
-	 * Check for a software override of the flow control settings, and
-	 * setup the device accordingly.  If auto-negotiation is enabled, then
-	 * software will have to set the "PAUSE" bits to the correct value in
-	 * the Transmit Config Word Register (TXCW) and re-start auto-
-	 * negotiation.  However, if auto-negotiation is disabled, then
-	 * software will have to manually configure the two flow control enable
-	 * bits in the CTRL register.
-	 *
-	 * The possible values of the "fc" parameter are:
-	 *      0:  Flow control is completely disabled
-	 *      1:  Rx flow control is enabled (we can receive pause frames,
-	 *          but not send pause frames).
-	 *      2:  Tx flow control is enabled (we can send pause frames but we
-	 *          do not support receiving pause frames).
-	 *      3:  Both Rx and Tx flow control (symmetric) are enabled.
-	 */
-	switch (hw->fc.current_mode) {
-	case e1000_fc_none:
-		/* Flow control completely disabled by a software over-ride. */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
-		break;
-	case e1000_fc_rx_pause:
-		/*
-		 * Rx Flow control is enabled and Tx Flow control is disabled
-		 * by a software over-ride. Since there really isn't a way to
-		 * advertise that we are capable of Rx Pause ONLY, we will
-		 * advertise that we support both symmetric and asymmetric RX
-		 * PAUSE.  Later, we will disable the adapter's ability to send
-		 * PAUSE frames.
-		 */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
-		break;
-	case e1000_fc_tx_pause:
-		/*
-		 * Tx Flow control is enabled, and Rx Flow control is disabled,
-		 * by a software over-ride.
-		 */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
-		break;
-	case e1000_fc_full:
-		/*
-		 * Flow control (both Rx and Tx) is enabled by a software
-		 * over-ride.
-		 */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
-		break;
-	default:
-		e_dbg("Flow control param set incorrectly\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-		break;
-	}
-
-	ew32(TXCW, txcw);
-	mac->txcw = txcw;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_set_fc_watermarks - Set flow control high/low watermarks
- *  @hw: pointer to the HW structure
- *
- *  Sets the flow control high/low threshold (watermark) registers.  If
- *  flow control XON frame transmission is enabled, then set XON frame
- *  transmission as well.
- **/
-s32 e1000e_set_fc_watermarks(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u32 fcrtl = 0, fcrth = 0;
-
-	/*
-	 * Set the flow control receive threshold registers.  Normally,
-	 * these registers will be set to a default threshold that may be
-	 * adjusted later by the driver's runtime code.  However, if the
-	 * ability to transmit pause frames is not enabled, then these
-	 * registers will be set to 0.
-	 */
-	if (hw->fc.current_mode & e1000_fc_tx_pause) {
-		/*
-		 * We need to set up the Receive Threshold high and low water
-		 * marks as well as (optionally) enabling the transmission of
-		 * XON frames.
-		 */
-		fcrtl = hw->fc.low_water;
-		if (hw->fc.send_xon)
-			fcrtl |= E1000_FCRTL_XONE;
-
-		fcrth = hw->fc.high_water;
-	}
-	ew32(FCRTL, fcrtl);
-	ew32(FCRTH, fcrth);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_set_default_fc_generic - Set flow control default values
- *  @hw: pointer to the HW structure
- *
- *  Read the EEPROM for the default values for flow control and store the
- *  values.
- **/
-static s32 e1000e_set_default_fc_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 nvm_data;
-
-	/*
-	 * Read and store word 0x0F of the EEPROM. This word contains bits
-	 * that determine the hardware's default PAUSE (flow control) mode,
-	 * a bit that determines whether the HW defaults to enabling or
-	 * disabling auto-negotiation, and the direction of the
-	 * SW defined pins. If there is no SW over-ride of the flow
-	 * control setting, then the variable hw->fc will
-	 * be initialized based on a value in the EEPROM.
-	 */
-	ret_val = e1000e_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
-
-	if (ret_val) {
-		e_dbg("NVM Read Error\n");
-		goto out;
-	}
-
-	if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
-		hw->fc.requested_mode = e1000_fc_none;
-	else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
-		 NVM_WORD0F_ASM_DIR)
-		hw->fc.requested_mode = e1000_fc_tx_pause;
-	else
-		hw->fc.requested_mode = e1000_fc_full;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_force_mac_fc - Force the MAC's flow control settings
- *  @hw: pointer to the HW structure
- *
- *  Force the MAC's flow control settings.  Sets the TFCE and RFCE bits in the
- *  device control register to reflect the adapter settings.  TFCE and RFCE
- *  need to be explicitly set by software when a copper PHY is used because
- *  autonegotiation is managed by the PHY rather than the MAC.  Software must
- *  also configure these bits when link is forced on a fiber connection.
- **/
-s32 e1000e_force_mac_fc(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val = E1000_SUCCESS;
-
-	ctrl = er32(CTRL);
-
-	/*
-	 * Because we didn't get link via the internal auto-negotiation
-	 * mechanism (we either forced link or we got link via PHY
-	 * auto-neg), we have to manually enable/disable transmit an
-	 * receive flow control.
-	 *
-	 * The "Case" statement below enables/disable flow control
-	 * according to the "hw->fc.current_mode" parameter.
-	 *
-	 * The possible values of the "fc" parameter are:
-	 *      0:  Flow control is completely disabled
-	 *      1:  Rx flow control is enabled (we can receive pause
-	 *          frames but not send pause frames).
-	 *      2:  Tx flow control is enabled (we can send pause frames
-	 *          frames but we do not receive pause frames).
-	 *      3:  Both Rx and Tx flow control (symmetric) is enabled.
-	 *  other:  No other values should be possible at this point.
-	 */
-	e_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode);
-
-	switch (hw->fc.current_mode) {
-	case e1000_fc_none:
-		ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
-		break;
-	case e1000_fc_rx_pause:
-		ctrl &= (~E1000_CTRL_TFCE);
-		ctrl |= E1000_CTRL_RFCE;
-		break;
-	case e1000_fc_tx_pause:
-		ctrl &= (~E1000_CTRL_RFCE);
-		ctrl |= E1000_CTRL_TFCE;
-		break;
-	case e1000_fc_full:
-		ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
-		break;
-	default:
-		e_dbg("Flow control param set incorrectly\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	ew32(CTRL, ctrl);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_config_fc_after_link_up - Configures flow control after link
- *  @hw: pointer to the HW structure
- *
- *  Checks the status of auto-negotiation after link up to ensure that the
- *  speed and duplex were not forced.  If the link needed to be forced, then
- *  flow control needs to be forced also.  If auto-negotiation is enabled
- *  and did not fail, then we configure flow control based on our link
- *  partner.
- **/
-s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val = E1000_SUCCESS;
-	u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
-	u16 speed, duplex;
-
-	/*
-	 * Check for the case where we have fiber media and auto-neg failed
-	 * so we had to force link.  In this case, we need to force the
-	 * configuration of the MAC to match the "fc" parameter.
-	 */
-	if (mac->autoneg_failed) {
-		if (hw->phy.media_type == e1000_media_type_fiber ||
-		    hw->phy.media_type == e1000_media_type_internal_serdes)
-			ret_val = e1000e_force_mac_fc(hw);
-	} else {
-		if (hw->phy.media_type == e1000_media_type_copper)
-			ret_val = e1000e_force_mac_fc(hw);
-	}
-
-	if (ret_val) {
-		e_dbg("Error forcing flow control settings\n");
-		goto out;
-	}
-
-	/*
-	 * Check for the case where we have copper media and auto-neg is
-	 * enabled.  In this case, we need to check and see if Auto-Neg
-	 * has completed, and if so, how the PHY and link partner has
-	 * flow control configured.
-	 */
-	if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) {
-		/*
-		 * Read the MII Status Register and check to see if AutoNeg
-		 * has completed.  We read this twice because this reg has
-		 * some "sticky" (latched) bits.
-		 */
-		ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
-		if (ret_val)
-			goto out;
-		ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
-		if (ret_val)
-			goto out;
-
-		if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
-			e_dbg("Copper PHY and Auto Neg "
-			         "has not completed.\n");
-			goto out;
-		}
-
-		/*
-		 * The AutoNeg process has completed, so we now need to
-		 * read both the Auto Negotiation Advertisement
-		 * Register (Address 4) and the Auto_Negotiation Base
-		 * Page Ability Register (Address 5) to determine how
-		 * flow control was negotiated.
-		 */
-		ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV,
-		                             &mii_nway_adv_reg);
-		if (ret_val)
-			goto out;
-		ret_val = e1e_rphy(hw, PHY_LP_ABILITY,
-		                             &mii_nway_lp_ability_reg);
-		if (ret_val)
-			goto out;
-
-		/*
-		 * Two bits in the Auto Negotiation Advertisement Register
-		 * (Address 4) and two bits in the Auto Negotiation Base
-		 * Page Ability Register (Address 5) determine flow control
-		 * for both the PHY and the link partner.  The following
-		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
-		 * 1999, describes these PAUSE resolution bits and how flow
-		 * control is determined based upon these settings.
-		 * NOTE:  DC = Don't Care
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
-		 *-------|---------|-------|---------|--------------------
-		 *   0   |    0    |  DC   |   DC    | e1000_fc_none
-		 *   0   |    1    |   0   |   DC    | e1000_fc_none
-		 *   0   |    1    |   1   |    0    | e1000_fc_none
-		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
-		 *   1   |    0    |   0   |   DC    | e1000_fc_none
-		 *   1   |   DC    |   1   |   DC    | e1000_fc_full
-		 *   1   |    1    |   0   |    0    | e1000_fc_none
-		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
-		 *
-		 * Are both PAUSE bits set to 1?  If so, this implies
-		 * Symmetric Flow Control is enabled at both ends.  The
-		 * ASM_DIR bits are irrelevant per the spec.
-		 *
-		 * For Symmetric Flow Control:
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-		 *-------|---------|-------|---------|--------------------
-		 *   1   |   DC    |   1   |   DC    | E1000_fc_full
-		 *
-		 */
-		if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-		    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
-			/*
-			 * Now we need to check if the user selected Rx ONLY
-			 * of pause frames.  In this case, we had to advertise
-			 * FULL flow control because we could not advertise RX
-			 * ONLY. Hence, we must now check to see if we need to
-			 * turn OFF  the TRANSMISSION of PAUSE frames.
-			 */
-			if (hw->fc.requested_mode == e1000_fc_full) {
-				hw->fc.current_mode = e1000_fc_full;
-				e_dbg("Flow Control = FULL.\r\n");
-			} else {
-				hw->fc.current_mode = e1000_fc_rx_pause;
-				e_dbg("Flow Control = "
-				         "RX PAUSE frames only.\r\n");
-			}
-		}
-		/*
-		 * For receiving PAUSE frames ONLY.
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-		 *-------|---------|-------|---------|--------------------
-		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
-		 */
-		else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-		          (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
-		          (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
-		          (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
-			hw->fc.current_mode = e1000_fc_tx_pause;
-			e_dbg("Flow Control = TX PAUSE frames only.\r\n");
-		}
-		/*
-		 * For transmitting PAUSE frames ONLY.
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-		 *-------|---------|-------|---------|--------------------
-		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
-		 */
-		else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-		         (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
-		         !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
-		         (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
-			hw->fc.current_mode = e1000_fc_rx_pause;
-			e_dbg("Flow Control = RX PAUSE frames only.\r\n");
-		} else {
-			/*
-			 * Per the IEEE spec, at this point flow control
-			 * should be disabled.
-			 */
-			hw->fc.current_mode = e1000_fc_none;
-			e_dbg("Flow Control = NONE.\r\n");
-		}
-
-		/*
-		 * Now we need to do one last check...  If we auto-
-		 * negotiated to HALF DUPLEX, flow control should not be
-		 * enabled per IEEE 802.3 spec.
-		 */
-		ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
-		if (ret_val) {
-			e_dbg("Error getting link speed and duplex\n");
-			goto out;
-		}
-
-		if (duplex == HALF_DUPLEX)
-			hw->fc.current_mode = e1000_fc_none;
-
-		/*
-		 * Now we call a subroutine to actually force the MAC
-		 * controller to use the correct flow control settings.
-		 */
-		ret_val = e1000e_force_mac_fc(hw);
-		if (ret_val) {
-			e_dbg("Error forcing flow control settings\n");
-			goto out;
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_get_speed_and_duplex_copper - Retrieve current speed/duplex
- *  @hw: pointer to the HW structure
- *  @speed: stores the current speed
- *  @duplex: stores the current duplex
- *
- *  Read the status register for the current speed/duplex and store the current
- *  speed and duplex for copper connections.
- **/
-s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
-                                              u16 *duplex)
-{
-	u32 status;
-
-	status = er32(STATUS);
-	if (status & E1000_STATUS_SPEED_1000) {
-		*speed = SPEED_1000;
-		e_dbg("1000 Mbs, ");
-	} else if (status & E1000_STATUS_SPEED_100) {
-		*speed = SPEED_100;
-		e_dbg("100 Mbs, ");
-	} else {
-		*speed = SPEED_10;
-		e_dbg("10 Mbs, ");
-	}
-
-	if (status & E1000_STATUS_FD) {
-		*duplex = FULL_DUPLEX;
-		e_dbg("Full Duplex\n");
-	} else {
-		*duplex = HALF_DUPLEX;
-		e_dbg("Half Duplex\n");
-	}
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_get_speed_and_duplex_fiber_generic - Retrieve current speed/duplex
- *  @hw: pointer to the HW structure
- *  @speed: stores the current speed
- *  @duplex: stores the current duplex
- *
- *  Sets the speed and duplex to gigabit full duplex (the only possible option)
- *  for fiber/serdes links.
- **/
-s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw __unused,
-                                                    u16 *speed, u16 *duplex)
-{
-	*speed = SPEED_1000;
-	*duplex = FULL_DUPLEX;
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_get_hw_semaphore - Acquire hardware semaphore
- *  @hw: pointer to the HW structure
- *
- *  Acquire the HW semaphore to access the PHY or NVM
- **/
-s32 e1000e_get_hw_semaphore(struct e1000_hw *hw)
-{
-	u32 swsm;
-	s32 ret_val = E1000_SUCCESS;
-	s32 timeout = hw->nvm.word_size + 1;
-	s32 i = 0;
-
-	/* Get the SW semaphore */
-	while (i < timeout) {
-		swsm = er32(SWSM);
-		if (!(swsm & E1000_SWSM_SMBI))
-			break;
-
-		udelay(50);
-		i++;
-	}
-
-	if (i == timeout) {
-		e_dbg("Driver can't access device - SMBI bit is set.\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	/* Get the FW semaphore. */
-	for (i = 0; i < timeout; i++) {
-		swsm = er32(SWSM);
-		ew32(SWSM, swsm | E1000_SWSM_SWESMBI);
-
-		/* Semaphore acquired if bit latched */
-		if (er32(SWSM) & E1000_SWSM_SWESMBI)
-			break;
-
-		udelay(50);
-	}
-
-	if (i == timeout) {
-		/* Release semaphores */
-		e1000e_put_hw_semaphore(hw);
-		e_dbg("Driver can't access the NVM\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_put_hw_semaphore - Release hardware semaphore
- *  @hw: pointer to the HW structure
- *
- *  Release hardware semaphore used to access the PHY or NVM
- **/
-void e1000e_put_hw_semaphore(struct e1000_hw *hw)
-{
-	u32 swsm;
-
-	swsm = er32(SWSM);
-	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
-	ew32(SWSM, swsm);
-}
-/**
- *  e1000e_get_auto_rd_done - Check for auto read completion
- *  @hw: pointer to the HW structure
- *
- *  Check EEPROM for Auto Read done bit.
- **/
-s32 e1000e_get_auto_rd_done(struct e1000_hw *hw)
-{
-	s32 i = 0;
-	s32 ret_val = E1000_SUCCESS;
-
-	while (i < AUTO_READ_DONE_TIMEOUT) {
-		if (er32(EECD) & E1000_EECD_AUTO_RD)
-			break;
-		msleep(1);
-		i++;
-	}
-
-	if (i == AUTO_READ_DONE_TIMEOUT) {
-		e_dbg("Auto read by HW from NVM has not completed.\n");
-		ret_val = -E1000_ERR_RESET;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_valid_led_default - Verify a valid default LED config
- *  @hw: pointer to the HW structure
- *  @data: pointer to the NVM (EEPROM)
- *
- *  Read the EEPROM for the current default LED configuration.  If the
- *  LED configuration is not valid, set to a valid LED configuration.
- **/
-s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data)
-{
-	s32 ret_val;
-
-	ret_val = e1000e_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
-	if (ret_val) {
-		e_dbg("NVM Read Error\n");
-		goto out;
-	}
-
-	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
-		*data = ID_LED_DEFAULT;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_id_led_init -
- *  @hw: pointer to the HW structure
- *
- **/
-s32 e1000e_id_led_init(struct e1000_hw *hw __unused)
-{
-#if 0
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val;
-	const u32 ledctl_mask = 0x000000FF;
-	const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
-	const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
-	u16 data, i, temp;
-	const u16 led_mask = 0x0F;
-
-	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
-	if (ret_val)
-		goto out;
-
-	mac->ledctl_default = er32(LEDCTL);
-	mac->ledctl_mode1 = mac->ledctl_default;
-	mac->ledctl_mode2 = mac->ledctl_default;
-
-	for (i = 0; i < 4; i++) {
-		temp = (data >> (i << 2)) & led_mask;
-		switch (temp) {
-		case ID_LED_ON1_DEF2:
-		case ID_LED_ON1_ON2:
-		case ID_LED_ON1_OFF2:
-			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode1 |= ledctl_on << (i << 3);
-			break;
-		case ID_LED_OFF1_DEF2:
-		case ID_LED_OFF1_ON2:
-		case ID_LED_OFF1_OFF2:
-			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode1 |= ledctl_off << (i << 3);
-			break;
-		default:
-			/* Do nothing */
-			break;
-		}
-		switch (temp) {
-		case ID_LED_DEF1_ON2:
-		case ID_LED_ON1_ON2:
-		case ID_LED_OFF1_ON2:
-			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode2 |= ledctl_on << (i << 3);
-			break;
-		case ID_LED_DEF1_OFF2:
-		case ID_LED_ON1_OFF2:
-		case ID_LED_OFF1_OFF2:
-			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode2 |= ledctl_off << (i << 3);
-			break;
-		default:
-			/* Do nothing */
-			break;
-		}
-	}
-
-out:
-	return ret_val;
-#endif
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_setup_led_generic - Configures SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  This prepares the SW controllable LED for use and saves the current state
- *  of the LED so it can be later restored.
- **/
-s32 e1000e_setup_led_generic(struct e1000_hw *hw __unused)
-{
-#if 0
-	u32 ledctl;
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->mac.ops.setup_led != e1000e_setup_led_generic) {
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	if (hw->phy.media_type == e1000_media_type_fiber) {
-		ledctl = er32(LEDCTL);
-		hw->mac.ledctl_default = ledctl;
-		/* Turn off LED0 */
-		ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
-		            E1000_LEDCTL_LED0_BLINK |
-		            E1000_LEDCTL_LED0_MODE_MASK);
-		ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
-		           E1000_LEDCTL_LED0_MODE_SHIFT);
-		ew32(LEDCTL, ledctl);
-	} else if (hw->phy.media_type == e1000_media_type_copper) {
-		ew32(LEDCTL, hw->mac.ledctl_mode1);
-	}
-
-out:
-	return ret_val;
-#endif
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_cleanup_led_generic - Set LED config to default operation
- *  @hw: pointer to the HW structure
- *
- *  Remove the current LED configuration and set the LED configuration
- *  to the default value, saved from the EEPROM.
- **/
-s32 e1000e_cleanup_led_generic(struct e1000_hw *hw __unused)
-{
-#if 0
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->mac.ops.cleanup_led != e1000e_cleanup_led_generic) {
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	ew32(LEDCTL, hw->mac.ledctl_default);
-
-out:
-	return ret_val;
-#endif
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_blink_led - Blink LED
- *  @hw: pointer to the HW structure
- *
- *  Blink the LEDs which are set to be on.
- **/
-s32 e1000e_blink_led(struct e1000_hw *hw __unused)
-{
-#if 0
-	u32 ledctl_blink = 0;
-	u32 i;
-
-	if (hw->phy.media_type == e1000_media_type_fiber) {
-		/* always blink LED0 for PCI-E fiber */
-		ledctl_blink = E1000_LEDCTL_LED0_BLINK |
-		     (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
-	} else {
-		/*
-		 * set the blink bit for each LED that's "on" (0x0E)
-		 * in ledctl_mode2
-		 */
-		ledctl_blink = hw->mac.ledctl_mode2;
-		for (i = 0; i < 4; i++)
-			if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
-			    E1000_LEDCTL_MODE_LED_ON)
-				ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
-				                 (i * 8));
-	}
-
-	ew32(LEDCTL, ledctl_blink);
-#endif
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_led_on_generic - Turn LED on
- *  @hw: pointer to the HW structure
- *
- *  Turn LED on.
- **/
-s32 e1000e_led_on_generic(struct e1000_hw *hw __unused)
-{
-#if 0
-	u32 ctrl;
-
-	switch (hw->phy.media_type) {
-	case e1000_media_type_fiber:
-		ctrl = er32(CTRL);
-		ctrl &= ~E1000_CTRL_SWDPIN0;
-		ctrl |= E1000_CTRL_SWDPIO0;
-		ew32(CTRL, ctrl);
-		break;
-	case e1000_media_type_copper:
-		ew32(LEDCTL, hw->mac.ledctl_mode2);
-		break;
-	default:
-		break;
-	}
-#endif
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_led_off_generic - Turn LED off
- *  @hw: pointer to the HW structure
- *
- *  Turn LED off.
- **/
-s32 e1000e_led_off_generic(struct e1000_hw *hw __unused)
-{
-#if 0
-	u32 ctrl;
-
-	switch (hw->phy.media_type) {
-	case e1000_media_type_fiber:
-		ctrl = er32(CTRL);
-		ctrl |= E1000_CTRL_SWDPIN0;
-		ctrl |= E1000_CTRL_SWDPIO0;
-		ew32(CTRL, ctrl);
-		break;
-	case e1000_media_type_copper:
-		ew32(LEDCTL, hw->mac.ledctl_mode1);
-		break;
-	default:
-		break;
-	}
-#endif
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_set_pcie_no_snoop - Set PCI-express capabilities
- *  @hw: pointer to the HW structure
- *  @no_snoop: bitmap of snoop events
- *
- *  Set the PCI-express register to snoop for events enabled in 'no_snoop'.
- **/
-void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop)
-{
-	u32 gcr;
-
-	if (hw->bus.type != e1000_bus_type_pci_express)
-		goto out;
-
-	if (no_snoop) {
-		gcr = er32(GCR);
-		gcr &= ~(PCIE_NO_SNOOP_ALL);
-		gcr |= no_snoop;
-		ew32(GCR, gcr);
-	}
-out:
-	return;
-}
-
-/**
- *  e1000e_disable_pcie_master - Disables PCI-express master access
- *  @hw: pointer to the HW structure
- *
- *  Returns 0 (E1000_SUCCESS) if successful, else returns -10
- *  (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
- *  the master requests to be disabled.
- *
- *  Disables PCI-Express master access and verifies there are no pending
- *  requests.
- **/
-s32 e1000e_disable_pcie_master(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 timeout = MASTER_DISABLE_TIMEOUT;
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->bus.type != e1000_bus_type_pci_express)
-		goto out;
-
-	ctrl = er32(CTRL);
-	ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
-	ew32(CTRL, ctrl);
-
-	while (timeout) {
-		if (!(er32(STATUS) &
-		      E1000_STATUS_GIO_MASTER_ENABLE))
-			break;
-		udelay(100);
-		timeout--;
-	}
-
-	if (!timeout) {
-		e_dbg("Master requests are pending.\n");
-		ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_reset_adaptive - Reset Adaptive Interframe Spacing
- *  @hw: pointer to the HW structure
- *
- *  Reset the Adaptive Interframe Spacing throttle to default values.
- **/
-void e1000e_reset_adaptive(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-
-	if (!mac->adaptive_ifs) {
-		e_dbg("Not in Adaptive IFS mode!\n");
-		goto out;
-	}
-
-	mac->current_ifs_val = 0;
-	mac->ifs_min_val = IFS_MIN;
-	mac->ifs_max_val = IFS_MAX;
-	mac->ifs_step_size = IFS_STEP;
-	mac->ifs_ratio = IFS_RATIO;
-
-	mac->in_ifs_mode = false;
-	ew32(AIT, 0);
-out:
-	return;
-}
-
-/**
- *  e1000e_update_adaptive - Update Adaptive Interframe Spacing
- *  @hw: pointer to the HW structure
- *
- *  Update the Adaptive Interframe Spacing Throttle value based on the
- *  time between transmitted packets and time between collisions.
- **/
-void e1000e_update_adaptive(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-
-	if (!mac->adaptive_ifs) {
-		e_dbg("Not in Adaptive IFS mode!\n");
-		goto out;
-	}
-
-	if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
-		if (mac->tx_packet_delta > MIN_NUM_XMITS) {
-			mac->in_ifs_mode = true;
-			if (mac->current_ifs_val < mac->ifs_max_val) {
-				if (!mac->current_ifs_val)
-					mac->current_ifs_val = mac->ifs_min_val;
-				else
-					mac->current_ifs_val +=
-						mac->ifs_step_size;
-				ew32(AIT, mac->current_ifs_val);
-			}
-		}
-	} else {
-		if (mac->in_ifs_mode &&
-		    (mac->tx_packet_delta <= MIN_NUM_XMITS)) {
-			mac->current_ifs_val = 0;
-			mac->in_ifs_mode = false;
-			ew32(AIT, 0);
-		}
-	}
-out:
-	return;
-}
-
-/**
- *  e1000e_validate_mdi_setting_generic - Verify MDI/MDIx settings
- *  @hw: pointer to the HW structure
- *
- *  Verify that when not using auto-negotiation that MDI/MDIx is correctly
- *  set, which is forced to MDI mode only.
- **/
-static s32 e1000e_validate_mdi_setting_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) {
-		e_dbg("Invalid MDI setting detected\n");
-		hw->phy.mdix = 1;
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_mac.h b/roms/ipxe/src/drivers/net/e1000e/e1000e_mac.h
deleted file mode 100644
index 5b8a42517ad0c1212b5f75b0a599c25bd77c0a34..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_mac.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000E_MAC_H_
-#define _E1000E_MAC_H_
-
-/*
- * Functions that should not be called directly from drivers but can be used
- * by other files in this 'shared code'
- */
-void e1000e_init_mac_ops_generic(struct e1000_hw *hw);
-s32  e1000e_blink_led(struct e1000_hw *hw);
-s32  e1000e_check_for_copper_link(struct e1000_hw *hw);
-s32  e1000e_check_for_fiber_link(struct e1000_hw *hw);
-s32  e1000e_check_for_serdes_link(struct e1000_hw *hw);
-s32  e1000e_cleanup_led_generic(struct e1000_hw *hw);
-s32  e1000e_config_fc_after_link_up(struct e1000_hw *hw);
-s32  e1000e_disable_pcie_master(struct e1000_hw *hw);
-s32  e1000e_force_mac_fc(struct e1000_hw *hw);
-s32  e1000e_get_auto_rd_done(struct e1000_hw *hw);
-s32  e1000e_get_bus_info_pcie(struct e1000_hw *hw);
-void e1000e_set_lan_id_single_port(struct e1000_hw *hw);
-s32  e1000e_get_hw_semaphore(struct e1000_hw *hw);
-s32  e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
-                                               u16 *duplex);
-s32  e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw,
-                                                     u16 *speed, u16 *duplex);
-s32  e1000e_id_led_init(struct e1000_hw *hw);
-s32  e1000e_led_on_generic(struct e1000_hw *hw);
-s32  e1000e_led_off_generic(struct e1000_hw *hw);
-void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw,
-	                               u8 *mc_addr_list, u32 mc_addr_count);
-s32  e1000e_set_fc_watermarks(struct e1000_hw *hw);
-s32  e1000e_setup_fiber_serdes_link(struct e1000_hw *hw);
-s32  e1000e_setup_led_generic(struct e1000_hw *hw);
-s32  e1000e_setup_link(struct e1000_hw *hw);
-
-void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw);
-void e1000e_clear_vfta_generic(struct e1000_hw *hw);
-void e1000e_config_collision_dist(struct e1000_hw *hw);
-void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
-void e1000e_mta_set_generic(struct e1000_hw *hw, u32 hash_value);
-void e1000e_pcix_mmrbc_workaround_generic(struct e1000_hw *hw);
-void e1000e_put_hw_semaphore(struct e1000_hw *hw);
-void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
-s32  e1000e_check_alt_mac_addr_generic(struct e1000_hw *hw);
-void e1000e_reset_adaptive(struct e1000_hw *hw);
-void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop);
-void e1000e_update_adaptive(struct e1000_hw *hw);
-void e1000e_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_main.c b/roms/ipxe/src/drivers/net/e1000e/e1000e_main.c
deleted file mode 100644
index e5cb2490a87d07094906cb5960ce9bce6e9ba55d..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_main.c
+++ /dev/null
@@ -1,1265 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  Portions Copyright(c) 2010 Marty Connor <mdc@etherboot.org>
-  Portions Copyright(c) 2010 Entity Cyber, Inc.
-  Portions Copyright(c) 2010 Northrop Grumman Corporation
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include "e1000e.h"
-
-static s32 e1000e_get_variants_82571(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	static int global_quad_port_a; /* global port a indication */
-	struct pci_device *pdev = adapter->pdev;
-	u16 eeprom_data = 0;
-	int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1;
-
-	/* tag quad port adapters first, it's used below */
-	switch (pdev->device) {
-	case E1000_DEV_ID_82571EB_QUAD_COPPER:
-	case E1000_DEV_ID_82571EB_QUAD_FIBER:
-	case E1000_DEV_ID_82571EB_QUAD_COPPER_LP:
-	case E1000_DEV_ID_82571PT_QUAD_COPPER:
-		adapter->flags |= FLAG_IS_QUAD_PORT;
-		/* mark the first port */
-		if (global_quad_port_a == 0)
-			adapter->flags |= FLAG_IS_QUAD_PORT_A;
-		/* Reset for multiple quad port adapters */
-		global_quad_port_a++;
-		if (global_quad_port_a == 4)
-			global_quad_port_a = 0;
-		break;
-	default:
-		break;
-	}
-
-	switch (adapter->hw.mac.type) {
-	case e1000_82571:
-		/* these dual ports don't have WoL on port B at all */
-		if (((pdev->device == E1000_DEV_ID_82571EB_FIBER) ||
-		     (pdev->device == E1000_DEV_ID_82571EB_SERDES) ||
-		     (pdev->device == E1000_DEV_ID_82571EB_COPPER)) &&
-		    (is_port_b))
-			adapter->flags &= ~FLAG_HAS_WOL;
-		/* quad ports only support WoL on port A */
-		if (adapter->flags & FLAG_IS_QUAD_PORT &&
-		    (!(adapter->flags & FLAG_IS_QUAD_PORT_A)))
-			adapter->flags &= ~FLAG_HAS_WOL;
-		/* Does not support WoL on any port */
-		if (pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD)
-			adapter->flags &= ~FLAG_HAS_WOL;
-		break;
-
-	case e1000_82573:
-		if (pdev->device == E1000_DEV_ID_82573L) {
-			if (e1000e_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1,
-					   &eeprom_data) < 0)
-				break;
-			if (!(eeprom_data & NVM_WORD1A_ASPM_MASK)) {
-				adapter->flags |= FLAG_HAS_JUMBO_FRAMES;
-				adapter->max_hw_frame_size = DEFAULT_JUMBO;
-			}
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static struct e1000_info e1000_82571_info = {
-	.mac			= e1000_82571,
-	.flags			= FLAG_HAS_HW_VLAN_FILTER
-				  | FLAG_HAS_JUMBO_FRAMES
-				  | FLAG_HAS_WOL
-				  | FLAG_APME_IN_CTRL3
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_CTRLEXT_ON_LOAD
-				  | FLAG_HAS_SMART_POWER_DOWN
-				  | FLAG_RESET_OVERWRITES_LAA /* errata */
-				  | FLAG_TARC_SPEED_MODE_BIT /* errata */
-				  | FLAG_APME_CHECK_PORT_B,
-	.pba			= 38,
-	.max_hw_frame_size	= DEFAULT_JUMBO,
-	.init_ops		= e1000e_init_function_pointers_82571,
-	.get_variants		= e1000e_get_variants_82571,
-};
-
-static struct e1000_info e1000_82572_info = {
-	.mac			= e1000_82572,
-	.flags			= FLAG_HAS_HW_VLAN_FILTER
-				  | FLAG_HAS_JUMBO_FRAMES
-				  | FLAG_HAS_WOL
-				  | FLAG_APME_IN_CTRL3
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_CTRLEXT_ON_LOAD
-				  | FLAG_TARC_SPEED_MODE_BIT, /* errata */
-	.pba			= 38,
-	.max_hw_frame_size	= DEFAULT_JUMBO,
-	.init_ops		= e1000e_init_function_pointers_82571,
-	.get_variants		= e1000e_get_variants_82571,
-};
-
-static struct e1000_info e1000_82573_info = {
-	.mac			= e1000_82573,
-	.flags			= FLAG_HAS_HW_VLAN_FILTER
-				  | FLAG_HAS_WOL
-				  | FLAG_APME_IN_CTRL3
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_SMART_POWER_DOWN
-				  | FLAG_HAS_AMT
-				  | FLAG_HAS_ERT
-				  | FLAG_HAS_SWSM_ON_LOAD,
-	.pba			= 20,
-	.max_hw_frame_size	= ETH_FRAME_LEN + ETH_FCS_LEN,
-	.init_ops		= e1000e_init_function_pointers_82571,
-	.get_variants		= e1000e_get_variants_82571,
-};
-
-static struct e1000_info e1000_82574_info = {
-	.mac			= e1000_82574,
-	.flags			= FLAG_HAS_HW_VLAN_FILTER
-#ifdef CONFIG_E1000E_MSIX
-				  | FLAG_HAS_MSIX
-#endif
-				  | FLAG_HAS_JUMBO_FRAMES
-				  | FLAG_HAS_WOL
-				  | FLAG_APME_IN_CTRL3
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_SMART_POWER_DOWN
-				  | FLAG_HAS_AMT
-				  | FLAG_HAS_CTRLEXT_ON_LOAD,
-	.pba			= 20,
-	.max_hw_frame_size	= DEFAULT_JUMBO,
-	.init_ops		= e1000e_init_function_pointers_82571,
-	.get_variants		= e1000e_get_variants_82571,
-};
-
-static struct e1000_info e1000_82583_info = {
-	.mac			= e1000_82583,
-	.flags			= FLAG_HAS_HW_VLAN_FILTER
-				  | FLAG_HAS_WOL
-				  | FLAG_APME_IN_CTRL3
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_SMART_POWER_DOWN
-				  | FLAG_HAS_AMT
-				  | FLAG_HAS_CTRLEXT_ON_LOAD,
-	.pba			= 20,
-	.max_hw_frame_size	= ETH_FRAME_LEN + ETH_FCS_LEN,
-	.init_ops		= e1000e_init_function_pointers_82571,
-	.get_variants		= e1000e_get_variants_82571,
-};
-
-static struct e1000_info e1000_es2_info = {
-	.mac			= e1000_80003es2lan,
-	.flags			= FLAG_HAS_HW_VLAN_FILTER
-				  | FLAG_HAS_JUMBO_FRAMES
-				  | FLAG_HAS_WOL
-				  | FLAG_APME_IN_CTRL3
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_CTRLEXT_ON_LOAD
-				  | FLAG_RX_NEEDS_RESTART /* errata */
-				  | FLAG_TARC_SET_BIT_ZERO /* errata */
-				  | FLAG_APME_CHECK_PORT_B
-				  | FLAG_DISABLE_FC_PAUSE_TIME /* errata */
-				  | FLAG_TIPG_MEDIUM_FOR_80003ESLAN,
-	.pba			= 38,
-	.max_hw_frame_size	= DEFAULT_JUMBO,
-	.init_ops		= e1000e_init_function_pointers_80003es2lan,
-	.get_variants		= NULL,
-};
-
-static s32 e1000e_get_variants_ich8lan(struct e1000_adapter *adapter)
-{
-	if (adapter->hw.phy.type == e1000_phy_ife) {
-		adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES;
-		adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN;
-	}
-
-	if ((adapter->hw.mac.type == e1000_ich8lan) &&
-	    (adapter->hw.phy.type == e1000_phy_igp_3))
-		adapter->flags |= FLAG_LSC_GIG_SPEED_DROP;
-
-	return 0;
-}
-
-static struct e1000_info e1000_ich8_info = {
-	.mac			= e1000_ich8lan,
-	.flags			= FLAG_HAS_WOL
-				  | FLAG_IS_ICH
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_CTRLEXT_ON_LOAD
-				  | FLAG_HAS_AMT
-				  | FLAG_HAS_FLASH
-				  | FLAG_APME_IN_WUC,
-	.pba			= 8,
-	.max_hw_frame_size	= ETH_FRAME_LEN + ETH_FCS_LEN,
-	.init_ops		= e1000e_init_function_pointers_ich8lan,
-	.get_variants		= e1000e_get_variants_ich8lan,
-};
-
-static struct e1000_info e1000_ich9_info = {
-	.mac			= e1000_ich9lan,
-	.flags			= FLAG_HAS_JUMBO_FRAMES
-				  | FLAG_IS_ICH
-				  | FLAG_HAS_WOL
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_CTRLEXT_ON_LOAD
-				  | FLAG_HAS_AMT
-				  | FLAG_HAS_ERT
-				  | FLAG_HAS_FLASH
-				  | FLAG_APME_IN_WUC,
-	.pba			= 10,
-	.max_hw_frame_size	= DEFAULT_JUMBO,
-	.init_ops		= e1000e_init_function_pointers_ich8lan,
-	.get_variants		= e1000e_get_variants_ich8lan,
-};
-
-static struct e1000_info e1000_ich10_info = {
-	.mac			= e1000_ich10lan,
-	.flags			= FLAG_HAS_JUMBO_FRAMES
-				  | FLAG_IS_ICH
-				  | FLAG_HAS_WOL
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_CTRLEXT_ON_LOAD
-				  | FLAG_HAS_AMT
-				  | FLAG_HAS_ERT
-				  | FLAG_HAS_FLASH
-				  | FLAG_APME_IN_WUC,
-	.pba			= 10,
-	.max_hw_frame_size	= DEFAULT_JUMBO,
-	.init_ops		= e1000e_init_function_pointers_ich8lan,
-	.get_variants		= e1000e_get_variants_ich8lan,
-};
-
-static struct e1000_info e1000_pch_info = {
-	.mac			= e1000_pchlan,
-	.flags			= FLAG_IS_ICH
-				  | FLAG_HAS_WOL
-				  | FLAG_RX_CSUM_ENABLED
-				  | FLAG_HAS_CTRLEXT_ON_LOAD
-				  | FLAG_HAS_AMT
-				  | FLAG_HAS_FLASH
-				  | FLAG_HAS_JUMBO_FRAMES
-				  | FLAG_DISABLE_FC_PAUSE_TIME /* errata */
-				  | FLAG_APME_IN_WUC,
-	.pba			= 26,
-	.max_hw_frame_size	= 4096,
-	.init_ops		= e1000e_init_function_pointers_ich8lan,
-	.get_variants		= e1000e_get_variants_ich8lan,
-};
-
-static const struct e1000_info *e1000_info_tbl[] = {
-	[board_82571]		= &e1000_82571_info,
-	[board_82572]		= &e1000_82572_info,
-	[board_82573]		= &e1000_82573_info,
-	[board_82574]		= &e1000_82574_info,
-	[board_82583]		= &e1000_82583_info,
-	[board_80003es2lan]	= &e1000_es2_info,
-	[board_ich8lan]		= &e1000_ich8_info,
-	[board_ich9lan]		= &e1000_ich9_info,
-	[board_ich10lan]	= &e1000_ich10_info,
-	[board_pchlan]		= &e1000_pch_info,
-};
-
-/* Low-level support routines */
-
-s32 e1000e_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
-{
-	u16 cap_offset;
-
-	cap_offset = pci_find_capability(hw->adapter->pdev, PCI_CAP_ID_EXP);
-	if (!cap_offset)
-		return -E1000_ERR_CONFIG;
-
-	pci_read_config_word(hw->adapter->pdev, cap_offset + reg, value);
-
-	return E1000_SUCCESS;
-}
-
-/**
- * e1000e_irq_disable - Mask off interrupt generation on the NIC
- **/
-static void e1000e_irq_disable(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-
-	ew32(IMC, ~0);
-	e1e_flush();
-}
-
-/**
- * e1000e_irq_enable - Enable default interrupt generation settings
- **/
-static void e1000e_irq_enable(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-
-	ew32(IMS, IMS_ENABLE_MASK);
-	e1e_flush();
-}
-
-/**
- * e1000_get_hw_control - get control of the h/w from f/w
- * @adapter: address of board private structure
- *
- * e1000_get_hw_control sets {CTRL_EXT|SWSM}:DRV_LOAD bit.
- * For ASF and Pass Through versions of f/w this means that
- * the driver is loaded. For AMT version (only with 82573)
- * of the f/w this means that the network i/f is open.
- **/
-static void e1000e_get_hw_control(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	u32 ctrl_ext;
-	u32 swsm;
-
-	/* Let firmware know the driver has taken over */
-	if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) {
-		swsm = er32(SWSM);
-		ew32(SWSM, swsm | E1000_SWSM_DRV_LOAD);
-	} else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) {
-		ctrl_ext = er32(CTRL_EXT);
-		ew32(CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
-	}
-}
-
-/**
- * e1000e_power_up_phy - restore link in case the phy was powered down
- * @adapter: address of board private structure
- *
- * The phy may be powered down to save power and turn off link when the
- * driver is unloaded and wake on lan is not enabled (among others)
- * *** this routine MUST be followed by a call to e1000e_reset ***
- **/
-void e1000e_power_up_phy(struct e1000_adapter *adapter)
-{
-	if (adapter->hw.phy.ops.power_up)
-		adapter->hw.phy.ops.power_up(&adapter->hw);
-
-	adapter->hw.mac.ops.setup_link(&adapter->hw);
-}
-
-/**
- * e1000_power_down_phy - Power down the PHY
- *
- * Power down the PHY so no link is implied when interface is down.
- * The PHY cannot be powered down if management or WoL is active.
- */
-void e1000e_power_down_phy(struct e1000_adapter *adapter)
-{
-	/* WoL is enabled */
-	if (adapter->wol)
-		return;
-
-	if (adapter->hw.phy.ops.power_down)
-		adapter->hw.phy.ops.power_down(&adapter->hw);
-}
-
-/**
- * e1000e_reset - bring the hardware into a known good state
- *
- * This function boots the hardware and enables some settings that
- * require a configuration cycle of the hardware - those cannot be
- * set/changed during runtime. After reset the device needs to be
- * properly configured for Rx, Tx etc.
- */
-void e1000e_reset(struct e1000_adapter *adapter)
-{
-	struct e1000_mac_info *mac = &adapter->hw.mac;
-	struct e1000_fc_info *fc = &adapter->hw.fc;
-	u32 pba = adapter->pba;
-	struct e1000_hw *hw = &adapter->hw;
-
-	/* Reset Packet Buffer Allocation to default */
-	ew32(PBA, pba);
-
-	hw->fc.requested_mode = e1000_fc_none;
-	fc->current_mode = fc->requested_mode;
-
-	/* Allow time for pending master requests to run */
-	mac->ops.reset_hw(hw);
-
-	/*
-	 * For parts with AMT enabled, let the firmware know
-	 * that the network interface is in control
-	 */
-	if (adapter->flags & FLAG_HAS_AMT)
-		e1000e_get_hw_control(adapter);
-
-	ew32(WUC, 0);
-	if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP)
-		e1e_wphy(&adapter->hw, BM_WUC, 0);
-
-	if (mac->ops.init_hw(hw))
-		DBG("Hardware Error\n");
-
-	/* additional part of the flow-control workaround above */
-	if (hw->mac.type == e1000_pchlan)
-		ew32(FCRTV_PCH, 0x1000);
-
-	e1000e_reset_adaptive(hw);
-
-	e1000e_get_phy_info(hw);
-
-	if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) &&
-	    !(adapter->flags & FLAG_SMART_POWER_DOWN)) {
-		u16 phy_data = 0;
-		/*
-		 * speed up time to link by disabling smart power down, ignore
-		 * the return value of this function because there is nothing
-		 * different we would do if it failed
-		 */
-		e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
-		phy_data &= ~IGP02E1000_PM_SPD;
-		e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
-	}
-}
-
-static int e1000e_sw_init(struct e1000_adapter *adapter)
-{
-	s32 rc;
-
-	/* Set various function pointers */
-	adapter->ei->init_ops(&adapter->hw);
-
-	rc = adapter->hw.mac.ops.init_params(&adapter->hw);
-	if (rc)
-		return rc;
-
-	rc = adapter->hw.nvm.ops.init_params(&adapter->hw);
-	if (rc)
-		return rc;
-
-	rc = adapter->hw.phy.ops.init_params(&adapter->hw);
-	if (rc)
-		return rc;
-
-	/* Explicitly disable IRQ since the NIC can be in any state. */
-	e1000e_irq_disable(adapter);
-
-	return E1000_SUCCESS;
-}
-
-/* TX support routines */
-
-/**
- * e1000_setup_tx_resources - allocate Tx resources (Descriptors)
- *
- * @v adapter	e1000 private structure
- *
- * @ret rc	 Returns 0 on success, negative on failure
- **/
-static int e1000e_setup_tx_resources ( struct e1000_adapter *adapter )
-{
-	DBGP ( "e1000_setup_tx_resources\n" );
-
-	/* Allocate transmit descriptor ring memory.
-	   It must not cross a 64K boundary because of hardware errata #23
-	   so we use malloc_dma() requesting a 128 byte block that is
-	   128 byte aligned. This should guarantee that the memory
-	   allocated will not cross a 64K boundary, because 128 is an
-	   even multiple of 65536 ( 65536 / 128 == 512 ), so all possible
-	   allocations of 128 bytes on a 128 byte boundary will not
-	   cross 64K bytes.
-	 */
-
-	adapter->tx_base =
-		malloc_dma ( adapter->tx_ring_size, adapter->tx_ring_size );
-
-	if ( ! adapter->tx_base ) {
-		return -ENOMEM;
-	}
-
-	memset ( adapter->tx_base, 0, adapter->tx_ring_size );
-
-	DBG ( "adapter->tx_base = %#08lx\n", virt_to_bus ( adapter->tx_base ) );
-
-	return 0;
-}
-
-/**
- * e1000_process_tx_packets - process transmitted packets
- *
- * @v netdev	network interface device structure
- **/
-static void e1000e_process_tx_packets ( struct net_device *netdev )
-{
-	struct e1000_adapter *adapter = netdev_priv ( netdev );
-	uint32_t i;
-	uint32_t tx_status;
-	struct e1000_tx_desc *tx_curr_desc;
-
-	/* Check status of transmitted packets
-	 */
-	DBG ( "process_tx_packets: tx_head = %d, tx_tail = %d\n", adapter->tx_head,
-	      adapter->tx_tail );
-
-	while ( ( i = adapter->tx_head ) != adapter->tx_tail ) {
-
-		tx_curr_desc = ( void * )  ( adapter->tx_base ) +
-					   ( i * sizeof ( *adapter->tx_base ) );
-
-		tx_status = tx_curr_desc->upper.data;
-
-		DBG ( "	 tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
-		DBG ( "	 tx_status = %#08x\n", tx_status );
-
-		/* if the packet at tx_head is not owned by hardware it is for us */
-		if ( ! ( tx_status & E1000_TXD_STAT_DD ) )
-			break;
-
-		DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n",
-		      adapter->tx_head, adapter->tx_tail, tx_status );
-
-		if ( tx_status & ( E1000_TXD_STAT_EC | E1000_TXD_STAT_LC |
-				   E1000_TXD_STAT_TU ) ) {
-			netdev_tx_complete_err ( netdev, adapter->tx_iobuf[i], -EINVAL );
-			DBG ( "Error transmitting packet, tx_status: %#08x\n",
-			      tx_status );
-		} else {
-			netdev_tx_complete ( netdev, adapter->tx_iobuf[i] );
-			DBG ( "Success transmitting packet, tx_status: %#08x\n",
-			      tx_status );
-		}
-
-		/* Decrement count of used descriptors, clear this descriptor
-		 */
-		adapter->tx_fill_ctr--;
-		memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
-
-		adapter->tx_head = ( adapter->tx_head + 1 ) % NUM_TX_DESC;
-	}
-}
-
-static void e1000e_free_tx_resources ( struct e1000_adapter *adapter )
-{
-	DBGP ( "e1000_free_tx_resources\n" );
-
-	free_dma ( adapter->tx_base, adapter->tx_ring_size );
-}
-
-/**
- * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
- * @adapter: board private structure
- *
- * Configure the Tx unit of the MAC after a reset.
- **/
-static void e1000e_configure_tx ( struct e1000_adapter *adapter )
-{
-	struct e1000_hw *hw = &adapter->hw;
-	u32 tctl, tipg, tarc;
-	u32 ipgr1, ipgr2;
-
-	DBGP ( "e1000_configure_tx\n" );
-
-	/* disable transmits while setting up the descriptors */
-	tctl = E1000_READ_REG ( hw, E1000_TCTL );
-	E1000_WRITE_REG ( hw, E1000_TCTL, tctl & ~E1000_TCTL_EN );
-	e1e_flush();
-	mdelay(10);
-
-	E1000_WRITE_REG ( hw, E1000_TDBAH(0), 0 );
-	E1000_WRITE_REG ( hw, E1000_TDBAL(0), virt_to_bus ( adapter->tx_base ) );
-	E1000_WRITE_REG ( hw, E1000_TDLEN(0), adapter->tx_ring_size );
-
-	DBG ( "E1000_TDBAL(0): %#08x\n",  E1000_READ_REG ( hw, E1000_TDBAL(0) ) );
-	DBG ( "E1000_TDLEN(0): %d\n",	  E1000_READ_REG ( hw, E1000_TDLEN(0) ) );
-
-	/* Setup the HW Tx Head and Tail descriptor pointers */
-	E1000_WRITE_REG ( hw, E1000_TDH(0), 0 );
-	E1000_WRITE_REG ( hw, E1000_TDT(0), 0 );
-
-	adapter->tx_head = 0;
-	adapter->tx_tail = 0;
-	adapter->tx_fill_ctr = 0;
-
-	/* Set the default values for the Tx Inter Packet Gap timer */
-	tipg = DEFAULT_82543_TIPG_IPGT_COPPER;		/*  8  */
-	ipgr1 = DEFAULT_82543_TIPG_IPGR1;		/*  8  */
-	ipgr2 = DEFAULT_82543_TIPG_IPGR2;		/*  6  */
-
-	if (adapter->flags & FLAG_TIPG_MEDIUM_FOR_80003ESLAN)
-		ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2; /*  7  */
-
-	tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT;
-	tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT;
-	ew32(TIPG, tipg);
-
-	/* Program the Transmit Control Register */
-	tctl = er32(TCTL);
-	tctl &= ~E1000_TCTL_CT;
-	tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
-		(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
-
-	if (adapter->flags & FLAG_TARC_SPEED_MODE_BIT) {
-		tarc = er32(TARC(0));
-		/*
-		 * set the speed mode bit, we'll clear it if we're not at
-		 * gigabit link later
-		 */
-#define SPEED_MODE_BIT (1 << 21)
-		tarc |= SPEED_MODE_BIT;
-		ew32(TARC(0), tarc);
-	}
-
-	/* errata: program both queues to unweighted RR */
-	if (adapter->flags & FLAG_TARC_SET_BIT_ZERO) {
-		tarc = er32(TARC(0));
-		tarc |= 1;
-		ew32(TARC(0), tarc);
-		tarc = er32(TARC(1));
-		tarc |= 1;
-		ew32(TARC(1), tarc);
-	}
-
-	/* Setup Transmit Descriptor Settings for eop descriptor */
-	adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS;
-
-	/* enable Report Status bit */
-	adapter->txd_cmd |= E1000_TXD_CMD_RS;
-
-	/*
-	 * enable transmits in the hardware, need to do this
-	 * after setting TARC(0)
-	 */
-	tctl |= E1000_TCTL_EN;
-	ew32(TCTL, tctl);
-	e1e_flush();
-
-	e1000e_config_collision_dist(hw);
-}
-
-/* RX support routines */
-
-static void e1000e_free_rx_resources ( struct e1000_adapter *adapter )
-{
-	int i;
-
-	DBGP ( "e1000_free_rx_resources\n" );
-
-	free_dma ( adapter->rx_base, adapter->rx_ring_size );
-
-	for ( i = 0; i < NUM_RX_DESC; i++ ) {
-		free_iob ( adapter->rx_iobuf[i] );
-	}
-}
-
-/**
- * e1000_refill_rx_ring - allocate Rx io_buffers
- *
- * @v adapter	e1000 private structure
- *
- * @ret rc	 Returns 0 on success, negative on failure
- **/
-static int e1000e_refill_rx_ring ( struct e1000_adapter *adapter )
-{
-	int i, rx_curr;
-	int rc = 0;
-	struct e1000_rx_desc *rx_curr_desc;
-	struct e1000_hw *hw = &adapter->hw;
-	struct io_buffer *iob;
-
-	DBGP ("e1000_refill_rx_ring\n");
-
-	for ( i = 0; i < NUM_RX_DESC; i++ ) {
-		rx_curr = ( ( adapter->rx_curr + i ) % NUM_RX_DESC );
-		rx_curr_desc = adapter->rx_base + rx_curr;
-
-		if ( rx_curr_desc->status & E1000_RXD_STAT_DD )
-			continue;
-
-		if ( adapter->rx_iobuf[rx_curr] != NULL )
-			continue;
-
-		DBG2 ( "Refilling rx desc %d\n", rx_curr );
-
-		iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE );
-		adapter->rx_iobuf[rx_curr] = iob;
-
-		if ( ! iob ) {
-			DBG ( "alloc_iob failed\n" );
-			rc = -ENOMEM;
-			break;
-		} else {
-			rx_curr_desc->buffer_addr = virt_to_bus ( iob->data );
-
-			E1000_WRITE_REG ( hw, E1000_RDT(0), rx_curr );
-		}
-	}
-	return rc;
-}
-
-/**
- * e1000_setup_rx_resources - allocate Rx resources (Descriptors)
- *
- * @v adapter	e1000 private structure
- *
- * @ret rc	 Returns 0 on success, negative on failure
- **/
-static int e1000e_setup_rx_resources ( struct e1000_adapter *adapter )
-{
-	int i, rc = 0;
-
-	DBGP ( "e1000_setup_rx_resources\n" );
-
-	/* Allocate receive descriptor ring memory.
-	   It must not cross a 64K boundary because of hardware errata
-	 */
-
-	adapter->rx_base =
-		malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size );
-
-	if ( ! adapter->rx_base ) {
-		return -ENOMEM;
-	}
-	memset ( adapter->rx_base, 0, adapter->rx_ring_size );
-
-	for ( i = 0; i < NUM_RX_DESC; i++ ) {
-		/* let e1000_refill_rx_ring() io_buffer allocations */
-		adapter->rx_iobuf[i] = NULL;
-	}
-
-	/* allocate io_buffers */
-	rc = e1000e_refill_rx_ring ( adapter );
-	if ( rc < 0 )
-		e1000e_free_rx_resources ( adapter );
-
-	return rc;
-}
-
-/**
- * e1000_configure_rx - Configure 8254x Receive Unit after Reset
- * @adapter: board private structure
- *
- * Configure the Rx unit of the MAC after a reset.
- **/
-static void e1000e_configure_rx ( struct e1000_adapter *adapter )
-{
-	struct e1000_hw *hw = &adapter->hw;
-	uint32_t rctl;
-
-	DBGP ( "e1000_configure_rx\n" );
-
-	/* disable receives while setting up the descriptors */
-	rctl = E1000_READ_REG ( hw, E1000_RCTL );
-	E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN );
-	e1e_flush();
-	mdelay(10);
-
-	adapter->rx_curr = 0;
-
-	/* Setup the HW Rx Head and Tail Descriptor Pointers and
-	 * the Base and Length of the Rx Descriptor Ring */
-
-	E1000_WRITE_REG ( hw, E1000_RDBAL(0), virt_to_bus ( adapter->rx_base ) );
-	E1000_WRITE_REG ( hw, E1000_RDBAH(0), 0 );
-	E1000_WRITE_REG ( hw, E1000_RDLEN(0), adapter->rx_ring_size );
-
-	E1000_WRITE_REG ( hw, E1000_RDH(0), 0 );
-	E1000_WRITE_REG ( hw, E1000_RDT(0), NUM_RX_DESC - 1 );
-
-	/* Enable Receives */
-	rctl |=	 E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
-		 E1000_RCTL_MPE;
-	E1000_WRITE_REG ( hw, E1000_RCTL, rctl );
-	e1e_flush();
-
-	DBG ( "E1000_RDBAL(0): %#08x\n",  E1000_READ_REG ( hw, E1000_RDBAL(0) ) );
-	DBG ( "E1000_RDLEN(0): %d\n",	  E1000_READ_REG ( hw, E1000_RDLEN(0) ) );
-	DBG ( "E1000_RCTL:  %#08x\n",  E1000_READ_REG ( hw, E1000_RCTL ) );
-}
-
-/**
- * e1000_process_rx_packets - process received packets
- *
- * @v netdev	network interface device structure
- **/
-static void e1000e_process_rx_packets ( struct net_device *netdev )
-{
-	struct e1000_adapter *adapter = netdev_priv ( netdev );
-	uint32_t i;
-	uint32_t rx_status;
-	uint32_t rx_len;
-	uint32_t rx_err;
-	struct e1000_rx_desc *rx_curr_desc;
-
-	/* Process received packets
-	 */
-	while ( 1 ) {
-
-		i = adapter->rx_curr;
-
-		rx_curr_desc = ( void * )  ( adapter->rx_base ) +
-				  ( i * sizeof ( *adapter->rx_base ) );
-		rx_status = rx_curr_desc->status;
-
-		DBG2 ( "Before DD Check RX_status: %#08x\n", rx_status );
-
-		if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
-			break;
-
-		if ( adapter->rx_iobuf[i] == NULL )
-			break;
-
-		DBG ( "E1000_RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, E1000_RCTL ) );
-
-		rx_len = rx_curr_desc->length;
-
-		DBG ( "Received packet, rx_curr: %d  rx_status: %#08x  rx_len: %d\n",
-		      i, rx_status, rx_len );
-
-		rx_err = rx_curr_desc->errors;
-
-		iob_put ( adapter->rx_iobuf[i], rx_len );
-
-		if ( rx_err & E1000_RXD_ERR_FRAME_ERR_MASK ) {
-
-			netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL );
-			DBG ( "e1000_poll: Corrupted packet received!"
-			      " rx_err: %#08x\n", rx_err );
-		} else	{
-			/* Add this packet to the receive queue. */
-			netdev_rx ( netdev, adapter->rx_iobuf[i] );
-		}
-		adapter->rx_iobuf[i] = NULL;
-
-		memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
-
-		adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC;
-	}
-}
-
-/** Functions that implement the iPXE driver API **/
-
-/**
- * e1000_close - Disables a network interface
- *
- * @v netdev	network interface device structure
- *
- **/
-static void e1000e_close ( struct net_device *netdev )
-{
-	struct e1000_adapter *adapter = netdev_priv ( netdev );
-	struct e1000_hw *hw = &adapter->hw;
-	uint32_t rctl;
-
-	DBGP ( "e1000_close\n" );
-
-	/* Disable and acknowledge interrupts */
-	e1000e_irq_disable ( adapter );
-	E1000_READ_REG ( hw, E1000_ICR );
-
-	/* disable receives */
-	rctl = E1000_READ_REG ( hw, E1000_RCTL );
-	E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN );
-	e1e_flush();
-
-	e1000e_reset ( adapter );
-
-	e1000e_free_tx_resources ( adapter );
-	e1000e_free_rx_resources ( adapter );
-}
-
-/**
- * e1000_transmit - Transmit a packet
- *
- * @v netdev	Network device
- * @v iobuf	I/O buffer
- *
- * @ret rc	 Returns 0 on success, negative on failure
- */
-static int e1000e_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
-{
-	struct e1000_adapter *adapter = netdev_priv( netdev );
-	struct e1000_hw *hw = &adapter->hw;
-	uint32_t tx_curr = adapter->tx_tail;
-	struct e1000_tx_desc *tx_curr_desc;
-
-	DBGP ("e1000_transmit\n");
-
-	if ( adapter->tx_fill_ctr == NUM_TX_DESC ) {
-		DBG ("TX overflow\n");
-		return -ENOBUFS;
-	}
-
-	/* Save pointer to iobuf we have been given to transmit,
-	   netdev_tx_complete() will need it later
-	 */
-	adapter->tx_iobuf[tx_curr] = iobuf;
-
-	tx_curr_desc = ( void * ) ( adapter->tx_base ) +
-		       ( tx_curr * sizeof ( *adapter->tx_base ) );
-
-	DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
-	DBG ( "tx_curr_desc + 16 = %#08lx\n", virt_to_bus ( tx_curr_desc ) + 16 );
-	DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) );
-
-	/* Add the packet to TX ring
-	 */
-	tx_curr_desc->buffer_addr = virt_to_bus ( iobuf->data );
-	tx_curr_desc->upper.data = 0;
-	tx_curr_desc->lower.data = adapter->txd_cmd | iob_len ( iobuf );
-
-	DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr,
-	      tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
-
-	/* Point to next free descriptor */
-	adapter->tx_tail = ( adapter->tx_tail + 1 ) % NUM_TX_DESC;
-	adapter->tx_fill_ctr++;
-
-	/* Write new tail to NIC, making packet available for transmit
-	 */
-	E1000_WRITE_REG ( hw, E1000_TDT(0), adapter->tx_tail );
-	e1e_flush();
-
-	return 0;
-}
-
-/**
- * e1000_poll - Poll for received packets
- *
- * @v netdev	Network device
- */
-static void e1000e_poll ( struct net_device *netdev )
-{
-	struct e1000_adapter *adapter = netdev_priv( netdev );
-	struct e1000_hw *hw = &adapter->hw;
-
-	uint32_t icr;
-
-	DBGP ( "e1000_poll\n" );
-
-	/* Acknowledge interrupts */
-	icr = E1000_READ_REG ( hw, E1000_ICR );
-	if ( ! icr )
-		return;
-
-	DBG ( "e1000_poll: intr_status = %#08x\n", icr );
-
-	e1000e_process_tx_packets ( netdev );
-
-	e1000e_process_rx_packets ( netdev );
-
-	e1000e_refill_rx_ring(adapter);
-}
-
-/**
- * e1000_irq - enable or Disable interrupts
- *
- * @v adapter	e1000 adapter
- * @v action	requested interrupt action
- **/
-static void e1000e_irq ( struct net_device *netdev, int enable )
-{
-	struct e1000_adapter *adapter = netdev_priv ( netdev );
-
-	DBGP ( "e1000_irq\n" );
-
-	if ( enable ) {
-		e1000e_irq_enable ( adapter );
-	} else {
-		e1000e_irq_disable ( adapter );
-	}
-}
-
-static struct net_device_operations e1000e_operations;
-
-/**
- * e1000_probe - Initial configuration of e1000 NIC
- *
- * @v pci	PCI device
- * @v id	PCI IDs
- *
- * @ret rc	Return status code
- **/
-int e1000e_probe ( struct pci_device *pdev )
-{
-	int i, err;
-	struct net_device *netdev;
-	struct e1000_adapter *adapter;
-	unsigned long mmio_start, mmio_len;
-	unsigned long flash_start, flash_len;
-	struct e1000_hw *hw;
-	const struct e1000_info *ei = e1000_info_tbl[pdev->id->driver_data];
-
-	DBGP ( "e1000_probe\n" );
-
-	err = -ENOMEM;
-
-	/* Allocate net device ( also allocates memory for netdev->priv
-	   and makes netdev-priv point to it ) */
-	netdev = alloc_etherdev ( sizeof ( struct e1000_adapter ) );
-	if ( ! netdev ) {
-                DBG ( "err_alloc_etherdev\n" );
-		goto err_alloc_etherdev;
-        }
-
-	/* Associate e1000-specific network operations operations with
-	 * generic network device layer */
-	netdev_init ( netdev, &e1000e_operations );
-
-	/* Associate this network device with given PCI device */
-	pci_set_drvdata ( pdev, netdev );
-	netdev->dev = &pdev->dev;
-
-	/* Initialize driver private storage */
-	adapter = netdev_priv ( netdev );
-	memset ( adapter, 0, ( sizeof ( *adapter ) ) );
-
-	adapter->pdev	    = pdev;
-
-	adapter->ioaddr	    = pdev->ioaddr;
-	adapter->hw.io_base = pdev->ioaddr;
-
-	hw		    = &adapter->hw;
-	hw->device_id	    = pdev->device;
-
-	adapter->irqno	    = pdev->irq;
-	adapter->netdev	    = netdev;
-	adapter->hw.back    = adapter;
-
-	adapter->ei	    = ei;
-	adapter->pba	    = ei->pba;
-	adapter->flags	    = ei->flags;
-	adapter->flags2	    = ei->flags2;
-
-	adapter->hw.adapter  = adapter;
-	adapter->hw.mac.type = ei->mac;
-	adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN;
-
-	adapter->tx_ring_size = sizeof ( *adapter->tx_base ) * NUM_TX_DESC;
-	adapter->rx_ring_size = sizeof ( *adapter->rx_base ) * NUM_RX_DESC;
-
-	/* Fix up PCI device */
-	adjust_pci_device ( pdev );
-
-	err = -EIO;
-
-	mmio_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_0 );
-	mmio_len   = pci_bar_size  ( pdev, PCI_BASE_ADDRESS_0 );
-
-	DBG ( "mmio_start: %#08lx\n", mmio_start );
-	DBG ( "mmio_len: %#08lx\n", mmio_len );
-
-	adapter->hw.hw_addr = ioremap ( mmio_start, mmio_len );
-	DBG ( "adapter->hw.hw_addr: %p\n", adapter->hw.hw_addr );
-
-	if ( ! adapter->hw.hw_addr ) {
-                DBG ( "err_ioremap\n" );
-		goto err_ioremap;
-        }
-
-	/* Flash BAR mapping depends on mac_type */
-	if ( ( adapter->flags & FLAG_HAS_FLASH) && ( pdev->ioaddr ) ) {
-		flash_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_1 );
-		flash_len = pci_bar_size ( pdev, PCI_BASE_ADDRESS_1 );
-		adapter->hw.flash_address = ioremap ( flash_start, flash_len );
-		if ( ! adapter->hw.flash_address ) {
-                        DBG ( "err_flashmap\n" );
-			goto err_flashmap;
-		}
-	}
-
-	/* setup adapter struct */
-	err = e1000e_sw_init ( adapter );
-	if (err) {
-                DBG ( "err_sw_init\n" );
-		goto err_sw_init;
-        }
-
-	if (ei->get_variants) {
-		err = ei->get_variants(adapter);
-		if (err) {
-                        DBG ( "err_hw_initr\n" );
-			goto err_hw_init;
-                }
-	}
-
-	/* Copper options */
-	if (adapter->hw.phy.media_type == e1000_media_type_copper) {
-		adapter->hw.phy.mdix = AUTO_ALL_MODES;
-		adapter->hw.phy.disable_polarity_correction = 0;
-		adapter->hw.phy.ms_type = e1000_ms_hw_default;
-	}
-
-	DBG ( "adapter->hw.mac.type: %#08x\n", adapter->hw.mac.type );
-
-	/* Force auto-negotiation */
-	adapter->hw.mac.autoneg = 1;
-	adapter->fc_autoneg = 1;
-	adapter->hw.phy.autoneg_wait_to_complete = true;
-	adapter->hw.mac.adaptive_ifs = true;
-	adapter->hw.fc.requested_mode = e1000_fc_default;
-	adapter->hw.fc.current_mode = e1000_fc_default;
-
-	/*
-	 * before reading the NVM, reset the controller to
-	 * put the device in a known good starting state
-	 */
-	adapter->hw.mac.ops.reset_hw(&adapter->hw);
-
-	/*
-	 * systems with ASPM and others may see the checksum fail on the first
-	 * attempt. Let's give it a few tries
-	 */
-	for (i = 0;; i++) {
-		if (e1000e_validate_nvm_checksum(&adapter->hw) >= 0)
-			break;
-		if (i == 2) {
-			DBG("The NVM Checksum Is Not Valid\n");
-			err = -EIO;
-			goto err_eeprom;
-		}
-	}
-
-	/* copy the MAC address out of the EEPROM */
-	if ( e1000e_read_mac_addr ( &adapter->hw ) )
-		DBG ( "EEPROM Read Error\n" );
-
-	memcpy ( netdev->hw_addr, adapter->hw.mac.perm_addr, ETH_ALEN );
-
-	/* reset the hardware with the new settings */
-	e1000e_reset ( adapter );
-
-	if ( ( err = register_netdev ( netdev ) ) != 0) {
-                DBG ( "err_register\n" );
-		goto err_register;
-        }
-
-	/* Mark as link up; we don't yet handle link state */
-	netdev_link_up ( netdev );
-
-	for (i = 0; i < 6; i++)
-		DBG ("%02x%s", netdev->ll_addr[i], i == 5 ? "\n" : ":");
-
-	DBG ( "e1000e_probe succeeded!\n" );
-
-	/* No errors, return success */
-	return 0;
-
-/* Error return paths */
-err_register:
-err_hw_init:
-err_eeprom:
-err_flashmap:
-	if (!e1000e_check_reset_block(&adapter->hw))
-		e1000e_phy_hw_reset(&adapter->hw);
-	if (adapter->hw.flash_address)
-		iounmap(adapter->hw.flash_address);
-err_sw_init:
-	iounmap ( adapter->hw.hw_addr );
-err_ioremap:
-	netdev_put ( netdev );
-err_alloc_etherdev:
-	return err;
-}
-
-/**
- * e1000e_remove - Device Removal Routine
- *
- * @v pdev PCI device information struct
- *
- **/
-void e1000e_remove ( struct pci_device *pdev )
-{
-	struct net_device *netdev = pci_get_drvdata ( pdev );
-	struct e1000_adapter *adapter = netdev_priv ( netdev );
-
-	DBGP ( "e1000e_remove\n" );
-
-	if ( adapter->hw.flash_address )
-		iounmap ( adapter->hw.flash_address );
-	if  ( adapter->hw.hw_addr )
-		iounmap ( adapter->hw.hw_addr );
-
-	unregister_netdev ( netdev );
-	e1000e_reset  ( adapter );
-	netdev_nullify ( netdev );
-	netdev_put ( netdev );
-}
-
-/**
- * e1000e_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 e1000e_open ( struct net_device *netdev )
-{
-	struct e1000_adapter *adapter = netdev_priv(netdev);
-	int err;
-
-	DBGP ( "e1000e_open\n" );
-
-	/* allocate transmit descriptors */
-	err = e1000e_setup_tx_resources ( adapter );
-	if ( err ) {
-		DBG ( "Error setting up TX resources!\n" );
-		goto err_setup_tx;
-	}
-
-	/* allocate receive descriptors */
-	err = e1000e_setup_rx_resources ( adapter );
-	if ( err ) {
-		DBG ( "Error setting up RX resources!\n" );
-		goto err_setup_rx;
-	}
-
-	e1000e_configure_tx ( adapter );
-
-	e1000e_configure_rx ( adapter );
-
-	DBG ( "E1000_RXDCTL(0): %#08x\n",  E1000_READ_REG ( &adapter->hw, E1000_RXDCTL(0) ) );
-
-	return 0;
-
-err_setup_rx:
-        DBG ( "err_setup_rx\n" );
-	e1000e_free_tx_resources ( adapter );
-err_setup_tx:
-        DBG ( "err_setup_tx\n" );
-	e1000e_reset ( adapter );
-
-	return err;
-}
-
-/** e1000e net device operations */
-static struct net_device_operations e1000e_operations = {
-	.open		= e1000e_open,
-	.close		= e1000e_close,
-	.transmit	= e1000e_transmit,
-	.poll		= e1000e_poll,
-	.irq		= e1000e_irq,
-};
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_manage.c b/roms/ipxe/src/drivers/net/e1000e/e1000e_manage.c
deleted file mode 100644
index e0935362ec45602a346395e9c9948528dae50f34..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_manage.c
+++ /dev/null
@@ -1,372 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#if 0
-
-#include "e1000e.h"
-
-static u8 e1000e_calculate_checksum(u8 *buffer, u32 length);
-
-/**
- *  e1000e_calculate_checksum - Calculate checksum for buffer
- *  @buffer: pointer to EEPROM
- *  @length: size of EEPROM to calculate a checksum for
- *
- *  Calculates the checksum for some buffer on a specified length.  The
- *  checksum calculated is returned.
- **/
-static u8 e1000e_calculate_checksum(u8 *buffer, u32 length)
-{
-	u32 i;
-	u8  sum = 0;
-
-	if (!buffer)
-		return 0;
-	for (i = 0; i < length; i++)
-		sum += buffer[i];
-
-	return (u8) (0 - sum);
-}
-
-/**
- *  e1000e_mng_enable_host_if_generic - Checks host interface is enabled
- *  @hw: pointer to the HW structure
- *
- *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
- *
- *  This function checks whether the HOST IF is enabled for command operation
- *  and also checks whether the previous command is completed.  It busy waits
- *  in case of previous command is not completed.
- **/
-s32 e1000e_mng_enable_host_if_generic(struct e1000_hw *hw)
-{
-	u32 hicr;
-	s32 ret_val = E1000_SUCCESS;
-	u8  i;
-
-	/* Check that the host interface is enabled. */
-	hicr = er32(HICR);
-	if ((hicr & E1000_HICR_EN) == 0) {
-		e_dbg("E1000_HOST_EN bit disabled.\n");
-		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
-		goto out;
-	}
-	/* check the previous command is completed */
-	for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
-		hicr = er32(HICR);
-		if (!(hicr & E1000_HICR_C))
-			break;
-		mdelay(1);
-	}
-
-	if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
-		e_dbg("Previous command timeout failed .\n");
-		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_check_mng_mode_generic - Generic check management mode
- *  @hw: pointer to the HW structure
- *
- *  Reads the firmware semaphore register and returns true (>0) if
- *  manageability is enabled, else false (0).
- **/
-bool e1000e_check_mng_mode_generic(struct e1000_hw *hw)
-{
-	u32 fwsm;
-
-	fwsm = er32(FWSM);
-	return (fwsm & E1000_FWSM_MODE_MASK) ==
-	        (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
-}
-
-/**
- *  e1000e_enable_tx_pkt_filtering - Enable packet filtering on TX
- *  @hw: pointer to the HW structure
- *
- *  Enables packet filtering on transmit packets if manageability is enabled
- *  and host interface is enabled.
- **/
-bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw)
-{
-	struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
-	u32 *buffer = (u32 *)&hw->mng_cookie;
-	u32 offset;
-	s32 ret_val, hdr_csum, csum;
-	u8 i, len;
-	bool tx_filter = true;
-
-	/* No manageability, no filtering */
-	if (!hw->mac.ops.check_mng_mode(hw)) {
-		tx_filter = false;
-		goto out;
-	}
-
-	/*
-	 * If we can't read from the host interface for whatever
-	 * reason, disable filtering.
-	 */
-	ret_val = hw->mac.ops.mng_enable_host_if(hw);
-	if (ret_val != E1000_SUCCESS) {
-		tx_filter = false;
-		goto out;
-	}
-
-	/* Read in the header.  Length and offset are in dwords. */
-	len    = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
-	offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
-	for (i = 0; i < len; i++) {
-		*(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw,
-		                                           E1000_HOST_IF,
-		                                           offset + i);
-	}
-	hdr_csum = hdr->checksum;
-	hdr->checksum = 0;
-	csum = e1000e_calculate_checksum((u8 *)hdr,
-	                                E1000_MNG_DHCP_COOKIE_LENGTH);
-	/*
-	 * If either the checksums or signature don't match, then
-	 * the cookie area isn't considered valid, in which case we
-	 * take the safe route of assuming Tx filtering is enabled.
-	 */
-	if (hdr_csum != csum)
-		goto out;
-	if (hdr->signature != E1000_IAMT_SIGNATURE)
-		goto out;
-
-	/* Cookie area is valid, make the final check for filtering. */
-	if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING))
-		tx_filter = false;
-
-out:
-	hw->mac.tx_pkt_filtering = tx_filter;
-	return tx_filter;
-}
-
-/**
- *  e1000e_mng_write_dhcp_info - Writes DHCP info to host interface
- *  @hw: pointer to the HW structure
- *  @buffer: pointer to the host interface
- *  @length: size of the buffer
- *
- *  Writes the DHCP information to the host interface.
- **/
-s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer,
-                                      u16 length)
-{
-	struct e1000_host_mng_command_header hdr;
-	s32 ret_val;
-	u32 hicr;
-
-	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
-	hdr.command_length = length;
-	hdr.reserved1 = 0;
-	hdr.reserved2 = 0;
-	hdr.checksum = 0;
-
-	/* Enable the host interface */
-	ret_val = hw->mac.ops.mng_enable_host_if(hw);
-	if (ret_val)
-		goto out;
-
-	/* Populate the host interface with the contents of "buffer". */
-	ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
-	                                  sizeof(hdr), &(hdr.checksum));
-	if (ret_val)
-		goto out;
-
-	/* Write the manageability command header */
-	ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
-	if (ret_val)
-		goto out;
-
-	/* Tell the ARC a new command is pending. */
-	hicr = er32(HICR);
-	ew32(HICR, hicr | E1000_HICR_C);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_mng_write_cmd_header_generic - Writes manageability command header
- *  @hw: pointer to the HW structure
- *  @hdr: pointer to the host interface command header
- *
- *  Writes the command header after does the checksum calculation.
- **/
-s32 e1000e_mng_write_cmd_header_generic(struct e1000_hw *hw,
-                                    struct e1000_host_mng_command_header *hdr)
-{
-	u16 i, length = sizeof(struct e1000_host_mng_command_header);
-
-	/* Write the whole command header structure with new checksum. */
-
-	hdr->checksum = e1000e_calculate_checksum((u8 *)hdr, length);
-
-	length >>= 2;
-	/* Write the relevant command block into the ram area. */
-	for (i = 0; i < length; i++) {
-		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
-		                            *((u32 *) hdr + i));
-		e1e_flush();
-	}
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_mng_host_if_write_generic - Write to the manageability host interface
- *  @hw: pointer to the HW structure
- *  @buffer: pointer to the host interface buffer
- *  @length: size of the buffer
- *  @offset: location in the buffer to write to
- *  @sum: sum of the data (not checksum)
- *
- *  This function writes the buffer content at the offset given on the host if.
- *  It also does alignment considerations to do the writes in most efficient
- *  way.  Also fills up the sum of the buffer in *buffer parameter.
- **/
-s32 e1000e_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
-                                    u16 length, u16 offset, u8 *sum)
-{
-	u8 *tmp;
-	u8 *bufptr = buffer;
-	u32 data = 0;
-	s32 ret_val = E1000_SUCCESS;
-	u16 remaining, i, j, prev_bytes;
-
-	/* sum = only sum of the data and it is not checksum */
-
-	if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
-		ret_val = -E1000_ERR_PARAM;
-		goto out;
-	}
-
-	tmp = (u8 *)&data;
-	prev_bytes = offset & 0x3;
-	offset >>= 2;
-
-	if (prev_bytes) {
-		data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
-		for (j = prev_bytes; j < sizeof(u32); j++) {
-			*(tmp + j) = *bufptr++;
-			*sum += *(tmp + j);
-		}
-		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
-		length -= j - prev_bytes;
-		offset++;
-	}
-
-	remaining = length & 0x3;
-	length -= remaining;
-
-	/* Calculate length in DWORDs */
-	length >>= 2;
-
-	/*
-	 * The device driver writes the relevant command block into the
-	 * ram area.
-	 */
-	for (i = 0; i < length; i++) {
-		for (j = 0; j < sizeof(u32); j++) {
-			*(tmp + j) = *bufptr++;
-			*sum += *(tmp + j);
-		}
-
-		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
-		                            data);
-	}
-	if (remaining) {
-		for (j = 0; j < sizeof(u32); j++) {
-			if (j < remaining)
-				*(tmp + j) = *bufptr++;
-			else
-				*(tmp + j) = 0;
-
-			*sum += *(tmp + j);
-		}
-		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_enable_mng_pass_thru - Enable processing of ARP's
- *  @hw: pointer to the HW structure
- *
- *  Verifies the hardware needs to allow ARPs to be processed by the host.
- **/
-bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw)
-{
-	u32 manc;
-	u32 fwsm, factps;
-	bool ret_val = false;
-
-	if (!hw->mac.asf_firmware_present)
-		goto out;
-
-	manc = er32(MANC);
-
-	if (!(manc & E1000_MANC_RCV_TCO_EN) ||
-	    !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
-		goto out;
-
-	if (hw->mac.arc_subsystem_valid) {
-		fwsm = er32(FWSM);
-		factps = er32(FACTPS);
-
-		if (!(factps & E1000_FACTPS_MNGCG) &&
-		    ((fwsm & E1000_FWSM_MODE_MASK) ==
-		     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
-			ret_val = true;
-			goto out;
-		}
-	} else {
-		if ((manc & E1000_MANC_SMBUS_EN) &&
-		    !(manc & E1000_MANC_ASF_EN)) {
-			ret_val = true;
-			goto out;
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-#endif
-
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_manage.h b/roms/ipxe/src/drivers/net/e1000e/e1000e_manage.h
deleted file mode 100644
index f136aee8408e7f90c029d4d94ea1310e3c0c2bc3..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_manage.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000E_MANAGE_H_
-#define _E1000E_MANAGE_H_
-
-bool e1000e_check_mng_mode_generic(struct e1000_hw *hw);
-bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
-s32  e1000e_mng_enable_host_if_generic(struct e1000_hw *hw);
-s32  e1000e_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
-                                     u16 length, u16 offset, u8 *sum);
-s32  e1000e_mng_write_cmd_header_generic(struct e1000_hw *hw,
-                                    struct e1000_host_mng_command_header *hdr);
-#if 0
-s32  e1000e_mng_write_dhcp_info(struct e1000_hw *hw,
-                                       u8 *buffer, u16 length);
-#endif
-bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw);
-
-enum e1000_mng_mode {
-	e1000_mng_mode_none = 0,
-	e1000_mng_mode_asf,
-	e1000_mng_mode_pt,
-	e1000_mng_mode_ipmi,
-	e1000_mng_mode_host_if_only
-};
-
-#define E1000_FACTPS_MNGCG    0x20000000
-
-#define E1000_FWSM_MODE_MASK  0xE
-#define E1000_FWSM_MODE_SHIFT 1
-
-#define E1000_MNG_IAMT_MODE                  0x3
-#define E1000_MNG_DHCP_COOKIE_LENGTH         0x10
-#define E1000_MNG_DHCP_COOKIE_OFFSET         0x6F0
-#define E1000_MNG_DHCP_COMMAND_TIMEOUT       10
-#define E1000_MNG_DHCP_TX_PAYLOAD_CMD        64
-#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1
-#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN    0x2
-
-#define E1000_VFTA_ENTRY_SHIFT               5
-#define E1000_VFTA_ENTRY_MASK                0x7F
-#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK      0x1F
-
-#define E1000_HI_MAX_BLOCK_BYTE_LENGTH       1792 /* Num of bytes in range */
-#define E1000_HI_MAX_BLOCK_DWORD_LENGTH      448 /* Num of dwords in range */
-#define E1000_HI_COMMAND_TIMEOUT             500 /* Process HI command limit */
-
-#define E1000_HICR_EN              0x01  /* Enable bit - RO */
-/* Driver sets this bit when done to put command in RAM */
-#define E1000_HICR_C               0x02
-#define E1000_HICR_SV              0x04  /* Status Validity */
-#define E1000_HICR_FW_RESET_ENABLE 0x40
-#define E1000_HICR_FW_RESET        0x80
-
-/* Intel(R) Active Management Technology signature */
-#define E1000_IAMT_SIGNATURE  0x544D4149
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_nvm.c b/roms/ipxe/src/drivers/net/e1000e/e1000e_nvm.c
deleted file mode 100644
index f49d421f5e8be4ad955b779d37a2f5b02b5f51a2..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_nvm.c
+++ /dev/null
@@ -1,596 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include "e1000e.h"
-
-static void e1000e_stop_nvm(struct e1000_hw *hw);
-static void e1000e_reload_nvm(struct e1000_hw *hw);
-
-/**
- *  e1000e_init_nvm_ops_generic - Initialize NVM function pointers
- *  @hw: pointer to the HW structure
- *
- *  Setups up the function pointers to no-op functions
- **/
-void e1000e_init_nvm_ops_generic(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	/* Initialize function pointers */
-	nvm->ops.reload = e1000e_reload_nvm;
-}
-
-/**
- *  e1000e_raise_eec_clk - Raise EEPROM clock
- *  @hw: pointer to the HW structure
- *  @eecd: pointer to the EEPROM
- *
- *  Enable/Raise the EEPROM clock bit.
- **/
-static void e1000e_raise_eec_clk(struct e1000_hw *hw, u32 *eecd)
-{
-	*eecd = *eecd | E1000_EECD_SK;
-	ew32(EECD, *eecd);
-	e1e_flush();
-	udelay(hw->nvm.delay_usec);
-}
-
-/**
- *  e1000e_lower_eec_clk - Lower EEPROM clock
- *  @hw: pointer to the HW structure
- *  @eecd: pointer to the EEPROM
- *
- *  Clear/Lower the EEPROM clock bit.
- **/
-static void e1000e_lower_eec_clk(struct e1000_hw *hw, u32 *eecd)
-{
-	*eecd = *eecd & ~E1000_EECD_SK;
-	ew32(EECD, *eecd);
-	e1e_flush();
-	udelay(hw->nvm.delay_usec);
-}
-
-/**
- *  e1000e_shift_out_eec_bits - Shift data bits our to the EEPROM
- *  @hw: pointer to the HW structure
- *  @data: data to send to the EEPROM
- *  @count: number of bits to shift out
- *
- *  We need to shift 'count' bits out to the EEPROM.  So, the value in the
- *  "data" parameter will be shifted out to the EEPROM one bit at a time.
- *  In order to do this, "data" must be broken down into bits.
- **/
-static void e1000e_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = er32(EECD);
-	u32 mask;
-
-	mask = 0x01 << (count - 1);
-	if (nvm->type == e1000_nvm_eeprom_spi)
-		eecd |= E1000_EECD_DO;
-
-	do {
-		eecd &= ~E1000_EECD_DI;
-
-		if (data & mask)
-			eecd |= E1000_EECD_DI;
-
-		ew32(EECD, eecd);
-		e1e_flush();
-
-		udelay(nvm->delay_usec);
-
-		e1000e_raise_eec_clk(hw, &eecd);
-		e1000e_lower_eec_clk(hw, &eecd);
-
-		mask >>= 1;
-	} while (mask);
-
-	eecd &= ~E1000_EECD_DI;
-	ew32(EECD, eecd);
-}
-
-/**
- *  e1000e_shift_in_eec_bits - Shift data bits in from the EEPROM
- *  @hw: pointer to the HW structure
- *  @count: number of bits to shift in
- *
- *  In order to read a register from the EEPROM, we need to shift 'count' bits
- *  in from the EEPROM.  Bits are "shifted in" by raising the clock input to
- *  the EEPROM (setting the SK bit), and then reading the value of the data out
- *  "DO" bit.  During this "shifting in" process the data in "DI" bit should
- *  always be clear.
- **/
-static u16 e1000e_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
-{
-	u32 eecd;
-	u32 i;
-	u16 data;
-
-	eecd = er32(EECD);
-	eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
-	data = 0;
-
-	for (i = 0; i < count; i++) {
-		data <<= 1;
-		e1000e_raise_eec_clk(hw, &eecd);
-
-		eecd = er32(EECD);
-
-		eecd &= ~E1000_EECD_DI;
-		if (eecd & E1000_EECD_DO)
-			data |= 1;
-
-		e1000e_lower_eec_clk(hw, &eecd);
-	}
-
-	return data;
-}
-
-/**
- *  e1000e_poll_eerd_eewr_done - Poll for EEPROM read/write completion
- *  @hw: pointer to the HW structure
- *  @ee_reg: EEPROM flag for polling
- *
- *  Polls the EEPROM status bit for either read or write completion based
- *  upon the value of 'ee_reg'.
- **/
-s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
-{
-	u32 attempts = 100000;
-	u32 i, reg = 0;
-	s32 ret_val = -E1000_ERR_NVM;
-
-	for (i = 0; i < attempts; i++) {
-		if (ee_reg == E1000_NVM_POLL_READ)
-			reg = er32(EERD);
-		else
-			reg = er32(EEWR);
-
-		if (reg & E1000_NVM_RW_REG_DONE) {
-			ret_val = E1000_SUCCESS;
-			break;
-		}
-
-		udelay(5);
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000e_acquire_nvm - Generic request for access to EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
- *  Return successful if access grant bit set, else clear the request for
- *  EEPROM access and return -E1000_ERR_NVM (-1).
- **/
-s32 e1000e_acquire_nvm(struct e1000_hw *hw)
-{
-	u32 eecd = er32(EECD);
-	s32 timeout = E1000_NVM_GRANT_ATTEMPTS;
-	s32 ret_val = E1000_SUCCESS;
-
-	ew32(EECD, eecd | E1000_EECD_REQ);
-	eecd = er32(EECD);
-	while (timeout) {
-		if (eecd & E1000_EECD_GNT)
-			break;
-		udelay(5);
-		eecd = er32(EECD);
-		timeout--;
-	}
-
-	if (!timeout) {
-		eecd &= ~E1000_EECD_REQ;
-		ew32(EECD, eecd);
-		e_dbg("Could not acquire NVM grant\n");
-		ret_val = -E1000_ERR_NVM;
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000e_standby_nvm - Return EEPROM to standby state
- *  @hw: pointer to the HW structure
- *
- *  Return the EEPROM to a standby state.
- **/
-static void e1000e_standby_nvm(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = er32(EECD);
-
-	if (nvm->type == e1000_nvm_eeprom_spi) {
-		/* Toggle CS to flush commands */
-		eecd |= E1000_EECD_CS;
-		ew32(EECD, eecd);
-		e1e_flush();
-		udelay(nvm->delay_usec);
-		eecd &= ~E1000_EECD_CS;
-		ew32(EECD, eecd);
-		e1e_flush();
-		udelay(nvm->delay_usec);
-	}
-}
-
-/**
- *  e1000e_stop_nvm - Terminate EEPROM command
- *  @hw: pointer to the HW structure
- *
- *  Terminates the current command by inverting the EEPROM's chip select pin.
- **/
-static void e1000e_stop_nvm(struct e1000_hw *hw)
-{
-	u32 eecd;
-
-	eecd = er32(EECD);
-	if (hw->nvm.type == e1000_nvm_eeprom_spi) {
-		/* Pull CS high */
-		eecd |= E1000_EECD_CS;
-		e1000e_lower_eec_clk(hw, &eecd);
-	}
-}
-
-/**
- *  e1000e_release_nvm - Release exclusive access to EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
- **/
-void e1000e_release_nvm(struct e1000_hw *hw)
-{
-	u32 eecd;
-
-	e1000e_stop_nvm(hw);
-
-	eecd = er32(EECD);
-	eecd &= ~E1000_EECD_REQ;
-	ew32(EECD, eecd);
-}
-
-/**
- *  e1000e_ready_nvm_eeprom - Prepares EEPROM for read/write
- *  @hw: pointer to the HW structure
- *
- *  Setups the EEPROM for reading and writing.
- **/
-static s32 e1000e_ready_nvm_eeprom(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = er32(EECD);
-	s32 ret_val = E1000_SUCCESS;
-	u16 timeout = 0;
-	u8 spi_stat_reg;
-
-	if (nvm->type == e1000_nvm_eeprom_spi) {
-		/* Clear SK and CS */
-		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
-		ew32(EECD, eecd);
-		udelay(1);
-		timeout = NVM_MAX_RETRY_SPI;
-
-		/*
-		 * Read "Status Register" repeatedly until the LSB is cleared.
-		 * The EEPROM will signal that the command has been completed
-		 * by clearing bit 0 of the internal status register.  If it's
-		 * not cleared within 'timeout', then error out.
-		 */
-		while (timeout) {
-			e1000e_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
-			                         hw->nvm.opcode_bits);
-			spi_stat_reg = (u8)e1000e_shift_in_eec_bits(hw, 8);
-			if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
-				break;
-
-			udelay(5);
-			e1000e_standby_nvm(hw);
-			timeout--;
-		}
-
-		if (!timeout) {
-			e_dbg("SPI NVM Status error\n");
-			ret_val = -E1000_ERR_NVM;
-			goto out;
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_read_nvm_eerd - Reads EEPROM using EERD register
- *  @hw: pointer to the HW structure
- *  @offset: offset of word in the EEPROM to read
- *  @words: number of words to read
- *  @data: word read from the EEPROM
- *
- *  Reads a 16 bit word from the EEPROM using the EERD register.
- **/
-s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 i, eerd = 0;
-	s32 ret_val = E1000_SUCCESS;
-
-	/*
-	 * A check for invalid values:  offset too large, too many words,
-	 * too many words for the offset, and not enough words.
-	 */
-	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
-	    (words == 0)) {
-		e_dbg("nvm parameter(s) out of bounds\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	for (i = 0; i < words; i++) {
-		eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
-		       E1000_NVM_RW_REG_START;
-
-		ew32(EERD, eerd);
-		ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
-		if (ret_val)
-			break;
-
-		data[i] = (er32(EERD) >>
-		           E1000_NVM_RW_REG_DATA);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_write_nvm_spi - Write to EEPROM using SPI
- *  @hw: pointer to the HW structure
- *  @offset: offset within the EEPROM to be written to
- *  @words: number of words to write
- *  @data: 16 bit word(s) to be written to the EEPROM
- *
- *  Writes data to EEPROM at offset using SPI interface.
- *
- *  If e1000e_update_nvm_checksum is not called after this function , the
- *  EEPROM will most likely contain an invalid checksum.
- **/
-s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	s32 ret_val;
-	u16 widx = 0;
-
-	/*
-	 * A check for invalid values:  offset too large, too many words,
-	 * and not enough words.
-	 */
-	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
-	    (words == 0)) {
-		e_dbg("nvm parameter(s) out of bounds\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	ret_val = nvm->ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	while (widx < words) {
-		u8 write_opcode = NVM_WRITE_OPCODE_SPI;
-
-		ret_val = e1000e_ready_nvm_eeprom(hw);
-		if (ret_val)
-			goto release;
-
-		e1000e_standby_nvm(hw);
-
-		/* Send the WRITE ENABLE command (8 bit opcode) */
-		e1000e_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
-		                         nvm->opcode_bits);
-
-		e1000e_standby_nvm(hw);
-
-		/*
-		 * Some SPI eeproms use the 8th address bit embedded in the
-		 * opcode
-		 */
-		if ((nvm->address_bits == 8) && (offset >= 128))
-			write_opcode |= NVM_A8_OPCODE_SPI;
-
-		/* Send the Write command (8-bit opcode + addr) */
-		e1000e_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
-		e1000e_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
-		                         nvm->address_bits);
-
-		/* Loop to allow for up to whole page write of eeprom */
-		while (widx < words) {
-			u16 word_out = data[widx];
-			word_out = (word_out >> 8) | (word_out << 8);
-			e1000e_shift_out_eec_bits(hw, word_out, 16);
-			widx++;
-
-			if ((((offset + widx) * 2) % nvm->page_size) == 0) {
-				e1000e_standby_nvm(hw);
-				break;
-			}
-		}
-	}
-
-	msleep(10);
-release:
-	nvm->ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_read_pba_num - Read device part number
- *  @hw: pointer to the HW structure
- *  @pba_num: pointer to device part number
- *
- *  Reads the product board assembly (PBA) number from the EEPROM and stores
- *  the value in pba_num.
- **/
-s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num)
-{
-	s32  ret_val;
-	u16 nvm_data;
-
-	ret_val = e1000e_read_nvm(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
-	if (ret_val) {
-		e_dbg("NVM Read Error\n");
-		goto out;
-	}
-	*pba_num = (u32)(nvm_data << 16);
-
-	ret_val = e1000e_read_nvm(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
-	if (ret_val) {
-		e_dbg("NVM Read Error\n");
-		goto out;
-	}
-	*pba_num |= nvm_data;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_read_mac_addr_generic - Read device MAC address
- *  @hw: pointer to the HW structure
- *
- *  Reads the device MAC address from the EEPROM and stores the value.
- *  Since devices with two ports use the same EEPROM, we increment the
- *  last bit in the MAC address for the second port.
- **/
-s32 e1000e_read_mac_addr_generic(struct e1000_hw *hw)
-{
-	u32 rar_high;
-	u32 rar_low;
-	u16 i;
-
-	rar_high = er32(RAH(0));
-	rar_low = er32(RAL(0));
-
-	for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++)
-		hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8));
-
-	for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
-		hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8));
-
-	for (i = 0; i < ETH_ADDR_LEN; i++)
-		hw->mac.addr[i] = hw->mac.perm_addr[i];
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_validate_nvm_checksum_generic - Validate EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
- *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
- **/
-s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 checksum = 0;
-	u16 i, nvm_data;
-
-	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
-		ret_val = e1000e_read_nvm(hw, i, 1, &nvm_data);
-		if (ret_val) {
-			e_dbg("NVM Read Error\n");
-			goto out;
-		}
-		checksum += nvm_data;
-	}
-
-	if (checksum != (u16) NVM_SUM) {
-		e_dbg("NVM Checksum Invalid\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_update_nvm_checksum_generic - Update EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
- *  up to the checksum.  Then calculates the EEPROM checksum and writes the
- *  value to the EEPROM.
- **/
-s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw)
-{
-	s32  ret_val;
-	u16 checksum = 0;
-	u16 i, nvm_data;
-
-	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
-		ret_val = e1000e_read_nvm(hw, i, 1, &nvm_data);
-		if (ret_val) {
-			e_dbg("NVM Read Error while updating checksum.\n");
-			goto out;
-		}
-		checksum += nvm_data;
-	}
-	checksum = (u16) NVM_SUM - checksum;
-	ret_val = e1000e_write_nvm(hw, NVM_CHECKSUM_REG, 1, &checksum);
-	if (ret_val)
-		e_dbg("NVM Write Error while updating checksum.\n");
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_reload_nvm - Reloads EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
- *  extended control register.
- **/
-static void e1000e_reload_nvm(struct e1000_hw *hw)
-{
-	u32 ctrl_ext;
-
-	udelay(10);
-	ctrl_ext = er32(CTRL_EXT);
-	ctrl_ext |= E1000_CTRL_EXT_EE_RST;
-	ew32(CTRL_EXT, ctrl_ext);
-	e1e_flush();
-}
-
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_nvm.h b/roms/ipxe/src/drivers/net/e1000e/e1000e_nvm.h
deleted file mode 100644
index 1a8e0f3fc43c9da2e0b57a8eac77a8db7757c7dd..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_nvm.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000E_NVM_H_
-#define _E1000E_NVM_H_
-
-void e1000e_init_nvm_ops_generic(struct e1000_hw *hw);
-s32  e1000e_acquire_nvm(struct e1000_hw *hw);
-
-s32  e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
-s32  e1000e_read_mac_addr_generic(struct e1000_hw *hw);
-s32  e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num);
-s32  e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words,
-                         u16 *data);
-s32  e1000e_valid_led_default(struct e1000_hw *hw, u16 *data);
-s32  e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw);
-s32  e1000e_write_nvm_eewr(struct e1000_hw *hw, u16 offset,
-                          u16 words, u16 *data);
-s32  e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words,
-                         u16 *data);
-s32  e1000e_update_nvm_checksum_generic(struct e1000_hw *hw);
-void e1000e_release_nvm(struct e1000_hw *hw);
-
-#define E1000_STM_OPCODE  0xDB00
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_phy.c b/roms/ipxe/src/drivers/net/e1000e/e1000e_phy.c
deleted file mode 100644
index 337be7371df37405c3c9e7c96ffd0ad0ca71dd41..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_phy.c
+++ /dev/null
@@ -1,3323 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#include "e1000e.h"
-
-static s32 e1000e_copper_link_autoneg(struct e1000_hw *hw);
-static s32 e1000e_phy_setup_autoneg(struct e1000_hw *hw);
-static u32 e1000e_get_phy_addr_for_bm_page(u32 page, u32 reg);
-static s32 e1000e_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
-                                          u16 *data, bool read);
-static u32 e1000e_get_phy_addr_for_hv_page(u32 page);
-static s32 e1000e_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
-                                          u16 *data, bool read);
-#if 0
-/* Cable length tables */
-static const u16 e1000_m88_cable_length_table[] =
-	{ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
-#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
-                (sizeof(e1000_m88_cable_length_table) / \
-                 sizeof(e1000_m88_cable_length_table[0]))
-
-static const u16 e1000_igp_2_cable_length_table[] =
-    { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
-      0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
-      6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
-      21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
-      40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
-      60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
-      83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
-      104, 109, 114, 118, 121, 124};
-#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
-                (sizeof(e1000_igp_2_cable_length_table) / \
-                 sizeof(e1000_igp_2_cable_length_table[0]))
-#endif
-
-/**
- *  e1000e_check_reset_block_generic - Check if PHY reset is blocked
- *  @hw: pointer to the HW structure
- *
- *  Read the PHY management control register and check whether a PHY reset
- *  is blocked.  If a reset is not blocked return E1000_SUCCESS, otherwise
- *  return E1000_BLK_PHY_RESET (12).
- **/
-s32 e1000e_check_reset_block_generic(struct e1000_hw *hw)
-{
-	u32 manc;
-
-	manc = er32(MANC);
-
-	return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
-	       E1000_BLK_PHY_RESET : E1000_SUCCESS;
-}
-
-/**
- *  e1000e_get_phy_id - Retrieve the PHY ID and revision
- *  @hw: pointer to the HW structure
- *
- *  Reads the PHY registers and stores the PHY ID and possibly the PHY
- *  revision in the hardware structure.
- **/
-s32 e1000e_get_phy_id(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 phy_id;
-	u16 retry_count = 0;
-
-	if (!(phy->ops.read_reg))
-		goto out;
-
-	while (retry_count < 2) {
-		ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
-		if (ret_val)
-			goto out;
-
-		phy->id = (u32)(phy_id << 16);
-		udelay(20);
-		ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
-		if (ret_val)
-			goto out;
-
-		phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
-		phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
-
-		if (phy->id != 0 && phy->id != PHY_REVISION_MASK)
-			goto out;
-
-		/*
-		 * If the PHY ID is still unknown, we may have an 82577
-		 * without link.  We will try again after setting Slow MDIC
-		 * mode. No harm in trying again in this case since the PHY
-		 * ID is unknown at this point anyway.
-		 */
-		ret_val = phy->ops.acquire(hw);
-		if (ret_val)
-			goto out;
-		ret_val = e1000e_set_mdio_slow_mode_hv(hw, true);
-		if (ret_val)
-			goto out;
-		phy->ops.release(hw);
-
-		retry_count++;
-	}
-out:
-	/* Revert to MDIO fast mode, if applicable */
-	if (retry_count) {
-		ret_val = phy->ops.acquire(hw);
-		if (ret_val)
-			return ret_val;
-		ret_val = e1000e_set_mdio_slow_mode_hv(hw, false);
-		phy->ops.release(hw);
-	}
-
-	return ret_val;
-}
-
-/**
- *  e1000e_phy_reset_dsp - Reset PHY DSP
- *  @hw: pointer to the HW structure
- *
- *  Reset the digital signal processor.
- **/
-s32 e1000e_phy_reset_dsp(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (!(hw->phy.ops.write_reg))
-		goto out;
-
-	ret_val = e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_read_phy_reg_mdic - Read MDI control register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Reads the MDI control register in the PHY at offset and stores the
- *  information read to data.
- **/
-s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, mdic = 0;
-	s32 ret_val = E1000_SUCCESS;
-
-	/*
-	 * Set up Op-code, Phy Address, and register offset in the MDI
-	 * Control register.  The MAC will take care of interfacing with the
-	 * PHY to retrieve the desired data.
-	 */
-	mdic = ((offset << E1000_MDIC_REG_SHIFT) |
-	        (phy->addr << E1000_MDIC_PHY_SHIFT) |
-	        (E1000_MDIC_OP_READ));
-
-	ew32(MDIC, mdic);
-
-	/*
-	 * Poll the ready bit to see if the MDI read completed
-	 * Increasing the time out as testing showed failures with
-	 * the lower time out
-	 */
-	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
-		udelay(50);
-		mdic = er32(MDIC);
-		if (mdic & E1000_MDIC_READY)
-			break;
-	}
-	if (!(mdic & E1000_MDIC_READY)) {
-		e_dbg("MDI Read did not complete\n");
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-	if (mdic & E1000_MDIC_ERROR) {
-		e_dbg("MDI Error\n");
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-	*data = (u16) mdic;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_write_phy_reg_mdic - Write MDI control register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write to register at offset
- *
- *  Writes data to MDI control register in the PHY at offset.
- **/
-s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, mdic = 0;
-	s32 ret_val = E1000_SUCCESS;
-
-	/*
-	 * Set up Op-code, Phy Address, and register offset in the MDI
-	 * Control register.  The MAC will take care of interfacing with the
-	 * PHY to retrieve the desired data.
-	 */
-	mdic = (((u32)data) |
-	        (offset << E1000_MDIC_REG_SHIFT) |
-	        (phy->addr << E1000_MDIC_PHY_SHIFT) |
-	        (E1000_MDIC_OP_WRITE));
-
-	ew32(MDIC, mdic);
-
-	/*
-	 * Poll the ready bit to see if the MDI read completed
-	 * Increasing the time out as testing showed failures with
-	 * the lower time out
-	 */
-	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
-		udelay(50);
-		mdic = er32(MDIC);
-		if (mdic & E1000_MDIC_READY)
-			break;
-	}
-	if (!(mdic & E1000_MDIC_READY)) {
-		e_dbg("MDI Write did not complete\n");
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-	if (mdic & E1000_MDIC_ERROR) {
-		e_dbg("MDI Error\n");
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_read_phy_reg_m88 - Read m88 PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquires semaphore, if necessary, then reads the PHY register at offset
- *  and storing the retrieved information in data.  Release any acquired
- *  semaphores before exiting.
- **/
-s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (!(hw->phy.ops.acquire))
-		goto out;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                  data);
-
-	hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_write_phy_reg_m88 - Write m88 PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquires semaphore, if necessary, then writes the data to PHY register
- *  at the offset.  Release any acquired semaphores before exiting.
- **/
-s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (!(hw->phy.ops.acquire))
-		goto out;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                   data);
-
-	hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  __e1000e_read_phy_reg_igp - Read igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *  @locked: semaphore has already been acquired or not
- *
- *  Acquires semaphore, if necessary, then reads the PHY register at offset
- *  and stores the retrieved information in data.  Release any acquired
- *  semaphores before exiting.
- **/
-static s32 __e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data,
-                                    bool locked)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (!locked) {
-		if (!(hw->phy.ops.acquire))
-			goto out;
-
-		ret_val = hw->phy.ops.acquire(hw);
-		if (ret_val)
-			goto out;
-	}
-
-	if (offset > MAX_PHY_MULTI_PAGE_REG) {
-		ret_val = e1000e_write_phy_reg_mdic(hw,
-		                                   IGP01E1000_PHY_PAGE_SELECT,
-		                                   (u16)offset);
-		if (ret_val)
-			goto release;
-	}
-
-	ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                  data);
-
-release:
-	if (!locked)
-		hw->phy.ops.release(hw);
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_read_phy_reg_igp - Read igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquires semaphore then reads the PHY register at offset and stores the
- *  retrieved information in data.
- *  Release the acquired semaphore before exiting.
- **/
-s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	return __e1000e_read_phy_reg_igp(hw, offset, data, false);
-}
-
-/**
- *  e1000e_read_phy_reg_igp_locked - Read igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Reads the PHY register at offset and stores the retrieved information
- *  in data.  Assumes semaphore already acquired.
- **/
-s32 e1000e_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	return __e1000e_read_phy_reg_igp(hw, offset, data, true);
-}
-
-/**
- *  e1000e_write_phy_reg_igp - Write igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *  @locked: semaphore has already been acquired or not
- *
- *  Acquires semaphore, if necessary, then writes the data to PHY register
- *  at the offset.  Release any acquired semaphores before exiting.
- **/
-static s32 __e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data,
-                                     bool locked)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (!locked) {
-		if (!(hw->phy.ops.acquire))
-			goto out;
-
-		ret_val = hw->phy.ops.acquire(hw);
-		if (ret_val)
-			goto out;
-	}
-
-	if (offset > MAX_PHY_MULTI_PAGE_REG) {
-		ret_val = e1000e_write_phy_reg_mdic(hw,
-		                                   IGP01E1000_PHY_PAGE_SELECT,
-		                                   (u16)offset);
-		if (ret_val)
-			goto release;
-	}
-
-	ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                   data);
-
-release:
-	if (!locked)
-		hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_write_phy_reg_igp - Write igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquires semaphore then writes the data to PHY register
- *  at the offset.  Release any acquired semaphores before exiting.
- **/
-s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	return __e1000e_write_phy_reg_igp(hw, offset, data, false);
-}
-
-/**
- *  e1000e_write_phy_reg_igp_locked - Write igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Writes the data to PHY register at the offset.
- *  Assumes semaphore already acquired.
- **/
-s32 e1000e_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	return __e1000e_write_phy_reg_igp(hw, offset, data, true);
-}
-
-/**
- *  __e1000e_read_kmrn_reg - Read kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *  @locked: semaphore has already been acquired or not
- *
- *  Acquires semaphore, if necessary.  Then reads the PHY register at offset
- *  using the kumeran interface.  The information retrieved is stored in data.
- *  Release any acquired semaphores before exiting.
- **/
-static s32 __e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data,
-                                 bool locked)
-{
-	u32 kmrnctrlsta;
-	s32 ret_val = E1000_SUCCESS;
-
-	if (!locked) {
-		if (!(hw->phy.ops.acquire))
-			goto out;
-
-		ret_val = hw->phy.ops.acquire(hw);
-		if (ret_val)
-			goto out;
-	}
-
-	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
-	               E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
-	ew32(KMRNCTRLSTA, kmrnctrlsta);
-
-	udelay(2);
-
-	kmrnctrlsta = er32(KMRNCTRLSTA);
-	*data = (u16)kmrnctrlsta;
-
-	if (!locked)
-		hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_read_kmrn_reg -  Read kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquires semaphore then reads the PHY register at offset using the
- *  kumeran interface.  The information retrieved is stored in data.
- *  Release the acquired semaphore before exiting.
- **/
-s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	return __e1000e_read_kmrn_reg(hw, offset, data, false);
-}
-
-/**
- *  e1000e_read_kmrn_reg_locked -  Read kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Reads the PHY register at offset using the kumeran interface.  The
- *  information retrieved is stored in data.
- *  Assumes semaphore already acquired.
- **/
-s32 e1000e_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	return __e1000e_read_kmrn_reg(hw, offset, data, true);
-}
-
-/**
- *  __e1000e_write_kmrn_reg - Write kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *  @locked: semaphore has already been acquired or not
- *
- *  Acquires semaphore, if necessary.  Then write the data to PHY register
- *  at the offset using the kumeran interface.  Release any acquired semaphores
- *  before exiting.
- **/
-static s32 __e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data,
-                                  bool locked)
-{
-	u32 kmrnctrlsta;
-	s32 ret_val = E1000_SUCCESS;
-
-	if (!locked) {
-		if (!(hw->phy.ops.acquire))
-			goto out;
-
-		ret_val = hw->phy.ops.acquire(hw);
-		if (ret_val)
-			goto out;
-	}
-
-	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
-	               E1000_KMRNCTRLSTA_OFFSET) | data;
-	ew32(KMRNCTRLSTA, kmrnctrlsta);
-
-	udelay(2);
-
-	if (!locked)
-		hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_write_kmrn_reg -  Write kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquires semaphore then writes the data to the PHY register at the offset
- *  using the kumeran interface.  Release the acquired semaphore before exiting.
- **/
-s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	return __e1000e_write_kmrn_reg(hw, offset, data, false);
-}
-
-/**
- *  e1000e_write_kmrn_reg_locked -  Write kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Write the data to PHY register at the offset using the kumeran interface.
- *  Assumes semaphore already acquired.
- **/
-s32 e1000e_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	return __e1000e_write_kmrn_reg(hw, offset, data, true);
-}
-
-/**
- *  e1000e_copper_link_setup_82577 - Setup 82577 PHY for copper link
- *  @hw: pointer to the HW structure
- *
- *  Sets up Carrier-sense on Transmit and downshift values.
- **/
-s32 e1000e_copper_link_setup_82577(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data;
-
-	if (phy->reset_disable) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	/* Enable CRS on TX. This must be set for half-duplex operation. */
-	ret_val = e1e_rphy(hw, I82577_CFG_REG, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data |= I82577_CFG_ASSERT_CRS_ON_TX;
-
-	/* Enable downshift */
-	phy_data |= I82577_CFG_ENABLE_DOWNSHIFT;
-
-	ret_val = e1e_wphy(hw, I82577_CFG_REG, phy_data);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_copper_link_setup_m88 - Setup m88 PHY's for copper link
- *  @hw: pointer to the HW structure
- *
- *  Sets up MDI/MDI-X and polarity for m88 PHY's.  If necessary, transmit clock
- *  and downshift values are set also.
- **/
-s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data;
-
-	if (phy->reset_disable) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	/* Enable CRS on TX. This must be set for half-duplex operation. */
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	/* For BM PHY this bit is downshift enable */
-	if (phy->type != e1000_phy_bm)
-		phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-
-	/*
-	 * Options:
-	 *   MDI/MDI-X = 0 (default)
-	 *   0 - Auto for all speeds
-	 *   1 - MDI mode
-	 *   2 - MDI-X mode
-	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
-	 */
-	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
-
-	switch (phy->mdix) {
-	case 1:
-		phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
-		break;
-	case 2:
-		phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
-		break;
-	case 3:
-		phy_data |= M88E1000_PSCR_AUTO_X_1000T;
-		break;
-	case 0:
-	default:
-		phy_data |= M88E1000_PSCR_AUTO_X_MODE;
-		break;
-	}
-
-	/*
-	 * Options:
-	 *   disable_polarity_correction = 0 (default)
-	 *       Automatic Correction for Reversed Cable Polarity
-	 *   0 - Disabled
-	 *   1 - Enabled
-	 */
-	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
-	if (phy->disable_polarity_correction == 1)
-		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
-
-	/* Enable downshift on BM (disabled by default) */
-	if (phy->type == e1000_phy_bm)
-		phy_data |= BME1000_PSCR_ENABLE_DOWNSHIFT;
-
-	ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
-	if (ret_val)
-		goto out;
-
-	if ((phy->type == e1000_phy_m88) &&
-	    (phy->revision < E1000_REVISION_4) &&
-	    (phy->id != BME1000_E_PHY_ID_R2)) {
-		/*
-		 * Force TX_CLK in the Extended PHY Specific Control Register
-		 * to 25MHz clock.
-		 */
-		ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-		                             &phy_data);
-		if (ret_val)
-			goto out;
-
-		phy_data |= M88E1000_EPSCR_TX_CLK_25;
-
-		if ((phy->revision == E1000_REVISION_2) &&
-		    (phy->id == M88E1111_I_PHY_ID)) {
-			/* 82573L PHY - set the downshift counter to 5x. */
-			phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
-			phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
-		} else {
-			/* Configure Master and Slave downshift values */
-			phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
-			             M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
-			phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
-			             M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
-		}
-		ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-		                             phy_data);
-		if (ret_val)
-			goto out;
-	}
-
-	if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) {
-		/* Set PHY page 0, register 29 to 0x0003 */
-		ret_val = e1e_wphy(hw, 29, 0x0003);
-		if (ret_val)
-			goto out;
-
-		/* Set PHY page 0, register 30 to 0x0000 */
-		ret_val = e1e_wphy(hw, 30, 0x0000);
-		if (ret_val)
-			goto out;
-	}
-
-	/* Commit the changes. */
-	ret_val = e1000e_commit_phy(hw);
-	if (ret_val) {
-		e_dbg("Error committing the PHY changes\n");
-		goto out;
-	}
-
-	if (phy->type == e1000_phy_82578) {
-		ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-		                            &phy_data);
-		if (ret_val)
-			goto out;
-
-		/* 82578 PHY - set the downshift count to 1x. */
-		phy_data |= I82578_EPSCR_DOWNSHIFT_ENABLE;
-		phy_data &= ~I82578_EPSCR_DOWNSHIFT_COUNTER_MASK;
-		ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-		                             phy_data);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_copper_link_setup_igp - Setup igp PHY's for copper link
- *  @hw: pointer to the HW structure
- *
- *  Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
- *  igp PHY's.
- **/
-s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-
-	if (phy->reset_disable) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	ret_val = e1000e_phy_hw_reset(hw);
-	if (ret_val) {
-		e_dbg("Error resetting the PHY.\n");
-		goto out;
-	}
-
-	/*
-	 * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
-	 * timeout issues when LFS is enabled.
-	 */
-	msleep(100);
-
-	/*
-	 * The NVM settings will configure LPLU in D3 for
-	 * non-IGP1 PHYs.
-	 */
-	if (phy->type == e1000_phy_igp) {
-		/* disable lplu d3 during driver init */
-		ret_val = hw->phy.ops.set_d3_lplu_state(hw, false);
-		if (ret_val) {
-			e_dbg("Error Disabling LPLU D3\n");
-			goto out;
-		}
-	}
-
-	/* disable lplu d0 during driver init */
-	if (hw->phy.ops.set_d0_lplu_state) {
-		ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
-		if (ret_val) {
-			e_dbg("Error Disabling LPLU D0\n");
-			goto out;
-		}
-	}
-	/* Configure mdi-mdix settings */
-	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &data);
-	if (ret_val)
-		goto out;
-
-	data &= ~IGP01E1000_PSCR_AUTO_MDIX;
-
-	switch (phy->mdix) {
-	case 1:
-		data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
-		break;
-	case 2:
-		data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
-		break;
-	case 0:
-	default:
-		data |= IGP01E1000_PSCR_AUTO_MDIX;
-		break;
-	}
-	ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, data);
-	if (ret_val)
-		goto out;
-
-	/* set auto-master slave resolution settings */
-	if (hw->mac.autoneg) {
-		/*
-		 * when autonegotiation advertisement is only 1000Mbps then we
-		 * should disable SmartSpeed and enable Auto MasterSlave
-		 * resolution as hardware default.
-		 */
-		if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
-			/* Disable SmartSpeed */
-			ret_val = e1e_rphy(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             &data);
-			if (ret_val)
-				goto out;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-
-			/* Set auto Master/Slave resolution process */
-			ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data);
-			if (ret_val)
-				goto out;
-
-			data &= ~CR_1000T_MS_ENABLE;
-			ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data);
-			if (ret_val)
-				goto out;
-		}
-
-		ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data);
-		if (ret_val)
-			goto out;
-
-		/* load defaults for future use */
-		phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
-			((data & CR_1000T_MS_VALUE) ?
-			e1000_ms_force_master :
-			e1000_ms_force_slave) :
-			e1000_ms_auto;
-
-		switch (phy->ms_type) {
-		case e1000_ms_force_master:
-			data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
-			break;
-		case e1000_ms_force_slave:
-			data |= CR_1000T_MS_ENABLE;
-			data &= ~(CR_1000T_MS_VALUE);
-			break;
-		case e1000_ms_auto:
-			data &= ~CR_1000T_MS_ENABLE;
-		default:
-			break;
-		}
-		ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_copper_link_autoneg - Setup/Enable autoneg for copper link
- *  @hw: pointer to the HW structure
- *
- *  Performs initial bounds checking on autoneg advertisement parameter, then
- *  configure to advertise the full capability.  Setup the PHY to autoneg
- *  and restart the negotiation process between the link partner.  If
- *  autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
- **/
-static s32 e1000e_copper_link_autoneg(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_ctrl;
-
-	/*
-	 * Perform some bounds checking on the autoneg advertisement
-	 * parameter.
-	 */
-	phy->autoneg_advertised &= phy->autoneg_mask;
-
-	/*
-	 * If autoneg_advertised is zero, we assume it was not defaulted
-	 * by the calling code so we set to advertise full capability.
-	 */
-	if (phy->autoneg_advertised == 0)
-		phy->autoneg_advertised = phy->autoneg_mask;
-
-	e_dbg("Reconfiguring auto-neg advertisement params\n");
-	ret_val = e1000e_phy_setup_autoneg(hw);
-	if (ret_val) {
-		e_dbg("Error Setting up Auto-Negotiation\n");
-		goto out;
-	}
-	e_dbg("Restarting Auto-Neg\n");
-
-	/*
-	 * Restart auto-negotiation by setting the Auto Neg Enable bit and
-	 * the Auto Neg Restart bit in the PHY control register.
-	 */
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
-	if (ret_val)
-		goto out;
-
-	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Does the user want to wait for Auto-Neg to complete here, or
-	 * check at a later time (for example, callback routine).
-	 */
-	if (phy->autoneg_wait_to_complete) {
-		ret_val = hw->mac.ops.wait_autoneg(hw);
-		if (ret_val) {
-			e_dbg("Error while waiting for "
-			         "autoneg to complete\n");
-			goto out;
-		}
-	}
-
-	hw->mac.get_link_status = true;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_phy_setup_autoneg - Configure PHY for auto-negotiation
- *  @hw: pointer to the HW structure
- *
- *  Reads the MII auto-neg advertisement register and/or the 1000T control
- *  register and if the PHY is already setup for auto-negotiation, then
- *  return successful.  Otherwise, setup advertisement and flow control to
- *  the appropriate values for the wanted auto-negotiation.
- **/
-static s32 e1000e_phy_setup_autoneg(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 mii_autoneg_adv_reg;
-	u16 mii_1000t_ctrl_reg = 0;
-
-	phy->autoneg_advertised &= phy->autoneg_mask;
-
-	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
-	ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
-	if (ret_val)
-		goto out;
-
-	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
-		/* Read the MII 1000Base-T Control Register (Address 9). */
-		ret_val = e1e_rphy(hw, PHY_1000T_CTRL,
-		                            &mii_1000t_ctrl_reg);
-		if (ret_val)
-			goto out;
-	}
-
-	/*
-	 * Need to parse both autoneg_advertised and fc and set up
-	 * the appropriate PHY registers.  First we will parse for
-	 * autoneg_advertised software override.  Since we can advertise
-	 * a plethora of combinations, we need to check each bit
-	 * individually.
-	 */
-
-	/*
-	 * First we clear all the 10/100 mb speed bits in the Auto-Neg
-	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
-	 * the  1000Base-T Control Register (Address 9).
-	 */
-	mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
-	                         NWAY_AR_100TX_HD_CAPS |
-	                         NWAY_AR_10T_FD_CAPS   |
-	                         NWAY_AR_10T_HD_CAPS);
-	mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
-
-	e_dbg("autoneg_advertised %x\n", phy->autoneg_advertised);
-
-	/* Do we want to advertise 10 Mb Half Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
-		e_dbg("Advertise 10mb Half duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
-	}
-
-	/* Do we want to advertise 10 Mb Full Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
-		e_dbg("Advertise 10mb Full duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
-	}
-
-	/* Do we want to advertise 100 Mb Half Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
-		e_dbg("Advertise 100mb Half duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
-	}
-
-	/* Do we want to advertise 100 Mb Full Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
-		e_dbg("Advertise 100mb Full duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
-	}
-
-	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
-	if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
-		e_dbg("Advertise 1000mb Half duplex request denied!\n");
-
-	/* Do we want to advertise 1000 Mb Full Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
-		e_dbg("Advertise 1000mb Full duplex\n");
-		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
-	}
-
-	/*
-	 * Check for a software override of the flow control settings, and
-	 * setup the PHY advertisement registers accordingly.  If
-	 * auto-negotiation is enabled, then software will have to set the
-	 * "PAUSE" bits to the correct value in the Auto-Negotiation
-	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
-	 * negotiation.
-	 *
-	 * The possible values of the "fc" parameter are:
-	 *      0:  Flow control is completely disabled
-	 *      1:  Rx flow control is enabled (we can receive pause frames
-	 *          but not send pause frames).
-	 *      2:  Tx flow control is enabled (we can send pause frames
-	 *          but we do not support receiving pause frames).
-	 *      3:  Both Rx and Tx flow control (symmetric) are enabled.
-	 *  other:  No software override.  The flow control configuration
-	 *          in the EEPROM is used.
-	 */
-	switch (hw->fc.current_mode) {
-	case e1000_fc_none:
-		/*
-		 * Flow control (Rx & Tx) is completely disabled by a
-		 * software over-ride.
-		 */
-		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
-		break;
-	case e1000_fc_rx_pause:
-		/*
-		 * Rx Flow control is enabled, and Tx Flow control is
-		 * disabled, by a software over-ride.
-		 *
-		 * Since there really isn't a way to advertise that we are
-		 * capable of Rx Pause ONLY, we will advertise that we
-		 * support both symmetric and asymmetric Rx PAUSE.  Later
-		 * (in e1000e_config_fc_after_link_up) we will disable the
-		 * hw's ability to send PAUSE frames.
-		 */
-		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
-		break;
-	case e1000_fc_tx_pause:
-		/*
-		 * Tx Flow control is enabled, and Rx Flow control is
-		 * disabled, by a software over-ride.
-		 */
-		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
-		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
-		break;
-	case e1000_fc_full:
-		/*
-		 * Flow control (both Rx and Tx) is enabled by a software
-		 * over-ride.
-		 */
-		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
-		break;
-	default:
-		e_dbg("Flow control param set incorrectly\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	ret_val = e1e_wphy(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
-	if (ret_val)
-		goto out;
-
-	e_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
-
-	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
-		ret_val = e1e_wphy(hw,
-		                              PHY_1000T_CTRL,
-		                              mii_1000t_ctrl_reg);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_setup_copper_link - Configure copper link settings
- *  @hw: pointer to the HW structure
- *
- *  Calls the appropriate function to configure the link for auto-neg or forced
- *  speed and duplex.  Then we check for link, once link is established calls
- *  to configure collision distance and flow control are called.  If link is
- *  not established, we return -E1000_ERR_PHY (-2).
- **/
-s32 e1000e_setup_copper_link(struct e1000_hw *hw)
-{
-	s32 ret_val;
-	bool link;
-
-	if (hw->mac.autoneg) {
-		/*
-		 * Setup autoneg and flow control advertisement and perform
-		 * autonegotiation.
-		 */
-		ret_val = e1000e_copper_link_autoneg(hw);
-		if (ret_val)
-			goto out;
-	} else {
-#if 0
-		/*
-		 * PHY will be set to 10H, 10F, 100H or 100F
-		 * depending on user settings.
-		 */
-		e_dbg("Forcing Speed and Duplex\n");
-		ret_val = hw->phy.ops.force_speed_duplex(hw);
-		if (ret_val) {
-			e_dbg("Error Forcing Speed and Duplex\n");
-			goto out;
-		}
-#endif
-	}
-
-	/*
-	 * Check link status. Wait up to 100 microseconds for link to become
-	 * valid.
-	 */
-	ret_val = e1000e_phy_has_link_generic(hw,
-	                                     COPPER_LINK_UP_LIMIT,
-	                                     10,
-	                                     &link);
-	if (ret_val)
-		goto out;
-
-	if (link) {
-		e_dbg("Valid link established!!!\n");
-		e1000e_config_collision_dist(hw);
-		ret_val = e1000e_config_fc_after_link_up(hw);
-	} else {
-		e_dbg("Unable to establish link!!!\n");
-	}
-
-out:
-	return ret_val;
-}
-
-#if 0
-/**
- *  e1000e_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
- *  @hw: pointer to the HW structure
- *
- *  Calls the PHY setup function to force speed and duplex.  Clears the
- *  auto-crossover to force MDI manually.  Waits for link and returns
- *  successful if link up is successful, else -E1000_ERR_PHY (-2).
- **/
-s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data;
-	bool link;
-
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
-
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Clear Auto-Crossover to force MDI manually.  IGP requires MDI
-	 * forced whenever speed and duplex are forced.
-	 */
-	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
-	phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
-
-	ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
-	if (ret_val)
-		goto out;
-
-	e_dbg("IGP PSCR: %X\n", phy_data);
-
-	udelay(1);
-
-	if (phy->autoneg_wait_to_complete) {
-		e_dbg("Waiting for forced speed/duplex link on IGP phy.\n");
-
-		ret_val = e1000e_phy_has_link_generic(hw,
-		                                     PHY_FORCE_LIMIT,
-		                                     100000,
-		                                     &link);
-		if (ret_val)
-			goto out;
-
-		if (!link)
-			e_dbg("Link taking longer than expected.\n");
-
-		/* Try once more */
-		ret_val = e1000e_phy_has_link_generic(hw,
-		                                     PHY_FORCE_LIMIT,
-		                                     100000,
-		                                     &link);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-#endif
-
-#if 0
-/**
- *  e1000e_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
- *  @hw: pointer to the HW structure
- *
- *  Calls the PHY setup function to force speed and duplex.  Clears the
- *  auto-crossover to force MDI manually.  Resets the PHY to commit the
- *  changes.  If time expires while waiting for link up, we reset the DSP.
- *  After reset, TX_CLK and CRS on Tx must be set.  Return successful upon
- *  successful completion, else return corresponding error code.
- **/
-s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data;
-	bool link;
-
-	/*
-	 * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
-	 * forced whenever speed and duplex are forced.
-	 */
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
-	ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
-	if (ret_val)
-		goto out;
-
-	e_dbg("M88E1000 PSCR: %X\n", phy_data);
-
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
-
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
-	if (ret_val)
-		goto out;
-
-	/* Reset the phy to commit changes. */
-	ret_val = e1000e_commit_phy(hw);
-	if (ret_val)
-		goto out;
-
-	if (phy->autoneg_wait_to_complete) {
-		e_dbg("Waiting for forced speed/duplex link on M88 phy.\n");
-
-		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
-		                                     100000, &link);
-		if (ret_val)
-			goto out;
-
-		if (!link) {
-			/*
-			 * We didn't get link.
-			 * Reset the DSP and cross our fingers.
-			 */
-			ret_val = e1e_wphy(hw,
-			                              M88E1000_PHY_PAGE_SELECT,
-			                              0x001d);
-			if (ret_val)
-				goto out;
-			ret_val = e1000e_phy_reset_dsp(hw);
-			if (ret_val)
-				goto out;
-		}
-
-		/* Try once more */
-		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
-		                                     100000, &link);
-		if (ret_val)
-			goto out;
-	}
-
-	ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Resetting the phy means we need to re-force TX_CLK in the
-	 * Extended PHY Specific Control Register to 25MHz clock from
-	 * the reset value of 2.5MHz.
-	 */
-	phy_data |= M88E1000_EPSCR_TX_CLK_25;
-	ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * In addition, we must re-enable CRS on Tx for both half and full
-	 * duplex.
-	 */
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-	ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
-
-out:
-	return ret_val;
-}
-#endif
-
-#if 0
-/**
- *  e1000e_phy_force_speed_duplex_ife - Force PHY speed & duplex
- *  @hw: pointer to the HW structure
- *
- *  Forces the speed and duplex settings of the PHY.
- *  This is a function pointer entry point only called by
- *  PHY setup routines.
- **/
-s32 e1000e_phy_force_speed_duplex_ife(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-	bool link;
-
-	if (phy->type != e1000_phy_ife) {
-		ret_val = e1000e_phy_force_speed_duplex_igp(hw);
-		goto out;
-	}
-
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &data);
-	if (ret_val)
-		goto out;
-
-	e1000e_phy_force_speed_duplex_setup(hw, &data);
-
-	ret_val = e1e_wphy(hw, PHY_CONTROL, data);
-	if (ret_val)
-		goto out;
-
-	/* Disable MDI-X support for 10/100 */
-	ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
-	if (ret_val)
-		goto out;
-
-	data &= ~IFE_PMC_AUTO_MDIX;
-	data &= ~IFE_PMC_FORCE_MDIX;
-
-	ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, data);
-	if (ret_val)
-		goto out;
-
-	e_dbg("IFE PMC: %X\n", data);
-
-	udelay(1);
-
-	if (phy->autoneg_wait_to_complete) {
-		e_dbg("Waiting for forced speed/duplex link on IFE phy.\n");
-
-		ret_val = e1000e_phy_has_link_generic(hw,
-		                                     PHY_FORCE_LIMIT,
-		                                     100000,
-		                                     &link);
-		if (ret_val)
-			goto out;
-
-		if (!link)
-			e_dbg("Link taking longer than expected.\n");
-
-		/* Try once more */
-		ret_val = e1000e_phy_has_link_generic(hw,
-		                                     PHY_FORCE_LIMIT,
-		                                     100000,
-		                                     &link);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-#endif
-
-#if 0
-/**
- *  e1000e_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
- *  @hw: pointer to the HW structure
- *  @phy_ctrl: pointer to current value of PHY_CONTROL
- *
- *  Forces speed and duplex on the PHY by doing the following: disable flow
- *  control, force speed/duplex on the MAC, disable auto speed detection,
- *  disable auto-negotiation, configure duplex, configure speed, configure
- *  the collision distance, write configuration to CTRL register.  The
- *  caller must write to the PHY_CONTROL register for these settings to
- *  take affect.
- **/
-void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 ctrl;
-
-	/* Turn off flow control when forcing speed/duplex */
-	hw->fc.current_mode = e1000_fc_none;
-
-	/* Force speed/duplex on the mac */
-	ctrl = er32(CTRL);
-	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-	ctrl &= ~E1000_CTRL_SPD_SEL;
-
-	/* Disable Auto Speed Detection */
-	ctrl &= ~E1000_CTRL_ASDE;
-
-	/* Disable autoneg on the phy */
-	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
-
-	/* Forcing Full or Half Duplex? */
-	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
-		ctrl &= ~E1000_CTRL_FD;
-		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;
-		e_dbg("Half Duplex\n");
-	} else {
-		ctrl |= E1000_CTRL_FD;
-		*phy_ctrl |= MII_CR_FULL_DUPLEX;
-		e_dbg("Full Duplex\n");
-	}
-
-	/* Forcing 10mb or 100mb? */
-	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
-		ctrl |= E1000_CTRL_SPD_100;
-		*phy_ctrl |= MII_CR_SPEED_100;
-		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
-		e_dbg("Forcing 100mb\n");
-	} else {
-		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
-		*phy_ctrl |= MII_CR_SPEED_10;
-		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
-		e_dbg("Forcing 10mb\n");
-	}
-
-	e1000e_config_collision_dist(hw);
-
-	ew32(CTRL, ctrl);
-}
-#endif
-
-/**
- *  e1000e_set_d3_lplu_state - Sets low power link up state for D3
- *  @hw: pointer to the HW structure
- *  @active: boolean used to enable/disable lplu
- *
- *  Success returns 0, Failure returns 1
- *
- *  The low power link up (lplu) state is set to the power management level D3
- *  and SmartSpeed is disabled when active is true, else clear lplu for D3
- *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
- *  is used during Dx states where the power conservation is most important.
- *  During driver activity, SmartSpeed should be enabled so performance is
- *  maintained.
- **/
-s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 data;
-
-	if (!(hw->phy.ops.read_reg))
-		goto out;
-
-	ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data);
-	if (ret_val)
-		goto out;
-
-	if (!active) {
-		data &= ~IGP02E1000_PM_D3_LPLU;
-		ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT,
-		                             data);
-		if (ret_val)
-			goto out;
-		/*
-		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
-		 * during Dx states where the power conservation is most
-		 * important.  During driver activity we should enable
-		 * SmartSpeed, so performance is maintained.
-		 */
-		if (phy->smart_speed == e1000_smart_speed_on) {
-			ret_val = e1e_rphy(hw,
-			                            IGP01E1000_PHY_PORT_CONFIG,
-			                            &data);
-			if (ret_val)
-				goto out;
-
-			data |= IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		} else if (phy->smart_speed == e1000_smart_speed_off) {
-			ret_val = e1e_rphy(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             &data);
-			if (ret_val)
-				goto out;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = e1e_wphy(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		}
-	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
-	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
-	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
-		data |= IGP02E1000_PM_D3_LPLU;
-		ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT,
-		                              data);
-		if (ret_val)
-			goto out;
-
-		/* When LPLU is enabled, we should disable SmartSpeed */
-		ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-		                             &data);
-		if (ret_val)
-			goto out;
-
-		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-		ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
-		                              data);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_check_downshift - Checks whether a downshift in speed occurred
- *  @hw: pointer to the HW structure
- *
- *  Success returns 0, Failure returns 1
- *
- *  A downshift is detected by querying the PHY link health.
- **/
-s32 e1000e_check_downshift(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data, offset, mask;
-
-	switch (phy->type) {
-	case e1000_phy_m88:
-	case e1000_phy_gg82563:
-	case e1000_phy_bm:
-	case e1000_phy_82578:
-		offset	= M88E1000_PHY_SPEC_STATUS;
-		mask	= M88E1000_PSSR_DOWNSHIFT;
-		break;
-	case e1000_phy_igp_2:
-	case e1000_phy_igp:
-	case e1000_phy_igp_3:
-		offset	= IGP01E1000_PHY_LINK_HEALTH;
-		mask	= IGP01E1000_PLHR_SS_DOWNGRADE;
-		break;
-	default:
-		/* speed downshift not supported */
-		phy->speed_downgraded = false;
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	ret_val = e1e_rphy(hw, offset, &phy_data);
-
-	if (!ret_val)
-		phy->speed_downgraded = (phy_data & mask) ? true : false;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_check_polarity_m88 - Checks the polarity.
- *  @hw: pointer to the HW structure
- *
- *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
- *
- *  Polarity is determined based on the PHY specific status register.
- **/
-s32 e1000e_check_polarity_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &data);
-
-	if (!ret_val)
-		phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
-		                      ? e1000_rev_polarity_reversed
-		                      : e1000_rev_polarity_normal;
-
-	return ret_val;
-}
-
-/**
- *  e1000e_check_polarity_igp - Checks the polarity.
- *  @hw: pointer to the HW structure
- *
- *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
- *
- *  Polarity is determined based on the PHY port status register, and the
- *  current speed (since there is no polarity at 100Mbps).
- **/
-s32 e1000e_check_polarity_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data, offset, mask;
-
-	/*
-	 * Polarity is determined based on the speed of
-	 * our connection.
-	 */
-	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data);
-	if (ret_val)
-		goto out;
-
-	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
-	    IGP01E1000_PSSR_SPEED_1000MBPS) {
-		offset	= IGP01E1000_PHY_PCS_INIT_REG;
-		mask	= IGP01E1000_PHY_POLARITY_MASK;
-	} else {
-		/*
-		 * This really only applies to 10Mbps since
-		 * there is no polarity for 100Mbps (always 0).
-		 */
-		offset	= IGP01E1000_PHY_PORT_STATUS;
-		mask	= IGP01E1000_PSSR_POLARITY_REVERSED;
-	}
-
-	ret_val = e1e_rphy(hw, offset, &data);
-
-	if (!ret_val)
-		phy->cable_polarity = (data & mask)
-		                      ? e1000_rev_polarity_reversed
-		                      : e1000_rev_polarity_normal;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_check_polarity_ife - Check cable polarity for IFE PHY
- *  @hw: pointer to the HW structure
- *
- *  Polarity is determined on the polarity reversal feature being enabled.
- **/
-s32 e1000e_check_polarity_ife(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data, offset, mask;
-
-	/*
-	 * Polarity is determined based on the reversal feature being enabled.
-	 */
-	if (phy->polarity_correction) {
-		offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
-		mask = IFE_PESC_POLARITY_REVERSED;
-	} else {
-		offset = IFE_PHY_SPECIAL_CONTROL;
-		mask = IFE_PSC_FORCE_POLARITY;
-	}
-
-	ret_val = e1e_rphy(hw, offset, &phy_data);
-
-	if (!ret_val)
-		phy->cable_polarity = (phy_data & mask)
-		                       ? e1000_rev_polarity_reversed
-		                       : e1000_rev_polarity_normal;
-
-	return ret_val;
-}
-
-/**
- *  e1000e_wait_autoneg - Wait for auto-neg completion
- *  @hw: pointer to the HW structure
- *
- *  Waits for auto-negotiation to complete or for the auto-negotiation time
- *  limit to expire, which ever happens first.
- **/
-s32 e1000e_wait_autoneg(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 i, phy_status;
-
-	if (!(hw->phy.ops.read_reg))
-		return E1000_SUCCESS;
-
-	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
-	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
-		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
-		if (ret_val)
-			break;
-		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
-		if (ret_val)
-			break;
-		if (phy_status & MII_SR_AUTONEG_COMPLETE)
-			break;
-		msleep(100);
-	}
-
-	/*
-	 * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
-	 * has completed.
-	 */
-	return ret_val;
-}
-
-/**
- *  e1000e_phy_has_link_generic - Polls PHY for link
- *  @hw: pointer to the HW structure
- *  @iterations: number of times to poll for link
- *  @usec_interval: delay between polling attempts
- *  @success: pointer to whether polling was successful or not
- *
- *  Polls the PHY status register for link, 'iterations' number of times.
- **/
-s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
-                               u32 usec_interval, bool *success)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 i, phy_status;
-
-	if (!(hw->phy.ops.read_reg))
-		return E1000_SUCCESS;
-
-	for (i = 0; i < iterations; i++) {
-		/*
-		 * Some PHYs require the PHY_STATUS register to be read
-		 * twice due to the link bit being sticky.  No harm doing
-		 * it across the board.
-		 */
-		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
-		if (ret_val) {
-			/*
-			 * If the first read fails, another entity may have
-			 * ownership of the resources, wait and try again to
-			 * see if they have relinquished the resources yet.
-			 */
-			udelay(usec_interval);
-		}
-		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
-		if (ret_val)
-			break;
-		if (phy_status & MII_SR_LINK_STATUS)
-			break;
-		if (usec_interval >= 1000)
-			mdelay(usec_interval/1000);
-		else
-			udelay(usec_interval);
-	}
-
-	*success = (i < iterations) ? true : false;
-
-	return ret_val;
-}
-
-#if 0
-/**
- *  e1000e_get_cable_length_m88 - Determine cable length for m88 PHY
- *  @hw: pointer to the HW structure
- *
- *  Reads the PHY specific status register to retrieve the cable length
- *  information.  The cable length is determined by averaging the minimum and
- *  maximum values to get the "average" cable length.  The m88 PHY has four
- *  possible cable length values, which are:
- *	Register Value		Cable Length
- *	0			< 50 meters
- *	1			50 - 80 meters
- *	2			80 - 110 meters
- *	3			110 - 140 meters
- *	4			> 140 meters
- **/
-s32 e1000e_get_cable_length_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data, index;
-
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
-	if (ret_val)
-		goto out;
-
-	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
-	        M88E1000_PSSR_CABLE_LENGTH_SHIFT;
-	if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-
-	phy->min_cable_length = e1000_m88_cable_length_table[index];
-	phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
-
-	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_get_cable_length_igp_2 - Determine cable length for igp2 PHY
- *  @hw: pointer to the HW structure
- *
- *  The automatic gain control (agc) normalizes the amplitude of the
- *  received signal, adjusting for the attenuation produced by the
- *  cable.  By reading the AGC registers, which represent the
- *  combination of coarse and fine gain value, the value can be put
- *  into a lookup table to obtain the approximate cable length
- *  for each channel.
- **/
-s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 phy_data, i, agc_value = 0;
-	u16 cur_agc_index, max_agc_index = 0;
-	u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
-	u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
-	                                                 {IGP02E1000_PHY_AGC_A,
-	                                                  IGP02E1000_PHY_AGC_B,
-	                                                  IGP02E1000_PHY_AGC_C,
-	                                                  IGP02E1000_PHY_AGC_D};
-
-	/* Read the AGC registers for all channels */
-	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
-		ret_val = e1e_rphy(hw, agc_reg_array[i], &phy_data);
-		if (ret_val)
-			goto out;
-
-		/*
-		 * Getting bits 15:9, which represent the combination of
-		 * coarse and fine gain values.  The result is a number
-		 * that can be put into the lookup table to obtain the
-		 * approximate cable length.
-		 */
-		cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
-		                IGP02E1000_AGC_LENGTH_MASK;
-
-		/* Array index bound check. */
-		if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
-		    (cur_agc_index == 0)) {
-			ret_val = -E1000_ERR_PHY;
-			goto out;
-		}
-
-		/* Remove min & max AGC values from calculation. */
-		if (e1000_igp_2_cable_length_table[min_agc_index] >
-		    e1000_igp_2_cable_length_table[cur_agc_index])
-			min_agc_index = cur_agc_index;
-		if (e1000_igp_2_cable_length_table[max_agc_index] <
-		    e1000_igp_2_cable_length_table[cur_agc_index])
-			max_agc_index = cur_agc_index;
-
-		agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
-	}
-
-	agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
-	              e1000_igp_2_cable_length_table[max_agc_index]);
-	agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
-
-	/* Calculate cable length with the error range of +/- 10 meters. */
-	phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
-	                         (agc_value - IGP02E1000_AGC_RANGE) : 0;
-	phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
-
-	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
-
-out:
-	return ret_val;
-}
-#endif
-
-/**
- *  e1000e_get_phy_info_m88 - Retrieve PHY information
- *  @hw: pointer to the HW structure
- *
- *  Valid for only copper links.  Read the PHY status register (sticky read)
- *  to verify that link is up.  Read the PHY special control register to
- *  determine the polarity and 10base-T extended distance.  Read the PHY
- *  special status register to determine MDI/MDIx and current speed.  If
- *  speed is 1000, then determine cable length, local and remote receiver.
- **/
-s32 e1000e_get_phy_info_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32  ret_val;
-	u16 phy_data;
-	bool link;
-
-	if (phy->media_type != e1000_media_type_copper) {
-		e_dbg("Phy info is only valid for copper media\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		goto out;
-
-	if (!link) {
-		e_dbg("Phy info is only valid if link is up\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
-	                           ? true : false;
-
-	ret_val = e1000e_check_polarity_m88(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false;
-
-	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
-#if 0
-		ret_val = e1000e_get_cable_length(hw);
-#endif
-		ret_val = -E1000_ERR_CONFIG;
-		if (ret_val)
-			goto out;
-#if 0
-		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
-		if (ret_val)
-			goto out;
-
-		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
-		                ? e1000_1000t_rx_status_ok
-		                : e1000_1000t_rx_status_not_ok;
-
-		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
-		                 ? e1000_1000t_rx_status_ok
-		                 : e1000_1000t_rx_status_not_ok;
-#endif
-	} else {
-		/* Set values to "undefined" */
-		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
-		phy->local_rx = e1000_1000t_rx_status_undefined;
-		phy->remote_rx = e1000_1000t_rx_status_undefined;
-	}
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_get_phy_info_igp - Retrieve igp PHY information
- *  @hw: pointer to the HW structure
- *
- *  Read PHY status to determine if link is up.  If link is up, then
- *  set/determine 10base-T extended distance and polarity correction.  Read
- *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
- *  determine on the cable length, local and remote receiver.
- **/
-s32 e1000e_get_phy_info_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-	bool link;
-
-	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		goto out;
-
-	if (!link) {
-		e_dbg("Phy info is only valid if link is up\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	phy->polarity_correction = true;
-
-	ret_val = e1000e_check_polarity_igp(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data);
-	if (ret_val)
-		goto out;
-
-	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false;
-
-	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
-	    IGP01E1000_PSSR_SPEED_1000MBPS) {
-#if 0
-		ret_val = phy->ops.get_cable_length(hw);
-#endif
-		ret_val = -E1000_ERR_CONFIG;
-		if (ret_val)
-			goto out;
-#if 0
-		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data);
-		if (ret_val)
-			goto out;
-
-		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
-		                ? e1000_1000t_rx_status_ok
-		                : e1000_1000t_rx_status_not_ok;
-
-		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
-		                 ? e1000_1000t_rx_status_ok
-		                 : e1000_1000t_rx_status_not_ok;
-#endif
-	} else {
-		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
-		phy->local_rx = e1000_1000t_rx_status_undefined;
-		phy->remote_rx = e1000_1000t_rx_status_undefined;
-	}
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_phy_sw_reset - PHY software reset
- *  @hw: pointer to the HW structure
- *
- *  Does a software reset of the PHY by reading the PHY control register and
- *  setting/write the control register reset bit to the PHY.
- **/
-s32 e1000e_phy_sw_reset(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 phy_ctrl;
-
-	if (!(hw->phy.ops.read_reg))
-		goto out;
-
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
-	if (ret_val)
-		goto out;
-
-	phy_ctrl |= MII_CR_RESET;
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
-	if (ret_val)
-		goto out;
-
-	udelay(1);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_phy_hw_reset_generic - PHY hardware reset
- *  @hw: pointer to the HW structure
- *
- *  Verify the reset block is not blocking us from resetting.  Acquire
- *  semaphore (if necessary) and read/set/write the device control reset
- *  bit in the PHY.  Wait the appropriate delay time for the device to
- *  reset and release the semaphore (if necessary).
- **/
-s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u32 ctrl;
-
-	ret_val = e1000e_check_reset_block(hw);
-	if (ret_val) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	ret_val = phy->ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	ctrl = er32(CTRL);
-	ew32(CTRL, ctrl | E1000_CTRL_PHY_RST);
-	e1e_flush();
-
-	udelay(phy->reset_delay_us);
-
-	ew32(CTRL, ctrl);
-	e1e_flush();
-
-	udelay(150);
-
-	phy->ops.release(hw);
-
-	ret_val = phy->ops.get_cfg_done(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_get_cfg_done - Generic configuration done
- *  @hw: pointer to the HW structure
- *
- *  Generic function to wait 10 milli-seconds for configuration to complete
- *  and return success.
- **/
-s32 e1000e_get_cfg_done(struct e1000_hw *hw __unused)
-{
-	mdelay(10);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_phy_init_script_igp3 - Inits the IGP3 PHY
- *  @hw: pointer to the HW structure
- *
- *  Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
- **/
-s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw)
-{
-	e_dbg("Running IGP 3 PHY init script\n");
-
-	/* PHY init IGP 3 */
-	/* Enable rise/fall, 10-mode work in class-A */
-	e1e_wphy(hw, 0x2F5B, 0x9018);
-	/* Remove all caps from Replica path filter */
-	e1e_wphy(hw, 0x2F52, 0x0000);
-	/* Bias trimming for ADC, AFE and Driver (Default) */
-	e1e_wphy(hw, 0x2FB1, 0x8B24);
-	/* Increase Hybrid poly bias */
-	e1e_wphy(hw, 0x2FB2, 0xF8F0);
-	/* Add 4% to Tx amplitude in Gig mode */
-	e1e_wphy(hw, 0x2010, 0x10B0);
-	/* Disable trimming (TTT) */
-	e1e_wphy(hw, 0x2011, 0x0000);
-	/* Poly DC correction to 94.6% + 2% for all channels */
-	e1e_wphy(hw, 0x20DD, 0x249A);
-	/* ABS DC correction to 95.9% */
-	e1e_wphy(hw, 0x20DE, 0x00D3);
-	/* BG temp curve trim */
-	e1e_wphy(hw, 0x28B4, 0x04CE);
-	/* Increasing ADC OPAMP stage 1 currents to max */
-	e1e_wphy(hw, 0x2F70, 0x29E4);
-	/* Force 1000 ( required for enabling PHY regs configuration) */
-	e1e_wphy(hw, 0x0000, 0x0140);
-	/* Set upd_freq to 6 */
-	e1e_wphy(hw, 0x1F30, 0x1606);
-	/* Disable NPDFE */
-	e1e_wphy(hw, 0x1F31, 0xB814);
-	/* Disable adaptive fixed FFE (Default) */
-	e1e_wphy(hw, 0x1F35, 0x002A);
-	/* Enable FFE hysteresis */
-	e1e_wphy(hw, 0x1F3E, 0x0067);
-	/* Fixed FFE for short cable lengths */
-	e1e_wphy(hw, 0x1F54, 0x0065);
-	/* Fixed FFE for medium cable lengths */
-	e1e_wphy(hw, 0x1F55, 0x002A);
-	/* Fixed FFE for long cable lengths */
-	e1e_wphy(hw, 0x1F56, 0x002A);
-	/* Enable Adaptive Clip Threshold */
-	e1e_wphy(hw, 0x1F72, 0x3FB0);
-	/* AHT reset limit to 1 */
-	e1e_wphy(hw, 0x1F76, 0xC0FF);
-	/* Set AHT master delay to 127 msec */
-	e1e_wphy(hw, 0x1F77, 0x1DEC);
-	/* Set scan bits for AHT */
-	e1e_wphy(hw, 0x1F78, 0xF9EF);
-	/* Set AHT Preset bits */
-	e1e_wphy(hw, 0x1F79, 0x0210);
-	/* Change integ_factor of channel A to 3 */
-	e1e_wphy(hw, 0x1895, 0x0003);
-	/* Change prop_factor of channels BCD to 8 */
-	e1e_wphy(hw, 0x1796, 0x0008);
-	/* Change cg_icount + enable integbp for channels BCD */
-	e1e_wphy(hw, 0x1798, 0xD008);
-	/*
-	 * Change cg_icount + enable integbp + change prop_factor_master
-	 * to 8 for channel A
-	 */
-	e1e_wphy(hw, 0x1898, 0xD918);
-	/* Disable AHT in Slave mode on channel A */
-	e1e_wphy(hw, 0x187A, 0x0800);
-	/*
-	 * Enable LPLU and disable AN to 1000 in non-D0a states,
-	 * Enable SPD+B2B
-	 */
-	e1e_wphy(hw, 0x0019, 0x008D);
-	/* Enable restart AN on an1000_dis change */
-	e1e_wphy(hw, 0x001B, 0x2080);
-	/* Enable wh_fifo read clock in 10/100 modes */
-	e1e_wphy(hw, 0x0014, 0x0045);
-	/* Restart AN, Speed selection is 1000 */
-	e1e_wphy(hw, 0x0000, 0x1340);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000e_get_phy_type_from_id - Get PHY type from id
- *  @phy_id: phy_id read from the phy
- *
- *  Returns the phy type from the id.
- **/
-enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id)
-{
-	enum e1000_phy_type phy_type = e1000_phy_unknown;
-
-	switch (phy_id)	{
-	case M88E1000_I_PHY_ID:
-	case M88E1000_E_PHY_ID:
-	case M88E1111_I_PHY_ID:
-	case M88E1011_I_PHY_ID:
-		phy_type = e1000_phy_m88;
-		break;
-	case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
-		phy_type = e1000_phy_igp_2;
-		break;
-	case GG82563_E_PHY_ID:
-		phy_type = e1000_phy_gg82563;
-		break;
-	case IGP03E1000_E_PHY_ID:
-		phy_type = e1000_phy_igp_3;
-		break;
-	case IFE_E_PHY_ID:
-	case IFE_PLUS_E_PHY_ID:
-	case IFE_C_E_PHY_ID:
-		phy_type = e1000_phy_ife;
-		break;
-	case BME1000_E_PHY_ID:
-	case BME1000_E_PHY_ID_R2:
-		phy_type = e1000_phy_bm;
-		break;
-	case I82578_E_PHY_ID:
-		phy_type = e1000_phy_82578;
-		break;
-	case I82577_E_PHY_ID:
-		phy_type = e1000_phy_82577;
-		break;
-	default:
-		phy_type = e1000_phy_unknown;
-		break;
-	}
-	return phy_type;
-}
-
-/**
- *  e1000e_determine_phy_address - Determines PHY address.
- *  @hw: pointer to the HW structure
- *
- *  This uses a trial and error method to loop through possible PHY
- *  addresses. It tests each by reading the PHY ID registers and
- *  checking for a match.
- **/
-s32 e1000e_determine_phy_address(struct e1000_hw *hw)
-{
-	s32 ret_val = -E1000_ERR_PHY_TYPE;
-	u32 phy_addr = 0;
-	u32 i;
-	enum e1000_phy_type phy_type = e1000_phy_unknown;
-
-	hw->phy.id = phy_type;
-
-	for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) {
-		hw->phy.addr = phy_addr;
-		i = 0;
-
-		do {
-			e1000e_get_phy_id(hw);
-			phy_type = e1000e_get_phy_type_from_id(hw->phy.id);
-
-			/*
-			 * If phy_type is valid, break - we found our
-			 * PHY address
-			 */
-			if (phy_type  != e1000_phy_unknown) {
-				ret_val = E1000_SUCCESS;
-				goto out;
-			}
-			msleep(1);
-			i++;
-		} while (i < 10);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_get_phy_addr_for_bm_page - Retrieve PHY page address
- *  @page: page to access
- *
- *  Returns the phy address for the page requested.
- **/
-static u32 e1000e_get_phy_addr_for_bm_page(u32 page, u32 reg)
-{
-	u32 phy_addr = 2;
-
-	if ((page >= 768) || (page == 0 && reg == 25) || (reg == 31))
-		phy_addr = 1;
-
-	return phy_addr;
-}
-
-/**
- *  e1000e_write_phy_reg_bm - Write BM PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquires semaphore, if necessary, then writes the data to PHY register
- *  at the offset.  Release any acquired semaphores before exiting.
- **/
-s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	s32 ret_val;
-	u32 page_select = 0;
-	u32 page = offset >> IGP_PAGE_SHIFT;
-	u32 page_shift = 0;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		return ret_val;
-
-	/* Page 800 works differently than the rest so it has its own func */
-	if (page == BM_WUC_PAGE) {
-		ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset, &data,
-		                                         false);
-		goto out;
-	}
-
-	hw->phy.addr = e1000e_get_phy_addr_for_bm_page(page, offset);
-
-	if (offset > MAX_PHY_MULTI_PAGE_REG) {
-		/*
-		 * Page select is register 31 for phy address 1 and 22 for
-		 * phy address 2 and 3. Page select is shifted only for
-		 * phy address 1.
-		 */
-		if (hw->phy.addr == 1) {
-			page_shift = IGP_PAGE_SHIFT;
-			page_select = IGP01E1000_PHY_PAGE_SELECT;
-		} else {
-			page_shift = 0;
-			page_select = BM_PHY_PAGE_SELECT;
-		}
-
-		/* Page is shifted left, PHY expects (page x 32) */
-		ret_val = e1000e_write_phy_reg_mdic(hw, page_select,
-		                                   (page << page_shift));
-		if (ret_val)
-			goto out;
-	}
-
-	ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                   data);
-
-out:
-	hw->phy.ops.release(hw);
-	return ret_val;
-}
-
-/**
- *  e1000e_read_phy_reg_bm - Read BM PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquires semaphore, if necessary, then reads the PHY register at offset
- *  and storing the retrieved information in data.  Release any acquired
- *  semaphores before exiting.
- **/
-s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	s32 ret_val;
-	u32 page_select = 0;
-	u32 page = offset >> IGP_PAGE_SHIFT;
-	u32 page_shift = 0;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		return ret_val;
-
-	/* Page 800 works differently than the rest so it has its own func */
-	if (page == BM_WUC_PAGE) {
-		ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset, data,
-		                                         true);
-		goto out;
-	}
-
-	hw->phy.addr = e1000e_get_phy_addr_for_bm_page(page, offset);
-
-	if (offset > MAX_PHY_MULTI_PAGE_REG) {
-		/*
-		 * Page select is register 31 for phy address 1 and 22 for
-		 * phy address 2 and 3. Page select is shifted only for
-		 * phy address 1.
-		 */
-		if (hw->phy.addr == 1) {
-			page_shift = IGP_PAGE_SHIFT;
-			page_select = IGP01E1000_PHY_PAGE_SELECT;
-		} else {
-			page_shift = 0;
-			page_select = BM_PHY_PAGE_SELECT;
-		}
-
-		/* Page is shifted left, PHY expects (page x 32) */
-		ret_val = e1000e_write_phy_reg_mdic(hw, page_select,
-		                                   (page << page_shift));
-		if (ret_val)
-			goto out;
-	}
-
-	ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                  data);
-out:
-	hw->phy.ops.release(hw);
-	return ret_val;
-}
-
-/**
- *  e1000e_read_phy_reg_bm2 - Read BM PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquires semaphore, if necessary, then reads the PHY register at offset
- *  and storing the retrieved information in data.  Release any acquired
- *  semaphores before exiting.
- **/
-s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	s32 ret_val;
-	u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		return ret_val;
-
-	/* Page 800 works differently than the rest so it has its own func */
-	if (page == BM_WUC_PAGE) {
-		ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset, data,
-		                                         true);
-		goto out;
-	}
-
-	hw->phy.addr = 1;
-
-	if (offset > MAX_PHY_MULTI_PAGE_REG) {
-
-		/* Page is shifted left, PHY expects (page x 32) */
-		ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
-		                                   page);
-
-		if (ret_val)
-			goto out;
-	}
-
-	ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                  data);
-out:
-	hw->phy.ops.release(hw);
-	return ret_val;
-}
-
-/**
- *  e1000e_write_phy_reg_bm2 - Write BM PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquires semaphore, if necessary, then writes the data to PHY register
- *  at the offset.  Release any acquired semaphores before exiting.
- **/
-s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	s32 ret_val;
-	u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		return ret_val;
-
-	/* Page 800 works differently than the rest so it has its own func */
-	if (page == BM_WUC_PAGE) {
-		ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset, &data,
-		                                         false);
-		goto out;
-	}
-
-	hw->phy.addr = 1;
-
-	if (offset > MAX_PHY_MULTI_PAGE_REG) {
-		/* Page is shifted left, PHY expects (page x 32) */
-		ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
-		                                   page);
-
-		if (ret_val)
-			goto out;
-	}
-
-	ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                   data);
-
-out:
-	hw->phy.ops.release(hw);
-	return ret_val;
-}
-
-/**
- *  e1000e_access_phy_wakeup_reg_bm - Read BM PHY wakeup register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read or written
- *  @data: pointer to the data to read or write
- *  @read: determines if operation is read or write
- *
- *  Acquires semaphore, if necessary, then reads the PHY register at offset
- *  and storing the retrieved information in data.  Release any acquired
- *  semaphores before exiting. Note that procedure to read the wakeup
- *  registers are different. It works as such:
- *  1) Set page 769, register 17, bit 2 = 1
- *  2) Set page to 800 for host (801 if we were manageability)
- *  3) Write the address using the address opcode (0x11)
- *  4) Read or write the data using the data opcode (0x12)
- *  5) Restore 769_17.2 to its original value
- *
- *  Assumes semaphore already acquired.
- **/
-static s32 e1000e_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
-                                          u16 *data, bool read)
-{
-	s32 ret_val;
-	u16 reg = BM_PHY_REG_NUM(offset);
-	u16 phy_reg = 0;
-
-	/* Gig must be disabled for MDIO accesses to page 800 */
-	if ((hw->mac.type == e1000_pchlan) &&
-	   (!(er32(PHY_CTRL) & E1000_PHY_CTRL_GBE_DISABLE)))
-		e_dbg("Attempting to access page 800 while gig enabled.\n");
-
-	/* All operations in this function are phy address 1 */
-	hw->phy.addr = 1;
-
-	/* Set page 769 */
-	e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
-	                         (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
-
-	ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg);
-	if (ret_val) {
-		e_dbg("Could not read PHY page 769\n");
-		goto out;
-	}
-
-	/* First clear bit 4 to avoid a power state change */
-	phy_reg &= ~(BM_WUC_HOST_WU_BIT);
-	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
-	if (ret_val) {
-		e_dbg("Could not clear PHY page 769 bit 4\n");
-		goto out;
-	}
-
-	/* Write bit 2 = 1, and clear bit 4 to 769_17 */
-	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG,
-	                                   phy_reg | BM_WUC_ENABLE_BIT);
-	if (ret_val) {
-		e_dbg("Could not write PHY page 769 bit 2\n");
-		goto out;
-	}
-
-	/* Select page 800 */
-	ret_val = e1000e_write_phy_reg_mdic(hw,
-	                                   IGP01E1000_PHY_PAGE_SELECT,
-	                                   (BM_WUC_PAGE << IGP_PAGE_SHIFT));
-
-	/* Write the page 800 offset value using opcode 0x11 */
-	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ADDRESS_OPCODE, reg);
-	if (ret_val) {
-		e_dbg("Could not write address opcode to page 800\n");
-		goto out;
-	}
-
-	if (read) {
-	        /* Read the page 800 value using opcode 0x12 */
-		ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
-		                                  data);
-	} else {
-	        /* Write the page 800 value using opcode 0x12 */
-		ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
-		                                   *data);
-	}
-
-	if (ret_val) {
-		e_dbg("Could not access data value from page 800\n");
-		goto out;
-	}
-
-	/*
-	 * Restore 769_17.2 to its original value
-	 * Set page 769
-	 */
-	e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
-	                         (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
-
-	/* Clear 769_17.2 */
-	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
-	if (ret_val) {
-		e_dbg("Could not clear PHY page 769 bit 2\n");
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- * e1000e_power_up_phy_copper - Restore copper link in case of PHY power down
- * @hw: pointer to the HW structure
- *
- * In the case of a PHY power down to save power, or to turn off link during a
- * driver unload, or wake on lan is not enabled, restore the link to previous
- * settings.
- **/
-void e1000e_power_up_phy_copper(struct e1000_hw *hw)
-{
-	u16 mii_reg = 0;
-
-	/* The PHY will retain its settings across a power down/up cycle */
-	e1e_rphy(hw, PHY_CONTROL, &mii_reg);
-	mii_reg &= ~MII_CR_POWER_DOWN;
-	e1e_wphy(hw, PHY_CONTROL, mii_reg);
-}
-
-/**
- * e1000e_power_down_phy_copper - Restore copper link in case of PHY power down
- * @hw: pointer to the HW structure
- *
- * In the case of a PHY power down to save power, or to turn off link during a
- * driver unload, or wake on lan is not enabled, restore the link to previous
- * settings.
- **/
-void e1000e_power_down_phy_copper(struct e1000_hw *hw)
-{
-	u16 mii_reg = 0;
-
-	/* The PHY will retain its settings across a power down/up cycle */
-	e1e_rphy(hw, PHY_CONTROL, &mii_reg);
-	mii_reg |= MII_CR_POWER_DOWN;
-	e1e_wphy(hw, PHY_CONTROL, mii_reg);
-	msleep(1);
-}
-
-/**
- *  e1000e_set_mdio_slow_mode_hv - Set slow MDIO access mode
- *  @hw:   pointer to the HW structure
- *  @slow: true for slow mode, false for normal mode
- *
- *  Assumes semaphore already acquired.
- **/
-s32 e1000e_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 data = 0;
-
-	/* Set MDIO mode - page 769, register 16: 0x2580==slow, 0x2180==fast */
-	hw->phy.addr = 1;
-	ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
-				         (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT));
-	if (ret_val)
-		goto out;
-
-	ret_val = e1000e_write_phy_reg_mdic(hw, BM_CS_CTRL1,
-	                                   (0x2180 | (slow << 10)));
-	if (ret_val)
-		goto out;
-
-	/* dummy read when reverting to fast mode - throw away result */
-	if (!slow)
-		ret_val = e1000e_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data);
-
-out:
-	return ret_val;
-}
-
-/**
- *  __e1000e_read_phy_reg_hv -  Read HV PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *  @locked: semaphore has already been acquired or not
- *
- *  Acquires semaphore, if necessary, then reads the PHY register at offset
- *  and stores the retrieved information in data.  Release any acquired
- *  semaphore before exiting.
- **/
-static s32 __e1000e_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data,
-                                   bool locked)
-{
-	s32 ret_val;
-	u16 page = BM_PHY_REG_PAGE(offset);
-	u16 reg = BM_PHY_REG_NUM(offset);
-	bool in_slow_mode = false;
-
-	if (!locked) {
-		ret_val = hw->phy.ops.acquire(hw);
-		if (ret_val)
-			return ret_val;
-	}
-
-	/* Workaround failure in MDIO access while cable is disconnected */
-	if ((hw->phy.type == e1000_phy_82577) &&
-	    !(er32(STATUS) & E1000_STATUS_LU)) {
-		ret_val = e1000e_set_mdio_slow_mode_hv(hw, true);
-		if (ret_val)
-			goto out;
-
-		in_slow_mode = true;
-	}
-
-	/* Page 800 works differently than the rest so it has its own func */
-	if (page == BM_WUC_PAGE) {
-		ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset,
-		                                         data, true);
-		goto out;
-	}
-
-	if (page > 0 && page < HV_INTC_FC_PAGE_START) {
-		ret_val = e1000e_access_phy_debug_regs_hv(hw, offset,
-		                                         data, true);
-		goto out;
-	}
-
-	hw->phy.addr = e1000e_get_phy_addr_for_hv_page(page);
-
-	if (page == HV_INTC_FC_PAGE_START)
-		page = 0;
-
-	if (reg > MAX_PHY_MULTI_PAGE_REG) {
-		u32 phy_addr = hw->phy.addr;
-
-		hw->phy.addr = 1;
-
-		/* Page is shifted left, PHY expects (page x 32) */
-		ret_val = e1000e_write_phy_reg_mdic(hw,
-					     IGP01E1000_PHY_PAGE_SELECT,
-					     (page << IGP_PAGE_SHIFT));
-		hw->phy.addr = phy_addr;
-
-		if (ret_val)
-			goto out;
-	}
-
-	ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
-	                                  data);
-out:
-	/* Revert to MDIO fast mode, if applicable */
-	if ((hw->phy.type == e1000_phy_82577) && in_slow_mode)
-		ret_val |= e1000e_set_mdio_slow_mode_hv(hw, false);
-
-	if (!locked)
-		hw->phy.ops.release(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_read_phy_reg_hv -  Read HV PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquires semaphore then reads the PHY register at offset and stores
- *  the retrieved information in data.  Release the acquired semaphore
- *  before exiting.
- **/
-s32 e1000e_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	return __e1000e_read_phy_reg_hv(hw, offset, data, false);
-}
-
-/**
- *  e1000e_read_phy_reg_hv_locked -  Read HV PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Reads the PHY register at offset and stores the retrieved information
- *  in data.  Assumes semaphore already acquired.
- **/
-s32 e1000e_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	return __e1000e_read_phy_reg_hv(hw, offset, data, true);
-}
-
-/**
- *  __e1000e_write_phy_reg_hv - Write HV PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *  @locked: semaphore has already been acquired or not
- *
- *  Acquires semaphore, if necessary, then writes the data to PHY register
- *  at the offset.  Release any acquired semaphores before exiting.
- **/
-static s32 __e1000e_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data,
-                                    bool locked)
-{
-	s32 ret_val;
-	u16 page = BM_PHY_REG_PAGE(offset);
-	u16 reg = BM_PHY_REG_NUM(offset);
-	bool in_slow_mode = false;
-
-	if (!locked) {
-		ret_val = hw->phy.ops.acquire(hw);
-		if (ret_val)
-			return ret_val;
-	}
-
-	/* Workaround failure in MDIO access while cable is disconnected */
-	if ((hw->phy.type == e1000_phy_82577) &&
-	    !(er32(STATUS) & E1000_STATUS_LU)) {
-		ret_val = e1000e_set_mdio_slow_mode_hv(hw, true);
-		if (ret_val)
-			goto out;
-
-		in_slow_mode = true;
-	}
-
-	/* Page 800 works differently than the rest so it has its own func */
-	if (page == BM_WUC_PAGE) {
-		ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset,
-		                                         &data, false);
-		goto out;
-	}
-
-	if (page > 0 && page < HV_INTC_FC_PAGE_START) {
-		ret_val = e1000e_access_phy_debug_regs_hv(hw, offset,
-		                                         &data, false);
-		goto out;
-	}
-
-	hw->phy.addr = e1000e_get_phy_addr_for_hv_page(page);
-
-	if (page == HV_INTC_FC_PAGE_START)
-		page = 0;
-
-	/*
-	 * Workaround MDIO accesses being disabled after entering IEEE Power
-	 * Down (whenever bit 11 of the PHY Control register is set)
-	 */
-	if ((hw->phy.type == e1000_phy_82578) &&
-	    (hw->phy.revision >= 1) &&
-	    (hw->phy.addr == 2) &&
-	    ((MAX_PHY_REG_ADDRESS & reg) == 0) &&
-	    (data & (1 << 11))) {
-		u16 data2 = 0x7EFF;
-		ret_val = e1000e_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3,
-		                                         &data2, false);
-		if (ret_val)
-			goto out;
-	}
-
-	if (reg > MAX_PHY_MULTI_PAGE_REG) {
-		u32 phy_addr = hw->phy.addr;
-
-		hw->phy.addr = 1;
-
-		/* Page is shifted left, PHY expects (page x 32) */
-		ret_val = e1000e_write_phy_reg_mdic(hw,
-					     IGP01E1000_PHY_PAGE_SELECT,
-					     (page << IGP_PAGE_SHIFT));
-		hw->phy.addr = phy_addr;
-
-		if (ret_val)
-			goto out;
-	}
-
-	ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
-	                                  data);
-
-out:
-	/* Revert to MDIO fast mode, if applicable */
-	if ((hw->phy.type == e1000_phy_82577) && in_slow_mode)
-		ret_val |= e1000e_set_mdio_slow_mode_hv(hw, false);
-
-	if (!locked)
-		hw->phy.ops.release(hw);
-
-	return ret_val;
-}
-
-/**
- *  e1000e_write_phy_reg_hv - Write HV PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquires semaphore then writes the data to PHY register at the offset.
- *  Release the acquired semaphores before exiting.
- **/
-s32 e1000e_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	return __e1000e_write_phy_reg_hv(hw, offset, data, false);
-}
-
-/**
- *  e1000e_write_phy_reg_hv_locked - Write HV PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Writes the data to PHY register at the offset.  Assumes semaphore
- *  already acquired.
- **/
-s32 e1000e_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	return __e1000e_write_phy_reg_hv(hw, offset, data, true);
-}
-
-/**
- *  e1000e_get_phy_addr_for_hv_page - Get PHY adrress based on page
- *  @page: page to be accessed
- **/
-static u32 e1000e_get_phy_addr_for_hv_page(u32 page)
-{
-	u32 phy_addr = 2;
-
-	if (page >= HV_INTC_FC_PAGE_START)
-		phy_addr = 1;
-
-	return phy_addr;
-}
-
-/**
- *  e1000e_access_phy_debug_regs_hv - Read HV PHY vendor specific high registers
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read or written
- *  @data: pointer to the data to be read or written
- *  @read: determines if operation is read or written
- *
- *  Reads the PHY register at offset and stores the retreived information
- *  in data.  Assumes semaphore already acquired.  Note that the procedure
- *  to read these regs uses the address port and data port to read/write.
- **/
-static s32 e1000e_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
-                                          u16 *data, bool read)
-{
-	s32 ret_val;
-	u32 addr_reg = 0;
-	u32 data_reg = 0;
-
-	/* This takes care of the difference with desktop vs mobile phy */
-	addr_reg = (hw->phy.type == e1000_phy_82578) ?
-	           I82578_ADDR_REG : I82577_ADDR_REG;
-	data_reg = addr_reg + 1;
-
-	/* All operations in this function are phy address 2 */
-	hw->phy.addr = 2;
-
-	/* masking with 0x3F to remove the page from offset */
-	ret_val = e1000e_write_phy_reg_mdic(hw, addr_reg, (u16)offset & 0x3F);
-	if (ret_val) {
-		e_dbg("Could not write PHY the HV address register\n");
-		goto out;
-	}
-
-	/* Read or write the data value next */
-	if (read)
-		ret_val = e1000e_read_phy_reg_mdic(hw, data_reg, data);
-	else
-		ret_val = e1000e_write_phy_reg_mdic(hw, data_reg, *data);
-
-	if (ret_val) {
-		e_dbg("Could not read data value from HV data register\n");
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_link_stall_workaround_hv - Si workaround
- *  @hw: pointer to the HW structure
- *
- *  This function works around a Si bug where the link partner can get
- *  a link up indication before the PHY does.  If small packets are sent
- *  by the link partner they can be placed in the packet buffer without
- *  being properly accounted for by the PHY and will stall preventing
- *  further packets from being received.  The workaround is to clear the
- *  packet buffer after the PHY detects link up.
- **/
-s32 e1000e_link_stall_workaround_hv(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 data;
-
-	if (hw->phy.type != e1000_phy_82578)
-		goto out;
-
-	/* Do not apply workaround if in PHY loopback bit 14 set */
-	e1e_rphy(hw, PHY_CONTROL, &data);
-	if (data & PHY_CONTROL_LB)
-		goto out;
-
-	/* check if link is up and at 1Gbps */
-	ret_val = e1e_rphy(hw, BM_CS_STATUS, &data);
-	if (ret_val)
-		goto out;
-
-	data &= BM_CS_STATUS_LINK_UP |
-	        BM_CS_STATUS_RESOLVED |
-	        BM_CS_STATUS_SPEED_MASK;
-
-	if (data != (BM_CS_STATUS_LINK_UP |
-	             BM_CS_STATUS_RESOLVED |
-	             BM_CS_STATUS_SPEED_1000))
-		goto out;
-
-	msleep(200);
-
-	/* flush the packets in the fifo buffer */
-	ret_val = e1e_wphy(hw, HV_MUX_DATA_CTRL,
-	                                HV_MUX_DATA_CTRL_GEN_TO_MAC |
-	                                HV_MUX_DATA_CTRL_FORCE_SPEED);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1e_wphy(hw, HV_MUX_DATA_CTRL,
-	                                HV_MUX_DATA_CTRL_GEN_TO_MAC);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000e_check_polarity_82577 - Checks the polarity.
- *  @hw: pointer to the HW structure
- *
- *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
- *
- *  Polarity is determined based on the PHY specific status register.
- **/
-s32 e1000e_check_polarity_82577(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-
-	ret_val = e1e_rphy(hw, I82577_PHY_STATUS_2, &data);
-
-	if (!ret_val)
-		phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY)
-		                      ? e1000_rev_polarity_reversed
-		                      : e1000_rev_polarity_normal;
-
-	return ret_val;
-}
-
-#if 0
-/**
- *  e1000e_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY
- *  @hw: pointer to the HW structure
- *
- *  Calls the PHY setup function to force speed and duplex.  Clears the
- *  auto-crossover to force MDI manually.  Waits for link and returns
- *  successful if link up is successful, else -E1000_ERR_PHY (-2).
- **/
-s32 e1000e_phy_force_speed_duplex_82577(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data;
-	bool link;
-
-	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
-
-	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Clear Auto-Crossover to force MDI manually.  82577 requires MDI
-	 * forced whenever speed and duplex are forced.
-	 */
-	ret_val = e1e_rphy(hw, I82577_PHY_CTRL_2, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data &= ~I82577_PHY_CTRL2_AUTO_MDIX;
-	phy_data &= ~I82577_PHY_CTRL2_FORCE_MDI_MDIX;
-
-	ret_val = e1e_wphy(hw, I82577_PHY_CTRL_2, phy_data);
-	if (ret_val)
-		goto out;
-
-	e_dbg("I82577_PHY_CTRL_2: %X\n", phy_data);
-
-	udelay(1);
-
-	if (phy->autoneg_wait_to_complete) {
-		e_dbg("Waiting for forced speed/duplex link on 82577 phy\n");
-
-		ret_val = e1000e_phy_has_link_generic(hw,
-		                                     PHY_FORCE_LIMIT,
-		                                     100000,
-		                                     &link);
-		if (ret_val)
-			goto out;
-
-		if (!link)
-			e_dbg("Link taking longer than expected.\n");
-
-		/* Try once more */
-		ret_val = e1000e_phy_has_link_generic(hw,
-		                                     PHY_FORCE_LIMIT,
-		                                     100000,
-		                                     &link);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-#endif
-
-/**
- *  e1000e_get_phy_info_82577 - Retrieve I82577 PHY information
- *  @hw: pointer to the HW structure
- *
- *  Read PHY status to determine if link is up.  If link is up, then
- *  set/determine 10base-T extended distance and polarity correction.  Read
- *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
- *  determine on the cable length, local and remote receiver.
- **/
-s32 e1000e_get_phy_info_82577(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-	bool link;
-
-	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		goto out;
-
-	if (!link) {
-		e_dbg("Phy info is only valid if link is up\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	phy->polarity_correction = true;
-
-	ret_val = e1000e_check_polarity_82577(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = e1e_rphy(hw, I82577_PHY_STATUS_2, &data);
-	if (ret_val)
-		goto out;
-
-	phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? true : false;
-
-	if ((data & I82577_PHY_STATUS2_SPEED_MASK) ==
-	    I82577_PHY_STATUS2_SPEED_1000MBPS) {
-#if 0
-		ret_val = e1000e_get_cable_length(hw);
-#endif
-		ret_val = -E1000_ERR_CONFIG;
-		if (ret_val)
-			goto out;
-#if 0
-		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data);
-		if (ret_val)
-			goto out;
-
-		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
-		                ? e1000_1000t_rx_status_ok
-		                : e1000_1000t_rx_status_not_ok;
-
-		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
-		                 ? e1000_1000t_rx_status_ok
-		                 : e1000_1000t_rx_status_not_ok;
-#endif
-	} else {
-		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
-		phy->local_rx = e1000_1000t_rx_status_undefined;
-		phy->remote_rx = e1000_1000t_rx_status_undefined;
-	}
-out:
-	return ret_val;
-}
-
-#if 0
-/**
- *  e1000e_get_cable_length_82577 - Determine cable length for 82577 PHY
- *  @hw: pointer to the HW structure
- *
- * Reads the diagnostic status register and verifies result is valid before
- * placing it in the phy_cable_length field.
- **/
-s32 e1000e_get_cable_length_82577(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data, length;
-
-	ret_val = e1e_rphy(hw, I82577_PHY_DIAG_STATUS, &phy_data);
-	if (ret_val)
-		goto out;
-
-	length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >>
-	         I82577_DSTATUS_CABLE_LENGTH_SHIFT;
-
-	if (length == E1000_CABLE_LENGTH_UNDEFINED)
-		ret_val = -E1000_ERR_PHY;
-
-	phy->cable_length = length;
-
-out:
-	return ret_val;
-}
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_phy.h b/roms/ipxe/src/drivers/net/e1000e/e1000e_phy.h
deleted file mode 100644
index 9081050fed8a58e264794baf5eb54524e4829662..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_phy.h
+++ /dev/null
@@ -1,261 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000E_PHY_H_
-#define _E1000E_PHY_H_
-
-void e1000e_init_phy_ops_generic(struct e1000_hw *hw);
-s32  e1000e_check_downshift(struct e1000_hw *hw);
-s32  e1000e_check_polarity_m88(struct e1000_hw *hw);
-s32  e1000e_check_polarity_igp(struct e1000_hw *hw);
-s32  e1000e_check_polarity_ife(struct e1000_hw *hw);
-s32  e1000e_check_reset_block_generic(struct e1000_hw *hw);
-s32  e1000e_copper_link_setup_igp(struct e1000_hw *hw);
-s32  e1000e_copper_link_setup_m88(struct e1000_hw *hw);
-#if 0
-s32  e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw);
-s32  e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw);
-s32  e1000e_phy_force_speed_duplex_ife(struct e1000_hw *hw);
-#endif
-#if 0
-s32  e1000e_get_cable_length_m88(struct e1000_hw *hw);
-s32  e1000e_get_cable_length_igp_2(struct e1000_hw *hw);
-#endif
-s32  e1000e_get_cfg_done(struct e1000_hw *hw);
-s32  e1000e_get_phy_id(struct e1000_hw *hw);
-s32  e1000e_get_phy_info_igp(struct e1000_hw *hw);
-s32  e1000e_get_phy_info_m88(struct e1000_hw *hw);
-s32  e1000e_phy_sw_reset(struct e1000_hw *hw);
-#if 0
-void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
-#endif
-s32  e1000e_phy_hw_reset_generic(struct e1000_hw *hw);
-s32  e1000e_phy_reset_dsp(struct e1000_hw *hw);
-s32  e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000e_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000e_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active);
-s32  e1000e_setup_copper_link(struct e1000_hw *hw);
-s32  e1000e_wait_autoneg(struct e1000_hw *hw);
-s32  e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
-s32  e1000e_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data);
-s32  e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
-s32  e1000e_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data);
-s32  e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
-s32  e1000e_phy_reset_dsp(struct e1000_hw *hw);
-s32  e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
-                                u32 usec_interval, bool *success);
-s32  e1000e_phy_init_script_igp3(struct e1000_hw *hw);
-enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
-s32  e1000e_determine_phy_address(struct e1000_hw *hw);
-s32  e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data);
-s32  e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data);
-void e1000e_power_up_phy_copper(struct e1000_hw *hw);
-void e1000e_power_down_phy_copper(struct e1000_hw *hw);
-s32  e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
-s32  e1000e_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000e_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  e1000e_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data);
-s32  e1000e_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data);
-s32  e1000e_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow);
-s32  e1000e_link_stall_workaround_hv(struct e1000_hw *hw);
-s32  e1000e_copper_link_setup_82577(struct e1000_hw *hw);
-s32  e1000e_check_polarity_82577(struct e1000_hw *hw);
-s32  e1000e_get_phy_info_82577(struct e1000_hw *hw);
-#if 0
-s32  e1000e_phy_force_speed_duplex_82577(struct e1000_hw *hw);
-#endif
-#if 0
-s32  e1000e_get_cable_length_82577(struct e1000_hw *hw);
-#endif
-
-#define E1000_MAX_PHY_ADDR                4
-
-/* IGP01E1000 Specific Registers */
-#define IGP01E1000_PHY_PORT_CONFIG        0x10 /* Port Config */
-#define IGP01E1000_PHY_PORT_STATUS        0x11 /* Status */
-#define IGP01E1000_PHY_PORT_CTRL          0x12 /* Control */
-#define IGP01E1000_PHY_LINK_HEALTH        0x13 /* PHY Link Health */
-#define IGP01E1000_GMII_FIFO              0x14 /* GMII FIFO */
-#define IGP01E1000_PHY_CHANNEL_QUALITY    0x15 /* PHY Channel Quality */
-#define IGP02E1000_PHY_POWER_MGMT         0x19 /* Power Management */
-#define IGP01E1000_PHY_PAGE_SELECT        0x1F /* Page Select */
-#define BM_PHY_PAGE_SELECT                22   /* Page Select for BM */
-#define IGP_PAGE_SHIFT                    5
-#define PHY_REG_MASK                      0x1F
-
-/* BM/HV Specific Registers */
-#define BM_PORT_CTRL_PAGE                 769
-#define BM_PCIE_PAGE                      770
-#define BM_WUC_PAGE                       800
-#define BM_WUC_ADDRESS_OPCODE             0x11
-#define BM_WUC_DATA_OPCODE                0x12
-#define BM_WUC_ENABLE_PAGE                BM_PORT_CTRL_PAGE
-#define BM_WUC_ENABLE_REG                 17
-#define BM_WUC_ENABLE_BIT                 (1 << 2)
-#define BM_WUC_HOST_WU_BIT                (1 << 4)
-
-#define PHY_UPPER_SHIFT                   21
-#define BM_PHY_REG(page, reg) \
-	(((reg) & MAX_PHY_REG_ADDRESS) |\
-	 (((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\
-	 (((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)))
-#define BM_PHY_REG_PAGE(offset) \
-	((u16)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF))
-#define BM_PHY_REG_NUM(offset) \
-	((u16)(((offset) & MAX_PHY_REG_ADDRESS) |\
-	 (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\
-		~MAX_PHY_REG_ADDRESS)))
-
-#define HV_INTC_FC_PAGE_START             768
-#define I82578_ADDR_REG                   29
-#define I82577_ADDR_REG                   16
-#define I82577_CFG_REG                    22
-#define I82577_CFG_ASSERT_CRS_ON_TX       (1 << 15)
-#define I82577_CFG_ENABLE_DOWNSHIFT       (3 << 10) /* auto downshift 100/10 */
-#define I82577_CTRL_REG                   23
-
-/* 82577 specific PHY registers */
-#define I82577_PHY_CTRL_2            18
-#define I82577_PHY_LBK_CTRL          19
-#define I82577_PHY_STATUS_2          26
-#define I82577_PHY_DIAG_STATUS       31
-
-/* I82577 PHY Status 2 */
-#define I82577_PHY_STATUS2_REV_POLARITY   0x0400
-#define I82577_PHY_STATUS2_MDIX           0x0800
-#define I82577_PHY_STATUS2_SPEED_MASK     0x0300
-#define I82577_PHY_STATUS2_SPEED_1000MBPS 0x0200
-#define I82577_PHY_STATUS2_SPEED_100MBPS  0x0100
-
-/* I82577 PHY Control 2 */
-#define I82577_PHY_CTRL2_AUTO_MDIX        0x0400
-#define I82577_PHY_CTRL2_FORCE_MDI_MDIX   0x0200
-
-/* I82577 PHY Diagnostics Status */
-#define I82577_DSTATUS_CABLE_LENGTH       0x03FC
-#define I82577_DSTATUS_CABLE_LENGTH_SHIFT 2
-
-/* BM PHY Copper Specific Control 1 */
-#define BM_CS_CTRL1                       16
-#define BM_CS_CTRL1_ENERGY_DETECT         0x0300 /* Enable Energy Detect */
-
-/* BM PHY Copper Specific Status */
-#define BM_CS_STATUS                      17
-#define BM_CS_STATUS_ENERGY_DETECT        0x0010 /* Energy Detect Status */
-#define BM_CS_STATUS_LINK_UP              0x0400
-#define BM_CS_STATUS_RESOLVED             0x0800
-#define BM_CS_STATUS_SPEED_MASK           0xC000
-#define BM_CS_STATUS_SPEED_1000           0x8000
-
-/* 82577 Mobile Phy Status Register */
-#define HV_M_STATUS                       26
-#define HV_M_STATUS_AUTONEG_COMPLETE      0x1000
-#define HV_M_STATUS_SPEED_MASK            0x0300
-#define HV_M_STATUS_SPEED_1000            0x0200
-#define HV_M_STATUS_LINK_UP               0x0040
-
-#define IGP01E1000_PHY_PCS_INIT_REG       0x00B4
-#define IGP01E1000_PHY_POLARITY_MASK      0x0078
-
-#define IGP01E1000_PSCR_AUTO_MDIX         0x1000
-#define IGP01E1000_PSCR_FORCE_MDI_MDIX    0x2000 /* 0=MDI, 1=MDIX */
-
-#define IGP01E1000_PSCFR_SMART_SPEED      0x0080
-
-/* Enable flexible speed on link-up */
-#define IGP01E1000_GMII_FLEX_SPD          0x0010
-#define IGP01E1000_GMII_SPD               0x0020 /* Enable SPD */
-
-#define IGP02E1000_PM_SPD                 0x0001 /* Smart Power Down */
-#define IGP02E1000_PM_D0_LPLU             0x0002 /* For D0a states */
-#define IGP02E1000_PM_D3_LPLU             0x0004 /* For all other states */
-
-#define IGP01E1000_PLHR_SS_DOWNGRADE      0x8000
-
-#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
-#define IGP01E1000_PSSR_MDIX              0x0800
-#define IGP01E1000_PSSR_SPEED_MASK        0xC000
-#define IGP01E1000_PSSR_SPEED_1000MBPS    0xC000
-
-#define IGP02E1000_PHY_CHANNEL_NUM        4
-#define IGP02E1000_PHY_AGC_A              0x11B1
-#define IGP02E1000_PHY_AGC_B              0x12B1
-#define IGP02E1000_PHY_AGC_C              0x14B1
-#define IGP02E1000_PHY_AGC_D              0x18B1
-
-#define IGP02E1000_AGC_LENGTH_SHIFT       9   /* Course - 15:13, Fine - 12:9 */
-#define IGP02E1000_AGC_LENGTH_MASK        0x7F
-#define IGP02E1000_AGC_RANGE              15
-
-#define IGP03E1000_PHY_MISC_CTRL          0x1B
-#define IGP03E1000_PHY_MISC_DUPLEX_MANUAL_SET  0x1000 /* Manually Set Duplex */
-
-#define E1000_CABLE_LENGTH_UNDEFINED      0xFF
-
-#define E1000_KMRNCTRLSTA_OFFSET          0x001F0000
-#define E1000_KMRNCTRLSTA_OFFSET_SHIFT    16
-#define E1000_KMRNCTRLSTA_REN             0x00200000
-#define E1000_KMRNCTRLSTA_DIAG_OFFSET     0x3    /* Kumeran Diagnostic */
-#define E1000_KMRNCTRLSTA_TIMEOUTS        0x4    /* Kumeran Timeouts */
-#define E1000_KMRNCTRLSTA_INBAND_PARAM    0x9    /* Kumeran InBand Parameters */
-#define E1000_KMRNCTRLSTA_DIAG_NELPBK     0x1000 /* Nearend Loopback mode */
-#define E1000_KMRNCTRLSTA_K1_CONFIG        0x7
-#define E1000_KMRNCTRLSTA_K1_ENABLE        0x0002
-
-#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
-#define IFE_PHY_SPECIAL_CONTROL     0x11 /* 100BaseTx PHY Special Control */
-#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */
-#define IFE_PHY_MDIX_CONTROL        0x1C /* MDI/MDI-X Control */
-
-/* IFE PHY Extended Status Control */
-#define IFE_PESC_POLARITY_REVERSED    0x0100
-
-/* IFE PHY Special Control */
-#define IFE_PSC_AUTO_POLARITY_DISABLE      0x0010
-#define IFE_PSC_FORCE_POLARITY             0x0020
-#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100
-
-/* IFE PHY Special Control and LED Control */
-#define IFE_PSCL_PROBE_MODE            0x0020
-#define IFE_PSCL_PROBE_LEDS_OFF        0x0006 /* Force LEDs 0 and 2 off */
-#define IFE_PSCL_PROBE_LEDS_ON         0x0007 /* Force LEDs 0 and 2 on */
-
-/* IFE PHY MDIX Control */
-#define IFE_PMC_MDIX_STATUS      0x0020 /* 1=MDI-X, 0=MDI */
-#define IFE_PMC_FORCE_MDIX       0x0040 /* 1=force MDI-X, 0=force MDI */
-#define IFE_PMC_AUTO_MDIX        0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/e1000e/e1000e_regs.h b/roms/ipxe/src/drivers/net/e1000e/e1000e_regs.h
deleted file mode 100644
index 064d92c9a71974230d21a60f3fb04adb1500943e..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/e1000e/e1000e_regs.h
+++ /dev/null
@@ -1,340 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#ifndef _E1000E_REGS_H_
-#define _E1000E_REGS_H_
-
-#define E1000_CTRL     0x00000  /* Device Control - RW */
-#define E1000_CTRL_DUP 0x00004  /* Device Control Duplicate (Shadow) - RW */
-#define E1000_STATUS   0x00008  /* Device Status - RO */
-#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
-#define E1000_EERD     0x00014  /* EEPROM Read - RW */
-#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
-#define E1000_FLA      0x0001C  /* Flash Access - RW */
-#define E1000_MDIC     0x00020  /* MDI Control - RW */
-#define E1000_SCTL     0x00024  /* SerDes Control - RW */
-#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
-#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
-#define E1000_FEXT     0x0002C  /* Future Extended - RW */
-#define E1000_FEXTNVM  0x00028  /* Future Extended NVM - RW */
-#define E1000_FCT      0x00030  /* Flow Control Type - RW */
-#define E1000_CONNSW   0x00034  /* Copper/Fiber switch control - RW */
-#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
-#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
-#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
-#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
-#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
-#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
-#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
-#define E1000_IVAR     0x000E4  /* Interrupt Vector Allocation Register - RW */
-#define E1000_SVCR     0x000F0
-#define E1000_SVT       0x000F4
-#define E1000_RCTL     0x00100  /* Rx Control - RW */
-#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
-#define E1000_TXCW     0x00178  /* Tx Configuration Word - RW */
-#define E1000_RXCW     0x00180  /* Rx Configuration Word - RO */
-#define E1000_PBA_ECC  0x01100  /* PBA ECC Register */
-#define E1000_TCTL     0x00400  /* Tx Control - RW */
-#define E1000_TCTL_EXT 0x00404  /* Extended Tx Control - RW */
-#define E1000_TIPG     0x00410  /* Tx Inter-packet gap -RW */
-#define E1000_TBT      0x00448  /* Tx Burst Timer - RW */
-#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
-#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
-#define E1000_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
-#define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
-#define E1000_PHY_CTRL     0x00F10  /* PHY Control Register in CSR */
-#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
-#define E1000_PBS      0x01008  /* Packet Buffer Size */
-#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
-#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
-#define E1000_FLASHT   0x01028  /* FLASH Timer Register */
-#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
-#define E1000_FLSWCTL  0x01030  /* FLASH control register */
-#define E1000_FLSWDATA 0x01034  /* FLASH data register */
-#define E1000_FLSWCNT  0x01038  /* FLASH Access Counter */
-#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
-#define E1000_I2CCMD   0x01028  /* SFPI2C Command Register - RW */
-#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */
-#define E1000_WDSTP    0x01040  /* Watchdog Setup - RW */
-#define E1000_SWDSTS   0x01044  /* SW Device Status - RW */
-#define E1000_FRTIMER  0x01048  /* Free Running Timer - RW */
-#define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
-#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
-#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
-#define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - RW */
-#define E1000_RDFPCQ(_n)  (0x02430 + (0x4 * (_n)))
-#define E1000_PBRTH    0x02458  /* PB Rx Arbitration Threshold - RW */
-#define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */
-/* Split and Replication Rx Control - RW */
-#define E1000_RDPUMB   0x025CC  /* DMA Rx Descriptor uC Mailbox - RW */
-#define E1000_RDPUAD   0x025D0  /* DMA Rx Descriptor uC Addr Command - RW */
-#define E1000_RDPUWD   0x025D4  /* DMA Rx Descriptor uC Data Write - RW */
-#define E1000_RDPURD   0x025D8  /* DMA Rx Descriptor uC Data Read - RW */
-#define E1000_RDPUCTL  0x025DC  /* DMA Rx Descriptor uC Control - RW */
-#define E1000_RDTR     0x02820  /* Rx Delay Timer - RW */
-#define E1000_RADV     0x0282C  /* Rx Interrupt Absolute Delay Timer - RW */
-/*
- * Convenience macros
- *
- * Note: "_n" is the queue number of the register to be written to.
- *
- * Example usage:
- * E1000_RDBAL_REG(current_rx_queue)
- */
-#define E1000_RDBAL(_n)      ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \
-                                         (0x0C000 + ((_n) * 0x40)))
-#define E1000_RDBAH(_n)      ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \
-                                         (0x0C004 + ((_n) * 0x40)))
-#define E1000_RDLEN(_n)      ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \
-                                         (0x0C008 + ((_n) * 0x40)))
-#define E1000_SRRCTL(_n)     ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \
-                                         (0x0C00C + ((_n) * 0x40)))
-#define E1000_RDH(_n)        ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \
-                                         (0x0C010 + ((_n) * 0x40)))
-#define E1000_RXCTL(_n)      ((_n) < 4 ? (0x02814 + ((_n) * 0x100)) : \
-                                         (0x0C014 + ((_n) * 0x40)))
-#define E1000_DCA_RXCTRL(_n) E1000_RXCTL(_n)
-#define E1000_RDT(_n)        ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \
-                                         (0x0C018 + ((_n) * 0x40)))
-#define E1000_RXDCTL(_n)     ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \
-                                         (0x0C028 + ((_n) * 0x40)))
-#define E1000_RQDPC(_n)      ((_n) < 4 ? (0x02830 + ((_n) * 0x100)) : \
-                                         (0x0C030 + ((_n) * 0x40)))
-#define E1000_TDBAL(_n)      ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \
-                                         (0x0E000 + ((_n) * 0x40)))
-#define E1000_TDBAH(_n)      ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \
-                                         (0x0E004 + ((_n) * 0x40)))
-#define E1000_TDLEN(_n)      ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \
-                                         (0x0E008 + ((_n) * 0x40)))
-#define E1000_TDH(_n)        ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \
-                                         (0x0E010 + ((_n) * 0x40)))
-#define E1000_TXCTL(_n)      ((_n) < 4 ? (0x03814 + ((_n) * 0x100)) : \
-                                         (0x0E014 + ((_n) * 0x40)))
-#define E1000_DCA_TXCTRL(_n) E1000_TXCTL(_n)
-#define E1000_TDT(_n)        ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \
-                                         (0x0E018 + ((_n) * 0x40)))
-#define E1000_TXDCTL(_n)     ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \
-                                         (0x0E028 + ((_n) * 0x40)))
-#define E1000_TDWBAL(_n)     ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : \
-                                         (0x0E038 + ((_n) * 0x40)))
-#define E1000_TDWBAH(_n)     ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : \
-                                         (0x0E03C + ((_n) * 0x40)))
-#define E1000_TARC(_n)                   (0x03840 + ((_n) * 0x100))
-#define E1000_RSRPD    0x02C00  /* Rx Small Packet Detect - RW */
-#define E1000_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
-#define E1000_TXDMAC   0x03000  /* Tx DMA Control - RW */
-#define E1000_KABGTXD  0x03004  /* AFE Band Gap Transmit Ref Data */
-#define E1000_PSRTYPE(_i)       (0x05480 + ((_i) * 4))
-#define E1000_RAL(_i)  (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
-                                       (0x054E0 + ((_i - 16) * 8)))
-#define E1000_RAH(_i)  (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
-                                       (0x054E4 + ((_i - 16) * 8)))
-#define E1000_IP4AT_REG(_i)     (0x05840 + ((_i) * 8))
-#define E1000_IP6AT_REG(_i)     (0x05880 + ((_i) * 4))
-#define E1000_WUPM_REG(_i)      (0x05A00 + ((_i) * 4))
-#define E1000_FFMT_REG(_i)      (0x09000 + ((_i) * 8))
-#define E1000_FFVT_REG(_i)      (0x09800 + ((_i) * 8))
-#define E1000_FFLT_REG(_i)      (0x05F00 + ((_i) * 8))
-#define E1000_TDFH     0x03410  /* Tx Data FIFO Head - RW */
-#define E1000_TDFT     0x03418  /* Tx Data FIFO Tail - RW */
-#define E1000_TDFHS    0x03420  /* Tx Data FIFO Head Saved - RW */
-#define E1000_TDFTS    0x03428  /* Tx Data FIFO Tail Saved - RW */
-#define E1000_TDFPC    0x03430  /* Tx Data FIFO Packet Count - RW */
-#define E1000_TDPUMB   0x0357C  /* DMA Tx Descriptor uC Mail Box - RW */
-#define E1000_TDPUAD   0x03580  /* DMA Tx Descriptor uC Addr Command - RW */
-#define E1000_TDPUWD   0x03584  /* DMA Tx Descriptor uC Data Write - RW */
-#define E1000_TDPURD   0x03588  /* DMA Tx Descriptor uC Data  Read  - RW */
-#define E1000_TDPUCTL  0x0358C  /* DMA Tx Descriptor uC Control - RW */
-#define E1000_DTXCTL   0x03590  /* DMA Tx Control - RW */
-#define E1000_TIDV     0x03820  /* Tx Interrupt Delay Value - RW */
-#define E1000_TADV     0x0382C  /* Tx Interrupt Absolute Delay Val - RW */
-#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
-#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
-#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
-#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
-#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
-#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
-#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
-#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
-#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
-#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
-#define E1000_COLC     0x04028  /* Collision Count - R/clr */
-#define E1000_DC       0x04030  /* Defer Count - R/clr */
-#define E1000_TNCRS    0x04034  /* Tx-No CRS - R/clr */
-#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
-#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
-#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
-#define E1000_XONRXC   0x04048  /* XON Rx Count - R/clr */
-#define E1000_XONTXC   0x0404C  /* XON Tx Count - R/clr */
-#define E1000_XOFFRXC  0x04050  /* XOFF Rx Count - R/clr */
-#define E1000_XOFFTXC  0x04054  /* XOFF Tx Count - R/clr */
-#define E1000_FCRUC    0x04058  /* Flow Control Rx Unsupported Count- R/clr */
-#define E1000_PRC64    0x0405C  /* Packets Rx (64 bytes) - R/clr */
-#define E1000_PRC127   0x04060  /* Packets Rx (65-127 bytes) - R/clr */
-#define E1000_PRC255   0x04064  /* Packets Rx (128-255 bytes) - R/clr */
-#define E1000_PRC511   0x04068  /* Packets Rx (255-511 bytes) - R/clr */
-#define E1000_PRC1023  0x0406C  /* Packets Rx (512-1023 bytes) - R/clr */
-#define E1000_PRC1522  0x04070  /* Packets Rx (1024-1522 bytes) - R/clr */
-#define E1000_GPRC     0x04074  /* Good Packets Rx Count - R/clr */
-#define E1000_BPRC     0x04078  /* Broadcast Packets Rx Count - R/clr */
-#define E1000_MPRC     0x0407C  /* Multicast Packets Rx Count - R/clr */
-#define E1000_GPTC     0x04080  /* Good Packets Tx Count - R/clr */
-#define E1000_GORCL    0x04088  /* Good Octets Rx Count Low - R/clr */
-#define E1000_GORCH    0x0408C  /* Good Octets Rx Count High - R/clr */
-#define E1000_GOTCL    0x04090  /* Good Octets Tx Count Low - R/clr */
-#define E1000_GOTCH    0x04094  /* Good Octets Tx Count High - R/clr */
-#define E1000_RNBC     0x040A0  /* Rx No Buffers Count - R/clr */
-#define E1000_RUC      0x040A4  /* Rx Undersize Count - R/clr */
-#define E1000_RFC      0x040A8  /* Rx Fragment Count - R/clr */
-#define E1000_ROC      0x040AC  /* Rx Oversize Count - R/clr */
-#define E1000_RJC      0x040B0  /* Rx Jabber Count - R/clr */
-#define E1000_MGTPRC   0x040B4  /* Management Packets Rx Count - R/clr */
-#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
-#define E1000_MGTPTC   0x040BC  /* Management Packets Tx Count - R/clr */
-#define E1000_TORL     0x040C0  /* Total Octets Rx Low - R/clr */
-#define E1000_TORH     0x040C4  /* Total Octets Rx High - R/clr */
-#define E1000_TOTL     0x040C8  /* Total Octets Tx Low - R/clr */
-#define E1000_TOTH     0x040CC  /* Total Octets Tx High - R/clr */
-#define E1000_TPR      0x040D0  /* Total Packets Rx - R/clr */
-#define E1000_TPT      0x040D4  /* Total Packets Tx - R/clr */
-#define E1000_PTC64    0x040D8  /* Packets Tx (64 bytes) - R/clr */
-#define E1000_PTC127   0x040DC  /* Packets Tx (65-127 bytes) - R/clr */
-#define E1000_PTC255   0x040E0  /* Packets Tx (128-255 bytes) - R/clr */
-#define E1000_PTC511   0x040E4  /* Packets Tx (256-511 bytes) - R/clr */
-#define E1000_PTC1023  0x040E8  /* Packets Tx (512-1023 bytes) - R/clr */
-#define E1000_PTC1522  0x040EC  /* Packets Tx (1024-1522 Bytes) - R/clr */
-#define E1000_MPTC     0x040F0  /* Multicast Packets Tx Count - R/clr */
-#define E1000_BPTC     0x040F4  /* Broadcast Packets Tx Count - R/clr */
-#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context Tx - R/clr */
-#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context Tx Fail - R/clr */
-#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
-#define E1000_ICRXPTC  0x04104  /* Interrupt Cause Rx Pkt Timer Expire Count */
-#define E1000_ICRXATC  0x04108  /* Interrupt Cause Rx Abs Timer Expire Count */
-#define E1000_ICTXPTC  0x0410C  /* Interrupt Cause Tx Pkt Timer Expire Count */
-#define E1000_ICTXATC  0x04110  /* Interrupt Cause Tx Abs Timer Expire Count */
-#define E1000_ICTXQEC  0x04118  /* Interrupt Cause Tx Queue Empty Count */
-#define E1000_ICTXQMTC 0x0411C  /* Interrupt Cause Tx Queue Min Thresh Count */
-#define E1000_ICRXDMTC 0x04120  /* Interrupt Cause Rx Desc Min Thresh Count */
-#define E1000_ICRXOC   0x04124  /* Interrupt Cause Receiver Overrun Count */
-#define E1000_CRC_OFFSET 0x05F50  /* CRC Offset register */
-
-#define E1000_PCS_CFG0    0x04200  /* PCS Configuration 0 - RW */
-#define E1000_PCS_LCTL    0x04208  /* PCS Link Control - RW */
-#define E1000_PCS_LSTAT   0x0420C  /* PCS Link Status - RO */
-#define E1000_CBTMPC      0x0402C  /* Circuit Breaker Tx Packet Count */
-#define E1000_HTDPMC      0x0403C  /* Host Transmit Discarded Packets */
-#define E1000_CBRDPC      0x04044  /* Circuit Breaker Rx Dropped Count */
-#define E1000_CBRMPC      0x040FC  /* Circuit Breaker Rx Packet Count */
-#define E1000_RPTHC       0x04104  /* Rx Packets To Host */
-#define E1000_HGPTC       0x04118  /* Host Good Packets Tx Count */
-#define E1000_HTCBDPC     0x04124  /* Host Tx Circuit Breaker Dropped Count */
-#define E1000_HGORCL      0x04128  /* Host Good Octets Received Count Low */
-#define E1000_HGORCH      0x0412C  /* Host Good Octets Received Count High */
-#define E1000_HGOTCL      0x04130  /* Host Good Octets Transmit Count Low */
-#define E1000_HGOTCH      0x04134  /* Host Good Octets Transmit Count High */
-#define E1000_LENERRS     0x04138  /* Length Errors Count */
-#define E1000_SCVPC       0x04228  /* SerDes/SGMII Code Violation Pkt Count */
-#define E1000_HRMPC       0x0A018  /* Header Redirection Missed Packet Count */
-#define E1000_PCS_ANADV   0x04218  /* AN advertisement - RW */
-#define E1000_PCS_LPAB    0x0421C  /* Link Partner Ability - RW */
-#define E1000_PCS_NPTX    0x04220  /* AN Next Page Transmit - RW */
-#define E1000_PCS_LPABNP  0x04224  /* Link Partner Ability Next Page - RW */
-#define E1000_1GSTAT_RCV  0x04228  /* 1GSTAT Code Violation Packet Count - RW */
-#define E1000_RXCSUM   0x05000  /* Rx Checksum Control - RW */
-#define E1000_RLPML    0x05004  /* Rx Long Packet Max Length */
-#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
-#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
-#define E1000_RA       0x05400  /* Receive Address - RW Array */
-#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
-#define E1000_VT_CTL   0x0581C  /* VMDq Control - RW */
-#define E1000_VFQA0    0x0B000  /* VLAN Filter Queue Array 0 - RW Array */
-#define E1000_VFQA1    0x0B200  /* VLAN Filter Queue Array 1 - RW Array */
-#define E1000_WUC      0x05800  /* Wakeup Control - RW */
-#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
-#define E1000_WUS      0x05810  /* Wakeup Status - RO */
-#define E1000_MANC     0x05820  /* Management Control - RW */
-#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
-#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
-#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
-#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
-#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
-#define E1000_PBACL    0x05B68  /* MSIx PBA Clear - Read/Write 1's to clear */
-#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
-#define E1000_HOST_IF  0x08800  /* Host Interface */
-#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
-#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
-
-#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */
-#define E1000_MDPHYA      0x0003C /* PHY address - RW */
-#define E1000_MANC2H      0x05860 /* Management Control To Host - RW */
-#define E1000_SW_FW_SYNC  0x05B5C /* Software-Firmware Synchronization - RW */
-#define E1000_CCMCTL      0x05B48 /* CCM Control Register */
-#define E1000_GIOCTL      0x05B44 /* GIO Analog Control Register */
-#define E1000_SCCTL       0x05B4C /* PCIc PLL Configuration Register */
-#define E1000_GCR         0x05B00 /* PCI-Ex Control */
-#define E1000_GCR2        0x05B64 /* PCI-Ex Control #2 */
-#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
-#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
-#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
-#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
-#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
-#define E1000_SWSM      0x05B50 /* SW Semaphore */
-#define E1000_FWSM      0x05B54 /* FW Semaphore */
-#define E1000_SWSM2     0x05B58 /* Driver-only SW semaphore (not used by BOOT agents) */
-#define E1000_DCA_ID    0x05B70 /* DCA Requester ID Information - RO */
-#define E1000_DCA_CTRL  0x05B74 /* DCA Control - RW */
-#define E1000_FFLT_DBG  0x05F04 /* Debug Register */
-#define E1000_HICR      0x08F00 /* Host Interface Control */
-
-/* RSS registers */
-#define E1000_CPUVEC    0x02C10 /* CPU Vector Register - RW */
-#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
-#define E1000_IMIR(_i)      (0x05A80 + ((_i) * 4))  /* Immediate Interrupt */
-#define E1000_IMIREXT(_i)   (0x05AA0 + ((_i) * 4))  /* Immediate Interrupt Ext*/
-#define E1000_IMIRVP    0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */
-#define E1000_MSIXBM(_i)    (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register
-                                                    * (_i) - RW */
-#define E1000_MSIXTADD(_i)  (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr
-                                                       * low reg - RW */
-#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr
-                                                       * upper reg - RW */
-#define E1000_MSIXTMSG(_i)  (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry
-                                                       * message reg - RW */
-#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry
-                                                       * vector ctrl reg - RW */
-#define E1000_MSIXPBA    0x0E000 /* MSI-X Pending bit array */
-#define E1000_RETA(_i)  (0x05C00 + ((_i) * 4)) /* Redirection Table - RW */
-#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW */
-#define E1000_RSSIM     0x05864 /* RSS Interrupt Mask */
-#define E1000_RSSIR     0x05868 /* RSS Interrupt Request */
-#define E1000_RXMTRL     0x0B634 /* Time sync Rx EtherType and Msg Type - RW */
-#define E1000_RXUDP      0x0B638 /* Time Sync Rx UDP Port - RW */
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/eepro100.c b/roms/ipxe/src/drivers/net/eepro100.c
index 85840cdfae2624eae88425339cb1..ede0a1a4b8b70c2b7436b58e7989 100644
--- a/roms/ipxe/src/drivers/net/eepro100.c
+++ b/roms/ipxe/src/drivers/net/eepro100.c
@@ -25,7 +25,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  *
  *
  *              date       version  by      what
@@ -909,7 +910,7 @@ static void ifec_refill_rx_ring ( struct net_device *netdev )
  * Initial allocation & initialization of the rx ring.
  *
  * @v netdev  		Device of rx ring.
- * @ret rc    		Non-zero if error occured
+ * @ret rc    		Non-zero if error occurred
  */
 static int ifec_rx_setup ( struct net_device *netdev )
 {
@@ -1141,6 +1142,7 @@ PCI_ROM(0x8086, 0x5200, "eepro100-5200", "Intel EtherExpress PRO/100 Intelligent
 PCI_ROM(0x8086, 0x5201, "eepro100-5201", "Intel EtherExpress PRO/100 Intelligent Server", 0),
 PCI_ROM(0x8086, 0x1092, "82562-3",       "Intel Pro/100 VE Network", 0),
 PCI_ROM(0x8086, 0x27dc, "eepro100-27dc", "Intel 82801G (ICH7) Chipset Ethernet Controller", 0),
+PCI_ROM(0x8086, 0x10fe, "82552",         "Intel 82552 10/100 Network Connection", 0),
 };
 
 /* Cards with device ids 0x1030 to 0x103F, 0x2449, 0x2459 or 0x245D might need
diff --git a/roms/ipxe/src/drivers/net/efi/snpnet.c b/roms/ipxe/src/drivers/net/efi/snpnet.c
index b725d407f206c91fbc214de79856..9779081511019ceb088edd30cd5e 100644
--- a/roms/ipxe/src/drivers/net/efi/snpnet.c
+++ b/roms/ipxe/src/drivers/net/efi/snpnet.c
@@ -57,28 +57,25 @@ static int snpnet_transmit ( struct net_device *netdev,
 	struct snpnet_device *snpnetdev = netdev->priv;
 	EFI_SIMPLE_NETWORK_PROTOCOL *snp = snpnetdev->snp;
 	EFI_STATUS efirc;
+	void *txbuf=NULL;
 	size_t len = iob_len ( iobuf );
 
 	efirc = snp->Transmit ( snp, 0, len, iobuf->data, NULL, NULL, NULL );
-	return EFIRC_TO_RC ( efirc );
-}
-
-/**
- * Find a I/O buffer on the list of outstanding Tx buffers and complete it.
- *
- * @v snpnetdev		SNP network device
- * @v txbuf		Buffer address
- */
-static void snpnet_complete ( struct net_device *netdev, void *txbuf ) {
-	struct io_buffer *tmp;
-	struct io_buffer *iobuf;
-
-	list_for_each_entry_safe ( iobuf, tmp, &netdev->tx_queue, list ) {
-		if ( iobuf->data == txbuf ) {
-			netdev_tx_complete ( netdev, iobuf );
+	if (efirc) {
+		return EFIRC_TO_RC ( efirc );
+	}
+	/* since GetStatus is so inconsistent, don't try more than one outstanding transmit at a time */
+	while ( txbuf == NULL ) {
+		efirc = snp->GetStatus ( snp, NULL, &txbuf );
+		if ( efirc ) {
+			DBGC ( snp, "SNP %p could not get status %s\n", snp,
+			       efi_strerror ( efirc ) );
 			break;
 		}
+
 	}
+	netdev_tx_complete ( netdev, iobuf );
+	return 0;
 }
 
 /**
@@ -92,22 +89,6 @@ static void snpnet_poll ( struct net_device *netdev ) {
 	EFI_STATUS efirc;
 	struct io_buffer *iobuf = NULL;
 	UINTN len;
-	void *txbuf;
-
-	/* Process Tx completions */
-	while ( 1 ) {
-		efirc = snp->GetStatus ( snp, NULL, &txbuf );
-		if ( efirc ) {
-			DBGC ( snp, "SNP %p could not get status %s\n", snp,
-			       efi_strerror ( efirc ) );
-			break;
-		}
-
-		if ( txbuf == NULL )
-			break;
-
-		snpnet_complete ( netdev, txbuf );
-	}
 
 	/* Process received packets */
 	while ( 1 ) {
diff --git a/roms/ipxe/src/drivers/net/epic100.c b/roms/ipxe/src/drivers/net/epic100.c
index 5211317fffee8bb67544622cc325..8e31a3bfa3bf79dcf4e5a6ca4bb7 100644
--- a/roms/ipxe/src/drivers/net/epic100.c
+++ b/roms/ipxe/src/drivers/net/epic100.c
@@ -10,7 +10,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/pci.h>
 #include <ipxe/ethernet.h>
 #include "nic.h"
-#include <ipxe/console.h>
 #include "epic100.h"
 
 /* Condensed operations for readability */
@@ -251,7 +250,7 @@ epic100_open(void)
 
     outl(tmp, txcon);
 
-    /* Give adress of RX and TX ring to the chip */
+    /* Give address of RX and TX ring to the chip */
     outl(virt_to_le32desc(&rx_ring), prcdar);
     outl(virt_to_le32desc(&tx_ring), ptcdar);
 
@@ -366,7 +365,7 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type,
  * Arguments: none
  *
  * returns:   1 if a packet was received.
- *            0 if no pacet was received.
+ *            0 if no packet was received.
  * side effects:
  *            returns the packet in the array nic->packet.
  *            returns the length of the packet in nic->packetlen.
@@ -377,7 +376,7 @@ epic100_poll(struct nic *nic, int retrieve)
 {
     int entry;
     int retcode;
-    int status;
+    unsigned long status;
     entry = cur_rx % RX_RING_SIZE;
 
     if ((rx_ring[entry].status & cpu_to_le32(RRING_OWN)) == RRING_OWN)
@@ -402,7 +401,7 @@ epic100_poll(struct nic *nic, int retrieve)
 	retcode = 0;
     } else {
 	/* Omit the four octet CRC from the length. */
-	nic->packetlen = le32_to_cpu((rx_ring[entry].buflength))- 4;
+	nic->packetlen = (status >> 16) - 4;
 	memcpy(nic->packet, &rx_packet[entry * PKT_BUF_SZ], nic->packetlen);
 	retcode = 1;
     }
diff --git a/roms/ipxe/src/drivers/net/epic100.h b/roms/ipxe/src/drivers/net/epic100.h
index f290b1037c94f3495c0298cefe09..806c4bdabe11ea8623f50a64fb98 100644
--- a/roms/ipxe/src/drivers/net/epic100.h
+++ b/roms/ipxe/src/drivers/net/epic100.h
@@ -64,7 +64,7 @@ enum epic100_registers {
 #define INTR_RX_STATUS_OK	(0x00008000)	/* rx status valid. NI */
 #define INTR_PCI_TGT_ABT	(0x00004000)	/* PCI Target abort */
 #define INTR_PCI_MASTER_ABT	(0x00002000)	/* PCI Master abort */
-#define INTR_PCI_PARITY_ERR	(0x00001000)	/* PCI adress parity error */
+#define INTR_PCI_PARITY_ERR	(0x00001000)	/* PCI address parity error */
 #define INTR_PCI_DATA_ERR	(0x00000800)	/* PCI data parity error */
 #define INTR_RX_THR_CROSSED	(0x00000400)	/* rx copy threshold crossed */
 #define INTR_CNTFULL		(0x00000200)	/* Counter overflow */
diff --git a/roms/ipxe/src/drivers/net/etherfabric.c b/roms/ipxe/src/drivers/net/etherfabric.c
index 15e7d4c1395b453b2a2e6988074b..6036d32169985e65378320a0ba27 100644
--- a/roms/ipxe/src/drivers/net/etherfabric.c
+++ b/roms/ipxe/src/drivers/net/etherfabric.c
@@ -20,11 +20,11 @@ FILE_LICENCE ( GPL_ANY );
 
 #include <stdint.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <unistd.h>
 #include <errno.h>
 #include <assert.h>
 #include <byteswap.h>
-#include <ipxe/console.h>
 #include <ipxe/io.h>
 #include <ipxe/pci.h>
 #include <ipxe/malloc.h>
@@ -93,7 +93,6 @@ static int falcon_mdio_read ( struct efab_nic *efab, int device, int location );
 #define LPA_EF_10000FULL		0x00040000
 #define LPA_EF_10000HALF		0x00080000
 
-#define LPA_100			(LPA_100FULL | LPA_100HALF | LPA_100BASE4)
 #define LPA_EF_1000		( LPA_EF_1000FULL | LPA_EF_1000HALF )
 #define LPA_EF_10000               ( LPA_EF_10000FULL | LPA_EF_10000HALF )
 #define LPA_EF_DUPLEX		( LPA_10FULL | LPA_100FULL | LPA_EF_1000FULL | \
@@ -1567,7 +1566,7 @@ falcon_gmii_wait ( struct efab_nic *efab )
 	efab_dword_t md_stat;
 	int count;
 
-	/* wait upto 10ms */
+	/* wait up to 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 ) {
@@ -2196,7 +2195,7 @@ falcon_reset_xaui ( struct efab_nic *efab )
 	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 */
+	for (count = 0; count < 1000; count++) { /* wait up to 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 );
@@ -3396,7 +3395,7 @@ falcon_init_sram ( struct efab_nic *efab )
 		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 */
+	} while (++count < 20);	/* wait up to 0.4 sec */
 
 	EFAB_ERR ( "timed out waiting for SRAM reset\n");
 	return -ETIMEDOUT;
@@ -3427,7 +3426,7 @@ falcon_setup_nic ( struct efab_nic *efab )
 	falcon_write ( efab, &reg, FCN_RX_DC_CFG_REG_KER );
 	
 	/* Set number of RSS CPUs
-	 * bug7244: Increase filter depth to reduce RX_RESET likelyhood
+	 * bug7244: Increase filter depth to reduce RX_RESET likelihood
 	 */
 	EFAB_POPULATE_OWORD_5 ( reg,
 				FCN_NUM_KER, 0,
diff --git a/roms/ipxe/src/drivers/net/forcedeth.c b/roms/ipxe/src/drivers/net/forcedeth.c
index c34a42961479c81753c7aef9cb18..d8ece9a7a2cad6f3ba91f437b114 100644
--- a/roms/ipxe/src/drivers/net/forcedeth.c
+++ b/roms/ipxe/src/drivers/net/forcedeth.c
@@ -14,7 +14,8 @@
  *
  *    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.
+ *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *    02110-1301, USA.
  *
  * Portions of this code are taken from the Linux forcedeth driver that was
  * based on a cleanroom reimplementation which was based on reverse engineered
@@ -61,6 +62,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 static inline void pci_push ( void *ioaddr )
 {
 	/* force out pending posted writes */
+	wmb();
 	readl ( ioaddr );
 }
 
@@ -334,6 +336,7 @@ nv_disable_hw_interrupts ( struct forcedeth_private *priv )
 	void *ioaddr = priv->mmio_addr;
 
 	writel ( 0, ioaddr + NvRegIrqMask );
+	pci_push ( ioaddr );
 }
 
 static void
@@ -738,8 +741,7 @@ forcedeth_open ( struct net_device *netdev )
 		 ioaddr + NvRegReceiverStatus );
 
 	/* Set up slot time */
-	get_random_bytes ( &low, sizeof(low) );
-	low &= NVREG_SLOTTIME_MASK;
+	low = ( random() & NVREG_SLOTTIME_MASK );
 	writel ( low | NVREG_SLOTTIME_DEFAULT, ioaddr + NvRegSlotTime );
 
 	writel ( NVREG_TX_DEFERRAL_DEFAULT , ioaddr + NvRegTxDeferral );
@@ -764,7 +766,6 @@ forcedeth_open ( struct net_device *netdev )
 		 ioaddr + NvRegPowerState );
 
 	nv_disable_hw_interrupts ( priv );
-	pci_push ( ioaddr );
 	writel ( NVREG_MIISTAT_MASK_ALL, ioaddr + NvRegMIIStatus );
 	writel ( NVREG_IRQSTAT_MASK, ioaddr + NvRegIrqStatus );
 	pci_push ( ioaddr );
@@ -997,7 +998,7 @@ forcedeth_poll ( struct net_device *netdev )
 
 	DBG ( "forcedeth_poll: status = %#04x\n", status );
 
-	/* Link change interrupt occured. Call always if link is down,
+	/* Link change interrupt occurred. Call always if link is down,
 	 * to give auto-neg a chance to finish */
 	if ( ( status & NVREG_IRQ_LINK ) || ! ( netdev_link_ok ( netdev ) ) )
 		forcedeth_link_status ( netdev );
@@ -1018,7 +1019,6 @@ static void
 forcedeth_close ( struct net_device *netdev )
 {
 	struct forcedeth_private *priv = netdev_priv ( netdev );
-	void *ioaddr = priv->mmio_addr;
 
 	DBGP ( "forcedeth_close\n" );
 
@@ -1028,7 +1028,6 @@ forcedeth_close ( struct net_device *netdev )
 
 	/* Disable interrupts on the nic or we will lock up */
 	nv_disable_hw_interrupts ( priv );
-	pci_push ( ioaddr );
 
 	nv_free_rxtx_resources ( priv );
 
diff --git a/roms/ipxe/src/drivers/net/forcedeth.h b/roms/ipxe/src/drivers/net/forcedeth.h
index 70686d151a116a96654cbd53cf06..e1cf6f71af6a99b26ac6a4a507d0 100644
--- a/roms/ipxe/src/drivers/net/forcedeth.h
+++ b/roms/ipxe/src/drivers/net/forcedeth.h
@@ -14,7 +14,8 @@
  *
  *    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.
+ *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *    02110-1301, USA.
  *
  * Portions of this code are taken from the Linux forcedeth driver that was
  * based on a cleanroom reimplementation which was based on reverse engineered
@@ -54,7 +55,7 @@ struct ring_desc_ex {
 #define DESC_VER_3	3
 
 #define RX_RING_SIZE		16
-#define TX_RING_SIZE		16
+#define TX_RING_SIZE		32
 #define RXTX_RING_SIZE		( ( RX_RING_SIZE ) + ( TX_RING_SIZE ) )
 #define RX_RING_MIN		128
 #define TX_RING_MIN		64
diff --git a/roms/ipxe/src/drivers/net/igb/igb.c b/roms/ipxe/src/drivers/net/igb/igb.c
deleted file mode 100644
index cd5db1ffe6c22b250822d2fb500975b40078ad78..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2008 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-REQUIRE_OBJECT(igb_main);
-REQUIRE_OBJECT(igb_82575);
diff --git a/roms/ipxe/src/drivers/net/igb/igb.h b/roms/ipxe/src/drivers/net/igb/igb.h
deleted file mode 100644
index c8e8205dfdcfb4cb6e26788ee046e37dfd5dcf1d..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb.h
+++ /dev/null
@@ -1,324 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-/* Linux PRO/1000 Ethernet Driver main header file */
-
-#ifndef _IGB_H_
-#define _IGB_H_
-
-#include "igb_api.h"
-
-extern int igb_probe ( struct pci_device *pdev );
-extern void igb_remove ( struct pci_device *pdev );
-
-struct igb_adapter;
-
-/* Interrupt defines */
-#define IGB_START_ITR                    648 /* ~6000 ints/sec */
-
-/* Interrupt modes, as used by the IntMode paramter */
-#define IGB_INT_MODE_LEGACY                0
-#define IGB_INT_MODE_MSI                   1
-#define IGB_INT_MODE_MSIX                  2
-
-#define HW_PERF
-/* TX/RX descriptor defines */
-#define IGB_DEFAULT_TXD                  256
-#define IGB_MIN_TXD                       80
-#define IGB_MAX_TXD                     4096
-
-#define IGB_DEFAULT_RXD                  256
-#define IGB_MIN_RXD                       80
-#define IGB_MAX_RXD                     4096
-
-#define IGB_MIN_ITR_USECS                 10 /* 100k irq/sec */
-#define IGB_MAX_ITR_USECS               8191 /* 120  irq/sec */
-
-#define NON_Q_VECTORS                      1
-#define MAX_Q_VECTORS                      8
-
-/* Transmit and receive queues */
-#define IGB_MAX_RX_QUEUES                  (adapter->vfs_allocated_count ? 2 : \
-                                           (hw->mac.type > e1000_82575 ? 8 : 4))
-#define IGB_ABS_MAX_TX_QUEUES              8
-#define IGB_MAX_TX_QUEUES                  IGB_MAX_RX_QUEUES
-
-#define IGB_MAX_VF_MC_ENTRIES              30
-#define IGB_MAX_VF_FUNCTIONS               8
-#define IGB_MAX_VFTA_ENTRIES               128
-#define IGB_MAX_UTA_ENTRIES                128
-#define MAX_EMULATION_MAC_ADDRS            16
-#define OUI_LEN                            3
-
-struct vf_data_storage {
-	unsigned char vf_mac_addresses[ETH_ALEN];
-	u16 vf_mc_hashes[IGB_MAX_VF_MC_ENTRIES];
-	u16 num_vf_mc_hashes;
-	u16 default_vf_vlan_id;
-	u16 vlans_enabled;
-	unsigned char em_mac_addresses[MAX_EMULATION_MAC_ADDRS * ETH_ALEN];
-	u32 uta_table_copy[IGB_MAX_UTA_ENTRIES];
-	u32 flags;
-	unsigned long last_nack;
-};
-
-#define IGB_VF_FLAG_CTS            0x00000001 /* VF is clear to send data */
-#define IGB_VF_FLAG_UNI_PROMISC    0x00000002 /* VF has unicast promisc */
-#define IGB_VF_FLAG_MULTI_PROMISC  0x00000004 /* VF has multicast promisc */
-
-/* RX descriptor control thresholds.
- * PTHRESH - MAC will consider prefetch if it has fewer than this number of
- *           descriptors available in its onboard memory.
- *           Setting this to 0 disables RX descriptor prefetch.
- * HTHRESH - MAC will only prefetch if there are at least this many descriptors
- *           available in host memory.
- *           If PTHRESH is 0, this should also be 0.
- * WTHRESH - RX descriptor writeback threshold - MAC will delay writing back
- *           descriptors until either it has this many to write back, or the
- *           ITR timer expires.
- */
-#define IGB_RX_PTHRESH                    (hw->mac.type <= e1000_82576 ? 16 : 8)
-#define IGB_RX_HTHRESH                     8
-#define IGB_RX_WTHRESH                     1
-#define IGB_TX_PTHRESH                     8
-#define IGB_TX_HTHRESH                     1
-#define IGB_TX_WTHRESH                     ((hw->mac.type == e1000_82576 && \
-                                             adapter->msix_entries) ? 0 : 16)
-
-/* this is the size past which hardware will drop packets when setting LPE=0 */
-#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
-
-/* Supported Rx Buffer Sizes */
-#define IGB_RXBUFFER_128   128    /* Used for packet split */
-#define IGB_RXBUFFER_256   256    /* Used for packet split */
-#define IGB_RXBUFFER_512   512
-#define IGB_RXBUFFER_1024  1024
-#define IGB_RXBUFFER_2048  2048
-#define IGB_RXBUFFER_4096  4096
-#define IGB_RXBUFFER_8192  8192
-#define IGB_RXBUFFER_16384 16384
-
-/* Packet Buffer allocations */
-#define IGB_PBA_BYTES_SHIFT 0xA
-#define IGB_TX_HEAD_ADDR_SHIFT 7
-#define IGB_PBA_TX_MASK 0xFFFF0000
-
-#define IGB_FC_PAUSE_TIME 0x0680 /* 858 usec */
-
-/* How many Tx Descriptors do we need to call netif_wake_queue ? */
-#define IGB_TX_QUEUE_WAKE	32
-/* How many Rx Buffers do we bundle into one write to the hardware ? */
-#define IGB_RX_BUFFER_WRITE	16	/* Must be power of 2 */
-
-#define AUTO_ALL_MODES            0
-#define IGB_EEPROM_APME         0x0400
-
-#ifndef IGB_MASTER_SLAVE
-/* Switch to override PHY master/slave setting */
-#define IGB_MASTER_SLAVE	e1000_ms_hw_default
-#endif
-
-#define IGB_MNG_VLAN_NONE -1
-
-/* wrapper around a pointer to a socket buffer,
- * so a DMA handle can be stored along with the buffer */
-struct igb_buffer {
-	struct sk_buff *skb;
-	dma_addr_t dma;
-	dma_addr_t page_dma;
-	union {
-		/* TX */
-		struct {
-			unsigned long time_stamp;
-			u16 length;
-			u16 next_to_watch;
-		};
-
-#ifndef CONFIG_IGB_DISABLE_PACKET_SPLIT
-		/* RX */
-		struct {
-			unsigned long page_offset;
-			struct page *page;
-		};
-#endif
-	};
-};
-
-struct igb_queue_stats {
-	u64 packets;
-	u64 bytes;
-};
-
-struct igb_q_vector {
-	struct igb_adapter *adapter; /* backlink */
-	struct igb_ring *rx_ring;
-	struct igb_ring *tx_ring;
-#if 0
-	struct napi_struct napi;
-#endif
-	u32 eims_value;
-	u16 cpu;
-
-	u16 itr_val;
-	u8 set_itr;
-	u8 itr_shift;
-	void __iomem *itr_register;
-
-#if 0
-	char name[IFNAMSIZ + 9];
-#endif
-#ifndef HAVE_NETDEV_NAPI_LIST
-	struct net_device poll_dev;
-#endif
-};
-
-struct igb_ring {
-	struct igb_q_vector *q_vector; /* backlink to q_vector */
-	struct pci_dev *pdev;          /* pci device for dma mapping */
-	dma_addr_t dma;                /* phys address of the ring */
-	void *desc;                    /* descriptor ring memory */
-	unsigned int size;             /* length of desc. ring in bytes */
-	u16 count;                     /* number of desc. in the ring */
-	u16 next_to_use;
-	u16 next_to_clean;
-	u8 queue_index;
-	u8 reg_idx;
-	void __iomem *head;
-	void __iomem *tail;
-	struct igb_buffer *buffer_info; /* array of buffer info structs */
-
-	unsigned int total_bytes;
-	unsigned int total_packets;
-
-	struct igb_queue_stats stats;
-
-	union {
-		/* TX */
-		struct {
-			unsigned int restart_queue;
-			u32 ctx_idx;
-			bool detect_tx_hung;
-		};
-		/* RX */
-		struct {
-			u64 hw_csum_err;
-			u64 hw_csum_good;
-			u32 rx_buffer_len;
-			u16 rx_ps_hdr_size;
-			bool rx_csum;
-#ifdef IGB_LRO
-			struct net_lro_mgr lro_mgr;
-			bool lro_used;
-#endif
-		};
-	};
-};
-
-
-#define IGB_ADVTXD_DCMD (E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_RS)
-
-#define IGB_DESC_UNUSED(R) \
-	((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
-	(R)->next_to_clean - (R)->next_to_use - 1)
-
-#define E1000_RX_DESC_ADV(R, i)	    \
-	(&(((union e1000_adv_rx_desc *)((R).desc))[i]))
-#define E1000_TX_DESC_ADV(R, i)	    \
-	(&(((union e1000_adv_tx_desc *)((R).desc))[i]))
-#define E1000_TX_CTXTDESC_ADV(R, i)	    \
-	(&(((struct e1000_adv_tx_context_desc *)((R).desc))[i]))
-#define E1000_GET_DESC(R, i, type)	(&(((struct type *)((R).desc))[i]))
-#define E1000_TX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_tx_desc)
-#define E1000_RX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_rx_desc)
-
-#define MAX_MSIX_COUNT 10
-/* board specific private data structure */
-
-/* board specific private data structure */
-struct igb_adapter {
-
-	/* OS defined structs */
-	struct net_device *netdev;
-	struct pci_device *pdev;
-	struct net_device_stats net_stats;
-
-	/* structs defined in e1000_hw.h */
-	struct e1000_hw hw;
-
-	struct e1000_phy_info phy_info;
-
-        u32 min_frame_size;
-        u32 max_frame_size;
-
-	u32 wol;
-	u32 pba;
-	u32 max_hw_frame_size;
-
-	bool fc_autoneg;
-
-	unsigned int flags;
-	unsigned int flags2;
-
-#define NUM_TX_DESC	8
-#define NUM_RX_DESC	8
-
-	struct io_buffer *tx_iobuf[NUM_TX_DESC];
-	struct io_buffer *rx_iobuf[NUM_RX_DESC];
-
-	struct e1000_tx_desc *tx_base;
-	struct e1000_rx_desc *rx_base;
-
-	uint32_t tx_ring_size;
-	uint32_t rx_ring_size;
-
-	uint32_t tx_head;
-	uint32_t tx_tail;
-	uint32_t tx_fill_ctr;
-
-	uint32_t rx_curr;
-
-	uint32_t ioaddr;
-	uint32_t irqno;
-
-        uint32_t tx_int_delay;
-        uint32_t tx_abs_int_delay;
-        uint32_t txd_cmd;
-};
-
-#define IGB_FLAG_HAS_MSI           (1 << 0)
-#define IGB_FLAG_MSI_ENABLE        (1 << 1)
-#define IGB_FLAG_DCA_ENABLED       (1 << 3)
-#define IGB_FLAG_LLI_PUSH          (1 << 4)
-#define IGB_FLAG_IN_NETPOLL        (1 << 5)
-#define IGB_FLAG_QUAD_PORT_A       (1 << 6)
-#define IGB_FLAG_QUEUE_PAIRS       (1 << 7)
-
-#define IGB_82576_TSYNC_SHIFT 19
-
-#endif /* _IGB_H_ */
diff --git a/roms/ipxe/src/drivers/net/igb/igb_82575.c b/roms/ipxe/src/drivers/net/igb/igb_82575.c
deleted file mode 100644
index b5b615ad44adc25832aeceab38e3f88f768d7aab..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_82575.c
+++ /dev/null
@@ -1,1617 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-/*
- * 82575EB Gigabit Network Connection
- * 82575EB Gigabit Backplane Connection
- * 82575GB Gigabit Network Connection
- * 82576 Gigabit Network Connection
- * 82576 Quad Port Gigabit Mezzanine Adapter
- */
-
-#include "igb.h"
-
-static s32  igb_init_phy_params_82575(struct e1000_hw *hw);
-static s32  igb_init_nvm_params_82575(struct e1000_hw *hw);
-static s32  igb_init_mac_params_82575(struct e1000_hw *hw);
-static s32  igb_acquire_phy_82575(struct e1000_hw *hw);
-static void igb_release_phy_82575(struct e1000_hw *hw);
-static s32  igb_acquire_nvm_82575(struct e1000_hw *hw);
-static void igb_release_nvm_82575(struct e1000_hw *hw);
-static s32  igb_check_for_link_82575(struct e1000_hw *hw);
-static s32  igb_get_cfg_done_82575(struct e1000_hw *hw);
-static s32  igb_get_link_up_info_82575(struct e1000_hw *hw, u16 *speed,
-                                         u16 *duplex);
-static s32  igb_init_hw_82575(struct e1000_hw *hw);
-static s32  igb_phy_hw_reset_sgmii_82575(struct e1000_hw *hw);
-static s32  igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
-                                           u16 *data);
-static s32  igb_reset_hw_82575(struct e1000_hw *hw);
-static s32  igb_set_d0_lplu_state_82575(struct e1000_hw *hw,
-                                          bool active);
-static s32  igb_setup_copper_link_82575(struct e1000_hw *hw);
-static s32  igb_setup_serdes_link_82575(struct e1000_hw *hw);
-static s32  igb_valid_led_default_82575(struct e1000_hw *hw, u16 *data);
-static s32  igb_write_phy_reg_sgmii_82575(struct e1000_hw *hw,
-                                            u32 offset, u16 data);
-static void igb_clear_hw_cntrs_82575(struct e1000_hw *hw);
-static s32  igb_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask);
-static s32  igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
-                                                 u16 *speed, u16 *duplex);
-static s32  igb_get_phy_id_82575(struct e1000_hw *hw);
-static void igb_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask);
-static bool igb_sgmii_active_82575(struct e1000_hw *hw);
-static s32  igb_reset_init_script_82575(struct e1000_hw *hw);
-static s32  igb_read_mac_addr_82575(struct e1000_hw *hw);
-static void igb_power_down_phy_copper_82575(struct e1000_hw *hw);
-static void igb_shutdown_serdes_link_82575(struct e1000_hw *hw);
-static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw);
-
-/**
- *  igb_init_phy_params_82575 - Init PHY func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 igb_init_phy_params_82575(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_init_phy_params_82575");
-
-	if (hw->phy.media_type != e1000_media_type_copper) {
-		phy->type = e1000_phy_none;
-		goto out;
-	}
-
-	phy->ops.power_up   = igb_power_up_phy_copper;
-	phy->ops.power_down = igb_power_down_phy_copper_82575;
-
-	phy->autoneg_mask           = AUTONEG_ADVERTISE_SPEED_DEFAULT;
-	phy->reset_delay_us         = 100;
-
-	phy->ops.acquire            = igb_acquire_phy_82575;
-	phy->ops.check_reset_block  = igb_check_reset_block_generic;
-	phy->ops.commit             = igb_phy_sw_reset_generic;
-	phy->ops.get_cfg_done       = igb_get_cfg_done_82575;
-	phy->ops.release            = igb_release_phy_82575;
-
-	if (igb_sgmii_active_82575(hw)) {
-		phy->ops.reset      = igb_phy_hw_reset_sgmii_82575;
-		phy->ops.read_reg   = igb_read_phy_reg_sgmii_82575;
-		phy->ops.write_reg  = igb_write_phy_reg_sgmii_82575;
-	} else {
-		phy->ops.reset      = igb_phy_hw_reset_generic;
-		phy->ops.read_reg   = igb_read_phy_reg_igp;
-		phy->ops.write_reg  = igb_write_phy_reg_igp;
-	}
-
-	/* Set phy->phy_addr and phy->id. */
-	ret_val = igb_get_phy_id_82575(hw);
-
-	/* Verify phy id and set remaining function pointers */
-	switch (phy->id) {
-	case M88E1111_I_PHY_ID:
-		phy->type                   = e1000_phy_m88;
-		phy->ops.check_polarity     = igb_check_polarity_m88;
-		phy->ops.get_info           = igb_get_phy_info_m88;
-#if 0
-		phy->ops.get_cable_length   = igb_get_cable_length_m88;
-#endif
-#if 0
-		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
-#endif
-		break;
-	case IGP03E1000_E_PHY_ID:
-	case IGP04E1000_E_PHY_ID:
-		phy->type                   = e1000_phy_igp_3;
-		phy->ops.check_polarity     = igb_check_polarity_igp;
-		phy->ops.get_info           = igb_get_phy_info_igp;
-#if 0
-		phy->ops.get_cable_length   = igb_get_cable_length_igp_2;
-#endif
-#if 0
-		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_igp;
-#endif
-		phy->ops.set_d0_lplu_state  = igb_set_d0_lplu_state_82575;
-		phy->ops.set_d3_lplu_state  = igb_set_d3_lplu_state_generic;
-		break;
-	default:
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_init_nvm_params_82575 - Init NVM func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 igb_init_nvm_params_82575(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
-	u16 size;
-
-	DEBUGFUNC("igb_init_nvm_params_82575");
-
-	nvm->opcode_bits        = 8;
-	nvm->delay_usec         = 1;
-	switch (nvm->override) {
-	case e1000_nvm_override_spi_large:
-		nvm->page_size    = 32;
-		nvm->address_bits = 16;
-		break;
-	case e1000_nvm_override_spi_small:
-		nvm->page_size    = 8;
-		nvm->address_bits = 8;
-		break;
-	default:
-		nvm->page_size    = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
-		nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
-		break;
-	}
-
-	nvm->type              = e1000_nvm_eeprom_spi;
-
-	size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
-	                  E1000_EECD_SIZE_EX_SHIFT);
-
-	/*
-	 * Added to a constant, "size" becomes the left-shift value
-	 * for setting word_size.
-	 */
-	size += NVM_WORD_SIZE_BASE_SHIFT;
-
-	/* EEPROM access above 16k is unsupported */
-	if (size > 14)
-		size = 14;
-	nvm->word_size = 1 << size;
-
-	/* Function Pointers */
-	nvm->ops.acquire       = igb_acquire_nvm_82575;
-	nvm->ops.read          = igb_read_nvm_eerd;
-	nvm->ops.release       = igb_release_nvm_82575;
-	nvm->ops.update        = igb_update_nvm_checksum_generic;
-	nvm->ops.valid_led_default = igb_valid_led_default_82575;
-	nvm->ops.validate      = igb_validate_nvm_checksum_generic;
-	nvm->ops.write         = igb_write_nvm_spi;
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_init_mac_params_82575 - Init MAC func ptrs.
- *  @hw: pointer to the HW structure
- **/
-static s32 igb_init_mac_params_82575(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
-	u32 ctrl_ext = 0;
-
-	DEBUGFUNC("igb_init_mac_params_82575");
-
-	/* Set media type */
-        /*
-	 * The 82575 uses bits 22:23 for link mode. The mode can be changed
-         * based on the EEPROM. We cannot rely upon device ID. There
-         * is no distinguishable difference between fiber and internal
-         * SerDes mode on the 82575. There can be an external PHY attached
-         * on the SGMII interface. For this, we'll set sgmii_active to true.
-         */
-	hw->phy.media_type = e1000_media_type_copper;
-	dev_spec->sgmii_active = false;
-
-	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
-	switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
-	case E1000_CTRL_EXT_LINK_MODE_SGMII:
-		dev_spec->sgmii_active = true;
-		ctrl_ext |= E1000_CTRL_I2C_ENA;
-		break;
-	case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
-		hw->phy.media_type = e1000_media_type_internal_serdes;
-		ctrl_ext |= E1000_CTRL_I2C_ENA;
-		break;
-	default:
-		ctrl_ext &= ~E1000_CTRL_I2C_ENA;
-		break;
-	}
-
-	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
-
-	/* Set mta register count */
-	mac->mta_reg_count = 128;
-	/* Set uta register count */
-	mac->uta_reg_count = (hw->mac.type == e1000_82575) ? 0 : 128;
-	/* Set rar entry count */
-	mac->rar_entry_count = E1000_RAR_ENTRIES_82575;
-	if (mac->type == e1000_82576)
-		mac->rar_entry_count = E1000_RAR_ENTRIES_82576;
-	/* Set if part includes ASF firmware */
-	mac->asf_firmware_present = true;
-	/* Set if manageability features are enabled. */
-	mac->arc_subsystem_valid =
-	        (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK)
-	                ? true : false;
-
-	/* Function pointers */
-
-	/* bus type/speed/width */
-	mac->ops.get_bus_info = igb_get_bus_info_pcie_generic;
-	/* reset */
-	mac->ops.reset_hw = igb_reset_hw_82575;
-	/* hw initialization */
-	mac->ops.init_hw = igb_init_hw_82575;
-	/* link setup */
-	mac->ops.setup_link = igb_setup_link_generic;
-	/* physical interface link setup */
-	mac->ops.setup_physical_interface =
-	        (hw->phy.media_type == e1000_media_type_copper)
-	                ? igb_setup_copper_link_82575
-	                : igb_setup_serdes_link_82575;
-	/* physical interface shutdown */
-	mac->ops.shutdown_serdes = igb_shutdown_serdes_link_82575;
-	/* check for link */
-	mac->ops.check_for_link = igb_check_for_link_82575;
-	/* receive address register setting */
-	mac->ops.rar_set = igb_rar_set_generic;
-	/* read mac address */
-	mac->ops.read_mac_addr = igb_read_mac_addr_82575;
-	/* multicast address update */
-	mac->ops.update_mc_addr_list = igb_update_mc_addr_list_generic;
-	/* writing VFTA */
-	mac->ops.write_vfta = igb_write_vfta_generic;
-	/* clearing VFTA */
-	mac->ops.clear_vfta = igb_clear_vfta_generic;
-	/* setting MTA */
-#if 0
-	mac->ops.mta_set = igb_mta_set_generic;
-	/* ID LED init */
-	mac->ops.id_led_init = igb_id_led_init_generic;
-	/* blink LED */
-	mac->ops.blink_led = igb_blink_led_generic;
-	/* setup LED */
-	mac->ops.setup_led = igb_setup_led_generic;
-	/* cleanup LED */
-	mac->ops.cleanup_led = igb_cleanup_led_generic;
-	/* turn on/off LED */
-	mac->ops.led_on = igb_led_on_generic;
-	mac->ops.led_off = igb_led_off_generic;
-#endif
-	/* clear hardware counters */
-	mac->ops.clear_hw_cntrs = igb_clear_hw_cntrs_82575;
-	/* link info */
-	mac->ops.get_link_up_info = igb_get_link_up_info_82575;
-
-	/* set lan id for port to determine which phy lock to use */
-	hw->mac.ops.set_lan_id(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_init_function_pointers_82575 - Init func ptrs.
- *  @hw: pointer to the HW structure
- *
- *  Called to initialize all function pointers and parameters.
- **/
-void igb_init_function_pointers_82575(struct e1000_hw *hw)
-{
-	DEBUGFUNC("igb_init_function_pointers_82575");
-
-	hw->mac.ops.init_params = igb_init_mac_params_82575;
-	hw->nvm.ops.init_params = igb_init_nvm_params_82575;
-	hw->phy.ops.init_params = igb_init_phy_params_82575;
-#if 0
-	hw->mbx.ops.init_params = igb_init_mbx_params_pf;
-#endif
-}
-
-/**
- *  igb_acquire_phy_82575 - Acquire rights to access PHY
- *  @hw: pointer to the HW structure
- *
- *  Acquire access rights to the correct PHY.
- **/
-static s32 igb_acquire_phy_82575(struct e1000_hw *hw)
-{
-	u16 mask = E1000_SWFW_PHY0_SM;
-
-	DEBUGFUNC("igb_acquire_phy_82575");
-
-	if (hw->bus.func == E1000_FUNC_1)
-		mask = E1000_SWFW_PHY1_SM;
-
-	return igb_acquire_swfw_sync_82575(hw, mask);
-}
-
-/**
- *  igb_release_phy_82575 - Release rights to access PHY
- *  @hw: pointer to the HW structure
- *
- *  A wrapper to release access rights to the correct PHY.
- **/
-static void igb_release_phy_82575(struct e1000_hw *hw)
-{
-	u16 mask = E1000_SWFW_PHY0_SM;
-
-	DEBUGFUNC("igb_release_phy_82575");
-
-	if (hw->bus.func == E1000_FUNC_1)
-		mask = E1000_SWFW_PHY1_SM;
-
-	igb_release_swfw_sync_82575(hw, mask);
-}
-
-/**
- *  igb_read_phy_reg_sgmii_82575 - Read PHY register using sgmii
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Reads the PHY register at offset using the serial gigabit media independent
- *  interface and stores the retrieved information in data.
- **/
-static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
-                                          u16 *data)
-{
-	s32 ret_val = -E1000_ERR_PARAM;
-
-	DEBUGFUNC("igb_read_phy_reg_sgmii_82575");
-
-	if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
-		DEBUGOUT1("PHY Address %u is out of range\n", offset);
-		goto out;
-	}
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = igb_read_phy_reg_i2c(hw, offset, data);
-
-	hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_write_phy_reg_sgmii_82575 - Write PHY register using sgmii
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Writes the data to PHY register at the offset using the serial gigabit
- *  media independent interface.
- **/
-static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
-                                           u16 data)
-{
-	s32 ret_val = -E1000_ERR_PARAM;
-
-	DEBUGFUNC("igb_write_phy_reg_sgmii_82575");
-
-	if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
-		DEBUGOUT1("PHY Address %d is out of range\n", offset);
-		goto out;
-	}
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = igb_write_phy_reg_i2c(hw, offset, data);
-
-	hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_get_phy_id_82575 - Retrieve PHY addr and id
- *  @hw: pointer to the HW structure
- *
- *  Retrieves the PHY address and ID for both PHY's which do and do not use
- *  sgmi interface.
- **/
-static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32  ret_val = E1000_SUCCESS;
-	u16 phy_id;
-	u32 ctrl_ext;
-
-	DEBUGFUNC("igb_get_phy_id_82575");
-
-	/*
-	 * For SGMII PHYs, we try the list of possible addresses until
-	 * we find one that works.  For non-SGMII PHYs
-	 * (e.g. integrated copper PHYs), an address of 1 should
-	 * work.  The result of this function should mean phy->phy_addr
-	 * and phy->id are set correctly.
-	 */
-	if (!igb_sgmii_active_82575(hw)) {
-		phy->addr = 1;
-		ret_val = igb_get_phy_id(hw);
-		goto out;
-	}
-
-	/* Power on sgmii phy if it is disabled */
-	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
-	E1000_WRITE_REG(hw, E1000_CTRL_EXT,
-	                ctrl_ext & ~E1000_CTRL_EXT_SDP3_DATA);
-	E1000_WRITE_FLUSH(hw);
-	msec_delay(300);
-
-	/*
-	 * The address field in the I2CCMD register is 3 bits and 0 is invalid.
-	 * Therefore, we need to test 1-7
-	 */
-	for (phy->addr = 1; phy->addr < 8; phy->addr++) {
-		ret_val = igb_read_phy_reg_sgmii_82575(hw, PHY_ID1, &phy_id);
-		if (ret_val == E1000_SUCCESS) {
-			DEBUGOUT2("Vendor ID 0x%08X read at address %u\n",
-			          phy_id,
-			          phy->addr);
-			/*
-			 * At the time of this writing, The M88 part is
-			 * the only supported SGMII PHY product.
-			 */
-			if (phy_id == M88_VENDOR)
-				break;
-		} else {
-			DEBUGOUT1("PHY address %u was unreadable\n",
-			          phy->addr);
-		}
-	}
-
-	/* A valid PHY type couldn't be found. */
-	if (phy->addr == 8) {
-		phy->addr = 0;
-		ret_val = -E1000_ERR_PHY;
-	} else {
-		ret_val = igb_get_phy_id(hw);
-	}
-
-	/* restore previous sfp cage power state */
-	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_phy_hw_reset_sgmii_82575 - Performs a PHY reset
- *  @hw: pointer to the HW structure
- *
- *  Resets the PHY using the serial gigabit media independent interface.
- **/
-static s32 igb_phy_hw_reset_sgmii_82575(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_phy_hw_reset_sgmii_82575");
-
-	/*
-	 * This isn't a true "hard" reset, but is the only reset
-	 * available to us at this time.
-	 */
-
-	DEBUGOUT("Soft resetting SGMII attached PHY...\n");
-
-	if (!(hw->phy.ops.write_reg))
-		goto out;
-
-	/*
-	 * SFP documentation requires the following to configure the SPF module
-	 * to work on SGMII.  No further documentation is given.
-	 */
-	ret_val = hw->phy.ops.write_reg(hw, 0x1B, 0x8084);
-	if (ret_val)
-		goto out;
-
-	ret_val = hw->phy.ops.commit(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_set_d0_lplu_state_82575 - Set Low Power Linkup D0 state
- *  @hw: pointer to the HW structure
- *  @active: true to enable LPLU, false to disable
- *
- *  Sets the LPLU D0 state according to the active flag.  When
- *  activating LPLU this function also disables smart speed
- *  and vice versa.  LPLU will not be activated unless the
- *  device autonegotiation advertisement meets standards of
- *  either 10 or 10/100 or 10/100/1000 at all duplexes.
- *  This is a function pointer entry point only called by
- *  PHY setup routines.
- **/
-static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *hw, bool active)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 data;
-
-	DEBUGFUNC("igb_set_d0_lplu_state_82575");
-
-	if (!(hw->phy.ops.read_reg))
-		goto out;
-
-	ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
-	if (ret_val)
-		goto out;
-
-	if (active) {
-		data |= IGP02E1000_PM_D0_LPLU;
-		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
-		                             data);
-		if (ret_val)
-			goto out;
-
-		/* When LPLU is enabled, we should disable SmartSpeed */
-		ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-		                            &data);
-		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-		ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-		                             data);
-		if (ret_val)
-			goto out;
-	} else {
-		data &= ~IGP02E1000_PM_D0_LPLU;
-		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
-		                             data);
-		/*
-		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
-		 * during Dx states where the power conservation is most
-		 * important.  During driver activity we should enable
-		 * SmartSpeed, so performance is maintained.
-		 */
-		if (phy->smart_speed == e1000_smart_speed_on) {
-			ret_val = phy->ops.read_reg(hw,
-			                            IGP01E1000_PHY_PORT_CONFIG,
-			                            &data);
-			if (ret_val)
-				goto out;
-
-			data |= IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = phy->ops.write_reg(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		} else if (phy->smart_speed == e1000_smart_speed_off) {
-			ret_val = phy->ops.read_reg(hw,
-			                            IGP01E1000_PHY_PORT_CONFIG,
-			                            &data);
-			if (ret_val)
-				goto out;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = phy->ops.write_reg(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_acquire_nvm_82575 - Request for access to EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Acquire the necessary semaphores for exclusive access to the EEPROM.
- *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
- *  Return successful if access grant bit set, else clear the request for
- *  EEPROM access and return -E1000_ERR_NVM (-1).
- **/
-static s32 igb_acquire_nvm_82575(struct e1000_hw *hw)
-{
-	s32 ret_val;
-
-	DEBUGFUNC("igb_acquire_nvm_82575");
-
-	ret_val = igb_acquire_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
-	if (ret_val)
-		goto out;
-
-	ret_val = igb_acquire_nvm_generic(hw);
-
-	if (ret_val)
-		igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_release_nvm_82575 - Release exclusive access to EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Stop any current commands to the EEPROM and clear the EEPROM request bit,
- *  then release the semaphores acquired.
- **/
-static void igb_release_nvm_82575(struct e1000_hw *hw)
-{
-	DEBUGFUNC("igb_release_nvm_82575");
-
-	igb_release_nvm_generic(hw);
-	igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
-}
-
-/**
- *  igb_acquire_swfw_sync_82575 - Acquire SW/FW semaphore
- *  @hw: pointer to the HW structure
- *  @mask: specifies which semaphore to acquire
- *
- *  Acquire the SW/FW semaphore to access the PHY or NVM.  The mask
- *  will also specify which port we're acquiring the lock for.
- **/
-static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask)
-{
-	u32 swfw_sync;
-	u32 swmask = mask;
-	u32 fwmask = mask << 16;
-	s32 ret_val = E1000_SUCCESS;
-	s32 i = 0, timeout = 200; /* FIXME: find real value to use here */
-
-	DEBUGFUNC("igb_acquire_swfw_sync_82575");
-
-	while (i < timeout) {
-		if (igb_get_hw_semaphore_generic(hw)) {
-			ret_val = -E1000_ERR_SWFW_SYNC;
-			goto out;
-		}
-
-		swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
-		if (!(swfw_sync & (fwmask | swmask)))
-			break;
-
-		/*
-		 * Firmware currently using resource (fwmask)
-		 * or other software thread using resource (swmask)
-		 */
-		igb_put_hw_semaphore_generic(hw);
-		msec_delay_irq(5);
-		i++;
-	}
-
-	if (i == timeout) {
-		DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n");
-		ret_val = -E1000_ERR_SWFW_SYNC;
-		goto out;
-	}
-
-	swfw_sync |= swmask;
-	E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
-
-	igb_put_hw_semaphore_generic(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_release_swfw_sync_82575 - Release SW/FW semaphore
- *  @hw: pointer to the HW structure
- *  @mask: specifies which semaphore to acquire
- *
- *  Release the SW/FW semaphore used to access the PHY or NVM.  The mask
- *  will also specify which port we're releasing the lock for.
- **/
-static void igb_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask)
-{
-	u32 swfw_sync;
-
-	DEBUGFUNC("igb_release_swfw_sync_82575");
-
-	while (igb_get_hw_semaphore_generic(hw) != E1000_SUCCESS);
-	/* Empty */
-
-	swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC);
-	swfw_sync &= ~mask;
-	E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync);
-
-	igb_put_hw_semaphore_generic(hw);
-}
-
-/**
- *  igb_get_cfg_done_82575 - Read config done bit
- *  @hw: pointer to the HW structure
- *
- *  Read the management control register for the config done bit for
- *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
- *  to read the config done bit, so an error is *ONLY* logged and returns
- *  E1000_SUCCESS.  If we were to return with error, EEPROM-less silicon
- *  would not be able to be reset or change link.
- **/
-static s32 igb_get_cfg_done_82575(struct e1000_hw *hw)
-{
-	s32 timeout = PHY_CFG_TIMEOUT;
-	s32 ret_val = E1000_SUCCESS;
-	u32 mask = E1000_NVM_CFG_DONE_PORT_0;
-
-	DEBUGFUNC("igb_get_cfg_done_82575");
-
-	if (hw->bus.func == E1000_FUNC_1)
-		mask = E1000_NVM_CFG_DONE_PORT_1;
-	while (timeout) {
-		if (E1000_READ_REG(hw, E1000_EEMNGCTL) & mask)
-			break;
-		msec_delay(1);
-		timeout--;
-	}
-	if (!timeout) {
-		DEBUGOUT("MNG configuration cycle has not completed.\n");
-        }
-
-	/* If EEPROM is not marked present, init the PHY manually */
-	if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
-	    (hw->phy.type == e1000_phy_igp_3))
-		igb_phy_init_script_igp3(hw);
-
-	return ret_val;
-}
-
-/**
- *  igb_get_link_up_info_82575 - Get link speed/duplex info
- *  @hw: pointer to the HW structure
- *  @speed: stores the current speed
- *  @duplex: stores the current duplex
- *
- *  This is a wrapper function, if using the serial gigabit media independent
- *  interface, use PCS to retrieve the link speed and duplex information.
- *  Otherwise, use the generic function to get the link speed and duplex info.
- **/
-static s32 igb_get_link_up_info_82575(struct e1000_hw *hw, u16 *speed,
-                                        u16 *duplex)
-{
-	s32 ret_val;
-
-	DEBUGFUNC("igb_get_link_up_info_82575");
-
-	if (hw->phy.media_type != e1000_media_type_copper)
-		ret_val = igb_get_pcs_speed_and_duplex_82575(hw, speed,
-		                                               duplex);
-	else
-		ret_val = igb_get_speed_and_duplex_copper_generic(hw, speed,
-		                                                    duplex);
-
-	return ret_val;
-}
-
-/**
- *  igb_check_for_link_82575 - Check for link
- *  @hw: pointer to the HW structure
- *
- *  If sgmii is enabled, then use the pcs register to determine link, otherwise
- *  use the generic interface for determining link.
- **/
-static s32 igb_check_for_link_82575(struct e1000_hw *hw)
-{
-	s32 ret_val;
-	u16 speed, duplex;
-
-	DEBUGFUNC("igb_check_for_link_82575");
-
-	if (hw->phy.media_type != e1000_media_type_copper) {
-		ret_val = igb_get_pcs_speed_and_duplex_82575(hw, &speed,
-		                                               &duplex);
-		/*
-		 * Use this flag to determine if link needs to be checked or
-		 * not.  If we have link clear the flag so that we do not
-		 * continue to check for link.
-		 */
-		hw->mac.get_link_status = !hw->mac.serdes_has_link;
-	} else {
-		ret_val = igb_check_for_copper_link_generic(hw);
-	}
-
-	return ret_val;
-}
-
-/**
- *  igb_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex
- *  @hw: pointer to the HW structure
- *  @speed: stores the current speed
- *  @duplex: stores the current duplex
- *
- *  Using the physical coding sub-layer (PCS), retrieve the current speed and
- *  duplex, then store the values in the pointers provided.
- **/
-static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
-                                                u16 *speed, u16 *duplex)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 pcs;
-
-	DEBUGFUNC("igb_get_pcs_speed_and_duplex_82575");
-
-	/* Set up defaults for the return values of this function */
-	mac->serdes_has_link = false;
-	*speed = 0;
-	*duplex = 0;
-
-	/*
-	 * Read the PCS Status register for link state. For non-copper mode,
-	 * the status register is not accurate. The PCS status register is
-	 * used instead.
-	 */
-	pcs = E1000_READ_REG(hw, E1000_PCS_LSTAT);
-
-	/*
-	 * The link up bit determines when link is up on autoneg. The sync ok
-	 * gets set once both sides sync up and agree upon link. Stable link
-	 * can be determined by checking for both link up and link sync ok
-	 */
-	if ((pcs & E1000_PCS_LSTS_LINK_OK) && (pcs & E1000_PCS_LSTS_SYNK_OK)) {
-		mac->serdes_has_link = true;
-
-		/* Detect and store PCS speed */
-		if (pcs & E1000_PCS_LSTS_SPEED_1000) {
-			*speed = SPEED_1000;
-		} else if (pcs & E1000_PCS_LSTS_SPEED_100) {
-			*speed = SPEED_100;
-		} else {
-			*speed = SPEED_10;
-		}
-
-		/* Detect and store PCS duplex */
-		if (pcs & E1000_PCS_LSTS_DUPLEX_FULL) {
-			*duplex = FULL_DUPLEX;
-		} else {
-			*duplex = HALF_DUPLEX;
-		}
-	}
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_shutdown_serdes_link_82575 - Remove link during power down
- *  @hw: pointer to the HW structure
- *
- *  In the case of serdes shut down sfp and PCS on driver unload
- *  when management pass thru is not enabled.
- **/
-void igb_shutdown_serdes_link_82575(struct e1000_hw *hw)
-{
-#if 0
-	u32 reg;
-#endif
-	u16 eeprom_data = 0;
-
-	if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
-	    !igb_sgmii_active_82575(hw))
-		return;
-
-	if (hw->bus.func == E1000_FUNC_0)
-		hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
-	else if (hw->bus.func == E1000_FUNC_1)
-		hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data);
-
-	/*
-	 * If APM is not enabled in the EEPROM and management interface is
-	 * not enabled, then power down.
-	 */
-#if 0
-	if (!(eeprom_data & E1000_NVM_APME_82575) &&
-	    !igb_enable_mng_pass_thru(hw)) {
-		/* Disable PCS to turn off link */
-		reg = E1000_READ_REG(hw, E1000_PCS_CFG0);
-		reg &= ~E1000_PCS_CFG_PCS_EN;
-		E1000_WRITE_REG(hw, E1000_PCS_CFG0, reg);
-
-		/* shutdown the laser */
-		reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
-		reg |= E1000_CTRL_EXT_SDP3_DATA;
-		E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
-
-		/* flush the write to verify completion */
-		E1000_WRITE_FLUSH(hw);
-		msec_delay(1);
-	}
-#endif
-	return;
-}
-
-/**
- *  igb_reset_hw_82575 - Reset hardware
- *  @hw: pointer to the HW structure
- *
- *  This resets the hardware into a known state.
- **/
-static s32 igb_reset_hw_82575(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val;
-
-	DEBUGFUNC("igb_reset_hw_82575");
-
-	/*
-	 * Prevent the PCI-E bus from sticking if there is no TLP connection
-	 * on the last TLP read/write transaction when MAC is reset.
-	 */
-	ret_val = igb_disable_pcie_master_generic(hw);
-	if (ret_val) {
-		DEBUGOUT("PCI-E Master disable polling has failed.\n");
-	}
-
-	/* set the completion timeout for interface */
-	ret_val = igb_set_pcie_completion_timeout(hw);
-	if (ret_val) {
-		DEBUGOUT("PCI-E Set completion timeout has failed.\n");
-	}
-
-	DEBUGOUT("Masking off all interrupts\n");
-	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
-
-	E1000_WRITE_REG(hw, E1000_RCTL, 0);
-	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
-	E1000_WRITE_FLUSH(hw);
-
-	msec_delay(10);
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	DEBUGOUT("Issuing a global reset to MAC\n");
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
-
-	ret_val = igb_get_auto_rd_done_generic(hw);
-	if (ret_val) {
-		/*
-		 * When auto config read does not complete, do not
-		 * return with an error. This can happen in situations
-		 * where there is no eeprom and prevents getting link.
-		 */
-		DEBUGOUT("Auto Read Done did not complete\n");
-	}
-
-	/* If EEPROM is not present, run manual init scripts */
-	if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0)
-		igb_reset_init_script_82575(hw);
-
-	/* Clear any pending interrupt events. */
-	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
-	E1000_READ_REG(hw, E1000_ICR);
-
-	/* Install any alternate MAC address into RAR0 */
-	ret_val = igb_check_alt_mac_addr_generic(hw);
-
-	return ret_val;
-}
-
-/**
- *  igb_init_hw_82575 - Initialize hardware
- *  @hw: pointer to the HW structure
- *
- *  This inits the hardware readying it for operation.
- **/
-static s32 igb_init_hw_82575(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val;
-	u16 i, rar_count = mac->rar_entry_count;
-
-	DEBUGFUNC("igb_init_hw_82575");
-
-	/* Initialize identification LED */
-	ret_val = mac->ops.id_led_init(hw);
-	if (ret_val) {
-		DEBUGOUT("Error initializing identification LED\n");
-		/* This is not fatal and we should not stop init due to this */
-	}
-
-	/* Disabling VLAN filtering */
-	DEBUGOUT("Initializing the IEEE VLAN\n");
-	mac->ops.clear_vfta(hw);
-
-	/* Setup the receive address */
-	igb_init_rx_addrs_generic(hw, rar_count);
-
-	/* Zero out the Multicast HASH table */
-	DEBUGOUT("Zeroing the MTA\n");
-	for (i = 0; i < mac->mta_reg_count; i++)
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
-
-	/* Zero out the Unicast HASH table */
-	DEBUGOUT("Zeroing the UTA\n");
-	for (i = 0; i < mac->uta_reg_count; i++)
-		E1000_WRITE_REG_ARRAY(hw, E1000_UTA, i, 0);
-
-	/* Setup link and flow control */
-	ret_val = mac->ops.setup_link(hw);
-
-	/*
-	 * Clear all of the statistics registers (clear on read).  It is
-	 * important that we do this after we have tried to establish link
-	 * because the symbol error count will increment wildly if there
-	 * is no link.
-	 */
-	igb_clear_hw_cntrs_82575(hw);
-
-	return ret_val;
-}
-
-/**
- *  igb_setup_copper_link_82575 - Configure copper link settings
- *  @hw: pointer to the HW structure
- *
- *  Configures the link for auto-neg or forced speed and duplex.  Then we check
- *  for link, once link is established calls to configure collision distance
- *  and flow control are called.
- **/
-static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32  ret_val;
-
-	DEBUGFUNC("igb_setup_copper_link_82575");
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	ctrl |= E1000_CTRL_SLU;
-	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-	ret_val = igb_setup_serdes_link_82575(hw);
-	if (ret_val)
-		goto out;
-
-	if (igb_sgmii_active_82575(hw) && !hw->phy.reset_disable) {
-		ret_val = hw->phy.ops.reset(hw);
-		if (ret_val) {
-			DEBUGOUT("Error resetting the PHY.\n");
-			goto out;
-		}
-	}
-	switch (hw->phy.type) {
-	case e1000_phy_m88:
-		ret_val = igb_copper_link_setup_m88(hw);
-		break;
-	case e1000_phy_igp_3:
-		ret_val = igb_copper_link_setup_igp(hw);
-		break;
-	default:
-		ret_val = -E1000_ERR_PHY;
-		break;
-	}
-
-	if (ret_val)
-		goto out;
-
-	ret_val = igb_setup_copper_link_generic(hw);
-out:
-	return ret_val;
-}
-
-/**
- *  igb_setup_serdes_link_82575 - Setup link for serdes
- *  @hw: pointer to the HW structure
- *
- *  Configure the physical coding sub-layer (PCS) link.  The PCS link is
- *  used on copper connections where the serialized gigabit media independent
- *  interface (sgmii), or serdes fiber is being used.  Configures the link
- *  for auto-negotiation or forces speed/duplex.
- **/
-static s32 igb_setup_serdes_link_82575(struct e1000_hw *hw)
-{
-	u32 ctrl_reg, reg;
-
-	DEBUGFUNC("igb_setup_serdes_link_82575");
-
-	if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
-	    !igb_sgmii_active_82575(hw))
-		return E1000_SUCCESS;
-
-	/*
-	 * On the 82575, SerDes loopback mode persists until it is
-	 * explicitly turned off or a power cycle is performed.  A read to
-	 * the register does not indicate its status.  Therefore, we ensure
-	 * loopback mode is disabled during initialization.
-	 */
-	E1000_WRITE_REG(hw, E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
-
-	/* power on the sfp cage if present */
-	reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
-	reg &= ~E1000_CTRL_EXT_SDP3_DATA;
-	E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
-
-	ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
-	ctrl_reg |= E1000_CTRL_SLU;
-
-	if (hw->mac.type == e1000_82575 || hw->mac.type == e1000_82576) {
-		/* set both sw defined pins */
-		ctrl_reg |= E1000_CTRL_SWDPIN0 | E1000_CTRL_SWDPIN1;
-
-		/* Set switch control to serdes energy detect */
-		reg = E1000_READ_REG(hw, E1000_CONNSW);
-		reg |= E1000_CONNSW_ENRGSRC;
-		E1000_WRITE_REG(hw, E1000_CONNSW, reg);
-	}
-
-	reg = E1000_READ_REG(hw, E1000_PCS_LCTL);
-
-	if (igb_sgmii_active_82575(hw)) {
-		/* allow time for SFP cage to power up phy */
-		msec_delay(300);
-
-		/* AN time out should be disabled for SGMII mode */
-		reg &= ~(E1000_PCS_LCTL_AN_TIMEOUT);
-	} else {
-		ctrl_reg |= E1000_CTRL_SPD_1000 | E1000_CTRL_FRCSPD |
-		            E1000_CTRL_FD | E1000_CTRL_FRCDPX;
-	}
-
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
-
-	/*
-	 * New SerDes mode allows for forcing speed or autonegotiating speed
-	 * at 1gb. Autoneg should be default set by most drivers. This is the
-	 * mode that will be compatible with older link partners and switches.
-	 * However, both are supported by the hardware and some drivers/tools.
-	 */
-
-	reg &= ~(E1000_PCS_LCTL_AN_ENABLE | E1000_PCS_LCTL_FLV_LINK_UP |
-	         E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK);
-
-	/*
-	 * We force flow control to prevent the CTRL register values from being
-	 * overwritten by the autonegotiated flow control values
-	 */
-	reg |= E1000_PCS_LCTL_FORCE_FCTRL;
-
-	/*
-	 * we always set sgmii to autoneg since it is the phy that will be
-	 * forcing the link and the serdes is just a go-between
-	 */
-	if (hw->mac.autoneg || igb_sgmii_active_82575(hw)) {
-		/* Set PCS register for autoneg */
-		reg |= E1000_PCS_LCTL_FSV_1000 |  /* Force 1000 */
-		       E1000_PCS_LCTL_FDV_FULL |  /* SerDes Full dplx */
-		       E1000_PCS_LCTL_AN_ENABLE | /* Enable Autoneg */
-		       E1000_PCS_LCTL_AN_RESTART; /* Restart autoneg */
-		DEBUGOUT1("Configuring Autoneg:PCS_LCTL=0x%08X\n", reg);
-	} else {
-		/* Check for duplex first */
-		if (hw->mac.forced_speed_duplex & E1000_ALL_FULL_DUPLEX)
-			reg |= E1000_PCS_LCTL_FDV_FULL;
-
-		/* No need to check for 1000/full since the spec states that
-		 * it requires autoneg to be enabled */
-		/* Now set speed */
-		if (hw->mac.forced_speed_duplex & E1000_ALL_100_SPEED)
-			reg |= E1000_PCS_LCTL_FSV_100;
-
-		/* Force speed and force link */
-		reg |= E1000_PCS_LCTL_FSD |
-		       E1000_PCS_LCTL_FORCE_LINK |
-		       E1000_PCS_LCTL_FLV_LINK_UP;
-
-		DEBUGOUT1("Configuring Forced Link:PCS_LCTL=0x%08X\n", reg);
-	}
-
-	E1000_WRITE_REG(hw, E1000_PCS_LCTL, reg);
-
-	if (!igb_sgmii_active_82575(hw))
-		igb_force_mac_fc_generic(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_valid_led_default_82575 - Verify a valid default LED config
- *  @hw: pointer to the HW structure
- *  @data: pointer to the NVM (EEPROM)
- *
- *  Read the EEPROM for the current default LED configuration.  If the
- *  LED configuration is not valid, set to a valid LED configuration.
- **/
-static s32 igb_valid_led_default_82575(struct e1000_hw *hw, u16 *data)
-{
-	s32 ret_val;
-
-	DEBUGFUNC("igb_valid_led_default_82575");
-
-	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
-	if (ret_val) {
-		DEBUGOUT("NVM Read Error\n");
-		goto out;
-	}
-
-	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) {
-		switch(hw->phy.media_type) {
-		case e1000_media_type_internal_serdes:
-			*data = ID_LED_DEFAULT_82575_SERDES;
-			break;
-		case e1000_media_type_copper:
-		default:
-			*data = ID_LED_DEFAULT;
-			break;
-		}
-	}
-out:
-	return ret_val;
-}
-
-/**
- *  igb_sgmii_active_82575 - Return sgmii state
- *  @hw: pointer to the HW structure
- *
- *  82575 silicon has a serialized gigabit media independent interface (sgmii)
- *  which can be enabled for use in the embedded applications.  Simply
- *  return the current state of the sgmii interface.
- **/
-static bool igb_sgmii_active_82575(struct e1000_hw *hw)
-{
-	struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
-	return dev_spec->sgmii_active;
-}
-
-/**
- *  igb_reset_init_script_82575 - Inits HW defaults after reset
- *  @hw: pointer to the HW structure
- *
- *  Inits recommended HW defaults after a reset when there is no EEPROM
- *  detected. This is only for the 82575.
- **/
-static s32 igb_reset_init_script_82575(struct e1000_hw* hw)
-{
-	DEBUGFUNC("igb_reset_init_script_82575");
-
-	if (hw->mac.type == e1000_82575) {
-		DEBUGOUT("Running reset init script for 82575\n");
-		/* SerDes configuration via SERDESCTRL */
-		igb_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x00, 0x0C);
-		igb_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x01, 0x78);
-		igb_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x1B, 0x23);
-		igb_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x23, 0x15);
-
-		/* CCM configuration via CCMCTL register */
-		igb_write_8bit_ctrl_reg_generic(hw, E1000_CCMCTL, 0x14, 0x00);
-		igb_write_8bit_ctrl_reg_generic(hw, E1000_CCMCTL, 0x10, 0x00);
-
-		/* PCIe lanes configuration */
-		igb_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x00, 0xEC);
-		igb_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x61, 0xDF);
-		igb_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x34, 0x05);
-		igb_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x2F, 0x81);
-
-		/* PCIe PLL Configuration */
-		igb_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x02, 0x47);
-		igb_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x14, 0x00);
-		igb_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x10, 0x00);
-	}
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_read_mac_addr_82575 - Read device MAC address
- *  @hw: pointer to the HW structure
- **/
-static s32 igb_read_mac_addr_82575(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_read_mac_addr_82575");
-
-	/*
-	 * If there's an alternate MAC address place it in RAR0
-	 * so that it will override the Si installed default perm
-	 * address.
-	 */
-	ret_val = igb_check_alt_mac_addr_generic(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = igb_read_mac_addr_generic(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- * igb_power_down_phy_copper_82575 - Remove link during PHY power down
- * @hw: pointer to the HW structure
- *
- * In the case of a PHY power down to save power, or to turn off link during a
- * driver unload, or wake on lan is not enabled, remove the link.
- **/
-static void igb_power_down_phy_copper_82575(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	struct e1000_mac_info *mac = &hw->mac;
-
-	if (!(phy->ops.check_reset_block))
-		return;
-
-	/* If the management interface is not enabled, then power down */
-	if (!(mac->ops.check_mng_mode(hw) || phy->ops.check_reset_block(hw)))
-		igb_power_down_phy_copper(hw);
-
-	return;
-}
-
-/**
- *  igb_clear_hw_cntrs_82575 - Clear device specific hardware counters
- *  @hw: pointer to the HW structure
- *
- *  Clears the hardware counters by reading the counter registers.
- **/
-static void igb_clear_hw_cntrs_82575(struct e1000_hw *hw)
-{
-	DEBUGFUNC("igb_clear_hw_cntrs_82575");
-
-	igb_clear_hw_cntrs_base_generic(hw);
-
-	E1000_READ_REG(hw, E1000_PRC64);
-	E1000_READ_REG(hw, E1000_PRC127);
-	E1000_READ_REG(hw, E1000_PRC255);
-	E1000_READ_REG(hw, E1000_PRC511);
-	E1000_READ_REG(hw, E1000_PRC1023);
-	E1000_READ_REG(hw, E1000_PRC1522);
-	E1000_READ_REG(hw, E1000_PTC64);
-	E1000_READ_REG(hw, E1000_PTC127);
-	E1000_READ_REG(hw, E1000_PTC255);
-	E1000_READ_REG(hw, E1000_PTC511);
-	E1000_READ_REG(hw, E1000_PTC1023);
-	E1000_READ_REG(hw, E1000_PTC1522);
-
-	E1000_READ_REG(hw, E1000_ALGNERRC);
-	E1000_READ_REG(hw, E1000_RXERRC);
-	E1000_READ_REG(hw, E1000_TNCRS);
-	E1000_READ_REG(hw, E1000_CEXTERR);
-	E1000_READ_REG(hw, E1000_TSCTC);
-	E1000_READ_REG(hw, E1000_TSCTFC);
-
-	E1000_READ_REG(hw, E1000_MGTPRC);
-	E1000_READ_REG(hw, E1000_MGTPDC);
-	E1000_READ_REG(hw, E1000_MGTPTC);
-
-	E1000_READ_REG(hw, E1000_IAC);
-	E1000_READ_REG(hw, E1000_ICRXOC);
-
-	E1000_READ_REG(hw, E1000_ICRXPTC);
-	E1000_READ_REG(hw, E1000_ICRXATC);
-	E1000_READ_REG(hw, E1000_ICTXPTC);
-	E1000_READ_REG(hw, E1000_ICTXATC);
-	E1000_READ_REG(hw, E1000_ICTXQEC);
-	E1000_READ_REG(hw, E1000_ICTXQMTC);
-	E1000_READ_REG(hw, E1000_ICRXDMTC);
-
-	E1000_READ_REG(hw, E1000_CBTMPC);
-	E1000_READ_REG(hw, E1000_HTDPMC);
-	E1000_READ_REG(hw, E1000_CBRMPC);
-	E1000_READ_REG(hw, E1000_RPTHC);
-	E1000_READ_REG(hw, E1000_HGPTC);
-	E1000_READ_REG(hw, E1000_HTCBDPC);
-	E1000_READ_REG(hw, E1000_HGORCL);
-	E1000_READ_REG(hw, E1000_HGORCH);
-	E1000_READ_REG(hw, E1000_HGOTCL);
-	E1000_READ_REG(hw, E1000_HGOTCH);
-	E1000_READ_REG(hw, E1000_LENERRS);
-
-	/* This register should not be read in copper configurations */
-	if ((hw->phy.media_type == e1000_media_type_internal_serdes) ||
-	    igb_sgmii_active_82575(hw))
-		E1000_READ_REG(hw, E1000_SCVPC);
-}
-
-/**
- *  igb_rx_fifo_flush_82575 - Clean rx fifo after RX enable
- *  @hw: pointer to the HW structure
- *
- *  After rx enable if managability is enabled then there is likely some
- *  bad data at the start of the fifo and possibly in the DMA fifo.  This
- *  function clears the fifos and flushes any packets that came in as rx was
- *  being enabled.
- **/
-void igb_rx_fifo_flush_82575(struct e1000_hw *hw)
-{
-	u32 rctl, rlpml, rxdctl[4], rfctl, temp_rctl, rx_enabled;
-	int i, ms_wait;
-
-	DEBUGFUNC("igb_rx_fifo_workaround_82575");
-	if (hw->mac.type != e1000_82575 ||
-	    !(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_RCV_TCO_EN))
-		return;
-
-	/* Disable all RX queues */
-	for (i = 0; i < 4; i++) {
-		rxdctl[i] = E1000_READ_REG(hw, E1000_RXDCTL(i));
-		E1000_WRITE_REG(hw, E1000_RXDCTL(i),
-		                rxdctl[i] & ~E1000_RXDCTL_QUEUE_ENABLE);
-	}
-	/* Poll all queues to verify they have shut down */
-	for (ms_wait = 0; ms_wait < 10; ms_wait++) {
-		msec_delay(1);
-		rx_enabled = 0;
-		for (i = 0; i < 4; i++)
-			rx_enabled |= E1000_READ_REG(hw, E1000_RXDCTL(i));
-		if (!(rx_enabled & E1000_RXDCTL_QUEUE_ENABLE))
-			break;
-	}
-
-	if (ms_wait == 10) {
-		DEBUGOUT("Queue disable timed out after 10ms\n");
-        }
-	/* Clear RLPML, RCTL.SBP, RFCTL.LEF, and set RCTL.LPE so that all
-	 * incoming packets are rejected.  Set enable and wait 2ms so that
-	 * any packet that was coming in as RCTL.EN was set is flushed
-	 */
-	rfctl = E1000_READ_REG(hw, E1000_RFCTL);
-	E1000_WRITE_REG(hw, E1000_RFCTL, rfctl & ~E1000_RFCTL_LEF);
-
-	rlpml = E1000_READ_REG(hw, E1000_RLPML);
-	E1000_WRITE_REG(hw, E1000_RLPML, 0);
-
-	rctl = E1000_READ_REG(hw, E1000_RCTL);
-	temp_rctl = rctl & ~(E1000_RCTL_EN | E1000_RCTL_SBP);
-	temp_rctl |= E1000_RCTL_LPE;
-
-	E1000_WRITE_REG(hw, E1000_RCTL, temp_rctl);
-	E1000_WRITE_REG(hw, E1000_RCTL, temp_rctl | E1000_RCTL_EN);
-	E1000_WRITE_FLUSH(hw);
-	msec_delay(2);
-
-	/* Enable RX queues that were previously enabled and restore our
-	 * previous state
-	 */
-	for (i = 0; i < 4; i++)
-		E1000_WRITE_REG(hw, E1000_RXDCTL(i), rxdctl[i]);
-	E1000_WRITE_REG(hw, E1000_RCTL, rctl);
-	E1000_WRITE_FLUSH(hw);
-
-	E1000_WRITE_REG(hw, E1000_RLPML, rlpml);
-	E1000_WRITE_REG(hw, E1000_RFCTL, rfctl);
-
-	/* Flush receive errors generated by workaround */
-	E1000_READ_REG(hw, E1000_ROC);
-	E1000_READ_REG(hw, E1000_RNBC);
-	E1000_READ_REG(hw, E1000_MPC);
-}
-
-/**
- *  igb_set_pcie_completion_timeout - set pci-e completion timeout
- *  @hw: pointer to the HW structure
- *
- *  The defaults for 82575 and 82576 should be in the range of 50us to 50ms,
- *  however the hardware default for these parts is 500us to 1ms which is less
- *  than the 10ms recommended by the pci-e spec.  To address this we need to
- *  increase the value to either 10ms to 200ms for capability version 1 config,
- *  or 16ms to 55ms for version 2.
- **/
-static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw)
-{
-	u32 gcr = E1000_READ_REG(hw, E1000_GCR);
-	s32 ret_val = E1000_SUCCESS;
-	u16 pcie_devctl2;
-
-	/* only take action if timeout value is defaulted to 0 */
-	if (gcr & E1000_GCR_CMPL_TMOUT_MASK)
-		goto out;
-
-	/*
-	 * if capababilities version is type 1 we can write the
-	 * timeout of 10ms to 200ms through the GCR register
-	 */
-	if (!(gcr & E1000_GCR_CAP_VER2)) {
-		gcr |= E1000_GCR_CMPL_TMOUT_10ms;
-		goto out;
-	}
-
-	/*
-	 * for version 2 capabilities we need to write the config space
-	 * directly in order to set the completion timeout value for
-	 * 16ms to 55ms
-	 */
-	ret_val = igb_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
-	                                  &pcie_devctl2);
-	if (ret_val)
-		goto out;
-
-	pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms;
-
-	ret_val = igb_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
-	                                   &pcie_devctl2);
-out:
-	/* disable completion timeout resend */
-	gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND;
-
-	E1000_WRITE_REG(hw, E1000_GCR, gcr);
-	return ret_val;
-}
-
-/**
- *  igb_vmdq_set_loopback_pf - enable or disable vmdq loopback
- *  @hw: pointer to the hardware struct
- *  @enable: state to enter, either enabled or disabled
- *
- *  enables/disables L2 switch loopback functionality.
- **/
-void igb_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable)
-{
-	u32 dtxswc = E1000_READ_REG(hw, E1000_DTXSWC);
-
-	if (enable)
-		dtxswc |= E1000_DTXSWC_VMDQ_LOOPBACK_EN;
-	else
-		dtxswc &= ~E1000_DTXSWC_VMDQ_LOOPBACK_EN;
-
-	E1000_WRITE_REG(hw, E1000_DTXSWC, dtxswc);
-}
-
-/**
- *  igb_vmdq_set_replication_pf - enable or disable vmdq replication
- *  @hw: pointer to the hardware struct
- *  @enable: state to enter, either enabled or disabled
- *
- *  enables/disables replication of packets across multiple pools.
- **/
-void igb_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable)
-{
-	u32 vt_ctl = E1000_READ_REG(hw, E1000_VT_CTL);
-
-	if (enable)
-		vt_ctl |= E1000_VT_CTL_VM_REPL_EN;
-	else
-		vt_ctl &= ~E1000_VT_CTL_VM_REPL_EN;
-
-	E1000_WRITE_REG(hw, E1000_VT_CTL, vt_ctl);
-}
-
-static struct pci_device_id igb_82575_nics[] = {
-        PCI_ROM(0x8086, 0x10C9, "E1000_DEV_ID_82576", "E1000_DEV_ID_82576", 0),
-        PCI_ROM(0x8086, 0x150A, "E1000_DEV_ID_82576_NS", "E1000_DEV_ID_82576_NS", 0),
-        PCI_ROM(0x8086, 0x1518, "E1000_DEV_ID_82576_NS_SERDES", "E1000_DEV_ID_82576_NS_SERDES", 0),
-        PCI_ROM(0x8086, 0x10E6, "E1000_DEV_ID_82576_FIBER", "E1000_DEV_ID_82576_FIBER", 0),
-        PCI_ROM(0x8086, 0x10E7, "E1000_DEV_ID_82576_SERDES", "E1000_DEV_ID_82576_SERDES", 0),
-        PCI_ROM(0x8086, 0x150D, "E1000_DEV_ID_82576_SERDES_QUAD", "E1000_DEV_ID_82576_SERDES_QUAD", 0),
-        PCI_ROM(0x8086, 0x10E8, "E1000_DEV_ID_82576_QUAD_COPPER", "E1000_DEV_ID_82576_QUAD_COPPER", 0),
-        PCI_ROM(0x8086, 0x10A7, "E1000_DEV_ID_82575EB_COPPER", "E1000_DEV_ID_82575EB_COPPER", 0),
-        PCI_ROM(0x8086, 0x10A9, "E1000_DEV_ID_82575EB_FIBER_SERDES", "E1000_DEV_ID_82575EB_FIBER_SERDES", 0),
-        PCI_ROM(0x8086, 0x10D6, "E1000_DEV_ID_82575GB_QUAD_COPPER", "E1000_DEV_ID_82575GB_QUAD_COPPER", 0),
-};
-
-struct pci_driver igb_82575_driver __pci_driver = {
-        .ids = igb_82575_nics,
-        .id_count = (sizeof (igb_82575_nics) / sizeof (igb_82575_nics[0])),
-        .probe = igb_probe,
-        .remove = igb_remove,
-};
diff --git a/roms/ipxe/src/drivers/net/igb/igb_82575.h b/roms/ipxe/src/drivers/net/igb/igb_82575.h
deleted file mode 100644
index 12c9a249d78d275b99564bdb04f98f1c4ca6b10b..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_82575.h
+++ /dev/null
@@ -1,442 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#ifndef _IGB_82575_H_
-#define _IGB_82575_H_
-
-#define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \
-                                     (ID_LED_DEF1_DEF2 <<  8) | \
-                                     (ID_LED_DEF1_DEF2 <<  4) | \
-                                     (ID_LED_OFF1_ON2))
-/*
- * Receive Address Register Count
- * Number of high/low register pairs in the RAR.  The RAR (Receive Address
- * Registers) holds the directed and multicast addresses that we monitor.
- * These entries are also used for MAC-based filtering.
- */
-/*
- * For 82576, there are an additional set of RARs that begin at an offset
- * separate from the first set of RARs.
- */
-#define E1000_RAR_ENTRIES_82575   16
-#define E1000_RAR_ENTRIES_82576   24
-
-struct e1000_adv_data_desc {
-	__le64 buffer_addr;    /* Address of the descriptor's data buffer */
-	union {
-		u32 data;
-		struct {
-			u32 datalen :16; /* Data buffer length */
-			u32 rsvd    :4;
-			u32 dtyp    :4;  /* Descriptor type */
-			u32 dcmd    :8;  /* Descriptor command */
-		} config;
-	} lower;
-	union {
-		u32 data;
-		struct {
-			u32 status  :4;  /* Descriptor status */
-			u32 idx     :4;
-			u32 popts   :6;  /* Packet Options */
-			u32 paylen  :18; /* Payload length */
-		} options;
-	} upper;
-};
-
-#define E1000_TXD_DTYP_ADV_C    0x2  /* Advanced Context Descriptor */
-#define E1000_TXD_DTYP_ADV_D    0x3  /* Advanced Data Descriptor */
-#define E1000_ADV_TXD_CMD_DEXT  0x20 /* Descriptor extension (0 = legacy) */
-#define E1000_ADV_TUCMD_IPV4    0x2  /* IP Packet Type: 1=IPv4 */
-#define E1000_ADV_TUCMD_IPV6    0x0  /* IP Packet Type: 0=IPv6 */
-#define E1000_ADV_TUCMD_L4T_UDP 0x0  /* L4 Packet TYPE of UDP */
-#define E1000_ADV_TUCMD_L4T_TCP 0x4  /* L4 Packet TYPE of TCP */
-#define E1000_ADV_TUCMD_MKRREQ  0x10 /* Indicates markers are required */
-#define E1000_ADV_DCMD_EOP      0x1  /* End of Packet */
-#define E1000_ADV_DCMD_IFCS     0x2  /* Insert FCS (Ethernet CRC) */
-#define E1000_ADV_DCMD_RS       0x8  /* Report Status */
-#define E1000_ADV_DCMD_VLE      0x40 /* Add VLAN tag */
-#define E1000_ADV_DCMD_TSE      0x80 /* TCP Seg enable */
-/* Extended Device Control */
-#define E1000_CTRL_EXT_NSICR    0x00000001 /* Disable Intr Clear all on read */
-
-struct e1000_adv_context_desc {
-	union {
-		u32 ip_config;
-		struct {
-			u32 iplen    :9;
-			u32 maclen   :7;
-			u32 vlan_tag :16;
-		} fields;
-	} ip_setup;
-	u32 seq_num;
-	union {
-		u64 l4_config;
-		struct {
-			u32 mkrloc :9;
-			u32 tucmd  :11;
-			u32 dtyp   :4;
-			u32 adv    :8;
-			u32 rsvd   :4;
-			u32 idx    :4;
-			u32 l4len  :8;
-			u32 mss    :16;
-		} fields;
-	} l4_setup;
-};
-
-/* SRRCTL bit definitions */
-#define E1000_SRRCTL_BSIZEPKT_SHIFT                     10 /* Shift _right_ */
-#define E1000_SRRCTL_BSIZEHDRSIZE_MASK                  0x00000F00
-#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT                 2  /* Shift _left_ */
-#define E1000_SRRCTL_DESCTYPE_LEGACY                    0x00000000
-#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF                0x02000000
-#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT                 0x04000000
-#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS          0x0A000000
-#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION           0x06000000
-#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000
-#define E1000_SRRCTL_DESCTYPE_MASK                      0x0E000000
-#define E1000_SRRCTL_DROP_EN                            0x80000000
-
-#define E1000_SRRCTL_BSIZEPKT_MASK      0x0000007F
-#define E1000_SRRCTL_BSIZEHDR_MASK      0x00003F00
-
-#define E1000_TX_HEAD_WB_ENABLE   0x1
-#define E1000_TX_SEQNUM_WB_ENABLE 0x2
-
-#define E1000_MRQC_ENABLE_RSS_4Q            0x00000002
-#define E1000_MRQC_ENABLE_VMDQ              0x00000003
-#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q       0x00000005
-#define E1000_MRQC_RSS_FIELD_IPV4_UDP       0x00400000
-#define E1000_MRQC_RSS_FIELD_IPV6_UDP       0x00800000
-#define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX    0x01000000
-
-#define E1000_VMRCTL_MIRROR_PORT_SHIFT      8
-#define E1000_VMRCTL_MIRROR_DSTPORT_MASK    (7 << E1000_VMRCTL_MIRROR_PORT_SHIFT)
-#define E1000_VMRCTL_POOL_MIRROR_ENABLE     (1 << 0)
-#define E1000_VMRCTL_UPLINK_MIRROR_ENABLE   (1 << 1)
-#define E1000_VMRCTL_DOWNLINK_MIRROR_ENABLE (1 << 2)
-
-#define E1000_EICR_TX_QUEUE ( \
-    E1000_EICR_TX_QUEUE0 |    \
-    E1000_EICR_TX_QUEUE1 |    \
-    E1000_EICR_TX_QUEUE2 |    \
-    E1000_EICR_TX_QUEUE3)
-
-#define E1000_EICR_RX_QUEUE ( \
-    E1000_EICR_RX_QUEUE0 |    \
-    E1000_EICR_RX_QUEUE1 |    \
-    E1000_EICR_RX_QUEUE2 |    \
-    E1000_EICR_RX_QUEUE3)
-
-#define E1000_EIMS_RX_QUEUE E1000_EICR_RX_QUEUE
-#define E1000_EIMS_TX_QUEUE E1000_EICR_TX_QUEUE
-
-#define EIMS_ENABLE_MASK ( \
-    E1000_EIMS_RX_QUEUE  | \
-    E1000_EIMS_TX_QUEUE  | \
-    E1000_EIMS_TCP_TIMER | \
-    E1000_EIMS_OTHER)
-
-/* Immediate Interrupt Rx (A.K.A. Low Latency Interrupt) */
-#define E1000_IMIR_PORT_IM_EN     0x00010000  /* TCP port enable */
-#define E1000_IMIR_PORT_BP        0x00020000  /* TCP port check bypass */
-#define E1000_IMIREXT_SIZE_BP     0x00001000  /* Packet size bypass */
-#define E1000_IMIREXT_CTRL_URG    0x00002000  /* Check URG bit in header */
-#define E1000_IMIREXT_CTRL_ACK    0x00004000  /* Check ACK bit in header */
-#define E1000_IMIREXT_CTRL_PSH    0x00008000  /* Check PSH bit in header */
-#define E1000_IMIREXT_CTRL_RST    0x00010000  /* Check RST bit in header */
-#define E1000_IMIREXT_CTRL_SYN    0x00020000  /* Check SYN bit in header */
-#define E1000_IMIREXT_CTRL_FIN    0x00040000  /* Check FIN bit in header */
-#define E1000_IMIREXT_CTRL_BP     0x00080000  /* Bypass check of ctrl bits */
-
-/* Receive Descriptor - Advanced */
-union e1000_adv_rx_desc {
-	struct {
-		__le64 pkt_addr;             /* Packet buffer address */
-		__le64 hdr_addr;             /* Header buffer address */
-	} read;
-	struct {
-		struct {
-			union {
-				__le32 data;
-				struct {
-					__le16 pkt_info; /*RSS type, Pkt type*/
-					__le16 hdr_info; /* Split Header,
-							  * header buffer len*/
-				} hs_rss;
-			} lo_dword;
-			union {
-				__le32 rss;          /* RSS Hash */
-				struct {
-					__le16 ip_id;    /* IP id */
-					__le16 csum;     /* Packet Checksum */
-				} csum_ip;
-			} hi_dword;
-		} lower;
-		struct {
-			__le32 status_error;     /* ext status/error */
-			__le16 length;           /* Packet length */
-			__le16 vlan;             /* VLAN tag */
-		} upper;
-	} wb;  /* writeback */
-};
-
-#define E1000_RXDADV_RSSTYPE_MASK        0x0000000F
-#define E1000_RXDADV_RSSTYPE_SHIFT       12
-#define E1000_RXDADV_HDRBUFLEN_MASK      0x7FE0
-#define E1000_RXDADV_HDRBUFLEN_SHIFT     5
-#define E1000_RXDADV_SPLITHEADER_EN      0x00001000
-#define E1000_RXDADV_SPH                 0x8000
-#define E1000_RXDADV_STAT_TS             0x10000 /* Pkt was time stamped */
-#define E1000_RXDADV_ERR_HBO             0x00800000
-
-/* RSS Hash results */
-#define E1000_RXDADV_RSSTYPE_NONE        0x00000000
-#define E1000_RXDADV_RSSTYPE_IPV4_TCP    0x00000001
-#define E1000_RXDADV_RSSTYPE_IPV4        0x00000002
-#define E1000_RXDADV_RSSTYPE_IPV6_TCP    0x00000003
-#define E1000_RXDADV_RSSTYPE_IPV6_EX     0x00000004
-#define E1000_RXDADV_RSSTYPE_IPV6        0x00000005
-#define E1000_RXDADV_RSSTYPE_IPV6_TCP_EX 0x00000006
-#define E1000_RXDADV_RSSTYPE_IPV4_UDP    0x00000007
-#define E1000_RXDADV_RSSTYPE_IPV6_UDP    0x00000008
-#define E1000_RXDADV_RSSTYPE_IPV6_UDP_EX 0x00000009
-
-/* RSS Packet Types as indicated in the receive descriptor */
-#define E1000_RXDADV_PKTTYPE_NONE        0x00000000
-#define E1000_RXDADV_PKTTYPE_IPV4        0x00000010 /* IPV4 hdr present */
-#define E1000_RXDADV_PKTTYPE_IPV4_EX     0x00000020 /* IPV4 hdr + extensions */
-#define E1000_RXDADV_PKTTYPE_IPV6        0x00000040 /* IPV6 hdr present */
-#define E1000_RXDADV_PKTTYPE_IPV6_EX     0x00000080 /* IPV6 hdr + extensions */
-#define E1000_RXDADV_PKTTYPE_TCP         0x00000100 /* TCP hdr present */
-#define E1000_RXDADV_PKTTYPE_UDP         0x00000200 /* UDP hdr present */
-#define E1000_RXDADV_PKTTYPE_SCTP        0x00000400 /* SCTP hdr present */
-#define E1000_RXDADV_PKTTYPE_NFS         0x00000800 /* NFS hdr present */
-
-#define E1000_RXDADV_PKTTYPE_IPSEC_ESP   0x00001000 /* IPSec ESP */
-#define E1000_RXDADV_PKTTYPE_IPSEC_AH    0x00002000 /* IPSec AH */
-#define E1000_RXDADV_PKTTYPE_LINKSEC     0x00004000 /* LinkSec Encap */
-#define E1000_RXDADV_PKTTYPE_ETQF        0x00008000 /* PKTTYPE is ETQF index */
-#define E1000_RXDADV_PKTTYPE_ETQF_MASK   0x00000070 /* ETQF has 8 indices */
-#define E1000_RXDADV_PKTTYPE_ETQF_SHIFT  4          /* Right-shift 4 bits */
-
-/* LinkSec results */
-/* Security Processing bit Indication */
-#define E1000_RXDADV_LNKSEC_STATUS_SECP         0x00020000
-#define E1000_RXDADV_LNKSEC_ERROR_BIT_MASK      0x18000000
-#define E1000_RXDADV_LNKSEC_ERROR_NO_SA_MATCH   0x08000000
-#define E1000_RXDADV_LNKSEC_ERROR_REPLAY_ERROR  0x10000000
-#define E1000_RXDADV_LNKSEC_ERROR_BAD_SIG       0x18000000
-
-#define E1000_RXDADV_IPSEC_STATUS_SECP          0x00020000
-#define E1000_RXDADV_IPSEC_ERROR_BIT_MASK       0x18000000
-#define E1000_RXDADV_IPSEC_ERROR_INVALID_PROTOCOL       0x08000000
-#define E1000_RXDADV_IPSEC_ERROR_INVALID_LENGTH         0x10000000
-#define E1000_RXDADV_IPSEC_ERROR_AUTHENTICATION_FAILED  0x18000000
-
-/* Transmit Descriptor - Advanced */
-union e1000_adv_tx_desc {
-	struct {
-		__le64 buffer_addr;    /* Address of descriptor's data buf */
-		__le32 cmd_type_len;
-		__le32 olinfo_status;
-	} read;
-	struct {
-		__le64 rsvd;       /* Reserved */
-		__le32 nxtseq_seed;
-		__le32 status;
-	} wb;
-};
-
-/* Adv Transmit Descriptor Config Masks */
-#define E1000_ADVTXD_DTYP_CTXT    0x00200000 /* Advanced Context Descriptor */
-#define E1000_ADVTXD_DTYP_DATA    0x00300000 /* Advanced Data Descriptor */
-#define E1000_ADVTXD_DCMD_EOP     0x01000000 /* End of Packet */
-#define E1000_ADVTXD_DCMD_IFCS    0x02000000 /* Insert FCS (Ethernet CRC) */
-#define E1000_ADVTXD_DCMD_RS      0x08000000 /* Report Status */
-#define E1000_ADVTXD_DCMD_DDTYP_ISCSI  0x10000000 /* DDP hdr type or iSCSI */
-#define E1000_ADVTXD_DCMD_DEXT    0x20000000 /* Descriptor extension (1=Adv) */
-#define E1000_ADVTXD_DCMD_VLE     0x40000000 /* VLAN pkt enable */
-#define E1000_ADVTXD_DCMD_TSE     0x80000000 /* TCP Seg enable */
-#define E1000_ADVTXD_MAC_LINKSEC  0x00040000 /* Apply LinkSec on packet */
-#define E1000_ADVTXD_MAC_TSTAMP   0x00080000 /* IEEE1588 Timestamp packet */
-#define E1000_ADVTXD_STAT_SN_CRC  0x00000002 /* NXTSEQ/SEED present in WB */
-#define E1000_ADVTXD_IDX_SHIFT    4  /* Adv desc Index shift */
-#define E1000_ADVTXD_POPTS_ISCO_1ST  0x00000000 /* 1st TSO of iSCSI PDU */
-#define E1000_ADVTXD_POPTS_ISCO_MDL  0x00000800 /* Middle TSO of iSCSI PDU */
-#define E1000_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */
-#define E1000_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU*/
-#define E1000_ADVTXD_POPTS_IPSEC     0x00000400 /* IPSec offload request */
-#define E1000_ADVTXD_PAYLEN_SHIFT    14 /* Adv desc PAYLEN shift */
-
-/* Context descriptors */
-struct e1000_adv_tx_context_desc {
-	__le32 vlan_macip_lens;
-	__le32 seqnum_seed;
-	__le32 type_tucmd_mlhl;
-	__le32 mss_l4len_idx;
-};
-
-#define E1000_ADVTXD_MACLEN_SHIFT    9  /* Adv ctxt desc mac len shift */
-#define E1000_ADVTXD_VLAN_SHIFT     16  /* Adv ctxt vlan tag shift */
-#define E1000_ADVTXD_TUCMD_IPV4    0x00000400  /* IP Packet Type: 1=IPv4 */
-#define E1000_ADVTXD_TUCMD_IPV6    0x00000000  /* IP Packet Type: 0=IPv6 */
-#define E1000_ADVTXD_TUCMD_L4T_UDP 0x00000000  /* L4 Packet TYPE of UDP */
-#define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800  /* L4 Packet TYPE of TCP */
-#define E1000_ADVTXD_TUCMD_L4T_SCTP 0x00001000  /* L4 Packet TYPE of SCTP */
-#define E1000_ADVTXD_TUCMD_IPSEC_TYPE_ESP    0x00002000 /* IPSec Type ESP */
-/* IPSec Encrypt Enable for ESP */
-#define E1000_ADVTXD_TUCMD_IPSEC_ENCRYPT_EN  0x00004000
-#define E1000_ADVTXD_TUCMD_MKRREQ  0x00002000 /* Req requires Markers and CRC */
-#define E1000_ADVTXD_L4LEN_SHIFT     8  /* Adv ctxt L4LEN shift */
-#define E1000_ADVTXD_MSS_SHIFT      16  /* Adv ctxt MSS shift */
-/* Adv ctxt IPSec SA IDX mask */
-#define E1000_ADVTXD_IPSEC_SA_INDEX_MASK     0x000000FF
-/* Adv ctxt IPSec ESP len mask */
-#define E1000_ADVTXD_IPSEC_ESP_LEN_MASK      0x000000FF
-
-/* Additional Transmit Descriptor Control definitions */
-#define E1000_TXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Tx Queue */
-#define E1000_TXDCTL_SWFLSH        0x04000000 /* Tx Desc. write-back flushing */
-/* Tx Queue Arbitration Priority 0=low, 1=high */
-#define E1000_TXDCTL_PRIORITY      0x08000000
-
-/* Additional Receive Descriptor Control definitions */
-#define E1000_RXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Rx Queue */
-#define E1000_RXDCTL_SWFLSH        0x04000000 /* Rx Desc. write-back flushing */
-
-/* Direct Cache Access (DCA) definitions */
-#define E1000_DCA_CTRL_DCA_ENABLE  0x00000000 /* DCA Enable */
-#define E1000_DCA_CTRL_DCA_DISABLE 0x00000001 /* DCA Disable */
-
-#define E1000_DCA_CTRL_DCA_MODE_CB1 0x00 /* DCA Mode CB1 */
-#define E1000_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */
-
-#define E1000_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */
-#define E1000_DCA_RXCTRL_DESC_DCA_EN (1 << 5) /* DCA Rx Desc enable */
-#define E1000_DCA_RXCTRL_HEAD_DCA_EN (1 << 6) /* DCA Rx Desc header enable */
-#define E1000_DCA_RXCTRL_DATA_DCA_EN (1 << 7) /* DCA Rx Desc payload enable */
-
-#define E1000_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */
-#define E1000_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */
-#define E1000_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */
-
-#define E1000_DCA_TXCTRL_CPUID_MASK_82576 0xFF000000 /* Tx CPUID Mask */
-#define E1000_DCA_RXCTRL_CPUID_MASK_82576 0xFF000000 /* Rx CPUID Mask */
-#define E1000_DCA_TXCTRL_CPUID_SHIFT_82576 24 /* Tx CPUID */
-#define E1000_DCA_RXCTRL_CPUID_SHIFT_82576 24 /* Rx CPUID */
-
-/* Additional interrupt register bit definitions */
-#define E1000_ICR_LSECPNS       0x00000020          /* PN threshold - server */
-#define E1000_IMS_LSECPNS       E1000_ICR_LSECPNS   /* PN threshold - server */
-#define E1000_ICS_LSECPNS       E1000_ICR_LSECPNS   /* PN threshold - server */
-
-/* ETQF register bit definitions */
-#define E1000_ETQF_FILTER_ENABLE   (1 << 26)
-#define E1000_ETQF_IMM_INT         (1 << 29)
-#define E1000_ETQF_1588            (1 << 30)
-#define E1000_ETQF_QUEUE_ENABLE    (1 << 31)
-/*
- * ETQF filter list: one static filter per filter consumer. This is
- *                   to avoid filter collisions later. Add new filters
- *                   here!!
- *
- * Current filters:
- *    EAPOL 802.1x (0x888e): Filter 0
- */
-#define E1000_ETQF_FILTER_EAPOL          0
-
-#define E1000_FTQF_VF_BP               0x00008000
-#define E1000_FTQF_1588_TIME_STAMP     0x08000000
-#define E1000_FTQF_MASK                0xF0000000
-#define E1000_FTQF_MASK_PROTO_BP       0x10000000
-#define E1000_FTQF_MASK_SOURCE_ADDR_BP 0x20000000
-#define E1000_FTQF_MASK_DEST_ADDR_BP   0x40000000
-#define E1000_FTQF_MASK_SOURCE_PORT_BP 0x80000000
-
-#define E1000_NVM_APME_82575          0x0400
-#define MAX_NUM_VFS                   8
-
-#define E1000_DTXSWC_MAC_SPOOF_MASK   0x000000FF /* Per VF MAC spoof control */
-#define E1000_DTXSWC_VLAN_SPOOF_MASK  0x0000FF00 /* Per VF VLAN spoof control */
-#define E1000_DTXSWC_LLE_MASK         0x00FF0000 /* Per VF Local LB enables */
-#define E1000_DTXSWC_VLAN_SPOOF_SHIFT 8
-#define E1000_DTXSWC_LLE_SHIFT        16
-#define E1000_DTXSWC_VMDQ_LOOPBACK_EN (1 << 31)  /* global VF LB enable */
-
-/* Easy defines for setting default pool, would normally be left a zero */
-#define E1000_VT_CTL_DEFAULT_POOL_SHIFT 7
-#define E1000_VT_CTL_DEFAULT_POOL_MASK  (0x7 << E1000_VT_CTL_DEFAULT_POOL_SHIFT)
-
-/* Other useful VMD_CTL register defines */
-#define E1000_VT_CTL_IGNORE_MAC         (1 << 28)
-#define E1000_VT_CTL_DISABLE_DEF_POOL   (1 << 29)
-#define E1000_VT_CTL_VM_REPL_EN         (1 << 30)
-
-/* Per VM Offload register setup */
-#define E1000_VMOLR_RLPML_MASK 0x00003FFF /* Long Packet Maximum Length mask */
-#define E1000_VMOLR_LPE        0x00010000 /* Accept Long packet */
-#define E1000_VMOLR_RSSE       0x00020000 /* Enable RSS */
-#define E1000_VMOLR_AUPE       0x01000000 /* Accept untagged packets */
-#define E1000_VMOLR_ROMPE      0x02000000 /* Accept overflow multicast */
-#define E1000_VMOLR_ROPE       0x04000000 /* Accept overflow unicast */
-#define E1000_VMOLR_BAM        0x08000000 /* Accept Broadcast packets */
-#define E1000_VMOLR_MPME       0x10000000 /* Multicast promiscuous mode */
-#define E1000_VMOLR_STRVLAN    0x40000000 /* Vlan stripping enable */
-#define E1000_VMOLR_STRCRC     0x80000000 /* CRC stripping enable */
-
-#define E1000_VLVF_ARRAY_SIZE     32
-#define E1000_VLVF_VLANID_MASK    0x00000FFF
-#define E1000_VLVF_POOLSEL_SHIFT  12
-#define E1000_VLVF_POOLSEL_MASK   (0xFF << E1000_VLVF_POOLSEL_SHIFT)
-#define E1000_VLVF_LVLAN          0x00100000
-#define E1000_VLVF_VLANID_ENABLE  0x80000000
-
-#define E1000_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */
-
-#define E1000_IOVCTL 0x05BBC
-#define E1000_IOVCTL_REUSE_VFQ 0x00000001
-
-#define E1000_RPLOLR_STRVLAN   0x40000000
-#define E1000_RPLOLR_STRCRC    0x80000000
-
-#define E1000_DTXCTL_8023LL     0x0004
-#define E1000_DTXCTL_VLAN_ADDED 0x0008
-#define E1000_DTXCTL_OOS_ENABLE 0x0010
-#define E1000_DTXCTL_MDP_EN     0x0020
-#define E1000_DTXCTL_SPOOF_INT  0x0040
-
-#define ALL_QUEUES   0xFFFF
-
-/* RX packet buffer size defines */
-#define E1000_RXPBS_SIZE_MASK_82576  0x0000007F
-void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable);
-void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable);
-
-#endif /* _IGB_82575_H_ */
diff --git a/roms/ipxe/src/drivers/net/igb/igb_api.c b/roms/ipxe/src/drivers/net/igb/igb_api.c
deleted file mode 100644
index eda6bc01831a40f7684d253d7bc630f2382c6886..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_api.c
+++ /dev/null
@@ -1,1108 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#include "igb.h"
-
-/**
- *  igb_init_mac_params - Initialize MAC function pointers
- *  @hw: pointer to the HW structure
- *
- *  This function initializes the function pointers for the MAC
- *  set of functions.  Called by drivers or by e1000_setup_init_funcs.
- **/
-s32 igb_init_mac_params(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->mac.ops.init_params) {
-		ret_val = hw->mac.ops.init_params(hw);
-		if (ret_val) {
-			DEBUGOUT("MAC Initialization Error\n");
-			goto out;
-		}
-	} else {
-		DEBUGOUT("mac.init_mac_params was NULL\n");
-		ret_val = -E1000_ERR_CONFIG;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_init_nvm_params - Initialize NVM function pointers
- *  @hw: pointer to the HW structure
- *
- *  This function initializes the function pointers for the NVM
- *  set of functions.  Called by drivers or by e1000_setup_init_funcs.
- **/
-s32 igb_init_nvm_params(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->nvm.ops.init_params) {
-		ret_val = hw->nvm.ops.init_params(hw);
-		if (ret_val) {
-			DEBUGOUT("NVM Initialization Error\n");
-			goto out;
-		}
-	} else {
-		DEBUGOUT("nvm.init_nvm_params was NULL\n");
-		ret_val = -E1000_ERR_CONFIG;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_init_phy_params - Initialize PHY function pointers
- *  @hw: pointer to the HW structure
- *
- *  This function initializes the function pointers for the PHY
- *  set of functions.  Called by drivers or by e1000_setup_init_funcs.
- **/
-s32 igb_init_phy_params(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->phy.ops.init_params) {
-		ret_val = hw->phy.ops.init_params(hw);
-		if (ret_val) {
-			DEBUGOUT("PHY Initialization Error\n");
-			goto out;
-		}
-	} else {
-		DEBUGOUT("phy.init_phy_params was NULL\n");
-		ret_val =  -E1000_ERR_CONFIG;
-	}
-
-out:
-	return ret_val;
-}
-
-#if 0
-/**
- *  igb_init_mbx_params - Initialize mailbox function pointers
- *  @hw: pointer to the HW structure
- *
- *  This function initializes the function pointers for the PHY
- *  set of functions.  Called by drivers or by e1000_setup_init_funcs.
- **/
-s32 igb_init_mbx_params(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	if (hw->mbx.ops.init_params) {
-		ret_val = hw->mbx.ops.init_params(hw);
-		if (ret_val) {
-			DEBUGOUT("Mailbox Initialization Error\n");
-			goto out;
-		}
-	} else {
-		DEBUGOUT("mbx.init_mbx_params was NULL\n");
-		ret_val =  -E1000_ERR_CONFIG;
-	}
-
-out:
-	return ret_val;
-}
-#endif
-
-/**
- *  igb_set_mac_type - Sets MAC type
- *  @hw: pointer to the HW structure
- *
- *  This function sets the mac type of the adapter based on the
- *  device ID stored in the hw structure.
- *  MUST BE FIRST FUNCTION CALLED (explicitly or through
- *  igb_setup_init_funcs()).
- **/
-s32 igb_set_mac_type(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_set_mac_type");
-
-	switch (hw->device_id) {
-	case E1000_DEV_ID_82575EB_COPPER:
-	case E1000_DEV_ID_82575EB_FIBER_SERDES:
-	case E1000_DEV_ID_82575GB_QUAD_COPPER:
-		mac->type = e1000_82575;
-		break;
-	case E1000_DEV_ID_82576:
-	case E1000_DEV_ID_82576_FIBER:
-	case E1000_DEV_ID_82576_SERDES:
-	case E1000_DEV_ID_82576_QUAD_COPPER:
-	case E1000_DEV_ID_82576_NS:
-	case E1000_DEV_ID_82576_NS_SERDES:
-	case E1000_DEV_ID_82576_SERDES_QUAD:
-		mac->type = e1000_82576;
-		break;
-	default:
-		/* Should never have loaded on this device */
-		ret_val = -E1000_ERR_MAC_INIT;
-		break;
-	}
-
-	return ret_val;
-}
-
-/**
- *  igb_setup_init_funcs - Initializes function pointers
- *  @hw: pointer to the HW structure
- *  @init_device: true will initialize the rest of the function pointers
- *                 getting the device ready for use.  false will only set
- *                 MAC type and the function pointers for the other init
- *                 functions.  Passing false will not generate any hardware
- *                 reads or writes.
- *
- *  This function must be called by a driver in order to use the rest
- *  of the 'shared' code files. Called by drivers only.
- **/
-s32 igb_setup_init_funcs(struct e1000_hw *hw, bool init_device)
-{
-	s32 ret_val;
-
-	/* Can't do much good without knowing the MAC type. */
-	ret_val = igb_set_mac_type(hw);
-	if (ret_val) {
-		DEBUGOUT("ERROR: MAC type could not be set properly.\n");
-		goto out;
-	}
-
-	if (!hw->hw_addr) {
-		DEBUGOUT("ERROR: Registers not mapped\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	/*
-	 * Init function pointers to generic implementations. We do this first
-	 * allowing a driver module to override it afterward.
-	 */
-	igb_init_mac_ops_generic(hw);
-	igb_init_nvm_ops_generic(hw);
-#if 0
-	igb_init_mbx_ops_generic(hw);
-#endif
-	/*
-	 * Set up the init function pointers. These are functions within the
-	 * adapter family file that sets up function pointers for the rest of
-	 * the functions in that family.
-	 */
-	switch (hw->mac.type) {
-	case e1000_82575:
-	case e1000_82576:
-		igb_init_function_pointers_82575(hw);
-		break;
-	default:
-		DEBUGOUT("Hardware not supported\n");
-		ret_val = -E1000_ERR_CONFIG;
-		break;
-	}
-
-	/*
-	 * Initialize the rest of the function pointers. These require some
-	 * register reads/writes in some cases.
-	 */
-	if (!(ret_val) && init_device) {
-		ret_val = igb_init_mac_params(hw);
-		if (ret_val)
-			goto out;
-
-		ret_val = igb_init_nvm_params(hw);
-		if (ret_val)
-			goto out;
-
-		ret_val = igb_init_phy_params(hw);
-		if (ret_val)
-			goto out;
-#if 0
-		ret_val = igb_init_mbx_params(hw);
-		if (ret_val)
-			goto out;
-#endif
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_get_bus_info - Obtain bus information for adapter
- *  @hw: pointer to the HW structure
- *
- *  This will obtain information about the HW bus for which the
- *  adapter is attached and stores it in the hw structure. This is a
- *  function pointer entry point called by drivers.
- **/
-s32 igb_get_bus_info(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.get_bus_info)
-		return hw->mac.ops.get_bus_info(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_clear_vfta - Clear VLAN filter table
- *  @hw: pointer to the HW structure
- *
- *  This clears the VLAN filter table on the adapter. This is a function
- *  pointer entry point called by drivers.
- **/
-void igb_clear_vfta(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.clear_vfta)
-		hw->mac.ops.clear_vfta(hw);
-}
-
-/**
- *  igb_write_vfta - Write value to VLAN filter table
- *  @hw: pointer to the HW structure
- *  @offset: the 32-bit offset in which to write the value to.
- *  @value: the 32-bit value to write at location offset.
- *
- *  This writes a 32-bit value to a 32-bit offset in the VLAN filter
- *  table. This is a function pointer entry point called by drivers.
- **/
-void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
-{
-	if (hw->mac.ops.write_vfta)
-		hw->mac.ops.write_vfta(hw, offset, value);
-}
-
-/**
- *  igb_update_mc_addr_list - Update Multicast addresses
- *  @hw: pointer to the HW structure
- *  @mc_addr_list: array of multicast addresses to program
- *  @mc_addr_count: number of multicast addresses to program
- *
- *  Updates the Multicast Table Array.
- *  The caller must have a packed mc_addr_list of multicast addresses.
- **/
-void igb_update_mc_addr_list(struct e1000_hw *hw, u8 *mc_addr_list,
-                               u32 mc_addr_count)
-{
-	if (hw->mac.ops.update_mc_addr_list)
-		hw->mac.ops.update_mc_addr_list(hw, mc_addr_list,
-		                                mc_addr_count);
-}
-
-/**
- *  igb_force_mac_fc - Force MAC flow control
- *  @hw: pointer to the HW structure
- *
- *  Force the MAC's flow control settings. Currently no func pointer exists
- *  and all implementations are handled in the generic version of this
- *  function.
- **/
-s32 igb_force_mac_fc(struct e1000_hw *hw)
-{
-	return igb_force_mac_fc_generic(hw);
-}
-
-/**
- *  igb_check_for_link - Check/Store link connection
- *  @hw: pointer to the HW structure
- *
- *  This checks the link condition of the adapter and stores the
- *  results in the hw->mac structure. This is a function pointer entry
- *  point called by drivers.
- **/
-s32 igb_check_for_link(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.check_for_link)
-		return hw->mac.ops.check_for_link(hw);
-
-	return -E1000_ERR_CONFIG;
-}
-
-/**
- *  igb_check_mng_mode - Check management mode
- *  @hw: pointer to the HW structure
- *
- *  This checks if the adapter has manageability enabled.
- *  This is a function pointer entry point called by drivers.
- **/
-bool igb_check_mng_mode(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.check_mng_mode)
-		return hw->mac.ops.check_mng_mode(hw);
-
-	return false;
-}
-
-#if 0
-/**
- *  igb_mng_write_dhcp_info - Writes DHCP info to host interface
- *  @hw: pointer to the HW structure
- *  @buffer: pointer to the host interface
- *  @length: size of the buffer
- *
- *  Writes the DHCP information to the host interface.
- **/
-s32 igb_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length)
-{
-	return igb_mng_write_dhcp_info_generic(hw, buffer, length);
-}
-#endif
-
-/**
- *  igb_reset_hw - Reset hardware
- *  @hw: pointer to the HW structure
- *
- *  This resets the hardware into a known state. This is a function pointer
- *  entry point called by drivers.
- **/
-s32 igb_reset_hw(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.reset_hw)
-		return hw->mac.ops.reset_hw(hw);
-
-	return -E1000_ERR_CONFIG;
-}
-
-/**
- *  igb_init_hw - Initialize hardware
- *  @hw: pointer to the HW structure
- *
- *  This inits the hardware readying it for operation. This is a function
- *  pointer entry point called by drivers.
- **/
-s32 igb_init_hw(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.init_hw)
-		return hw->mac.ops.init_hw(hw);
-
-	return -E1000_ERR_CONFIG;
-}
-
-/**
- *  igb_setup_link - Configures link and flow control
- *  @hw: pointer to the HW structure
- *
- *  This configures link and flow control settings for the adapter. This
- *  is a function pointer entry point called by drivers. While modules can
- *  also call this, they probably call their own version of this function.
- **/
-s32 igb_setup_link(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.setup_link)
-		return hw->mac.ops.setup_link(hw);
-
-	return -E1000_ERR_CONFIG;
-}
-
-/**
- *  igb_get_speed_and_duplex - Returns current speed and duplex
- *  @hw: pointer to the HW structure
- *  @speed: pointer to a 16-bit value to store the speed
- *  @duplex: pointer to a 16-bit value to store the duplex.
- *
- *  This returns the speed and duplex of the adapter in the two 'out'
- *  variables passed in. This is a function pointer entry point called
- *  by drivers.
- **/
-s32 igb_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed, u16 *duplex)
-{
-	if (hw->mac.ops.get_link_up_info)
-		return hw->mac.ops.get_link_up_info(hw, speed, duplex);
-
-	return -E1000_ERR_CONFIG;
-}
-
-/**
- *  igb_setup_led - Configures SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  This prepares the SW controllable LED for use and saves the current state
- *  of the LED so it can be later restored. This is a function pointer entry
- *  point called by drivers.
- **/
-s32 igb_setup_led(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.setup_led)
-		return hw->mac.ops.setup_led(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_cleanup_led - Restores SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  This restores the SW controllable LED to the value saved off by
- *  e1000_setup_led. This is a function pointer entry point called by drivers.
- **/
-s32 igb_cleanup_led(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.cleanup_led)
-		return hw->mac.ops.cleanup_led(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_blink_led - Blink SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  This starts the adapter LED blinking. Request the LED to be setup first
- *  and cleaned up after. This is a function pointer entry point called by
- *  drivers.
- **/
-s32 igb_blink_led(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.blink_led)
-		return hw->mac.ops.blink_led(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_id_led_init - store LED configurations in SW
- *  @hw: pointer to the HW structure
- *
- *  Initializes the LED config in SW. This is a function pointer entry point
- *  called by drivers.
- **/
-s32 igb_id_led_init(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.id_led_init)
-		return hw->mac.ops.id_led_init(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_led_on - Turn on SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  Turns the SW defined LED on. This is a function pointer entry point
- *  called by drivers.
- **/
-s32 igb_led_on(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.led_on)
-		return hw->mac.ops.led_on(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_led_off - Turn off SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  Turns the SW defined LED off. This is a function pointer entry point
- *  called by drivers.
- **/
-s32 igb_led_off(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.led_off)
-		return hw->mac.ops.led_off(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_reset_adaptive - Reset adaptive IFS
- *  @hw: pointer to the HW structure
- *
- *  Resets the adaptive IFS. Currently no func pointer exists and all
- *  implementations are handled in the generic version of this function.
- **/
-void igb_reset_adaptive(struct e1000_hw *hw)
-{
-	igb_reset_adaptive_generic(hw);
-}
-
-/**
- *  igb_update_adaptive - Update adaptive IFS
- *  @hw: pointer to the HW structure
- *
- *  Updates adapter IFS. Currently no func pointer exists and all
- *  implementations are handled in the generic version of this function.
- **/
-void igb_update_adaptive(struct e1000_hw *hw)
-{
-	igb_update_adaptive_generic(hw);
-}
-
-/**
- *  igb_disable_pcie_master - Disable PCI-Express master access
- *  @hw: pointer to the HW structure
- *
- *  Disables PCI-Express master access and verifies there are no pending
- *  requests. Currently no func pointer exists and all implementations are
- *  handled in the generic version of this function.
- **/
-s32 igb_disable_pcie_master(struct e1000_hw *hw)
-{
-	return igb_disable_pcie_master_generic(hw);
-}
-
-/**
- *  igb_config_collision_dist - Configure collision distance
- *  @hw: pointer to the HW structure
- *
- *  Configures the collision distance to the default value and is used
- *  during link setup.
- **/
-void igb_config_collision_dist(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.config_collision_dist)
-		hw->mac.ops.config_collision_dist(hw);
-}
-
-/**
- *  igb_rar_set - Sets a receive address register
- *  @hw: pointer to the HW structure
- *  @addr: address to set the RAR to
- *  @index: the RAR to set
- *
- *  Sets a Receive Address Register (RAR) to the specified address.
- **/
-void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
-{
-	if (hw->mac.ops.rar_set)
-		hw->mac.ops.rar_set(hw, addr, index);
-}
-
-/**
- *  igb_validate_mdi_setting - Ensures valid MDI/MDIX SW state
- *  @hw: pointer to the HW structure
- *
- *  Ensures that the MDI/MDIX SW state is valid.
- **/
-s32 igb_validate_mdi_setting(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.validate_mdi_setting)
-		return hw->mac.ops.validate_mdi_setting(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_mta_set - Sets multicast table bit
- *  @hw: pointer to the HW structure
- *  @hash_value: Multicast hash value.
- *
- *  This sets the bit in the multicast table corresponding to the
- *  hash value.  This is a function pointer entry point called by drivers.
- **/
-void igb_mta_set(struct e1000_hw *hw, u32 hash_value)
-{
-	if (hw->mac.ops.mta_set)
-		hw->mac.ops.mta_set(hw, hash_value);
-}
-
-/**
- *  igb_hash_mc_addr - Determines address location in multicast table
- *  @hw: pointer to the HW structure
- *  @mc_addr: Multicast address to hash.
- *
- *  This hashes an address to determine its location in the multicast
- *  table. Currently no func pointer exists and all implementations
- *  are handled in the generic version of this function.
- **/
-u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr)
-{
-	return igb_hash_mc_addr_generic(hw, mc_addr);
-}
-
-/**
- *  igb_enable_tx_pkt_filtering - Enable packet filtering on TX
- *  @hw: pointer to the HW structure
- *
- *  Enables packet filtering on transmit packets if manageability is enabled
- *  and host interface is enabled.
- *  Currently no func pointer exists and all implementations are handled in the
- *  generic version of this function.
- **/
-#if 0
-bool igb_enable_tx_pkt_filtering(struct e1000_hw *hw)
-{
-	return igb_enable_tx_pkt_filtering_generic(hw);
-}
-#endif
-
-/**
- *  igb_mng_host_if_write - Writes to the manageability host interface
- *  @hw: pointer to the HW structure
- *  @buffer: pointer to the host interface buffer
- *  @length: size of the buffer
- *  @offset: location in the buffer to write to
- *  @sum: sum of the data (not checksum)
- *
- *  This function writes the buffer content at the offset given on the host if.
- *  It also does alignment considerations to do the writes in most efficient
- *  way.  Also fills up the sum of the buffer in *buffer parameter.
- **/
-s32 igb_mng_host_if_write(struct e1000_hw * hw, u8 *buffer, u16 length,
-                            u16 offset, u8 *sum)
-{
-	if (hw->mac.ops.mng_host_if_write)
-		return hw->mac.ops.mng_host_if_write(hw, buffer, length,
-		                                     offset, sum);
-
-	return E1000_NOT_IMPLEMENTED;
-}
-
-/**
- *  igb_mng_write_cmd_header - Writes manageability command header
- *  @hw: pointer to the HW structure
- *  @hdr: pointer to the host interface command header
- *
- *  Writes the command header after does the checksum calculation.
- **/
-s32 igb_mng_write_cmd_header(struct e1000_hw *hw,
-                               struct e1000_host_mng_command_header *hdr)
-{
-	if (hw->mac.ops.mng_write_cmd_header)
-		return hw->mac.ops.mng_write_cmd_header(hw, hdr);
-
-	return E1000_NOT_IMPLEMENTED;
-}
-
-/**
- *  igb_mng_enable_host_if - Checks host interface is enabled
- *  @hw: pointer to the HW structure
- *
- *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
- *
- *  This function checks whether the HOST IF is enabled for command operation
- *  and also checks whether the previous command is completed.  It busy waits
- *  in case of previous command is not completed.
- **/
-s32 igb_mng_enable_host_if(struct e1000_hw * hw)
-{
-	if (hw->mac.ops.mng_enable_host_if)
-		return hw->mac.ops.mng_enable_host_if(hw);
-
-	return E1000_NOT_IMPLEMENTED;
-}
-
-/**
- *  igb_wait_autoneg - Waits for autonegotiation completion
- *  @hw: pointer to the HW structure
- *
- *  Waits for autoneg to complete. Currently no func pointer exists and all
- *  implementations are handled in the generic version of this function.
- **/
-s32 igb_wait_autoneg(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.wait_autoneg)
-		return hw->mac.ops.wait_autoneg(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_check_reset_block - Verifies PHY can be reset
- *  @hw: pointer to the HW structure
- *
- *  Checks if the PHY is in a state that can be reset or if manageability
- *  has it tied up. This is a function pointer entry point called by drivers.
- **/
-s32 igb_check_reset_block(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.check_reset_block)
-		return hw->phy.ops.check_reset_block(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_read_phy_reg - Reads PHY register
- *  @hw: pointer to the HW structure
- *  @offset: the register to read
- *  @data: the buffer to store the 16-bit read.
- *
- *  Reads the PHY register and returns the value in data.
- *  This is a function pointer entry point called by drivers.
- **/
-s32 igb_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	if (hw->phy.ops.read_reg)
-		return hw->phy.ops.read_reg(hw, offset, data);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_write_phy_reg - Writes PHY register
- *  @hw: pointer to the HW structure
- *  @offset: the register to write
- *  @data: the value to write.
- *
- *  Writes the PHY register at offset with the value in data.
- *  This is a function pointer entry point called by drivers.
- **/
-s32 igb_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	if (hw->phy.ops.write_reg)
-		return hw->phy.ops.write_reg(hw, offset, data);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_release_phy - Generic release PHY
- *  @hw: pointer to the HW structure
- *
- *  Return if silicon family does not require a semaphore when accessing the
- *  PHY.
- **/
-void igb_release_phy(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.release)
-		hw->phy.ops.release(hw);
-}
-
-/**
- *  igb_acquire_phy - Generic acquire PHY
- *  @hw: pointer to the HW structure
- *
- *  Return success if silicon family does not require a semaphore when
- *  accessing the PHY.
- **/
-s32 igb_acquire_phy(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.acquire)
-		return hw->phy.ops.acquire(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_read_kmrn_reg - Reads register using Kumeran interface
- *  @hw: pointer to the HW structure
- *  @offset: the register to read
- *  @data: the location to store the 16-bit value read.
- *
- *  Reads a register out of the Kumeran interface. Currently no func pointer
- *  exists and all implementations are handled in the generic version of
- *  this function.
- **/
-s32 igb_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	return igb_read_kmrn_reg_generic(hw, offset, data);
-}
-
-/**
- *  igb_write_kmrn_reg - Writes register using Kumeran interface
- *  @hw: pointer to the HW structure
- *  @offset: the register to write
- *  @data: the value to write.
- *
- *  Writes a register to the Kumeran interface. Currently no func pointer
- *  exists and all implementations are handled in the generic version of
- *  this function.
- **/
-s32 igb_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	return igb_write_kmrn_reg_generic(hw, offset, data);
-}
-
-#if 0
-/**
- *  igb_get_cable_length - Retrieves cable length estimation
- *  @hw: pointer to the HW structure
- *
- *  This function estimates the cable length and stores them in
- *  hw->phy.min_length and hw->phy.max_length. This is a function pointer
- *  entry point called by drivers.
- **/
-s32 igb_get_cable_length(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.get_cable_length)
-		return hw->phy.ops.get_cable_length(hw);
-
-	return E1000_SUCCESS;
-}
-#endif
-
-/**
- *  igb_get_phy_info - Retrieves PHY information from registers
- *  @hw: pointer to the HW structure
- *
- *  This function gets some information from various PHY registers and
- *  populates hw->phy values with it. This is a function pointer entry
- *  point called by drivers.
- **/
-s32 igb_get_phy_info(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.get_info)
-		return hw->phy.ops.get_info(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_phy_hw_reset - Hard PHY reset
- *  @hw: pointer to the HW structure
- *
- *  Performs a hard PHY reset. This is a function pointer entry point called
- *  by drivers.
- **/
-s32 igb_phy_hw_reset(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.reset)
-		return hw->phy.ops.reset(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_phy_commit - Soft PHY reset
- *  @hw: pointer to the HW structure
- *
- *  Performs a soft PHY reset on those that apply. This is a function pointer
- *  entry point called by drivers.
- **/
-s32 igb_phy_commit(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.commit)
-		return hw->phy.ops.commit(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_set_d0_lplu_state - Sets low power link up state for D0
- *  @hw: pointer to the HW structure
- *  @active: boolean used to enable/disable lplu
- *
- *  Success returns 0, Failure returns 1
- *
- *  The low power link up (lplu) state is set to the power management level D0
- *  and SmartSpeed is disabled when active is true, else clear lplu for D0
- *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
- *  is used during Dx states where the power conservation is most important.
- *  During driver activity, SmartSpeed should be enabled so performance is
- *  maintained.  This is a function pointer entry point called by drivers.
- **/
-s32 igb_set_d0_lplu_state(struct e1000_hw *hw, bool active)
-{
-	if (hw->phy.ops.set_d0_lplu_state)
-		return hw->phy.ops.set_d0_lplu_state(hw, active);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_set_d3_lplu_state - Sets low power link up state for D3
- *  @hw: pointer to the HW structure
- *  @active: boolean used to enable/disable lplu
- *
- *  Success returns 0, Failure returns 1
- *
- *  The low power link up (lplu) state is set to the power management level D3
- *  and SmartSpeed is disabled when active is true, else clear lplu for D3
- *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
- *  is used during Dx states where the power conservation is most important.
- *  During driver activity, SmartSpeed should be enabled so performance is
- *  maintained.  This is a function pointer entry point called by drivers.
- **/
-s32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active)
-{
-	if (hw->phy.ops.set_d3_lplu_state)
-		return hw->phy.ops.set_d3_lplu_state(hw, active);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_read_mac_addr - Reads MAC address
- *  @hw: pointer to the HW structure
- *
- *  Reads the MAC address out of the adapter and stores it in the HW structure.
- *  Currently no func pointer exists and all implementations are handled in the
- *  generic version of this function.
- **/
-s32 igb_read_mac_addr(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.read_mac_addr)
-		return hw->mac.ops.read_mac_addr(hw);
-
-	return igb_read_mac_addr_generic(hw);
-}
-
-/**
- *  igb_read_pba_num - Read device part number
- *  @hw: pointer to the HW structure
- *  @pba_num: pointer to device part number
- *
- *  Reads the product board assembly (PBA) number from the EEPROM and stores
- *  the value in pba_num.
- *  Currently no func pointer exists and all implementations are handled in the
- *  generic version of this function.
- **/
-s32 igb_read_pba_num(struct e1000_hw *hw, u32 *pba_num)
-{
-	return igb_read_pba_num_generic(hw, pba_num);
-}
-
-/**
- *  igb_validate_nvm_checksum - Verifies NVM (EEPROM) checksum
- *  @hw: pointer to the HW structure
- *
- *  Validates the NVM checksum is correct. This is a function pointer entry
- *  point called by drivers.
- **/
-s32 igb_validate_nvm_checksum(struct e1000_hw *hw)
-{
-	if (hw->nvm.ops.validate)
-		return hw->nvm.ops.validate(hw);
-
-	return -E1000_ERR_CONFIG;
-}
-
-/**
- *  igb_update_nvm_checksum - Updates NVM (EEPROM) checksum
- *  @hw: pointer to the HW structure
- *
- *  Updates the NVM checksum. Currently no func pointer exists and all
- *  implementations are handled in the generic version of this function.
- **/
-s32 igb_update_nvm_checksum(struct e1000_hw *hw)
-{
-	if (hw->nvm.ops.update)
-		return hw->nvm.ops.update(hw);
-
-	return -E1000_ERR_CONFIG;
-}
-
-/**
- *  igb_reload_nvm - Reloads EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
- *  extended control register.
- **/
-void igb_reload_nvm(struct e1000_hw *hw)
-{
-	if (hw->nvm.ops.reload)
-		hw->nvm.ops.reload(hw);
-}
-
-/**
- *  igb_read_nvm - Reads NVM (EEPROM)
- *  @hw: pointer to the HW structure
- *  @offset: the word offset to read
- *  @words: number of 16-bit words to read
- *  @data: pointer to the properly sized buffer for the data.
- *
- *  Reads 16-bit chunks of data from the NVM (EEPROM). This is a function
- *  pointer entry point called by drivers.
- **/
-s32 igb_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	if (hw->nvm.ops.read)
-		return hw->nvm.ops.read(hw, offset, words, data);
-
-	return -E1000_ERR_CONFIG;
-}
-
-/**
- *  igb_write_nvm - Writes to NVM (EEPROM)
- *  @hw: pointer to the HW structure
- *  @offset: the word offset to read
- *  @words: number of 16-bit words to write
- *  @data: pointer to the properly sized buffer for the data.
- *
- *  Writes 16-bit chunks of data to the NVM (EEPROM). This is a function
- *  pointer entry point called by drivers.
- **/
-s32 igb_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	if (hw->nvm.ops.write)
-		return hw->nvm.ops.write(hw, offset, words, data);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_write_8bit_ctrl_reg - Writes 8bit Control register
- *  @hw: pointer to the HW structure
- *  @reg: 32bit register offset
- *  @offset: the register to write
- *  @data: the value to write.
- *
- *  Writes the PHY register at offset with the value in data.
- *  This is a function pointer entry point called by drivers.
- **/
-s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg, u32 offset,
-                              u8 data)
-{
-	return igb_write_8bit_ctrl_reg_generic(hw, reg, offset, data);
-}
-
-/**
- * igb_power_up_phy - Restores link in case of PHY power down
- * @hw: pointer to the HW structure
- *
- * The phy may be powered down to save power, to turn off link when the
- * driver is unloaded, or wake on lan is not enabled (among others).
- **/
-void igb_power_up_phy(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.power_up)
-		hw->phy.ops.power_up(hw);
-
-	igb_setup_link(hw);
-}
-
-/**
- * igb_power_down_phy - Power down PHY
- * @hw: pointer to the HW structure
- *
- * The phy may be powered down to save power, to turn off link when the
- * driver is unloaded, or wake on lan is not enabled (among others).
- **/
-void igb_power_down_phy(struct e1000_hw *hw)
-{
-	if (hw->phy.ops.power_down)
-		hw->phy.ops.power_down(hw);
-}
-
-/**
- *  igb_shutdown_fiber_serdes_link - Remove link during power down
- *  @hw: pointer to the HW structure
- *
- *  Shutdown the optics and PCS on driver unload.
- **/
-void igb_shutdown_fiber_serdes_link(struct e1000_hw *hw)
-{
-	if (hw->mac.ops.shutdown_serdes)
-		hw->mac.ops.shutdown_serdes(hw);
-}
-
diff --git a/roms/ipxe/src/drivers/net/igb/igb_api.h b/roms/ipxe/src/drivers/net/igb/igb_api.h
deleted file mode 100644
index 2d97fecc2e05ebf81d6db28fc1869f9e8be588be..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_api.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#ifndef _IGB_API_H_
-#define _IGB_API_H_
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <ipxe/io.h>
-#include <errno.h>
-#include <byteswap.h>
-#include <ipxe/pci.h>
-#include <ipxe/malloc.h>
-#include <ipxe/if_ether.h>
-#include <ipxe/ethernet.h>
-#include <ipxe/iobuf.h>
-#include <ipxe/netdevice.h>
-
-#include "igb_hw.h"
-
-extern void    igb_init_function_pointers_82575(struct e1000_hw *hw) __attribute__((weak));
-extern void    igb_rx_fifo_flush_82575(struct e1000_hw *hw) __attribute__((weak));
-extern void    igb_init_function_pointers_vf(struct e1000_hw *hw) __attribute__((weak));
-extern void    igb_shutdown_fiber_serdes_link(struct e1000_hw *hw) __attribute__((weak));
-
-s32  igb_set_mac_type(struct e1000_hw *hw);
-s32  igb_setup_init_funcs(struct e1000_hw *hw, bool init_device);
-s32  igb_init_mac_params(struct e1000_hw *hw);
-s32  igb_init_nvm_params(struct e1000_hw *hw);
-s32  igb_init_phy_params(struct e1000_hw *hw);
-s32  igb_init_mbx_params(struct e1000_hw *hw);
-s32  igb_get_bus_info(struct e1000_hw *hw);
-void igb_clear_vfta(struct e1000_hw *hw);
-void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value);
-s32  igb_force_mac_fc(struct e1000_hw *hw);
-s32  igb_check_for_link(struct e1000_hw *hw);
-s32  igb_reset_hw(struct e1000_hw *hw);
-s32  igb_init_hw(struct e1000_hw *hw);
-s32  igb_setup_link(struct e1000_hw *hw);
-s32  igb_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed,
-                                u16 *duplex);
-s32  igb_disable_pcie_master(struct e1000_hw *hw);
-void igb_config_collision_dist(struct e1000_hw *hw);
-void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
-void igb_mta_set(struct e1000_hw *hw, u32 hash_value);
-u32  igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr);
-void igb_update_mc_addr_list(struct e1000_hw *hw,
-                               u8 *mc_addr_list, u32 mc_addr_count);
-s32  igb_setup_led(struct e1000_hw *hw);
-s32  igb_cleanup_led(struct e1000_hw *hw);
-s32  igb_check_reset_block(struct e1000_hw *hw);
-s32  igb_blink_led(struct e1000_hw *hw);
-s32  igb_led_on(struct e1000_hw *hw);
-s32  igb_led_off(struct e1000_hw *hw);
-s32 igb_id_led_init(struct e1000_hw *hw);
-void igb_reset_adaptive(struct e1000_hw *hw);
-void igb_update_adaptive(struct e1000_hw *hw);
-#if 0
-s32  igb_get_cable_length(struct e1000_hw *hw);
-#endif
-s32  igb_validate_mdi_setting(struct e1000_hw *hw);
-s32  igb_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  igb_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data);
-s32  igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg,
-                               u32 offset, u8 data);
-s32  igb_get_phy_info(struct e1000_hw *hw);
-void igb_release_phy(struct e1000_hw *hw);
-s32  igb_acquire_phy(struct e1000_hw *hw);
-s32  igb_phy_hw_reset(struct e1000_hw *hw);
-s32  igb_phy_commit(struct e1000_hw *hw);
-void igb_power_up_phy(struct e1000_hw *hw);
-void igb_power_down_phy(struct e1000_hw *hw);
-s32  igb_read_mac_addr(struct e1000_hw *hw);
-s32  igb_read_pba_num(struct e1000_hw *hw, u32 *part_num);
-void igb_reload_nvm(struct e1000_hw *hw);
-s32  igb_update_nvm_checksum(struct e1000_hw *hw);
-s32  igb_validate_nvm_checksum(struct e1000_hw *hw);
-s32  igb_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
-s32  igb_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  igb_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
-s32  igb_write_nvm(struct e1000_hw *hw, u16 offset, u16 words,
-                     u16 *data);
-s32  igb_wait_autoneg(struct e1000_hw *hw);
-s32  igb_set_d3_lplu_state(struct e1000_hw *hw, bool active);
-s32  igb_set_d0_lplu_state(struct e1000_hw *hw, bool active);
-bool igb_check_mng_mode(struct e1000_hw *hw);
-bool igb_enable_tx_pkt_filtering(struct e1000_hw *hw);
-s32  igb_mng_enable_host_if(struct e1000_hw *hw);
-s32  igb_mng_host_if_write(struct e1000_hw *hw,
-                             u8 *buffer, u16 length, u16 offset, u8 *sum);
-s32  igb_mng_write_cmd_header(struct e1000_hw *hw,
-                                struct e1000_host_mng_command_header *hdr);
-s32  igb_mng_write_dhcp_info(struct e1000_hw * hw,
-                                    u8 *buffer, u16 length);
-
-/*
- * TBI_ACCEPT macro definition:
- *
- * This macro requires:
- *      adapter = a pointer to struct e1000_hw
- *      status = the 8 bit status field of the Rx descriptor with EOP set
- *      error = the 8 bit error field of the Rx descriptor with EOP set
- *      length = the sum of all the length fields of the Rx descriptors that
- *               make up the current frame
- *      last_byte = the last byte of the frame DMAed by the hardware
- *      max_frame_length = the maximum frame length we want to accept.
- *      min_frame_length = the minimum frame length we want to accept.
- *
- * This macro is a conditional that should be used in the interrupt
- * handler's Rx processing routine when RxErrors have been detected.
- *
- * Typical use:
- *  ...
- *  if (TBI_ACCEPT) {
- *      accept_frame = true;
- *      e1000_tbi_adjust_stats(adapter, MacAddress);
- *      frame_length--;
- *  } else {
- *      accept_frame = false;
- *  }
- *  ...
- */
-
-/* The carrier extension symbol, as received by the NIC. */
-#define CARRIER_EXTENSION   0x0F
-
-#define TBI_ACCEPT(a, status, errors, length, last_byte, min_frame_size, max_frame_size) \
-    (e1000_tbi_sbp_enabled_82543(a) && \
-     (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \
-     ((last_byte) == CARRIER_EXTENSION) && \
-     (((status) & E1000_RXD_STAT_VP) ? \
-          (((length) > (min_frame_size - VLAN_TAG_SIZE)) && \
-           ((length) <= (max_frame_size + 1))) : \
-          (((length) > min_frame_size) && \
-           ((length) <= (max_frame_size + VLAN_TAG_SIZE + 1)))))
-
-#endif /* _IGB_API_H_ */
diff --git a/roms/ipxe/src/drivers/net/igb/igb_defines.h b/roms/ipxe/src/drivers/net/igb/igb_defines.h
deleted file mode 100644
index 4f58ba83d4fb6536367bb1ee884c9eaaf25774da..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_defines.h
+++ /dev/null
@@ -1,1515 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#ifndef _IGB_DEFINES_H_
-#define _IGB_DEFINES_H_
-
-/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
-#define REQ_TX_DESCRIPTOR_MULTIPLE  8
-#define REQ_RX_DESCRIPTOR_MULTIPLE  8
-
-/* Definitions for power management and wakeup registers */
-/* Wake Up Control */
-#define E1000_WUC_APME       0x00000001 /* APM Enable */
-#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
-#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
-#define E1000_WUC_APMPME     0x00000008 /* Assert PME on APM Wakeup */
-#define E1000_WUC_LSCWE      0x00000010 /* Link Status wake up enable */
-#define E1000_WUC_LSCWO      0x00000020 /* Link Status wake up override */
-#define E1000_WUC_SPM        0x80000000 /* Enable SPM */
-#define E1000_WUC_PHY_WAKE   0x00000100 /* if PHY supports wakeup */
-
-/* Wake Up Filter Control */
-#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
-#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
-#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
-#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
-#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
-#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
-#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
-#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
-#define E1000_WUFC_IGNORE_TCO   0x00008000 /* Ignore WakeOn TCO packets */
-#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
-#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
-#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
-#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
-#define E1000_WUFC_FLX4 0x00100000 /* Flexible Filter 4 Enable */
-#define E1000_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */
-#define E1000_WUFC_ALL_FILTERS  0x000F00FF /* Mask for all wakeup filters */
-#define E1000_WUFC_FLX_OFFSET   16 /* Offset to the Flexible Filters bits */
-#define E1000_WUFC_FLX_FILTERS  0x000F0000 /*Mask for the 4 flexible filters */
-/*
- * For 82576 to utilize Extended filter masks in addition to
- * existing (filter) masks
- */
-#define E1000_WUFC_EXT_FLX_FILTERS      0x00300000 /* Ext. FLX filter mask */
-
-/* Wake Up Status */
-#define E1000_WUS_LNKC         E1000_WUFC_LNKC
-#define E1000_WUS_MAG          E1000_WUFC_MAG
-#define E1000_WUS_EX           E1000_WUFC_EX
-#define E1000_WUS_MC           E1000_WUFC_MC
-#define E1000_WUS_BC           E1000_WUFC_BC
-#define E1000_WUS_ARP          E1000_WUFC_ARP
-#define E1000_WUS_IPV4         E1000_WUFC_IPV4
-#define E1000_WUS_IPV6         E1000_WUFC_IPV6
-#define E1000_WUS_FLX0         E1000_WUFC_FLX0
-#define E1000_WUS_FLX1         E1000_WUFC_FLX1
-#define E1000_WUS_FLX2         E1000_WUFC_FLX2
-#define E1000_WUS_FLX3         E1000_WUFC_FLX3
-#define E1000_WUS_FLX_FILTERS  E1000_WUFC_FLX_FILTERS
-
-/* Wake Up Packet Length */
-#define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
-
-/* Four Flexible Filters are supported */
-#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
-/* Two Extended Flexible Filters are supported (82576) */
-#define E1000_EXT_FLEXIBLE_FILTER_COUNT_MAX     2
-#define E1000_FHFT_LENGTH_OFFSET        0xFC /* Length byte in FHFT */
-#define E1000_FHFT_LENGTH_MASK          0x0FF /* Length in lower byte */
-
-/* Each Flexible Filter is at most 128 (0x80) bytes in length */
-#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
-
-#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
-#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
-#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
-
-/* Extended Device Control */
-#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */
-#define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
-#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
-#define E1000_CTRL_EXT_GPI2_EN   0x00000004 /* Maps SDP6 to GPI2 */
-#define E1000_CTRL_EXT_GPI3_EN   0x00000008 /* Maps SDP7 to GPI3 */
-/* Reserved (bits 4,5) in >= 82575 */
-#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Definable Pin 4 */
-#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */
-#define E1000_CTRL_EXT_PHY_INT   E1000_CTRL_EXT_SDP5_DATA
-#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */
-#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */
-/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */
-#define E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
-#define E1000_CTRL_EXT_SDP5_DIR  0x00000200 /* Direction of SDP5 0=in 1=out */
-#define E1000_CTRL_EXT_SDP6_DIR  0x00000400 /* Direction of SDP6 0=in 1=out */
-#define E1000_CTRL_EXT_SDP3_DIR  0x00000800 /* Direction of SDP3 0=in 1=out */
-#define E1000_CTRL_EXT_ASDCHK    0x00001000 /* Initiate an ASD sequence */
-#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
-#define E1000_CTRL_EXT_IPS       0x00004000 /* Invert Power State */
-/* Physical Func Reset Done Indication */
-#define E1000_CTRL_EXT_PFRSTD    0x00004000
-#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
-#define E1000_CTRL_EXT_RO_DIS    0x00020000 /* Relaxed Ordering disable */
-#define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 /* DMA Dynamic Clock Gating */
-#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
-#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
-#define E1000_CTRL_EXT_LINK_MODE_TBI  0x00C00000
-#define E1000_CTRL_EXT_LINK_MODE_KMRN    0x00000000
-#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
-#define E1000_CTRL_EXT_LINK_MODE_PCIX_SERDES  0x00800000
-#define E1000_CTRL_EXT_LINK_MODE_SGMII   0x00800000
-#define E1000_CTRL_EXT_EIAME          0x01000000
-#define E1000_CTRL_EXT_IRCA           0x00000001
-#define E1000_CTRL_EXT_WR_WMARK_MASK  0x03000000
-#define E1000_CTRL_EXT_WR_WMARK_256   0x00000000
-#define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
-#define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
-#define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
-#define E1000_CTRL_EXT_CANC           0x04000000 /* Int delay cancellation */
-#define E1000_CTRL_EXT_DRV_LOAD       0x10000000 /* Driver loaded bit for FW */
-/* IAME enable bit (27) was removed in >= 82575 */
-#define E1000_CTRL_EXT_IAME          0x08000000 /* Int acknowledge Auto-mask */
-#define E1000_CRTL_EXT_PB_PAREN       0x01000000 /* packet buffer parity error
-                                                  * detection enabled */
-#define E1000_CTRL_EXT_DF_PAREN       0x02000000 /* descriptor FIFO parity
-                                                  * error detection enable */
-#define E1000_CTRL_EXT_GHOST_PAREN    0x40000000
-#define E1000_CTRL_EXT_PBA_CLR        0x80000000 /* PBA Clear */
-#define E1000_I2CCMD_REG_ADDR_SHIFT   16
-#define E1000_I2CCMD_REG_ADDR         0x00FF0000
-#define E1000_I2CCMD_PHY_ADDR_SHIFT   24
-#define E1000_I2CCMD_PHY_ADDR         0x07000000
-#define E1000_I2CCMD_OPCODE_READ      0x08000000
-#define E1000_I2CCMD_OPCODE_WRITE     0x00000000
-#define E1000_I2CCMD_RESET            0x10000000
-#define E1000_I2CCMD_READY            0x20000000
-#define E1000_I2CCMD_INTERRUPT_ENA    0x40000000
-#define E1000_I2CCMD_ERROR            0x80000000
-#define E1000_MAX_SGMII_PHY_REG_ADDR  255
-#define E1000_I2CCMD_PHY_TIMEOUT      200
-#define E1000_IVAR_VALID        0x80
-#define E1000_GPIE_NSICR        0x00000001
-#define E1000_GPIE_MSIX_MODE    0x00000010
-#define E1000_GPIE_EIAME        0x40000000
-#define E1000_GPIE_PBA          0x80000000
-
-/* Receive Descriptor bit definitions */
-#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
-#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
-#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
-#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
-#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum calculated */
-#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
-#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
-#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
-#define E1000_RXD_STAT_CRCV     0x100   /* Speculative CRC Valid */
-#define E1000_RXD_STAT_IPIDV    0x200   /* IP identification valid */
-#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
-#define E1000_RXD_STAT_DYNINT   0x800   /* Pkt caused INT via DYNINT */
-#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
-#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
-#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
-#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
-#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
-#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
-#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
-#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
-#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
-#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
-#define E1000_RXD_SPC_PRI_SHIFT 13
-#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
-#define E1000_RXD_SPC_CFI_SHIFT 12
-
-#define E1000_RXDEXT_STATERR_CE    0x01000000
-#define E1000_RXDEXT_STATERR_SE    0x02000000
-#define E1000_RXDEXT_STATERR_SEQ   0x04000000
-#define E1000_RXDEXT_STATERR_CXE   0x10000000
-#define E1000_RXDEXT_STATERR_TCPE  0x20000000
-#define E1000_RXDEXT_STATERR_IPE   0x40000000
-#define E1000_RXDEXT_STATERR_RXE   0x80000000
-
-/* mask to determine if packets should be dropped due to frame errors */
-#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
-    E1000_RXD_ERR_CE  |                \
-    E1000_RXD_ERR_SE  |                \
-    E1000_RXD_ERR_SEQ |                \
-    E1000_RXD_ERR_CXE |                \
-    E1000_RXD_ERR_RXE)
-
-/* Same mask, but for extended and packet split descriptors */
-#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
-    E1000_RXDEXT_STATERR_CE  |            \
-    E1000_RXDEXT_STATERR_SE  |            \
-    E1000_RXDEXT_STATERR_SEQ |            \
-    E1000_RXDEXT_STATERR_CXE |            \
-    E1000_RXDEXT_STATERR_RXE)
-
-#define E1000_MRQC_ENABLE_MASK                 0x00000007
-#define E1000_MRQC_ENABLE_RSS_2Q               0x00000001
-#define E1000_MRQC_ENABLE_RSS_INT              0x00000004
-#define E1000_MRQC_RSS_FIELD_MASK              0xFFFF0000
-#define E1000_MRQC_RSS_FIELD_IPV4_TCP          0x00010000
-#define E1000_MRQC_RSS_FIELD_IPV4              0x00020000
-#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX       0x00040000
-#define E1000_MRQC_RSS_FIELD_IPV6_EX           0x00080000
-#define E1000_MRQC_RSS_FIELD_IPV6              0x00100000
-#define E1000_MRQC_RSS_FIELD_IPV6_TCP          0x00200000
-
-#define E1000_RXDPS_HDRSTAT_HDRSP              0x00008000
-#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK        0x000003FF
-
-/* Management Control */
-#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
-#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
-#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
-#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
-#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
-#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
-#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
-#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
-#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
-/* Enable Neighbor Discovery Filtering */
-#define E1000_MANC_NEIGHBOR_EN   0x00004000
-#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response Filtering */
-#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
-#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
-#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
-#define E1000_MANC_RCV_ALL       0x00080000 /* Receive All Enabled */
-#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
-/* Enable MAC address filtering */
-#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000
-/* Enable MNG packets to host memory */
-#define E1000_MANC_EN_MNG2HOST   0x00200000
-/* Enable IP address filtering */
-#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000
-#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
-#define E1000_MANC_BR_EN            0x01000000 /* Enable broadcast filtering */
-#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
-#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
-#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
-#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
-#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
-#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
-
-#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
-#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
-
-/* Receive Control */
-#define E1000_RCTL_RST            0x00000001    /* Software reset */
-#define E1000_RCTL_EN             0x00000002    /* enable */
-#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
-#define E1000_RCTL_UPE            0x00000008    /* unicast promisc enable */
-#define E1000_RCTL_MPE            0x00000010    /* multicast promisc enable */
-#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
-#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
-#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
-#define E1000_RCTL_LBM_SLP        0x00000080    /* serial link loopback mode */
-#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
-#define E1000_RCTL_DTYP_MASK      0x00000C00    /* Descriptor type mask */
-#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
-#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min thresh size */
-#define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min thresh size */
-#define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min thresh size */
-#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
-#define E1000_RCTL_MO_0           0x00000000    /* multicast offset 11:0 */
-#define E1000_RCTL_MO_1           0x00001000    /* multicast offset 12:1 */
-#define E1000_RCTL_MO_2           0x00002000    /* multicast offset 13:2 */
-#define E1000_RCTL_MO_3           0x00003000    /* multicast offset 15:4 */
-#define E1000_RCTL_MDR            0x00004000    /* multicast desc ring 0 */
-#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
-#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
-#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
-#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
-#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
-#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
-#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
-#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
-#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
-#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
-#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
-#define E1000_RCTL_DPF            0x00400000    /* discard pause frames */
-#define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
-#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
-#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
-#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
-#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
-
-/*
- * Use byte values for the following shift parameters
- * Usage:
- *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
- *                  E1000_PSRCTL_BSIZE0_MASK) |
- *                ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
- *                  E1000_PSRCTL_BSIZE1_MASK) |
- *                ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
- *                  E1000_PSRCTL_BSIZE2_MASK) |
- *                ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
- *                  E1000_PSRCTL_BSIZE3_MASK))
- * where value0 = [128..16256],  default=256
- *       value1 = [1024..64512], default=4096
- *       value2 = [0..64512],    default=4096
- *       value3 = [0..64512],    default=0
- */
-
-#define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
-#define E1000_PSRCTL_BSIZE1_MASK   0x00003F00
-#define E1000_PSRCTL_BSIZE2_MASK   0x003F0000
-#define E1000_PSRCTL_BSIZE3_MASK   0x3F000000
-
-#define E1000_PSRCTL_BSIZE0_SHIFT  7            /* Shift _right_ 7 */
-#define E1000_PSRCTL_BSIZE1_SHIFT  2            /* Shift _right_ 2 */
-#define E1000_PSRCTL_BSIZE2_SHIFT  6            /* Shift _left_ 6 */
-#define E1000_PSRCTL_BSIZE3_SHIFT 14            /* Shift _left_ 14 */
-
-/* SWFW_SYNC Definitions */
-#define E1000_SWFW_EEP_SM   0x01
-#define E1000_SWFW_PHY0_SM  0x02
-#define E1000_SWFW_PHY1_SM  0x04
-#define E1000_SWFW_CSR_SM   0x08
-
-/* FACTPS Definitions */
-#define E1000_FACTPS_LFS    0x40000000  /* LAN Function Select */
-/* Device Control */
-#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
-#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
-#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
-#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master reqs */
-#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
-#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
-#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
-#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
-#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
-#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
-#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
-#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
-#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
-#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
-#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
-#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
-#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
-#define E1000_CTRL_D_UD_EN  0x00002000  /* Dock/Undock enable */
-#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock
-                                             * indication in SDP[0] */
-#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through
-                                               * PHYRST_N pin */
-#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external
-                                           * LINK_0 and LINK_1 pins */
-#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
-#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
-#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
-#define E1000_CTRL_ADVD3WUC 0x00100000  /* D3 WUC */
-#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
-#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
-#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
-#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
-#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
-#define E1000_CTRL_RST      0x04000000  /* Global reset */
-#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
-#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
-#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
-#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
-#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
-#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to ME */
-#define E1000_CTRL_I2C_ENA  0x02000000  /* I2C enable */
-
-/*
- * Bit definitions for the Management Data IO (MDIO) and Management Data
- * Clock (MDC) pins in the Device Control Register.
- */
-#define E1000_CTRL_PHY_RESET_DIR  E1000_CTRL_SWDPIO0
-#define E1000_CTRL_PHY_RESET      E1000_CTRL_SWDPIN0
-#define E1000_CTRL_MDIO_DIR       E1000_CTRL_SWDPIO2
-#define E1000_CTRL_MDIO           E1000_CTRL_SWDPIN2
-#define E1000_CTRL_MDC_DIR        E1000_CTRL_SWDPIO3
-#define E1000_CTRL_MDC            E1000_CTRL_SWDPIN3
-#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
-#define E1000_CTRL_PHY_RESET4     E1000_CTRL_EXT_SDP4_DATA
-
-#define E1000_CONNSW_ENRGSRC             0x4
-#define E1000_PCS_CFG_PCS_EN             8
-#define E1000_PCS_LCTL_FLV_LINK_UP       1
-#define E1000_PCS_LCTL_FSV_10            0
-#define E1000_PCS_LCTL_FSV_100           2
-#define E1000_PCS_LCTL_FSV_1000          4
-#define E1000_PCS_LCTL_FDV_FULL          8
-#define E1000_PCS_LCTL_FSD               0x10
-#define E1000_PCS_LCTL_FORCE_LINK        0x20
-#define E1000_PCS_LCTL_LOW_LINK_LATCH    0x40
-#define E1000_PCS_LCTL_FORCE_FCTRL       0x80
-#define E1000_PCS_LCTL_AN_ENABLE         0x10000
-#define E1000_PCS_LCTL_AN_RESTART        0x20000
-#define E1000_PCS_LCTL_AN_TIMEOUT        0x40000
-#define E1000_PCS_LCTL_AN_SGMII_BYPASS   0x80000
-#define E1000_PCS_LCTL_AN_SGMII_TRIGGER  0x100000
-#define E1000_PCS_LCTL_FAST_LINK_TIMER   0x1000000
-#define E1000_PCS_LCTL_LINK_OK_FIX       0x2000000
-#define E1000_PCS_LCTL_CRS_ON_NI         0x4000000
-#define E1000_ENABLE_SERDES_LOOPBACK     0x0410
-
-#define E1000_PCS_LSTS_LINK_OK           1
-#define E1000_PCS_LSTS_SPEED_10          0
-#define E1000_PCS_LSTS_SPEED_100         2
-#define E1000_PCS_LSTS_SPEED_1000        4
-#define E1000_PCS_LSTS_DUPLEX_FULL       8
-#define E1000_PCS_LSTS_SYNK_OK           0x10
-#define E1000_PCS_LSTS_AN_COMPLETE       0x10000
-#define E1000_PCS_LSTS_AN_PAGE_RX        0x20000
-#define E1000_PCS_LSTS_AN_TIMED_OUT      0x40000
-#define E1000_PCS_LSTS_AN_REMOTE_FAULT   0x80000
-#define E1000_PCS_LSTS_AN_ERROR_RWS      0x100000
-
-/* Device Status */
-#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
-#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
-#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
-#define E1000_STATUS_FUNC_SHIFT 2
-#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
-#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
-#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
-#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
-#define E1000_STATUS_SPEED_MASK 0x000000C0
-#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
-#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
-#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
-#define E1000_STATUS_LAN_INIT_DONE 0x00000200  /* Lan Init Completion by NVM */
-#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
-#define E1000_STATUS_PHYRA      0x00000400      /* PHY Reset Asserted */
-#define E1000_STATUS_DOCK_CI    0x00000800      /* Change in Dock/Undock state.
-                                                 * Clear on write '0'. */
-#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Master request status */
-#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
-#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
-#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
-#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
-#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
-#define E1000_STATUS_BMC_SKU_0  0x00100000 /* BMC USB redirect disabled */
-#define E1000_STATUS_BMC_SKU_1  0x00200000 /* BMC SRAM disabled */
-#define E1000_STATUS_BMC_SKU_2  0x00400000 /* BMC SDRAM disabled */
-#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
-#define E1000_STATUS_BMC_LITE   0x01000000 /* BMC external code execution
-                                            * disabled */
-#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */
-#define E1000_STATUS_FUSE_8       0x04000000
-#define E1000_STATUS_FUSE_9       0x08000000
-#define E1000_STATUS_SERDES0_DIS  0x10000000 /* SERDES disabled on port 0 */
-#define E1000_STATUS_SERDES1_DIS  0x20000000 /* SERDES disabled on port 1 */
-
-/* Constants used to interpret the masked PCI-X bus speed. */
-#define E1000_STATUS_PCIX_SPEED_66  0x00000000 /* PCI-X bus speed 50-66 MHz */
-#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */
-#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /*PCI-X bus speed 100-133 MHz*/
-
-#define SPEED_10    10
-#define SPEED_100   100
-#define SPEED_1000  1000
-#define HALF_DUPLEX 1
-#define FULL_DUPLEX 2
-
-#define PHY_FORCE_TIME   20
-
-#define ADVERTISE_10_HALF                 0x0001
-#define ADVERTISE_10_FULL                 0x0002
-#define ADVERTISE_100_HALF                0x0004
-#define ADVERTISE_100_FULL                0x0008
-#define ADVERTISE_1000_HALF               0x0010 /* Not used, just FYI */
-#define ADVERTISE_1000_FULL               0x0020
-
-/* 1000/H is not supported, nor spec-compliant. */
-#define E1000_ALL_SPEED_DUPLEX  (ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
-                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL | \
-                                                     ADVERTISE_1000_FULL)
-#define E1000_ALL_NOT_GIG       (ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
-                                ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
-#define E1000_ALL_100_SPEED    (ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
-#define E1000_ALL_10_SPEED      (ADVERTISE_10_HALF |   ADVERTISE_10_FULL)
-#define E1000_ALL_FULL_DUPLEX   (ADVERTISE_10_FULL |  ADVERTISE_100_FULL | \
-                                                     ADVERTISE_1000_FULL)
-#define E1000_ALL_HALF_DUPLEX   (ADVERTISE_10_HALF |  ADVERTISE_100_HALF)
-
-#define AUTONEG_ADVERTISE_SPEED_DEFAULT   E1000_ALL_SPEED_DUPLEX
-
-/* LED Control */
-#define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
-#define E1000_LEDCTL_LED0_MODE_SHIFT      0
-#define E1000_LEDCTL_LED0_BLINK_RATE      0x00000020
-#define E1000_LEDCTL_LED0_IVRT            0x00000040
-#define E1000_LEDCTL_LED0_BLINK           0x00000080
-#define E1000_LEDCTL_LED1_MODE_MASK       0x00000F00
-#define E1000_LEDCTL_LED1_MODE_SHIFT      8
-#define E1000_LEDCTL_LED1_BLINK_RATE      0x00002000
-#define E1000_LEDCTL_LED1_IVRT            0x00004000
-#define E1000_LEDCTL_LED1_BLINK           0x00008000
-#define E1000_LEDCTL_LED2_MODE_MASK       0x000F0000
-#define E1000_LEDCTL_LED2_MODE_SHIFT      16
-#define E1000_LEDCTL_LED2_BLINK_RATE      0x00200000
-#define E1000_LEDCTL_LED2_IVRT            0x00400000
-#define E1000_LEDCTL_LED2_BLINK           0x00800000
-#define E1000_LEDCTL_LED3_MODE_MASK       0x0F000000
-#define E1000_LEDCTL_LED3_MODE_SHIFT      24
-#define E1000_LEDCTL_LED3_BLINK_RATE      0x20000000
-#define E1000_LEDCTL_LED3_IVRT            0x40000000
-#define E1000_LEDCTL_LED3_BLINK           0x80000000
-
-#define E1000_LEDCTL_MODE_LINK_10_1000  0x0
-#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
-#define E1000_LEDCTL_MODE_LINK_UP       0x2
-#define E1000_LEDCTL_MODE_ACTIVITY      0x3
-#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
-#define E1000_LEDCTL_MODE_LINK_10       0x5
-#define E1000_LEDCTL_MODE_LINK_100      0x6
-#define E1000_LEDCTL_MODE_LINK_1000     0x7
-#define E1000_LEDCTL_MODE_PCIX_MODE     0x8
-#define E1000_LEDCTL_MODE_FULL_DUPLEX   0x9
-#define E1000_LEDCTL_MODE_COLLISION     0xA
-#define E1000_LEDCTL_MODE_BUS_SPEED     0xB
-#define E1000_LEDCTL_MODE_BUS_SIZE      0xC
-#define E1000_LEDCTL_MODE_PAUSED        0xD
-#define E1000_LEDCTL_MODE_LED_ON        0xE
-#define E1000_LEDCTL_MODE_LED_OFF       0xF
-
-/* Transmit Descriptor bit definitions */
-#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
-#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
-#define E1000_TXD_POPTS_SHIFT 8         /* POPTS shift */
-#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
-#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
-#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
-#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
-#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
-#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
-#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
-#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
-#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
-#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
-#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
-#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
-#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
-#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
-#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
-#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
-#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
-#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
-/* Extended desc bits for Linksec and timesync */
-
-/* Transmit Control */
-#define E1000_TCTL_RST    0x00000001    /* software reset */
-#define E1000_TCTL_EN     0x00000002    /* enable tx */
-#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
-#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
-#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
-#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
-#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
-#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
-#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
-#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
-#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
-
-/* Transmit Arbitration Count */
-#define E1000_TARC0_ENABLE     0x00000400   /* Enable Tx Queue 0 */
-
-/* SerDes Control */
-#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
-
-/* Receive Checksum Control */
-#define E1000_RXCSUM_PCSS_MASK 0x000000FF   /* Packet Checksum Start */
-#define E1000_RXCSUM_IPOFL     0x00000100   /* IPv4 checksum offload */
-#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
-#define E1000_RXCSUM_IPV6OFL   0x00000400   /* IPv6 checksum offload */
-#define E1000_RXCSUM_CRCOFL    0x00000800   /* CRC32 offload enable */
-#define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
-#define E1000_RXCSUM_PCSD      0x00002000   /* packet checksum disabled */
-
-/* Header split receive */
-#define E1000_RFCTL_ISCSI_DIS           0x00000001
-#define E1000_RFCTL_ISCSI_DWC_MASK      0x0000003E
-#define E1000_RFCTL_ISCSI_DWC_SHIFT     1
-#define E1000_RFCTL_NFSW_DIS            0x00000040
-#define E1000_RFCTL_NFSR_DIS            0x00000080
-#define E1000_RFCTL_NFS_VER_MASK        0x00000300
-#define E1000_RFCTL_NFS_VER_SHIFT       8
-#define E1000_RFCTL_IPV6_DIS            0x00000400
-#define E1000_RFCTL_IPV6_XSUM_DIS       0x00000800
-#define E1000_RFCTL_ACK_DIS             0x00001000
-#define E1000_RFCTL_ACKD_DIS            0x00002000
-#define E1000_RFCTL_IPFRSP_DIS          0x00004000
-#define E1000_RFCTL_EXTEN               0x00008000
-#define E1000_RFCTL_IPV6_EX_DIS         0x00010000
-#define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
-#define E1000_RFCTL_LEF                 0x00040000
-
-/* Collision related configuration parameters */
-#define E1000_COLLISION_THRESHOLD       15
-#define E1000_CT_SHIFT                  4
-#define E1000_COLLISION_DISTANCE        63
-#define E1000_COLD_SHIFT                12
-
-/* Default values for the transmit IPG register */
-#define DEFAULT_82543_TIPG_IPGT_FIBER  9
-#define DEFAULT_82543_TIPG_IPGT_COPPER 8
-
-#define E1000_TIPG_IPGT_MASK  0x000003FF
-#define E1000_TIPG_IPGR1_MASK 0x000FFC00
-#define E1000_TIPG_IPGR2_MASK 0x3FF00000
-
-#define DEFAULT_82543_TIPG_IPGR1 8
-#define E1000_TIPG_IPGR1_SHIFT  10
-
-#define DEFAULT_82543_TIPG_IPGR2 6
-#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
-#define E1000_TIPG_IPGR2_SHIFT  20
-
-/* Ethertype field values */
-#define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
-
-#define ETHERNET_FCS_SIZE       4
-#define MAX_JUMBO_FRAME_SIZE    0x3F00
-
-/* Extended Configuration Control and Size */
-#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP      0x00000020
-#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE       0x00000001
-#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE       0x00000008
-#define E1000_EXTCNF_CTRL_SWFLAG                 0x00000020
-#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK   0x00FF0000
-#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT          16
-#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK   0x0FFF0000
-#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT          16
-
-#define E1000_PHY_CTRL_SPD_EN             0x00000001
-#define E1000_PHY_CTRL_D0A_LPLU           0x00000002
-#define E1000_PHY_CTRL_NOND0A_LPLU        0x00000004
-#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
-#define E1000_PHY_CTRL_GBE_DISABLE        0x00000040
-
-#define E1000_KABGTXD_BGSQLBIAS           0x00050000
-
-/* PBA constants */
-#define E1000_PBA_6K  0x0006    /* 6KB */
-#define E1000_PBA_8K  0x0008    /* 8KB */
-#define E1000_PBA_10K 0x000A    /* 10KB */
-#define E1000_PBA_12K 0x000C    /* 12KB */
-#define E1000_PBA_14K 0x000E    /* 14KB */
-#define E1000_PBA_16K 0x0010    /* 16KB */
-#define E1000_PBA_18K 0x0012
-#define E1000_PBA_20K 0x0014
-#define E1000_PBA_22K 0x0016
-#define E1000_PBA_24K 0x0018
-#define E1000_PBA_26K 0x001A
-#define E1000_PBA_30K 0x001E
-#define E1000_PBA_32K 0x0020
-#define E1000_PBA_34K 0x0022
-#define E1000_PBA_35K 0x0023
-#define E1000_PBA_38K 0x0026
-#define E1000_PBA_40K 0x0028
-#define E1000_PBA_48K 0x0030    /* 48KB */
-#define E1000_PBA_64K 0x0040    /* 64KB */
-
-#define E1000_PBS_16K E1000_PBA_16K
-#define E1000_PBS_24K E1000_PBA_24K
-
-#define IFS_MAX       80
-#define IFS_MIN       40
-#define IFS_RATIO     4
-#define IFS_STEP      10
-#define MIN_NUM_XMITS 1000
-
-/* SW Semaphore Register */
-#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
-#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
-#define E1000_SWSM_WMNG         0x00000004 /* Wake MNG Clock */
-#define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
-
-#define E1000_SWSM2_LOCK        0x00000002 /* Secondary driver semaphore bit */
-
-/* Interrupt Cause Read */
-#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
-#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
-#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
-#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
-#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
-#define E1000_ICR_RXO           0x00000040 /* rx overrun */
-#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
-#define E1000_ICR_VMMB          0x00000100 /* VM MB event */
-#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
-#define E1000_ICR_RXCFG         0x00000400 /* Rx /c/ ordered set */
-#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
-#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
-#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
-#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
-#define E1000_ICR_TXD_LOW       0x00008000
-#define E1000_ICR_SRPD          0x00010000
-#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
-#define E1000_ICR_MNG           0x00040000 /* Manageability event */
-#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
-#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver
-                                            * should claim the interrupt */
-#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* Q0 Rx desc FIFO parity error */
-#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* Q0 Tx desc FIFO parity error */
-#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity err */
-#define E1000_ICR_PB_PAR        0x00800000 /* packet buffer parity error */
-#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* Q1 Rx desc FIFO parity error */
-#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* Q1 Tx desc FIFO parity error */
-#define E1000_ICR_ALL_PARITY    0x03F00000 /* all parity error bits */
-#define E1000_ICR_DSW           0x00000020 /* FW changed the status of DISSW
-                                            * bit in the FWSM */
-#define E1000_ICR_PHYINT        0x00001000 /* LAN connected device generates
-                                            * an interrupt */
-#define E1000_ICR_DOUTSYNC      0x10000000 /* NIC DMA out of sync */
-#define E1000_ICR_EPRST         0x00100000 /* ME hardware reset occurs */
-
-
-/* Extended Interrupt Cause Read */
-#define E1000_EICR_RX_QUEUE0    0x00000001 /* Rx Queue 0 Interrupt */
-#define E1000_EICR_RX_QUEUE1    0x00000002 /* Rx Queue 1 Interrupt */
-#define E1000_EICR_RX_QUEUE2    0x00000004 /* Rx Queue 2 Interrupt */
-#define E1000_EICR_RX_QUEUE3    0x00000008 /* Rx Queue 3 Interrupt */
-#define E1000_EICR_TX_QUEUE0    0x00000100 /* Tx Queue 0 Interrupt */
-#define E1000_EICR_TX_QUEUE1    0x00000200 /* Tx Queue 1 Interrupt */
-#define E1000_EICR_TX_QUEUE2    0x00000400 /* Tx Queue 2 Interrupt */
-#define E1000_EICR_TX_QUEUE3    0x00000800 /* Tx Queue 3 Interrupt */
-#define E1000_EICR_TCP_TIMER    0x40000000 /* TCP Timer */
-#define E1000_EICR_OTHER        0x80000000 /* Interrupt Cause Active */
-/* TCP Timer */
-#define E1000_TCPTIMER_KS       0x00000100 /* KickStart */
-#define E1000_TCPTIMER_COUNT_ENABLE       0x00000200 /* Count Enable */
-#define E1000_TCPTIMER_COUNT_FINISH       0x00000400 /* Count finish */
-#define E1000_TCPTIMER_LOOP     0x00000800 /* Loop */
-
-/*
- * This defines the bits that are set in the Interrupt Mask
- * Set/Read Register.  Each bit is documented below:
- *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
- *   o RXSEQ  = Receive Sequence Error
- */
-#define POLL_IMS_ENABLE_MASK ( \
-    E1000_IMS_RXDMT0 |    \
-    E1000_IMS_RXSEQ)
-
-/*
- * This defines the bits that are set in the Interrupt Mask
- * Set/Read Register.  Each bit is documented below:
- *   o RXT0   = Receiver Timer Interrupt (ring 0)
- *   o TXDW   = Transmit Descriptor Written Back
- *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
- *   o RXSEQ  = Receive Sequence Error
- *   o LSC    = Link Status Change
- */
-#define IMS_ENABLE_MASK ( \
-    E1000_IMS_RXT0   |    \
-    E1000_IMS_TXDW   |    \
-    E1000_IMS_RXDMT0 |    \
-    E1000_IMS_RXSEQ  |    \
-    E1000_IMS_LSC)
-
-/* Interrupt Mask Set */
-#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Tx desc written back */
-#define E1000_IMS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
-#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
-#define E1000_IMS_VMMB      E1000_ICR_VMMB      /* Mail box activity */
-#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
-#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
-#define E1000_IMS_RXO       E1000_ICR_RXO       /* rx overrun */
-#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
-#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
-#define E1000_IMS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
-#define E1000_IMS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
-#define E1000_IMS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
-#define E1000_IMS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
-#define E1000_IMS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
-#define E1000_IMS_TXD_LOW   E1000_ICR_TXD_LOW
-#define E1000_IMS_SRPD      E1000_ICR_SRPD
-#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
-#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
-#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
-#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
-                                                         * parity error */
-#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
-                                                         * parity error */
-#define E1000_IMS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer
-                                                         * parity error */
-#define E1000_IMS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity
-                                                         * error */
-#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
-                                                         * parity error */
-#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
-                                                         * parity error */
-#define E1000_IMS_DSW       E1000_ICR_DSW
-#define E1000_IMS_PHYINT    E1000_ICR_PHYINT
-#define E1000_IMS_DOUTSYNC  E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
-#define E1000_IMS_EPRST     E1000_ICR_EPRST
-
-/* Extended Interrupt Mask Set */
-#define E1000_EIMS_RX_QUEUE0    E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */
-#define E1000_EIMS_RX_QUEUE1    E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */
-#define E1000_EIMS_RX_QUEUE2    E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */
-#define E1000_EIMS_RX_QUEUE3    E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */
-#define E1000_EIMS_TX_QUEUE0    E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */
-#define E1000_EIMS_TX_QUEUE1    E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */
-#define E1000_EIMS_TX_QUEUE2    E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */
-#define E1000_EIMS_TX_QUEUE3    E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */
-#define E1000_EIMS_TCP_TIMER    E1000_EICR_TCP_TIMER /* TCP Timer */
-#define E1000_EIMS_OTHER        E1000_EICR_OTHER   /* Interrupt Cause Active */
-
-/* Interrupt Cause Set */
-#define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Tx desc written back */
-#define E1000_ICS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
-#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
-#define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
-#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
-#define E1000_ICS_RXO       E1000_ICR_RXO       /* rx overrun */
-#define E1000_ICS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
-#define E1000_ICS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
-#define E1000_ICS_RXCFG     E1000_ICR_RXCFG     /* Rx /c/ ordered set */
-#define E1000_ICS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
-#define E1000_ICS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
-#define E1000_ICS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
-#define E1000_ICS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
-#define E1000_ICS_TXD_LOW   E1000_ICR_TXD_LOW
-#define E1000_ICS_SRPD      E1000_ICR_SRPD
-#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
-#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
-#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
-#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO
-                                                         * parity error */
-#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO
-                                                         * parity error */
-#define E1000_ICS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer
-                                                         * parity error */
-#define E1000_ICS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity
-                                                         * error */
-#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO
-                                                         * parity error */
-#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO
-                                                         * parity error */
-#define E1000_ICS_DSW       E1000_ICR_DSW
-#define E1000_ICS_DOUTSYNC  E1000_ICR_DOUTSYNC /* NIC DMA out of sync */
-#define E1000_ICS_PHYINT    E1000_ICR_PHYINT
-#define E1000_ICS_EPRST     E1000_ICR_EPRST
-
-/* Extended Interrupt Cause Set */
-#define E1000_EICS_RX_QUEUE0    E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */
-#define E1000_EICS_RX_QUEUE1    E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */
-#define E1000_EICS_RX_QUEUE2    E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */
-#define E1000_EICS_RX_QUEUE3    E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */
-#define E1000_EICS_TX_QUEUE0    E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */
-#define E1000_EICS_TX_QUEUE1    E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */
-#define E1000_EICS_TX_QUEUE2    E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */
-#define E1000_EICS_TX_QUEUE3    E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */
-#define E1000_EICS_TCP_TIMER    E1000_EICR_TCP_TIMER /* TCP Timer */
-#define E1000_EICS_OTHER        E1000_EICR_OTHER   /* Interrupt Cause Active */
-
-#define E1000_EITR_ITR_INT_MASK 0x0000FFFF
-
-/* Transmit Descriptor Control */
-#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
-#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */
-#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
-#define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
-#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
-#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
-#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */
-/* Enable the counting of descriptors still to be processed. */
-#define E1000_TXDCTL_COUNT_DESC 0x00400000
-
-/* Flow Control Constants */
-#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
-#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
-#define FLOW_CONTROL_TYPE         0x8808
-
-/* 802.1q VLAN Packet Size */
-#define VLAN_TAG_SIZE              4    /* 802.3ac tag (not DMA'd) */
-#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
-
-/* Receive Address */
-/*
- * Number of high/low register pairs in the RAR. The RAR (Receive Address
- * Registers) holds the directed and multicast addresses that we monitor.
- * Technically, we have 16 spots.  However, we reserve one of these spots
- * (RAR[15]) for our directed address used by controllers with
- * manageability enabled, allowing us room for 15 multicast addresses.
- */
-#define E1000_RAR_ENTRIES     15
-#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
-#define E1000_RAL_MAC_ADDR_LEN 4
-#define E1000_RAH_MAC_ADDR_LEN 2
-#define E1000_RAH_POOL_MASK 0x03FC0000
-#define E1000_RAH_POOL_1 0x00040000
-
-/* Error Codes */
-#define E1000_SUCCESS      0
-#define E1000_ERR_NVM      1
-#define E1000_ERR_PHY      2
-#define E1000_ERR_CONFIG   3
-#define E1000_ERR_PARAM    4
-#define E1000_ERR_MAC_INIT 5
-#define E1000_ERR_PHY_TYPE 6
-#define E1000_ERR_RESET   9
-#define E1000_ERR_MASTER_REQUESTS_PENDING 10
-#define E1000_ERR_HOST_INTERFACE_COMMAND 11
-#define E1000_BLK_PHY_RESET   12
-#define E1000_ERR_SWFW_SYNC 13
-#define E1000_NOT_IMPLEMENTED 14
-#define E1000_ERR_MBX      15
-
-/* Loop limit on how long we wait for auto-negotiation to complete */
-#define FIBER_LINK_UP_LIMIT               50
-#define COPPER_LINK_UP_LIMIT              10
-#define PHY_AUTO_NEG_LIMIT                45
-#define PHY_FORCE_LIMIT                   20
-/* Number of 100 microseconds we wait for PCI Express master disable */
-#define MASTER_DISABLE_TIMEOUT      800
-/* Number of milliseconds we wait for PHY configuration done after MAC reset */
-#define PHY_CFG_TIMEOUT             100
-/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
-#define MDIO_OWNERSHIP_TIMEOUT      10
-/* Number of milliseconds for NVM auto read done after MAC reset. */
-#define AUTO_READ_DONE_TIMEOUT      10
-
-/* Flow Control */
-#define E1000_FCRTH_RTH  0x0000FFF8     /* Mask Bits[15:3] for RTH */
-#define E1000_FCRTH_XFCE 0x80000000     /* External Flow Control Enable */
-#define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
-#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
-
-/* Transmit Configuration Word */
-#define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
-#define E1000_TXCW_HD         0x00000040        /* TXCW half duplex */
-#define E1000_TXCW_PAUSE      0x00000080        /* TXCW sym pause request */
-#define E1000_TXCW_ASM_DIR    0x00000100        /* TXCW astm pause direction */
-#define E1000_TXCW_PAUSE_MASK 0x00000180        /* TXCW pause request mask */
-#define E1000_TXCW_RF         0x00003000        /* TXCW remote fault */
-#define E1000_TXCW_NP         0x00008000        /* TXCW next page */
-#define E1000_TXCW_CW         0x0000ffff        /* TxConfigWord mask */
-#define E1000_TXCW_TXC        0x40000000        /* Transmit Config control */
-#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
-
-/* Receive Configuration Word */
-#define E1000_RXCW_CW         0x0000ffff        /* RxConfigWord mask */
-#define E1000_RXCW_NC         0x04000000        /* Receive config no carrier */
-#define E1000_RXCW_IV         0x08000000        /* Receive config invalid */
-#define E1000_RXCW_CC         0x10000000        /* Receive config change */
-#define E1000_RXCW_C          0x20000000        /* Receive config */
-#define E1000_RXCW_SYNCH      0x40000000        /* Receive config synch */
-#define E1000_RXCW_ANC        0x80000000        /* Auto-neg complete */
-
-#define E1000_TSYNCTXCTL_VALID    0x00000001 /* tx timestamp valid */
-#define E1000_TSYNCTXCTL_ENABLED  0x00000010 /* enable tx timestampping */
-
-#define E1000_TSYNCRXCTL_VALID      0x00000001 /* rx timestamp valid */
-#define E1000_TSYNCRXCTL_TYPE_MASK  0x0000000E /* rx type mask */
-#define E1000_TSYNCRXCTL_TYPE_L2_V2       0x00
-#define E1000_TSYNCRXCTL_TYPE_L4_V1       0x02
-#define E1000_TSYNCRXCTL_TYPE_L2_L4_V2    0x04
-#define E1000_TSYNCRXCTL_TYPE_ALL         0x08
-#define E1000_TSYNCRXCTL_TYPE_EVENT_V2    0x0A
-#define E1000_TSYNCRXCTL_ENABLED    0x00000010 /* enable rx timestampping */
-
-#define E1000_TSYNCRXCFG_PTP_V1_CTRLT_MASK   0x000000FF
-#define E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE       0x00
-#define E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE  0x01
-#define E1000_TSYNCRXCFG_PTP_V1_FOLLOWUP_MESSAGE   0x02
-#define E1000_TSYNCRXCFG_PTP_V1_DELAY_RESP_MESSAGE 0x03
-#define E1000_TSYNCRXCFG_PTP_V1_MANAGEMENT_MESSAGE 0x04
-
-#define E1000_TSYNCRXCFG_PTP_V2_MSGID_MASK               0x00000F00
-#define E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE                 0x0000
-#define E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE            0x0100
-#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_REQ_MESSAGE       0x0200
-#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_RESP_MESSAGE      0x0300
-#define E1000_TSYNCRXCFG_PTP_V2_FOLLOWUP_MESSAGE             0x0800
-#define E1000_TSYNCRXCFG_PTP_V2_DELAY_RESP_MESSAGE           0x0900
-#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_FOLLOWUP_MESSAGE  0x0A00
-#define E1000_TSYNCRXCFG_PTP_V2_ANNOUNCE_MESSAGE             0x0B00
-#define E1000_TSYNCRXCFG_PTP_V2_SIGNALLING_MESSAGE           0x0C00
-#define E1000_TSYNCRXCFG_PTP_V2_MANAGEMENT_MESSAGE           0x0D00
-
-#define E1000_TIMINCA_16NS_SHIFT 24
-
-/* PCI Express Control */
-#define E1000_GCR_RXD_NO_SNOOP          0x00000001
-#define E1000_GCR_RXDSCW_NO_SNOOP       0x00000002
-#define E1000_GCR_RXDSCR_NO_SNOOP       0x00000004
-#define E1000_GCR_TXD_NO_SNOOP          0x00000008
-#define E1000_GCR_TXDSCW_NO_SNOOP       0x00000010
-#define E1000_GCR_TXDSCR_NO_SNOOP       0x00000020
-#define E1000_GCR_CMPL_TMOUT_MASK       0x0000F000
-#define E1000_GCR_CMPL_TMOUT_10ms       0x00001000
-#define E1000_GCR_CMPL_TMOUT_RESEND     0x00010000
-#define E1000_GCR_CAP_VER2              0x00040000
-
-#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP         | \
-                           E1000_GCR_RXDSCW_NO_SNOOP      | \
-                           E1000_GCR_RXDSCR_NO_SNOOP      | \
-                           E1000_GCR_TXD_NO_SNOOP         | \
-                           E1000_GCR_TXDSCW_NO_SNOOP      | \
-                           E1000_GCR_TXDSCR_NO_SNOOP)
-
-/* PHY Control Register */
-#define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
-#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
-#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
-#define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */
-#define MII_CR_POWER_DOWN       0x0800  /* Power down */
-#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
-#define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
-#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
-#define MII_CR_SPEED_1000       0x0040
-#define MII_CR_SPEED_100        0x2000
-#define MII_CR_SPEED_10         0x0000
-
-/* PHY Status Register */
-#define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */
-#define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */
-#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
-#define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */
-#define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */
-#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
-#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
-#define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */
-#define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */
-#define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */
-#define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */
-#define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */
-#define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */
-#define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */
-#define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */
-
-/* Autoneg Advertisement Register */
-#define NWAY_AR_SELECTOR_FIELD   0x0001   /* indicates IEEE 802.3 CSMA/CD */
-#define NWAY_AR_10T_HD_CAPS      0x0020   /* 10T   Half Duplex Capable */
-#define NWAY_AR_10T_FD_CAPS      0x0040   /* 10T   Full Duplex Capable */
-#define NWAY_AR_100TX_HD_CAPS    0x0080   /* 100TX Half Duplex Capable */
-#define NWAY_AR_100TX_FD_CAPS    0x0100   /* 100TX Full Duplex Capable */
-#define NWAY_AR_100T4_CAPS       0x0200   /* 100T4 Capable */
-#define NWAY_AR_PAUSE            0x0400   /* Pause operation desired */
-#define NWAY_AR_ASM_DIR          0x0800   /* Asymmetric Pause Direction bit */
-#define NWAY_AR_REMOTE_FAULT     0x2000   /* Remote Fault detected */
-#define NWAY_AR_NEXT_PAGE        0x8000   /* Next Page ability supported */
-
-/* Link Partner Ability Register (Base Page) */
-#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
-#define NWAY_LPAR_10T_HD_CAPS    0x0020 /* LP is 10T   Half Duplex Capable */
-#define NWAY_LPAR_10T_FD_CAPS    0x0040 /* LP is 10T   Full Duplex Capable */
-#define NWAY_LPAR_100TX_HD_CAPS  0x0080 /* LP is 100TX Half Duplex Capable */
-#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP is 100TX Full Duplex Capable */
-#define NWAY_LPAR_100T4_CAPS     0x0200 /* LP is 100T4 Capable */
-#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
-#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
-#define NWAY_LPAR_REMOTE_FAULT   0x2000 /* LP has detected Remote Fault */
-#define NWAY_LPAR_ACKNOWLEDGE    0x4000 /* LP has rx'd link code word */
-#define NWAY_LPAR_NEXT_PAGE      0x8000 /* Next Page ability supported */
-
-/* Autoneg Expansion Register */
-#define NWAY_ER_LP_NWAY_CAPS      0x0001 /* LP has Auto Neg Capability */
-#define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */
-#define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */
-#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
-#define NWAY_ER_PAR_DETECT_FAULT  0x0010 /* LP is 100TX Full Duplex Capable */
-
-/* 1000BASE-T Control Register */
-#define CR_1000T_ASYM_PAUSE      0x0080 /* Advertise asymmetric pause bit */
-#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
-#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
-#define CR_1000T_REPEATER_DTE    0x0400 /* 1=Repeater/switch device port */
-                                        /* 0=DTE device */
-#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
-                                        /* 0=Configure PHY as Slave */
-#define CR_1000T_MS_ENABLE      0x1000 /* 1=Master/Slave manual config value */
-                                        /* 0=Automatic Master/Slave config */
-#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
-#define CR_1000T_TEST_MODE_1     0x2000 /* Transmit Waveform test */
-#define CR_1000T_TEST_MODE_2     0x4000 /* Master Transmit Jitter test */
-#define CR_1000T_TEST_MODE_3     0x6000 /* Slave Transmit Jitter test */
-#define CR_1000T_TEST_MODE_4     0x8000 /* Transmitter Distortion test */
-
-/* 1000BASE-T Status Register */
-#define SR_1000T_IDLE_ERROR_CNT   0x00FF /* Num idle errors since last read */
-#define SR_1000T_ASYM_PAUSE_DIR  0x0100 /* LP asymmetric pause direction bit */
-#define SR_1000T_LP_HD_CAPS       0x0400 /* LP is 1000T HD capable */
-#define SR_1000T_LP_FD_CAPS       0x0800 /* LP is 1000T FD capable */
-#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
-#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
-#define SR_1000T_MS_CONFIG_RES    0x4000 /* 1=Local Tx is Master, 0=Slave */
-#define SR_1000T_MS_CONFIG_FAULT  0x8000 /* Master/Slave config fault */
-
-#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5
-
-/* PHY 1000 MII Register/Bit Definitions */
-/* PHY Registers defined by IEEE */
-#define PHY_CONTROL      0x00 /* Control Register */
-#define PHY_STATUS       0x01 /* Status Register */
-#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
-#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
-#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
-#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
-#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
-#define PHY_NEXT_PAGE_TX 0x07 /* Next Page Tx */
-#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
-#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
-#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
-#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
-
-#define PHY_CONTROL_LB   0x4000 /* PHY Loopback bit */
-
-/* NVM Control */
-#define E1000_EECD_SK        0x00000001 /* NVM Clock */
-#define E1000_EECD_CS        0x00000002 /* NVM Chip Select */
-#define E1000_EECD_DI        0x00000004 /* NVM Data In */
-#define E1000_EECD_DO        0x00000008 /* NVM Data Out */
-#define E1000_EECD_FWE_MASK  0x00000030
-#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
-#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
-#define E1000_EECD_FWE_SHIFT 4
-#define E1000_EECD_REQ       0x00000040 /* NVM Access Request */
-#define E1000_EECD_GNT       0x00000080 /* NVM Access Grant */
-#define E1000_EECD_PRES      0x00000100 /* NVM Present */
-#define E1000_EECD_SIZE      0x00000200 /* NVM Size (0=64 word 1=256 word) */
-/* NVM Addressing bits based on type 0=small, 1=large */
-#define E1000_EECD_ADDR_BITS 0x00000400
-#define E1000_EECD_TYPE      0x00002000 /* NVM Type (1-SPI, 0-Microwire) */
-#define E1000_NVM_GRANT_ATTEMPTS   1000 /* NVM # attempts to gain grant */
-#define E1000_EECD_AUTO_RD          0x00000200  /* NVM Auto Read done */
-#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* NVM Size */
-#define E1000_EECD_SIZE_EX_SHIFT     11
-#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
-#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
-#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
-#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
-#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
-#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
-#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
-#define E1000_EECD_SECVAL_SHIFT      22
-#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES)
-
-#define E1000_NVM_SWDPIN0   0x0001   /* SWDPIN 0 NVM Value */
-#define E1000_NVM_LED_LOGIC 0x0020   /* Led Logic Word */
-#define E1000_NVM_RW_REG_DATA   16  /* Offset to data in NVM read/write regs */
-#define E1000_NVM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
-#define E1000_NVM_RW_REG_START  1    /* Start operation */
-#define E1000_NVM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
-#define E1000_NVM_POLL_WRITE    1    /* Flag for polling for write complete */
-#define E1000_NVM_POLL_READ     0    /* Flag for polling for read complete */
-#define E1000_FLASH_UPDATES  2000
-
-/* NVM Word Offsets */
-#define NVM_COMPAT                 0x0003
-#define NVM_ID_LED_SETTINGS        0x0004
-#define NVM_VERSION                0x0005
-#define NVM_SERDES_AMPLITUDE       0x0006 /* SERDES output amplitude */
-#define NVM_PHY_CLASS_WORD         0x0007
-#define NVM_INIT_CONTROL1_REG      0x000A
-#define NVM_INIT_CONTROL2_REG      0x000F
-#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010
-#define NVM_INIT_CONTROL3_PORT_B   0x0014
-#define NVM_INIT_3GIO_3            0x001A
-#define NVM_SWDEF_PINS_CTRL_PORT_0 0x0020
-#define NVM_INIT_CONTROL3_PORT_A   0x0024
-#define NVM_CFG                    0x0012
-#define NVM_FLASH_VERSION          0x0032
-#define NVM_ALT_MAC_ADDR_PTR       0x0037
-#define NVM_CHECKSUM_REG           0x003F
-
-#define E1000_NVM_CFG_DONE_PORT_0  0x040000 /* MNG config cycle done */
-#define E1000_NVM_CFG_DONE_PORT_1  0x080000 /* ...for second port */
-
-/* Mask bits for fields in Word 0x0f of the NVM */
-#define NVM_WORD0F_PAUSE_MASK       0x3000
-#define NVM_WORD0F_PAUSE            0x1000
-#define NVM_WORD0F_ASM_DIR          0x2000
-#define NVM_WORD0F_ANE              0x0800
-#define NVM_WORD0F_SWPDIO_EXT_MASK  0x00F0
-#define NVM_WORD0F_LPLU             0x0001
-
-/* Mask bits for fields in Word 0x1a of the NVM */
-#define NVM_WORD1A_ASPM_MASK  0x000C
-
-/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
-#define NVM_SUM                    0xBABA
-
-#define NVM_MAC_ADDR_OFFSET        0
-#define NVM_PBA_OFFSET_0           8
-#define NVM_PBA_OFFSET_1           9
-#define NVM_RESERVED_WORD          0xFFFF
-#define NVM_PHY_CLASS_A            0x8000
-#define NVM_SERDES_AMPLITUDE_MASK  0x000F
-#define NVM_SIZE_MASK              0x1C00
-#define NVM_SIZE_SHIFT             10
-#define NVM_WORD_SIZE_BASE_SHIFT   6
-#define NVM_SWDPIO_EXT_SHIFT       4
-
-/* NVM Commands - SPI */
-#define NVM_MAX_RETRY_SPI          5000 /* Max wait of 5ms, for RDY signal */
-#define NVM_READ_OPCODE_SPI        0x03 /* NVM read opcode */
-#define NVM_WRITE_OPCODE_SPI       0x02 /* NVM write opcode */
-#define NVM_A8_OPCODE_SPI          0x08 /* opcode bit-3 = address bit-8 */
-#define NVM_WREN_OPCODE_SPI        0x06 /* NVM set Write Enable latch */
-#define NVM_WRDI_OPCODE_SPI        0x04 /* NVM reset Write Enable latch */
-#define NVM_RDSR_OPCODE_SPI        0x05 /* NVM read Status register */
-#define NVM_WRSR_OPCODE_SPI        0x01 /* NVM write Status register */
-
-/* SPI NVM Status Register */
-#define NVM_STATUS_RDY_SPI         0x01
-#define NVM_STATUS_WEN_SPI         0x02
-#define NVM_STATUS_BP0_SPI         0x04
-#define NVM_STATUS_BP1_SPI         0x08
-#define NVM_STATUS_WPEN_SPI        0x80
-
-/* Word definitions for ID LED Settings */
-#define ID_LED_RESERVED_0000 0x0000
-#define ID_LED_RESERVED_FFFF 0xFFFF
-#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2  << 12) | \
-                              (ID_LED_OFF1_OFF2 <<  8) | \
-                              (ID_LED_DEF1_DEF2 <<  4) | \
-                              (ID_LED_DEF1_DEF2))
-#define ID_LED_DEF1_DEF2     0x1
-#define ID_LED_DEF1_ON2      0x2
-#define ID_LED_DEF1_OFF2     0x3
-#define ID_LED_ON1_DEF2      0x4
-#define ID_LED_ON1_ON2       0x5
-#define ID_LED_ON1_OFF2      0x6
-#define ID_LED_OFF1_DEF2     0x7
-#define ID_LED_OFF1_ON2      0x8
-#define ID_LED_OFF1_OFF2     0x9
-
-#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
-#define IGP_ACTIVITY_LED_ENABLE 0x0300
-#define IGP_LED3_MODE           0x07000000
-
-/* PCI/PCI-X/PCI-EX Config space */
-#define PCI_HEADER_TYPE_REGISTER     0x0E
-#define PCIE_LINK_STATUS             0x12
-#define PCIE_DEVICE_CONTROL2         0x28
-
-#define PCI_HEADER_TYPE_MULTIFUNC    0x80
-#define PCIE_LINK_WIDTH_MASK         0x3F0
-#define PCIE_LINK_WIDTH_SHIFT        4
-#define PCIE_DEVICE_CONTROL2_16ms    0x0005
-
-#ifndef ETH_ADDR_LEN
-#define ETH_ADDR_LEN                 6
-#endif
-
-#define PHY_REVISION_MASK      0xFFFFFFF0
-#define MAX_PHY_REG_ADDRESS    0x1F  /* 5 bit address bus (0-0x1F) */
-#define MAX_PHY_MULTI_PAGE_REG 0xF
-
-/* Bit definitions for valid PHY IDs. */
-/*
- * I = Integrated
- * E = External
- */
-#define M88E1000_E_PHY_ID    0x01410C50
-#define M88E1000_I_PHY_ID    0x01410C30
-#define M88E1011_I_PHY_ID    0x01410C20
-#define IGP01E1000_I_PHY_ID  0x02A80380
-#define M88E1011_I_REV_4     0x04
-#define M88E1111_I_PHY_ID    0x01410CC0
-#define GG82563_E_PHY_ID     0x01410CA0
-#define IGP03E1000_E_PHY_ID  0x02A80390
-#define IFE_E_PHY_ID         0x02A80330
-#define IFE_PLUS_E_PHY_ID    0x02A80320
-#define IFE_C_E_PHY_ID       0x02A80310
-#define IGP04E1000_E_PHY_ID  0x02A80391
-#define M88_VENDOR           0x0141
-
-/* M88E1000 Specific Registers */
-#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
-#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
-#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
-#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
-#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
-#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
-
-#define M88E1000_PHY_EXT_CTRL      0x1A  /* PHY extend control register */
-#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
-#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
-#define M88E1000_PHY_VCO_REG_BIT8  0x100 /* Bits 8 & 11 are adjusted for */
-#define M88E1000_PHY_VCO_REG_BIT11 0x800    /* improved BER performance */
-
-/* M88E1000 PHY Specific Control Register */
-#define M88E1000_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
-#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reverse enabled */
-#define M88E1000_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
-/* 1=CLK125 low, 0=CLK125 toggling */
-#define M88E1000_PSCR_CLK125_DISABLE    0x0010
-#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000 /* MDI Crossover Mode bits 6:5 */
-                                               /* Manual MDI configuration */
-#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
-/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
-#define M88E1000_PSCR_AUTO_X_1000T     0x0040
-/* Auto crossover enabled all speeds */
-#define M88E1000_PSCR_AUTO_X_MODE      0x0060
-/*
- * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold
- * 0=Normal 10BASE-T Rx Threshold
- */
-#define M88E1000_PSCR_EN_10BT_EXT_DIST 0x0080
-/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
-#define M88E1000_PSCR_MII_5BIT_ENABLE      0x0100
-#define M88E1000_PSCR_SCRAMBLER_DISABLE    0x0200 /* 1=Scrambler disable */
-#define M88E1000_PSCR_FORCE_LINK_GOOD      0x0400 /* 1=Force link good */
-#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Tx */
-
-/* M88E1000 PHY Specific Status Register */
-#define M88E1000_PSSR_JABBER             0x0001 /* 1=Jabber */
-#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
-#define M88E1000_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
-#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
-/*
- * 0 = <50M
- * 1 = 50-80M
- * 2 = 80-110M
- * 3 = 110-140M
- * 4 = >140M
- */
-#define M88E1000_PSSR_CABLE_LENGTH       0x0380
-#define M88E1000_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
-#define M88E1000_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
-#define M88E1000_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
-#define M88E1000_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
-#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
-#define M88E1000_PSSR_10MBS              0x0000 /* 00=10Mbs */
-#define M88E1000_PSSR_100MBS             0x4000 /* 01=100Mbs */
-#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
-
-#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
-
-/* M88E1000 Extended PHY Specific Control Register */
-#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
-/*
- * 1 = Lost lock detect enabled.
- * Will assert lost lock and bring
- * link down if idle not seen
- * within 1ms in 1000BASE-T
- */
-#define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000
-/*
- * Number of times we will attempt to autonegotiate before downshifting if we
- * are the master
- */
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X   0x0400
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X   0x0800
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X   0x0C00
-/*
- * Number of times we will attempt to autonegotiate before downshifting if we
- * are the slave
- */
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS   0x0000
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X    0x0200
-#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X    0x0300
-#define M88E1000_EPSCR_TX_CLK_2_5     0x0060 /* 2.5 MHz TX_CLK */
-#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
-#define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
-
-/* M88EC018 Rev 2 specific DownShift settings */
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK  0x0E00
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X    0x0000
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X    0x0200
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X    0x0400
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X    0x0600
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X    0x0800
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X    0x0A00
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X    0x0C00
-#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X    0x0E00
-
-/*
- * Bits...
- * 15-5: page
- * 4-0: register offset
- */
-#define GG82563_PAGE_SHIFT        5
-#define GG82563_REG(page, reg)    \
-        (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
-#define GG82563_MIN_ALT_REG       30
-
-/* GG82563 Specific Registers */
-#define GG82563_PHY_SPEC_CTRL           \
-        GG82563_REG(0, 16) /* PHY Specific Control */
-#define GG82563_PHY_SPEC_STATUS         \
-        GG82563_REG(0, 17) /* PHY Specific Status */
-#define GG82563_PHY_INT_ENABLE          \
-        GG82563_REG(0, 18) /* Interrupt Enable */
-#define GG82563_PHY_SPEC_STATUS_2       \
-        GG82563_REG(0, 19) /* PHY Specific Status 2 */
-#define GG82563_PHY_RX_ERR_CNTR         \
-        GG82563_REG(0, 21) /* Receive Error Counter */
-#define GG82563_PHY_PAGE_SELECT         \
-        GG82563_REG(0, 22) /* Page Select */
-#define GG82563_PHY_SPEC_CTRL_2         \
-        GG82563_REG(0, 26) /* PHY Specific Control 2 */
-#define GG82563_PHY_PAGE_SELECT_ALT     \
-        GG82563_REG(0, 29) /* Alternate Page Select */
-#define GG82563_PHY_TEST_CLK_CTRL       \
-        GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */
-
-#define GG82563_PHY_MAC_SPEC_CTRL       \
-        GG82563_REG(2, 21) /* MAC Specific Control Register */
-#define GG82563_PHY_MAC_SPEC_CTRL_2     \
-        GG82563_REG(2, 26) /* MAC Specific Control 2 */
-
-#define GG82563_PHY_DSP_DISTANCE    \
-        GG82563_REG(5, 26) /* DSP Distance */
-
-/* Page 193 - Port Control Registers */
-#define GG82563_PHY_KMRN_MODE_CTRL   \
-        GG82563_REG(193, 16) /* Kumeran Mode Control */
-#define GG82563_PHY_PORT_RESET          \
-        GG82563_REG(193, 17) /* Port Reset */
-#define GG82563_PHY_REVISION_ID         \
-        GG82563_REG(193, 18) /* Revision ID */
-#define GG82563_PHY_DEVICE_ID           \
-        GG82563_REG(193, 19) /* Device ID */
-#define GG82563_PHY_PWR_MGMT_CTRL       \
-        GG82563_REG(193, 20) /* Power Management Control */
-#define GG82563_PHY_RATE_ADAPT_CTRL     \
-        GG82563_REG(193, 25) /* Rate Adaptation Control */
-
-/* Page 194 - KMRN Registers */
-#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \
-        GG82563_REG(194, 16) /* FIFO's Control/Status */
-#define GG82563_PHY_KMRN_CTRL           \
-        GG82563_REG(194, 17) /* Control */
-#define GG82563_PHY_INBAND_CTRL         \
-        GG82563_REG(194, 18) /* Inband Control */
-#define GG82563_PHY_KMRN_DIAGNOSTIC     \
-        GG82563_REG(194, 19) /* Diagnostic */
-#define GG82563_PHY_ACK_TIMEOUTS        \
-        GG82563_REG(194, 20) /* Acknowledge Timeouts */
-#define GG82563_PHY_ADV_ABILITY         \
-        GG82563_REG(194, 21) /* Advertised Ability */
-#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \
-        GG82563_REG(194, 23) /* Link Partner Advertised Ability */
-#define GG82563_PHY_ADV_NEXT_PAGE       \
-        GG82563_REG(194, 24) /* Advertised Next Page */
-#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \
-        GG82563_REG(194, 25) /* Link Partner Advertised Next page */
-#define GG82563_PHY_KMRN_MISC           \
-        GG82563_REG(194, 26) /* Misc. */
-
-/* MDI Control */
-#define E1000_MDIC_DATA_MASK 0x0000FFFF
-#define E1000_MDIC_REG_MASK  0x001F0000
-#define E1000_MDIC_REG_SHIFT 16
-#define E1000_MDIC_PHY_MASK  0x03E00000
-#define E1000_MDIC_PHY_SHIFT 21
-#define E1000_MDIC_OP_WRITE  0x04000000
-#define E1000_MDIC_OP_READ   0x08000000
-#define E1000_MDIC_READY     0x10000000
-#define E1000_MDIC_INT_EN    0x20000000
-#define E1000_MDIC_ERROR     0x40000000
-
-/* SerDes Control */
-#define E1000_GEN_CTL_READY             0x80000000
-#define E1000_GEN_CTL_ADDRESS_SHIFT     8
-#define E1000_GEN_POLL_TIMEOUT          640
-
-/* LinkSec register fields */
-#define E1000_LSECTXCAP_SUM_MASK        0x00FF0000
-#define E1000_LSECTXCAP_SUM_SHIFT       16
-#define E1000_LSECRXCAP_SUM_MASK        0x00FF0000
-#define E1000_LSECRXCAP_SUM_SHIFT       16
-
-#define E1000_LSECTXCTRL_EN_MASK        0x00000003
-#define E1000_LSECTXCTRL_DISABLE        0x0
-#define E1000_LSECTXCTRL_AUTH           0x1
-#define E1000_LSECTXCTRL_AUTH_ENCRYPT   0x2
-#define E1000_LSECTXCTRL_AISCI          0x00000020
-#define E1000_LSECTXCTRL_PNTHRSH_MASK   0xFFFFFF00
-#define E1000_LSECTXCTRL_RSV_MASK       0x000000D8
-
-#define E1000_LSECRXCTRL_EN_MASK        0x0000000C
-#define E1000_LSECRXCTRL_EN_SHIFT       2
-#define E1000_LSECRXCTRL_DISABLE        0x0
-#define E1000_LSECRXCTRL_CHECK          0x1
-#define E1000_LSECRXCTRL_STRICT         0x2
-#define E1000_LSECRXCTRL_DROP           0x3
-#define E1000_LSECRXCTRL_PLSH           0x00000040
-#define E1000_LSECRXCTRL_RP             0x00000080
-#define E1000_LSECRXCTRL_RSV_MASK       0xFFFFFF33
-
-
-
-#endif /* _IGB_DEFINES_H_ */
diff --git a/roms/ipxe/src/drivers/net/igb/igb_hw.h b/roms/ipxe/src/drivers/net/igb/igb_hw.h
deleted file mode 100644
index 65a04f2087a12adcfa40b2258eb915a5930f71b8..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_hw.h
+++ /dev/null
@@ -1,697 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#ifndef _IGB_HW_H_
-#define _IGB_HW_H_
-
-#include "igb_osdep.h"
-#include "igb_regs.h"
-#include "igb_defines.h"
-
-struct e1000_hw;
-
-#define E1000_DEV_ID_82576                    0x10C9
-#define E1000_DEV_ID_82576_FIBER              0x10E6
-#define E1000_DEV_ID_82576_SERDES             0x10E7
-#define E1000_DEV_ID_82576_QUAD_COPPER        0x10E8
-#define E1000_DEV_ID_82576_NS                 0x150A
-#define E1000_DEV_ID_82576_NS_SERDES          0x1518
-#define E1000_DEV_ID_82576_SERDES_QUAD        0x150D
-#define E1000_DEV_ID_82575EB_COPPER           0x10A7
-#define E1000_DEV_ID_82575EB_FIBER_SERDES     0x10A9
-#define E1000_DEV_ID_82575GB_QUAD_COPPER      0x10D6
-#define E1000_REVISION_0 0
-#define E1000_REVISION_1 1
-#define E1000_REVISION_2 2
-#define E1000_REVISION_3 3
-#define E1000_REVISION_4 4
-
-#define E1000_FUNC_0     0
-#define E1000_FUNC_1     1
-
-#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0   0
-#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1   3
-
-enum e1000_mac_type {
-	e1000_undefined = 0,
-	e1000_82575,
-	e1000_82576,
-	e1000_num_macs  /* List is 1-based, so subtract 1 for true count. */
-};
-
-enum e1000_media_type {
-	e1000_media_type_unknown = 0,
-	e1000_media_type_copper = 1,
-	e1000_media_type_fiber = 2,
-	e1000_media_type_internal_serdes = 3,
-	e1000_num_media_types
-};
-
-enum e1000_nvm_type {
-	e1000_nvm_unknown = 0,
-	e1000_nvm_none,
-	e1000_nvm_eeprom_spi,
-	e1000_nvm_flash_hw,
-	e1000_nvm_flash_sw
-};
-
-enum e1000_nvm_override {
-	e1000_nvm_override_none = 0,
-	e1000_nvm_override_spi_small,
-	e1000_nvm_override_spi_large,
-};
-
-enum e1000_phy_type {
-	e1000_phy_unknown = 0,
-	e1000_phy_none,
-	e1000_phy_m88,
-	e1000_phy_igp,
-	e1000_phy_igp_2,
-	e1000_phy_gg82563,
-	e1000_phy_igp_3,
-	e1000_phy_ife,
-	e1000_phy_vf,
-};
-
-enum e1000_bus_type {
-	e1000_bus_type_unknown = 0,
-	e1000_bus_type_pci,
-	e1000_bus_type_pcix,
-	e1000_bus_type_pci_express,
-	e1000_bus_type_reserved
-};
-
-enum e1000_bus_speed {
-	e1000_bus_speed_unknown = 0,
-	e1000_bus_speed_33,
-	e1000_bus_speed_66,
-	e1000_bus_speed_100,
-	e1000_bus_speed_120,
-	e1000_bus_speed_133,
-	e1000_bus_speed_2500,
-	e1000_bus_speed_5000,
-	e1000_bus_speed_reserved
-};
-
-enum e1000_bus_width {
-	e1000_bus_width_unknown = 0,
-	e1000_bus_width_pcie_x1,
-	e1000_bus_width_pcie_x2,
-	e1000_bus_width_pcie_x4 = 4,
-	e1000_bus_width_pcie_x8 = 8,
-	e1000_bus_width_32,
-	e1000_bus_width_64,
-	e1000_bus_width_reserved
-};
-
-enum e1000_1000t_rx_status {
-	e1000_1000t_rx_status_not_ok = 0,
-	e1000_1000t_rx_status_ok,
-	e1000_1000t_rx_status_undefined = 0xFF
-};
-
-enum e1000_rev_polarity {
-	e1000_rev_polarity_normal = 0,
-	e1000_rev_polarity_reversed,
-	e1000_rev_polarity_undefined = 0xFF
-};
-
-enum e1000_fc_mode {
-	e1000_fc_none = 0,
-	e1000_fc_rx_pause,
-	e1000_fc_tx_pause,
-	e1000_fc_full,
-	e1000_fc_default = 0xFF
-};
-
-enum e1000_ms_type {
-	e1000_ms_hw_default = 0,
-	e1000_ms_force_master,
-	e1000_ms_force_slave,
-	e1000_ms_auto
-};
-
-enum e1000_smart_speed {
-	e1000_smart_speed_default = 0,
-	e1000_smart_speed_on,
-	e1000_smart_speed_off
-};
-
-enum e1000_serdes_link_state {
-	e1000_serdes_link_down = 0,
-	e1000_serdes_link_autoneg_progress,
-	e1000_serdes_link_autoneg_complete,
-	e1000_serdes_link_forced_up
-};
-
-/* Receive Descriptor */
-struct e1000_rx_desc {
-	__le64 buffer_addr; /* Address of the descriptor's data buffer */
-	__le16 length;      /* Length of data DMAed into data buffer */
-	__le16 csum;        /* Packet checksum */
-	u8  status;         /* Descriptor status */
-	u8  errors;         /* Descriptor Errors */
-	__le16 special;
-};
-
-/* Receive Descriptor - Extended */
-union e1000_rx_desc_extended {
-	struct {
-		__le64 buffer_addr;
-		__le64 reserved;
-	} read;
-	struct {
-		struct {
-			__le32 mrq;           /* Multiple Rx Queues */
-			union {
-				__le32 rss;         /* RSS Hash */
-				struct {
-					__le16 ip_id;  /* IP id */
-					__le16 csum;   /* Packet Checksum */
-				} csum_ip;
-			} hi_dword;
-		} lower;
-		struct {
-			__le32 status_error;  /* ext status/error */
-			__le16 length;
-			__le16 vlan;          /* VLAN tag */
-		} upper;
-	} wb;  /* writeback */
-};
-
-#define MAX_PS_BUFFERS 4
-/* Receive Descriptor - Packet Split */
-union e1000_rx_desc_packet_split {
-	struct {
-		/* one buffer for protocol header(s), three data buffers */
-		__le64 buffer_addr[MAX_PS_BUFFERS];
-	} read;
-	struct {
-		struct {
-			__le32 mrq;           /* Multiple Rx Queues */
-			union {
-				__le32 rss;           /* RSS Hash */
-				struct {
-					__le16 ip_id;    /* IP id */
-					__le16 csum;     /* Packet Checksum */
-				} csum_ip;
-			} hi_dword;
-		} lower;
-		struct {
-			__le32 status_error;  /* ext status/error */
-			__le16 length0;       /* length of buffer 0 */
-			__le16 vlan;          /* VLAN tag */
-		} middle;
-		struct {
-			__le16 header_status;
-			__le16 length[3];     /* length of buffers 1-3 */
-		} upper;
-		__le64 reserved;
-	} wb; /* writeback */
-};
-
-/* Transmit Descriptor */
-struct e1000_tx_desc {
-	__le64 buffer_addr;   /* Address of the descriptor's data buffer */
-	union {
-		__le32 data;
-		struct {
-			__le16 length;    /* Data buffer length */
-			u8 cso;           /* Checksum offset */
-			u8 cmd;           /* Descriptor control */
-		} flags;
-	} lower;
-	union {
-		__le32 data;
-		struct {
-			u8 status;        /* Descriptor status */
-			u8 css;           /* Checksum start */
-			__le16 special;
-		} fields;
-	} upper;
-};
-
-/* Offload Context Descriptor */
-struct e1000_context_desc {
-	union {
-		__le32 ip_config;
-		struct {
-			u8 ipcss;         /* IP checksum start */
-			u8 ipcso;         /* IP checksum offset */
-			__le16 ipcse;     /* IP checksum end */
-		} ip_fields;
-	} lower_setup;
-	union {
-		__le32 tcp_config;
-		struct {
-			u8 tucss;         /* TCP checksum start */
-			u8 tucso;         /* TCP checksum offset */
-			__le16 tucse;     /* TCP checksum end */
-		} tcp_fields;
-	} upper_setup;
-	__le32 cmd_and_length;
-	union {
-		__le32 data;
-		struct {
-			u8 status;        /* Descriptor status */
-			u8 hdr_len;       /* Header length */
-			__le16 mss;       /* Maximum segment size */
-		} fields;
-	} tcp_seg_setup;
-};
-
-/* Offload data descriptor */
-struct e1000_data_desc {
-	__le64 buffer_addr;   /* Address of the descriptor's buffer address */
-	union {
-		__le32 data;
-		struct {
-			__le16 length;    /* Data buffer length */
-			u8 typ_len_ext;
-			u8 cmd;
-		} flags;
-	} lower;
-	union {
-		__le32 data;
-		struct {
-			u8 status;        /* Descriptor status */
-			u8 popts;         /* Packet Options */
-			__le16 special;
-		} fields;
-	} upper;
-};
-
-/* Statistics counters collected by the MAC */
-struct e1000_hw_stats {
-	u64 crcerrs;
-	u64 algnerrc;
-	u64 symerrs;
-	u64 rxerrc;
-	u64 mpc;
-	u64 scc;
-	u64 ecol;
-	u64 mcc;
-	u64 latecol;
-	u64 colc;
-	u64 dc;
-	u64 tncrs;
-	u64 sec;
-	u64 cexterr;
-	u64 rlec;
-	u64 xonrxc;
-	u64 xontxc;
-	u64 xoffrxc;
-	u64 xofftxc;
-	u64 fcruc;
-	u64 prc64;
-	u64 prc127;
-	u64 prc255;
-	u64 prc511;
-	u64 prc1023;
-	u64 prc1522;
-	u64 gprc;
-	u64 bprc;
-	u64 mprc;
-	u64 gptc;
-	u64 gorc;
-	u64 gotc;
-	u64 rnbc;
-	u64 ruc;
-	u64 rfc;
-	u64 roc;
-	u64 rjc;
-	u64 mgprc;
-	u64 mgpdc;
-	u64 mgptc;
-	u64 tor;
-	u64 tot;
-	u64 tpr;
-	u64 tpt;
-	u64 ptc64;
-	u64 ptc127;
-	u64 ptc255;
-	u64 ptc511;
-	u64 ptc1023;
-	u64 ptc1522;
-	u64 mptc;
-	u64 bptc;
-	u64 tsctc;
-	u64 tsctfc;
-	u64 iac;
-	u64 icrxptc;
-	u64 icrxatc;
-	u64 ictxptc;
-	u64 ictxatc;
-	u64 ictxqec;
-	u64 ictxqmtc;
-	u64 icrxdmtc;
-	u64 icrxoc;
-	u64 cbtmpc;
-	u64 htdpmc;
-	u64 cbrdpc;
-	u64 cbrmpc;
-	u64 rpthc;
-	u64 hgptc;
-	u64 htcbdpc;
-	u64 hgorc;
-	u64 hgotc;
-	u64 lenerrs;
-	u64 scvpc;
-	u64 hrmpc;
-	u64 doosync;
-};
-
-
-struct e1000_phy_stats {
-	u32 idle_errors;
-	u32 receive_errors;
-};
-
-struct e1000_host_mng_dhcp_cookie {
-	u32 signature;
-	u8  status;
-	u8  reserved0;
-	u16 vlan_id;
-	u32 reserved1;
-	u16 reserved2;
-	u8  reserved3;
-	u8  checksum;
-};
-
-/* Host Interface "Rev 1" */
-struct e1000_host_command_header {
-	u8 command_id;
-	u8 command_length;
-	u8 command_options;
-	u8 checksum;
-};
-
-#define E1000_HI_MAX_DATA_LENGTH     252
-struct e1000_host_command_info {
-	struct e1000_host_command_header command_header;
-	u8 command_data[E1000_HI_MAX_DATA_LENGTH];
-};
-
-/* Host Interface "Rev 2" */
-struct e1000_host_mng_command_header {
-	u8  command_id;
-	u8  checksum;
-	u16 reserved1;
-	u16 reserved2;
-	u16 command_length;
-};
-
-#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
-struct e1000_host_mng_command_info {
-	struct e1000_host_mng_command_header command_header;
-	u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
-};
-
-#include "igb_mac.h"
-#include "igb_phy.h"
-#include "igb_nvm.h"
-#include "igb_manage.h"
-
-struct e1000_mac_operations {
-	/* Function pointers for the MAC. */
-	s32  (*init_params)(struct e1000_hw *);
-	s32  (*id_led_init)(struct e1000_hw *);
-	s32  (*blink_led)(struct e1000_hw *);
-	s32  (*check_for_link)(struct e1000_hw *);
-	bool (*check_mng_mode)(struct e1000_hw *hw);
-	s32  (*cleanup_led)(struct e1000_hw *);
-	void (*clear_hw_cntrs)(struct e1000_hw *);
-	void (*clear_vfta)(struct e1000_hw *);
-	s32  (*get_bus_info)(struct e1000_hw *);
-	void (*set_lan_id)(struct e1000_hw *);
-	s32  (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
-	s32  (*led_on)(struct e1000_hw *);
-	s32  (*led_off)(struct e1000_hw *);
-	void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32);
-	s32  (*reset_hw)(struct e1000_hw *);
-	s32  (*init_hw)(struct e1000_hw *);
-	void (*shutdown_serdes)(struct e1000_hw *);
-	s32  (*setup_link)(struct e1000_hw *);
-	s32  (*setup_physical_interface)(struct e1000_hw *);
-	s32  (*setup_led)(struct e1000_hw *);
-	void (*write_vfta)(struct e1000_hw *, u32, u32);
-	void (*mta_set)(struct e1000_hw *, u32);
-	void (*config_collision_dist)(struct e1000_hw *);
-	void (*rar_set)(struct e1000_hw *, u8*, u32);
-	s32  (*read_mac_addr)(struct e1000_hw *);
-	s32  (*validate_mdi_setting)(struct e1000_hw *);
-	s32  (*mng_host_if_write)(struct e1000_hw *, u8*, u16, u16, u8*);
-	s32  (*mng_write_cmd_header)(struct e1000_hw *hw,
-                      struct e1000_host_mng_command_header*);
-	s32  (*mng_enable_host_if)(struct e1000_hw *);
-	s32  (*wait_autoneg)(struct e1000_hw *);
-};
-
-struct e1000_phy_operations {
-	s32  (*init_params)(struct e1000_hw *);
-	s32  (*acquire)(struct e1000_hw *);
-	s32  (*check_polarity)(struct e1000_hw *);
-	s32  (*check_reset_block)(struct e1000_hw *);
-	s32  (*commit)(struct e1000_hw *);
-#if 0
-	s32  (*force_speed_duplex)(struct e1000_hw *);
-#endif
-	s32  (*get_cfg_done)(struct e1000_hw *hw);
-#if 0
-	s32  (*get_cable_length)(struct e1000_hw *);
-#endif
-	s32  (*get_info)(struct e1000_hw *);
-	s32  (*read_reg)(struct e1000_hw *, u32, u16 *);
-	s32  (*read_reg_locked)(struct e1000_hw *, u32, u16 *);
-	void (*release)(struct e1000_hw *);
-	s32  (*reset)(struct e1000_hw *);
-	s32  (*set_d0_lplu_state)(struct e1000_hw *, bool);
-	s32  (*set_d3_lplu_state)(struct e1000_hw *, bool);
-	s32  (*write_reg)(struct e1000_hw *, u32, u16);
-	s32  (*write_reg_locked)(struct e1000_hw *, u32, u16);
-	void (*power_up)(struct e1000_hw *);
-	void (*power_down)(struct e1000_hw *);
-};
-
-struct e1000_nvm_operations {
-	s32  (*init_params)(struct e1000_hw *);
-	s32  (*acquire)(struct e1000_hw *);
-	s32  (*read)(struct e1000_hw *, u16, u16, u16 *);
-	void (*release)(struct e1000_hw *);
-	void (*reload)(struct e1000_hw *);
-	s32  (*update)(struct e1000_hw *);
-	s32  (*valid_led_default)(struct e1000_hw *, u16 *);
-	s32  (*validate)(struct e1000_hw *);
-	s32  (*write)(struct e1000_hw *, u16, u16, u16 *);
-};
-
-struct e1000_mac_info {
-	struct e1000_mac_operations ops;
-	u8 addr[6];
-	u8 perm_addr[6];
-
-	enum e1000_mac_type type;
-
-	u32 collision_delta;
-	u32 ledctl_default;
-	u32 ledctl_mode1;
-	u32 ledctl_mode2;
-	u32 mc_filter_type;
-	u32 tx_packet_delta;
-	u32 txcw;
-
-	u16 current_ifs_val;
-	u16 ifs_max_val;
-	u16 ifs_min_val;
-	u16 ifs_ratio;
-	u16 ifs_step_size;
-	u16 mta_reg_count;
-	u16 uta_reg_count;
-
-	/* Maximum size of the MTA register table in all supported adapters */
-	#define MAX_MTA_REG 128
-	u32 mta_shadow[MAX_MTA_REG];
-	u16 rar_entry_count;
-
-	u8  forced_speed_duplex;
-
-	bool adaptive_ifs;
-	bool arc_subsystem_valid;
-	bool asf_firmware_present;
-	bool autoneg;
-	bool autoneg_failed;
-	bool get_link_status;
-	bool in_ifs_mode;
-	enum e1000_serdes_link_state serdes_link_state;
-	bool serdes_has_link;
-	bool tx_pkt_filtering;
-};
-
-struct e1000_phy_info {
-	struct e1000_phy_operations ops;
-	enum e1000_phy_type type;
-
-	enum e1000_1000t_rx_status local_rx;
-	enum e1000_1000t_rx_status remote_rx;
-	enum e1000_ms_type ms_type;
-	enum e1000_ms_type original_ms_type;
-	enum e1000_rev_polarity cable_polarity;
-	enum e1000_smart_speed smart_speed;
-
-	u32 addr;
-	u32 id;
-	u32 reset_delay_us; /* in usec */
-	u32 revision;
-
-	enum e1000_media_type media_type;
-
-	u16 autoneg_advertised;
-	u16 autoneg_mask;
-	u16 cable_length;
-	u16 max_cable_length;
-	u16 min_cable_length;
-
-	u8 mdix;
-
-	bool disable_polarity_correction;
-	bool is_mdix;
-	bool polarity_correction;
-	bool reset_disable;
-	bool speed_downgraded;
-	bool autoneg_wait_to_complete;
-};
-
-struct e1000_nvm_info {
-	struct e1000_nvm_operations ops;
-	enum e1000_nvm_type type;
-	enum e1000_nvm_override override;
-
-	u32 flash_bank_size;
-	u32 flash_base_addr;
-
-	u16 word_size;
-	u16 delay_usec;
-	u16 address_bits;
-	u16 opcode_bits;
-	u16 page_size;
-};
-
-struct e1000_bus_info {
-	enum e1000_bus_type type;
-	enum e1000_bus_speed speed;
-	enum e1000_bus_width width;
-
-	u16 func;
-	u16 pci_cmd_word;
-};
-
-struct e1000_fc_info {
-	u32 high_water;          /* Flow control high-water mark */
-	u32 low_water;           /* Flow control low-water mark */
-	u16 pause_time;          /* Flow control pause timer */
-	bool send_xon;           /* Flow control send XON */
-	bool strict_ieee;        /* Strict IEEE mode */
-	enum e1000_fc_mode current_mode; /* FC mode in effect */
-	enum e1000_fc_mode requested_mode; /* FC mode requested by caller */
-};
-
-struct e1000_mbx_operations {
-	s32 (*init_params)(struct e1000_hw *hw);
-	s32 (*read)(struct e1000_hw *, u32 *, u16,  u16);
-	s32 (*write)(struct e1000_hw *, u32 *, u16, u16);
-	s32 (*read_posted)(struct e1000_hw *, u32 *, u16,  u16);
-	s32 (*write_posted)(struct e1000_hw *, u32 *, u16, u16);
-	s32 (*check_for_msg)(struct e1000_hw *, u16);
-	s32 (*check_for_ack)(struct e1000_hw *, u16);
-	s32 (*check_for_rst)(struct e1000_hw *, u16);
-};
-
-struct e1000_mbx_stats {
-	u32 msgs_tx;
-	u32 msgs_rx;
-
-	u32 acks;
-	u32 reqs;
-	u32 rsts;
-};
-
-struct e1000_mbx_info {
-	struct e1000_mbx_operations ops;
-	struct e1000_mbx_stats stats;
-	u32 timeout;
-	u32 usec_delay;
-	u16 size;
-};
-
-struct e1000_dev_spec_82575 {
-	bool sgmii_active;
-	bool global_device_reset;
-};
-
-struct e1000_dev_spec_vf {
-	u32	vf_number;
-	u32	v2p_mailbox;
-};
-
-
-struct e1000_hw {
-	void *back;
-
-	u8 __iomem *hw_addr;
-	u8 __iomem *flash_address;
-	unsigned long io_base;
-
-	struct e1000_mac_info  mac;
-	struct e1000_fc_info   fc;
-	struct e1000_phy_info  phy;
-	struct e1000_nvm_info  nvm;
-	struct e1000_bus_info  bus;
-	struct e1000_mbx_info mbx;
-	struct e1000_host_mng_dhcp_cookie mng_cookie;
-
-	union {
-		struct e1000_dev_spec_82575	_82575;
-		struct e1000_dev_spec_vf	vf;
-	} dev_spec;
-
-	u16 device_id;
-	u16 subsystem_vendor_id;
-	u16 subsystem_device_id;
-	u16 vendor_id;
-
-	u8  revision_id;
-};
-
-#include "igb_82575.h"
-
-/* These functions must be implemented by drivers */
-s32  igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
-s32  igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
-
-#endif /* _IGB_HW_H_ */
diff --git a/roms/ipxe/src/drivers/net/igb/igb_mac.c b/roms/ipxe/src/drivers/net/igb/igb_mac.c
deleted file mode 100644
index 237c6c75242e5b1da7a8831abf697348d70e5ef1..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_mac.c
+++ /dev/null
@@ -1,1991 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#include "igb.h"
-
-static s32 igb_set_default_fc_generic(struct e1000_hw *hw);
-static s32 igb_commit_fc_settings_generic(struct e1000_hw *hw);
-static s32 igb_poll_fiber_serdes_link_generic(struct e1000_hw *hw);
-static s32 igb_validate_mdi_setting_generic(struct e1000_hw *hw);
-static void igb_set_lan_id_multi_port_pcie(struct e1000_hw *hw);
-
-/**
- *  igb_init_mac_ops_generic - Initialize MAC function pointers
- *  @hw: pointer to the HW structure
- *
- *  Setups up the function pointers to no-op functions
- **/
-void igb_init_mac_ops_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	DEBUGFUNC("igb_init_mac_ops_generic");
-
-	/* General Setup */
-	mac->ops.set_lan_id = igb_set_lan_id_multi_port_pcie;
-	mac->ops.read_mac_addr = igb_read_mac_addr_generic;
-	mac->ops.config_collision_dist = igb_config_collision_dist_generic;
-	/* LINK */
-	mac->ops.wait_autoneg = igb_wait_autoneg_generic;
-	/* Management */
-#if 0
-	mac->ops.mng_host_if_write = igb_mng_host_if_write_generic;
-	mac->ops.mng_write_cmd_header = igb_mng_write_cmd_header_generic;
-	mac->ops.mng_enable_host_if = igb_mng_enable_host_if_generic;
-#endif
-	/* VLAN, MC, etc. */
-	mac->ops.rar_set = igb_rar_set_generic;
-	mac->ops.validate_mdi_setting = igb_validate_mdi_setting_generic;
-}
-
-/**
- *  igb_get_bus_info_pcie_generic - Get PCIe bus information
- *  @hw: pointer to the HW structure
- *
- *  Determines and stores the system bus information for a particular
- *  network interface.  The following bus information is determined and stored:
- *  bus speed, bus width, type (PCIe), and PCIe function.
- **/
-s32 igb_get_bus_info_pcie_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	struct e1000_bus_info *bus = &hw->bus;
-
-	s32 ret_val;
-	u16 pcie_link_status;
-
-	DEBUGFUNC("igb_get_bus_info_pcie_generic");
-
-	bus->type = e1000_bus_type_pci_express;
-	bus->speed = e1000_bus_speed_2500;
-
-	ret_val = igb_read_pcie_cap_reg(hw,
-	                                  PCIE_LINK_STATUS,
-	                                  &pcie_link_status);
-	if (ret_val)
-		bus->width = e1000_bus_width_unknown;
-	else
-		bus->width = (enum e1000_bus_width)((pcie_link_status &
-		                                PCIE_LINK_WIDTH_MASK) >>
-		                               PCIE_LINK_WIDTH_SHIFT);
-
-	mac->ops.set_lan_id(hw);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices
- *
- *  @hw: pointer to the HW structure
- *
- *  Determines the LAN function id by reading memory-mapped registers
- *  and swaps the port value if requested.
- **/
-static void igb_set_lan_id_multi_port_pcie(struct e1000_hw *hw)
-{
-	struct e1000_bus_info *bus = &hw->bus;
-	u32 reg;
-
-	/*
-	 * The status register reports the correct function number
-	 * for the device regardless of function swap state.
-	 */
-	reg = E1000_READ_REG(hw, E1000_STATUS);
-	bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
-}
-
-/**
- *  igb_set_lan_id_single_port - Set LAN id for a single port device
- *  @hw: pointer to the HW structure
- *
- *  Sets the LAN function id to zero for a single port device.
- **/
-void igb_set_lan_id_single_port(struct e1000_hw *hw)
-{
-	struct e1000_bus_info *bus = &hw->bus;
-
-	bus->func = 0;
-}
-
-/**
- *  igb_clear_vfta_generic - Clear VLAN filter table
- *  @hw: pointer to the HW structure
- *
- *  Clears the register array which contains the VLAN filter table by
- *  setting all the values to 0.
- **/
-void igb_clear_vfta_generic(struct e1000_hw *hw)
-{
-	u32 offset;
-
-	DEBUGFUNC("igb_clear_vfta_generic");
-
-	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
-                E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0);
-		E1000_WRITE_FLUSH(hw);
-	}
-}
-
-/**
- *  igb_write_vfta_generic - Write value to VLAN filter table
- *  @hw: pointer to the HW structure
- *  @offset: register offset in VLAN filter table
- *  @value: register value written to VLAN filter table
- *
- *  Writes value at the given offset in the register array which stores
- *  the VLAN filter table.
- **/
-void igb_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value)
-{
-	DEBUGFUNC("igb_write_vfta_generic");
-
-	E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
-	E1000_WRITE_FLUSH(hw);
-}
-
-/**
- *  igb_init_rx_addrs_generic - Initialize receive address's
- *  @hw: pointer to the HW structure
- *  @rar_count: receive address registers
- *
- *  Setups the receive address registers by setting the base receive address
- *  register to the devices MAC address and clearing all the other receive
- *  address registers to 0.
- **/
-void igb_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count)
-{
-	u32 i;
-	u8 mac_addr[ETH_ADDR_LEN] = {0};
-
-	DEBUGFUNC("igb_init_rx_addrs_generic");
-
-	/* Setup the receive address */
-	DEBUGOUT("Programming MAC Address into RAR[0]\n");
-
-	hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
-
-	/* Zero out the other (rar_entry_count - 1) receive addresses */
-	DEBUGOUT1("Clearing RAR[1-%u]\n", rar_count-1);
-	for (i = 1; i < rar_count; i++)
-		hw->mac.ops.rar_set(hw, mac_addr, i);
-}
-
-/**
- *  igb_check_alt_mac_addr_generic - Check for alternate MAC addr
- *  @hw: pointer to the HW structure
- *
- *  Checks the nvm for an alternate MAC address.  An alternate MAC address
- *  can be setup by pre-boot software and must be treated like a permanent
- *  address and must override the actual permanent MAC address. If an
- *  alternate MAC address is found it is programmed into RAR0, replacing
- *  the permanent address that was installed into RAR0 by the Si on reset.
- *  This function will return SUCCESS unless it encounters an error while
- *  reading the EEPROM.
- **/
-s32 igb_check_alt_mac_addr_generic(struct e1000_hw *hw)
-{
-	u32 i;
-	s32 ret_val = E1000_SUCCESS;
-	u16 offset, nvm_alt_mac_addr_offset, nvm_data;
-	u8 alt_mac_addr[ETH_ADDR_LEN];
-
-	DEBUGFUNC("igb_check_alt_mac_addr_generic");
-
-	ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1,
-	                         &nvm_alt_mac_addr_offset);
-	if (ret_val) {
-		DEBUGOUT("NVM Read Error\n");
-		goto out;
-	}
-
-	if (nvm_alt_mac_addr_offset == 0xFFFF) {
-		/* There is no Alternate MAC Address */
-		goto out;
-	}
-
-	if (hw->bus.func == E1000_FUNC_1)
-		nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1;
-	for (i = 0; i < ETH_ADDR_LEN; i += 2) {
-		offset = nvm_alt_mac_addr_offset + (i >> 1);
-		ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data);
-		if (ret_val) {
-			DEBUGOUT("NVM Read Error\n");
-			goto out;
-		}
-
-		alt_mac_addr[i] = (u8)(nvm_data & 0xFF);
-		alt_mac_addr[i + 1] = (u8)(nvm_data >> 8);
-	}
-
-	/* if multicast bit is set, the alternate address will not be used */
-	if (alt_mac_addr[0] & 0x01) {
-		DEBUGOUT("Ignoring Alternate Mac Address with MC bit set\n");
-		goto out;
-	}
-
-	/*
-	 * We have a valid alternate MAC address, and we want to treat it the
-	 * same as the normal permanent MAC address stored by the HW into the
-	 * RAR. Do this by mapping this address into RAR0.
-	 */
-	hw->mac.ops.rar_set(hw, alt_mac_addr, 0);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_rar_set_generic - Set receive address register
- *  @hw: pointer to the HW structure
- *  @addr: pointer to the receive address
- *  @index: receive address array register
- *
- *  Sets the receive address array register at index to the address passed
- *  in by addr.
- **/
-void igb_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index)
-{
-	u32 rar_low, rar_high;
-
-	DEBUGFUNC("igb_rar_set_generic");
-
-	/*
-	 * HW expects these in little endian so we reverse the byte order
-	 * from network order (big endian) to little endian
-	 */
-	rar_low = ((u32) addr[0] |
-	           ((u32) addr[1] << 8) |
-	           ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
-
-	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
-
-	/* If MAC address zero, no need to set the AV bit */
-	if (rar_low || rar_high)
-		rar_high |= E1000_RAH_AV;
-
-	/*
-	 * Some bridges will combine consecutive 32-bit writes into
-	 * a single burst write, which will malfunction on some parts.
-	 * The flushes avoid this.
-	 */
-	E1000_WRITE_REG(hw, E1000_RAL(index), rar_low);
-	E1000_WRITE_FLUSH(hw);
-	E1000_WRITE_REG(hw, E1000_RAH(index), rar_high);
-	E1000_WRITE_FLUSH(hw);
-}
-
-/**
- *  igb_mta_set_generic - Set multicast filter table address
- *  @hw: pointer to the HW structure
- *  @hash_value: determines the MTA register and bit to set
- *
- *  The multicast table address is a register array of 32-bit registers.
- *  The hash_value is used to determine what register the bit is in, the
- *  current value is read, the new bit is OR'd in and the new value is
- *  written back into the register.
- **/
-void igb_mta_set_generic(struct e1000_hw *hw, u32 hash_value)
-{
-	u32 hash_bit, hash_reg, mta;
-
-	DEBUGFUNC("igb_mta_set_generic");
-	/*
-	 * The MTA is a register array of 32-bit registers. It is
-	 * treated like an array of (32*mta_reg_count) bits.  We want to
-	 * set bit BitArray[hash_value]. So we figure out what register
-	 * the bit is in, read it, OR in the new bit, then write
-	 * back the new value.  The (hw->mac.mta_reg_count - 1) serves as a
-	 * mask to bits 31:5 of the hash value which gives us the
-	 * register we're modifying.  The hash bit within that register
-	 * is determined by the lower 5 bits of the hash value.
-	 */
-	hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
-	hash_bit = hash_value & 0x1F;
-
-	mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg);
-
-	mta |= (1 << hash_bit);
-
-	E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta);
-	E1000_WRITE_FLUSH(hw);
-}
-
-/**
- *  igb_update_mc_addr_list_generic - Update Multicast addresses
- *  @hw: pointer to the HW structure
- *  @mc_addr_list: array of multicast addresses to program
- *  @mc_addr_count: number of multicast addresses to program
- *
- *  Updates entire Multicast Table Array.
- *  The caller must have a packed mc_addr_list of multicast addresses.
- **/
-void igb_update_mc_addr_list_generic(struct e1000_hw *hw,
-                                       u8 *mc_addr_list, u32 mc_addr_count)
-{
-	u32 hash_value, hash_bit, hash_reg;
-	int i;
-
-	DEBUGFUNC("igb_update_mc_addr_list_generic");
-
-	/* clear mta_shadow */
-	memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
-
-	/* update mta_shadow from mc_addr_list */
-	for (i = 0; (u32) i < mc_addr_count; i++) {
-		hash_value = igb_hash_mc_addr_generic(hw, mc_addr_list);
-
-		hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
-		hash_bit = hash_value & 0x1F;
-
-		hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
-		mc_addr_list += (ETH_ADDR_LEN);
-	}
-
-	/* replace the entire MTA table */
-	for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
-		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]);
-	E1000_WRITE_FLUSH(hw);
-}
-
-/**
- *  igb_hash_mc_addr_generic - Generate a multicast hash value
- *  @hw: pointer to the HW structure
- *  @mc_addr: pointer to a multicast address
- *
- *  Generates a multicast address hash value which is used to determine
- *  the multicast filter table array address and new table value.  See
- *  igb_mta_set_generic()
- **/
-u32 igb_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr)
-{
-	u32 hash_value, hash_mask;
-	u8 bit_shift = 0;
-
-	DEBUGFUNC("igb_hash_mc_addr_generic");
-
-	/* Register count multiplied by bits per register */
-	hash_mask = (hw->mac.mta_reg_count * 32) - 1;
-
-	/*
-	 * For a mc_filter_type of 0, bit_shift is the number of left-shifts
-	 * where 0xFF would still fall within the hash mask.
-	 */
-	while (hash_mask >> bit_shift != 0xFF)
-		bit_shift++;
-
-	/*
-	 * The portion of the address that is used for the hash table
-	 * is determined by the mc_filter_type setting.
-	 * The algorithm is such that there is a total of 8 bits of shifting.
-	 * The bit_shift for a mc_filter_type of 0 represents the number of
-	 * left-shifts where the MSB of mc_addr[5] would still fall within
-	 * the hash_mask.  Case 0 does this exactly.  Since there are a total
-	 * of 8 bits of shifting, then mc_addr[4] will shift right the
-	 * remaining number of bits. Thus 8 - bit_shift.  The rest of the
-	 * cases are a variation of this algorithm...essentially raising the
-	 * number of bits to shift mc_addr[5] left, while still keeping the
-	 * 8-bit shifting total.
-	 *
-	 * For example, given the following Destination MAC Address and an
-	 * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
-	 * we can see that the bit_shift for case 0 is 4.  These are the hash
-	 * values resulting from each mc_filter_type...
-	 * [0] [1] [2] [3] [4] [5]
-	 * 01  AA  00  12  34  56
-	 * LSB                 MSB
-	 *
-	 * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
-	 * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
-	 * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
-	 * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
-	 */
-	switch (hw->mac.mc_filter_type) {
-	default:
-	case 0:
-		break;
-	case 1:
-		bit_shift += 1;
-		break;
-	case 2:
-		bit_shift += 2;
-		break;
-	case 3:
-		bit_shift += 4;
-		break;
-	}
-
-	hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
-	                          (((u16) mc_addr[5]) << bit_shift)));
-
-	return hash_value;
-}
-
-/**
- *  igb_clear_hw_cntrs_base_generic - Clear base hardware counters
- *  @hw: pointer to the HW structure
- *
- *  Clears the base hardware counters by reading the counter registers.
- **/
-void igb_clear_hw_cntrs_base_generic(struct e1000_hw *hw)
-{
-	DEBUGFUNC("igb_clear_hw_cntrs_base_generic");
-
-	E1000_READ_REG(hw, E1000_CRCERRS);
-	E1000_READ_REG(hw, E1000_SYMERRS);
-	E1000_READ_REG(hw, E1000_MPC);
-	E1000_READ_REG(hw, E1000_SCC);
-	E1000_READ_REG(hw, E1000_ECOL);
-	E1000_READ_REG(hw, E1000_MCC);
-	E1000_READ_REG(hw, E1000_LATECOL);
-	E1000_READ_REG(hw, E1000_COLC);
-	E1000_READ_REG(hw, E1000_DC);
-	E1000_READ_REG(hw, E1000_SEC);
-	E1000_READ_REG(hw, E1000_RLEC);
-	E1000_READ_REG(hw, E1000_XONRXC);
-	E1000_READ_REG(hw, E1000_XONTXC);
-	E1000_READ_REG(hw, E1000_XOFFRXC);
-	E1000_READ_REG(hw, E1000_XOFFTXC);
-	E1000_READ_REG(hw, E1000_FCRUC);
-	E1000_READ_REG(hw, E1000_GPRC);
-	E1000_READ_REG(hw, E1000_BPRC);
-	E1000_READ_REG(hw, E1000_MPRC);
-	E1000_READ_REG(hw, E1000_GPTC);
-	E1000_READ_REG(hw, E1000_GORCL);
-	E1000_READ_REG(hw, E1000_GORCH);
-	E1000_READ_REG(hw, E1000_GOTCL);
-	E1000_READ_REG(hw, E1000_GOTCH);
-	E1000_READ_REG(hw, E1000_RNBC);
-	E1000_READ_REG(hw, E1000_RUC);
-	E1000_READ_REG(hw, E1000_RFC);
-	E1000_READ_REG(hw, E1000_ROC);
-	E1000_READ_REG(hw, E1000_RJC);
-	E1000_READ_REG(hw, E1000_TORL);
-	E1000_READ_REG(hw, E1000_TORH);
-	E1000_READ_REG(hw, E1000_TOTL);
-	E1000_READ_REG(hw, E1000_TOTH);
-	E1000_READ_REG(hw, E1000_TPR);
-	E1000_READ_REG(hw, E1000_TPT);
-	E1000_READ_REG(hw, E1000_MPTC);
-	E1000_READ_REG(hw, E1000_BPTC);
-}
-
-/**
- *  igb_check_for_copper_link_generic - Check for link (Copper)
- *  @hw: pointer to the HW structure
- *
- *  Checks to see of the link status of the hardware has changed.  If a
- *  change in link status has been detected, then we read the PHY registers
- *  to get the current speed/duplex if link exists.
- **/
-s32 igb_check_for_copper_link_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val;
-	bool link;
-
-	DEBUGFUNC("igb_check_for_copper_link");
-
-	/*
-	 * We only want to go out to the PHY registers to see if Auto-Neg
-	 * has completed and/or if our link status has changed.  The
-	 * get_link_status flag is set upon receiving a Link Status
-	 * Change or Rx Sequence Error interrupt.
-	 */
-	if (!mac->get_link_status) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	/*
-	 * First we want to see if the MII Status Register reports
-	 * link.  If so, then we want to get the current speed/duplex
-	 * of the PHY.
-	 */
-	ret_val = igb_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		goto out;
-
-	if (!link)
-		goto out; /* No link detected */
-
-	mac->get_link_status = false;
-
-	/*
-	 * Check if there was DownShift, must be checked
-	 * immediately after link-up
-	 */
-	igb_check_downshift_generic(hw);
-
-	/*
-	 * If we are forcing speed/duplex, then we simply return since
-	 * we have already determined whether we have link or not.
-	 */
-	if (!mac->autoneg) {
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	/*
-	 * Auto-Neg is enabled.  Auto Speed Detection takes care
-	 * of MAC speed/duplex configuration.  So we only need to
-	 * configure Collision Distance in the MAC.
-	 */
-	igb_config_collision_dist_generic(hw);
-
-	/*
-	 * Configure Flow Control now that Auto-Neg has completed.
-	 * First, we need to restore the desired flow control
-	 * settings because we may have had to re-autoneg with a
-	 * different link partner.
-	 */
-	ret_val = igb_config_fc_after_link_up_generic(hw);
-	if (ret_val) {
-		DEBUGOUT("Error configuring flow control\n");
-        }
-out:
-	return ret_val;
-}
-
-/**
- *  igb_check_for_fiber_link_generic - Check for link (Fiber)
- *  @hw: pointer to the HW structure
- *
- *  Checks for link up on the hardware.  If link is not up and we have
- *  a signal, then we need to force link up.
- **/
-s32 igb_check_for_fiber_link_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 rxcw;
-	u32 ctrl;
-	u32 status;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_check_for_fiber_link_generic");
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	status = E1000_READ_REG(hw, E1000_STATUS);
-	rxcw = E1000_READ_REG(hw, E1000_RXCW);
-
-	/*
-	 * If we don't have link (auto-negotiation failed or link partner
-	 * cannot auto-negotiate), the cable is plugged in (we have signal),
-	 * and our link partner is not trying to auto-negotiate with us (we
-	 * are receiving idles or data), we need to force link up. We also
-	 * need to give auto-negotiation time to complete, in case the cable
-	 * was just plugged in. The autoneg_failed flag does this.
-	 */
-	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
-	if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) &&
-	    (!(rxcw & E1000_RXCW_C))) {
-		if (mac->autoneg_failed == 0) {
-			mac->autoneg_failed = 1;
-			goto out;
-		}
-		DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
-
-		/* Disable auto-negotiation in the TXCW register */
-		E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
-
-		/* Force link-up and also force full-duplex. */
-		ctrl = E1000_READ_REG(hw, E1000_CTRL);
-		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-		/* Configure Flow Control after forcing link up. */
-		ret_val = igb_config_fc_after_link_up_generic(hw);
-		if (ret_val) {
-			DEBUGOUT("Error configuring flow control\n");
-			goto out;
-		}
-	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
-		/*
-		 * If we are forcing link and we are receiving /C/ ordered
-		 * sets, re-enable auto-negotiation in the TXCW register
-		 * and disable forced link in the Device Control register
-		 * in an attempt to auto-negotiate with our link partner.
-		 */
-		DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
-		E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
-		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
-
-		mac->serdes_has_link = true;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_check_for_serdes_link_generic - Check for link (Serdes)
- *  @hw: pointer to the HW structure
- *
- *  Checks for link up on the hardware.  If link is not up and we have
- *  a signal, then we need to force link up.
- **/
-s32 igb_check_for_serdes_link_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 rxcw;
-	u32 ctrl;
-	u32 status;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_check_for_serdes_link_generic");
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	status = E1000_READ_REG(hw, E1000_STATUS);
-	rxcw = E1000_READ_REG(hw, E1000_RXCW);
-
-	/*
-	 * If we don't have link (auto-negotiation failed or link partner
-	 * cannot auto-negotiate), and our link partner is not trying to
-	 * auto-negotiate with us (we are receiving idles or data),
-	 * we need to force link up. We also need to give auto-negotiation
-	 * time to complete.
-	 */
-	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
-	if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) {
-		if (mac->autoneg_failed == 0) {
-			mac->autoneg_failed = 1;
-			goto out;
-		}
-		DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
-
-		/* Disable auto-negotiation in the TXCW register */
-		E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE));
-
-		/* Force link-up and also force full-duplex. */
-		ctrl = E1000_READ_REG(hw, E1000_CTRL);
-		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-		/* Configure Flow Control after forcing link up. */
-		ret_val = igb_config_fc_after_link_up_generic(hw);
-		if (ret_val) {
-			DEBUGOUT("Error configuring flow control\n");
-			goto out;
-		}
-	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
-		/*
-		 * If we are forcing link and we are receiving /C/ ordered
-		 * sets, re-enable auto-negotiation in the TXCW register
-		 * and disable forced link in the Device Control register
-		 * in an attempt to auto-negotiate with our link partner.
-		 */
-		DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
-		E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw);
-		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU));
-
-		mac->serdes_has_link = true;
-	} else if (!(E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW))) {
-		/*
-		 * If we force link for non-auto-negotiation switch, check
-		 * link status based on MAC synchronization for internal
-		 * serdes media type.
-		 */
-		/* SYNCH bit and IV bit are sticky. */
-		usec_delay(10);
-		rxcw = E1000_READ_REG(hw, E1000_RXCW);
-		if (rxcw & E1000_RXCW_SYNCH) {
-			if (!(rxcw & E1000_RXCW_IV)) {
-				mac->serdes_has_link = true;
-				DEBUGOUT("SERDES: Link up - forced.\n");
-			}
-		} else {
-			mac->serdes_has_link = false;
-			DEBUGOUT("SERDES: Link down - force failed.\n");
-		}
-	}
-
-	if (E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW)) {
-		status = E1000_READ_REG(hw, E1000_STATUS);
-		if (status & E1000_STATUS_LU) {
-			/* SYNCH bit and IV bit are sticky, so reread rxcw. */
-			usec_delay(10);
-			rxcw = E1000_READ_REG(hw, E1000_RXCW);
-			if (rxcw & E1000_RXCW_SYNCH) {
-				if (!(rxcw & E1000_RXCW_IV)) {
-					mac->serdes_has_link = true;
-					DEBUGOUT("SERDES: Link up - autoneg "
-					   "completed sucessfully.\n");
-				} else {
-					mac->serdes_has_link = false;
-					DEBUGOUT("SERDES: Link down - invalid"
-					   "codewords detected in autoneg.\n");
-				}
-			} else {
-				mac->serdes_has_link = false;
-				DEBUGOUT("SERDES: Link down - no sync.\n");
-			}
-		} else {
-			mac->serdes_has_link = false;
-			DEBUGOUT("SERDES: Link down - autoneg failed\n");
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_setup_link_generic - Setup flow control and link settings
- *  @hw: pointer to the HW structure
- *
- *  Determines which flow control settings to use, then configures flow
- *  control.  Calls the appropriate media-specific link configuration
- *  function.  Assuming the adapter has a valid link partner, a valid link
- *  should be established.  Assumes the hardware has previously been reset
- *  and the transmitter and receiver are not enabled.
- **/
-s32 igb_setup_link_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_setup_link_generic");
-
-	/*
-	 * In the case of the phy reset being blocked, we already have a link.
-	 * We do not need to set it up again.
-	 */
-	if (hw->phy.ops.check_reset_block)
-		if (hw->phy.ops.check_reset_block(hw))
-			goto out;
-
-	/*
-	 * If requested flow control is set to default, set flow control
-	 * based on the EEPROM flow control settings.
-	 */
-	if (hw->fc.requested_mode == e1000_fc_default) {
-		ret_val = igb_set_default_fc_generic(hw);
-		if (ret_val)
-			goto out;
-	}
-
-	/*
-	 * Save off the requested flow control mode for use later.  Depending
-	 * on the link partner's capabilities, we may or may not use this mode.
-	 */
-	hw->fc.current_mode = hw->fc.requested_mode;
-
-	DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
-		hw->fc.current_mode);
-
-	/* Call the necessary media_type subroutine to configure the link. */
-	ret_val = hw->mac.ops.setup_physical_interface(hw);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Initialize the flow control address, type, and PAUSE timer
-	 * registers to their default values.  This is done even if flow
-	 * control is disabled, because it does not hurt anything to
-	 * initialize these registers.
-	 */
-	DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
-	E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE);
-	E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
-	E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
-
-	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
-
-	ret_val = igb_set_fc_watermarks_generic(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_setup_fiber_serdes_link_generic - Setup link for fiber/serdes
- *  @hw: pointer to the HW structure
- *
- *  Configures collision distance and flow control for fiber and serdes
- *  links.  Upon successful setup, poll for link.
- **/
-s32 igb_setup_fiber_serdes_link_generic(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_setup_fiber_serdes_link_generic");
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	/* Take the link out of reset */
-	ctrl &= ~E1000_CTRL_LRST;
-
-	igb_config_collision_dist_generic(hw);
-
-	ret_val = igb_commit_fc_settings_generic(hw);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Since auto-negotiation is enabled, take the link out of reset (the
-	 * link will be in reset, because we previously reset the chip). This
-	 * will restart auto-negotiation.  If auto-negotiation is successful
-	 * then the link-up status bit will be set and the flow control enable
-	 * bits (RFCE and TFCE) will be set according to their negotiated value.
-	 */
-	DEBUGOUT("Auto-negotiation enabled\n");
-
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-	E1000_WRITE_FLUSH(hw);
-	msec_delay(1);
-
-	/*
-	 * For these adapters, the SW definable pin 1 is set when the optics
-	 * detect a signal.  If we have a signal, then poll for a "Link-Up"
-	 * indication.
-	 */
-	if (hw->phy.media_type == e1000_media_type_internal_serdes ||
-	    (E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) {
-		ret_val = igb_poll_fiber_serdes_link_generic(hw);
-	} else {
-		DEBUGOUT("No signal detected\n");
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_config_collision_dist_generic - Configure collision distance
- *  @hw: pointer to the HW structure
- *
- *  Configures the collision distance to the default value and is used
- *  during link setup. Currently no func pointer exists and all
- *  implementations are handled in the generic version of this function.
- **/
-void igb_config_collision_dist_generic(struct e1000_hw *hw)
-{
-	u32 tctl;
-
-	DEBUGFUNC("igb_config_collision_dist_generic");
-
-	tctl = E1000_READ_REG(hw, E1000_TCTL);
-
-	tctl &= ~E1000_TCTL_COLD;
-	tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
-
-	E1000_WRITE_REG(hw, E1000_TCTL, tctl);
-	E1000_WRITE_FLUSH(hw);
-}
-
-/**
- *  igb_poll_fiber_serdes_link_generic - Poll for link up
- *  @hw: pointer to the HW structure
- *
- *  Polls for link up by reading the status register, if link fails to come
- *  up with auto-negotiation, then the link is forced if a signal is detected.
- **/
-static s32 igb_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 i, status;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_poll_fiber_serdes_link_generic");
-
-	/*
-	 * If we have a signal (the cable is plugged in, or assumed true for
-	 * serdes media) then poll for a "Link-Up" indication in the Device
-	 * Status Register.  Time-out if a link isn't seen in 500 milliseconds
-	 * seconds (Auto-negotiation should complete in less than 500
-	 * milliseconds even if the other end is doing it in SW).
-	 */
-	for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
-		msec_delay(10);
-		status = E1000_READ_REG(hw, E1000_STATUS);
-		if (status & E1000_STATUS_LU)
-			break;
-	}
-	if (i == FIBER_LINK_UP_LIMIT) {
-		DEBUGOUT("Never got a valid link from auto-neg!!!\n");
-		mac->autoneg_failed = 1;
-		/*
-		 * AutoNeg failed to achieve a link, so we'll call
-		 * mac->check_for_link. This routine will force the
-		 * link up if we detect a signal. This will allow us to
-		 * communicate with non-autonegotiating link partners.
-		 */
-		ret_val = hw->mac.ops.check_for_link(hw);
-		if (ret_val) {
-			DEBUGOUT("Error while checking for link\n");
-			goto out;
-		}
-		mac->autoneg_failed = 0;
-	} else {
-		mac->autoneg_failed = 0;
-		DEBUGOUT("Valid Link Found\n");
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_commit_fc_settings_generic - Configure flow control
- *  @hw: pointer to the HW structure
- *
- *  Write the flow control settings to the Transmit Config Word Register (TXCW)
- *  base on the flow control settings in e1000_mac_info.
- **/
-static s32 igb_commit_fc_settings_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 txcw;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_commit_fc_settings_generic");
-
-	/*
-	 * Check for a software override of the flow control settings, and
-	 * setup the device accordingly.  If auto-negotiation is enabled, then
-	 * software will have to set the "PAUSE" bits to the correct value in
-	 * the Transmit Config Word Register (TXCW) and re-start auto-
-	 * negotiation.  However, if auto-negotiation is disabled, then
-	 * software will have to manually configure the two flow control enable
-	 * bits in the CTRL register.
-	 *
-	 * The possible values of the "fc" parameter are:
-	 *      0:  Flow control is completely disabled
-	 *      1:  Rx flow control is enabled (we can receive pause frames,
-	 *          but not send pause frames).
-	 *      2:  Tx flow control is enabled (we can send pause frames but we
-	 *          do not support receiving pause frames).
-	 *      3:  Both Rx and Tx flow control (symmetric) are enabled.
-	 */
-	switch (hw->fc.current_mode) {
-	case e1000_fc_none:
-		/* Flow control completely disabled by a software over-ride. */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
-		break;
-	case e1000_fc_rx_pause:
-		/*
-		 * Rx Flow control is enabled and Tx Flow control is disabled
-		 * by a software over-ride. Since there really isn't a way to
-		 * advertise that we are capable of Rx Pause ONLY, we will
-		 * advertise that we support both symmetric and asymmetric RX
-		 * PAUSE.  Later, we will disable the adapter's ability to send
-		 * PAUSE frames.
-		 */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
-		break;
-	case e1000_fc_tx_pause:
-		/*
-		 * Tx Flow control is enabled, and Rx Flow control is disabled,
-		 * by a software over-ride.
-		 */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
-		break;
-	case e1000_fc_full:
-		/*
-		 * Flow control (both Rx and Tx) is enabled by a software
-		 * over-ride.
-		 */
-		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
-		break;
-	default:
-		DEBUGOUT("Flow control param set incorrectly\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-		break;
-	}
-
-	E1000_WRITE_REG(hw, E1000_TXCW, txcw);
-	mac->txcw = txcw;
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_set_fc_watermarks_generic - Set flow control high/low watermarks
- *  @hw: pointer to the HW structure
- *
- *  Sets the flow control high/low threshold (watermark) registers.  If
- *  flow control XON frame transmission is enabled, then set XON frame
- *  transmission as well.
- **/
-s32 igb_set_fc_watermarks_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u32 fcrtl = 0, fcrth = 0;
-
-	DEBUGFUNC("igb_set_fc_watermarks_generic");
-
-	/*
-	 * Set the flow control receive threshold registers.  Normally,
-	 * these registers will be set to a default threshold that may be
-	 * adjusted later by the driver's runtime code.  However, if the
-	 * ability to transmit pause frames is not enabled, then these
-	 * registers will be set to 0.
-	 */
-	if (hw->fc.current_mode & e1000_fc_tx_pause) {
-		/*
-		 * We need to set up the Receive Threshold high and low water
-		 * marks as well as (optionally) enabling the transmission of
-		 * XON frames.
-		 */
-		fcrtl = hw->fc.low_water;
-		if (hw->fc.send_xon)
-			fcrtl |= E1000_FCRTL_XONE;
-
-		fcrth = hw->fc.high_water;
-	}
-	E1000_WRITE_REG(hw, E1000_FCRTL, fcrtl);
-	E1000_WRITE_REG(hw, E1000_FCRTH, fcrth);
-
-	return ret_val;
-}
-
-/**
- *  igb_set_default_fc_generic - Set flow control default values
- *  @hw: pointer to the HW structure
- *
- *  Read the EEPROM for the default values for flow control and store the
- *  values.
- **/
-static s32 igb_set_default_fc_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 nvm_data;
-
-	DEBUGFUNC("igb_set_default_fc_generic");
-
-	/*
-	 * Read and store word 0x0F of the EEPROM. This word contains bits
-	 * that determine the hardware's default PAUSE (flow control) mode,
-	 * a bit that determines whether the HW defaults to enabling or
-	 * disabling auto-negotiation, and the direction of the
-	 * SW defined pins. If there is no SW over-ride of the flow
-	 * control setting, then the variable hw->fc will
-	 * be initialized based on a value in the EEPROM.
-	 */
-	ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
-
-	if (ret_val) {
-		DEBUGOUT("NVM Read Error\n");
-		goto out;
-	}
-
-	if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
-		hw->fc.requested_mode = e1000_fc_none;
-	else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
-		 NVM_WORD0F_ASM_DIR)
-		hw->fc.requested_mode = e1000_fc_tx_pause;
-	else
-		hw->fc.requested_mode = e1000_fc_full;
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_force_mac_fc_generic - Force the MAC's flow control settings
- *  @hw: pointer to the HW structure
- *
- *  Force the MAC's flow control settings.  Sets the TFCE and RFCE bits in the
- *  device control register to reflect the adapter settings.  TFCE and RFCE
- *  need to be explicitly set by software when a copper PHY is used because
- *  autonegotiation is managed by the PHY rather than the MAC.  Software must
- *  also configure these bits when link is forced on a fiber connection.
- **/
-s32 igb_force_mac_fc_generic(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_force_mac_fc_generic");
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-
-	/*
-	 * Because we didn't get link via the internal auto-negotiation
-	 * mechanism (we either forced link or we got link via PHY
-	 * auto-neg), we have to manually enable/disable transmit an
-	 * receive flow control.
-	 *
-	 * The "Case" statement below enables/disable flow control
-	 * according to the "hw->fc.current_mode" parameter.
-	 *
-	 * The possible values of the "fc" parameter are:
-	 *      0:  Flow control is completely disabled
-	 *      1:  Rx flow control is enabled (we can receive pause
-	 *          frames but not send pause frames).
-	 *      2:  Tx flow control is enabled (we can send pause frames
-	 *          frames but we do not receive pause frames).
-	 *      3:  Both Rx and Tx flow control (symmetric) is enabled.
-	 *  other:  No other values should be possible at this point.
-	 */
-	DEBUGOUT1("hw->fc.current_mode = %u\n", hw->fc.current_mode);
-
-	switch (hw->fc.current_mode) {
-	case e1000_fc_none:
-		ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
-		break;
-	case e1000_fc_rx_pause:
-		ctrl &= (~E1000_CTRL_TFCE);
-		ctrl |= E1000_CTRL_RFCE;
-		break;
-	case e1000_fc_tx_pause:
-		ctrl &= (~E1000_CTRL_RFCE);
-		ctrl |= E1000_CTRL_TFCE;
-		break;
-	case e1000_fc_full:
-		ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
-		break;
-	default:
-		DEBUGOUT("Flow control param set incorrectly\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_config_fc_after_link_up_generic - Configures flow control after link
- *  @hw: pointer to the HW structure
- *
- *  Checks the status of auto-negotiation after link up to ensure that the
- *  speed and duplex were not forced.  If the link needed to be forced, then
- *  flow control needs to be forced also.  If auto-negotiation is enabled
- *  and did not fail, then we configure flow control based on our link
- *  partner.
- **/
-s32 igb_config_fc_after_link_up_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val = E1000_SUCCESS;
-	u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
-	u16 speed, duplex;
-
-	DEBUGFUNC("igb_config_fc_after_link_up_generic");
-
-	/*
-	 * Check for the case where we have fiber media and auto-neg failed
-	 * so we had to force link.  In this case, we need to force the
-	 * configuration of the MAC to match the "fc" parameter.
-	 */
-	if (mac->autoneg_failed) {
-		if (hw->phy.media_type == e1000_media_type_fiber ||
-		    hw->phy.media_type == e1000_media_type_internal_serdes)
-			ret_val = igb_force_mac_fc_generic(hw);
-	} else {
-		if (hw->phy.media_type == e1000_media_type_copper)
-			ret_val = igb_force_mac_fc_generic(hw);
-	}
-
-	if (ret_val) {
-		DEBUGOUT("Error forcing flow control settings\n");
-		goto out;
-	}
-
-	/*
-	 * Check for the case where we have copper media and auto-neg is
-	 * enabled.  In this case, we need to check and see if Auto-Neg
-	 * has completed, and if so, how the PHY and link partner has
-	 * flow control configured.
-	 */
-	if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) {
-		/*
-		 * Read the MII Status Register and check to see if AutoNeg
-		 * has completed.  We read this twice because this reg has
-		 * some "sticky" (latched) bits.
-		 */
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
-		if (ret_val)
-			goto out;
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg);
-		if (ret_val)
-			goto out;
-
-		if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
-			DEBUGOUT("Copper PHY and Auto Neg "
-			         "has not completed.\n");
-			goto out;
-		}
-
-		/*
-		 * The AutoNeg process has completed, so we now need to
-		 * read both the Auto Negotiation Advertisement
-		 * Register (Address 4) and the Auto_Negotiation Base
-		 * Page Ability Register (Address 5) to determine how
-		 * flow control was negotiated.
-		 */
-		ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV,
-		                             &mii_nway_adv_reg);
-		if (ret_val)
-			goto out;
-		ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY,
-		                             &mii_nway_lp_ability_reg);
-		if (ret_val)
-			goto out;
-
-		/*
-		 * Two bits in the Auto Negotiation Advertisement Register
-		 * (Address 4) and two bits in the Auto Negotiation Base
-		 * Page Ability Register (Address 5) determine flow control
-		 * for both the PHY and the link partner.  The following
-		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
-		 * 1999, describes these PAUSE resolution bits and how flow
-		 * control is determined based upon these settings.
-		 * NOTE:  DC = Don't Care
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
-		 *-------|---------|-------|---------|--------------------
-		 *   0   |    0    |  DC   |   DC    | e1000_fc_none
-		 *   0   |    1    |   0   |   DC    | e1000_fc_none
-		 *   0   |    1    |   1   |    0    | e1000_fc_none
-		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
-		 *   1   |    0    |   0   |   DC    | e1000_fc_none
-		 *   1   |   DC    |   1   |   DC    | e1000_fc_full
-		 *   1   |    1    |   0   |    0    | e1000_fc_none
-		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
-		 *
-		 * Are both PAUSE bits set to 1?  If so, this implies
-		 * Symmetric Flow Control is enabled at both ends.  The
-		 * ASM_DIR bits are irrelevant per the spec.
-		 *
-		 * For Symmetric Flow Control:
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-		 *-------|---------|-------|---------|--------------------
-		 *   1   |   DC    |   1   |   DC    | E1000_fc_full
-		 *
-		 */
-		if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-		    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
-			/*
-			 * Now we need to check if the user selected Rx ONLY
-			 * of pause frames.  In this case, we had to advertise
-			 * FULL flow control because we could not advertise RX
-			 * ONLY. Hence, we must now check to see if we need to
-			 * turn OFF  the TRANSMISSION of PAUSE frames.
-			 */
-			if (hw->fc.requested_mode == e1000_fc_full) {
-				hw->fc.current_mode = e1000_fc_full;
-				DEBUGOUT("Flow Control = FULL.\r\n");
-			} else {
-				hw->fc.current_mode = e1000_fc_rx_pause;
-				DEBUGOUT("Flow Control = "
-				         "RX PAUSE frames only.\r\n");
-			}
-		}
-		/*
-		 * For receiving PAUSE frames ONLY.
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-		 *-------|---------|-------|---------|--------------------
-		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
-		 */
-		else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-		          (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
-		          (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
-		          (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
-			hw->fc.current_mode = e1000_fc_tx_pause;
-			DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
-		}
-		/*
-		 * For transmitting PAUSE frames ONLY.
-		 *
-		 *   LOCAL DEVICE  |   LINK PARTNER
-		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-		 *-------|---------|-------|---------|--------------------
-		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
-		 */
-		else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-		         (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
-		         !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
-		         (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
-			hw->fc.current_mode = e1000_fc_rx_pause;
-			DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
-		} else {
-			/*
-			 * Per the IEEE spec, at this point flow control
-			 * should be disabled.
-			 */
-			hw->fc.current_mode = e1000_fc_none;
-			DEBUGOUT("Flow Control = NONE.\r\n");
-		}
-
-		/*
-		 * Now we need to do one last check...  If we auto-
-		 * negotiated to HALF DUPLEX, flow control should not be
-		 * enabled per IEEE 802.3 spec.
-		 */
-		ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
-		if (ret_val) {
-			DEBUGOUT("Error getting link speed and duplex\n");
-			goto out;
-		}
-
-		if (duplex == HALF_DUPLEX)
-			hw->fc.current_mode = e1000_fc_none;
-
-		/*
-		 * Now we call a subroutine to actually force the MAC
-		 * controller to use the correct flow control settings.
-		 */
-		ret_val = igb_force_mac_fc_generic(hw);
-		if (ret_val) {
-			DEBUGOUT("Error forcing flow control settings\n");
-			goto out;
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_get_speed_and_duplex_copper_generic - Retrieve current speed/duplex
- *  @hw: pointer to the HW structure
- *  @speed: stores the current speed
- *  @duplex: stores the current duplex
- *
- *  Read the status register for the current speed/duplex and store the current
- *  speed and duplex for copper connections.
- **/
-s32 igb_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed,
-                                              u16 *duplex)
-{
-	u32 status;
-
-	DEBUGFUNC("igb_get_speed_and_duplex_copper_generic");
-
-	status = E1000_READ_REG(hw, E1000_STATUS);
-	if (status & E1000_STATUS_SPEED_1000) {
-		*speed = SPEED_1000;
-		DEBUGOUT("1000 Mbs, ");
-	} else if (status & E1000_STATUS_SPEED_100) {
-		*speed = SPEED_100;
-		DEBUGOUT("100 Mbs, ");
-	} else {
-		*speed = SPEED_10;
-		DEBUGOUT("10 Mbs, ");
-	}
-
-	if (status & E1000_STATUS_FD) {
-		*duplex = FULL_DUPLEX;
-		DEBUGOUT("Full Duplex\n");
-	} else {
-		*duplex = HALF_DUPLEX;
-		DEBUGOUT("Half Duplex\n");
-	}
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_get_speed_and_duplex_fiber_generic - Retrieve current speed/duplex
- *  @hw: pointer to the HW structure
- *  @speed: stores the current speed
- *  @duplex: stores the current duplex
- *
- *  Sets the speed and duplex to gigabit full duplex (the only possible option)
- *  for fiber/serdes links.
- **/
-s32 igb_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw __unused,
-                                                  u16 *speed, u16 *duplex)
-{
-	DEBUGFUNC("igb_get_speed_and_duplex_fiber_serdes_generic");
-
-	*speed = SPEED_1000;
-	*duplex = FULL_DUPLEX;
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_get_hw_semaphore_generic - Acquire hardware semaphore
- *  @hw: pointer to the HW structure
- *
- *  Acquire the HW semaphore to access the PHY or NVM
- **/
-s32 igb_get_hw_semaphore_generic(struct e1000_hw *hw)
-{
-	u32 swsm;
-	s32 ret_val = E1000_SUCCESS;
-	s32 timeout = hw->nvm.word_size + 1;
-	s32 i = 0;
-
-	DEBUGFUNC("igb_get_hw_semaphore_generic");
-
-	/* Get the SW semaphore */
-	while (i < timeout) {
-		swsm = E1000_READ_REG(hw, E1000_SWSM);
-		if (!(swsm & E1000_SWSM_SMBI))
-			break;
-
-		usec_delay(50);
-		i++;
-	}
-
-	if (i == timeout) {
-		DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	/* Get the FW semaphore. */
-	for (i = 0; i < timeout; i++) {
-		swsm = E1000_READ_REG(hw, E1000_SWSM);
-		E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
-
-		/* Semaphore acquired if bit latched */
-		if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI)
-			break;
-
-		usec_delay(50);
-	}
-
-	if (i == timeout) {
-		/* Release semaphores */
-		igb_put_hw_semaphore_generic(hw);
-		DEBUGOUT("Driver can't access the NVM\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_put_hw_semaphore_generic - Release hardware semaphore
- *  @hw: pointer to the HW structure
- *
- *  Release hardware semaphore used to access the PHY or NVM
- **/
-void igb_put_hw_semaphore_generic(struct e1000_hw *hw)
-{
-	u32 swsm;
-
-	DEBUGFUNC("igb_put_hw_semaphore_generic");
-
-	swsm = E1000_READ_REG(hw, E1000_SWSM);
-
-	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
-
-	E1000_WRITE_REG(hw, E1000_SWSM, swsm);
-}
-
-/**
- *  igb_get_auto_rd_done_generic - Check for auto read completion
- *  @hw: pointer to the HW structure
- *
- *  Check EEPROM for Auto Read done bit.
- **/
-s32 igb_get_auto_rd_done_generic(struct e1000_hw *hw)
-{
-	s32 i = 0;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_get_auto_rd_done_generic");
-
-	while (i < AUTO_READ_DONE_TIMEOUT) {
-		if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_AUTO_RD)
-			break;
-		msec_delay(1);
-		i++;
-	}
-
-	if (i == AUTO_READ_DONE_TIMEOUT) {
-		DEBUGOUT("Auto read by HW from NVM has not completed.\n");
-		ret_val = -E1000_ERR_RESET;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_valid_led_default_generic - Verify a valid default LED config
- *  @hw: pointer to the HW structure
- *  @data: pointer to the NVM (EEPROM)
- *
- *  Read the EEPROM for the current default LED configuration.  If the
- *  LED configuration is not valid, set to a valid LED configuration.
- **/
-s32 igb_valid_led_default_generic(struct e1000_hw *hw, u16 *data)
-{
-	s32 ret_val;
-
-	DEBUGFUNC("igb_valid_led_default_generic");
-
-	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
-	if (ret_val) {
-		DEBUGOUT("NVM Read Error\n");
-		goto out;
-	}
-
-	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
-		*data = ID_LED_DEFAULT;
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_id_led_init_generic -
- *  @hw: pointer to the HW structure
- *
- **/
-s32 igb_id_led_init_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	s32 ret_val;
-	const u32 ledctl_mask = 0x000000FF;
-	const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
-	const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
-	u16 data, i, temp;
-	const u16 led_mask = 0x0F;
-
-	DEBUGFUNC("igb_id_led_init_generic");
-
-	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
-	if (ret_val)
-		goto out;
-
-	mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
-	mac->ledctl_mode1 = mac->ledctl_default;
-	mac->ledctl_mode2 = mac->ledctl_default;
-
-	for (i = 0; i < 4; i++) {
-		temp = (data >> (i << 2)) & led_mask;
-		switch (temp) {
-		case ID_LED_ON1_DEF2:
-		case ID_LED_ON1_ON2:
-		case ID_LED_ON1_OFF2:
-			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode1 |= ledctl_on << (i << 3);
-			break;
-		case ID_LED_OFF1_DEF2:
-		case ID_LED_OFF1_ON2:
-		case ID_LED_OFF1_OFF2:
-			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode1 |= ledctl_off << (i << 3);
-			break;
-		default:
-			/* Do nothing */
-			break;
-		}
-		switch (temp) {
-		case ID_LED_DEF1_ON2:
-		case ID_LED_ON1_ON2:
-		case ID_LED_OFF1_ON2:
-			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode2 |= ledctl_on << (i << 3);
-			break;
-		case ID_LED_DEF1_OFF2:
-		case ID_LED_ON1_OFF2:
-		case ID_LED_OFF1_OFF2:
-			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
-			mac->ledctl_mode2 |= ledctl_off << (i << 3);
-			break;
-		default:
-			/* Do nothing */
-			break;
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-#if 0
-/**
- *  igb_setup_led_generic - Configures SW controllable LED
- *  @hw: pointer to the HW structure
- *
- *  This prepares the SW controllable LED for use and saves the current state
- *  of the LED so it can be later restored.
- **/
-s32 igb_setup_led_generic(struct e1000_hw *hw)
-{
-	u32 ledctl;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_setup_led_generic");
-
-	if (hw->mac.ops.setup_led != e1000_setup_led_generic) {
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	if (hw->phy.media_type == e1000_media_type_fiber) {
-		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
-		hw->mac.ledctl_default = ledctl;
-		/* Turn off LED0 */
-		ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
-		            E1000_LEDCTL_LED0_BLINK |
-		            E1000_LEDCTL_LED0_MODE_MASK);
-		ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
-		           E1000_LEDCTL_LED0_MODE_SHIFT);
-		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
-	} else if (hw->phy.media_type == e1000_media_type_copper) {
-		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_cleanup_led_generic - Set LED config to default operation
- *  @hw: pointer to the HW structure
- *
- *  Remove the current LED configuration and set the LED configuration
- *  to the default value, saved from the EEPROM.
- **/
-s32 igb_cleanup_led_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_cleanup_led_generic");
-
-	if (hw->mac.ops.cleanup_led != e1000_cleanup_led_generic) {
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_blink_led_generic - Blink LED
- *  @hw: pointer to the HW structure
- *
- *  Blink the LEDs which are set to be on.
- **/
-s32 igb_blink_led_generic(struct e1000_hw *hw)
-{
-	u32 ledctl_blink = 0;
-	u32 i;
-
-	DEBUGFUNC("igb_blink_led_generic");
-
-	if (hw->phy.media_type == e1000_media_type_fiber) {
-		/* always blink LED0 for PCI-E fiber */
-		ledctl_blink = E1000_LEDCTL_LED0_BLINK |
-		     (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
-	} else {
-		/*
-		 * set the blink bit for each LED that's "on" (0x0E)
-		 * in ledctl_mode2
-		 */
-		ledctl_blink = hw->mac.ledctl_mode2;
-		for (i = 0; i < 4; i++)
-			if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
-			    E1000_LEDCTL_MODE_LED_ON)
-				ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
-				                 (i * 8));
-	}
-
-	E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl_blink);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_led_on_generic - Turn LED on
- *  @hw: pointer to the HW structure
- *
- *  Turn LED on.
- **/
-s32 igb_led_on_generic(struct e1000_hw *hw)
-{
-	u32 ctrl;
-
-	DEBUGFUNC("igb_led_on_generic");
-
-	switch (hw->phy.media_type) {
-	case e1000_media_type_fiber:
-		ctrl = E1000_READ_REG(hw, E1000_CTRL);
-		ctrl &= ~E1000_CTRL_SWDPIN0;
-		ctrl |= E1000_CTRL_SWDPIO0;
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-		break;
-	case e1000_media_type_copper:
-		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
-		break;
-	default:
-		break;
-	}
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_led_off_generic - Turn LED off
- *  @hw: pointer to the HW structure
- *
- *  Turn LED off.
- **/
-s32 igb_led_off_generic(struct e1000_hw *hw)
-{
-	u32 ctrl;
-
-	DEBUGFUNC("igb_led_off_generic");
-
-	switch (hw->phy.media_type) {
-	case e1000_media_type_fiber:
-		ctrl = E1000_READ_REG(hw, E1000_CTRL);
-		ctrl |= E1000_CTRL_SWDPIN0;
-		ctrl |= E1000_CTRL_SWDPIO0;
-		E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-		break;
-	case e1000_media_type_copper:
-		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
-		break;
-	default:
-		break;
-	}
-
-	return E1000_SUCCESS;
-}
-#endif
-
-/**
- *  igb_set_pcie_no_snoop_generic - Set PCI-express capabilities
- *  @hw: pointer to the HW structure
- *  @no_snoop: bitmap of snoop events
- *
- *  Set the PCI-express register to snoop for events enabled in 'no_snoop'.
- **/
-void igb_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop)
-{
-	u32 gcr;
-
-	DEBUGFUNC("igb_set_pcie_no_snoop_generic");
-
-	if (hw->bus.type != e1000_bus_type_pci_express)
-		goto out;
-
-	if (no_snoop) {
-		gcr = E1000_READ_REG(hw, E1000_GCR);
-		gcr &= ~(PCIE_NO_SNOOP_ALL);
-		gcr |= no_snoop;
-		E1000_WRITE_REG(hw, E1000_GCR, gcr);
-	}
-out:
-	return;
-}
-
-/**
- *  igb_disable_pcie_master_generic - Disables PCI-express master access
- *  @hw: pointer to the HW structure
- *
- *  Returns 0 (E1000_SUCCESS) if successful, else returns -10
- *  (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
- *  the master requests to be disabled.
- *
- *  Disables PCI-Express master access and verifies there are no pending
- *  requests.
- **/
-s32 igb_disable_pcie_master_generic(struct e1000_hw *hw)
-{
-	u32 ctrl;
-	s32 timeout = MASTER_DISABLE_TIMEOUT;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_disable_pcie_master_generic");
-
-	if (hw->bus.type != e1000_bus_type_pci_express)
-		goto out;
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-
-	while (timeout) {
-		if (!(E1000_READ_REG(hw, E1000_STATUS) &
-		      E1000_STATUS_GIO_MASTER_ENABLE))
-			break;
-		usec_delay(100);
-		timeout--;
-	}
-
-	if (!timeout) {
-		DEBUGOUT("Master requests are pending.\n");
-		ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_reset_adaptive_generic - Reset Adaptive Interframe Spacing
- *  @hw: pointer to the HW structure
- *
- *  Reset the Adaptive Interframe Spacing throttle to default values.
- **/
-void igb_reset_adaptive_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-
-	DEBUGFUNC("igb_reset_adaptive_generic");
-
-	if (!mac->adaptive_ifs) {
-		DEBUGOUT("Not in Adaptive IFS mode!\n");
-		goto out;
-	}
-
-	mac->current_ifs_val = 0;
-	mac->ifs_min_val = IFS_MIN;
-	mac->ifs_max_val = IFS_MAX;
-	mac->ifs_step_size = IFS_STEP;
-	mac->ifs_ratio = IFS_RATIO;
-
-	mac->in_ifs_mode = false;
-	E1000_WRITE_REG(hw, E1000_AIT, 0);
-out:
-	return;
-}
-
-/**
- *  igb_update_adaptive_generic - Update Adaptive Interframe Spacing
- *  @hw: pointer to the HW structure
- *
- *  Update the Adaptive Interframe Spacing Throttle value based on the
- *  time between transmitted packets and time between collisions.
- **/
-void igb_update_adaptive_generic(struct e1000_hw *hw)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-
-	DEBUGFUNC("igb_update_adaptive_generic");
-
-	if (!mac->adaptive_ifs) {
-		DEBUGOUT("Not in Adaptive IFS mode!\n");
-		goto out;
-	}
-
-	if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
-		if (mac->tx_packet_delta > MIN_NUM_XMITS) {
-			mac->in_ifs_mode = true;
-			if (mac->current_ifs_val < mac->ifs_max_val) {
-				if (!mac->current_ifs_val)
-					mac->current_ifs_val = mac->ifs_min_val;
-				else
-					mac->current_ifs_val +=
-						mac->ifs_step_size;
-				E1000_WRITE_REG(hw, E1000_AIT, mac->current_ifs_val);
-			}
-		}
-	} else {
-		if (mac->in_ifs_mode &&
-		    (mac->tx_packet_delta <= MIN_NUM_XMITS)) {
-			mac->current_ifs_val = 0;
-			mac->in_ifs_mode = false;
-			E1000_WRITE_REG(hw, E1000_AIT, 0);
-		}
-	}
-out:
-	return;
-}
-
-/**
- *  igb_validate_mdi_setting_generic - Verify MDI/MDIx settings
- *  @hw: pointer to the HW structure
- *
- *  Verify that when not using auto-negotiation that MDI/MDIx is correctly
- *  set, which is forced to MDI mode only.
- **/
-static s32 igb_validate_mdi_setting_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_validate_mdi_setting_generic");
-
-	if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) {
-		DEBUGOUT("Invalid MDI setting detected\n");
-		hw->phy.mdix = 1;
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_write_8bit_ctrl_reg_generic - Write a 8bit CTRL register
- *  @hw: pointer to the HW structure
- *  @reg: 32bit register offset such as E1000_SCTL
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Writes an address/data control type register.  There are several of these
- *  and they all have the format address << 8 | data and bit 31 is polled for
- *  completion.
- **/
-s32 igb_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg,
-                                      u32 offset, u8 data)
-{
-	u32 i, regvalue = 0;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_write_8bit_ctrl_reg_generic");
-
-	/* Set up the address and data */
-	regvalue = ((u32)data) | (offset << E1000_GEN_CTL_ADDRESS_SHIFT);
-	E1000_WRITE_REG(hw, reg, regvalue);
-
-	/* Poll the ready bit to see if the MDI read completed */
-	for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) {
-		usec_delay(5);
-		regvalue = E1000_READ_REG(hw, reg);
-		if (regvalue & E1000_GEN_CTL_READY)
-			break;
-	}
-	if (!(regvalue & E1000_GEN_CTL_READY)) {
-		DEBUGOUT1("Reg %08x did not indicate ready\n", reg);
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
diff --git a/roms/ipxe/src/drivers/net/igb/igb_mac.h b/roms/ipxe/src/drivers/net/igb/igb_mac.h
deleted file mode 100644
index 7639e24e4d158f401a6b2a167edad5e1481d8aef..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_mac.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#ifndef _IGB_MAC_H_
-#define _IGB_MAC_H_
-
-/*
- * Functions that should not be called directly from drivers but can be used
- * by other files in this 'shared code'
- */
-void igb_init_mac_ops_generic(struct e1000_hw *hw);
-s32  igb_blink_led_generic(struct e1000_hw *hw);
-s32  igb_check_for_copper_link_generic(struct e1000_hw *hw);
-s32  igb_check_for_fiber_link_generic(struct e1000_hw *hw);
-s32  igb_check_for_serdes_link_generic(struct e1000_hw *hw);
-s32  igb_cleanup_led_generic(struct e1000_hw *hw);
-s32  igb_config_fc_after_link_up_generic(struct e1000_hw *hw);
-s32  igb_disable_pcie_master_generic(struct e1000_hw *hw);
-s32  igb_force_mac_fc_generic(struct e1000_hw *hw);
-s32  igb_get_auto_rd_done_generic(struct e1000_hw *hw);
-s32  igb_get_bus_info_pcie_generic(struct e1000_hw *hw);
-void igb_set_lan_id_single_port(struct e1000_hw *hw);
-s32  igb_get_hw_semaphore_generic(struct e1000_hw *hw);
-s32  igb_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed,
-                                               u16 *duplex);
-s32  igb_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw,
-                                                     u16 *speed, u16 *duplex);
-s32  igb_id_led_init_generic(struct e1000_hw *hw);
-s32  igb_led_on_generic(struct e1000_hw *hw);
-s32  igb_led_off_generic(struct e1000_hw *hw);
-void igb_update_mc_addr_list_generic(struct e1000_hw *hw,
-	                               u8 *mc_addr_list, u32 mc_addr_count);
-s32  igb_set_fc_watermarks_generic(struct e1000_hw *hw);
-s32  igb_setup_fiber_serdes_link_generic(struct e1000_hw *hw);
-s32  igb_setup_led_generic(struct e1000_hw *hw);
-s32  igb_setup_link_generic(struct e1000_hw *hw);
-s32  igb_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg,
-                                       u32 offset, u8 data);
-
-u32  igb_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr);
-
-void igb_clear_hw_cntrs_base_generic(struct e1000_hw *hw);
-void igb_clear_vfta_generic(struct e1000_hw *hw);
-void igb_config_collision_dist_generic(struct e1000_hw *hw);
-void igb_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count);
-void igb_mta_set_generic(struct e1000_hw *hw, u32 hash_value);
-void igb_pcix_mmrbc_workaround_generic(struct e1000_hw *hw);
-void igb_put_hw_semaphore_generic(struct e1000_hw *hw);
-void igb_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index);
-s32  igb_check_alt_mac_addr_generic(struct e1000_hw *hw);
-void igb_reset_adaptive_generic(struct e1000_hw *hw);
-void igb_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop);
-void igb_update_adaptive_generic(struct e1000_hw *hw);
-void igb_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
-
-#endif /* _IGB_MAC_H_ */
diff --git a/roms/ipxe/src/drivers/net/igb/igb_main.c b/roms/ipxe/src/drivers/net/igb/igb_main.c
deleted file mode 100644
index 9295c2c8c994a65f22e162881c87ae06bb33f4cf..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_main.c
+++ /dev/null
@@ -1,1010 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  Portions Copyright(c) 2010 Marty Connor <mdc@etherboot.org>
-  Portions Copyright(c) 2010 Entity Cyber, Inc.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#include "igb.h"
-
-/* Low-level support routines */
-
-/**
- * igb_read_pcie_cap_reg - retrieve PCIe capability register contents
- * @hw: address of board private structure
- * @reg: PCIe capability register requested
- * @value: where to store requested value
- **/
-int32_t igb_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
-{
-    struct igb_adapter *adapter = hw->back;
-    uint16_t cap_offset;
-
-#define	 PCI_CAP_ID_EXP	       0x10    /* PCI Express */
-    cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
-    if (!cap_offset)
-	return -E1000_ERR_CONFIG;
-
-    pci_read_config_word(adapter->pdev, cap_offset + reg, value);
-
-    return E1000_SUCCESS;
-}
-
-/**
- * igb_write_pcie_cap_reg - write value to PCIe capability register
- * @hw: address of board private structure
- * @reg: PCIe capability register to write to
- * @value: value to store in given register
- **/
-int32_t igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
-{
-	struct igb_adapter *adapter = hw->back;
-	u16 cap_offset;
-
-	cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
-	if (!cap_offset)
-		return -E1000_ERR_CONFIG;
-
-	pci_write_config_word(adapter->pdev, cap_offset + reg, *value);
-
-	return E1000_SUCCESS;
-}
-
-/**
- * igb_irq_disable - Mask off interrupt generation on the NIC
- * @adapter: board private structure
- **/
-static void igb_irq_disable(struct igb_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-
-	E1000_WRITE_REG(hw, E1000_IAM, 0);
-	E1000_WRITE_REG(hw, E1000_IMC, ~0);
-	E1000_WRITE_FLUSH(hw);
-}
-
-/**
- * igb_irq_enable - Enable default interrupt generation settings
- * @adapter: board private structure
- **/
-static void igb_irq_enable(struct igb_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-
-	E1000_WRITE_REG(hw, E1000_IMS, IMS_ENABLE_MASK);
-	E1000_WRITE_REG(hw, E1000_IAM, IMS_ENABLE_MASK);
-	E1000_WRITE_FLUSH(hw);
-}
-
-/**
- * igb_get_hw_control - get control of the h/w from f/w
- * @adapter: address of board private structure
- *
- * igb_get_hw_control sets CTRL_EXT:DRV_LOAD bit.
- * For ASF and Pass Through versions of f/w this means that
- * the driver is loaded.
- *
- **/
-void igb_get_hw_control(struct igb_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	u32 ctrl_ext;
-
-	/* Let firmware know the driver has taken over */
-	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
-	E1000_WRITE_REG(hw, E1000_CTRL_EXT,
-			ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
-}
-
-/**
- * igb_reset - put adapter in known initial state
- * @adapter: board private structure
- **/
-void igb_reset(struct igb_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-
-	struct e1000_mac_info *mac = &hw->mac;
-	struct e1000_fc_info *fc = &hw->fc;
-	u32 pba = 0;
-	u16 hwm;
-
-	/* Repartition Pba for greater than 9k mtu
-	 * To take effect CTRL.RST is required.
-	 */
-	switch (mac->type) {
-	case e1000_82576:
-		pba = E1000_READ_REG(hw, E1000_RXPBS);
-		pba &= E1000_RXPBS_SIZE_MASK_82576;
-		break;
-	case e1000_82575:
-	default:
-		pba = E1000_PBA_34K;
-		break;
-	}
-
-	/* flow control settings */
-	/* The high water mark must be low enough to fit one full frame
-	 * (or the size used for early receive) above it in the Rx FIFO.
-	 * Set it to the lower of:
-	 * - 90% of the Rx FIFO size, or
-	 * - the full Rx FIFO size minus one full frame */
-#define min(a,b) (((a)<(b))?(a):(b))
-	hwm = min(((pba << 10) * 9 / 10),
-			((pba << 10) - 2 * adapter->max_frame_size));
-
-	if (mac->type < e1000_82576) {
-		fc->high_water = hwm & 0xFFF8;	/* 8-byte granularity */
-		fc->low_water = fc->high_water - 8;
-	} else {
-		fc->high_water = hwm & 0xFFF0;	/* 16-byte granularity */
-		fc->low_water = fc->high_water - 16;
-	}
-	fc->pause_time = 0xFFFF;
-	fc->send_xon = 1;
-	fc->current_mode = fc->requested_mode;
-
-	/* Allow time for pending master requests to run */
-	igb_reset_hw(hw);
-	E1000_WRITE_REG(hw, E1000_WUC, 0);
-
-	if (igb_init_hw(hw)) {
-		DBG ("Hardware Error\n");
-        }
-
-	igb_get_phy_info(hw);
-}
-
-/**
- * igb_sw_init - Initialize general software structures (struct igb_adapter)
- * @adapter: board private structure to initialize
- **/
-int igb_sw_init(struct igb_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	struct pci_device *pdev = adapter->pdev;
-
-	/* PCI config space info */
-
-	hw->vendor_id = pdev->vendor;
-	hw->device_id = pdev->device;
-
-	pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
-
-	pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
-
-	adapter->max_frame_size = MAXIMUM_ETHERNET_VLAN_SIZE + ETH_HLEN + ETH_FCS_LEN;
-	adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
-
-	/* Initialize the hardware-specific values */
-	if (igb_setup_init_funcs(hw, TRUE)) {
-		DBG ("Hardware Initialization Failure\n");
-		return -EIO;
-	}
-
-	/* Explicitly disable IRQ since the NIC can be in any state. */
-	igb_irq_disable(adapter);
-
-	return 0;
-}
-
-/* TX support routines */
-
-/**
- * igb_setup_tx_resources - allocate Tx resources (Descriptors)
- *
- * @v adapter	e1000 private structure
- *
- * @ret rc	 Returns 0 on success, negative on failure
- **/
-static int igb_setup_tx_resources ( struct igb_adapter *adapter )
-{
-	DBG ( "igb_setup_tx_resources\n" );
-
-	/* Allocate transmit descriptor ring memory.
-	   It must not cross a 64K boundary because of hardware errata #23
-	   so we use malloc_dma() requesting a 128 byte block that is
-	   128 byte aligned. This should guarantee that the memory
-	   allocated will not cross a 64K boundary, because 128 is an
-	   even multiple of 65536 ( 65536 / 128 == 512 ), so all possible
-	   allocations of 128 bytes on a 128 byte boundary will not
-	   cross 64K bytes.
-	 */
-
-	adapter->tx_base =
-		malloc_dma ( adapter->tx_ring_size, adapter->tx_ring_size );
-
-	if ( ! adapter->tx_base ) {
-		return -ENOMEM;
-	}
-
-	memset ( adapter->tx_base, 0, adapter->tx_ring_size );
-
-	DBG ( "adapter->tx_base = %#08lx\n", virt_to_bus ( adapter->tx_base ) );
-
-	return 0;
-}
-
-/**
- * igb_process_tx_packets - process transmitted packets
- *
- * @v netdev	network interface device structure
- **/
-static void igb_process_tx_packets ( struct net_device *netdev )
-{
-	struct igb_adapter *adapter = netdev_priv ( netdev );
-	uint32_t i;
-	uint32_t tx_status;
-	struct e1000_tx_desc *tx_curr_desc;
-
-	/* Check status of transmitted packets
-	 */
-	DBG ( "process_tx_packets: tx_head = %d, tx_tail = %d\n", adapter->tx_head,
-	      adapter->tx_tail );
-
-	while ( ( i = adapter->tx_head ) != adapter->tx_tail ) {
-
-		tx_curr_desc = ( void * )  ( adapter->tx_base ) +
-					   ( i * sizeof ( *adapter->tx_base ) );
-
-		tx_status = tx_curr_desc->upper.data;
-
-		DBG ( "	 tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
-		DBG ( "	 tx_status = %#08x\n", tx_status );
-
-		/* if the packet at tx_head is not owned by hardware it is for us */
-		if ( ! ( tx_status & E1000_TXD_STAT_DD ) )
-			break;
-
-		DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n",
-		      adapter->tx_head, adapter->tx_tail, tx_status );
-
-		if ( tx_status & ( E1000_TXD_STAT_EC | E1000_TXD_STAT_LC |
-				   E1000_TXD_STAT_TU ) ) {
-			netdev_tx_complete_err ( netdev, adapter->tx_iobuf[i], -EINVAL );
-			DBG ( "Error transmitting packet, tx_status: %#08x\n",
-			      tx_status );
-		} else {
-			netdev_tx_complete ( netdev, adapter->tx_iobuf[i] );
-			DBG ( "Success transmitting packet, tx_status: %#08x\n",
-			      tx_status );
-		}
-
-		/* Decrement count of used descriptors, clear this descriptor
-		 */
-		adapter->tx_fill_ctr--;
-		memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
-
-		adapter->tx_head = ( adapter->tx_head + 1 ) % NUM_TX_DESC;
-	}
-}
-
-static void igb_free_tx_resources ( struct igb_adapter *adapter )
-{
-	DBG ( "igb_free_tx_resources\n" );
-
-	free_dma ( adapter->tx_base, adapter->tx_ring_size );
-}
-
-/**
- * igb_configure_tx - Configure 8254x Transmit Unit after Reset
- * @adapter: board private structure
- *
- * Configure the Tx unit of the MAC after a reset.
- **/
-static void igb_configure_tx ( struct igb_adapter *adapter )
-{
-	struct e1000_hw *hw = &adapter->hw;
-	u32 tctl, txdctl;
-
-	DBG ( "igb_configure_tx\n" );
-
-	/* disable transmits while setting up the descriptors */
-	tctl = E1000_READ_REG ( hw, E1000_TCTL );
-	E1000_WRITE_REG ( hw, E1000_TCTL, tctl & ~E1000_TCTL_EN );
-	E1000_WRITE_FLUSH(hw);
-	mdelay(10);
-
-	E1000_WRITE_REG ( hw, E1000_TDBAH(0), 0 );
-	E1000_WRITE_REG ( hw, E1000_TDBAL(0), virt_to_bus ( adapter->tx_base ) );
-	E1000_WRITE_REG ( hw, E1000_TDLEN(0), adapter->tx_ring_size );
-
-	DBG ( "E1000_TDBAL(0): %#08x\n",  E1000_READ_REG ( hw, E1000_TDBAL(0) ) );
-	DBG ( "E1000_TDLEN(0): %d\n",	  E1000_READ_REG ( hw, E1000_TDLEN(0) ) );
-
-	/* Setup the HW Tx Head and Tail descriptor pointers */
-	E1000_WRITE_REG ( hw, E1000_TDH(0), 0 );
-	E1000_WRITE_REG ( hw, E1000_TDT(0), 0 );
-
-	adapter->tx_head = 0;
-	adapter->tx_tail = 0;
-	adapter->tx_fill_ctr = 0;
-
-	txdctl = E1000_READ_REG ( hw, E1000_TXDCTL(0) );
-	txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
-	E1000_WRITE_REG ( hw, E1000_TXDCTL(0), txdctl );
-
-	/* Setup Transmit Descriptor Settings for eop descriptor */
-	adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS;
-
-	/* enable Report Status bit */
-	adapter->txd_cmd |= E1000_TXD_CMD_RS;
-
-	/* Program the Transmit Control Register */
-	tctl &= ~E1000_TCTL_CT;
-	tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
-		(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
-
-	igb_config_collision_dist(hw);
-
-	/* Enable transmits */
-	tctl |= E1000_TCTL_EN;
-	E1000_WRITE_REG(hw, E1000_TCTL, tctl);
-	E1000_WRITE_FLUSH(hw);
-}
-
-/* RX support routines */
-
-static void igb_free_rx_resources ( struct igb_adapter *adapter )
-{
-	int i;
-
-	DBG ( "igb_free_rx_resources\n" );
-
-	free_dma ( adapter->rx_base, adapter->rx_ring_size );
-
-	for ( i = 0; i < NUM_RX_DESC; i++ ) {
-		free_iob ( adapter->rx_iobuf[i] );
-	}
-}
-
-/**
- * igb_refill_rx_ring - allocate Rx io_buffers
- *
- * @v adapter	e1000 private structure
- *
- * @ret rc	 Returns 0 on success, negative on failure
- **/
-static int igb_refill_rx_ring ( struct igb_adapter *adapter )
-{
-	int i, rx_curr;
-	int rc = 0;
-	struct e1000_rx_desc *rx_curr_desc;
-	struct e1000_hw *hw = &adapter->hw;
-	struct io_buffer *iob;
-
-	DBGP ("igb_refill_rx_ring\n");
-
-	for ( i = 0; i < NUM_RX_DESC; i++ ) {
-		rx_curr = ( ( adapter->rx_curr + i ) % NUM_RX_DESC );
-		rx_curr_desc = adapter->rx_base + rx_curr;
-
-		if ( rx_curr_desc->status & E1000_RXD_STAT_DD )
-			continue;
-
-		if ( adapter->rx_iobuf[rx_curr] != NULL )
-			continue;
-
-		DBG2 ( "Refilling rx desc %d\n", rx_curr );
-
-		iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE );
-		adapter->rx_iobuf[rx_curr] = iob;
-
-		if ( ! iob ) {
-			DBG ( "alloc_iob failed\n" );
-			rc = -ENOMEM;
-			break;
-		} else {
-			rx_curr_desc->buffer_addr = virt_to_bus ( iob->data );
-
-			E1000_WRITE_REG ( hw, E1000_RDT(0), rx_curr );
-		}
-	}
-	return rc;
-}
-
-/**
- * igb_setup_rx_resources - allocate Rx resources (Descriptors)
- *
- * @v adapter	e1000 private structure
- *
- * @ret rc	 Returns 0 on success, negative on failure
- **/
-static int igb_setup_rx_resources ( struct igb_adapter *adapter )
-{
-	int i, rc = 0;
-
-	DBGP ( "igb_setup_rx_resources\n" );
-
-	/* Allocate receive descriptor ring memory.
-	   It must not cross a 64K boundary because of hardware errata
-	 */
-
-	adapter->rx_base =
-		malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size );
-
-	if ( ! adapter->rx_base ) {
-		return -ENOMEM;
-	}
-	memset ( adapter->rx_base, 0, adapter->rx_ring_size );
-
-	for ( i = 0; i < NUM_RX_DESC; i++ ) {
-		/* let igb_refill_rx_ring() io_buffer allocations */
-		adapter->rx_iobuf[i] = NULL;
-	}
-
-	/* allocate io_buffers */
-	rc = igb_refill_rx_ring ( adapter );
-	if ( rc < 0 )
-		igb_free_rx_resources ( adapter );
-
-	return rc;
-}
-
-/**
- * igb_configure_rx - Configure 8254x Receive Unit after Reset
- * @adapter: board private structure
- *
- * Configure the Rx unit of the MAC after a reset.
- **/
-static void igb_configure_rx ( struct igb_adapter *adapter )
-{
-	struct e1000_hw *hw = &adapter->hw;
-	uint32_t rctl, rxdctl, rxcsum, mrqc;
-
-	DBGP ( "igb_configure_rx\n" );
-
-	/* disable receives while setting up the descriptors */
-	rctl = E1000_READ_REG ( hw, E1000_RCTL );
-	E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN );
-	E1000_WRITE_FLUSH(hw);
-	mdelay(10);
-
-	adapter->rx_curr = 0;
-
-	/* Setup the HW Rx Head and Tail Descriptor Pointers and
-	 * the Base and Length of the Rx Descriptor Ring */
-
-	E1000_WRITE_REG ( hw, E1000_RDBAL(0), virt_to_bus ( adapter->rx_base ) );
-	E1000_WRITE_REG ( hw, E1000_RDBAH(0), 0 );
-	E1000_WRITE_REG ( hw, E1000_RDLEN(0), adapter->rx_ring_size );
-
-	E1000_WRITE_REG ( hw, E1000_RDH(0), 0 );
-	E1000_WRITE_REG ( hw, E1000_RDT(0), 0 );
-
-	DBG ( "E1000_RDBAL(0): %#08x\n",  E1000_READ_REG ( hw, E1000_RDBAL(0) ) );
-	DBG ( "E1000_RDLEN(0): %d\n",	  E1000_READ_REG ( hw, E1000_RDLEN(0) ) );
-	DBG ( "E1000_RCTL:  %#08x\n",	  E1000_READ_REG ( hw, E1000_RCTL ) );
-
-	rxdctl = E1000_READ_REG ( hw, E1000_RXDCTL(0) );
-	rxdctl |= E1000_RXDCTL_QUEUE_ENABLE;
-	rxdctl &= 0xFFF00000;
-	rxdctl |= IGB_RX_PTHRESH;
-	rxdctl |= IGB_RX_HTHRESH << 8;
-	rxdctl |= IGB_RX_WTHRESH << 16;
-	E1000_WRITE_REG ( hw, E1000_RXDCTL(0), rxdctl );
-	E1000_WRITE_FLUSH ( hw );
-
-	rxcsum = E1000_READ_REG(hw, E1000_RXCSUM);
-	rxcsum &= ~( E1000_RXCSUM_TUOFL | E1000_RXCSUM_IPPCSE );
-	E1000_WRITE_REG ( hw, E1000_RXCSUM, 0 );
-
-	/* The initial value for MRQC disables multiple receive
-	 * queues, however this setting is not recommended.
-	 * - Intel® 82576 Gigabit Ethernet Controller Datasheet r2.41
-	 *   Section 8.10.9 Multiple Queues Command Register - MRQC
-	 */
-	mrqc = E1000_MRQC_ENABLE_VMDQ;
-	E1000_WRITE_REG ( hw, E1000_MRQC, mrqc );
-
-	/* Turn off loopback modes */
-	rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
-
-	/* set maximum packet size */
-	rctl |=	 E1000_RCTL_SZ_2048;
-
-	/* Broadcast enable, multicast promisc, unicast promisc */
-	rctl |=	 E1000_RCTL_BAM | E1000_RCTL_MPE | E1000_RCTL_UPE;
-
-	/* Store bad packets */
-	rctl |=	 E1000_RCTL_SBP;
-
-	/* enable LPE to prevent packets larger than max_frame_size */
-	rctl |= E1000_RCTL_LPE;
-
-	/* enable stripping of CRC. */
-	rctl |= E1000_RCTL_SECRC;
-
-	/* enable receive control register */
-	rctl |= E1000_RCTL_EN;
-	E1000_WRITE_REG(hw, E1000_RCTL, rctl);
-	E1000_WRITE_FLUSH(hw);
-
-	/* On the 82576, RDT([0]) must not be "bumped" before
-	 * the enable bit of RXDCTL([0]) is set.
-	 * - Intel® 82576 Gigabit Ethernet Controller Datasheet r2.41
-	 *   Section 4.5.9 receive Initialization
-	 *
-	 * By observation I have found this to occur when the enable bit of
-	 * RCTL is set. The datasheet recommends polling for this bit,
-	 * however as I see no evidence of this in the Linux igb driver
-	 * I have omitted that step.
-	 * - Simon Horman, May 2009
-	 */
-	E1000_WRITE_REG ( hw, E1000_RDT(0), NUM_RX_DESC - 1 );
-
-	DBG ( "RDBAH: %#08x\n",	 E1000_READ_REG ( hw, E1000_RDBAH(0) ) );
-	DBG ( "RDBAL: %#08x\n",	 E1000_READ_REG ( hw, E1000_RDBAL(0) ) );
-	DBG ( "RDLEN: %d\n",	 E1000_READ_REG ( hw, E1000_RDLEN(0) ) );
-	DBG ( "RCTL:  %#08x\n",	 E1000_READ_REG ( hw, E1000_RCTL ) );
-}
-
-/**
- * igb_process_rx_packets - process received packets
- *
- * @v netdev	network interface device structure
- **/
-static void igb_process_rx_packets ( struct net_device *netdev )
-{
-	struct igb_adapter *adapter = netdev_priv ( netdev );
-	uint32_t i;
-	uint32_t rx_status;
-	uint32_t rx_len;
-	uint32_t rx_err;
-	struct e1000_rx_desc *rx_curr_desc;
-
-	DBGP ( "igb_process_rx_packets\n" );
-
-	/* Process received packets
-	 */
-	while ( 1 ) {
-
-		i = adapter->rx_curr;
-
-		rx_curr_desc = ( void * )  ( adapter->rx_base ) +
-				  ( i * sizeof ( *adapter->rx_base ) );
-		rx_status = rx_curr_desc->status;
-
-		DBG2 ( "Before DD Check RX_status: %#08x\n", rx_status );
-
-		if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
-			break;
-
-		if ( adapter->rx_iobuf[i] == NULL )
-			break;
-
-		DBG ( "E1000_RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, E1000_RCTL ) );
-
-		rx_len = rx_curr_desc->length;
-
-		DBG ( "Received packet, rx_curr: %d  rx_status: %#08x  rx_len: %d\n",
-		      i, rx_status, rx_len );
-
-		rx_err = rx_curr_desc->errors;
-
-		iob_put ( adapter->rx_iobuf[i], rx_len );
-
-		if ( rx_err & E1000_RXD_ERR_FRAME_ERR_MASK ) {
-
-			netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL );
-			DBG ( "igb_process_rx_packets: Corrupted packet received!"
-			      " rx_err: %#08x\n", rx_err );
-		} else	{
-			/* Add this packet to the receive queue. */
-			netdev_rx ( netdev, adapter->rx_iobuf[i] );
-		}
-		adapter->rx_iobuf[i] = NULL;
-
-		memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
-
-		adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC;
-	}
-}
-
-/** Functions that implement the iPXE driver API **/
-
-/**
- * igb_close - Disables a network interface
- *
- * @v netdev	network interface device structure
- *
- **/
-static void igb_close ( struct net_device *netdev )
-{
-	struct igb_adapter *adapter = netdev_priv ( netdev );
-	struct e1000_hw *hw = &adapter->hw;
-	uint32_t rctl;
-
-	DBGP ( "igb_close\n" );
-
-	/* Disable and acknowledge interrupts */
-	igb_irq_disable ( adapter );
-	E1000_READ_REG ( hw, E1000_ICR );
-
-	/* disable receives */
-	rctl = E1000_READ_REG ( hw, E1000_RCTL );
-	E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN );
-	E1000_WRITE_FLUSH(hw);
-
-	igb_reset ( adapter );
-
-	igb_free_tx_resources ( adapter );
-	igb_free_rx_resources ( adapter );
-}
-
-/**
- * igb_transmit - Transmit a packet
- *
- * @v netdev	Network device
- * @v iobuf	I/O buffer
- *
- * @ret rc	 Returns 0 on success, negative on failure
- */
-static int igb_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
-{
-	struct igb_adapter *adapter = netdev_priv( netdev );
-	struct e1000_hw *hw = &adapter->hw;
-	uint32_t tx_curr = adapter->tx_tail;
-	struct e1000_tx_desc *tx_curr_desc;
-
-	DBGP ("igb_transmit\n");
-
-	if ( adapter->tx_fill_ctr == NUM_TX_DESC ) {
-		DBG ("TX overflow\n");
-		return -ENOBUFS;
-	}
-
-	/* Save pointer to iobuf we have been given to transmit,
-	   netdev_tx_complete() will need it later
-	 */
-	adapter->tx_iobuf[tx_curr] = iobuf;
-
-	tx_curr_desc = ( void * ) ( adapter->tx_base ) +
-		       ( tx_curr * sizeof ( *adapter->tx_base ) );
-
-	DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
-	DBG ( "tx_curr_desc + 16 = %#08lx\n", virt_to_bus ( tx_curr_desc ) + 16 );
-	DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) );
-
-	/* Add the packet to TX ring
-	 */
-	tx_curr_desc->buffer_addr = virt_to_bus ( iobuf->data );
-	tx_curr_desc->upper.data = 0;
-	tx_curr_desc->lower.data = adapter->txd_cmd | iob_len ( iobuf );
-
-	DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr,
-	      tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
-
-	/* Point to next free descriptor */
-	adapter->tx_tail = ( adapter->tx_tail + 1 ) % NUM_TX_DESC;
-	adapter->tx_fill_ctr++;
-
-	/* Write new tail to NIC, making packet available for transmit
-	 */
-	E1000_WRITE_REG ( hw, E1000_TDT(0), adapter->tx_tail );
-	E1000_WRITE_FLUSH(hw);
-
-	return 0;
-}
-
-/**
- * igb_poll - Poll for received packets
- *
- * @v netdev	Network device
- */
-static void igb_poll ( struct net_device *netdev )
-{
-	struct igb_adapter *adapter = netdev_priv( netdev );
-	struct e1000_hw *hw = &adapter->hw;
-
-	uint32_t icr;
-
-	DBGP ( "igb_poll\n" );
-
-	/* Acknowledge interrupts */
-	icr = E1000_READ_REG ( hw, E1000_ICR );
-	if ( ! icr )
-		return;
-
-	DBG ( "igb_poll: intr_status = %#08x\n", icr );
-
-	igb_process_tx_packets ( netdev );
-
-	igb_process_rx_packets ( netdev );
-
-	igb_refill_rx_ring(adapter);
-}
-
-/**
- * igb_irq - enable or Disable interrupts
- *
- * @v adapter	e1000 adapter
- * @v action	requested interrupt action
- **/
-static void igb_irq ( struct net_device *netdev, int enable )
-{
-	struct igb_adapter *adapter = netdev_priv ( netdev );
-
-	DBGP ( "igb_irq\n" );
-
-	if ( enable ) {
-		igb_irq_enable ( adapter );
-	} else {
-		igb_irq_disable ( adapter );
-	}
-}
-
-static struct net_device_operations igb_operations;
-
-/**
- * igb_probe - Initial configuration of NIC
- *
- * @v pci	PCI device
- * @v id	PCI IDs
- *
- * @ret rc	Return status code
- **/
-int igb_probe ( struct pci_device *pdev )
-{
-	int i, err;
-	struct net_device *netdev;
-	struct igb_adapter *adapter;
-	unsigned long mmio_start, mmio_len;
-	struct e1000_hw *hw;
-
-	DBGP ( "igb_probe\n" );
-
-	err = -ENOMEM;
-
-	/* Allocate net device ( also allocates memory for netdev->priv
-	   and makes netdev-priv point to it ) */
-	netdev = alloc_etherdev ( sizeof ( struct igb_adapter ) );
-	if ( ! netdev ) {
-		DBG ( "err_alloc_etherdev\n" );
-		goto err_alloc_etherdev;
-	}
-
-	/* Associate igb-specific network operations operations with
-	 * generic network device layer */
-	netdev_init ( netdev, &igb_operations );
-
-	/* Associate this network device with given PCI device */
-	pci_set_drvdata ( pdev, netdev );
-	netdev->dev = &pdev->dev;
-
-	/* Initialize driver private storage */
-	adapter = netdev_priv ( netdev );
-	memset ( adapter, 0, ( sizeof ( *adapter ) ) );
-
-	adapter->pdev	    = pdev;
-
-	adapter->ioaddr	    = pdev->ioaddr;
-	adapter->hw.io_base = pdev->ioaddr;
-
-	hw		    = &adapter->hw;
-	hw->vendor_id	    = pdev->vendor;
-	hw->device_id	    = pdev->device;
-
-	adapter->irqno	    = pdev->irq;
-	adapter->netdev	    = netdev;
-	adapter->hw.back    = adapter;
-
-	adapter->min_frame_size	   = ETH_ZLEN + ETH_FCS_LEN;
-	adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN;
-
-	adapter->tx_ring_size = sizeof ( *adapter->tx_base ) * NUM_TX_DESC;
-	adapter->rx_ring_size = sizeof ( *adapter->rx_base ) * NUM_RX_DESC;
-
-	/* Fix up PCI device */
-	adjust_pci_device ( pdev );
-
-	err = -EIO;
-
-	mmio_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_0 );
-	mmio_len   = pci_bar_size  ( pdev, PCI_BASE_ADDRESS_0 );
-
-	DBG ( "mmio_start: %#08lx\n", mmio_start );
-	DBG ( "mmio_len: %#08lx\n", mmio_len );
-
-	adapter->hw.hw_addr = ioremap ( mmio_start, mmio_len );
-	DBG ( "adapter->hw.hw_addr: %p\n", adapter->hw.hw_addr );
-
-	if ( ! adapter->hw.hw_addr ) {
-		DBG ( "err_ioremap\n" );
-		goto err_ioremap;
-	}
-
-	/* setup adapter struct */
-	err = igb_sw_init ( adapter );
-	if (err) {
-		DBG ( "err_sw_init\n" );
-		goto err_sw_init;
-	}
-
-	igb_get_bus_info(hw);
-
-	/* Copper options */
-	if (adapter->hw.phy.media_type == e1000_media_type_copper) {
-		adapter->hw.phy.mdix = AUTO_ALL_MODES;
-		adapter->hw.phy.disable_polarity_correction = 0;
-		adapter->hw.phy.ms_type = e1000_ms_hw_default;
-	}
-
-	DBG ( "adapter->hw.mac.type: %#08x\n", adapter->hw.mac.type );
-
-	/* Force auto-negotiation */
-	adapter->hw.mac.autoneg = 1;
-	adapter->fc_autoneg = 1;
-	adapter->hw.phy.autoneg_wait_to_complete = true;
-	adapter->hw.mac.adaptive_ifs = true;
-	adapter->hw.fc.requested_mode = e1000_fc_default;
-	adapter->hw.fc.current_mode = e1000_fc_default;
-
-	igb_validate_mdi_setting(hw);
-
-	/*
-	 * before reading the NVM, reset the controller to
-	 * put the device in a known good starting state
-	 */
-	igb_reset_hw(hw);
-
-	/*
-	 * systems with ASPM and others may see the checksum fail on the first
-	 * attempt. Let's give it a few tries
-	 */
-	for (i = 0;; i++) {
-		if (igb_validate_nvm_checksum(&adapter->hw) >= 0)
-			break;
-		if (i == 2) {
-			err = -EIO;
-			DBG ( "The NVM Checksum Is Not Valid\n" );
-			DBG ( "err_eeprom\n" );
-			goto err_eeprom;
-		}
-	}
-
-	/* copy the MAC address out of the EEPROM */
-	if ( igb_read_mac_addr ( &adapter->hw ) ) {
-		DBG ( "EEPROM Read Error\n" );
-	}
-
-	memcpy ( netdev->hw_addr, adapter->hw.mac.perm_addr, ETH_ALEN );
-
-	/* reset the hardware with the new settings */
-	igb_reset ( adapter );
-
-	/* let the f/w know that the h/w is now under the control of the
-	 * driver. */
-	igb_get_hw_control(adapter);
-
-	if ( ( err = register_netdev ( netdev ) ) != 0) {
-		DBG ( "err_register\n" );
-		goto err_register;
-	}
-
-	/* Mark as link up; we don't yet handle link state */
-	netdev_link_up ( netdev );
-
-	for (i = 0; i < 6; i++) {
-		DBG ("%02x%s", netdev->ll_addr[i], i == 5 ? "\n" : ":");
-        }
-
-	DBG ( "igb_probe succeeded!\n" );
-
-	/* No errors, return success */
-	return 0;
-
-/* Error return paths */
-err_register:
-err_eeprom:
-err_sw_init:
-	iounmap ( adapter->hw.hw_addr );
-err_ioremap:
-	netdev_put ( netdev );
-err_alloc_etherdev:
-	return err;
-}
-
-/**
- * igb_remove - Device Removal Routine
- *
- * @v pdev PCI device information struct
- *
- **/
-void igb_remove ( struct pci_device *pdev )
-{
-	struct net_device *netdev = pci_get_drvdata ( pdev );
-	struct igb_adapter *adapter = netdev_priv ( netdev );
-
-	DBGP ( "igb_remove\n" );
-
-	if ( adapter->hw.flash_address )
-		iounmap ( adapter->hw.flash_address );
-	if  ( adapter->hw.hw_addr )
-		iounmap ( adapter->hw.hw_addr );
-
-	unregister_netdev ( netdev );
-	igb_reset  ( adapter );
-	netdev_nullify ( netdev );
-	netdev_put ( netdev );
-}
-
-/**
- * igb_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 igb_open ( struct net_device *netdev )
-{
-	struct igb_adapter *adapter = netdev_priv(netdev);
-	int err;
-
-	DBGP ( "igb_open\n" );
-
-	/* allocate transmit descriptors */
-	err = igb_setup_tx_resources ( adapter );
-	if ( err ) {
-		DBG ( "Error setting up TX resources!\n" );
-		goto err_setup_tx;
-	}
-
-	/* allocate receive descriptors */
-	err = igb_setup_rx_resources ( adapter );
-	if ( err ) {
-		DBG ( "Error setting up RX resources!\n" );
-		goto err_setup_rx;
-	}
-
-	igb_configure_tx ( adapter );
-
-	igb_configure_rx ( adapter );
-
-	DBG ( "E1000_RXDCTL(0): %#08x\n",  E1000_READ_REG ( &adapter->hw, E1000_RXDCTL(0) ) );
-
-	return 0;
-
-err_setup_rx:
-	DBG ( "err_setup_rx\n" );
-	igb_free_tx_resources ( adapter );
-err_setup_tx:
-	DBG ( "err_setup_tx\n" );
-	igb_reset ( adapter );
-
-	return err;
-}
-
-/** igb net device operations */
-static struct net_device_operations igb_operations = {
-	.open		= igb_open,
-	.close		= igb_close,
-	.transmit	= igb_transmit,
-	.poll		= igb_poll,
-	.irq		= igb_irq,
-};
diff --git a/roms/ipxe/src/drivers/net/igb/igb_manage.c b/roms/ipxe/src/drivers/net/igb/igb_manage.c
deleted file mode 100644
index b29d4c4a5c1e8b685dd5558cc6c12b9355039fd6..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_manage.c
+++ /dev/null
@@ -1,388 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#include "igb.h"
-
-#if 0
-
-static u8 e1000_calculate_checksum(u8 *buffer, u32 length);
-
-/**
- *  e1000_calculate_checksum - Calculate checksum for buffer
- *  @buffer: pointer to EEPROM
- *  @length: size of EEPROM to calculate a checksum for
- *
- *  Calculates the checksum for some buffer on a specified length.  The
- *  checksum calculated is returned.
- **/
-static u8 e1000_calculate_checksum(u8 *buffer, u32 length)
-{
-	u32 i;
-	u8  sum = 0;
-
-	DEBUGFUNC("igb_calculate_checksum");
-
-	if (!buffer)
-		return 0;
-
-	for (i = 0; i < length; i++)
-		sum += buffer[i];
-
-	return (u8) (0 - sum);
-}
-
-/**
- *  e1000_mng_enable_host_if_generic - Checks host interface is enabled
- *  @hw: pointer to the HW structure
- *
- *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
- *
- *  This function checks whether the HOST IF is enabled for command operation
- *  and also checks whether the previous command is completed.  It busy waits
- *  in case of previous command is not completed.
- **/
-s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw)
-{
-	u32 hicr;
-	s32 ret_val = E1000_SUCCESS;
-	u8  i;
-
-	DEBUGFUNC("igb_mng_enable_host_if_generic");
-
-	/* Check that the host interface is enabled. */
-	hicr = E1000_READ_REG(hw, E1000_HICR);
-	if ((hicr & E1000_HICR_EN) == 0) {
-		DEBUGOUT("E1000_HOST_EN bit disabled.\n");
-		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
-		goto out;
-	}
-	/* check the previous command is completed */
-	for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
-		hicr = E1000_READ_REG(hw, E1000_HICR);
-		if (!(hicr & E1000_HICR_C))
-			break;
-		msec_delay_irq(1);
-	}
-
-	if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
-		DEBUGOUT("Previous command timeout failed .\n");
-		ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_check_mng_mode_generic - Generic check management mode
- *  @hw: pointer to the HW structure
- *
- *  Reads the firmware semaphore register and returns true (>0) if
- *  manageability is enabled, else false (0).
- **/
-bool e1000_check_mng_mode_generic(struct e1000_hw *hw)
-{
-	u32 fwsm;
-
-	DEBUGFUNC("igb_check_mng_mode_generic");
-
-	fwsm = E1000_READ_REG(hw, E1000_FWSM);
-
-	return (fwsm & E1000_FWSM_MODE_MASK) ==
-	        (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
-}
-
-/**
- *  e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on TX
- *  @hw: pointer to the HW structure
- *
- *  Enables packet filtering on transmit packets if manageability is enabled
- *  and host interface is enabled.
- **/
-bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw)
-{
-	struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
-	u32 *buffer = (u32 *)&hw->mng_cookie;
-	u32 offset;
-	s32 ret_val, hdr_csum, csum;
-	u8 i, len;
-	bool tx_filter = true;
-
-	DEBUGFUNC("igb_enable_tx_pkt_filtering_generic");
-
-	/* No manageability, no filtering */
-	if (!hw->mac.ops.check_mng_mode(hw)) {
-		tx_filter = false;
-		goto out;
-	}
-
-	/*
-	 * If we can't read from the host interface for whatever
-	 * reason, disable filtering.
-	 */
-	ret_val = hw->mac.ops.mng_enable_host_if(hw);
-	if (ret_val != E1000_SUCCESS) {
-		tx_filter = false;
-		goto out;
-	}
-
-	/* Read in the header.  Length and offset are in dwords. */
-	len    = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
-	offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
-	for (i = 0; i < len; i++) {
-		*(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw,
-		                                           E1000_HOST_IF,
-		                                           offset + i);
-	}
-	hdr_csum = hdr->checksum;
-	hdr->checksum = 0;
-	csum = e1000_calculate_checksum((u8 *)hdr,
-	                                E1000_MNG_DHCP_COOKIE_LENGTH);
-	/*
-	 * If either the checksums or signature don't match, then
-	 * the cookie area isn't considered valid, in which case we
-	 * take the safe route of assuming Tx filtering is enabled.
-	 */
-	if (hdr_csum != csum)
-		goto out;
-	if (hdr->signature != E1000_IAMT_SIGNATURE)
-		goto out;
-
-	/* Cookie area is valid, make the final check for filtering. */
-	if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING))
-		tx_filter = false;
-
-out:
-	hw->mac.tx_pkt_filtering = tx_filter;
-	return tx_filter;
-}
-
-/**
- *  e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface
- *  @hw: pointer to the HW structure
- *  @buffer: pointer to the host interface
- *  @length: size of the buffer
- *
- *  Writes the DHCP information to the host interface.
- **/
-s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer,
-                                      u16 length)
-{
-	struct e1000_host_mng_command_header hdr;
-	s32 ret_val;
-	u32 hicr;
-
-	DEBUGFUNC("igb_mng_write_dhcp_info_generic");
-
-	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
-	hdr.command_length = length;
-	hdr.reserved1 = 0;
-	hdr.reserved2 = 0;
-	hdr.checksum = 0;
-
-	/* Enable the host interface */
-	ret_val = hw->mac.ops.mng_enable_host_if(hw);
-	if (ret_val)
-		goto out;
-
-	/* Populate the host interface with the contents of "buffer". */
-	ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
-	                                  sizeof(hdr), &(hdr.checksum));
-	if (ret_val)
-		goto out;
-
-	/* Write the manageability command header */
-	ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
-	if (ret_val)
-		goto out;
-
-	/* Tell the ARC a new command is pending. */
-	hicr = E1000_READ_REG(hw, E1000_HICR);
-	E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C);
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_mng_write_cmd_header_generic - Writes manageability command header
- *  @hw: pointer to the HW structure
- *  @hdr: pointer to the host interface command header
- *
- *  Writes the command header after does the checksum calculation.
- **/
-s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
-                                    struct e1000_host_mng_command_header *hdr)
-{
-	u16 i, length = sizeof(struct e1000_host_mng_command_header);
-
-	DEBUGFUNC("igb_mng_write_cmd_header_generic");
-
-	/* Write the whole command header structure with new checksum. */
-
-	hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
-
-	length >>= 2;
-	/* Write the relevant command block into the ram area. */
-	for (i = 0; i < length; i++) {
-		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i,
-		                            *((u32 *) hdr + i));
-		E1000_WRITE_FLUSH(hw);
-	}
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  e1000_mng_host_if_write_generic - Write to the manageability host interface
- *  @hw: pointer to the HW structure
- *  @buffer: pointer to the host interface buffer
- *  @length: size of the buffer
- *  @offset: location in the buffer to write to
- *  @sum: sum of the data (not checksum)
- *
- *  This function writes the buffer content at the offset given on the host if.
- *  It also does alignment considerations to do the writes in most efficient
- *  way.  Also fills up the sum of the buffer in *buffer parameter.
- **/
-s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
-                                    u16 length, u16 offset, u8 *sum)
-{
-	u8 *tmp;
-	u8 *bufptr = buffer;
-	u32 data = 0;
-	s32 ret_val = E1000_SUCCESS;
-	u16 remaining, i, j, prev_bytes;
-
-	DEBUGFUNC("igb_mng_host_if_write_generic");
-
-	/* sum = only sum of the data and it is not checksum */
-
-	if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) {
-		ret_val = -E1000_ERR_PARAM;
-		goto out;
-	}
-
-	tmp = (u8 *)&data;
-	prev_bytes = offset & 0x3;
-	offset >>= 2;
-
-	if (prev_bytes) {
-		data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset);
-		for (j = prev_bytes; j < sizeof(u32); j++) {
-			*(tmp + j) = *bufptr++;
-			*sum += *(tmp + j);
-		}
-		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data);
-		length -= j - prev_bytes;
-		offset++;
-	}
-
-	remaining = length & 0x3;
-	length -= remaining;
-
-	/* Calculate length in DWORDs */
-	length >>= 2;
-
-	/*
-	 * The device driver writes the relevant command block into the
-	 * ram area.
-	 */
-	for (i = 0; i < length; i++) {
-		for (j = 0; j < sizeof(u32); j++) {
-			*(tmp + j) = *bufptr++;
-			*sum += *(tmp + j);
-		}
-
-		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i,
-		                            data);
-	}
-	if (remaining) {
-		for (j = 0; j < sizeof(u32); j++) {
-			if (j < remaining)
-				*(tmp + j) = *bufptr++;
-			else
-				*(tmp + j) = 0;
-
-			*sum += *(tmp + j);
-		}
-		E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  e1000_enable_mng_pass_thru - Enable processing of ARP's
- *  @hw: pointer to the HW structure
- *
- *  Verifies the hardware needs to allow ARPs to be processed by the host.
- **/
-bool e1000_enable_mng_pass_thru(struct e1000_hw *hw)
-{
-	u32 manc;
-	u32 fwsm, factps;
-	bool ret_val = false;
-
-	DEBUGFUNC("igb_enable_mng_pass_thru");
-
-	if (!hw->mac.asf_firmware_present)
-		goto out;
-
-	manc = E1000_READ_REG(hw, E1000_MANC);
-
-	if (!(manc & E1000_MANC_RCV_TCO_EN) ||
-	    !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
-		goto out;
-
-	if (hw->mac.arc_subsystem_valid) {
-		fwsm = E1000_READ_REG(hw, E1000_FWSM);
-		factps = E1000_READ_REG(hw, E1000_FACTPS);
-
-		if (!(factps & E1000_FACTPS_MNGCG) &&
-		    ((fwsm & E1000_FWSM_MODE_MASK) ==
-		     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
-			ret_val = true;
-			goto out;
-		}
-	} else {
-		if ((manc & E1000_MANC_SMBUS_EN) &&
-		    !(manc & E1000_MANC_ASF_EN)) {
-			ret_val = true;
-			goto out;
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-#endif
diff --git a/roms/ipxe/src/drivers/net/igb/igb_manage.h b/roms/ipxe/src/drivers/net/igb/igb_manage.h
deleted file mode 100644
index ff70d8c9ee3f881ff1da156e65d0afb2ef6cf987..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_manage.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#ifndef _IGB_MANAGE_H_
-#define _IGB_MANAGE_H_
-
-bool e1000_check_mng_mode_generic(struct e1000_hw *hw);
-bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw);
-s32  e1000_mng_enable_host_if_generic(struct e1000_hw *hw);
-s32  e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer,
-                                     u16 length, u16 offset, u8 *sum);
-s32  e1000_mng_write_cmd_header_generic(struct e1000_hw *hw,
-                                    struct e1000_host_mng_command_header *hdr);
-s32  e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw,
-                                       u8 *buffer, u16 length);
-bool e1000_enable_mng_pass_thru(struct e1000_hw *hw);
-
-enum e1000_mng_mode {
-	e1000_mng_mode_none = 0,
-	e1000_mng_mode_asf,
-	e1000_mng_mode_pt,
-	e1000_mng_mode_ipmi,
-	e1000_mng_mode_host_if_only
-};
-
-#define E1000_FACTPS_MNGCG    0x20000000
-
-#define E1000_FWSM_MODE_MASK  0xE
-#define E1000_FWSM_MODE_SHIFT 1
-
-#define E1000_MNG_IAMT_MODE                  0x3
-#define E1000_MNG_DHCP_COOKIE_LENGTH         0x10
-#define E1000_MNG_DHCP_COOKIE_OFFSET         0x6F0
-#define E1000_MNG_DHCP_COMMAND_TIMEOUT       10
-#define E1000_MNG_DHCP_TX_PAYLOAD_CMD        64
-#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1
-#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN    0x2
-
-#define E1000_VFTA_ENTRY_SHIFT               5
-#define E1000_VFTA_ENTRY_MASK                0x7F
-#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK      0x1F
-
-#define E1000_HI_MAX_BLOCK_BYTE_LENGTH       1792 /* Num of bytes in range */
-#define E1000_HI_MAX_BLOCK_DWORD_LENGTH      448 /* Num of dwords in range */
-#define E1000_HI_COMMAND_TIMEOUT             500 /* Process HI command limit */
-
-#define E1000_HICR_EN              0x01  /* Enable bit - RO */
-/* Driver sets this bit when done to put command in RAM */
-#define E1000_HICR_C               0x02
-#define E1000_HICR_SV              0x04  /* Status Validity */
-#define E1000_HICR_FW_RESET_ENABLE 0x40
-#define E1000_HICR_FW_RESET        0x80
-
-/* Intel(R) Active Management Technology signature */
-#define E1000_IAMT_SIGNATURE  0x544D4149
-
-#endif /* _IGB_MANAGE_H_ */
diff --git a/roms/ipxe/src/drivers/net/igb/igb_nvm.c b/roms/ipxe/src/drivers/net/igb/igb_nvm.c
deleted file mode 100644
index 1bad567cf14ffdc4ae6d5ce54c62dfd5326954e6..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_nvm.c
+++ /dev/null
@@ -1,627 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#include "igb.h"
-
-static void igb_stop_nvm(struct e1000_hw *hw);
-static void igb_reload_nvm_generic(struct e1000_hw *hw);
-
-/**
- *  igb_init_nvm_ops_generic - Initialize NVM function pointers
- *  @hw: pointer to the HW structure
- *
- *  Setups up the function pointers to no-op functions
- **/
-void igb_init_nvm_ops_generic(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	DEBUGFUNC("igb_init_nvm_ops_generic");
-
-	/* Initialize function pointers */
-	nvm->ops.reload = igb_reload_nvm_generic;
-}
-
-/**
- *  igb_raise_eec_clk - Raise EEPROM clock
- *  @hw: pointer to the HW structure
- *  @eecd: pointer to the EEPROM
- *
- *  Enable/Raise the EEPROM clock bit.
- **/
-static void igb_raise_eec_clk(struct e1000_hw *hw, u32 *eecd)
-{
-	*eecd = *eecd | E1000_EECD_SK;
-	E1000_WRITE_REG(hw, E1000_EECD, *eecd);
-	E1000_WRITE_FLUSH(hw);
-	usec_delay(hw->nvm.delay_usec);
-}
-
-/**
- *  igb_lower_eec_clk - Lower EEPROM clock
- *  @hw: pointer to the HW structure
- *  @eecd: pointer to the EEPROM
- *
- *  Clear/Lower the EEPROM clock bit.
- **/
-static void igb_lower_eec_clk(struct e1000_hw *hw, u32 *eecd)
-{
-	*eecd = *eecd & ~E1000_EECD_SK;
-	E1000_WRITE_REG(hw, E1000_EECD, *eecd);
-	E1000_WRITE_FLUSH(hw);
-	usec_delay(hw->nvm.delay_usec);
-}
-
-/**
- *  igb_shift_out_eec_bits - Shift data bits our to the EEPROM
- *  @hw: pointer to the HW structure
- *  @data: data to send to the EEPROM
- *  @count: number of bits to shift out
- *
- *  We need to shift 'count' bits out to the EEPROM.  So, the value in the
- *  "data" parameter will be shifted out to the EEPROM one bit at a time.
- *  In order to do this, "data" must be broken down into bits.
- **/
-static void igb_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
-	u32 mask;
-
-	DEBUGFUNC("igb_shift_out_eec_bits");
-
-	mask = 0x01 << (count - 1);
-	if (nvm->type == e1000_nvm_eeprom_spi)
-		eecd |= E1000_EECD_DO;
-
-	do {
-		eecd &= ~E1000_EECD_DI;
-
-		if (data & mask)
-			eecd |= E1000_EECD_DI;
-
-		E1000_WRITE_REG(hw, E1000_EECD, eecd);
-		E1000_WRITE_FLUSH(hw);
-
-		usec_delay(nvm->delay_usec);
-
-		igb_raise_eec_clk(hw, &eecd);
-		igb_lower_eec_clk(hw, &eecd);
-
-		mask >>= 1;
-	} while (mask);
-
-	eecd &= ~E1000_EECD_DI;
-	E1000_WRITE_REG(hw, E1000_EECD, eecd);
-}
-
-/**
- *  igb_shift_in_eec_bits - Shift data bits in from the EEPROM
- *  @hw: pointer to the HW structure
- *  @count: number of bits to shift in
- *
- *  In order to read a register from the EEPROM, we need to shift 'count' bits
- *  in from the EEPROM.  Bits are "shifted in" by raising the clock input to
- *  the EEPROM (setting the SK bit), and then reading the value of the data out
- *  "DO" bit.  During this "shifting in" process the data in "DI" bit should
- *  always be clear.
- **/
-static u16 igb_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
-{
-	u32 eecd;
-	u32 i;
-	u16 data;
-
-	DEBUGFUNC("igb_shift_in_eec_bits");
-
-	eecd = E1000_READ_REG(hw, E1000_EECD);
-
-	eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
-	data = 0;
-
-	for (i = 0; i < count; i++) {
-		data <<= 1;
-		igb_raise_eec_clk(hw, &eecd);
-
-		eecd = E1000_READ_REG(hw, E1000_EECD);
-
-		eecd &= ~E1000_EECD_DI;
-		if (eecd & E1000_EECD_DO)
-			data |= 1;
-
-		igb_lower_eec_clk(hw, &eecd);
-	}
-
-	return data;
-}
-
-/**
- *  igb_poll_eerd_eewr_done - Poll for EEPROM read/write completion
- *  @hw: pointer to the HW structure
- *  @ee_reg: EEPROM flag for polling
- *
- *  Polls the EEPROM status bit for either read or write completion based
- *  upon the value of 'ee_reg'.
- **/
-s32 igb_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
-{
-	u32 attempts = 100000;
-	u32 i, reg = 0;
-	s32 ret_val = -E1000_ERR_NVM;
-
-	DEBUGFUNC("igb_poll_eerd_eewr_done");
-
-	for (i = 0; i < attempts; i++) {
-		if (ee_reg == E1000_NVM_POLL_READ)
-			reg = E1000_READ_REG(hw, E1000_EERD);
-		else
-			reg = E1000_READ_REG(hw, E1000_EEWR);
-
-		if (reg & E1000_NVM_RW_REG_DONE) {
-			ret_val = E1000_SUCCESS;
-			break;
-		}
-
-		usec_delay(5);
-	}
-
-	return ret_val;
-}
-
-/**
- *  igb_acquire_nvm_generic - Generic request for access to EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
- *  Return successful if access grant bit set, else clear the request for
- *  EEPROM access and return -E1000_ERR_NVM (-1).
- **/
-s32 igb_acquire_nvm_generic(struct e1000_hw *hw)
-{
-	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
-	s32 timeout = E1000_NVM_GRANT_ATTEMPTS;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_acquire_nvm_generic");
-
-	E1000_WRITE_REG(hw, E1000_EECD, eecd | E1000_EECD_REQ);
-	eecd = E1000_READ_REG(hw, E1000_EECD);
-
-	while (timeout) {
-		if (eecd & E1000_EECD_GNT)
-			break;
-		usec_delay(5);
-		eecd = E1000_READ_REG(hw, E1000_EECD);
-		timeout--;
-	}
-
-	if (!timeout) {
-		eecd &= ~E1000_EECD_REQ;
-		E1000_WRITE_REG(hw, E1000_EECD, eecd);
-		DEBUGOUT("Could not acquire NVM grant\n");
-		ret_val = -E1000_ERR_NVM;
-	}
-
-	return ret_val;
-}
-
-/**
- *  igb_standby_nvm - Return EEPROM to standby state
- *  @hw: pointer to the HW structure
- *
- *  Return the EEPROM to a standby state.
- **/
-static void igb_standby_nvm(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
-
-	DEBUGFUNC("igb_standby_nvm");
-
-	if (nvm->type == e1000_nvm_eeprom_spi) {
-		/* Toggle CS to flush commands */
-		eecd |= E1000_EECD_CS;
-		E1000_WRITE_REG(hw, E1000_EECD, eecd);
-		E1000_WRITE_FLUSH(hw);
-		usec_delay(nvm->delay_usec);
-		eecd &= ~E1000_EECD_CS;
-		E1000_WRITE_REG(hw, E1000_EECD, eecd);
-		E1000_WRITE_FLUSH(hw);
-		usec_delay(nvm->delay_usec);
-	}
-}
-
-/**
- *  igb_stop_nvm - Terminate EEPROM command
- *  @hw: pointer to the HW structure
- *
- *  Terminates the current command by inverting the EEPROM's chip select pin.
- **/
-static void igb_stop_nvm(struct e1000_hw *hw)
-{
-	u32 eecd;
-
-	DEBUGFUNC("igb_stop_nvm");
-
-	eecd = E1000_READ_REG(hw, E1000_EECD);
-	if (hw->nvm.type == e1000_nvm_eeprom_spi) {
-		/* Pull CS high */
-		eecd |= E1000_EECD_CS;
-		igb_lower_eec_clk(hw, &eecd);
-	}
-}
-
-/**
- *  igb_release_nvm_generic - Release exclusive access to EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
- **/
-void igb_release_nvm_generic(struct e1000_hw *hw)
-{
-	u32 eecd;
-
-	DEBUGFUNC("igb_release_nvm_generic");
-
-	igb_stop_nvm(hw);
-
-	eecd = E1000_READ_REG(hw, E1000_EECD);
-	eecd &= ~E1000_EECD_REQ;
-	E1000_WRITE_REG(hw, E1000_EECD, eecd);
-}
-
-/**
- *  igb_ready_nvm_eeprom - Prepares EEPROM for read/write
- *  @hw: pointer to the HW structure
- *
- *  Setups the EEPROM for reading and writing.
- **/
-static s32 igb_ready_nvm_eeprom(struct e1000_hw *hw)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
-	s32 ret_val = E1000_SUCCESS;
-	u16 timeout = 0;
-	u8 spi_stat_reg;
-
-	DEBUGFUNC("igb_ready_nvm_eeprom");
-
-	if (nvm->type == e1000_nvm_eeprom_spi) {
-		/* Clear SK and CS */
-		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
-		E1000_WRITE_REG(hw, E1000_EECD, eecd);
-		usec_delay(1);
-		timeout = NVM_MAX_RETRY_SPI;
-
-		/*
-		 * Read "Status Register" repeatedly until the LSB is cleared.
-		 * The EEPROM will signal that the command has been completed
-		 * by clearing bit 0 of the internal status register.  If it's
-		 * not cleared within 'timeout', then error out.
-		 */
-		while (timeout) {
-			igb_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
-			                         hw->nvm.opcode_bits);
-			spi_stat_reg = (u8)igb_shift_in_eec_bits(hw, 8);
-			if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
-				break;
-
-			usec_delay(5);
-			igb_standby_nvm(hw);
-			timeout--;
-		}
-
-		if (!timeout) {
-			DEBUGOUT("SPI NVM Status error\n");
-			ret_val = -E1000_ERR_NVM;
-			goto out;
-		}
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_read_nvm_eerd - Reads EEPROM using EERD register
- *  @hw: pointer to the HW structure
- *  @offset: offset of word in the EEPROM to read
- *  @words: number of words to read
- *  @data: word read from the EEPROM
- *
- *  Reads a 16 bit word from the EEPROM using the EERD register.
- **/
-s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	u32 i, eerd = 0;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_read_nvm_eerd");
-
-	/*
-	 * A check for invalid values:  offset too large, too many words,
-	 * too many words for the offset, and not enough words.
-	 */
-	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
-	    (words == 0)) {
-		DEBUGOUT("nvm parameter(s) out of bounds\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	for (i = 0; i < words; i++) {
-		eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
-		       E1000_NVM_RW_REG_START;
-
-		E1000_WRITE_REG(hw, E1000_EERD, eerd);
-		ret_val = igb_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
-		if (ret_val)
-			break;
-
-		data[i] = (E1000_READ_REG(hw, E1000_EERD) >>
-		           E1000_NVM_RW_REG_DATA);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_write_nvm_spi - Write to EEPROM using SPI
- *  @hw: pointer to the HW structure
- *  @offset: offset within the EEPROM to be written to
- *  @words: number of words to write
- *  @data: 16 bit word(s) to be written to the EEPROM
- *
- *  Writes data to EEPROM at offset using SPI interface.
- *
- *  If e1000_update_nvm_checksum is not called after this function , the
- *  EEPROM will most likely contain an invalid checksum.
- **/
-s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
-{
-	struct e1000_nvm_info *nvm = &hw->nvm;
-	s32 ret_val;
-	u16 widx = 0;
-
-	DEBUGFUNC("igb_write_nvm_spi");
-
-	/*
-	 * A check for invalid values:  offset too large, too many words,
-	 * and not enough words.
-	 */
-	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
-	    (words == 0)) {
-		DEBUGOUT("nvm parameter(s) out of bounds\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-	ret_val = nvm->ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	while (widx < words) {
-		u8 write_opcode = NVM_WRITE_OPCODE_SPI;
-
-		ret_val = igb_ready_nvm_eeprom(hw);
-		if (ret_val)
-			goto release;
-
-		igb_standby_nvm(hw);
-
-		/* Send the WRITE ENABLE command (8 bit opcode) */
-		igb_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
-		                         nvm->opcode_bits);
-
-		igb_standby_nvm(hw);
-
-		/*
-		 * Some SPI eeproms use the 8th address bit embedded in the
-		 * opcode
-		 */
-		if ((nvm->address_bits == 8) && (offset >= 128))
-			write_opcode |= NVM_A8_OPCODE_SPI;
-
-		/* Send the Write command (8-bit opcode + addr) */
-		igb_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
-		igb_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
-		                         nvm->address_bits);
-
-		/* Loop to allow for up to whole page write of eeprom */
-		while (widx < words) {
-			u16 word_out = data[widx];
-			word_out = (word_out >> 8) | (word_out << 8);
-			igb_shift_out_eec_bits(hw, word_out, 16);
-			widx++;
-
-			if ((((offset + widx) * 2) % nvm->page_size) == 0) {
-				igb_standby_nvm(hw);
-				break;
-			}
-		}
-	}
-
-	msec_delay(10);
-release:
-	nvm->ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_read_pba_num_generic - Read device part number
- *  @hw: pointer to the HW structure
- *  @pba_num: pointer to device part number
- *
- *  Reads the product board assembly (PBA) number from the EEPROM and stores
- *  the value in pba_num.
- **/
-s32 igb_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num)
-{
-	s32  ret_val;
-	u16 nvm_data;
-
-	DEBUGFUNC("igb_read_pba_num_generic");
-
-	ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
-	if (ret_val) {
-		DEBUGOUT("NVM Read Error\n");
-		goto out;
-	}
-	*pba_num = (u32)(nvm_data << 16);
-
-	ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
-	if (ret_val) {
-		DEBUGOUT("NVM Read Error\n");
-		goto out;
-	}
-	*pba_num |= nvm_data;
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_read_mac_addr_generic - Read device MAC address
- *  @hw: pointer to the HW structure
- *
- *  Reads the device MAC address from the EEPROM and stores the value.
- *  Since devices with two ports use the same EEPROM, we increment the
- *  last bit in the MAC address for the second port.
- **/
-s32 igb_read_mac_addr_generic(struct e1000_hw *hw)
-{
-	u32 rar_high;
-	u32 rar_low;
-	u16 i;
-
-	rar_high = E1000_READ_REG(hw, E1000_RAH(0));
-	rar_low = E1000_READ_REG(hw, E1000_RAL(0));
-
-	for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++)
-		hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8));
-
-	for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++)
-		hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8));
-
-	for (i = 0; i < ETH_ADDR_LEN; i++)
-		hw->mac.addr[i] = hw->mac.perm_addr[i];
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_validate_nvm_checksum_generic - Validate EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
- *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
- **/
-s32 igb_validate_nvm_checksum_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 checksum = 0;
-	u16 i, nvm_data;
-
-	DEBUGFUNC("igb_validate_nvm_checksum_generic");
-
-	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
-		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
-		if (ret_val) {
-			DEBUGOUT("NVM Read Error\n");
-			goto out;
-		}
-		checksum += nvm_data;
-	}
-
-	if (checksum != (u16) NVM_SUM) {
-		DEBUGOUT("NVM Checksum Invalid\n");
-		ret_val = -E1000_ERR_NVM;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_update_nvm_checksum_generic - Update EEPROM checksum
- *  @hw: pointer to the HW structure
- *
- *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
- *  up to the checksum.  Then calculates the EEPROM checksum and writes the
- *  value to the EEPROM.
- **/
-s32 igb_update_nvm_checksum_generic(struct e1000_hw *hw)
-{
-	s32  ret_val;
-	u16 checksum = 0;
-	u16 i, nvm_data;
-
-	DEBUGFUNC("igb_update_nvm_checksum");
-
-	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
-		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
-		if (ret_val) {
-			DEBUGOUT("NVM Read Error while updating checksum.\n");
-			goto out;
-		}
-		checksum += nvm_data;
-	}
-	checksum = (u16) NVM_SUM - checksum;
-	ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum);
-	if (ret_val) {
-		DEBUGOUT("NVM Write Error while updating checksum.\n");
-        }
-out:
-	return ret_val;
-}
-
-/**
- *  igb_reload_nvm_generic - Reloads EEPROM
- *  @hw: pointer to the HW structure
- *
- *  Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
- *  extended control register.
- **/
-static void igb_reload_nvm_generic(struct e1000_hw *hw)
-{
-	u32 ctrl_ext;
-
-	DEBUGFUNC("igb_reload_nvm_generic");
-
-	usec_delay(10);
-	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
-	ctrl_ext |= E1000_CTRL_EXT_EE_RST;
-	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
-	E1000_WRITE_FLUSH(hw);
-}
-
diff --git a/roms/ipxe/src/drivers/net/igb/igb_nvm.h b/roms/ipxe/src/drivers/net/igb/igb_nvm.h
deleted file mode 100644
index 6b54d44ce5805a7da9982c77f8cfc2dfd4ac1f78..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_nvm.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#ifndef _IGB_NVM_H_
-#define _IGB_NVM_H_
-
-void igb_init_nvm_ops_generic(struct e1000_hw *hw);
-s32  igb_acquire_nvm_generic(struct e1000_hw *hw);
-
-s32  igb_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
-s32  igb_read_mac_addr_generic(struct e1000_hw *hw);
-s32  igb_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num);
-s32  igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words,
-                         u16 *data);
-s32  igb_valid_led_default_generic(struct e1000_hw *hw, u16 *data);
-s32  igb_validate_nvm_checksum_generic(struct e1000_hw *hw);
-s32  igb_write_nvm_eewr(struct e1000_hw *hw, u16 offset,
-                          u16 words, u16 *data);
-s32  igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words,
-                         u16 *data);
-s32  igb_update_nvm_checksum_generic(struct e1000_hw *hw);
-void igb_release_nvm_generic(struct e1000_hw *hw);
-
-#define E1000_STM_OPCODE  0xDB00
-
-#endif /* _IGB_NVM_H_ */
diff --git a/roms/ipxe/src/drivers/net/igb/igb_osdep.h b/roms/ipxe/src/drivers/net/igb/igb_osdep.h
deleted file mode 100644
index 167b0f85c60da17622389a76e8440a5290910580..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_osdep.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-/* glue for the OS independent part of e1000
- * includes register access macros
- */
-
-#ifndef _IGB_OSDEP_H_
-#define _IGB_OSDEP_H_
-
-/* Begin OS Dependencies */
-
-#define u8         unsigned char
-#define bool       boolean_t
-#define dma_addr_t unsigned long
-#define __le16     uint16_t
-#define __le32     uint32_t
-#define __le64     uint64_t
-
-#define __iomem
-#define __devinit
-
-#define msleep(x) mdelay(x)
-
-#define ETH_FCS_LEN 4
-
-typedef int spinlock_t;
-typedef enum {
-    false = 0,
-    true = 1
-} boolean_t;
-
-#define TRUE  1
-#define FALSE 0
-
-#define usec_delay(x) udelay(x)
-#define msec_delay(x) mdelay(x)
-#define msec_delay_irq(x) mdelay(x)
-
-/* End OS Dependencies */
-
-#define PCI_COMMAND_REGISTER   PCI_COMMAND
-#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
-#define ETH_ADDR_LEN           ETH_ALEN
-
-#ifdef __BIG_ENDIAN
-#define E1000_BIG_ENDIAN __BIG_ENDIAN
-#endif
-
-
-#define DEBUGOUT(S) if (0) { printf(S); }
-#define DEBUGOUT1(S, A...) if (0) { printf(S, A); }
-
-#define DEBUGFUNC(F) DEBUGOUT(F "\n")
-#define DEBUGOUT2 DEBUGOUT1
-#define DEBUGOUT3 DEBUGOUT2
-#define DEBUGOUT7 DEBUGOUT3
-
-#define E1000_REGISTER(a, reg) (reg)
-
-#define E1000_WRITE_REG(a, reg, value) do {  \
-                writel((value), ((a)->hw_addr + E1000_REGISTER(a, reg))); } while (0)
-
-#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + E1000_REGISTER(a, reg)))
-
-#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) do { \
-          writel((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 2))); } while (0);
-
-#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
-    readl((a)->hw_addr + E1000_REGISTER(a, reg) + ((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) ( \
-    writew((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 1))))
-
-#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \
-    readw((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 1)))
-
-#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \
-    writeb((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + (offset))))
-
-#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \
-    readb((a)->hw_addr + E1000_REGISTER(a, reg) + (offset)))
-
-#define E1000_WRITE_REG_IO(a, reg, offset) do { \
-    outl(reg, ((a)->io_base));                  \
-    outl(offset, ((a)->io_base + 4));      } while (0)
-
-#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, E1000_STATUS)
-
-#define E1000_WRITE_FLASH_REG(a, reg, value) ( \
-    writel((value), ((a)->flash_address + reg)))
-
-#define E1000_WRITE_FLASH_REG16(a, reg, value) ( \
-    writew((value), ((a)->flash_address + reg)))
-
-#define E1000_READ_FLASH_REG(a, reg) (readl((a)->flash_address + reg))
-
-#define E1000_READ_FLASH_REG16(a, reg) (readw((a)->flash_address + reg))
-
-#endif /* _IGB_OSDEP_H_ */
diff --git a/roms/ipxe/src/drivers/net/igb/igb_phy.c b/roms/ipxe/src/drivers/net/igb/igb_phy.c
deleted file mode 100644
index 16664fd1f02c9982ff2684c91245390a095ac4d5..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_phy.c
+++ /dev/null
@@ -1,2470 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#include "igb.h"
-
-static s32 igb_phy_setup_autoneg(struct e1000_hw *hw);
-
-#if 0
-/* Cable length tables */
-static const u16 e1000_m88_cable_length_table[] =
-	{ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
-#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
-                (sizeof(e1000_m88_cable_length_table) / \
-                 sizeof(e1000_m88_cable_length_table[0]))
-
-static const u16 e1000_igp_2_cable_length_table[] =
-    { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
-      0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
-      6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
-      21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
-      40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
-      60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
-      83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
-      104, 109, 114, 118, 121, 124};
-#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
-                (sizeof(e1000_igp_2_cable_length_table) / \
-                 sizeof(e1000_igp_2_cable_length_table[0]))
-#endif
-
-/**
- *  igb_check_reset_block_generic - Check if PHY reset is blocked
- *  @hw: pointer to the HW structure
- *
- *  Read the PHY management control register and check whether a PHY reset
- *  is blocked.  If a reset is not blocked return E1000_SUCCESS, otherwise
- *  return E1000_BLK_PHY_RESET (12).
- **/
-s32 igb_check_reset_block_generic(struct e1000_hw *hw)
-{
-	u32 manc;
-
-	DEBUGFUNC("igb_check_reset_block");
-
-	manc = E1000_READ_REG(hw, E1000_MANC);
-
-	return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
-	       E1000_BLK_PHY_RESET : E1000_SUCCESS;
-}
-
-/**
- *  igb_get_phy_id - Retrieve the PHY ID and revision
- *  @hw: pointer to the HW structure
- *
- *  Reads the PHY registers and stores the PHY ID and possibly the PHY
- *  revision in the hardware structure.
- **/
-s32 igb_get_phy_id(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 phy_id;
-
-	DEBUGFUNC("igb_get_phy_id");
-
-	if (!(phy->ops.read_reg))
-		goto out;
-
-		ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id);
-		if (ret_val)
-			goto out;
-
-		phy->id = (u32)(phy_id << 16);
-		usec_delay(20);
-		ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id);
-		if (ret_val)
-			goto out;
-
-		phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
-		phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_phy_reset_dsp_generic - Reset PHY DSP
- *  @hw: pointer to the HW structure
- *
- *  Reset the digital signal processor.
- **/
-s32 igb_phy_reset_dsp_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_phy_reset_dsp_generic");
-
-	if (!(hw->phy.ops.write_reg))
-		goto out;
-
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
-	if (ret_val)
-		goto out;
-
-	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_read_phy_reg_mdic - Read MDI control register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Reads the MDI control register in the PHY at offset and stores the
- *  information read to data.
- **/
-s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, mdic = 0;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_read_phy_reg_mdic");
-
-	/*
-	 * Set up Op-code, Phy Address, and register offset in the MDI
-	 * Control register.  The MAC will take care of interfacing with the
-	 * PHY to retrieve the desired data.
-	 */
-	mdic = ((offset << E1000_MDIC_REG_SHIFT) |
-	        (phy->addr << E1000_MDIC_PHY_SHIFT) |
-	        (E1000_MDIC_OP_READ));
-
-	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
-
-	/*
-	 * Poll the ready bit to see if the MDI read completed
-	 * Increasing the time out as testing showed failures with
-	 * the lower time out
-	 */
-	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
-		usec_delay(50);
-		mdic = E1000_READ_REG(hw, E1000_MDIC);
-		if (mdic & E1000_MDIC_READY)
-			break;
-	}
-	if (!(mdic & E1000_MDIC_READY)) {
-		DEBUGOUT("MDI Read did not complete\n");
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-	if (mdic & E1000_MDIC_ERROR) {
-		DEBUGOUT("MDI Error\n");
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-	*data = (u16) mdic;
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_write_phy_reg_mdic - Write MDI control register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write to register at offset
- *
- *  Writes data to MDI control register in the PHY at offset.
- **/
-s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, mdic = 0;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_write_phy_reg_mdic");
-
-	/*
-	 * Set up Op-code, Phy Address, and register offset in the MDI
-	 * Control register.  The MAC will take care of interfacing with the
-	 * PHY to retrieve the desired data.
-	 */
-	mdic = (((u32)data) |
-	        (offset << E1000_MDIC_REG_SHIFT) |
-	        (phy->addr << E1000_MDIC_PHY_SHIFT) |
-	        (E1000_MDIC_OP_WRITE));
-
-	E1000_WRITE_REG(hw, E1000_MDIC, mdic);
-
-	/*
-	 * Poll the ready bit to see if the MDI read completed
-	 * Increasing the time out as testing showed failures with
-	 * the lower time out
-	 */
-	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
-		usec_delay(50);
-		mdic = E1000_READ_REG(hw, E1000_MDIC);
-		if (mdic & E1000_MDIC_READY)
-			break;
-	}
-	if (!(mdic & E1000_MDIC_READY)) {
-		DEBUGOUT("MDI Write did not complete\n");
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-	if (mdic & E1000_MDIC_ERROR) {
-		DEBUGOUT("MDI Error\n");
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_read_phy_reg_i2c - Read PHY register using i2c
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Reads the PHY register at offset using the i2c interface and stores the
- *  retrieved information in data.
- **/
-s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, i2ccmd = 0;
-
-	DEBUGFUNC("igb_read_phy_reg_i2c");
-
-	/*
-	 * Set up Op-code, Phy Address, and register address in the I2CCMD
-	 * register.  The MAC will take care of interfacing with the
-	 * PHY to retrieve the desired data.
-	 */
-	i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
-	          (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
-	          (E1000_I2CCMD_OPCODE_READ));
-
-	E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
-
-	/* Poll the ready bit to see if the I2C read completed */
-	for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
-		usec_delay(50);
-		i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
-		if (i2ccmd & E1000_I2CCMD_READY)
-			break;
-	}
-	if (!(i2ccmd & E1000_I2CCMD_READY)) {
-		DEBUGOUT("I2CCMD Read did not complete\n");
-		return -E1000_ERR_PHY;
-	}
-	if (i2ccmd & E1000_I2CCMD_ERROR) {
-		DEBUGOUT("I2CCMD Error bit set\n");
-		return -E1000_ERR_PHY;
-	}
-
-	/* Need to byte-swap the 16-bit value. */
-	*data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_write_phy_reg_i2c - Write PHY register using i2c
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Writes the data to PHY register at the offset using the i2c interface.
- **/
-s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	u32 i, i2ccmd = 0;
-	u16 phy_data_swapped;
-
-	DEBUGFUNC("igb_write_phy_reg_i2c");
-
-	/* Swap the data bytes for the I2C interface */
-	phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
-
-	/*
-	 * Set up Op-code, Phy Address, and register address in the I2CCMD
-	 * register.  The MAC will take care of interfacing with the
-	 * PHY to retrieve the desired data.
-	 */
-	i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
-	          (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
-	          E1000_I2CCMD_OPCODE_WRITE |
-	          phy_data_swapped);
-
-	E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd);
-
-	/* Poll the ready bit to see if the I2C read completed */
-	for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
-		usec_delay(50);
-		i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD);
-		if (i2ccmd & E1000_I2CCMD_READY)
-			break;
-	}
-	if (!(i2ccmd & E1000_I2CCMD_READY)) {
-		DEBUGOUT("I2CCMD Write did not complete\n");
-		return -E1000_ERR_PHY;
-	}
-	if (i2ccmd & E1000_I2CCMD_ERROR) {
-		DEBUGOUT("I2CCMD Error bit set\n");
-		return -E1000_ERR_PHY;
-	}
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_read_phy_reg_m88 - Read m88 PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquires semaphore, if necessary, then reads the PHY register at offset
- *  and storing the retrieved information in data.  Release any acquired
- *  semaphores before exiting.
- **/
-s32 igb_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_read_phy_reg_m88");
-
-	if (!(hw->phy.ops.acquire))
-		goto out;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = igb_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                  data);
-
-	hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_write_phy_reg_m88 - Write m88 PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquires semaphore, if necessary, then writes the data to PHY register
- *  at the offset.  Release any acquired semaphores before exiting.
- **/
-s32 igb_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_write_phy_reg_m88");
-
-	if (!(hw->phy.ops.acquire))
-		goto out;
-
-	ret_val = hw->phy.ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = igb_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                   data);
-
-	hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  __igb_read_phy_reg_igp - Read igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *  @locked: semaphore has already been acquired or not
- *
- *  Acquires semaphore, if necessary, then reads the PHY register at offset
- *  and stores the retrieved information in data.  Release any acquired
- *  semaphores before exiting.
- **/
-static s32 __igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data,
-                                    bool locked)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("__igb_read_phy_reg_igp");
-
-	if (!locked) {
-		if (!(hw->phy.ops.acquire))
-			goto out;
-
-		ret_val = hw->phy.ops.acquire(hw);
-		if (ret_val)
-			goto out;
-	}
-
-	if (offset > MAX_PHY_MULTI_PAGE_REG) {
-		ret_val = igb_write_phy_reg_mdic(hw,
-		                                   IGP01E1000_PHY_PAGE_SELECT,
-		                                   (u16)offset);
-		if (ret_val)
-			goto release;
-	}
-
-	ret_val = igb_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                  data);
-
-release:
-	if (!locked)
-		hw->phy.ops.release(hw);
-out:
-	return ret_val;
-}
-/**
- *  igb_read_phy_reg_igp - Read igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquires semaphore then reads the PHY register at offset and stores the
- *  retrieved information in data.
- *  Release the acquired semaphore before exiting.
- **/
-s32 igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	return __igb_read_phy_reg_igp(hw, offset, data, false);
-}
-
-/**
- *  igb_read_phy_reg_igp_locked - Read igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Reads the PHY register at offset and stores the retrieved information
- *  in data.  Assumes semaphore already acquired.
- **/
-s32 igb_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	return __igb_read_phy_reg_igp(hw, offset, data, true);
-}
-
-/**
- *  igb_write_phy_reg_igp - Write igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *  @locked: semaphore has already been acquired or not
- *
- *  Acquires semaphore, if necessary, then writes the data to PHY register
- *  at the offset.  Release any acquired semaphores before exiting.
- **/
-static s32 __igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data,
-                                     bool locked)
-{
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_write_phy_reg_igp");
-
-	if (!locked) {
-		if (!(hw->phy.ops.acquire))
-			goto out;
-
-		ret_val = hw->phy.ops.acquire(hw);
-		if (ret_val)
-			goto out;
-	}
-
-	if (offset > MAX_PHY_MULTI_PAGE_REG) {
-		ret_val = igb_write_phy_reg_mdic(hw,
-		                                   IGP01E1000_PHY_PAGE_SELECT,
-		                                   (u16)offset);
-		if (ret_val)
-			goto release;
-	}
-
-	ret_val = igb_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
-	                                   data);
-
-release:
-	if (!locked)
-		hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_write_phy_reg_igp - Write igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquires semaphore then writes the data to PHY register
- *  at the offset.  Release any acquired semaphores before exiting.
- **/
-s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	return __igb_write_phy_reg_igp(hw, offset, data, false);
-}
-
-/**
- *  igb_write_phy_reg_igp_locked - Write igp PHY register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Writes the data to PHY register at the offset.
- *  Assumes semaphore already acquired.
- **/
-s32 igb_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	return __igb_write_phy_reg_igp(hw, offset, data, true);
-}
-
-/**
- *  __igb_read_kmrn_reg - Read kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *  @locked: semaphore has already been acquired or not
- *
- *  Acquires semaphore, if necessary.  Then reads the PHY register at offset
- *  using the kumeran interface.  The information retrieved is stored in data.
- *  Release any acquired semaphores before exiting.
- **/
-static s32 __igb_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data,
-                                 bool locked)
-{
-	u32 kmrnctrlsta;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("__igb_read_kmrn_reg");
-
-	if (!locked) {
-		if (!(hw->phy.ops.acquire))
-			goto out;
-
-		ret_val = hw->phy.ops.acquire(hw);
-		if (ret_val)
-			goto out;
-	}
-
-	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
-	               E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
-	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
-
-	usec_delay(2);
-
-	kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA);
-	*data = (u16)kmrnctrlsta;
-
-	if (!locked)
-		hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_read_kmrn_reg_generic -  Read kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Acquires semaphore then reads the PHY register at offset using the
- *  kumeran interface.  The information retrieved is stored in data.
- *  Release the acquired semaphore before exiting.
- **/
-s32 igb_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	return __igb_read_kmrn_reg(hw, offset, data, false);
-}
-
-/**
- *  igb_read_kmrn_reg_locked -  Read kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to be read
- *  @data: pointer to the read data
- *
- *  Reads the PHY register at offset using the kumeran interface.  The
- *  information retrieved is stored in data.
- *  Assumes semaphore already acquired.
- **/
-s32 igb_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data)
-{
-	return __igb_read_kmrn_reg(hw, offset, data, true);
-}
-
-/**
- *  __igb_write_kmrn_reg - Write kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *  @locked: semaphore has already been acquired or not
- *
- *  Acquires semaphore, if necessary.  Then write the data to PHY register
- *  at the offset using the kumeran interface.  Release any acquired semaphores
- *  before exiting.
- **/
-static s32 __igb_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data,
-                                  bool locked)
-{
-	u32 kmrnctrlsta;
-	s32 ret_val = E1000_SUCCESS;
-
-	DEBUGFUNC("igb_write_kmrn_reg_generic");
-
-	if (!locked) {
-		if (!(hw->phy.ops.acquire))
-			goto out;
-
-		ret_val = hw->phy.ops.acquire(hw);
-		if (ret_val)
-			goto out;
-	}
-
-	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
-	               E1000_KMRNCTRLSTA_OFFSET) | data;
-	E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta);
-
-	usec_delay(2);
-
-	if (!locked)
-		hw->phy.ops.release(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_write_kmrn_reg_generic -  Write kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Acquires semaphore then writes the data to the PHY register at the offset
- *  using the kumeran interface.  Release the acquired semaphore before exiting.
- **/
-s32 igb_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	return __igb_write_kmrn_reg(hw, offset, data, false);
-}
-
-/**
- *  igb_write_kmrn_reg_locked -  Write kumeran register
- *  @hw: pointer to the HW structure
- *  @offset: register offset to write to
- *  @data: data to write at register offset
- *
- *  Write the data to PHY register at the offset using the kumeran interface.
- *  Assumes semaphore already acquired.
- **/
-s32 igb_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data)
-{
-	return __igb_write_kmrn_reg(hw, offset, data, true);
-}
-
-/**
- *  igb_copper_link_setup_m88 - Setup m88 PHY's for copper link
- *  @hw: pointer to the HW structure
- *
- *  Sets up MDI/MDI-X and polarity for m88 PHY's.  If necessary, transmit clock
- *  and downshift values are set also.
- **/
-s32 igb_copper_link_setup_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data;
-
-	DEBUGFUNC("igb_copper_link_setup_m88");
-
-	if (phy->reset_disable) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	/* Enable CRS on TX. This must be set for half-duplex operation. */
-	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-
-	/*
-	 * Options:
-	 *   MDI/MDI-X = 0 (default)
-	 *   0 - Auto for all speeds
-	 *   1 - MDI mode
-	 *   2 - MDI-X mode
-	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
-	 */
-	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
-
-	switch (phy->mdix) {
-	case 1:
-		phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
-		break;
-	case 2:
-		phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
-		break;
-	case 3:
-		phy_data |= M88E1000_PSCR_AUTO_X_1000T;
-		break;
-	case 0:
-	default:
-		phy_data |= M88E1000_PSCR_AUTO_X_MODE;
-		break;
-	}
-
-	/*
-	 * Options:
-	 *   disable_polarity_correction = 0 (default)
-	 *       Automatic Correction for Reversed Cable Polarity
-	 *   0 - Disabled
-	 *   1 - Enabled
-	 */
-	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
-	if (phy->disable_polarity_correction == 1)
-		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
-
-	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
-	if (ret_val)
-		goto out;
-
-	if (phy->revision < E1000_REVISION_4) {
-		/*
-		 * Force TX_CLK in the Extended PHY Specific Control Register
-		 * to 25MHz clock.
-		 */
-		ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-		                             &phy_data);
-		if (ret_val)
-			goto out;
-
-		phy_data |= M88E1000_EPSCR_TX_CLK_25;
-
-		if ((phy->revision == E1000_REVISION_2) &&
-		    (phy->id == M88E1111_I_PHY_ID)) {
-			/* 82573L PHY - set the downshift counter to 5x. */
-			phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
-			phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
-		} else {
-			/* Configure Master and Slave downshift values */
-			phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
-			             M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
-			phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
-			             M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
-		}
-		ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
-		                             phy_data);
-		if (ret_val)
-			goto out;
-	}
-
-	/* Commit the changes. */
-	ret_val = phy->ops.commit(hw);
-	if (ret_val) {
-		DEBUGOUT("Error committing the PHY changes\n");
-		goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_copper_link_setup_igp - Setup igp PHY's for copper link
- *  @hw: pointer to the HW structure
- *
- *  Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
- *  igp PHY's.
- **/
-s32 igb_copper_link_setup_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-
-	DEBUGFUNC("igb_copper_link_setup_igp");
-
-	if (phy->reset_disable) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	ret_val = hw->phy.ops.reset(hw);
-	if (ret_val) {
-		DEBUGOUT("Error resetting the PHY.\n");
-		goto out;
-	}
-
-	/*
-	 * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
-	 * timeout issues when LFS is enabled.
-	 */
-	msec_delay(100);
-
-	/*
-	 * The NVM settings will configure LPLU in D3 for
-	 * non-IGP1 PHYs.
-	 */
-	if (phy->type == e1000_phy_igp) {
-		/* disable lplu d3 during driver init */
-		ret_val = hw->phy.ops.set_d3_lplu_state(hw, false);
-		if (ret_val) {
-			DEBUGOUT("Error Disabling LPLU D3\n");
-			goto out;
-		}
-	}
-
-	/* disable lplu d0 during driver init */
-	if (hw->phy.ops.set_d0_lplu_state) {
-		ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
-		if (ret_val) {
-			DEBUGOUT("Error Disabling LPLU D0\n");
-			goto out;
-		}
-	}
-	/* Configure mdi-mdix settings */
-	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data);
-	if (ret_val)
-		goto out;
-
-	data &= ~IGP01E1000_PSCR_AUTO_MDIX;
-
-	switch (phy->mdix) {
-	case 1:
-		data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
-		break;
-	case 2:
-		data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
-		break;
-	case 0:
-	default:
-		data |= IGP01E1000_PSCR_AUTO_MDIX;
-		break;
-	}
-	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data);
-	if (ret_val)
-		goto out;
-
-	/* set auto-master slave resolution settings */
-	if (hw->mac.autoneg) {
-		/*
-		 * when autonegotiation advertisement is only 1000Mbps then we
-		 * should disable SmartSpeed and enable Auto MasterSlave
-		 * resolution as hardware default.
-		 */
-		if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
-			/* Disable SmartSpeed */
-			ret_val = phy->ops.read_reg(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             &data);
-			if (ret_val)
-				goto out;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = phy->ops.write_reg(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-
-			/* Set auto Master/Slave resolution process */
-			ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
-			if (ret_val)
-				goto out;
-
-			data &= ~CR_1000T_MS_ENABLE;
-			ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
-			if (ret_val)
-				goto out;
-		}
-
-		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data);
-		if (ret_val)
-			goto out;
-
-		/* load defaults for future use */
-		phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
-			((data & CR_1000T_MS_VALUE) ?
-			e1000_ms_force_master :
-			e1000_ms_force_slave) :
-			e1000_ms_auto;
-
-		switch (phy->ms_type) {
-		case e1000_ms_force_master:
-			data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
-			break;
-		case e1000_ms_force_slave:
-			data |= CR_1000T_MS_ENABLE;
-			data &= ~(CR_1000T_MS_VALUE);
-			break;
-		case e1000_ms_auto:
-			data &= ~CR_1000T_MS_ENABLE;
-		default:
-			break;
-		}
-		ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_copper_link_autoneg - Setup/Enable autoneg for copper link
- *  @hw: pointer to the HW structure
- *
- *  Performs initial bounds checking on autoneg advertisement parameter, then
- *  configure to advertise the full capability.  Setup the PHY to autoneg
- *  and restart the negotiation process between the link partner.  If
- *  autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
- **/
-s32 igb_copper_link_autoneg(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_ctrl;
-
-	DEBUGFUNC("igb_copper_link_autoneg");
-
-	/*
-	 * Perform some bounds checking on the autoneg advertisement
-	 * parameter.
-	 */
-	phy->autoneg_advertised &= phy->autoneg_mask;
-
-	/*
-	 * If autoneg_advertised is zero, we assume it was not defaulted
-	 * by the calling code so we set to advertise full capability.
-	 */
-	if (phy->autoneg_advertised == 0)
-		phy->autoneg_advertised = phy->autoneg_mask;
-
-	DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
-	ret_val = igb_phy_setup_autoneg(hw);
-	if (ret_val) {
-		DEBUGOUT("Error Setting up Auto-Negotiation\n");
-		goto out;
-	}
-	DEBUGOUT("Restarting Auto-Neg\n");
-
-	/*
-	 * Restart auto-negotiation by setting the Auto Neg Enable bit and
-	 * the Auto Neg Restart bit in the PHY control register.
-	 */
-	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
-	if (ret_val)
-		goto out;
-
-	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
-	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Does the user want to wait for Auto-Neg to complete here, or
-	 * check at a later time (for example, callback routine).
-	 */
-	if (phy->autoneg_wait_to_complete) {
-		ret_val = hw->mac.ops.wait_autoneg(hw);
-		if (ret_val) {
-			DEBUGOUT("Error while waiting for "
-			         "autoneg to complete\n");
-			goto out;
-		}
-	}
-
-	hw->mac.get_link_status = true;
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_phy_setup_autoneg - Configure PHY for auto-negotiation
- *  @hw: pointer to the HW structure
- *
- *  Reads the MII auto-neg advertisement register and/or the 1000T control
- *  register and if the PHY is already setup for auto-negotiation, then
- *  return successful.  Otherwise, setup advertisement and flow control to
- *  the appropriate values for the wanted auto-negotiation.
- **/
-static s32 igb_phy_setup_autoneg(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 mii_autoneg_adv_reg;
-	u16 mii_1000t_ctrl_reg = 0;
-
-	DEBUGFUNC("igb_phy_setup_autoneg");
-
-	phy->autoneg_advertised &= phy->autoneg_mask;
-
-	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
-	ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
-	if (ret_val)
-		goto out;
-
-	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
-		/* Read the MII 1000Base-T Control Register (Address 9). */
-		ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL,
-		                            &mii_1000t_ctrl_reg);
-		if (ret_val)
-			goto out;
-	}
-
-	/*
-	 * Need to parse both autoneg_advertised and fc and set up
-	 * the appropriate PHY registers.  First we will parse for
-	 * autoneg_advertised software override.  Since we can advertise
-	 * a plethora of combinations, we need to check each bit
-	 * individually.
-	 */
-
-	/*
-	 * First we clear all the 10/100 mb speed bits in the Auto-Neg
-	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
-	 * the  1000Base-T Control Register (Address 9).
-	 */
-	mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
-	                         NWAY_AR_100TX_HD_CAPS |
-	                         NWAY_AR_10T_FD_CAPS   |
-	                         NWAY_AR_10T_HD_CAPS);
-	mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
-
-	DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised);
-
-	/* Do we want to advertise 10 Mb Half Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
-		DEBUGOUT("Advertise 10mb Half duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
-	}
-
-	/* Do we want to advertise 10 Mb Full Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
-		DEBUGOUT("Advertise 10mb Full duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
-	}
-
-	/* Do we want to advertise 100 Mb Half Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
-		DEBUGOUT("Advertise 100mb Half duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
-	}
-
-	/* Do we want to advertise 100 Mb Full Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
-		DEBUGOUT("Advertise 100mb Full duplex\n");
-		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
-	}
-
-	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
-	if (phy->autoneg_advertised & ADVERTISE_1000_HALF) {
-		DEBUGOUT("Advertise 1000mb Half duplex request denied!\n");
-        }
-	/* Do we want to advertise 1000 Mb Full Duplex? */
-	if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
-		DEBUGOUT("Advertise 1000mb Full duplex\n");
-		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
-	}
-
-	/*
-	 * Check for a software override of the flow control settings, and
-	 * setup the PHY advertisement registers accordingly.  If
-	 * auto-negotiation is enabled, then software will have to set the
-	 * "PAUSE" bits to the correct value in the Auto-Negotiation
-	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
-	 * negotiation.
-	 *
-	 * The possible values of the "fc" parameter are:
-	 *      0:  Flow control is completely disabled
-	 *      1:  Rx flow control is enabled (we can receive pause frames
-	 *          but not send pause frames).
-	 *      2:  Tx flow control is enabled (we can send pause frames
-	 *          but we do not support receiving pause frames).
-	 *      3:  Both Rx and Tx flow control (symmetric) are enabled.
-	 *  other:  No software override.  The flow control configuration
-	 *          in the EEPROM is used.
-	 */
-	switch (hw->fc.current_mode) {
-	case e1000_fc_none:
-		/*
-		 * Flow control (Rx & Tx) is completely disabled by a
-		 * software over-ride.
-		 */
-		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
-		break;
-	case e1000_fc_rx_pause:
-		/*
-		 * Rx Flow control is enabled, and Tx Flow control is
-		 * disabled, by a software over-ride.
-		 *
-		 * Since there really isn't a way to advertise that we are
-		 * capable of Rx Pause ONLY, we will advertise that we
-		 * support both symmetric and asymmetric Rx PAUSE.  Later
-		 * (in e1000_config_fc_after_link_up) we will disable the
-		 * hw's ability to send PAUSE frames.
-		 */
-		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
-		break;
-	case e1000_fc_tx_pause:
-		/*
-		 * Tx Flow control is enabled, and Rx Flow control is
-		 * disabled, by a software over-ride.
-		 */
-		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
-		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
-		break;
-	case e1000_fc_full:
-		/*
-		 * Flow control (both Rx and Tx) is enabled by a software
-		 * over-ride.
-		 */
-		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
-		break;
-	default:
-		DEBUGOUT("Flow control param set incorrectly\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
-	if (ret_val)
-		goto out;
-
-	DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
-
-	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
-		ret_val = phy->ops.write_reg(hw,
-		                              PHY_1000T_CTRL,
-		                              mii_1000t_ctrl_reg);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_setup_copper_link_generic - Configure copper link settings
- *  @hw: pointer to the HW structure
- *
- *  Calls the appropriate function to configure the link for auto-neg or forced
- *  speed and duplex.  Then we check for link, once link is established calls
- *  to configure collision distance and flow control are called.  If link is
- *  not established, we return -E1000_ERR_PHY (-2).
- **/
-s32 igb_setup_copper_link_generic(struct e1000_hw *hw)
-{
-	s32 ret_val;
-	bool link;
-
-	DEBUGFUNC("igb_setup_copper_link_generic");
-
-	if (hw->mac.autoneg) {
-		/*
-		 * Setup autoneg and flow control advertisement and perform
-		 * autonegotiation.
-		 */
-		ret_val = igb_copper_link_autoneg(hw);
-		if (ret_val)
-			goto out;
-	} else {
-#if 0
-		/*
-		 * PHY will be set to 10H, 10F, 100H or 100F
-		 * depending on user settings.
-		 */
-		DEBUGOUT("Forcing Speed and Duplex\n");
-		ret_val = hw->phy.ops.force_speed_duplex(hw);
-		if (ret_val) {
-			DEBUGOUT("Error Forcing Speed and Duplex\n");
-			goto out;
-		}
-#endif
-	}
-
-	/*
-	 * Check link status. Wait up to 100 microseconds for link to become
-	 * valid.
-	 */
-	ret_val = igb_phy_has_link_generic(hw,
-	                                     COPPER_LINK_UP_LIMIT,
-	                                     10,
-	                                     &link);
-	if (ret_val)
-		goto out;
-
-	if (link) {
-		DEBUGOUT("Valid link established!!!\n");
-		igb_config_collision_dist_generic(hw);
-		ret_val = igb_config_fc_after_link_up_generic(hw);
-	} else {
-		DEBUGOUT("Unable to establish link!!!\n");
-	}
-
-out:
-	return ret_val;
-}
-
-#if 0
-/**
- *  igb_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
- *  @hw: pointer to the HW structure
- *
- *  Calls the PHY setup function to force speed and duplex.  Clears the
- *  auto-crossover to force MDI manually.  Waits for link and returns
- *  successful if link up is successful, else -E1000_ERR_PHY (-2).
- **/
-s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data;
-	bool link;
-
-	DEBUGFUNC("igb_phy_force_speed_duplex_igp");
-
-	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	igb_phy_force_speed_duplex_setup(hw, &phy_data);
-
-	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Clear Auto-Crossover to force MDI manually.  IGP requires MDI
-	 * forced whenever speed and duplex are forced.
-	 */
-	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
-	phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
-
-	ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
-	if (ret_val)
-		goto out;
-
-	DEBUGOUT1("IGP PSCR: %X\n", phy_data);
-
-	usec_delay(1);
-
-	if (phy->autoneg_wait_to_complete) {
-		DEBUGOUT("Waiting for forced speed/duplex link on IGP phy.\n");
-
-		ret_val = igb_phy_has_link_generic(hw,
-		                                     PHY_FORCE_LIMIT,
-		                                     100000,
-		                                     &link);
-		if (ret_val)
-			goto out;
-
-		if (!link) {
-			DEBUGOUT("Link taking longer than expected.\n");
-                }
-		/* Try once more */
-		ret_val = igb_phy_has_link_generic(hw,
-		                                     PHY_FORCE_LIMIT,
-		                                     100000,
-		                                     &link);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-#endif
-
-#if 0
-/**
- *  igb_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
- *  @hw: pointer to the HW structure
- *
- *  Calls the PHY setup function to force speed and duplex.  Clears the
- *  auto-crossover to force MDI manually.  Resets the PHY to commit the
- *  changes.  If time expires while waiting for link up, we reset the DSP.
- *  After reset, TX_CLK and CRS on Tx must be set.  Return successful upon
- *  successful completion, else return corresponding error code.
- **/
-s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data;
-	bool link;
-
-	DEBUGFUNC("igb_phy_force_speed_duplex_m88");
-
-	/*
-	 * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
-	 * forced whenever speed and duplex are forced.
-	 */
-	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
-	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
-	if (ret_val)
-		goto out;
-
-	DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data);
-
-	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	igb_phy_force_speed_duplex_setup(hw, &phy_data);
-
-	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
-	if (ret_val)
-		goto out;
-
-	/* Reset the phy to commit changes. */
-	ret_val = hw->phy.ops.commit(hw);
-	if (ret_val)
-		goto out;
-
-	if (phy->autoneg_wait_to_complete) {
-		DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n");
-
-		ret_val = igb_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
-		                                     100000, &link);
-		if (ret_val)
-			goto out;
-
-		if (!link) {
-			/*
-			 * We didn't get link.
-			 * Reset the DSP and cross our fingers.
-			 */
-			ret_val = phy->ops.write_reg(hw,
-			                              M88E1000_PHY_PAGE_SELECT,
-			                              0x001d);
-			if (ret_val)
-				goto out;
-			ret_val = igb_phy_reset_dsp_generic(hw);
-			if (ret_val)
-				goto out;
-		}
-
-		/* Try once more */
-		ret_val = igb_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
-		                                     100000, &link);
-		if (ret_val)
-			goto out;
-	}
-
-	ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * Resetting the phy means we need to re-force TX_CLK in the
-	 * Extended PHY Specific Control Register to 25MHz clock from
-	 * the reset value of 2.5MHz.
-	 */
-	phy_data |= M88E1000_EPSCR_TX_CLK_25;
-	ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
-	if (ret_val)
-		goto out;
-
-	/*
-	 * In addition, we must re-enable CRS on Tx for both half and full
-	 * duplex.
-	 */
-	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-	ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
-
-out:
-	return ret_val;
-}
-#endif
-
-#if 0
-/**
- *  igb_phy_force_speed_duplex_ife - Force PHY speed & duplex
- *  @hw: pointer to the HW structure
- *
- *  Forces the speed and duplex settings of the PHY.
- *  This is a function pointer entry point only called by
- *  PHY setup routines.
- **/
-s32 igb_phy_force_speed_duplex_ife(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-	bool link;
-
-	DEBUGFUNC("igb_phy_force_speed_duplex_ife");
-
-	if (phy->type != e1000_phy_ife) {
-		ret_val = igb_phy_force_speed_duplex_igp(hw);
-		goto out;
-	}
-
-	ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data);
-	if (ret_val)
-		goto out;
-
-	igb_phy_force_speed_duplex_setup(hw, &data);
-
-	ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data);
-	if (ret_val)
-		goto out;
-
-	/* Disable MDI-X support for 10/100 */
-	ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
-	if (ret_val)
-		goto out;
-
-	data &= ~IFE_PMC_AUTO_MDIX;
-	data &= ~IFE_PMC_FORCE_MDIX;
-
-	ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data);
-	if (ret_val)
-		goto out;
-
-	DEBUGOUT1("IFE PMC: %X\n", data);
-
-	usec_delay(1);
-
-	if (phy->autoneg_wait_to_complete) {
-		DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n");
-
-		ret_val = igb_phy_has_link_generic(hw,
-		                                     PHY_FORCE_LIMIT,
-		                                     100000,
-		                                     &link);
-		if (ret_val)
-			goto out;
-
-		if (!link) {
-			DEBUGOUT("Link taking longer than expected.\n");
-                }
-		/* Try once more */
-		ret_val = igb_phy_has_link_generic(hw,
-		                                     PHY_FORCE_LIMIT,
-		                                     100000,
-		                                     &link);
-		if (ret_val)
-			goto out;
-	}
-
-out:
-	return ret_val;
-}
-#endif
-
-#if 0
-/**
- *  igb_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
- *  @hw: pointer to the HW structure
- *  @phy_ctrl: pointer to current value of PHY_CONTROL
- *
- *  Forces speed and duplex on the PHY by doing the following: disable flow
- *  control, force speed/duplex on the MAC, disable auto speed detection,
- *  disable auto-negotiation, configure duplex, configure speed, configure
- *  the collision distance, write configuration to CTRL register.  The
- *  caller must write to the PHY_CONTROL register for these settings to
- *  take affect.
- **/
-void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
-{
-	struct e1000_mac_info *mac = &hw->mac;
-	u32 ctrl;
-
-	DEBUGFUNC("igb_phy_force_speed_duplex_setup");
-
-	/* Turn off flow control when forcing speed/duplex */
-	hw->fc.current_mode = e1000_fc_none;
-
-	/* Force speed/duplex on the mac */
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-	ctrl &= ~E1000_CTRL_SPD_SEL;
-
-	/* Disable Auto Speed Detection */
-	ctrl &= ~E1000_CTRL_ASDE;
-
-	/* Disable autoneg on the phy */
-	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
-
-	/* Forcing Full or Half Duplex? */
-	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
-		ctrl &= ~E1000_CTRL_FD;
-		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;
-		DEBUGOUT("Half Duplex\n");
-	} else {
-		ctrl |= E1000_CTRL_FD;
-		*phy_ctrl |= MII_CR_FULL_DUPLEX;
-		DEBUGOUT("Full Duplex\n");
-	}
-
-	/* Forcing 10mb or 100mb? */
-	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
-		ctrl |= E1000_CTRL_SPD_100;
-		*phy_ctrl |= MII_CR_SPEED_100;
-		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
-		DEBUGOUT("Forcing 100mb\n");
-	} else {
-		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
-		*phy_ctrl |= MII_CR_SPEED_10;
-		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
-		DEBUGOUT("Forcing 10mb\n");
-	}
-
-	igb_config_collision_dist_generic(hw);
-
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-}
-#endif
-
-/**
- *  igb_set_d3_lplu_state_generic - Sets low power link up state for D3
- *  @hw: pointer to the HW structure
- *  @active: boolean used to enable/disable lplu
- *
- *  Success returns 0, Failure returns 1
- *
- *  The low power link up (lplu) state is set to the power management level D3
- *  and SmartSpeed is disabled when active is true, else clear lplu for D3
- *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
- *  is used during Dx states where the power conservation is most important.
- *  During driver activity, SmartSpeed should be enabled so performance is
- *  maintained.
- **/
-s32 igb_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 data;
-
-	DEBUGFUNC("igb_set_d3_lplu_state_generic");
-
-	if (!(hw->phy.ops.read_reg))
-		goto out;
-
-	ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
-	if (ret_val)
-		goto out;
-
-	if (!active) {
-		data &= ~IGP02E1000_PM_D3_LPLU;
-		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
-		                             data);
-		if (ret_val)
-			goto out;
-		/*
-		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
-		 * during Dx states where the power conservation is most
-		 * important.  During driver activity we should enable
-		 * SmartSpeed, so performance is maintained.
-		 */
-		if (phy->smart_speed == e1000_smart_speed_on) {
-			ret_val = phy->ops.read_reg(hw,
-			                            IGP01E1000_PHY_PORT_CONFIG,
-			                            &data);
-			if (ret_val)
-				goto out;
-
-			data |= IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = phy->ops.write_reg(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		} else if (phy->smart_speed == e1000_smart_speed_off) {
-			ret_val = phy->ops.read_reg(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             &data);
-			if (ret_val)
-				goto out;
-
-			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-			ret_val = phy->ops.write_reg(hw,
-			                             IGP01E1000_PHY_PORT_CONFIG,
-			                             data);
-			if (ret_val)
-				goto out;
-		}
-	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
-	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
-	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
-		data |= IGP02E1000_PM_D3_LPLU;
-		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
-		                              data);
-		if (ret_val)
-			goto out;
-
-		/* When LPLU is enabled, we should disable SmartSpeed */
-		ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-		                             &data);
-		if (ret_val)
-			goto out;
-
-		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
-		ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
-		                              data);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_check_downshift_generic - Checks whether a downshift in speed occurred
- *  @hw: pointer to the HW structure
- *
- *  Success returns 0, Failure returns 1
- *
- *  A downshift is detected by querying the PHY link health.
- **/
-s32 igb_check_downshift_generic(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data, offset, mask;
-
-	DEBUGFUNC("igb_check_downshift_generic");
-
-	switch (phy->type) {
-	case e1000_phy_m88:
-	case e1000_phy_gg82563:
-		offset	= M88E1000_PHY_SPEC_STATUS;
-		mask	= M88E1000_PSSR_DOWNSHIFT;
-		break;
-	case e1000_phy_igp_2:
-	case e1000_phy_igp:
-	case e1000_phy_igp_3:
-		offset	= IGP01E1000_PHY_LINK_HEALTH;
-		mask	= IGP01E1000_PLHR_SS_DOWNGRADE;
-		break;
-	default:
-		/* speed downshift not supported */
-		phy->speed_downgraded = false;
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
-
-	if (!ret_val)
-		phy->speed_downgraded = (phy_data & mask) ? true : false;
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_check_polarity_m88 - Checks the polarity.
- *  @hw: pointer to the HW structure
- *
- *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
- *
- *  Polarity is determined based on the PHY specific status register.
- **/
-s32 igb_check_polarity_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-
-	DEBUGFUNC("igb_check_polarity_m88");
-
-	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);
-
-	if (!ret_val)
-		phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
-		                      ? e1000_rev_polarity_reversed
-		                      : e1000_rev_polarity_normal;
-
-	return ret_val;
-}
-
-/**
- *  igb_check_polarity_igp - Checks the polarity.
- *  @hw: pointer to the HW structure
- *
- *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
- *
- *  Polarity is determined based on the PHY port status register, and the
- *  current speed (since there is no polarity at 100Mbps).
- **/
-s32 igb_check_polarity_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data, offset, mask;
-
-	DEBUGFUNC("igb_check_polarity_igp");
-
-	/*
-	 * Polarity is determined based on the speed of
-	 * our connection.
-	 */
-	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
-	if (ret_val)
-		goto out;
-
-	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
-	    IGP01E1000_PSSR_SPEED_1000MBPS) {
-		offset	= IGP01E1000_PHY_PCS_INIT_REG;
-		mask	= IGP01E1000_PHY_POLARITY_MASK;
-	} else {
-		/*
-		 * This really only applies to 10Mbps since
-		 * there is no polarity for 100Mbps (always 0).
-		 */
-		offset	= IGP01E1000_PHY_PORT_STATUS;
-		mask	= IGP01E1000_PSSR_POLARITY_REVERSED;
-	}
-
-	ret_val = phy->ops.read_reg(hw, offset, &data);
-
-	if (!ret_val)
-		phy->cable_polarity = (data & mask)
-		                      ? e1000_rev_polarity_reversed
-		                      : e1000_rev_polarity_normal;
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_check_polarity_ife - Check cable polarity for IFE PHY
- *  @hw: pointer to the HW structure
- *
- *  Polarity is determined on the polarity reversal feature being enabled.
- **/
-s32 igb_check_polarity_ife(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data, offset, mask;
-
-	DEBUGFUNC("igb_check_polarity_ife");
-
-	/*
-	 * Polarity is determined based on the reversal feature being enabled.
-	 */
-	if (phy->polarity_correction) {
-		offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
-		mask = IFE_PESC_POLARITY_REVERSED;
-	} else {
-		offset = IFE_PHY_SPECIAL_CONTROL;
-		mask = IFE_PSC_FORCE_POLARITY;
-	}
-
-	ret_val = phy->ops.read_reg(hw, offset, &phy_data);
-
-	if (!ret_val)
-		phy->cable_polarity = (phy_data & mask)
-		                       ? e1000_rev_polarity_reversed
-		                       : e1000_rev_polarity_normal;
-
-	return ret_val;
-}
-
-/**
- *  igb_wait_autoneg_generic - Wait for auto-neg completion
- *  @hw: pointer to the HW structure
- *
- *  Waits for auto-negotiation to complete or for the auto-negotiation time
- *  limit to expire, which ever happens first.
- **/
-s32 igb_wait_autoneg_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 i, phy_status;
-
-	DEBUGFUNC("igb_wait_autoneg_generic");
-
-	if (!(hw->phy.ops.read_reg))
-		return E1000_SUCCESS;
-
-	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
-	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
-		if (ret_val)
-			break;
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
-		if (ret_val)
-			break;
-		if (phy_status & MII_SR_AUTONEG_COMPLETE)
-			break;
-		msec_delay(100);
-	}
-
-	/*
-	 * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
-	 * has completed.
-	 */
-	return ret_val;
-}
-
-/**
- *  igb_phy_has_link_generic - Polls PHY for link
- *  @hw: pointer to the HW structure
- *  @iterations: number of times to poll for link
- *  @usec_interval: delay between polling attempts
- *  @success: pointer to whether polling was successful or not
- *
- *  Polls the PHY status register for link, 'iterations' number of times.
- **/
-s32 igb_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
-                               u32 usec_interval, bool *success)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 i, phy_status;
-
-	DEBUGFUNC("igb_phy_has_link_generic");
-
-	if (!(hw->phy.ops.read_reg))
-		return E1000_SUCCESS;
-
-	for (i = 0; i < iterations; i++) {
-		/*
-		 * Some PHYs require the PHY_STATUS register to be read
-		 * twice due to the link bit being sticky.  No harm doing
-		 * it across the board.
-		 */
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
-		if (ret_val) {
-			/*
-			 * If the first read fails, another entity may have
-			 * ownership of the resources, wait and try again to
-			 * see if they have relinquished the resources yet.
-			 */
-			usec_delay(usec_interval);
-		}
-		ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
-		if (ret_val)
-			break;
-		if (phy_status & MII_SR_LINK_STATUS)
-			break;
-		if (usec_interval >= 1000)
-			msec_delay_irq(usec_interval/1000);
-		else
-			usec_delay(usec_interval);
-	}
-
-	*success = (i < iterations) ? true : false;
-
-	return ret_val;
-}
-
-#if 0
-/**
- *  igb_get_cable_length_m88 - Determine cable length for m88 PHY
- *  @hw: pointer to the HW structure
- *
- *  Reads the PHY specific status register to retrieve the cable length
- *  information.  The cable length is determined by averaging the minimum and
- *  maximum values to get the "average" cable length.  The m88 PHY has four
- *  possible cable length values, which are:
- *	Register Value		Cable Length
- *	0			< 50 meters
- *	1			50 - 80 meters
- *	2			80 - 110 meters
- *	3			110 - 140 meters
- *	4			> 140 meters
- **/
-s32 igb_get_cable_length_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 phy_data, index;
-
-	DEBUGFUNC("igb_get_cable_length_m88");
-
-	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
-	if (ret_val)
-		goto out;
-
-	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
-	        M88E1000_PSSR_CABLE_LENGTH_SHIFT;
-	if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
-		ret_val = -E1000_ERR_PHY;
-		goto out;
-	}
-
-	phy->min_cable_length = e1000_m88_cable_length_table[index];
-	phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
-
-	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_get_cable_length_igp_2 - Determine cable length for igp2 PHY
- *  @hw: pointer to the HW structure
- *
- *  The automatic gain control (agc) normalizes the amplitude of the
- *  received signal, adjusting for the attenuation produced by the
- *  cable.  By reading the AGC registers, which represent the
- *  combination of coarse and fine gain value, the value can be put
- *  into a lookup table to obtain the approximate cable length
- *  for each channel.
- **/
-s32 igb_get_cable_length_igp_2(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u16 phy_data, i, agc_value = 0;
-	u16 cur_agc_index, max_agc_index = 0;
-	u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
-	u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
-	                                                 {IGP02E1000_PHY_AGC_A,
-	                                                  IGP02E1000_PHY_AGC_B,
-	                                                  IGP02E1000_PHY_AGC_C,
-	                                                  IGP02E1000_PHY_AGC_D};
-
-	DEBUGFUNC("igb_get_cable_length_igp_2");
-
-	/* Read the AGC registers for all channels */
-	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
-		ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data);
-		if (ret_val)
-			goto out;
-
-		/*
-		 * Getting bits 15:9, which represent the combination of
-		 * coarse and fine gain values.  The result is a number
-		 * that can be put into the lookup table to obtain the
-		 * approximate cable length.
-		 */
-		cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
-		                IGP02E1000_AGC_LENGTH_MASK;
-
-		/* Array index bound check. */
-		if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
-		    (cur_agc_index == 0)) {
-			ret_val = -E1000_ERR_PHY;
-			goto out;
-		}
-
-		/* Remove min & max AGC values from calculation. */
-		if (e1000_igp_2_cable_length_table[min_agc_index] >
-		    e1000_igp_2_cable_length_table[cur_agc_index])
-			min_agc_index = cur_agc_index;
-		if (e1000_igp_2_cable_length_table[max_agc_index] <
-		    e1000_igp_2_cable_length_table[cur_agc_index])
-			max_agc_index = cur_agc_index;
-
-		agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
-	}
-
-	agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
-	              e1000_igp_2_cable_length_table[max_agc_index]);
-	agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
-
-	/* Calculate cable length with the error range of +/- 10 meters. */
-	phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
-	                         (agc_value - IGP02E1000_AGC_RANGE) : 0;
-	phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
-
-	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
-
-out:
-	return ret_val;
-}
-#endif
-
-/**
- *  igb_get_phy_info_m88 - Retrieve PHY information
- *  @hw: pointer to the HW structure
- *
- *  Valid for only copper links.  Read the PHY status register (sticky read)
- *  to verify that link is up.  Read the PHY special control register to
- *  determine the polarity and 10base-T extended distance.  Read the PHY
- *  special status register to determine MDI/MDIx and current speed.  If
- *  speed is 1000, then determine cable length, local and remote receiver.
- **/
-s32 igb_get_phy_info_m88(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32  ret_val;
-	u16 phy_data;
-	bool link;
-
-	DEBUGFUNC("igb_get_phy_info_m88");
-
-	if (phy->media_type != e1000_media_type_copper) {
-		DEBUGOUT("Phy info is only valid for copper media\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	ret_val = igb_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		goto out;
-
-	if (!link) {
-		DEBUGOUT("Phy info is only valid if link is up\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
-	                           ? true : false;
-
-	ret_val = igb_check_polarity_m88(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
-	if (ret_val)
-		goto out;
-
-	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false;
-
-	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
-#if 0
-		ret_val = hw->phy.ops.get_cable_length(hw);
-#endif
-		ret_val = -E1000_ERR_CONFIG;
-		if (ret_val)
-			goto out;
-#if 0
-		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
-		if (ret_val)
-			goto out;
-
-		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
-		                ? e1000_1000t_rx_status_ok
-		                : e1000_1000t_rx_status_not_ok;
-
-		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
-		                 ? e1000_1000t_rx_status_ok
-		                 : e1000_1000t_rx_status_not_ok;
-#endif
-	} else {
-		/* Set values to "undefined" */
-		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
-		phy->local_rx = e1000_1000t_rx_status_undefined;
-		phy->remote_rx = e1000_1000t_rx_status_undefined;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_get_phy_info_igp - Retrieve igp PHY information
- *  @hw: pointer to the HW structure
- *
- *  Read PHY status to determine if link is up.  If link is up, then
- *  set/determine 10base-T extended distance and polarity correction.  Read
- *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
- *  determine on the cable length, local and remote receiver.
- **/
-s32 igb_get_phy_info_igp(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val;
-	u16 data;
-	bool link;
-
-	DEBUGFUNC("igb_get_phy_info_igp");
-
-	ret_val = igb_phy_has_link_generic(hw, 1, 0, &link);
-	if (ret_val)
-		goto out;
-
-	if (!link) {
-		DEBUGOUT("Phy info is only valid if link is up\n");
-		ret_val = -E1000_ERR_CONFIG;
-		goto out;
-	}
-
-	phy->polarity_correction = true;
-
-	ret_val = igb_check_polarity_igp(hw);
-	if (ret_val)
-		goto out;
-
-	ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
-	if (ret_val)
-		goto out;
-
-	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false;
-
-	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
-	    IGP01E1000_PSSR_SPEED_1000MBPS) {
-#if 0
-		ret_val = phy->ops.get_cable_length(hw);
-#endif
-		ret_val = -E1000_ERR_CONFIG;
-		if (ret_val)
-			goto out;
-#if 0
-		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data);
-		if (ret_val)
-			goto out;
-
-		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
-		                ? e1000_1000t_rx_status_ok
-		                : e1000_1000t_rx_status_not_ok;
-
-		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
-		                 ? e1000_1000t_rx_status_ok
-		                 : e1000_1000t_rx_status_not_ok;
-#endif
-	} else {
-		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
-		phy->local_rx = e1000_1000t_rx_status_undefined;
-		phy->remote_rx = e1000_1000t_rx_status_undefined;
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_phy_sw_reset_generic - PHY software reset
- *  @hw: pointer to the HW structure
- *
- *  Does a software reset of the PHY by reading the PHY control register and
- *  setting/write the control register reset bit to the PHY.
- **/
-s32 igb_phy_sw_reset_generic(struct e1000_hw *hw)
-{
-	s32 ret_val = E1000_SUCCESS;
-	u16 phy_ctrl;
-
-	DEBUGFUNC("igb_phy_sw_reset_generic");
-
-	if (!(hw->phy.ops.read_reg))
-		goto out;
-
-	ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
-	if (ret_val)
-		goto out;
-
-	phy_ctrl |= MII_CR_RESET;
-	ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl);
-	if (ret_val)
-		goto out;
-
-	usec_delay(1);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_phy_hw_reset_generic - PHY hardware reset
- *  @hw: pointer to the HW structure
- *
- *  Verify the reset block is not blocking us from resetting.  Acquire
- *  semaphore (if necessary) and read/set/write the device control reset
- *  bit in the PHY.  Wait the appropriate delay time for the device to
- *  reset and release the semaphore (if necessary).
- **/
-s32 igb_phy_hw_reset_generic(struct e1000_hw *hw)
-{
-	struct e1000_phy_info *phy = &hw->phy;
-	s32 ret_val = E1000_SUCCESS;
-	u32 ctrl;
-
-	DEBUGFUNC("igb_phy_hw_reset_generic");
-
-	ret_val = phy->ops.check_reset_block(hw);
-	if (ret_val) {
-		ret_val = E1000_SUCCESS;
-		goto out;
-	}
-
-	ret_val = phy->ops.acquire(hw);
-	if (ret_val)
-		goto out;
-
-	ctrl = E1000_READ_REG(hw, E1000_CTRL);
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);
-	E1000_WRITE_FLUSH(hw);
-
-	usec_delay(phy->reset_delay_us);
-
-	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
-	E1000_WRITE_FLUSH(hw);
-
-	usec_delay(150);
-
-	phy->ops.release(hw);
-
-	ret_val = phy->ops.get_cfg_done(hw);
-
-out:
-	return ret_val;
-}
-
-/**
- *  igb_get_cfg_done_generic - Generic configuration done
- *  @hw: pointer to the HW structure
- *
- *  Generic function to wait 10 milli-seconds for configuration to complete
- *  and return success.
- **/
-s32 igb_get_cfg_done_generic(struct e1000_hw *hw __unused)
-{
-	DEBUGFUNC("igb_get_cfg_done_generic");
-
-	msec_delay_irq(10);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_phy_init_script_igp3 - Inits the IGP3 PHY
- *  @hw: pointer to the HW structure
- *
- *  Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
- **/
-s32 igb_phy_init_script_igp3(struct e1000_hw *hw)
-{
-	DEBUGOUT("Running IGP 3 PHY init script\n");
-
-	/* PHY init IGP 3 */
-	/* Enable rise/fall, 10-mode work in class-A */
-	hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018);
-	/* Remove all caps from Replica path filter */
-	hw->phy.ops.write_reg(hw, 0x2F52, 0x0000);
-	/* Bias trimming for ADC, AFE and Driver (Default) */
-	hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24);
-	/* Increase Hybrid poly bias */
-	hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0);
-	/* Add 4% to Tx amplitude in Gig mode */
-	hw->phy.ops.write_reg(hw, 0x2010, 0x10B0);
-	/* Disable trimming (TTT) */
-	hw->phy.ops.write_reg(hw, 0x2011, 0x0000);
-	/* Poly DC correction to 94.6% + 2% for all channels */
-	hw->phy.ops.write_reg(hw, 0x20DD, 0x249A);
-	/* ABS DC correction to 95.9% */
-	hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3);
-	/* BG temp curve trim */
-	hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE);
-	/* Increasing ADC OPAMP stage 1 currents to max */
-	hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4);
-	/* Force 1000 ( required for enabling PHY regs configuration) */
-	hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
-	/* Set upd_freq to 6 */
-	hw->phy.ops.write_reg(hw, 0x1F30, 0x1606);
-	/* Disable NPDFE */
-	hw->phy.ops.write_reg(hw, 0x1F31, 0xB814);
-	/* Disable adaptive fixed FFE (Default) */
-	hw->phy.ops.write_reg(hw, 0x1F35, 0x002A);
-	/* Enable FFE hysteresis */
-	hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067);
-	/* Fixed FFE for short cable lengths */
-	hw->phy.ops.write_reg(hw, 0x1F54, 0x0065);
-	/* Fixed FFE for medium cable lengths */
-	hw->phy.ops.write_reg(hw, 0x1F55, 0x002A);
-	/* Fixed FFE for long cable lengths */
-	hw->phy.ops.write_reg(hw, 0x1F56, 0x002A);
-	/* Enable Adaptive Clip Threshold */
-	hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0);
-	/* AHT reset limit to 1 */
-	hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF);
-	/* Set AHT master delay to 127 msec */
-	hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC);
-	/* Set scan bits for AHT */
-	hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF);
-	/* Set AHT Preset bits */
-	hw->phy.ops.write_reg(hw, 0x1F79, 0x0210);
-	/* Change integ_factor of channel A to 3 */
-	hw->phy.ops.write_reg(hw, 0x1895, 0x0003);
-	/* Change prop_factor of channels BCD to 8 */
-	hw->phy.ops.write_reg(hw, 0x1796, 0x0008);
-	/* Change cg_icount + enable integbp for channels BCD */
-	hw->phy.ops.write_reg(hw, 0x1798, 0xD008);
-	/*
-	 * Change cg_icount + enable integbp + change prop_factor_master
-	 * to 8 for channel A
-	 */
-	hw->phy.ops.write_reg(hw, 0x1898, 0xD918);
-	/* Disable AHT in Slave mode on channel A */
-	hw->phy.ops.write_reg(hw, 0x187A, 0x0800);
-	/*
-	 * Enable LPLU and disable AN to 1000 in non-D0a states,
-	 * Enable SPD+B2B
-	 */
-	hw->phy.ops.write_reg(hw, 0x0019, 0x008D);
-	/* Enable restart AN on an1000_dis change */
-	hw->phy.ops.write_reg(hw, 0x001B, 0x2080);
-	/* Enable wh_fifo read clock in 10/100 modes */
-	hw->phy.ops.write_reg(hw, 0x0014, 0x0045);
-	/* Restart AN, Speed selection is 1000 */
-	hw->phy.ops.write_reg(hw, 0x0000, 0x1340);
-
-	return E1000_SUCCESS;
-}
-
-/**
- *  igb_get_phy_type_from_id - Get PHY type from id
- *  @phy_id: phy_id read from the phy
- *
- *  Returns the phy type from the id.
- **/
-enum e1000_phy_type igb_get_phy_type_from_id(u32 phy_id)
-{
-	enum e1000_phy_type phy_type = e1000_phy_unknown;
-
-	switch (phy_id)	{
-	case M88E1000_I_PHY_ID:
-	case M88E1000_E_PHY_ID:
-	case M88E1111_I_PHY_ID:
-	case M88E1011_I_PHY_ID:
-		phy_type = e1000_phy_m88;
-		break;
-	case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
-		phy_type = e1000_phy_igp_2;
-		break;
-	case GG82563_E_PHY_ID:
-		phy_type = e1000_phy_gg82563;
-		break;
-	case IGP03E1000_E_PHY_ID:
-		phy_type = e1000_phy_igp_3;
-		break;
-	case IFE_E_PHY_ID:
-	case IFE_PLUS_E_PHY_ID:
-	case IFE_C_E_PHY_ID:
-		phy_type = e1000_phy_ife;
-		break;
-	default:
-		phy_type = e1000_phy_unknown;
-		break;
-	}
-	return phy_type;
-}
-
-/**
- *  igb_determine_phy_address - Determines PHY address.
- *  @hw: pointer to the HW structure
- *
- *  This uses a trial and error method to loop through possible PHY
- *  addresses. It tests each by reading the PHY ID registers and
- *  checking for a match.
- **/
-s32 igb_determine_phy_address(struct e1000_hw *hw)
-{
-	s32 ret_val = -E1000_ERR_PHY_TYPE;
-	u32 phy_addr = 0;
-	u32 i;
-	enum e1000_phy_type phy_type = e1000_phy_unknown;
-
-	hw->phy.id = phy_type;
-
-	for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) {
-		hw->phy.addr = phy_addr;
-		i = 0;
-
-		do {
-			igb_get_phy_id(hw);
-			phy_type = igb_get_phy_type_from_id(hw->phy.id);
-
-			/*
-			 * If phy_type is valid, break - we found our
-			 * PHY address
-			 */
-			if (phy_type  != e1000_phy_unknown) {
-				ret_val = E1000_SUCCESS;
-				goto out;
-			}
-			msec_delay(1);
-			i++;
-		} while (i < 10);
-	}
-
-out:
-	return ret_val;
-}
-
-/**
- * igb_power_up_phy_copper - Restore copper link in case of PHY power down
- * @hw: pointer to the HW structure
- *
- * In the case of a PHY power down to save power, or to turn off link during a
- * driver unload, or wake on lan is not enabled, restore the link to previous
- * settings.
- **/
-void igb_power_up_phy_copper(struct e1000_hw *hw)
-{
-	u16 mii_reg = 0;
-
-	/* The PHY will retain its settings across a power down/up cycle */
-	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
-	mii_reg &= ~MII_CR_POWER_DOWN;
-	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
-}
-
-/**
- * igb_power_down_phy_copper - Restore copper link in case of PHY power down
- * @hw: pointer to the HW structure
- *
- * In the case of a PHY power down to save power, or to turn off link during a
- * driver unload, or wake on lan is not enabled, restore the link to previous
- * settings.
- **/
-void igb_power_down_phy_copper(struct e1000_hw *hw)
-{
-	u16 mii_reg = 0;
-
-	/* The PHY will retain its settings across a power down/up cycle */
-	hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
-	mii_reg |= MII_CR_POWER_DOWN;
-	hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
-	msec_delay(1);
-}
diff --git a/roms/ipxe/src/drivers/net/igb/igb_phy.h b/roms/ipxe/src/drivers/net/igb/igb_phy.h
deleted file mode 100644
index 8e6bc9917ef4e2b4cbe51fe5d7fe87c33470e20f..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_phy.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#ifndef _IGB_PHY_H_
-#define _IGB_PHY_H_
-
-void igb_init_phy_ops_generic(struct e1000_hw *hw);
-s32  igb_check_downshift_generic(struct e1000_hw *hw);
-s32  igb_check_polarity_m88(struct e1000_hw *hw);
-s32  igb_check_polarity_igp(struct e1000_hw *hw);
-s32  igb_check_polarity_ife(struct e1000_hw *hw);
-s32  igb_check_reset_block_generic(struct e1000_hw *hw);
-s32  igb_copper_link_autoneg(struct e1000_hw *hw);
-s32  igb_copper_link_setup_igp(struct e1000_hw *hw);
-s32  igb_copper_link_setup_m88(struct e1000_hw *hw);
-#if 0
-s32  igb_phy_force_speed_duplex_igp(struct e1000_hw *hw);
-s32  igb_phy_force_speed_duplex_m88(struct e1000_hw *hw);
-s32  igb_phy_force_speed_duplex_ife(struct e1000_hw *hw);
-#endif
-#if 0
-s32  igb_get_cable_length_m88(struct e1000_hw *hw);
-s32  igb_get_cable_length_igp_2(struct e1000_hw *hw);
-#endif
-s32  igb_get_cfg_done_generic(struct e1000_hw *hw);
-s32  igb_get_phy_id(struct e1000_hw *hw);
-s32  igb_get_phy_info_igp(struct e1000_hw *hw);
-s32  igb_get_phy_info_m88(struct e1000_hw *hw);
-s32  igb_phy_sw_reset_generic(struct e1000_hw *hw);
-#if 0
-void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
-#endif
-s32  igb_phy_hw_reset_generic(struct e1000_hw *hw);
-s32  igb_phy_reset_dsp_generic(struct e1000_hw *hw);
-s32  igb_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  igb_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  igb_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  igb_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  igb_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active);
-s32  igb_setup_copper_link_generic(struct e1000_hw *hw);
-s32  igb_wait_autoneg_generic(struct e1000_hw *hw);
-s32  igb_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data);
-s32  igb_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data);
-s32  igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
-s32  igb_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data);
-s32  igb_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
-s32  igb_phy_reset_dsp(struct e1000_hw *hw);
-s32  igb_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
-                                u32 usec_interval, bool *success);
-s32  igb_phy_init_script_igp3(struct e1000_hw *hw);
-enum e1000_phy_type igb_get_phy_type_from_id(u32 phy_id);
-s32  igb_determine_phy_address(struct e1000_hw *hw);
-void igb_power_up_phy_copper(struct e1000_hw *hw);
-void igb_power_down_phy_copper(struct e1000_hw *hw);
-s32  igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
-s32  igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data);
-s32  igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data);
-
-#define E1000_MAX_PHY_ADDR                4
-
-/* IGP01E1000 Specific Registers */
-#define IGP01E1000_PHY_PORT_CONFIG        0x10 /* Port Config */
-#define IGP01E1000_PHY_PORT_STATUS        0x11 /* Status */
-#define IGP01E1000_PHY_PORT_CTRL          0x12 /* Control */
-#define IGP01E1000_PHY_LINK_HEALTH        0x13 /* PHY Link Health */
-#define IGP01E1000_GMII_FIFO              0x14 /* GMII FIFO */
-#define IGP01E1000_PHY_CHANNEL_QUALITY    0x15 /* PHY Channel Quality */
-#define IGP02E1000_PHY_POWER_MGMT         0x19 /* Power Management */
-#define IGP01E1000_PHY_PAGE_SELECT        0x1F /* Page Select */
-#define BM_PHY_PAGE_SELECT                22   /* Page Select for BM */
-#define IGP_PAGE_SHIFT                    5
-#define PHY_REG_MASK                      0x1F
-
-#define IGP01E1000_PHY_PCS_INIT_REG       0x00B4
-#define IGP01E1000_PHY_POLARITY_MASK      0x0078
-
-#define IGP01E1000_PSCR_AUTO_MDIX         0x1000
-#define IGP01E1000_PSCR_FORCE_MDI_MDIX    0x2000 /* 0=MDI, 1=MDIX */
-
-#define IGP01E1000_PSCFR_SMART_SPEED      0x0080
-
-/* Enable flexible speed on link-up */
-#define IGP01E1000_GMII_FLEX_SPD          0x0010
-#define IGP01E1000_GMII_SPD               0x0020 /* Enable SPD */
-
-#define IGP02E1000_PM_SPD                 0x0001 /* Smart Power Down */
-#define IGP02E1000_PM_D0_LPLU             0x0002 /* For D0a states */
-#define IGP02E1000_PM_D3_LPLU             0x0004 /* For all other states */
-
-#define IGP01E1000_PLHR_SS_DOWNGRADE      0x8000
-
-#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
-#define IGP01E1000_PSSR_MDIX              0x0800
-#define IGP01E1000_PSSR_SPEED_MASK        0xC000
-#define IGP01E1000_PSSR_SPEED_1000MBPS    0xC000
-
-#define IGP02E1000_PHY_CHANNEL_NUM        4
-#define IGP02E1000_PHY_AGC_A              0x11B1
-#define IGP02E1000_PHY_AGC_B              0x12B1
-#define IGP02E1000_PHY_AGC_C              0x14B1
-#define IGP02E1000_PHY_AGC_D              0x18B1
-
-#define IGP02E1000_AGC_LENGTH_SHIFT       9   /* Course - 15:13, Fine - 12:9 */
-#define IGP02E1000_AGC_LENGTH_MASK        0x7F
-#define IGP02E1000_AGC_RANGE              15
-
-#define IGP03E1000_PHY_MISC_CTRL          0x1B
-#define IGP03E1000_PHY_MISC_DUPLEX_MANUAL_SET  0x1000 /* Manually Set Duplex */
-
-#define E1000_CABLE_LENGTH_UNDEFINED      0xFF
-
-#define E1000_KMRNCTRLSTA_OFFSET          0x001F0000
-#define E1000_KMRNCTRLSTA_OFFSET_SHIFT    16
-#define E1000_KMRNCTRLSTA_REN             0x00200000
-#define E1000_KMRNCTRLSTA_DIAG_OFFSET     0x3    /* Kumeran Diagnostic */
-#define E1000_KMRNCTRLSTA_TIMEOUTS        0x4    /* Kumeran Timeouts */
-#define E1000_KMRNCTRLSTA_INBAND_PARAM    0x9    /* Kumeran InBand Parameters */
-#define E1000_KMRNCTRLSTA_DIAG_NELPBK     0x1000 /* Nearend Loopback mode */
-
-#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
-#define IFE_PHY_SPECIAL_CONTROL     0x11 /* 100BaseTx PHY Special Control */
-#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */
-#define IFE_PHY_MDIX_CONTROL        0x1C /* MDI/MDI-X Control */
-
-/* IFE PHY Extended Status Control */
-#define IFE_PESC_POLARITY_REVERSED    0x0100
-
-/* IFE PHY Special Control */
-#define IFE_PSC_AUTO_POLARITY_DISABLE      0x0010
-#define IFE_PSC_FORCE_POLARITY             0x0020
-#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100
-
-/* IFE PHY Special Control and LED Control */
-#define IFE_PSCL_PROBE_MODE            0x0020
-#define IFE_PSCL_PROBE_LEDS_OFF        0x0006 /* Force LEDs 0 and 2 off */
-#define IFE_PSCL_PROBE_LEDS_ON         0x0007 /* Force LEDs 0 and 2 on */
-
-/* IFE PHY MDIX Control */
-#define IFE_PMC_MDIX_STATUS      0x0020 /* 1=MDI-X, 0=MDI */
-#define IFE_PMC_FORCE_MDIX       0x0040 /* 1=force MDI-X, 0=force MDI */
-#define IFE_PMC_AUTO_MDIX        0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */
-
-#endif /* _IGB_PHY_H_ */
diff --git a/roms/ipxe/src/drivers/net/igb/igb_regs.h b/roms/ipxe/src/drivers/net/igb/igb_regs.h
deleted file mode 100644
index e549675b23021a3b89c9b39ab892537ba8c8a0a3..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/igb/igb_regs.h
+++ /dev/null
@@ -1,486 +0,0 @@
-/*******************************************************************************
-
-  Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2009 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope 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.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#ifndef _IGB_REGS_H_
-#define _IGB_REGS_H_
-
-#define E1000_CTRL     0x00000  /* Device Control - RW */
-#define E1000_CTRL_DUP 0x00004  /* Device Control Duplicate (Shadow) - RW */
-#define E1000_STATUS   0x00008  /* Device Status - RO */
-#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
-#define E1000_EERD     0x00014  /* EEPROM Read - RW */
-#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
-#define E1000_FLA      0x0001C  /* Flash Access - RW */
-#define E1000_MDIC     0x00020  /* MDI Control - RW */
-#define E1000_SCTL     0x00024  /* SerDes Control - RW */
-#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
-#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
-#define E1000_FEXT     0x0002C  /* Future Extended - RW */
-#define E1000_FEXTNVM  0x00028  /* Future Extended NVM - RW */
-#define E1000_FCT      0x00030  /* Flow Control Type - RW */
-#define E1000_CONNSW   0x00034  /* Copper/Fiber switch control - RW */
-#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
-#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
-#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
-#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
-#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
-#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
-#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
-#define E1000_RCTL     0x00100  /* Rx Control - RW */
-#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
-#define E1000_TXCW     0x00178  /* Tx Configuration Word - RW */
-#define E1000_RXCW     0x00180  /* Rx Configuration Word - RO */
-#define E1000_EICR     0x01580  /* Ext. Interrupt Cause Read - R/clr */
-#define E1000_EITR(_n) (0x01680 + (0x4 * (_n)))
-#define E1000_EICS     0x01520  /* Ext. Interrupt Cause Set - W0 */
-#define E1000_EIMS     0x01524  /* Ext. Interrupt Mask Set/Read - RW */
-#define E1000_EIMC     0x01528  /* Ext. Interrupt Mask Clear - WO */
-#define E1000_EIAC     0x0152C  /* Ext. Interrupt Auto Clear - RW */
-#define E1000_EIAM     0x01530  /* Ext. Interrupt Ack Auto Clear Mask - RW */
-#define E1000_GPIE     0x01514  /* General Purpose Interrupt Enable - RW */
-#define E1000_IVAR0    0x01700  /* Interrupt Vector Allocation (array) - RW */
-#define E1000_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */
-#define E1000_TCTL     0x00400  /* Tx Control - RW */
-#define E1000_TCTL_EXT 0x00404  /* Extended Tx Control - RW */
-#define E1000_TIPG     0x00410  /* Tx Inter-packet gap -RW */
-#define E1000_TBT      0x00448  /* Tx Burst Timer - RW */
-#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
-#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
-#define E1000_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
-#define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
-#define E1000_PHY_CTRL     0x00F10  /* PHY Control Register in CSR */
-#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
-#define E1000_PBS      0x01008  /* Packet Buffer Size */
-#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
-#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
-#define E1000_FLASHT   0x01028  /* FLASH Timer Register */
-#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
-#define E1000_FLSWCTL  0x01030  /* FLASH control register */
-#define E1000_FLSWDATA 0x01034  /* FLASH data register */
-#define E1000_FLSWCNT  0x01038  /* FLASH Access Counter */
-#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
-#define E1000_I2CCMD   0x01028  /* SFPI2C Command Register - RW */
-#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */
-#define E1000_WDSTP    0x01040  /* Watchdog Setup - RW */
-#define E1000_SWDSTS   0x01044  /* SW Device Status - RW */
-#define E1000_FRTIMER  0x01048  /* Free Running Timer - RW */
-#define E1000_TCPTIMER 0x0104C  /* TCP Timer - RW */
-#define E1000_VPDDIAG  0x01060  /* VPD Diagnostic - RO */
-#define E1000_ICR_V2   0x01500  /* Interrupt Cause - new location - RC */
-#define E1000_ICS_V2   0x01504  /* Interrupt Cause Set - new location - WO */
-#define E1000_IMS_V2   0x01508  /* Interrupt Mask Set/Read - new location - RW */
-#define E1000_IMC_V2   0x0150C  /* Interrupt Mask Clear - new location - WO */
-#define E1000_IAM_V2   0x01510  /* Interrupt Ack Auto Mask - new location - RW */
-#define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
-#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
-#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
-#define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - RW */
-#define E1000_RDFPCQ(_n)  (0x02430 + (0x4 * (_n)))
-#define E1000_PBRTH    0x02458  /* PB Rx Arbitration Threshold - RW */
-#define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */
-/* Split and Replication Rx Control - RW */
-#define E1000_RDPUMB   0x025CC  /* DMA Rx Descriptor uC Mailbox - RW */
-#define E1000_RDPUAD   0x025D0  /* DMA Rx Descriptor uC Addr Command - RW */
-#define E1000_RDPUWD   0x025D4  /* DMA Rx Descriptor uC Data Write - RW */
-#define E1000_RDPURD   0x025D8  /* DMA Rx Descriptor uC Data Read - RW */
-#define E1000_RDPUCTL  0x025DC  /* DMA Rx Descriptor uC Control - RW */
-#define E1000_PBDIAG   0x02458  /* Packet Buffer Diagnostic - RW */
-#define E1000_RXPBS    0x02404  /* Rx Packet Buffer Size - RW */
-#define E1000_RDTR     0x02820  /* Rx Delay Timer - RW */
-#define E1000_RADV     0x0282C  /* Rx Interrupt Absolute Delay Timer - RW */
-/*
- * Convenience macros
- *
- * Note: "_n" is the queue number of the register to be written to.
- *
- * Example usage:
- * E1000_RDBAL_REG(current_rx_queue)
- */
-#define E1000_RDBAL(_n)      ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \
-                                         (0x0C000 + ((_n) * 0x40)))
-#define E1000_RDBAH(_n)      ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \
-                                         (0x0C004 + ((_n) * 0x40)))
-#define E1000_RDLEN(_n)      ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \
-                                         (0x0C008 + ((_n) * 0x40)))
-#define E1000_SRRCTL(_n)     ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \
-                                         (0x0C00C + ((_n) * 0x40)))
-#define E1000_RDH(_n)        ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \
-                                         (0x0C010 + ((_n) * 0x40)))
-#define E1000_RXCTL(_n)      ((_n) < 4 ? (0x02814 + ((_n) * 0x100)) : \
-                                         (0x0C014 + ((_n) * 0x40)))
-#define E1000_DCA_RXCTRL(_n) E1000_RXCTL(_n)
-#define E1000_RDT(_n)        ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \
-                                         (0x0C018 + ((_n) * 0x40)))
-#define E1000_RXDCTL(_n)     ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \
-                                         (0x0C028 + ((_n) * 0x40)))
-#define E1000_RQDPC(_n)      ((_n) < 4 ? (0x02830 + ((_n) * 0x100)) : \
-                                         (0x0C030 + ((_n) * 0x40)))
-#define E1000_TDBAL(_n)      ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \
-                                         (0x0E000 + ((_n) * 0x40)))
-#define E1000_TDBAH(_n)      ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \
-                                         (0x0E004 + ((_n) * 0x40)))
-#define E1000_TDLEN(_n)      ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \
-                                         (0x0E008 + ((_n) * 0x40)))
-#define E1000_TDH(_n)        ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \
-                                         (0x0E010 + ((_n) * 0x40)))
-#define E1000_TXCTL(_n)      ((_n) < 4 ? (0x03814 + ((_n) * 0x100)) : \
-                                         (0x0E014 + ((_n) * 0x40)))
-#define E1000_DCA_TXCTRL(_n) E1000_TXCTL(_n)
-#define E1000_TDT(_n)        ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \
-                                         (0x0E018 + ((_n) * 0x40)))
-#define E1000_TXDCTL(_n)     ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \
-                                         (0x0E028 + ((_n) * 0x40)))
-#define E1000_TDWBAL(_n)     ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : \
-                                         (0x0E038 + ((_n) * 0x40)))
-#define E1000_TDWBAH(_n)     ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : \
-                                         (0x0E03C + ((_n) * 0x40)))
-#define E1000_TARC(_n)                   (0x03840 + ((_n) * 0x100))
-#define E1000_RSRPD    0x02C00  /* Rx Small Packet Detect - RW */
-#define E1000_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
-#define E1000_TXDMAC   0x03000  /* Tx DMA Control - RW */
-#define E1000_KABGTXD  0x03004  /* AFE Band Gap Transmit Ref Data */
-#define E1000_PSRTYPE(_i)       (0x05480 + ((_i) * 4))
-#define E1000_RAL(_i)  (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
-                                       (0x054E0 + ((_i - 16) * 8)))
-#define E1000_RAH(_i)  (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
-                                       (0x054E4 + ((_i - 16) * 8)))
-#define E1000_IP4AT_REG(_i)     (0x05840 + ((_i) * 8))
-#define E1000_IP6AT_REG(_i)     (0x05880 + ((_i) * 4))
-#define E1000_WUPM_REG(_i)      (0x05A00 + ((_i) * 4))
-#define E1000_FFMT_REG(_i)      (0x09000 + ((_i) * 8))
-#define E1000_FFVT_REG(_i)      (0x09800 + ((_i) * 8))
-#define E1000_FFLT_REG(_i)      (0x05F00 + ((_i) * 8))
-#define E1000_PBSLAC   0x03100  /* Packet Buffer Slave Access Control */
-#define E1000_PBSLAD(_n)  (0x03110 + (0x4 * (_n)))  /* Packet Buffer DWORD (_n) */
-#define E1000_TXPBS    0x03404  /* Tx Packet Buffer Size - RW */
-#define E1000_TDFH     0x03410  /* Tx Data FIFO Head - RW */
-#define E1000_TDFT     0x03418  /* Tx Data FIFO Tail - RW */
-#define E1000_TDFHS    0x03420  /* Tx Data FIFO Head Saved - RW */
-#define E1000_TDFTS    0x03428  /* Tx Data FIFO Tail Saved - RW */
-#define E1000_TDFPC    0x03430  /* Tx Data FIFO Packet Count - RW */
-#define E1000_TDPUMB   0x0357C  /* DMA Tx Descriptor uC Mail Box - RW */
-#define E1000_TDPUAD   0x03580  /* DMA Tx Descriptor uC Addr Command - RW */
-#define E1000_TDPUWD   0x03584  /* DMA Tx Descriptor uC Data Write - RW */
-#define E1000_TDPURD   0x03588  /* DMA Tx Descriptor uC Data  Read  - RW */
-#define E1000_TDPUCTL  0x0358C  /* DMA Tx Descriptor uC Control - RW */
-#define E1000_DTXCTL   0x03590  /* DMA Tx Control - RW */
-#define E1000_DTXTCPFLGL 0x0359C /* DMA Tx Control flag low - RW */
-#define E1000_DTXTCPFLGH 0x035A0 /* DMA Tx Control flag high - RW */
-#define E1000_DTXMXSZRQ  0x03540 /* DMA Tx Max Total Allow Size Requests - RW */
-#define E1000_TIDV     0x03820  /* Tx Interrupt Delay Value - RW */
-#define E1000_TADV     0x0382C  /* Tx Interrupt Absolute Delay Val - RW */
-#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
-#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
-#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
-#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
-#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
-#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
-#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
-#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
-#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
-#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
-#define E1000_COLC     0x04028  /* Collision Count - R/clr */
-#define E1000_DC       0x04030  /* Defer Count - R/clr */
-#define E1000_TNCRS    0x04034  /* Tx-No CRS - R/clr */
-#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
-#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
-#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
-#define E1000_XONRXC   0x04048  /* XON Rx Count - R/clr */
-#define E1000_XONTXC   0x0404C  /* XON Tx Count - R/clr */
-#define E1000_XOFFRXC  0x04050  /* XOFF Rx Count - R/clr */
-#define E1000_XOFFTXC  0x04054  /* XOFF Tx Count - R/clr */
-#define E1000_FCRUC    0x04058  /* Flow Control Rx Unsupported Count- R/clr */
-#define E1000_PRC64    0x0405C  /* Packets Rx (64 bytes) - R/clr */
-#define E1000_PRC127   0x04060  /* Packets Rx (65-127 bytes) - R/clr */
-#define E1000_PRC255   0x04064  /* Packets Rx (128-255 bytes) - R/clr */
-#define E1000_PRC511   0x04068  /* Packets Rx (255-511 bytes) - R/clr */
-#define E1000_PRC1023  0x0406C  /* Packets Rx (512-1023 bytes) - R/clr */
-#define E1000_PRC1522  0x04070  /* Packets Rx (1024-1522 bytes) - R/clr */
-#define E1000_GPRC     0x04074  /* Good Packets Rx Count - R/clr */
-#define E1000_BPRC     0x04078  /* Broadcast Packets Rx Count - R/clr */
-#define E1000_MPRC     0x0407C  /* Multicast Packets Rx Count - R/clr */
-#define E1000_GPTC     0x04080  /* Good Packets Tx Count - R/clr */
-#define E1000_GORCL    0x04088  /* Good Octets Rx Count Low - R/clr */
-#define E1000_GORCH    0x0408C  /* Good Octets Rx Count High - R/clr */
-#define E1000_GOTCL    0x04090  /* Good Octets Tx Count Low - R/clr */
-#define E1000_GOTCH    0x04094  /* Good Octets Tx Count High - R/clr */
-#define E1000_RNBC     0x040A0  /* Rx No Buffers Count - R/clr */
-#define E1000_RUC      0x040A4  /* Rx Undersize Count - R/clr */
-#define E1000_RFC      0x040A8  /* Rx Fragment Count - R/clr */
-#define E1000_ROC      0x040AC  /* Rx Oversize Count - R/clr */
-#define E1000_RJC      0x040B0  /* Rx Jabber Count - R/clr */
-#define E1000_MGTPRC   0x040B4  /* Management Packets Rx Count - R/clr */
-#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
-#define E1000_MGTPTC   0x040BC  /* Management Packets Tx Count - R/clr */
-#define E1000_TORL     0x040C0  /* Total Octets Rx Low - R/clr */
-#define E1000_TORH     0x040C4  /* Total Octets Rx High - R/clr */
-#define E1000_TOTL     0x040C8  /* Total Octets Tx Low - R/clr */
-#define E1000_TOTH     0x040CC  /* Total Octets Tx High - R/clr */
-#define E1000_TPR      0x040D0  /* Total Packets Rx - R/clr */
-#define E1000_TPT      0x040D4  /* Total Packets Tx - R/clr */
-#define E1000_PTC64    0x040D8  /* Packets Tx (64 bytes) - R/clr */
-#define E1000_PTC127   0x040DC  /* Packets Tx (65-127 bytes) - R/clr */
-#define E1000_PTC255   0x040E0  /* Packets Tx (128-255 bytes) - R/clr */
-#define E1000_PTC511   0x040E4  /* Packets Tx (256-511 bytes) - R/clr */
-#define E1000_PTC1023  0x040E8  /* Packets Tx (512-1023 bytes) - R/clr */
-#define E1000_PTC1522  0x040EC  /* Packets Tx (1024-1522 Bytes) - R/clr */
-#define E1000_MPTC     0x040F0  /* Multicast Packets Tx Count - R/clr */
-#define E1000_BPTC     0x040F4  /* Broadcast Packets Tx Count - R/clr */
-#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context Tx - R/clr */
-#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context Tx Fail - R/clr */
-#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
-#define E1000_ICRXPTC  0x04104  /* Interrupt Cause Rx Pkt Timer Expire Count */
-#define E1000_ICRXATC  0x04108  /* Interrupt Cause Rx Abs Timer Expire Count */
-#define E1000_ICTXPTC  0x0410C  /* Interrupt Cause Tx Pkt Timer Expire Count */
-#define E1000_ICTXATC  0x04110  /* Interrupt Cause Tx Abs Timer Expire Count */
-#define E1000_ICTXQEC  0x04118  /* Interrupt Cause Tx Queue Empty Count */
-#define E1000_ICTXQMTC 0x0411C  /* Interrupt Cause Tx Queue Min Thresh Count */
-#define E1000_ICRXDMTC 0x04120  /* Interrupt Cause Rx Desc Min Thresh Count */
-#define E1000_ICRXOC   0x04124  /* Interrupt Cause Receiver Overrun Count */
-
-#define E1000_LSECTXUT        0x04300  /* LinkSec Tx Untagged Packet Count - OutPktsUntagged */
-#define E1000_LSECTXPKTE      0x04304  /* LinkSec Encrypted Tx Packets Count - OutPktsEncrypted */
-#define E1000_LSECTXPKTP      0x04308  /* LinkSec Protected Tx Packet Count - OutPktsProtected */
-#define E1000_LSECTXOCTE      0x0430C  /* LinkSec Encrypted Tx Octets Count - OutOctetsEncrypted */
-#define E1000_LSECTXOCTP      0x04310  /* LinkSec Protected Tx Octets Count - OutOctetsProtected */
-#define E1000_LSECRXUT        0x04314  /* LinkSec Untagged non-Strict Rx Packet Count - InPktsUntagged/InPktsNoTag */
-#define E1000_LSECRXOCTD      0x0431C  /* LinkSec Rx Octets Decrypted Count - InOctetsDecrypted */
-#define E1000_LSECRXOCTV      0x04320  /* LinkSec Rx Octets Validated - InOctetsValidated */
-#define E1000_LSECRXBAD       0x04324  /* LinkSec Rx Bad Tag - InPktsBadTag */
-#define E1000_LSECRXNOSCI     0x04328  /* LinkSec Rx Packet No SCI Count - InPktsNoSci */
-#define E1000_LSECRXUNSCI     0x0432C  /* LinkSec Rx Packet Unknown SCI Count - InPktsUnknownSci */
-#define E1000_LSECRXUNCH      0x04330  /* LinkSec Rx Unchecked Packets Count - InPktsUnchecked */
-#define E1000_LSECRXDELAY     0x04340  /* LinkSec Rx Delayed Packet Count - InPktsDelayed */
-#define E1000_LSECRXLATE      0x04350  /* LinkSec Rx Late Packets Count - InPktsLate */
-#define E1000_LSECRXOK(_n)    (0x04360 + (0x04 * (_n))) /* LinkSec Rx Packet OK Count - InPktsOk */
-#define E1000_LSECRXINV(_n)   (0x04380 + (0x04 * (_n))) /* LinkSec Rx Invalid Count - InPktsInvalid */
-#define E1000_LSECRXNV(_n)    (0x043A0 + (0x04 * (_n))) /* LinkSec Rx Not Valid Count - InPktsNotValid */
-#define E1000_LSECRXUNSA      0x043C0  /* LinkSec Rx Unused SA Count - InPktsUnusedSa */
-#define E1000_LSECRXNUSA      0x043D0  /* LinkSec Rx Not Using SA Count - InPktsNotUsingSa */
-#define E1000_LSECTXCAP       0x0B000  /* LinkSec Tx Capabilities Register - RO */
-#define E1000_LSECRXCAP       0x0B300  /* LinkSec Rx Capabilities Register - RO */
-#define E1000_LSECTXCTRL      0x0B004  /* LinkSec Tx Control - RW */
-#define E1000_LSECRXCTRL      0x0B304  /* LinkSec Rx Control - RW */
-#define E1000_LSECTXSCL       0x0B008  /* LinkSec Tx SCI Low - RW */
-#define E1000_LSECTXSCH       0x0B00C  /* LinkSec Tx SCI High - RW */
-#define E1000_LSECTXSA        0x0B010  /* LinkSec Tx SA0 - RW */
-#define E1000_LSECTXPN0       0x0B018  /* LinkSec Tx SA PN 0 - RW */
-#define E1000_LSECTXPN1       0x0B01C  /* LinkSec Tx SA PN 1 - RW */
-#define E1000_LSECRXSCL       0x0B3D0  /* LinkSec Rx SCI Low - RW */
-#define E1000_LSECRXSCH       0x0B3E0  /* LinkSec Rx SCI High - RW */
-#define E1000_LSECTXKEY0(_n)  (0x0B020 + (0x04 * (_n))) /* LinkSec Tx 128-bit Key 0 - WO */
-#define E1000_LSECTXKEY1(_n)  (0x0B030 + (0x04 * (_n))) /* LinkSec Tx 128-bit Key 1 - WO */
-#define E1000_LSECRXSA(_n)    (0x0B310 + (0x04 * (_n))) /* LinkSec Rx SAs - RW */
-#define E1000_LSECRXPN(_n)    (0x0B330 + (0x04 * (_n))) /* LinkSec Rx SAs - RW */
-/*
- * LinkSec Rx Keys  - where _n is the SA no. and _m the 4 dwords of the 128 bit
- * key - RW.
- */
-#define E1000_LSECRXKEY(_n, _m) (0x0B350 + (0x10 * (_n)) + (0x04 * (_m)))
-
-#define E1000_SSVPC             0x041A0  /* Switch Security Violation Packet Count */
-#define E1000_IPSCTRL           0xB430   /* IpSec Control Register */
-#define E1000_IPSRXCMD          0x0B408  /* IPSec Rx Command Register - RW */
-#define E1000_IPSRXIDX          0x0B400  /* IPSec Rx Index - RW */
-#define E1000_IPSRXIPADDR(_n)   (0x0B420+ (0x04 * (_n)))  /* IPSec Rx IPv4/v6 Address - RW */
-#define E1000_IPSRXKEY(_n)      (0x0B410 + (0x04 * (_n))) /* IPSec Rx 128-bit Key - RW */
-#define E1000_IPSRXSALT         0x0B404  /* IPSec Rx Salt - RW */
-#define E1000_IPSRXSPI          0x0B40C  /* IPSec Rx SPI - RW */
-#define E1000_IPSTXKEY(_n)      (0x0B460 + (0x04 * (_n))) /* IPSec Tx 128-bit Key - RW */
-#define E1000_IPSTXSALT         0x0B454  /* IPSec Tx Salt - RW */
-#define E1000_IPSTXIDX          0x0B450  /* IPSec Tx SA IDX - RW */
-#define E1000_PCS_CFG0    0x04200  /* PCS Configuration 0 - RW */
-#define E1000_PCS_LCTL    0x04208  /* PCS Link Control - RW */
-#define E1000_PCS_LSTAT   0x0420C  /* PCS Link Status - RO */
-#define E1000_CBTMPC      0x0402C  /* Circuit Breaker Tx Packet Count */
-#define E1000_HTDPMC      0x0403C  /* Host Transmit Discarded Packets */
-#define E1000_CBRDPC      0x04044  /* Circuit Breaker Rx Dropped Count */
-#define E1000_CBRMPC      0x040FC  /* Circuit Breaker Rx Packet Count */
-#define E1000_RPTHC       0x04104  /* Rx Packets To Host */
-#define E1000_HGPTC       0x04118  /* Host Good Packets Tx Count */
-#define E1000_HTCBDPC     0x04124  /* Host Tx Circuit Breaker Dropped Count */
-#define E1000_HGORCL      0x04128  /* Host Good Octets Received Count Low */
-#define E1000_HGORCH      0x0412C  /* Host Good Octets Received Count High */
-#define E1000_HGOTCL      0x04130  /* Host Good Octets Transmit Count Low */
-#define E1000_HGOTCH      0x04134  /* Host Good Octets Transmit Count High */
-#define E1000_LENERRS     0x04138  /* Length Errors Count */
-#define E1000_SCVPC       0x04228  /* SerDes/SGMII Code Violation Pkt Count */
-#define E1000_HRMPC       0x0A018  /* Header Redirection Missed Packet Count */
-#define E1000_PCS_ANADV   0x04218  /* AN advertisement - RW */
-#define E1000_PCS_LPAB    0x0421C  /* Link Partner Ability - RW */
-#define E1000_PCS_NPTX    0x04220  /* AN Next Page Transmit - RW */
-#define E1000_PCS_LPABNP  0x04224  /* Link Partner Ability Next Page - RW */
-#define E1000_1GSTAT_RCV  0x04228  /* 1GSTAT Code Violation Packet Count - RW */
-#define E1000_RXCSUM   0x05000  /* Rx Checksum Control - RW */
-#define E1000_RLPML    0x05004  /* Rx Long Packet Max Length */
-#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
-#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
-#define E1000_RA       0x05400  /* Receive Address - RW Array */
-#define E1000_RA2      0x054E0  /* 2nd half of receive address array - RW Array */
-#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
-#define E1000_VT_CTL   0x0581C  /* VMDq Control - RW */
-#define E1000_VFQA0    0x0B000  /* VLAN Filter Queue Array 0 - RW Array */
-#define E1000_VFQA1    0x0B200  /* VLAN Filter Queue Array 1 - RW Array */
-#define E1000_WUC      0x05800  /* Wakeup Control - RW */
-#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
-#define E1000_WUS      0x05810  /* Wakeup Status - RO */
-#define E1000_MANC     0x05820  /* Management Control - RW */
-#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
-#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
-#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
-#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
-#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
-#define E1000_PBACL    0x05B68  /* MSIx PBA Clear - Read/Write 1's to clear */
-#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
-#define E1000_HOST_IF  0x08800  /* Host Interface */
-#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
-#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
-#define E1000_FHFT(_n)  (0x09000 + (_n * 0x100)) /* Flexible Host Filter Table */
-#define E1000_FHFT_EXT(_n) (0x09A00 + (_n * 0x100)) /* Ext Flexible Host Filter Table */
-
-
-#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */
-#define E1000_MDPHYA      0x0003C /* PHY address - RW */
-#define E1000_MANC2H      0x05860 /* Management Control To Host - RW */
-#define E1000_SW_FW_SYNC  0x05B5C /* Software-Firmware Synchronization - RW */
-#define E1000_CCMCTL      0x05B48 /* CCM Control Register */
-#define E1000_GIOCTL      0x05B44 /* GIO Analog Control Register */
-#define E1000_SCCTL       0x05B4C /* PCIc PLL Configuration Register */
-#define E1000_GCR         0x05B00 /* PCI-Ex Control */
-#define E1000_GCR2        0x05B64 /* PCI-Ex Control #2 */
-#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
-#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
-#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
-#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
-#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
-#define E1000_SWSM      0x05B50 /* SW Semaphore */
-#define E1000_FWSM      0x05B54 /* FW Semaphore */
-#define E1000_SWSM2     0x05B58 /* Driver-only SW semaphore (not used by BOOT agents) */
-#define E1000_DCA_ID    0x05B70 /* DCA Requester ID Information - RO */
-#define E1000_DCA_CTRL  0x05B74 /* DCA Control - RW */
-#define E1000_FFLT_DBG  0x05F04 /* Debug Register */
-#define E1000_HICR      0x08F00 /* Host Interface Control */
-
-/* RSS registers */
-#define E1000_CPUVEC    0x02C10 /* CPU Vector Register - RW */
-#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
-#define E1000_IMIR(_i)      (0x05A80 + ((_i) * 4))  /* Immediate Interrupt */
-#define E1000_IMIREXT(_i)   (0x05AA0 + ((_i) * 4))  /* Immediate Interrupt Ext*/
-#define E1000_IMIRVP    0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */
-#define E1000_MSIXBM(_i)    (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register
-                                                    * (_i) - RW */
-#define E1000_MSIXTADD(_i)  (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr
-                                                       * low reg - RW */
-#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr
-                                                       * upper reg - RW */
-#define E1000_MSIXTMSG(_i)  (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry
-                                                       * message reg - RW */
-#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry
-                                                       * vector ctrl reg - RW */
-#define E1000_MSIXPBA    0x0E000 /* MSI-X Pending bit array */
-#define E1000_RETA(_i)  (0x05C00 + ((_i) * 4)) /* Redirection Table - RW */
-#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW */
-#define E1000_RSSIM     0x05864 /* RSS Interrupt Mask */
-#define E1000_RSSIR     0x05868 /* RSS Interrupt Request */
-/* VT Registers */
-#define E1000_SWPBS     0x03004 /* Switch Packet Buffer Size - RW */
-#define E1000_MBVFICR   0x00C80 /* Mailbox VF Cause - RWC */
-#define E1000_MBVFIMR   0x00C84 /* Mailbox VF int Mask - RW */
-#define E1000_VFLRE     0x00C88 /* VF Register Events - RWC */
-#define E1000_VFRE      0x00C8C /* VF Receive Enables */
-#define E1000_VFTE      0x00C90 /* VF Transmit Enables */
-#define E1000_QDE       0x02408 /* Queue Drop Enable - RW */
-#define E1000_DTXSWC    0x03500 /* DMA Tx Switch Control - RW */
-#define E1000_RPLOLR    0x05AF0 /* Replication Offload - RW */
-#define E1000_UTA       0x0A000 /* Unicast Table Array - RW */
-#define E1000_IOVTCL    0x05BBC /* IOV Control Register */
-#define E1000_VMRCTL    0X05D80 /* Virtual Mirror Rule Control */
-/* These act per VF so an array friendly macro is used */
-#define E1000_V2PMAILBOX(_n)   (0x00C40 + (4 * (_n)))
-#define E1000_P2VMAILBOX(_n)   (0x00C00 + (4 * (_n)))
-#define E1000_VMBMEM(_n)       (0x00800 + (64 * (_n)))
-#define E1000_VFVMBMEM(_n)     (0x00800 + (_n))
-#define E1000_VMOLR(_n)        (0x05AD0 + (4 * (_n)))
-#define E1000_VLVF(_n)         (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine
-                                                       * Filter - RW */
-/* Time Sync */
-#define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */
-#define E1000_TSYNCTXCTL 0x0B614 /* Tx Time Sync Control register - RW */
-#define E1000_TSYNCRXCFG 0x05F50 /* Time Sync Rx Configuration - RW */
-#define E1000_RXSTMPL    0x0B624 /* Rx timestamp Low - RO */
-#define E1000_RXSTMPH    0x0B628 /* Rx timestamp High - RO */
-#define E1000_RXSATRL    0x0B62C /* Rx timestamp attribute low - RO */
-#define E1000_RXSATRH    0x0B630 /* Rx timestamp attribute high - RO */
-#define E1000_TXSTMPL    0x0B618 /* Tx timestamp value Low - RO */
-#define E1000_TXSTMPH    0x0B61C /* Tx timestamp value High - RO */
-#define E1000_SYSTIML    0x0B600 /* System time register Low - RO */
-#define E1000_SYSTIMH    0x0B604 /* System time register High - RO */
-#define E1000_TIMINCA    0x0B608 /* Increment attributes register - RW */
-
-/* Filtering Registers */
-#define E1000_SAQF(_n)  (0x05980 + (4 * (_n))) /* Source Address Queue Fltr */
-#define E1000_DAQF(_n)  (0x059A0 + (4 * (_n))) /* Dest Address Queue Fltr */
-#define E1000_SPQF(_n)  (0x059C0 + (4 * (_n))) /* Source Port Queue Fltr */
-#define E1000_FTQF(_n)  (0x059E0 + (4 * (_n))) /* 5-tuple Queue Fltr */
-#define E1000_TTQF(_n)  (0x059E0 + (4 * (_n))) /* 2-tuple Queue Fltr */
-#define E1000_SYNQF(_n) (0x055FC + (4 * (_n))) /* SYN Packet Queue Fltr */
-#define E1000_ETQF(_n)  (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */
-
-#define E1000_RTTDCS            0x3600  /* Reedtown Tx Desc plane control and status */
-#define E1000_RTTPCS            0x3474  /* Reedtown Tx Packet Plane control and status */
-#define E1000_RTRPCS            0x2474  /* Rx packet plane control and status */
-#define E1000_RTRUP2TC          0x05AC4 /* Rx User Priority to Traffic Class */
-#define E1000_RTTUP2TC          0x0418  /* Transmit User Priority to Traffic Class */
-#define E1000_RTTDTCRC(_n)      (0x3610 + ((_n) * 4)) /* Tx Desc plane TC Rate-scheduler config */
-#define E1000_RTTPTCRC(_n)      (0x3480 + ((_n) * 4)) /* Tx Packet plane TC Rate-Scheduler Config */
-#define E1000_RTRPTCRC(_n)      (0x2480 + ((_n) * 4)) /* Rx Packet plane TC Rate-Scheduler Config */
-#define E1000_RTTDTCRS(_n)      (0x3630 + ((_n) * 4)) /* Tx Desc Plane TC Rate-Scheduler Status */
-#define E1000_RTTDTCRM(_n)      (0x3650 + ((_n) * 4)) /* Tx Desc Plane TC Rate-Scheduler MMW */
-#define E1000_RTTPTCRS(_n)      (0x34A0 + ((_n) * 4)) /* Tx Packet plane TC Rate-Scheduler Status */
-#define E1000_RTTPTCRM(_n)      (0x34C0 + ((_n) * 4)) /* Tx Packet plane TC Rate-scheduler MMW */
-#define E1000_RTRPTCRS(_n)      (0x24A0 + ((_n) * 4)) /* Rx Packet plane TC Rate-Scheduler Status */
-#define E1000_RTRPTCRM(_n)      (0x24C0 + ((_n) * 4)) /* Rx Packet plane TC Rate-Scheduler MMW */
-#define E1000_RTTDVMRM(_n)      (0x3670 + ((_n) * 4)) /* Tx Desc plane VM Rate-Scheduler MMW*/
-#define E1000_RTTBCNRM(_n)      (0x3690 + ((_n) * 4)) /* Tx BCN Rate-Scheduler MMW */
-#define E1000_RTTDQSEL          0x3604  /* Tx Desc Plane Queue Select */
-#define E1000_RTTDVMRC          0x3608  /* Tx Desc Plane VM Rate-Scheduler Config */
-#define E1000_RTTDVMRS          0x360C  /* Tx Desc Plane VM Rate-Scheduler Status */
-#define E1000_RTTBCNRC          0x36B0  /* Tx BCN Rate-Scheduler Config */
-#define E1000_RTTBCNRS          0x36B4  /* Tx BCN Rate-Scheduler Status */
-#define E1000_RTTBCNCR          0xB200  /* Tx BCN Control Register */
-#define E1000_RTTBCNTG          0x35A4  /* Tx BCN Tagging */
-#define E1000_RTTBCNCP          0xB208  /* Tx BCN Congestion point */
-#define E1000_RTRBCNCR          0xB20C  /* Rx BCN Control Register */
-#define E1000_RTTBCNRD          0x36B8  /* Tx BCN Rate Drift */
-#define E1000_PFCTOP            0x1080  /* Priority Flow Control Type and Opcode */
-#define E1000_RTTBCNIDX         0xB204  /* Tx BCN Congestion Point */
-#define E1000_RTTBCNACH         0x0B214 /* Tx BCN Control High */
-#define E1000_RTTBCNACL         0x0B210 /* Tx BCN Control Low */
-
-#endif /* _IGB_REGS_H_ */
diff --git a/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c b/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c
index 1f7e1dfd9afb9aef15ba4ebc461e..cd189ecb0d69c907552986095b63 100644
--- a/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c
+++ b/roms/ipxe/src/drivers/net/igbvf/igbvf_main.c
@@ -942,7 +942,8 @@ void igbvf_remove ( struct pci_device *pdev )
 }
 
 static struct pci_device_id igbvf_pci_tbl[] = {
-	PCI_ROM(0x8086, 0x10CA, "igbvf", "E1000_DEV_ID_82576_VF", 0)
+	PCI_ROM(0x8086, 0x10CA, "igbvf", "E1000_DEV_ID_82576_VF", 0),
+	PCI_ROM(0x8086, 0x1520, "i350vf", "E1000_DEV_ID_I350_VF", 0),
 };
 
 
diff --git a/roms/ipxe/src/drivers/net/igbvf/igbvf_vf.h b/roms/ipxe/src/drivers/net/igbvf/igbvf_vf.h
index ce8ad796c32b2da1eb1a8ea43ad1..8d8963fea73980f6a9437456029f 100644
--- a/roms/ipxe/src/drivers/net/igbvf/igbvf_vf.h
+++ b/roms/ipxe/src/drivers/net/igbvf/igbvf_vf.h
@@ -54,6 +54,7 @@ FILE_LICENCE ( GPL2_ONLY );
 struct e1000_hw;
 
 #define E1000_DEV_ID_82576_VF                 0x10CA
+#define E1000_DEV_ID_I350_VF                  0x1520
 
 #define E1000_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */
 
diff --git a/roms/ipxe/src/drivers/net/intel.c b/roms/ipxe/src/drivers/net/intel.c
new file mode 100644
index 0000000000000000000000000000000000000000..ce17e9f2da92c15fdb24879dfad2cb5b5c5da9c8
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/intel.c
@@ -0,0 +1,959 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+#include "intel.h"
+
+/** @file
+ *
+ * Intel 10/100/1000 network card driver
+ *
+ */
+
+/******************************************************************************
+ *
+ * EEPROM interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Read data from EEPROM
+ *
+ * @v nvs		NVS device
+ * @v address		Address from which to read
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+static int intel_read_eeprom ( struct nvs_device *nvs, unsigned int address,
+			       void *data, size_t len ) {
+	struct intel_nic *intel =
+		container_of ( nvs, struct intel_nic, eeprom );
+	unsigned int i;
+	uint32_t value;
+	uint16_t *data_word = data;
+
+	/* Sanity check.  We advertise a blocksize of one word, so
+	 * should only ever receive single-word requests.
+	 */
+	assert ( len == sizeof ( *data_word ) );
+
+	/* Initiate read */
+	writel ( ( INTEL_EERD_START | ( address << intel->eerd_addr_shift ) ),
+		 intel->regs + INTEL_EERD );
+
+	/* Wait for read to complete */
+	for ( i = 0 ; i < INTEL_EEPROM_MAX_WAIT_MS ; i++ ) {
+
+		/* If read is not complete, delay 1ms and retry */
+		value = readl ( intel->regs + INTEL_EERD );
+		if ( ! ( value & intel->eerd_done ) ) {
+			mdelay ( 1 );
+			continue;
+		}
+
+		/* Extract data */
+		*data_word = cpu_to_le16 ( INTEL_EERD_DATA ( value ) );
+		return 0;
+	}
+
+	DBGC ( intel, "INTEL %p timed out waiting for EEPROM read\n", intel );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Write data to EEPROM
+ *
+ * @v nvs		NVS device
+ * @v address		Address to which to write
+ * @v data		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+static int intel_write_eeprom ( struct nvs_device *nvs,
+				unsigned int address __unused,
+				const void *data __unused,
+				size_t len __unused ) {
+	struct intel_nic *intel =
+		container_of ( nvs, struct intel_nic, eeprom );
+
+	DBGC ( intel, "INTEL %p EEPROM write not supported\n", intel );
+	return -ENOTSUP;
+}
+
+/**
+ * Initialise EEPROM
+ *
+ * @v intel		Intel device
+ * @ret rc		Return status code
+ */
+static int intel_init_eeprom ( struct intel_nic *intel ) {
+	unsigned int i;
+	uint32_t value;
+
+	/* The NIC automatically detects the type of attached EEPROM.
+	 * The EERD register provides access to only a single word at
+	 * a time, so we pretend to have a single-word block size.
+	 *
+	 * The EEPROM size may be larger than the minimum size, but
+	 * this doesn't matter to us since we access only the first
+	 * few words.
+	 */
+	intel->eeprom.word_len_log2 = INTEL_EEPROM_WORD_LEN_LOG2;
+	intel->eeprom.size = INTEL_EEPROM_MIN_SIZE_WORDS;
+	intel->eeprom.block_size = 1;
+	intel->eeprom.read = intel_read_eeprom;
+	intel->eeprom.write = intel_write_eeprom;
+
+	/* The layout of the EERD register was changed at some point
+	 * to accommodate larger EEPROMs.  Read from address zero (for
+	 * which the request layouts are compatible) to determine
+	 * which type of register we have.
+	 */
+	writel ( INTEL_EERD_START, intel->regs + INTEL_EERD );
+	for ( i = 0 ; i < INTEL_EEPROM_MAX_WAIT_MS ; i++ ) {
+		value = readl ( intel->regs + INTEL_EERD );
+		if ( value & INTEL_EERD_DONE_LARGE ) {
+			DBGC ( intel, "INTEL %p has large-format EERD\n",
+			       intel );
+			intel->eerd_done = INTEL_EERD_DONE_LARGE;
+			intel->eerd_addr_shift = INTEL_EERD_ADDR_SHIFT_LARGE;
+			return 0;
+		}
+		if ( value & INTEL_EERD_DONE_SMALL ) {
+			DBGC ( intel, "INTEL %p has small-format EERD\n",
+			       intel );
+			intel->eerd_done = INTEL_EERD_DONE_SMALL;
+			intel->eerd_addr_shift = INTEL_EERD_ADDR_SHIFT_SMALL;
+			return 0;
+		}
+		mdelay ( 1 );
+	}
+
+	DBGC ( intel, "INTEL %p timed out waiting for initial EEPROM read "
+	       "(value %08x)\n", intel, value );
+	return -ETIMEDOUT;
+}
+
+/******************************************************************************
+ *
+ * MAC address
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Fetch initial MAC address from EEPROM
+ *
+ * @v intel		Intel device
+ * @v hw_addr		Hardware address to fill in
+ * @ret rc		Return status code
+ */
+static int intel_fetch_mac_eeprom ( struct intel_nic *intel,
+				    uint8_t *hw_addr ) {
+	int rc;
+
+	/* Initialise EEPROM */
+	if ( ( rc = intel_init_eeprom ( intel ) ) != 0 )
+		return rc;
+
+	/* Read base MAC address from EEPROM */
+	if ( ( rc = nvs_read ( &intel->eeprom, INTEL_EEPROM_MAC,
+			       hw_addr, ETH_ALEN ) ) != 0 ) {
+		DBGC ( intel, "INTEL %p could not read EEPROM base MAC "
+		       "address: %s\n", intel, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Adjust MAC address for multi-port devices */
+	hw_addr[ETH_ALEN-1] ^= intel->port;
+
+	DBGC ( intel, "INTEL %p has EEPROM MAC address %s (port %d)\n",
+	       intel, eth_ntoa ( hw_addr ), intel->port );
+	return 0;
+}
+
+/**
+ * Fetch initial MAC address
+ *
+ * @v intel		Intel device
+ * @v hw_addr		Hardware address to fill in
+ * @ret rc		Return status code
+ */
+static int intel_fetch_mac ( struct intel_nic *intel, uint8_t *hw_addr ) {
+	union intel_receive_address mac;
+	int rc;
+
+	/* Read current address from RAL0/RAH0 */
+	mac.reg.low = cpu_to_le32 ( readl ( intel->regs + INTEL_RAL0 ) );
+	mac.reg.high = cpu_to_le32 ( readl ( intel->regs + INTEL_RAH0 ) );
+	DBGC ( intel, "INTEL %p has autoloaded MAC address %s\n",
+	       intel, eth_ntoa ( mac.raw ) );
+
+	/* Try to read address from EEPROM */
+	if ( ( rc = intel_fetch_mac_eeprom ( intel, hw_addr ) ) == 0 )
+		return 0;
+
+	/* Use current address if valid */
+	if ( is_valid_ether_addr ( mac.raw ) ) {
+		memcpy ( hw_addr, mac.raw, ETH_ALEN );
+		return 0;
+	}
+
+	DBGC ( intel, "INTEL %p has no MAC address to use\n", intel );
+	return -ENOENT;
+}
+
+/******************************************************************************
+ *
+ * Diagnostics
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Dump diagnostic information
+ *
+ * @v intel		Intel device
+ */
+static void __attribute__ (( unused )) intel_diag ( struct intel_nic *intel ) {
+
+	DBGC ( intel, "INTEL %p TDH=%04x TDT=%04x RDH=%04x RDT=%04x\n", intel,
+	       readl ( intel->regs + INTEL_TDH ),
+	       readl ( intel->regs + INTEL_TDT ),
+	       readl ( intel->regs + INTEL_RDH ),
+	       readl ( intel->regs + INTEL_RDT ) );
+}
+
+/******************************************************************************
+ *
+ * Device reset
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Reset hardware
+ *
+ * @v intel		Intel device
+ * @ret rc		Return status code
+ */
+static int intel_reset ( struct intel_nic *intel ) {
+	uint32_t pbs;
+	uint32_t ctrl;
+	uint32_t status;
+
+	/* Force RX and TX packet buffer allocation, to work around an
+	 * errata in ICH devices.
+	 */
+	pbs = readl ( intel->regs + INTEL_PBS );
+	if ( ( pbs == 0x14 ) || ( pbs == 0x18 ) ) {
+		DBGC ( intel, "INTEL %p WARNING: applying ICH PBS/PBA errata\n",
+		       intel );
+		writel ( 0x08, intel->regs + INTEL_PBA );
+		writel ( 0x10, intel->regs + INTEL_PBS );
+	}
+
+	/* Always reset MAC.  Required to reset the TX and RX rings. */
+	ctrl = readl ( intel->regs + INTEL_CTRL );
+	writel ( ( ctrl | INTEL_CTRL_RST ), intel->regs + INTEL_CTRL );
+	mdelay ( INTEL_RESET_DELAY_MS );
+
+	/* Set a sensible default configuration */
+	ctrl |= ( INTEL_CTRL_SLU | INTEL_CTRL_ASDE );
+	ctrl &= ~( INTEL_CTRL_LRST | INTEL_CTRL_FRCSPD | INTEL_CTRL_FRCDPLX );
+	writel ( ctrl, intel->regs + INTEL_CTRL );
+	mdelay ( INTEL_RESET_DELAY_MS );
+
+	/* If link is already up, do not attempt to reset the PHY.  On
+	 * some models (notably ICH), performing a PHY reset seems to
+	 * drop the link speed to 10Mbps.
+	 */
+	status = readl ( intel->regs + INTEL_STATUS );
+	if ( status & INTEL_STATUS_LU ) {
+		DBGC ( intel, "INTEL %p MAC reset (ctrl %08x)\n",
+		       intel, ctrl );
+		return 0;
+	}
+
+	/* Reset PHY and MAC simultaneously */
+	writel ( ( ctrl | INTEL_CTRL_RST | INTEL_CTRL_PHY_RST ),
+		 intel->regs + INTEL_CTRL );
+	mdelay ( INTEL_RESET_DELAY_MS );
+
+	/* PHY reset is not self-clearing on all models */
+	writel ( ctrl, intel->regs + INTEL_CTRL );
+	mdelay ( INTEL_RESET_DELAY_MS );
+
+	DBGC ( intel, "INTEL %p MAC+PHY reset (ctrl %08x)\n", intel, ctrl );
+	return 0;
+}
+
+/******************************************************************************
+ *
+ * Link state
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Check link state
+ *
+ * @v netdev		Network device
+ */
+static void intel_check_link ( struct net_device *netdev ) {
+	struct intel_nic *intel = netdev->priv;
+	uint32_t status;
+
+	/* Read link status */
+	status = readl ( intel->regs + INTEL_STATUS );
+	DBGC ( intel, "INTEL %p link status is %08x\n", intel, status );
+
+	/* Update network device */
+	if ( status & INTEL_STATUS_LU ) {
+		netdev_link_up ( netdev );
+	} else {
+		netdev_link_down ( netdev );
+	}
+}
+
+/******************************************************************************
+ *
+ * Network device interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Create descriptor ring
+ *
+ * @v intel		Intel device
+ * @v ring		Descriptor ring
+ * @ret rc		Return status code
+ */
+static int intel_create_ring ( struct intel_nic *intel,
+			       struct intel_ring *ring ) {
+	physaddr_t address;
+	uint32_t dctl;
+
+	/* Allocate descriptor ring.  Align ring on its own size to
+	 * prevent any possible page-crossing errors due to hardware
+	 * errata.
+	 */
+	ring->desc = malloc_dma ( ring->len, ring->len );
+	if ( ! ring->desc )
+		return -ENOMEM;
+
+	/* Initialise descriptor ring */
+	memset ( ring->desc, 0, ring->len );
+
+	/* Program ring address */
+	address = virt_to_bus ( ring->desc );
+	writel ( ( address & 0xffffffffUL ),
+		 ( intel->regs + ring->reg + INTEL_xDBAL ) );
+	if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) {
+		writel ( ( ( ( uint64_t ) address ) >> 32 ),
+			 ( intel->regs + ring->reg + INTEL_xDBAH ) );
+	} else {
+		writel ( 0, intel->regs + ring->reg + INTEL_xDBAH );
+	}
+
+	/* Program ring length */
+	writel ( ring->len, ( intel->regs + ring->reg + INTEL_xDLEN ) );
+
+	/* Reset head and tail pointers */
+	writel ( 0, ( intel->regs + ring->reg + INTEL_xDH ) );
+	writel ( 0, ( intel->regs + ring->reg + INTEL_xDT ) );
+
+	/* Enable ring */
+	dctl = readl ( intel->regs + ring->reg + INTEL_xDCTL );
+	dctl |= INTEL_xDCTL_ENABLE;
+	writel ( dctl, intel->regs + ring->reg + INTEL_xDCTL );
+
+	DBGC ( intel, "INTEL %p ring %05x is at [%08llx,%08llx)\n",
+	       intel, ring->reg, ( ( unsigned long long ) address ),
+	       ( ( unsigned long long ) address + ring->len ) );
+
+	return 0;
+}
+
+/**
+ * Destroy descriptor ring
+ *
+ * @v intel		Intel device
+ * @v ring		Descriptor ring
+ */
+static void intel_destroy_ring ( struct intel_nic *intel,
+				 struct intel_ring *ring ) {
+
+	/* Clear ring length */
+	writel ( 0, ( intel->regs + ring->reg + INTEL_xDLEN ) );
+
+	/* Clear ring address */
+	writel ( 0, ( intel->regs + ring->reg + INTEL_xDBAL ) );
+	writel ( 0, ( intel->regs + ring->reg + INTEL_xDBAH ) );
+
+	/* Free descriptor ring */
+	free_dma ( ring->desc, ring->len );
+	ring->desc = NULL;
+	ring->prod = 0;
+	ring->cons = 0;
+}
+
+/**
+ * Refill receive descriptor ring
+ *
+ * @v intel		Intel device
+ */
+static void intel_refill_rx ( struct intel_nic *intel ) {
+	struct intel_descriptor *rx;
+	struct io_buffer *iobuf;
+	unsigned int rx_idx;
+	unsigned int rx_tail;
+	physaddr_t address;
+
+	while ( ( intel->rx.prod - intel->rx.cons ) < INTEL_RX_FILL ) {
+
+		/* Allocate I/O buffer */
+		iobuf = alloc_iob ( INTEL_RX_MAX_LEN );
+		if ( ! iobuf ) {
+			/* Wait for next refill */
+			return;
+		}
+
+		/* Get next receive descriptor */
+		rx_idx = ( intel->rx.prod++ % INTEL_NUM_RX_DESC );
+		rx_tail = ( intel->rx.prod % INTEL_NUM_RX_DESC );
+		rx = &intel->rx.desc[rx_idx];
+
+		/* Populate receive descriptor */
+		address = virt_to_bus ( iobuf->data );
+		rx->address = cpu_to_le64 ( address );
+		rx->length = 0;
+		rx->status = 0;
+		rx->errors = 0;
+		wmb();
+
+		/* Record I/O buffer */
+		assert ( intel->rx_iobuf[rx_idx] == NULL );
+		intel->rx_iobuf[rx_idx] = iobuf;
+
+		/* Push descriptor to card */
+		writel ( rx_tail, intel->regs + INTEL_RDT );
+
+		DBGC2 ( intel, "INTEL %p RX %d is [%llx,%llx)\n", intel, rx_idx,
+			( ( unsigned long long ) address ),
+			( ( unsigned long long ) address + INTEL_RX_MAX_LEN ) );
+	}
+}
+
+/**
+ * Open network device
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int intel_open ( struct net_device *netdev ) {
+	struct intel_nic *intel = netdev->priv;
+	union intel_receive_address mac;
+	uint32_t tctl;
+	uint32_t rctl;
+	int rc;
+
+	/* Create transmit descriptor ring */
+	if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 )
+		goto err_create_tx;
+
+	/* Create receive descriptor ring */
+	if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 )
+		goto err_create_rx;
+
+	/* Program MAC address */
+	memset ( &mac, 0, sizeof ( mac ) );
+	memcpy ( mac.raw, netdev->ll_addr, sizeof ( mac.raw ) );
+	writel ( le32_to_cpu ( mac.reg.low ), intel->regs + INTEL_RAL0 );
+	writel ( ( le32_to_cpu ( mac.reg.high ) | INTEL_RAH0_AV ),
+		 intel->regs + INTEL_RAH0 );
+
+	/* Enable transmitter  */
+	tctl = readl ( intel->regs + INTEL_TCTL );
+	tctl &= ~( INTEL_TCTL_CT_MASK | INTEL_TCTL_COLD_MASK );
+	tctl |= ( INTEL_TCTL_EN | INTEL_TCTL_PSP | INTEL_TCTL_CT_DEFAULT |
+		  INTEL_TCTL_COLD_DEFAULT );
+	writel ( tctl, intel->regs + INTEL_TCTL );
+
+	/* Enable receiver */
+	rctl = readl ( intel->regs + INTEL_RCTL );
+	rctl &= ~( INTEL_RCTL_BSIZE_BSEX_MASK );
+	rctl |= ( INTEL_RCTL_EN | INTEL_RCTL_UPE | INTEL_RCTL_MPE |
+		  INTEL_RCTL_BAM | INTEL_RCTL_BSIZE_2048 | INTEL_RCTL_SECRC );
+	writel ( rctl, intel->regs + INTEL_RCTL );
+
+	/* Fill receive ring */
+	intel_refill_rx ( intel );
+
+	/* Update link state */
+	intel_check_link ( netdev );
+
+	return 0;
+
+	intel_destroy_ring ( intel, &intel->rx );
+ err_create_rx:
+	intel_destroy_ring ( intel, &intel->tx );
+ err_create_tx:
+	return rc;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev		Network device
+ */
+static void intel_close ( struct net_device *netdev ) {
+	struct intel_nic *intel = netdev->priv;
+	unsigned int i;
+
+	/* Disable receiver */
+	writel ( 0, intel->regs + INTEL_RCTL );
+
+	/* Disable transmitter  */
+	writel ( 0, intel->regs + INTEL_TCTL );
+
+	/* Destroy receive descriptor ring */
+	intel_destroy_ring ( intel, &intel->rx );
+
+	/* Discard any unused receive buffers */
+	for ( i = 0 ; i < INTEL_NUM_RX_DESC ; i++ ) {
+		if ( intel->rx_iobuf[i] )
+			free_iob ( intel->rx_iobuf[i] );
+		intel->rx_iobuf[i] = NULL;
+	}
+
+	/* Destroy transmit descriptor ring */
+	intel_destroy_ring ( intel, &intel->tx );
+
+	/* Reset the NIC, to flush the transmit and receive FIFOs */
+	intel_reset ( intel );
+}
+
+/**
+ * Transmit packet
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int intel_transmit ( struct net_device *netdev,
+			       struct io_buffer *iobuf ) {
+	struct intel_nic *intel = netdev->priv;
+	struct intel_descriptor *tx;
+	unsigned int tx_idx;
+	unsigned int tx_tail;
+	physaddr_t address;
+
+	/* Get next transmit descriptor */
+	if ( ( intel->tx.prod - intel->tx.cons ) >= INTEL_NUM_TX_DESC ) {
+		DBGC ( intel, "INTEL %p out of transmit descriptors\n", intel );
+		return -ENOBUFS;
+	}
+	tx_idx = ( intel->tx.prod++ % INTEL_NUM_TX_DESC );
+	tx_tail = ( intel->tx.prod % INTEL_NUM_TX_DESC );
+	tx = &intel->tx.desc[tx_idx];
+
+	/* Populate transmit descriptor */
+	address = virt_to_bus ( iobuf->data );
+	tx->address = cpu_to_le64 ( address );
+	tx->length = cpu_to_le16 ( iob_len ( iobuf ) );
+	tx->command = ( INTEL_DESC_CMD_RS | INTEL_DESC_CMD_IFCS |
+			INTEL_DESC_CMD_EOP );
+	tx->status = 0;
+	wmb();
+
+	/* Notify card that there are packets ready to transmit */
+	writel ( tx_tail, intel->regs + INTEL_TDT );
+
+	DBGC2 ( intel, "INTEL %p TX %d is [%llx,%llx)\n", intel, tx_idx,
+		( ( unsigned long long ) address ),
+		( ( unsigned long long ) address + iob_len ( iobuf ) ) );
+
+	return 0;
+}
+
+/**
+ * Poll for completed packets
+ *
+ * @v netdev		Network device
+ */
+static void intel_poll_tx ( struct net_device *netdev ) {
+	struct intel_nic *intel = netdev->priv;
+	struct intel_descriptor *tx;
+	unsigned int tx_idx;
+
+	/* Check for completed packets */
+	while ( intel->tx.cons != intel->tx.prod ) {
+
+		/* Get next transmit descriptor */
+		tx_idx = ( intel->tx.cons % INTEL_NUM_TX_DESC );
+		tx = &intel->tx.desc[tx_idx];
+
+		/* Stop if descriptor is still in use */
+		if ( ! ( tx->status & INTEL_DESC_STATUS_DD ) )
+			return;
+
+		DBGC2 ( intel, "INTEL %p TX %d complete\n", intel, tx_idx );
+
+		/* Complete TX descriptor */
+		netdev_tx_complete_next ( netdev );
+		intel->tx.cons++;
+	}
+}
+
+/**
+ * Poll for received packets
+ *
+ * @v netdev		Network device
+ */
+static void intel_poll_rx ( struct net_device *netdev ) {
+	struct intel_nic *intel = netdev->priv;
+	struct intel_descriptor *rx;
+	struct io_buffer *iobuf;
+	unsigned int rx_idx;
+	size_t len;
+
+	/* Check for received packets */
+	while ( intel->rx.cons != intel->rx.prod ) {
+
+		/* Get next receive descriptor */
+		rx_idx = ( intel->rx.cons % INTEL_NUM_RX_DESC );
+		rx = &intel->rx.desc[rx_idx];
+
+		/* Stop if descriptor is still in use */
+		if ( ! ( rx->status & INTEL_DESC_STATUS_DD ) )
+			return;
+
+		/* Populate I/O buffer */
+		iobuf = intel->rx_iobuf[rx_idx];
+		intel->rx_iobuf[rx_idx] = NULL;
+		len = le16_to_cpu ( rx->length );
+		iob_put ( iobuf, len );
+
+		/* Hand off to network stack */
+		if ( rx->errors ) {
+			DBGC ( intel, "INTEL %p RX %d error (length %zd, "
+			       "errors %02x)\n",
+			       intel, rx_idx, len, rx->errors );
+			netdev_rx_err ( netdev, iobuf, -EIO );
+		} else {
+			DBGC2 ( intel, "INTEL %p RX %d complete (length %zd)\n",
+				intel, rx_idx, len );
+			netdev_rx ( netdev, iobuf );
+		}
+		intel->rx.cons++;
+	}
+}
+
+/**
+ * Poll for completed and received packets
+ *
+ * @v netdev		Network device
+ */
+static void intel_poll ( struct net_device *netdev ) {
+	struct intel_nic *intel = netdev->priv;
+	uint32_t icr;
+
+	/* Check for and acknowledge interrupts */
+	icr = readl ( intel->regs + INTEL_ICR );
+	if ( ! icr )
+		return;
+
+	/* Poll for TX completions, if applicable */
+	if ( icr & INTEL_IRQ_TXDW )
+		intel_poll_tx ( netdev );
+
+	/* Poll for RX completions, if applicable */
+	if ( icr & ( INTEL_IRQ_RXT0 | INTEL_IRQ_RXO ) )
+		intel_poll_rx ( netdev );
+
+	/* Report receive overruns */
+	if ( icr & INTEL_IRQ_RXO )
+		netdev_rx_err ( netdev, NULL, -ENOBUFS );
+
+	/* Check link state, if applicable */
+	if ( icr & INTEL_IRQ_LSC )
+		intel_check_link ( netdev );
+
+	/* Refill RX ring */
+	intel_refill_rx ( intel );
+}
+
+/**
+ * Enable or disable interrupts
+ *
+ * @v netdev		Network device
+ * @v enable		Interrupts should be enabled
+ */
+static void intel_irq ( struct net_device *netdev, int enable ) {
+	struct intel_nic *intel = netdev->priv;
+	uint32_t mask;
+
+	mask = ( INTEL_IRQ_TXDW | INTEL_IRQ_LSC | INTEL_IRQ_RXT0 );
+	if ( enable ) {
+		writel ( mask, intel->regs + INTEL_IMS );
+	} else {
+		writel ( mask, intel->regs + INTEL_IMC );
+	}
+}
+
+/** Intel network device operations */
+static struct net_device_operations intel_operations = {
+	.open		= intel_open,
+	.close		= intel_close,
+	.transmit	= intel_transmit,
+	.poll		= intel_poll,
+	.irq		= intel_irq,
+};
+
+/******************************************************************************
+ *
+ * PCI interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Probe PCI device
+ *
+ * @v pci		PCI device
+ * @ret rc		Return status code
+ */
+static int intel_probe ( struct pci_device *pci ) {
+	struct net_device *netdev;
+	struct intel_nic *intel;
+	int rc;
+
+	/* Allocate and initialise net device */
+	netdev = alloc_etherdev ( sizeof ( *intel ) );
+	if ( ! netdev ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	netdev_init ( netdev, &intel_operations );
+	intel = netdev->priv;
+	pci_set_drvdata ( pci, netdev );
+	netdev->dev = &pci->dev;
+	memset ( intel, 0, sizeof ( *intel ) );
+	intel->port = PCI_FUNC ( pci->busdevfn );
+	intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTEL_TD );
+	intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTEL_RD );
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pci );
+
+	/* Map registers */
+	intel->regs = ioremap ( pci->membase, INTEL_BAR_SIZE );
+
+	/* Reset the NIC */
+	if ( ( rc = intel_reset ( intel ) ) != 0 )
+		goto err_reset;
+
+	/* Fetch MAC address */
+	if ( ( rc = intel_fetch_mac ( intel, netdev->hw_addr ) ) != 0 )
+		goto err_fetch_mac;
+
+	/* Register network device */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
+		goto err_register_netdev;
+
+	/* Set initial link state */
+	intel_check_link ( netdev );
+
+	return 0;
+
+	unregister_netdev ( netdev );
+ err_register_netdev:
+ err_fetch_mac:
+	intel_reset ( intel );
+ err_reset:
+	iounmap ( intel->regs );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+ err_alloc:
+	return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci		PCI device
+ */
+static void intel_remove ( struct pci_device *pci ) {
+	struct net_device *netdev = pci_get_drvdata ( pci );
+	struct intel_nic *intel = netdev->priv;
+
+	/* Unregister network device */
+	unregister_netdev ( netdev );
+
+	/* Reset the NIC */
+	intel_reset ( intel );
+
+	/* Free network device */
+	iounmap ( intel->regs );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+/** Intel PCI device IDs */
+static struct pci_device_id intel_nics[] = {
+	PCI_ROM ( 0x8086, 0x0438, "dh8900cc", "DH8900CC", 0 ),
+	PCI_ROM ( 0x8086, 0x043a, "dh8900cc-f", "DH8900CC Fiber", 0 ),
+	PCI_ROM ( 0x8086, 0x043c, "dh8900cc-b", "DH8900CC Backplane", 0 ),
+	PCI_ROM ( 0x8086, 0x0440, "dh8900cc-s", "DH8900CC SFP", 0 ),
+	PCI_ROM ( 0x8086, 0x1000, "82542-f", "82542 (Fiber)", 0 ),
+	PCI_ROM ( 0x8086, 0x1001, "82543gc-f", "82543GC (Fiber)", 0 ),
+	PCI_ROM ( 0x8086, 0x1004, "82543gc", "82543GC (Copper)", 0 ),
+	PCI_ROM ( 0x8086, 0x1008, "82544ei", "82544EI (Copper)", 0 ),
+	PCI_ROM ( 0x8086, 0x1009, "82544ei-f", "82544EI (Fiber)", 0 ),
+	PCI_ROM ( 0x8086, 0x100c, "82544gc", "82544GC (Copper)", 0 ),
+	PCI_ROM ( 0x8086, 0x100d, "82544gc-l", "82544GC (LOM)", 0 ),
+	PCI_ROM ( 0x8086, 0x100e, "82540em", "82540EM", 0 ),
+	PCI_ROM ( 0x8086, 0x100f, "82545em", "82545EM (Copper)", 0 ),
+	PCI_ROM ( 0x8086, 0x1010, "82546eb", "82546EB (Copper)", 0 ),
+	PCI_ROM ( 0x8086, 0x1011, "82545em-f", "82545EM (Fiber)", 0 ),
+	PCI_ROM ( 0x8086, 0x1012, "82546eb-f", "82546EB (Fiber)", 0 ),
+	PCI_ROM ( 0x8086, 0x1013, "82541ei", "82541EI", 0 ),
+	PCI_ROM ( 0x8086, 0x1014, "82541er", "82541ER", 0 ),
+	PCI_ROM ( 0x8086, 0x1015, "82540em-l", "82540EM (LOM)", 0 ),
+	PCI_ROM ( 0x8086, 0x1016, "82540ep-m", "82540EP (Mobile)", 0 ),
+	PCI_ROM ( 0x8086, 0x1017, "82540ep", "82540EP", 0 ),
+	PCI_ROM ( 0x8086, 0x1018, "82541ei", "82541EI", 0 ),
+	PCI_ROM ( 0x8086, 0x1019, "82547ei", "82547EI", 0 ),
+	PCI_ROM ( 0x8086, 0x101a, "82547ei-m", "82547EI (Mobile)", 0 ),
+	PCI_ROM ( 0x8086, 0x101d, "82546eb", "82546EB", 0 ),
+	PCI_ROM ( 0x8086, 0x101e, "82540ep-m", "82540EP (Mobile)", 0 ),
+	PCI_ROM ( 0x8086, 0x1026, "82545gm", "82545GM", 0 ),
+	PCI_ROM ( 0x8086, 0x1027, "82545gm-1", "82545GM", 0 ),
+	PCI_ROM ( 0x8086, 0x1028, "82545gm-2", "82545GM", 0 ),
+	PCI_ROM ( 0x8086, 0x1049, "82566mm", "82566MM", 0 ),
+	PCI_ROM ( 0x8086, 0x104a, "82566dm", "82566DM", 0 ),
+	PCI_ROM ( 0x8086, 0x104b, "82566dc", "82566DC", 0 ),
+	PCI_ROM ( 0x8086, 0x104c, "82562v", "82562V 10/100", 0 ),
+	PCI_ROM ( 0x8086, 0x104d, "82566mc", "82566MC", 0 ),
+	PCI_ROM ( 0x8086, 0x105e, "82571eb", "82571EB", 0 ),
+	PCI_ROM ( 0x8086, 0x105f, "82571eb-1", "82571EB", 0 ),
+	PCI_ROM ( 0x8086, 0x1060, "82571eb-2", "82571EB", 0 ),
+	PCI_ROM ( 0x8086, 0x1075, "82547gi", "82547GI", 0 ),
+	PCI_ROM ( 0x8086, 0x1076, "82541gi", "82541GI", 0 ),
+	PCI_ROM ( 0x8086, 0x1077, "82541gi-1", "82541GI", 0 ),
+	PCI_ROM ( 0x8086, 0x1078, "82541er", "82541ER", 0 ),
+	PCI_ROM ( 0x8086, 0x1079, "82546gb", "82546GB", 0 ),
+	PCI_ROM ( 0x8086, 0x107a, "82546gb-1", "82546GB", 0 ),
+	PCI_ROM ( 0x8086, 0x107b, "82546gb-2", "82546GB", 0 ),
+	PCI_ROM ( 0x8086, 0x107c, "82541pi", "82541PI", 0 ),
+	PCI_ROM ( 0x8086, 0x107d, "82572ei", "82572EI (Copper)", 0 ),
+	PCI_ROM ( 0x8086, 0x107e, "82572ei-f", "82572EI (Fiber)", 0 ),
+	PCI_ROM ( 0x8086, 0x107f, "82572ei", "82572EI", 0 ),
+	PCI_ROM ( 0x8086, 0x108a, "82546gb-3", "82546GB", 0 ),
+	PCI_ROM ( 0x8086, 0x108b, "82573v", "82573V (Copper)", 0 ),
+	PCI_ROM ( 0x8086, 0x108c, "82573e", "82573E (Copper)", 0 ),
+	PCI_ROM ( 0x8086, 0x1096, "80003es2lan", "80003ES2LAN (Copper)", 0 ),
+	PCI_ROM ( 0x8086, 0x1098, "80003es2lan-s", "80003ES2LAN (Serdes)", 0 ),
+	PCI_ROM ( 0x8086, 0x1099, "82546gb-4", "82546GB (Copper)", 0 ),
+	PCI_ROM ( 0x8086, 0x109a, "82573l", "82573L", 0 ),
+	PCI_ROM ( 0x8086, 0x10a4, "82571eb", "82571EB", 0 ),
+	PCI_ROM ( 0x8086, 0x10a5, "82571eb", "82571EB (Fiber)", 0 ),
+	PCI_ROM ( 0x8086, 0x10a7, "82575eb", "82575EB", 0 ),
+	PCI_ROM ( 0x8086, 0x10a9, "82575eb", "82575EB Backplane", 0 ),
+	PCI_ROM ( 0x8086, 0x10b5, "82546gb", "82546GB (Copper)", 0 ),
+	PCI_ROM ( 0x8086, 0x10b9, "82572ei", "82572EI (Copper)", 0 ),
+	PCI_ROM ( 0x8086, 0x10ba, "80003es2lan", "80003ES2LAN (Copper)", 0 ),
+	PCI_ROM ( 0x8086, 0x10bb, "80003es2lan", "80003ES2LAN (Serdes)", 0 ),
+	PCI_ROM ( 0x8086, 0x10bc, "82571eb", "82571EB (Copper)", 0 ),
+	PCI_ROM ( 0x8086, 0x10bd, "82566dm-2", "82566DM-2", 0 ),
+	PCI_ROM ( 0x8086, 0x10bf, "82567lf", "82567LF", 0 ),
+	PCI_ROM ( 0x8086, 0x10c0, "82562v-2", "82562V-2 10/100", 0 ),
+	PCI_ROM ( 0x8086, 0x10c2, "82562g-2", "82562G-2 10/100", 0 ),
+	PCI_ROM ( 0x8086, 0x10c3, "82562gt-2", "82562GT-2 10/100", 0 ),
+	PCI_ROM ( 0x8086, 0x10c4, "82562gt", "82562GT 10/100", 0 ),
+	PCI_ROM ( 0x8086, 0x10c5, "82562g", "82562G 10/100", 0 ),
+	PCI_ROM ( 0x8086, 0x10c9, "82576", "82576", 0 ),
+	PCI_ROM ( 0x8086, 0x10cb, "82567v", "82567V", 0 ),
+	PCI_ROM ( 0x8086, 0x10cc, "82567lm-2", "82567LM-2", 0 ),
+	PCI_ROM ( 0x8086, 0x10cd, "82567lf-2", "82567LF-2", 0 ),
+	PCI_ROM ( 0x8086, 0x10ce, "82567v-2", "82567V-2", 0 ),
+	PCI_ROM ( 0x8086, 0x10d3, "82574l", "82574L", 0 ),
+	PCI_ROM ( 0x8086, 0x10d5, "82571pt", "82571PT PT Quad", 0 ),
+	PCI_ROM ( 0x8086, 0x10d6, "82575gb", "82575GB", 0 ),
+	PCI_ROM ( 0x8086, 0x10d9, "82571eb-d", "82571EB Dual Mezzanine", 0 ),
+	PCI_ROM ( 0x8086, 0x10da, "82571eb-q", "82571EB Quad Mezzanine", 0 ),
+	PCI_ROM ( 0x8086, 0x10de, "82567lm-3", "82567LM-3", 0 ),
+	PCI_ROM ( 0x8086, 0x10df, "82567lf-3", "82567LF-3", 0 ),
+	PCI_ROM ( 0x8086, 0x10e5, "82567lm-4", "82567LM-4", 0 ),
+	PCI_ROM ( 0x8086, 0x10e6, "82576", "82576", 0 ),
+	PCI_ROM ( 0x8086, 0x10e7, "82576-2", "82576", 0 ),
+	PCI_ROM ( 0x8086, 0x10e8, "82576-3", "82576", 0 ),
+	PCI_ROM ( 0x8086, 0x10ea, "82577lm", "82577LM", 0 ),
+	PCI_ROM ( 0x8086, 0x10eb, "82577lc", "82577LC", 0 ),
+	PCI_ROM ( 0x8086, 0x10ef, "82578dm", "82578DM", 0 ),
+	PCI_ROM ( 0x8086, 0x10f0, "82578dc", "82578DC", 0 ),
+	PCI_ROM ( 0x8086, 0x10f5, "82567lm", "82567LM", 0 ),
+	PCI_ROM ( 0x8086, 0x10f6, "82574l", "82574L", 0 ),
+	PCI_ROM ( 0x8086, 0x1501, "82567v-3", "82567V-3", 0 ),
+	PCI_ROM ( 0x8086, 0x1502, "82579lm", "82579LM", 0 ),
+	PCI_ROM ( 0x8086, 0x1503, "82579v", "82579V", 0 ),
+	PCI_ROM ( 0x8086, 0x150a, "82576ns", "82576NS", 0 ),
+	PCI_ROM ( 0x8086, 0x150c, "82583v", "82583V", 0 ),
+	PCI_ROM ( 0x8086, 0x150d, "82576-4", "82576 Backplane", 0 ),
+	PCI_ROM ( 0x8086, 0x150e, "82580", "82580", 0 ),
+	PCI_ROM ( 0x8086, 0x150f, "82580-f", "82580 Fiber", 0 ),
+	PCI_ROM ( 0x8086, 0x1510, "82580-b", "82580 Backplane", 0 ),
+	PCI_ROM ( 0x8086, 0x1511, "82580-s", "82580 SFP", 0 ),
+	PCI_ROM ( 0x8086, 0x1516, "82580-2", "82580", 0 ),
+	PCI_ROM ( 0x8086, 0x1518, "82576ns", "82576NS SerDes", 0 ),
+	PCI_ROM ( 0x8086, 0x1521, "i350", "I350", 0 ),
+	PCI_ROM ( 0x8086, 0x1522, "i350-f", "I350 Fiber", 0 ),
+	PCI_ROM ( 0x8086, 0x1523, "i350-b", "I350 Backplane", 0 ),
+	PCI_ROM ( 0x8086, 0x1524, "i350-2", "I350", 0 ),
+	PCI_ROM ( 0x8086, 0x1525, "82567v-4", "82567V-4", 0 ),
+	PCI_ROM ( 0x8086, 0x1526, "82576-5", "82576", 0 ),
+	PCI_ROM ( 0x8086, 0x1527, "82580-f2", "82580 Fiber", 0 ),
+	PCI_ROM ( 0x8086, 0x1533, "i210", "I210", 0 ),
+	PCI_ROM ( 0x8086, 0x294c, "82566dc-2", "82566DC-2", 0 ),
+	PCI_ROM ( 0x8086, 0x2e6e, "cemedia", "CE Media Processor", 0 ),
+};
+
+/** Intel PCI driver */
+struct pci_driver intel_driver __pci_driver = {
+	.ids = intel_nics,
+	.id_count = ( sizeof ( intel_nics ) / sizeof ( intel_nics[0] ) ),
+	.probe = intel_probe,
+	.remove = intel_remove,
+};
diff --git a/roms/ipxe/src/drivers/net/intel.h b/roms/ipxe/src/drivers/net/intel.h
new file mode 100644
index 0000000000000000000000000000000000000000..e9e9052b834a566e4fac7273f6f13b0319cd1307
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/intel.h
@@ -0,0 +1,257 @@
+#ifndef _INTEL_H
+#define _INTEL_H
+
+/** @file
+ *
+ * Intel 10/100/1000 network card driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/nvs.h>
+
+/** Intel BAR size */
+#define INTEL_BAR_SIZE ( 128 * 1024 )
+
+/** A packet descriptor */
+struct intel_descriptor {
+	/** Buffer address */
+	uint64_t address;
+	/** Length */
+	uint16_t length;
+	/** Reserved */
+	uint8_t reserved_a;
+	/** Command */
+	uint8_t command;
+	/** Status */
+	uint8_t status;
+	/** Errors */
+	uint8_t errors;
+	/** Reserved */
+	uint16_t reserved_b;
+} __attribute__ (( packed ));
+
+/** Packet descriptor command bits */
+enum intel_descriptor_command {
+	/** Report status */
+	INTEL_DESC_CMD_RS = 0x08,
+	/** Insert frame checksum (CRC) */
+	INTEL_DESC_CMD_IFCS = 0x02,
+	/** End of packet */
+	INTEL_DESC_CMD_EOP = 0x01,
+};
+
+/** Packet descriptor status bits */
+enum intel_descriptor_status {
+	/** Descriptor done */
+	INTEL_DESC_STATUS_DD = 0x01,
+};
+
+/** Device Control Register */
+#define INTEL_CTRL 0x00000UL
+#define INTEL_CTRL_LRST		0x00000008UL	/**< Link reset */
+#define INTEL_CTRL_ASDE		0x00000020UL	/**< Auto-speed detection */
+#define INTEL_CTRL_SLU		0x00000040UL	/**< Set link up */
+#define INTEL_CTRL_FRCSPD	0x00000800UL	/**< Force speed */
+#define INTEL_CTRL_FRCDPLX	0x00001000UL	/**< Force duplex */
+#define INTEL_CTRL_RST		0x04000000UL	/**< Device reset */
+#define INTEL_CTRL_PHY_RST	0x80000000UL	/**< PHY reset */
+
+/** Time to delay for device reset, in milliseconds */
+#define INTEL_RESET_DELAY_MS 20
+
+/** Device Status Register */
+#define INTEL_STATUS 0x00008UL
+#define INTEL_STATUS_LU		0x00000002UL	/**< Link up */
+
+/** EEPROM Read Register */
+#define INTEL_EERD 0x00014UL
+#define INTEL_EERD_START	0x00000001UL	/**< Start read */
+#define INTEL_EERD_DONE_SMALL	0x00000010UL	/**< Read done (small EERD) */
+#define INTEL_EERD_DONE_LARGE	0x00000002UL	/**< Read done (large EERD) */
+#define INTEL_EERD_ADDR_SHIFT_SMALL 8		/**< Address shift (small) */
+#define INTEL_EERD_ADDR_SHIFT_LARGE 2		/**< Address shift (large) */
+#define INTEL_EERD_DATA(value)	( (value) >> 16 ) /**< Read data */
+
+/** Maximum time to wait for EEPROM read, in milliseconds */
+#define INTEL_EEPROM_MAX_WAIT_MS 100
+
+/** EEPROM word length */
+#define INTEL_EEPROM_WORD_LEN_LOG2 1
+
+/** Minimum EEPROM size, in words */
+#define INTEL_EEPROM_MIN_SIZE_WORDS 64
+
+/** Offset of MAC address within EEPROM */
+#define INTEL_EEPROM_MAC 0x00
+
+/** Interrupt Cause Read Register */
+#define INTEL_ICR 0x000c0UL
+#define INTEL_IRQ_TXDW		0x00000001UL	/**< Transmit descriptor done */
+#define INTEL_IRQ_LSC		0x00000004UL	/**< Link status change */
+#define INTEL_IRQ_RXT0		0x00000080UL	/**< Receive timer */
+#define INTEL_IRQ_RXO		0x00000400UL	/**< Receive overrun */
+
+/** Interrupt Mask Set/Read Register */
+#define INTEL_IMS 0x000d0UL
+
+/** Interrupt Mask Clear Register */
+#define INTEL_IMC 0x000d8UL
+
+/** Receive Control Register */
+#define INTEL_RCTL 0x00100UL
+#define INTEL_RCTL_EN		0x00000002UL	/**< Receive enable */
+#define INTEL_RCTL_UPE		0x00000008UL	/**< Unicast promiscuous mode */
+#define INTEL_RCTL_MPE		0x00000010UL	/**< Multicast promiscuous */
+#define INTEL_RCTL_BAM		0x00008000UL	/**< Broadcast accept mode */
+#define INTEL_RCTL_BSIZE_BSEX(bsex,bsize) \
+	( ( (bsize) << 16 ) | ( (bsex) << 25 ) ) /**< Buffer size */
+#define INTEL_RCTL_BSIZE_2048	INTEL_RCTL_BSIZE_BSEX ( 0, 0 )
+#define INTEL_RCTL_BSIZE_BSEX_MASK INTEL_RCTL_BSIZE_BSEX ( 1, 3 )
+#define INTEL_RCTL_SECRC	0x04000000UL	/**< Strip CRC */
+
+/** Transmit Control Register */
+#define INTEL_TCTL 0x00400UL
+#define INTEL_TCTL_EN		0x00000002UL	/**< Transmit enable */
+#define INTEL_TCTL_PSP		0x00000008UL	/**< Pad short packets */
+#define INTEL_TCTL_CT(x)	( (x) << 4 )	/**< Collision threshold */
+#define INTEL_TCTL_CT_DEFAULT	INTEL_TCTL_CT ( 0x0f )
+#define INTEL_TCTL_CT_MASK	INTEL_TCTL_CT ( 0xff )
+#define INTEL_TCTL_COLD(x)	( (x) << 12 )	/**< Collision distance */
+#define INTEL_TCTL_COLD_DEFAULT	INTEL_TCTL_COLD ( 0x040 )
+#define INTEL_TCTL_COLD_MASK	INTEL_TCTL_COLD ( 0x3ff )
+
+/** Packet Buffer Allocation */
+#define INTEL_PBA 0x01000UL
+
+/** Packet Buffer Size */
+#define INTEL_PBS 0x01008UL
+
+/** Receive Descriptor register block */
+#define INTEL_RD 0x02800UL
+
+/** Number of receive descriptors
+ *
+ * Minimum value is 8, since the descriptor ring length must be a
+ * multiple of 128.
+ */
+#define INTEL_NUM_RX_DESC 8
+
+/** Receive descriptor ring fill level */
+#define INTEL_RX_FILL 4
+
+/** Receive buffer length */
+#define INTEL_RX_MAX_LEN 2048
+
+/** Transmit Descriptor register block */
+#define INTEL_TD 0x03800UL
+
+/** Number of transmit descriptors
+ *
+ * Descriptor ring length must be a multiple of 16.  ICH8/9/10
+ * requires a minimum of 16 TX descriptors.
+ */
+#define INTEL_NUM_TX_DESC 16
+
+/** Receive/Transmit Descriptor Base Address Low (offset) */
+#define INTEL_xDBAL 0x00
+
+/** Receive/Transmit Descriptor Base Address High (offset) */
+#define INTEL_xDBAH 0x04
+
+/** Receive/Transmit Descriptor Length (offset) */
+#define INTEL_xDLEN 0x08
+
+/** Receive/Transmit Descriptor Head (offset) */
+#define INTEL_xDH 0x10
+
+/** Receive/Transmit Descriptor Tail (offset) */
+#define INTEL_xDT 0x18
+
+/** Receive/Transmit Descriptor Control (offset) */
+#define INTEL_xDCTL 0x28
+#define INTEL_xDCTL_ENABLE	0x02000000UL	/**< Queue enable */
+
+/** Receive Descriptor Head */
+#define INTEL_RDH ( INTEL_RD + INTEL_xDH )
+
+/** Receive Descriptor Tail */
+#define INTEL_RDT ( INTEL_RD + INTEL_xDT )
+
+/** Transmit Descriptor Head */
+#define INTEL_TDH ( INTEL_TD + INTEL_xDH )
+
+/** Transmit Descriptor Tail */
+#define INTEL_TDT ( INTEL_TD + INTEL_xDT )
+
+/** Receive Address Low */
+#define INTEL_RAL0 0x05400UL
+
+/** Receive Address High */
+#define INTEL_RAH0 0x05404UL
+#define INTEL_RAH0_AV		0x80000000UL	/**< Address valid */
+
+/** Receive address */
+union intel_receive_address {
+	struct {
+		uint32_t low;
+		uint32_t high;
+	} __attribute__ (( packed )) reg;
+	uint8_t raw[ETH_ALEN];
+};
+
+/** An Intel descriptor ring */
+struct intel_ring {
+	/** Descriptors */
+	struct intel_descriptor *desc;
+	/** Producer index */
+	unsigned int prod;
+	/** Consumer index */
+	unsigned int cons;
+
+	/** Register block */
+	unsigned int reg;
+	/** Length (in bytes) */
+	size_t len;
+};
+
+/**
+ * Initialise descriptor ring
+ *
+ * @v ring		Descriptor ring
+ * @v count		Number of descriptors
+ * @v reg		Descriptor register block
+ */
+static inline __attribute__ (( always_inline)) void
+intel_init_ring ( struct intel_ring *ring, unsigned int count,
+		  unsigned int reg ) {
+	ring->len = ( count * sizeof ( ring->desc[0] ) );
+	ring->reg = reg;
+}
+
+/** An Intel network card */
+struct intel_nic {
+	/** Registers */
+	void *regs;
+	/** Port number (for multi-port devices) */
+	unsigned int port;
+
+	/** EEPROM */
+	struct nvs_device eeprom;
+	/** EEPROM done flag */
+	uint32_t eerd_done;
+	/** EEPROM address shift */
+	unsigned int eerd_addr_shift;
+
+	/** Transmit descriptor ring */
+	struct intel_ring tx;
+	/** Receive descriptor ring */
+	struct intel_ring rx;
+	/** Receive I/O buffers */
+	struct io_buffer *rx_iobuf[INTEL_NUM_RX_DESC];
+};
+
+#endif /* _INTEL_H */
diff --git a/roms/ipxe/src/drivers/net/ipoib.c b/roms/ipxe/src/drivers/net/ipoib.c
index 4917b58e8f570831135ed5bf5f9d..c1b8cad9a6ca58f4eb3ec96e2019 100644
--- a/roms/ipxe/src/drivers/net/ipoib.c
+++ b/roms/ipxe/src/drivers/net/ipoib.c
@@ -13,24 +13,30 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
+#include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <byteswap.h>
 #include <errno.h>
 #include <ipxe/errortab.h>
+#include <ipxe/malloc.h>
 #include <ipxe/if_arp.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
 #include <ipxe/iobuf.h>
 #include <ipxe/netdevice.h>
 #include <ipxe/infiniband.h>
 #include <ipxe/ib_pathrec.h>
 #include <ipxe/ib_mcast.h>
+#include <ipxe/retry.h>
 #include <ipxe/ipoib.h>
 
 /** @file
@@ -57,6 +63,8 @@ struct ipoib_device {
 	struct ib_completion_queue *cq;
 	/** Queue pair */
 	struct ib_queue_pair *qp;
+	/** Local MAC */
+	struct ipoib_mac mac;
 	/** Broadcast MAC */
 	struct ipoib_mac broadcast;
 	/** Joined to IPv4 broadcast multicast group
@@ -67,6 +75,8 @@ struct ipoib_device {
 	int broadcast_joined;
 	/** IPv4 broadcast multicast group membership */
 	struct ib_mc_membership broadcast_membership;
+	/** REMAC cache */
+	struct list_head peers;
 };
 
 /** Broadcast IPoIB address */
@@ -88,176 +98,140 @@ struct errortab ipoib_errors[] __errortab = {
 
 /****************************************************************************
  *
- * IPoIB peer cache
+ * IPoIB REMAC cache
  *
  ****************************************************************************
  */
 
-/**
- * IPoIB peer address
- *
- * The IPoIB link-layer header is only four bytes long and so does not
- * have sufficient room to store IPoIB MAC address(es).  We therefore
- * maintain a cache of MAC addresses identified by a single-byte key,
- * and abuse the spare two bytes within the link-layer header to
- * communicate these MAC addresses between the link-layer code and the
- * netdevice driver.
- */
+/** An IPoIB REMAC cache entry */
 struct ipoib_peer {
-	/** Key */
-	uint8_t key;
+	/** List of REMAC cache entries */
+	struct list_head list;
+	/** Remote Ethermet MAC */
+	struct ipoib_remac remac;
 	/** MAC address */
 	struct ipoib_mac mac;
 };
 
-/** Number of IPoIB peer cache entries
- *
- * Must be a power of two.
- */
-#define IPOIB_NUM_CACHED_PEERS 4
-
-/** IPoIB peer address cache */
-static struct ipoib_peer ipoib_peer_cache[IPOIB_NUM_CACHED_PEERS];
-
-/** Oldest IPoIB peer cache entry index */
-static unsigned int ipoib_peer_cache_idx = 1;
-
 /**
- * Look up cached peer by key
+ * Find IPoIB MAC from REMAC
  *
- * @v key		Peer cache key
- * @ret peer		Peer cache entry, or NULL
+ * @v ipoib		IPoIB device
+ * @v remac		Remote Ethernet MAC
+ * @ret mac		IPoIB MAC (or NULL if not found)
  */
-static struct ipoib_peer * ipoib_lookup_peer_by_key ( unsigned int key ) {
+static struct ipoib_mac * ipoib_find_remac ( struct ipoib_device *ipoib,
+					     const struct ipoib_remac *remac ) {
 	struct ipoib_peer *peer;
-	unsigned int i;
 
-	for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) {
-		peer = &ipoib_peer_cache[i];
-		if ( peer->key == key )
-			return peer;
+	/* Check for broadcast REMAC */
+	if ( is_broadcast_ether_addr ( remac ) )
+		return &ipoib->broadcast;
+
+	/* Try to find via REMAC cache */
+	list_for_each_entry ( peer, &ipoib->peers, list ) {
+		if ( memcmp ( remac, &peer->remac,
+			      sizeof ( peer->remac ) ) == 0 ) {
+			/* Move peer to start of list */
+			list_del ( &peer->list );
+			list_add ( &peer->list, &ipoib->peers );
+			return &peer->mac;
+		}
 	}
 
-	if ( key != 0 ) {
-		DBG ( "IPoIB warning: peer cache lost track of key %x while "
-		      "still in use\n", key );
-	}
+	DBGC ( ipoib, "IPoIB %p unknown REMAC %s\n",
+	       ipoib, eth_ntoa ( remac ) );
 	return NULL;
 }
 
 /**
- * Store GID and QPN in peer cache
+ * Add IPoIB MAC to REMAC cache
  *
- * @v mac		Peer MAC address
- * @ret peer		Peer cache entry
+ * @v ipoib		IPoIB device
+ * @v remac		Remote Ethernet MAC
+ * @v mac		IPoIB MAC
+ * @ret rc		Return status code
  */
-static struct ipoib_peer * ipoib_cache_peer ( const struct ipoib_mac *mac ) {
+static int ipoib_map_remac ( struct ipoib_device *ipoib,
+			     const struct ipoib_remac *remac,
+			     const struct ipoib_mac *mac ) {
 	struct ipoib_peer *peer;
-	unsigned int key;
-	unsigned int i;
 
-	/* Look for existing cache entry */
-	for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) {
-		peer = &ipoib_peer_cache[i];
-		if ( memcmp ( &peer->mac, mac, sizeof ( peer->mac ) ) == 0 )
-			return peer;
+	/* Check for existing entry in REMAC cache */
+	list_for_each_entry ( peer, &ipoib->peers, list ) {
+		if ( memcmp ( remac, &peer->remac,
+			      sizeof ( peer->remac ) ) == 0 ) {
+			/* Move peer to start of list */
+			list_del ( &peer->list );
+			list_add ( &peer->list, &ipoib->peers );
+			/* Update MAC */
+			memcpy ( &peer->mac, mac, sizeof ( peer->mac ) );
+			return 0;
+		}
 	}
 
-	/* 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;
+	/* Create new entry */
+	peer = malloc ( sizeof ( *peer ) );
+	if ( ! peer )
+		return -ENOMEM;
+	memcpy ( &peer->remac, remac, sizeof ( peer->remac ) );
 	memcpy ( &peer->mac, mac, sizeof ( peer->mac ) );
-	DBG ( "IPoIB peer %x has MAC %s\n",
-	      peer->key, ipoib_ntoa ( &peer->mac ) );
-	return peer;
-}
+	list_add ( &peer->list, &ipoib->peers );
 
-/****************************************************************************
- *
- * IPoIB link layer
- *
- ****************************************************************************
- */
+	return 0;
+}
 
 /**
- * Add IPoIB link-layer header
+ * Flush REMAC cache
  *
- * @v netdev		Network device
- * @v iobuf		I/O buffer
- * @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
+ * @v ipoib		IPoIB device
  */
-static int ipoib_push ( struct net_device *netdev __unused,
-			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 );
-	src = ipoib_cache_peer ( src_mac );
-
-	/* Build IPoIB header */
-	ipoib_hdr->proto = net_proto;
-	ipoib_hdr->u.peer.dest = dest->key;
-	ipoib_hdr->u.peer.src = src->key;
+static void ipoib_flush_remac ( struct ipoib_device *ipoib ) {
+	struct ipoib_peer *peer;
+	struct ipoib_peer *tmp;
 
-	return 0;
+	list_for_each_entry_safe ( peer, tmp, &ipoib->peers, list ) {
+		list_del ( &peer->list );
+		free ( peer );
+	}
 }
 
 /**
- * Remove IPoIB link-layer header
+ * Discard some entries from the REMAC cache
  *
- * @v netdev		Network device
- * @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
+ * @ret discarded	Number of cached items discarded
  */
-static int ipoib_pull ( struct net_device *netdev,
-			struct io_buffer *iobuf, const void **ll_dest,
-			const void **ll_source, uint16_t *net_proto ) {
-	struct ipoib_device *ipoib = netdev->priv;
-	struct ipoib_hdr *ipoib_hdr = iobuf->data;
-	struct ipoib_peer *dest;
-	struct ipoib_peer *source;
-
-	/* Sanity check */
-	if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) {
-		DBG ( "IPoIB packet too short for link-layer header\n" );
-		DBG_HD ( iobuf->data, iob_len ( iobuf ) );
-		return -EINVAL;
+static unsigned int ipoib_discard_remac ( void ) {
+	struct ib_device *ibdev;
+	struct ipoib_device *ipoib;
+	struct ipoib_peer *peer;
+	unsigned int discarded = 0;
+
+	/* Try to discard one cache entry for each IPoIB device */
+	for_each_ibdev ( ibdev ) {
+		ipoib = ib_get_ownerdata ( ibdev );
+		list_for_each_entry_reverse ( peer, &ipoib->peers, list ) {
+			list_del ( &peer->list );
+			free ( peer );
+			discarded++;
+			break;
+		}
 	}
 
-	/* 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;
+	return discarded;
+}
 
-	/* Fill in required fields */
-	*ll_dest = ( dest ? &dest->mac : &ipoib->broadcast );
-	*ll_source = ( source ? &source->mac : &ipoib->broadcast );
-	*net_proto = ipoib_hdr->proto;
+/** IPoIB cache discarder */
+struct cache_discarder ipoib_discarder __cache_discarder ( CACHE_NORMAL ) = {
+	.discard = ipoib_discard_remac,
+};
 
-	return 0;
-}
+/****************************************************************************
+ *
+ * IPoIB link layer
+ *
+ ****************************************************************************
+ */
 
 /**
  * Initialise IPoIB link-layer address
@@ -266,133 +240,205 @@ static int ipoib_pull ( struct net_device *netdev,
  * @v ll_addr		Link-layer address
  */
 static void ipoib_init_addr ( const void *hw_addr, void *ll_addr ) {
-	const union ib_guid *guid = hw_addr;
-	struct ipoib_mac *mac = ll_addr;
+	const uint8_t *guid = hw_addr;
+	uint8_t *eth_addr = ll_addr;
+	uint8_t guid_mask = IPOIB_GUID_MASK;
+	unsigned int i;
 
-	memset ( mac, 0, sizeof ( *mac ) );
-	memcpy ( &mac->gid.s.guid, guid, sizeof ( mac->gid.s.guid ) );
+	/* Extract bytes from GUID according to mask */
+	for ( i = 0 ; i < 8 ; i++, guid++, guid_mask <<= 1 ) {
+		if ( guid_mask & 0x80 )
+			*(eth_addr++) = *guid;
+	}
 }
 
+/** IPoIB protocol */
+struct ll_protocol ipoib_protocol __ll_protocol = {
+	.name		= "IPoIB",
+	.ll_proto	= htons ( ARPHRD_ETHER ),
+	.hw_addr_len	= sizeof ( union ib_guid ),
+	.ll_addr_len	= ETH_ALEN,
+	.ll_header_len	= ETH_HLEN,
+	.push		= eth_push,
+	.pull		= eth_pull,
+	.init_addr	= ipoib_init_addr,
+	.ntoa		= eth_ntoa,
+	.mc_hash	= eth_mc_hash,
+	.eth_addr	= eth_eth_addr,
+	.flags		= LL_NAME_ONLY,
+};
+
 /**
- * Transcribe IPoIB link-layer address
+ * Allocate IPoIB device
  *
- * @v ll_addr	Link-layer address
- * @ret string	Link-layer address in human-readable format
+ * @v priv_size		Size of driver private data
+ * @ret netdev		Network device, or NULL
  */
-const char * ipoib_ntoa ( const void *ll_addr ) {
-	static char buf[45];
-	const struct ipoib_mac *mac = ll_addr;
-
-	snprintf ( buf, sizeof ( buf ), "%08x:%08x:%08x:%08x:%08x",
-		   htonl ( mac->flags__qpn ), htonl ( mac->gid.dwords[0] ),
-		   htonl ( mac->gid.dwords[1] ),
-		   htonl ( mac->gid.dwords[2] ),
-		   htonl ( mac->gid.dwords[3] ) );
-	return buf;
+struct net_device * alloc_ipoibdev ( size_t priv_size ) {
+	struct net_device *netdev;
+
+	netdev = alloc_netdev ( priv_size );
+	if ( netdev ) {
+		netdev->ll_protocol = &ipoib_protocol;
+		netdev->ll_broadcast = eth_broadcast;
+		netdev->max_pkt_len = IB_MAX_PAYLOAD_SIZE;
+	}
+	return netdev;
 }
 
+/****************************************************************************
+ *
+ * IPoIB translation layer
+ *
+ ****************************************************************************
+ */
+
 /**
- * Hash multicast address
+ * Translate transmitted ARP packet
  *
- * @v af		Address family
- * @v net_addr		Network-layer address
- * @v ll_addr		Link-layer address to fill in
+ * @v netdev		Network device
+ * @v iobuf		Packet to be transmitted (with no link-layer headers)
  * @ret rc		Return status code
  */
-static int ipoib_mc_hash ( unsigned int af __unused,
-			   const void *net_addr __unused,
-			   void *ll_addr __unused ) {
+static int ipoib_translate_tx_arp ( struct net_device *netdev,
+				    struct io_buffer *iobuf ) {
+	struct ipoib_device *ipoib = netdev->priv;
+	struct arphdr *arphdr = iobuf->data;
+	struct ipoib_mac *target_ha = NULL;
+	void *sender_pa;
+	void *target_pa;
+
+	/* Do nothing unless ARP contains eIPoIB link-layer addresses */
+	if ( arphdr->ar_hln != ETH_ALEN )
+		return 0;
+
+	/* Fail unless we have room to expand packet */
+	if ( iob_tailroom ( iobuf ) < ( 2 * ( sizeof ( ipoib->mac ) -
+					      ETH_ALEN ) ) ) {
+		DBGC ( ipoib, "IPoIB %p insufficient space in TX ARP\n",
+		       ipoib );
+		return -ENOBUFS;
+	}
+
+	/* Look up REMAC, if applicable */
+	if ( arphdr->ar_op == ARPOP_REPLY ) {
+		target_ha = ipoib_find_remac ( ipoib, arp_target_pa ( arphdr ));
+		if ( ! target_ha )
+			return -ENXIO;
+	}
+
+	/* Construct new packet */
+	iob_put ( iobuf, ( 2 * ( sizeof ( ipoib->mac ) - ETH_ALEN ) ) );
+	sender_pa = arp_sender_pa ( arphdr );
+	target_pa = arp_target_pa ( arphdr );
+	arphdr->ar_hrd = htons ( ARPHRD_INFINIBAND );
+	arphdr->ar_hln = sizeof ( ipoib->mac );
+	memcpy ( arp_target_pa ( arphdr ), target_pa, arphdr->ar_pln );
+	memcpy ( arp_sender_pa ( arphdr ), sender_pa, arphdr->ar_pln );
+	memcpy ( arp_sender_ha ( arphdr ), &ipoib->mac, sizeof ( ipoib->mac ) );
+	memset ( arp_target_ha ( arphdr ), 0, sizeof ( ipoib->mac ) );
+	if ( target_ha ) {
+		memcpy ( arp_target_ha ( arphdr ), target_ha,
+			 sizeof ( *target_ha ) );
+	}
 
-	return -ENOTSUP;
+	return 0;
 }
 
 /**
- * Generate Mellanox Ethernet-compatible compressed link-layer address
+ * Translate transmitted packet
  *
- * @v ll_addr		Link-layer address
- * @v eth_addr		Ethernet-compatible address to fill in
+ * @v netdev		Network device
+ * @v iobuf		Packet to be transmitted (with no link-layer headers)
+ * @v net_proto		Network-layer protocol (in network byte order)
+ * @ret rc		Return status code
  */
-static int ipoib_mlx_eth_addr ( const union ib_guid *guid,
-				uint8_t *eth_addr ) {
-	eth_addr[0] = ( ( guid->bytes[3] == 2 ) ? 0x00 : 0x02 );
-	eth_addr[1] = guid->bytes[1];
-	eth_addr[2] = guid->bytes[2];
-	eth_addr[3] = guid->bytes[5];
-	eth_addr[4] = guid->bytes[6];
-	eth_addr[5] = guid->bytes[7];
-	return 0;
+static int ipoib_translate_tx ( struct net_device *netdev,
+				struct io_buffer *iobuf, uint16_t net_proto ) {
+
+	switch ( net_proto ) {
+	case htons ( ETH_P_ARP ) :
+		return ipoib_translate_tx_arp ( netdev, iobuf );
+	case htons ( ETH_P_IP ) :
+		/* No translation needed */
+		return 0;
+	default:
+		/* Cannot handle other traffic via eIPoIB */
+		return -ENOTSUP;
+	}
 }
 
-/** An IPoIB Ethernet-compatible compressed link-layer address generator */
-struct ipoib_eth_addr_handler {
-	/** GUID byte 1 */
-	uint8_t byte1;
-	/** GUID byte 2 */
-	uint8_t byte2;
-	/** Handler */
-	int ( * eth_addr ) ( const union ib_guid *guid,
-			     uint8_t *eth_addr );
-};
-
-/** IPoIB Ethernet-compatible compressed link-layer address generators */
-static struct ipoib_eth_addr_handler ipoib_eth_addr_handlers[] = {
-	{ 0x02, 0xc9, ipoib_mlx_eth_addr },
-};
-
 /**
- * Generate Ethernet-compatible compressed link-layer address
+ * Translate received ARP packet
  *
- * @v ll_addr		Link-layer address
- * @v eth_addr		Ethernet-compatible address to fill in
+ * @v netdev		Network device
+ * @v iobuf		Received packet (with no link-layer headers)
+ * @v remac		Constructed Remote Ethernet MAC
+ * @ret rc		Return status code
  */
-static int ipoib_eth_addr ( const void *ll_addr, void *eth_addr ) {
-	const struct ipoib_mac *ipoib_addr = ll_addr;
-	const union ib_guid *guid = &ipoib_addr->gid.s.guid;
-	struct ipoib_eth_addr_handler *handler;
-	unsigned int i;
+static int ipoib_translate_rx_arp ( struct net_device *netdev,
+				    struct io_buffer *iobuf,
+				    struct ipoib_remac *remac ) {
+	struct ipoib_device *ipoib = netdev->priv;
+	struct arphdr *arphdr = iobuf->data;
+	void *sender_pa;
+	void *target_pa;
+	int rc;
 
-	for ( i = 0 ; i < ( sizeof ( ipoib_eth_addr_handlers ) /
-			    sizeof ( ipoib_eth_addr_handlers[0] ) ) ; i++ ) {
-		handler = &ipoib_eth_addr_handlers[i];
-		if ( ( handler->byte1 == guid->bytes[1] ) &&
-		     ( handler->byte2 == guid->bytes[2] ) ) {
-			return handler->eth_addr ( guid, eth_addr );
-		}
+	/* Do nothing unless ARP contains IPoIB link-layer addresses */
+	if ( arphdr->ar_hln != sizeof ( ipoib->mac ) )
+		return 0;
+
+	/* Create REMAC cache entry */
+	if ( ( rc = ipoib_map_remac ( ipoib, remac,
+				      arp_sender_ha ( arphdr ) ) ) != 0 ) {
+		DBGC ( ipoib, "IPoIB %p could not map REMAC: %s\n",
+		       ipoib, strerror ( rc ) );
+		return rc;
 	}
-	return -ENOTSUP;
-}
 
-/** IPoIB protocol */
-struct ll_protocol ipoib_protocol __ll_protocol = {
-	.name		= "IPoIB",
-	.ll_proto	= htons ( ARPHRD_INFINIBAND ),
-	.hw_addr_len	= sizeof ( union ib_guid ),
-	.ll_addr_len	= IPOIB_ALEN,
-	.ll_header_len	= IPOIB_HLEN,
-	.push		= ipoib_push,
-	.pull		= ipoib_pull,
-	.init_addr	= ipoib_init_addr,
-	.ntoa		= ipoib_ntoa,
-	.mc_hash	= ipoib_mc_hash,
-	.eth_addr	= ipoib_eth_addr,
-};
+	/* Construct new packet */
+	sender_pa = arp_sender_pa ( arphdr );
+	target_pa = arp_target_pa ( arphdr );
+	arphdr->ar_hrd = htons ( ARPHRD_ETHER );
+	arphdr->ar_hln = ETH_ALEN;
+	memcpy ( arp_sender_pa ( arphdr ), sender_pa, arphdr->ar_pln );
+	memcpy ( arp_target_pa ( arphdr ), target_pa, arphdr->ar_pln );
+	memcpy ( arp_sender_ha ( arphdr ), remac, ETH_ALEN );
+	memset ( arp_target_ha ( arphdr ), 0, ETH_ALEN );
+	if ( arphdr->ar_op == ARPOP_REPLY ) {
+		/* Assume received replies were directed to us */
+		memcpy ( arp_target_ha ( arphdr ), netdev->ll_addr, ETH_ALEN );
+	}
+	iob_unput ( iobuf, ( 2 * ( sizeof ( ipoib->mac ) - ETH_ALEN ) ) );
+
+	return 0;
+}
 
 /**
- * Allocate IPoIB device
+ * Translate received packet
  *
- * @v priv_size		Size of driver private data
- * @ret netdev		Network device, or NULL
+ * @v netdev		Network device
+ * @v iobuf		Received packet (with no link-layer headers)
+ * @v remac		Constructed Remote Ethernet MAC
+ * @v net_proto		Network-layer protocol (in network byte order)
+ * @ret rc		Return status code
  */
-struct net_device * alloc_ipoibdev ( size_t priv_size ) {
-	struct net_device *netdev;
-
-	netdev = alloc_netdev ( priv_size );
-	if ( netdev ) {
-		netdev->ll_protocol = &ipoib_protocol;
-		netdev->ll_broadcast = ( uint8_t * ) &ipoib_broadcast;
-		netdev->max_pkt_len = IB_MAX_PAYLOAD_SIZE;
+static int ipoib_translate_rx ( struct net_device *netdev,
+				struct io_buffer *iobuf,
+				struct ipoib_remac *remac,
+				uint16_t net_proto ) {
+
+	switch ( net_proto ) {
+	case htons ( ETH_P_ARP ) :
+		return ipoib_translate_rx_arp ( netdev, iobuf, remac );
+	case htons ( ETH_P_IP ) :
+		/* No translation needed */
+		return 0;
+	default:
+		/* Cannot handle other traffic via eIPoIB */
+		return -ENOTSUP;
 	}
-	return netdev;
 }
 
 /****************************************************************************
@@ -413,17 +459,18 @@ 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 ethhdr *ethhdr;
 	struct ipoib_hdr *ipoib_hdr;
-	struct ipoib_peer *dest;
-	struct ib_address_vector av;
+	struct ipoib_mac *mac;
+	struct ib_address_vector dest;
+	uint16_t net_proto;
 	int rc;
 
 	/* Sanity check */
-	if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) {
+	if ( iob_len ( iobuf ) < sizeof ( *ethhdr ) ) {
 		DBGC ( ipoib, "IPoIB %p buffer too short\n", ipoib );
 		return -EINVAL;
 	}
-	ipoib_hdr = iobuf->data;
 
 	/* Attempting transmission while link is down will put the
 	 * queue pair into an error state, so don't try it.
@@ -431,23 +478,36 @@ static int ipoib_transmit ( struct net_device *netdev,
 	if ( ! ib_link_ok ( ibdev ) )
 		return -ENETUNREACH;
 
+	/* Strip eIPoIB header */
+	ethhdr = iobuf->data;
+	net_proto = ethhdr->h_protocol;
+	iob_pull ( iobuf, sizeof ( *ethhdr ) );
+
 	/* Identify destination address */
-	dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest );
-	if ( ! dest )
+	mac = ipoib_find_remac ( ipoib, ( ( void *) ethhdr->h_dest ) );
+	if ( ! mac )
 		return -ENXIO;
-	ipoib_hdr->u.reserved = 0;
+
+	/* Translate packet if applicable */
+	if ( ( rc = ipoib_translate_tx ( netdev, iobuf, net_proto ) ) != 0 )
+		return rc;
+
+	/* Prepend real IPoIB header */
+	ipoib_hdr = iob_push ( iobuf, sizeof ( *ipoib_hdr ) );
+	ipoib_hdr->proto = net_proto;
+	ipoib_hdr->reserved = 0;
 
 	/* Construct address vector */
-	memset ( &av, 0, sizeof ( av ) );
-	av.qpn = ( ntohl ( dest->mac.flags__qpn ) & IB_QPN_MASK );
-	av.gid_present = 1;
-	memcpy ( &av.gid, &dest->mac.gid, sizeof ( av.gid ) );
-	if ( ( rc = ib_resolve_path ( ibdev, &av ) ) != 0 ) {
+	memset ( &dest, 0, sizeof ( dest ) );
+	dest.qpn = ( ntohl ( mac->flags__qpn ) & IB_QPN_MASK );
+	dest.gid_present = 1;
+	memcpy ( &dest.gid, &mac->gid, sizeof ( dest.gid ) );
+	if ( ( rc = ib_resolve_path ( ibdev, &dest ) ) != 0 ) {
 		/* Path not resolved yet */
 		return rc;
 	}
 
-	return ib_post_send ( ibdev, ipoib->qp, &av, iobuf );
+	return ib_post_send ( ibdev, ipoib->qp, &dest, iobuf );
 }
 
 /**
@@ -471,19 +531,22 @@ static void ipoib_complete_send ( struct ib_device *ibdev __unused,
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector, or NULL
+ * @v dest		Destination address vector, or NULL
+ * @v source		Source address vector, or NULL
  * @v iobuf		I/O buffer
  * @v rc		Completion status code
  */
 static void ipoib_complete_recv ( struct ib_device *ibdev __unused,
 				  struct ib_queue_pair *qp,
-				  struct ib_address_vector *av,
+				  struct ib_address_vector *dest,
+				  struct ib_address_vector *source,
 				  struct io_buffer *iobuf, int rc ) {
 	struct ipoib_device *ipoib = ib_qp_get_ownerdata ( qp );
 	struct net_device *netdev = ipoib->netdev;
 	struct ipoib_hdr *ipoib_hdr;
-	struct ipoib_mac ll_src;
-	struct ipoib_peer *src;
+	struct ethhdr *ethhdr;
+	struct ipoib_remac remac;
+	uint16_t net_proto;
 
 	/* Record errors */
 	if ( rc != 0 ) {
@@ -499,20 +562,44 @@ static void ipoib_complete_recv ( struct ib_device *ibdev __unused,
 		netdev_rx_err ( netdev, iobuf, -EIO );
 		return;
 	}
-	ipoib_hdr = iobuf->data;
-	if ( ! av ) {
+	if ( ! source ) {
 		DBGC ( ipoib, "IPoIB %p received packet without address "
 		       "vector\n", ipoib );
 		netdev_rx_err ( netdev, iobuf, -ENOTTY );
 		return;
 	}
 
-	/* Parse source address */
-	if ( av->gid_present ) {
-		ll_src.flags__qpn = htonl ( av->qpn );
-		memcpy ( &ll_src.gid, &av->gid, sizeof ( ll_src.gid ) );
-		src = ipoib_cache_peer ( &ll_src );
-		ipoib_hdr->u.peer.src = src->key;
+	/* Strip real IPoIB header */
+	ipoib_hdr = iobuf->data;
+	net_proto = ipoib_hdr->proto;
+	iob_pull ( iobuf, sizeof ( *ipoib_hdr ) );
+
+	/* Construct source address from remote QPN and LID */
+	remac.qpn = htonl ( source->qpn | EIPOIB_QPN_LA );
+	remac.lid = htons ( source->lid );
+
+	/* Translate packet if applicable */
+	if ( ( rc = ipoib_translate_rx ( netdev, iobuf, &remac,
+					 net_proto ) ) != 0 ) {
+		netdev_rx_err ( netdev, iobuf, rc );
+		return;
+	}
+
+	/* Prepend eIPoIB header */
+	ethhdr = iob_push ( iobuf, sizeof ( *ethhdr ) );
+	memcpy ( &ethhdr->h_source, &remac, sizeof ( ethhdr->h_source ) );
+	ethhdr->h_protocol = net_proto;
+
+	/* Construct destination address */
+	if ( dest->gid_present && ( memcmp ( &dest->gid, &ipoib->broadcast.gid,
+					     sizeof ( dest->gid ) ) == 0 ) ) {
+		/* Broadcast GID; use the Ethernet broadcast address */
+		memcpy ( &ethhdr->h_dest, eth_broadcast,
+			 sizeof ( ethhdr->h_dest ) );
+	} else {
+		/* Assume destination address is local Ethernet MAC */
+		memcpy ( &ethhdr->h_dest, netdev->ll_addr,
+			 sizeof ( ethhdr->h_dest ) );
 	}
 
 	/* Hand off to network layer */
@@ -525,6 +612,42 @@ static struct ib_completion_queue_operations ipoib_cq_op = {
 	.complete_recv = ipoib_complete_recv,
 };
 
+/**
+ * Allocate IPoIB receive I/O buffer
+ *
+ * @v len		Length of buffer
+ * @ret iobuf		I/O buffer, or NULL
+ *
+ * Some Infiniband hardware requires 2kB alignment of receive buffers
+ * and provides no way to disable header separation.  The result is
+ * that there are only four bytes of link-layer header (the real IPoIB
+ * header) before the payload.  This is not sufficient space to insert
+ * an eIPoIB link-layer pseudo-header.
+ *
+ * We therefore allocate I/O buffers offset to start slightly before
+ * the natural alignment boundary, in order to allow sufficient space.
+ */
+static struct io_buffer * ipoib_alloc_iob ( size_t len ) {
+	struct io_buffer *iobuf;
+	size_t reserve_len;
+
+	/* Calculate additional length required at start of buffer */
+	reserve_len = ( sizeof ( struct ethhdr ) -
+			sizeof ( struct ipoib_hdr ) );
+
+	/* Allocate buffer */
+	iobuf = alloc_iob_raw ( ( len + reserve_len ), len, -reserve_len );
+	if ( iobuf ) {
+		iob_reserve ( iobuf, reserve_len );
+	}
+	return iobuf;
+}
+
+/** IPoIB queue pair operations */
+static struct ib_queue_pair_operations ipoib_qp_op = {
+	.alloc_iob = ipoib_alloc_iob,
+};
+
 /**
  * Poll IPoIB network device
  *
@@ -534,7 +657,11 @@ static void ipoib_poll ( struct net_device *netdev ) {
 	struct ipoib_device *ipoib = netdev->priv;
 	struct ib_device *ibdev = ipoib->ibdev;
 
+	/* Poll Infiniband device */
 	ib_poll_eq ( ibdev );
+
+	/* Poll the retry timers (required for IPoIB multicast join) */
+	retry_poll();
 }
 
 /**
@@ -601,15 +728,14 @@ static void ipoib_leave_broadcast_group ( struct ipoib_device *ipoib ) {
 static void ipoib_link_state_changed ( struct ib_device *ibdev ) {
 	struct net_device *netdev = ib_get_ownerdata ( ibdev );
 	struct ipoib_device *ipoib = netdev->priv;
-	struct ipoib_mac *mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
 	int rc;
 
 	/* Leave existing broadcast group */
 	ipoib_leave_broadcast_group ( ipoib );
 
 	/* Update MAC address based on potentially-new GID prefix */
-	memcpy ( &mac->gid.s.prefix, &ibdev->gid.s.prefix,
-		 sizeof ( mac->gid.s.prefix ) );
+	memcpy ( &ipoib->mac.gid.s.prefix, &ibdev->gid.s.prefix,
+		 sizeof ( ipoib->mac.gid.s.prefix ) );
 
 	/* Update broadcast GID based on potentially-new partition key */
 	ipoib->broadcast.gid.words[2] =
@@ -638,7 +764,6 @@ static void ipoib_link_state_changed ( struct ib_device *ibdev ) {
 static int ipoib_open ( struct net_device *netdev ) {
 	struct ipoib_device *ipoib = netdev->priv;
 	struct ib_device *ibdev = ipoib->ibdev;
-	struct ipoib_mac *mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
 	int rc;
 
 	/* Open IB device */
@@ -658,9 +783,9 @@ static int ipoib_open ( struct net_device *netdev ) {
 	}
 
 	/* Allocate queue pair */
-	ipoib->qp = ib_create_qp ( ibdev, IB_QPT_UD,
-				   IPOIB_NUM_SEND_WQES, ipoib->cq,
-				   IPOIB_NUM_RECV_WQES, ipoib->cq );
+	ipoib->qp = ib_create_qp ( ibdev, IB_QPT_UD, IPOIB_NUM_SEND_WQES,
+				   ipoib->cq, IPOIB_NUM_RECV_WQES, ipoib->cq,
+				   &ipoib_qp_op );
 	if ( ! ipoib->qp ) {
 		DBGC ( ipoib, "IPoIB %p could not allocate queue pair\n",
 		       ipoib );
@@ -670,7 +795,7 @@ static int ipoib_open ( struct net_device *netdev ) {
 	ib_qp_set_ownerdata ( ipoib->qp, ipoib );
 
 	/* Update MAC address with QPN */
-	mac->flags__qpn = htonl ( ipoib->qp->qpn );
+	ipoib->mac.flags__qpn = htonl ( ipoib->qp->qpn );
 
 	/* Fill receive rings */
 	ib_refill_recv ( ibdev, ipoib->qp );
@@ -697,13 +822,15 @@ static int ipoib_open ( struct net_device *netdev ) {
 static void ipoib_close ( struct net_device *netdev ) {
 	struct ipoib_device *ipoib = netdev->priv;
 	struct ib_device *ibdev = ipoib->ibdev;
-	struct ipoib_mac *mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
+
+	/* Flush REMAC cache */
+	ipoib_flush_remac ( ipoib );
 
 	/* Leave broadcast group */
 	ipoib_leave_broadcast_group ( ipoib );
 
 	/* Remove QPN from MAC address */
-	mac->flags__qpn = 0;
+	ipoib->mac.flags__qpn = 0;
 
 	/* Tear down the queues */
 	ib_destroy_qp ( ibdev, ipoib->qp );
@@ -743,15 +870,19 @@ static int ipoib_probe ( struct ib_device *ibdev ) {
 	memset ( ipoib, 0, sizeof ( *ipoib ) );
 	ipoib->netdev = netdev;
 	ipoib->ibdev = ibdev;
+	INIT_LIST_HEAD ( &ipoib->peers );
 
 	/* Extract hardware address */
 	memcpy ( netdev->hw_addr, &ibdev->gid.s.guid,
 		 sizeof ( ibdev->gid.s.guid ) );
 
-	/* Set default broadcast address */
+	/* Set local MAC address */
+	memcpy ( &ipoib->mac.gid.s.guid, &ibdev->gid.s.guid,
+		 sizeof ( ipoib->mac.gid.s.guid ) );
+
+	/* Set default broadcast MAC address */
 	memcpy ( &ipoib->broadcast, &ipoib_broadcast,
 		 sizeof ( ipoib->broadcast ) );
-	netdev->ll_broadcast = ( ( uint8_t * ) &ipoib->broadcast );
 
 	/* Register network device */
 	if ( ( rc = register_netdev ( netdev ) ) != 0 )
diff --git a/roms/ipxe/src/drivers/net/jme.c b/roms/ipxe/src/drivers/net/jme.c
index 545402650fca92f95dd43f1b3214..29694b6992759b53603cf6633fb4 100644
--- a/roms/ipxe/src/drivers/net/jme.c
+++ b/roms/ipxe/src/drivers/net/jme.c
@@ -14,7 +14,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  *
  */
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/net/jme.h b/roms/ipxe/src/drivers/net/jme.h
index 7e22543098892a3b30824b399a61..42db01ed3a107b37e3c95189061e 100644
--- a/roms/ipxe/src/drivers/net/jme.h
+++ b/roms/ipxe/src/drivers/net/jme.h
@@ -14,7 +14,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  *
  */
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/net/mii.c b/roms/ipxe/src/drivers/net/mii.c
new file mode 100644
index 0000000000000000000000000000000000000000..c4d32514d670c588510005725a873d233f8acd65
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/mii.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ipxe/mii.h>
+
+/** @file
+ *
+ * Media Independent Interface
+ *
+ */
+
+/**
+ * Restart autonegotiation
+ *
+ * @v mii		MII interface
+ * @ret rc		Return status code
+ */
+int mii_restart ( struct mii_interface *mii ) {
+	int bmcr;
+	int rc;
+
+	/* Read BMCR */
+	bmcr = mii_read ( mii, MII_BMCR );
+	if ( bmcr < 0 ) {
+		rc = bmcr;
+		DBGC ( mii, "MII %p could not read BMCR: %s\n",
+		       mii, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Enable and restart autonegotiation */
+	bmcr |= ( BMCR_ANENABLE | BMCR_ANRESTART );
+	if ( ( rc = mii_write ( mii, MII_BMCR, bmcr ) ) != 0 ) {
+		DBGC ( mii, "MII %p could not write BMCR: %s\n",
+		       mii, strerror ( rc ) );
+		return rc;
+	}
+
+	DBGC ( mii, "MII %p restarted autonegotiation\n", mii );
+	return 0;
+}
+
+/**
+ * Reset MII interface
+ *
+ * @v mii		MII interface
+ * @ret rc		Return status code
+ */
+int mii_reset ( struct mii_interface *mii ) {
+	unsigned int i;
+	int bmcr;
+	int rc;
+
+	/* Power-up, enable autonegotiation and initiate reset */
+	if ( ( rc = mii_write ( mii, MII_BMCR,
+				( BMCR_RESET | BMCR_ANENABLE ) ) ) != 0 ) {
+		DBGC ( mii, "MII %p could not write BMCR: %s\n",
+		       mii, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Wait for reset to complete */
+	for ( i = 0 ; i < MII_RESET_MAX_WAIT_MS ; i++ ) {
+
+		/* Check if reset has completed */
+		bmcr = mii_read ( mii, MII_BMCR );
+		if ( bmcr < 0 ) {
+			rc = bmcr;
+			DBGC ( mii, "MII %p could not read BMCR: %s\n",
+			       mii, strerror ( rc ) );
+			return rc;
+		}
+
+		/* If reset is not complete, delay 1ms and retry */
+		if ( bmcr & BMCR_RESET ) {
+			mdelay ( 1 );
+			continue;
+		}
+
+		/* Force autonegotation on again, in case it was
+		 * cleared by the reset.
+		 */
+		if ( ( rc = mii_restart ( mii ) ) != 0 )
+			return rc;
+
+		DBGC ( mii, "MII %p reset after %dms\n", mii, i );
+		return 0;
+	}
+
+	DBGC ( mii, "MII %p timed out waiting for reset\n", mii );
+	return -ETIMEDOUT;
+}
diff --git a/roms/ipxe/src/drivers/net/mtd80x.c b/roms/ipxe/src/drivers/net/mtd80x.c
deleted file mode 100644
index 170b5c524a6e3880b2f2cd16c33efed73d7333ad..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/mtd80x.c
+++ /dev/null
@@ -1,1022 +0,0 @@
-/**************************************************************************
-*
-*    mtd80x.c: Etherboot device driver for the mtd80x Ethernet chip.
-*    Written 2004-2004 by Erdem Güven <zuencap@yahoo.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:
-*               fealnx.c: A Linux device driver for the mtd80x Ethernet chip
-*               Written 1998-2000 by Donald Becker
-*
-***************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/* to get some global routines like printf */
-#include "etherboot.h"
-/* to get the interface to the body of the program */
-#include "nic.h"
-/* to get the PCI support functions, if this is a PCI NIC */
-#include <ipxe/pci.h>
-#include <ipxe/ethernet.h>
-#include <mii.h>
-
-/* 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 get_unaligned(ptr) (*(ptr))
-
-
-/* Operational parameters that are set at compile time. */
-
-/* Keep the ring sizes a power of two for compile efficiency.           */
-/* The compiler will convert <unsigned>'%'<2^N> into a bit mask.        */
-/* Making the Tx ring too large decreases the effectiveness of channel  */
-/* bonding and packet priority.                                         */
-/* There are no ill effects from too-large receive rings.               */
-#define TX_RING_SIZE 2
-#define TX_QUEUE_LEN 10 /* Limit ring entries actually used.  */
-#define RX_RING_SIZE 4
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define HZ 100
-#define TX_TIME_OUT   (6*HZ)
-
-/* Allocation size of Rx buffers with normal sized Ethernet frames.
-   Do not change this value without good reason.  This is not a limit,
-   but a way to keep a consistent allocation size among drivers.
- */
-#define PKT_BUF_SZ 1536
-
-/* for different PHY */
-enum phy_type_flags {
-    MysonPHY = 1,
-    AhdocPHY = 2,
-    SeeqPHY = 3,
-    MarvellPHY = 4,
-    Myson981 = 5,
-    LevelOnePHY = 6,
-    OtherPHY = 10,
-};
-
-/* A chip capabilities table*/
-enum chip_capability_flags {
-    HAS_MII_XCVR,
-    HAS_CHIP_XCVR,
-};
-
-#if 0 /* not used */
-static
-struct chip_info
-{
-    u16 dev_id;
-    int flag;
-}
-mtd80x_chips[] = {
-                     {0x0800, HAS_MII_XCVR},
-                     {0x0803, HAS_CHIP_XCVR},
-                     {0x0891, HAS_MII_XCVR}
-                 };
-static int chip_cnt = sizeof( mtd80x_chips ) / sizeof( struct chip_info );
-#endif
-
-/* Offsets to the Command and Status Registers. */
-enum mtd_offsets {
-    PAR0 = 0x0,        /* physical address 0-3 */
-    PAR1 = 0x04,        /* physical address 4-5 */
-    MAR0 = 0x08,        /* multicast address 0-3 */
-    MAR1 = 0x0C,        /* multicast address 4-7 */
-    FAR0 = 0x10,        /* flow-control address 0-3 */
-    FAR1 = 0x14,        /* flow-control address 4-5 */
-    TCRRCR = 0x18,        /* receive & transmit configuration */
-    BCR = 0x1C,        /* bus command */
-    TXPDR = 0x20,        /* transmit polling demand */
-    RXPDR = 0x24,        /* receive polling demand */
-    RXCWP = 0x28,        /* receive current word pointer */
-    TXLBA = 0x2C,        /* transmit list base address */
-    RXLBA = 0x30,        /* receive list base address */
-    ISR = 0x34,        /* interrupt status */
-    IMR = 0x38,        /* interrupt mask */
-    FTH = 0x3C,        /* flow control high/low threshold */
-    MANAGEMENT = 0x40,    /* bootrom/eeprom and mii management */
-    TALLY = 0x44,        /* tally counters for crc and mpa */
-    TSR = 0x48,        /* tally counter for transmit status */
-    BMCRSR = 0x4c,        /* basic mode control and status */
-    PHYIDENTIFIER = 0x50,    /* phy identifier */
-    ANARANLPAR = 0x54,    /* auto-negotiation advertisement and link
-                                                       partner ability */
-    ANEROCR = 0x58,        /* auto-negotiation expansion and pci conf. */
-    BPREMRPSR = 0x5c,    /* bypass & receive error mask and phy status */
-};
-
-/* Bits in the interrupt status/enable registers. */
-/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
-enum intr_status_bits {
-    RFCON = 0x00020000, /* receive flow control xon packet */
-    RFCOFF = 0x00010000, /* receive flow control xoff packet */
-    LSCStatus = 0x00008000, /* link status change */
-    ANCStatus = 0x00004000, /* autonegotiation completed */
-    FBE = 0x00002000, /* fatal bus error */
-    FBEMask = 0x00001800, /* mask bit12-11 */
-    ParityErr = 0x00000000, /* parity error */
-    TargetErr = 0x00001000, /* target abort */
-    MasterErr = 0x00000800, /* master error */
-    TUNF = 0x00000400, /* transmit underflow */
-    ROVF = 0x00000200, /* receive overflow */
-    ETI = 0x00000100, /* transmit early int */
-    ERI = 0x00000080, /* receive early int */
-    CNTOVF = 0x00000040, /* counter overflow */
-    RBU = 0x00000020, /* receive buffer unavailable */
-    TBU = 0x00000010, /* transmit buffer unavilable */
-    TI = 0x00000008, /* transmit interrupt */
-    RI = 0x00000004, /* receive interrupt */
-    RxErr = 0x00000002, /* receive error */
-};
-
-/* Bits in the NetworkConfig register. */
-enum rx_mode_bits {
-    RxModeMask   = 0xe0,
-    AcceptAllPhys = 0x80,        /* promiscuous mode */
-    AcceptBroadcast = 0x40,        /* accept broadcast */
-    AcceptMulticast = 0x20,        /* accept mutlicast */
-    AcceptRunt   = 0x08,        /* receive runt pkt */
-    ALP          = 0x04,        /* receive long pkt */
-    AcceptErr    = 0x02,        /* receive error pkt */
-
-    AcceptMyPhys = 0x00000000,
-    RxEnable     = 0x00000001,
-    RxFlowCtrl   = 0x00002000,
-    TxEnable     = 0x00040000,
-    TxModeFDX    = 0x00100000,
-    TxThreshold  = 0x00e00000,
-
-    PS1000       = 0x00010000,
-    PS10         = 0x00080000,
-    FD           = 0x00100000,
-};
-
-/* Bits in network_desc.status */
-enum rx_desc_status_bits {
-    RXOWN = 0x80000000, /* own bit */
-    FLNGMASK = 0x0fff0000, /* frame length */
-    FLNGShift = 16,
-    MARSTATUS = 0x00004000, /* multicast address received */
-    BARSTATUS = 0x00002000, /* broadcast address received */
-    PHYSTATUS = 0x00001000, /* physical address received */
-    RXFSD = 0x00000800, /* first descriptor */
-    RXLSD = 0x00000400, /* last descriptor */
-    ErrorSummary = 0x80, /* error summary */
-    RUNT = 0x40,  /* runt packet received */
-    LONG = 0x20,  /* long packet received */
-    FAE = 0x10,  /* frame align error */
-    CRC = 0x08,  /* crc error */
-    RXER = 0x04,  /* receive error */
-};
-
-enum rx_desc_control_bits {
-    RXIC = 0x00800000, /* interrupt control */
-    RBSShift = 0,
-};
-
-enum tx_desc_status_bits {
-    TXOWN = 0x80000000, /* own bit */
-    JABTO = 0x00004000, /* jabber timeout */
-    CSL = 0x00002000, /* carrier sense lost */
-    LC = 0x00001000, /* late collision */
-    EC = 0x00000800, /* excessive collision */
-    UDF = 0x00000400, /* fifo underflow */
-    DFR = 0x00000200, /* deferred */
-    HF = 0x00000100, /* heartbeat fail */
-    NCRMask = 0x000000ff, /* collision retry count */
-    NCRShift = 0,
-};
-
-enum tx_desc_control_bits {
-    TXIC = 0x80000000, /* interrupt control */
-    ETIControl = 0x40000000, /* early transmit interrupt */
-    TXLD = 0x20000000, /* last descriptor */
-    TXFD = 0x10000000, /* first descriptor */
-    CRCEnable = 0x08000000, /* crc control */
-    PADEnable = 0x04000000, /* padding control */
-    RetryTxLC = 0x02000000, /* retry late collision */
-    PKTSMask = 0x3ff800, /* packet size bit21-11 */
-    PKTSShift = 11,
-    TBSMask = 0x000007ff, /* transmit buffer bit 10-0 */
-    TBSShift = 0,
-};
-
-/* BootROM/EEPROM/MII Management Register */
-#define MASK_MIIR_MII_READ       0x00000000
-#define MASK_MIIR_MII_WRITE      0x00000008
-#define MASK_MIIR_MII_MDO        0x00000004
-#define MASK_MIIR_MII_MDI        0x00000002
-#define MASK_MIIR_MII_MDC        0x00000001
-
-/* ST+OP+PHYAD+REGAD+TA */
-#define OP_READ             0x6000 /* ST:01+OP:10+PHYAD+REGAD+TA:Z0 */
-#define OP_WRITE            0x5002 /* ST:01+OP:01+PHYAD+REGAD+TA:10 */
-
-/* ------------------------------------------------------------------------- */
-/*      Constants for Myson PHY                                              */
-/* ------------------------------------------------------------------------- */
-#define MysonPHYID      0xd0000302
-/* 89-7-27 add, (begin) */
-#define MysonPHYID0     0x0302
-#define StatusRegister  18
-#define SPEED100        0x0400 // bit10
-#define FULLMODE        0x0800 // bit11
-/* 89-7-27 add, (end) */
-
-/* ------------------------------------------------------------------------- */
-/*      Constants for Seeq 80225 PHY                                         */
-/* ------------------------------------------------------------------------- */
-#define SeeqPHYID0      0x0016
-
-#define MIIRegister18   18
-#define SPD_DET_100     0x80
-#define DPLX_DET_FULL   0x40
-
-/* ------------------------------------------------------------------------- */
-/*      Constants for Ahdoc 101 PHY                                          */
-/* ------------------------------------------------------------------------- */
-#define AhdocPHYID0     0x0022
-
-#define DiagnosticReg   18
-#define DPLX_FULL       0x0800
-#define Speed_100       0x0400
-
-/* 89/6/13 add, */
-/* -------------------------------------------------------------------------- */
-/*      Constants                                                             */
-/* -------------------------------------------------------------------------- */
-#define MarvellPHYID0           0x0141
-#define LevelOnePHYID0  0x0013
-
-#define MII1000BaseTControlReg  9
-#define MII1000BaseTStatusReg   10
-#define SpecificReg  17
-
-/* for 1000BaseT Control Register */
-#define PHYAbletoPerform1000FullDuplex  0x0200
-#define PHYAbletoPerform1000HalfDuplex  0x0100
-#define PHY1000AbilityMask              0x300
-
-// for phy specific status register, marvell phy.
-#define SpeedMask       0x0c000
-#define Speed_1000M     0x08000
-#define Speed_100M      0x4000
-#define Speed_10M       0
-#define Full_Duplex     0x2000
-
-// 89/12/29 add, for phy specific status register, levelone phy, (begin)
-#define LXT1000_100M    0x08000
-#define LXT1000_1000M   0x0c000
-#define LXT1000_Full    0x200
-// 89/12/29 add, for phy specific status register, levelone phy, (end)
-
-#if 0
-/* for 3-in-1 case */
-#define PS10            0x00080000
-#define FD              0x00100000
-#define PS1000          0x00010000
-#endif
-
-/* for PHY */
-#define LinkIsUp        0x0004
-#define LinkIsUp2 0x00040000
-
-/* Create a static buffer of size PKT_BUF_SZ for each
-RX and TX Descriptor.  All descriptors point to a
-part of this buffer */
-struct {
-	u8 txb[PKT_BUF_SZ * TX_RING_SIZE] __attribute__ ((aligned(8)));
-	u8 rxb[PKT_BUF_SZ * RX_RING_SIZE] __attribute__ ((aligned(8)));
-} mtd80x_bufs __shared;
-#define txb mtd80x_bufs.txb
-#define rxb mtd80x_bufs.rxb
-
-/* The Tulip Rx and Tx buffer descriptors. */
-struct mtd_desc
-{
-    s32 status;
-    s32 control;
-    u32 buffer;
-    u32 next_desc;
-    struct mtd_desc *next_desc_logical;
-    u8* skbuff;
-    u32 reserved1;
-    u32 reserved2;
-};
-
-struct mtd_private
-{
-    struct mtd_desc rx_ring[RX_RING_SIZE];
-    struct mtd_desc tx_ring[TX_RING_SIZE];
-
-    /* Frequently used values: keep some adjacent for cache effect. */
-    int flags;
-    struct pci_dev *pci_dev;
-    unsigned long crvalue;
-    unsigned long bcrvalue;
-    /*unsigned long imrvalue;*/
-    struct mtd_desc *cur_rx;
-    struct mtd_desc *lack_rxbuf;
-    int really_rx_count;
-    struct mtd_desc *cur_tx;
-    struct mtd_desc *cur_tx_copy;
-    int really_tx_count;
-    int free_tx_count;
-    unsigned int rx_buf_sz; /* Based on MTU+slack. */
-
-    /* These values are keep track of the transceiver/media in use. */
-    unsigned int linkok;
-    unsigned int line_speed;
-    unsigned int duplexmode;
-    unsigned int default_port:
-    4; /* Last dev->if_port value. */
-    unsigned int PHYType;
-
-    /* MII transceiver section. */
-    int mii_cnt;  /* MII device addresses. */
-    unsigned char phys[1]; /* MII device addresses. */
-
-    /*other*/
-    const char *nic_name;
-    int ioaddr;
-    u16 dev_id;
-};
-
-static struct mtd_private mtdx;
-
-static int mdio_read(struct nic * , int phy_id, int location);
-static void getlinktype(struct nic * );
-static void getlinkstatus(struct nic * );
-static void set_rx_mode(struct nic *);
-
-/**************************************************************************
- *  init_ring - setup the tx and rx descriptors
- *************************************************************************/
-static void init_ring(struct nic *nic __unused)
-{
-    int i;
-
-    mtdx.cur_rx = &mtdx.rx_ring[0];
-
-    mtdx.rx_buf_sz = PKT_BUF_SZ;
-    /*mtdx.rx_head_desc = &mtdx.rx_ring[0];*/
-
-    /* Initialize all Rx descriptors. */
-    /* Fill in the Rx buffers.  Handle allocation failure gracefully. */
-    for (i = 0; i < RX_RING_SIZE; i++)
-    {
-        mtdx.rx_ring[i].status = RXOWN;
-        mtdx.rx_ring[i].control = mtdx.rx_buf_sz << RBSShift;
-        mtdx.rx_ring[i].next_desc = virt_to_le32desc(&mtdx.rx_ring[i+1]);
-        mtdx.rx_ring[i].next_desc_logical = &mtdx.rx_ring[i+1];
-        mtdx.rx_ring[i].buffer = virt_to_le32desc(&rxb[i * PKT_BUF_SZ]);
-        mtdx.rx_ring[i].skbuff = &rxb[i * PKT_BUF_SZ];
-    }
-    /* Mark the last entry as wrapping the ring. */
-    mtdx.rx_ring[i-1].next_desc = virt_to_le32desc(&mtdx.rx_ring[0]);
-    mtdx.rx_ring[i-1].next_desc_logical = &mtdx.rx_ring[0];
-
-    /* We only use one transmit buffer, but two
-     * descriptors so transmit engines have somewhere
-     * to point should they feel the need */
-    mtdx.tx_ring[0].status = 0x00000000;
-    mtdx.tx_ring[0].buffer = virt_to_bus(&txb[0]);
-    mtdx.tx_ring[0].next_desc = virt_to_le32desc(&mtdx.tx_ring[1]);
-
-    /* This descriptor is never used */
-    mtdx.tx_ring[1].status = 0x00000000;
-    mtdx.tx_ring[1].buffer = 0; /*virt_to_bus(&txb[1]); */
-    mtdx.tx_ring[1].next_desc = virt_to_le32desc(&mtdx.tx_ring[0]);
-
-    return;
-}
-
-/**************************************************************************
-RESET - Reset Adapter
-***************************************************************************/
-static void mtd_reset( struct nic *nic )
-{
-    /* Reset the chip to erase previous misconfiguration. */
-    outl(0x00000001, mtdx.ioaddr + BCR);
-
-    init_ring(nic);
-
-    outl(virt_to_bus(mtdx.rx_ring), mtdx.ioaddr + RXLBA);
-    outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA);
-
-    /* Initialize other registers. */
-    /* Configure the PCI bus bursts and FIFO thresholds. */
-    mtdx.bcrvalue = 0x10; /* little-endian, 8 burst length */
-    mtdx.crvalue = 0xa00; /* rx 128 burst length */
-
-	if ( mtdx.dev_id == 0x891 ) {
-		mtdx.bcrvalue |= 0x200;	/* set PROG bit */
-		mtdx.crvalue |= 0x02000000;	/* set enhanced bit */
-	}
-
-    outl( mtdx.bcrvalue, mtdx.ioaddr + BCR);
-
-    /* Restart Rx engine if stopped. */
-    outl(0, mtdx.ioaddr + RXPDR);
-
-    getlinkstatus(nic);
-    if (mtdx.linkok)
-    {
-        static const char* texts[]={"half","full","10","100","1000"};
-        getlinktype(nic);
-        DBG ( "Link is OK : %s %s\n", texts[mtdx.duplexmode-1], texts[mtdx.line_speed+1] );
-    } else
-    {
-        DBG ( "No link!!!\n" );
-    }
-
-    mtdx.crvalue |= /*TxEnable |*/ RxEnable | TxThreshold;
-    set_rx_mode(nic);
-
-    /* Clear interrupts by setting the interrupt mask. */
-    outl(FBE | TUNF | CNTOVF | RBU | TI | RI, mtdx.ioaddr + ISR);
-    outl( 0, mtdx.ioaddr + IMR);
-}
-
-/**************************************************************************
-POLL - Wait for a frame
-***************************************************************************/
-static int mtd_poll(struct nic *nic, __unused int retrieve)
-{
-    s32 rx_status = mtdx.cur_rx->status;
-    int retval = 0;
-
-    if( ( rx_status & RXOWN ) != 0 )
-    {
-        return 0;
-    }
-
-    if (rx_status & ErrorSummary)
-    { /* there was a fatal error */
-        printf( "%s: Receive error, Rx status %8.8x, Error(s) %s%s%s\n",
-                mtdx.nic_name, (unsigned int) rx_status,
-                (rx_status & (LONG | RUNT)) ? "length_error ":"",
-                (rx_status & RXER) ? "frame_error ":"",
-                (rx_status & CRC) ? "crc_error ":"" );
-        retval = 0;
-    } else if( !((rx_status & RXFSD) && (rx_status & RXLSD)) )
-    {
-        /* this pkt is too long, over one rx buffer */
-        printf("Pkt is too long, over one rx buffer.\n");
-        retval = 0;
-    } else
-    { /* this received pkt is ok */
-        /* Omit the four octet CRC from the length. */
-        short pkt_len = ((rx_status & FLNGMASK) >> FLNGShift) - 4;
-
-        DBG ( " netdev_rx() normal Rx pkt length %d"
- 	      " status %x.\n", pkt_len, (unsigned int) rx_status );
-
-        nic->packetlen = pkt_len;
-        memcpy(nic->packet, mtdx.cur_rx->skbuff, pkt_len);
-
-        retval = 1;
-    }
-
-    while( ( mtdx.cur_rx->status & RXOWN ) == 0 )
-    {
-        mtdx.cur_rx->status = RXOWN;
-        mtdx.cur_rx = mtdx.cur_rx->next_desc_logical;
-    }
-
-    /* Restart Rx engine if stopped. */
-    outl(0, mtdx.ioaddr + RXPDR);
-
-    return retval;
-}
-
-/**************************************************************************
-TRANSMIT - Transmit a frame
-***************************************************************************/
-static void mtd_transmit(
-    struct nic *nic,
-    const char *dest,            /* Destination */
-    unsigned int type,            /* Type */
-    unsigned int size,            /* size */
-    const char *data)            /* Packet */
-{
-    u32 to;
-    u32 tx_status;
-    unsigned int nstype = htons ( type );
-
-    memcpy( txb, dest, ETH_ALEN );
-    memcpy( txb + ETH_ALEN, nic->node_addr, ETH_ALEN );
-    memcpy( txb + 2 * ETH_ALEN, &nstype, 2 );
-    memcpy( txb + ETH_HLEN, data, size );
-
-    size += ETH_HLEN;
-    size &= 0x0FFF;
-    while( size < ETH_ZLEN )
-    {
-        txb[size++] = '\0';
-    }
-
-    mtdx.tx_ring[0].control = TXLD | TXFD | CRCEnable | PADEnable;
-    mtdx.tx_ring[0].control |= (size << PKTSShift); /* pkt size */
-    mtdx.tx_ring[0].control |= (size << TBSShift); /* buffer size */
-    mtdx.tx_ring[0].status = TXOWN;
-
-    /* Point to transmit descriptor */
-    outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA);
-    /* Enable Tx */
-    outl( mtdx.crvalue | TxEnable, mtdx.ioaddr + TCRRCR);
-    /* Wake the potentially-idle transmit channel. */
-    outl(0, mtdx.ioaddr + TXPDR);
-
-    to = currticks() + TX_TIME_OUT;
-    while(( mtdx.tx_ring[0].status & TXOWN) && (currticks() < to));
-
-    /* Disable Tx */
-    outl( mtdx.crvalue & (~TxEnable), mtdx.ioaddr + TCRRCR);
-
-    tx_status = mtdx.tx_ring[0].status;
-    if (currticks() >= to){
-        DBG ( "TX Time Out" );
-    } else if( tx_status & (CSL | LC | EC | UDF | HF)){
-        printf( "Transmit error: %8.8x %s %s %s %s %s\n",
-                (unsigned int) tx_status,
-                tx_status & EC ? "abort" : "",
-                tx_status & CSL ? "carrier" : "",
-                tx_status & LC ? "late" : "",
-                tx_status & UDF ? "fifo" : "",
-                tx_status & HF ? "heartbeat" : "" );
-    }
-
-    /*hex_dump( txb, size );*/
-    /*pause();*/
-
-    DBG ( "TRANSMIT\n" );
-}
-
-/**************************************************************************
-DISABLE - Turn off ethernet interface
-***************************************************************************/
-static void mtd_disable ( struct nic *nic ) {
-
-    /* Disable Tx Rx*/
-    outl( mtdx.crvalue & (~TxEnable) & (~RxEnable), mtdx.ioaddr + TCRRCR );
-
-    /* Reset the chip to erase previous misconfiguration. */
-    mtd_reset(nic);
-
-    DBG ( "DISABLE\n" );
-}
-
-static struct nic_operations mtd_operations = {
-	.connect	= dummy_connect,
-	.poll		= mtd_poll,
-	.transmit	= mtd_transmit,
-	.irq		= dummy_irq,
-
-};
-
-static struct pci_device_id mtd80x_nics[] = {
-        PCI_ROM(0x1516, 0x0800, "MTD800", "Myson MTD800", 0),
-        PCI_ROM(0x1516, 0x0803, "MTD803", "Surecom EP-320X", 0),
-        PCI_ROM(0x1516, 0x0891, "MTD891", "Myson MTD891", 0),
-};
-
-PCI_DRIVER ( mtd80x_driver, mtd80x_nics, PCI_NO_CLASS );
-
-/**************************************************************************
-PROBE - Look for an adapter, this routine's visible to the outside
-***************************************************************************/
-
-static int mtd_probe ( struct nic *nic, struct pci_device *pci ) {
-
-    int i;
-
-    if (pci->ioaddr == 0)
-	    return 0;
-
-    adjust_pci_device(pci);
-
-    nic->ioaddr = pci->ioaddr;
-    nic->irqno = 0;
-
-    mtdx.nic_name = pci->id->name;
-    mtdx.dev_id = pci->device;
-    mtdx.ioaddr = nic->ioaddr;
-
-    /* read ethernet id */
-    for (i = 0; i < 6; ++i)
-    {
-        nic->node_addr[i] = inb(mtdx.ioaddr + PAR0 + i);
-    }
-
-    if (memcmp(nic->node_addr, "\0\0\0\0\0\0", 6) == 0)
-    {
-        return 0;
-    }
-
-    DBG ( "%s: ioaddr %4.4x MAC %s\n", mtdx.nic_name, mtdx.ioaddr, eth_ntoa ( nic->node_addr ) );
-
-    /* Reset the chip to erase previous misconfiguration. */
-    outl(0x00000001, mtdx.ioaddr + BCR);
-
-    /* find the connected MII xcvrs */
-
-    if( mtdx.dev_id != 0x803 )
-    {
-        int phy, phy_idx = 0;
-
-        for (phy = 1; phy < 32 && phy_idx < 1; phy++) {
-            int mii_status = mdio_read(nic, phy, 1);
-
-            if (mii_status != 0xffff && mii_status != 0x0000) {
-                mtdx.phys[phy_idx] = phy;
-
-                DBG ( "%s: MII PHY found at address %d, status "
-		      "0x%4.4x.\n", mtdx.nic_name, phy, mii_status );
-                /* get phy type */
-                {
-                    unsigned int data;
-
-                    data = mdio_read(nic, mtdx.phys[phy_idx], 2);
-                    if (data == SeeqPHYID0)
-                        mtdx.PHYType = SeeqPHY;
-                    else if (data == AhdocPHYID0)
-                        mtdx.PHYType = AhdocPHY;
-                    else if (data == MarvellPHYID0)
-                        mtdx.PHYType = MarvellPHY;
-                    else if (data == MysonPHYID0)
-                        mtdx.PHYType = Myson981;
-                    else if (data == LevelOnePHYID0)
-                        mtdx.PHYType = LevelOnePHY;
-                    else
-                        mtdx.PHYType = OtherPHY;
-                }
-                phy_idx++;
-            }
-        }
-
-        mtdx.mii_cnt = phy_idx;
-        if (phy_idx == 0) {
-            printf("%s: MII PHY not found -- this device may "
-                   "not operate correctly.\n", mtdx.nic_name);
-        }
-    } else {
-        mtdx.phys[0] = 32;
-        /* get phy type */
-        if (inl(mtdx.ioaddr + PHYIDENTIFIER) == MysonPHYID ) {
-            mtdx.PHYType = MysonPHY;
-            DBG ( "MysonPHY\n" );
-        } else {
-            mtdx.PHYType = OtherPHY;
-            DBG ( "OtherPHY\n" );
-        }
-    }
-
-    getlinkstatus(nic);
-    if( !mtdx.linkok )
-    {
-        printf("No link!!!\n");
-        return 0;
-    }
-
-    mtd_reset( nic );
-
-    /* point to NIC specific routines */
-    nic->nic_op	= &mtd_operations;
-    return 1;
-}
-
-
-/**************************************************************************/
-static void set_rx_mode(struct nic *nic __unused)
-{
-    u32 mc_filter[2];                       /* Multicast hash filter */
-    u32 rx_mode;
-
-    /* Too many to match, or accept all multicasts. */
-    mc_filter[1] = mc_filter[0] = ~0;
-    rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-
-    outl(mc_filter[0], mtdx.ioaddr + MAR0);
-    outl(mc_filter[1], mtdx.ioaddr + MAR1);
-
-    mtdx.crvalue = ( mtdx.crvalue & ~RxModeMask ) | rx_mode;
-    outb( mtdx.crvalue, mtdx.ioaddr + TCRRCR);
-}
-/**************************************************************************/
-static unsigned int m80x_read_tick(void)
-/* function: Reads the Timer tick count register which decrements by 2 from  */
-/*           65536 to 0 every 1/36.414 of a second. Each 2 decrements of the */
-/*           count represents 838 nsec's.                                    */
-/* input   : none.                                                           */
-/* output  : none.                                                           */
-{
-    unsigned char tmp;
-    int value;
-
-    outb((char) 0x06, 0x43); // Command 8254 to latch T0's count
-
-    // now read the count.
-    tmp = (unsigned char) inb(0x40);
-    value = ((int) tmp) << 8;
-    tmp = (unsigned char) inb(0x40);
-    value |= (((int) tmp) & 0xff);
-    return (value);
-}
-
-static void m80x_delay(unsigned int interval)
-/* function: to wait for a specified time.                                   */
-/* input   : interval ... the specified time.                                */
-/* output  : none.                                                           */
-{
-    unsigned int interval1, interval2, i = 0;
-
-    interval1 = m80x_read_tick(); // get initial value
-    do
-    {
-        interval2 = m80x_read_tick();
-        if (interval1 < interval2)
-            interval1 += 65536;
-        ++i;
-    } while (((interval1 - interval2) < (u16) interval) && (i < 65535));
-}
-
-
-static u32 m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad)
-{
-    u32 miir;
-    int i;
-    unsigned int mask, data;
-
-    /* enable MII output */
-    miir = (u32) inl(miiport);
-    miir &= 0xfffffff0;
-
-    miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO;
-
-    /* send 32 1's preamble */
-    for (i = 0; i < 32; i++) {
-        /* low MDC; MDO is already high (miir) */
-        miir &= ~MASK_MIIR_MII_MDC;
-        outl(miir, miiport);
-
-        /* high MDC */
-        miir |= MASK_MIIR_MII_MDC;
-        outl(miir, miiport);
-    }
-
-    /* calculate ST+OP+PHYAD+REGAD+TA */
-    data = opcode | (phyad << 7) | (regad << 2);
-
-    /* sent out */
-    mask = 0x8000;
-    while (mask) {
-        /* low MDC, prepare MDO */
-        miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO);
-        if (mask & data)
-            miir |= MASK_MIIR_MII_MDO;
-
-        outl(miir, miiport);
-        /* high MDC */
-        miir |= MASK_MIIR_MII_MDC;
-        outl(miir, miiport);
-        m80x_delay(30);
-
-        /* next */
-        mask >>= 1;
-        if (mask == 0x2 && opcode == OP_READ)
-            miir &= ~MASK_MIIR_MII_WRITE;
-    }
-    return miir;
-}
-
-static int mdio_read(struct nic *nic __unused, int phyad, int regad)
-{
-    long miiport = mtdx.ioaddr + MANAGEMENT;
-    u32 miir;
-    unsigned int mask, data;
-
-    miir = m80x_send_cmd_to_phy(miiport, OP_READ, phyad, regad);
-
-    /* read data */
-    mask = 0x8000;
-    data = 0;
-    while (mask)
-    {
-        /* low MDC */
-        miir &= ~MASK_MIIR_MII_MDC;
-        outl(miir, miiport);
-
-        /* read MDI */
-        miir = inl(miiport);
-        if (miir & MASK_MIIR_MII_MDI)
-            data |= mask;
-
-        /* high MDC, and wait */
-        miir |= MASK_MIIR_MII_MDC;
-        outl(miir, miiport);
-        m80x_delay((int) 30);
-
-        /* next */
-        mask >>= 1;
-    }
-
-    /* low MDC */
-    miir &= ~MASK_MIIR_MII_MDC;
-    outl(miir, miiport);
-
-    return data & 0xffff;
-}
-
-#if 0 /* not used */
-static void mdio_write(struct nic *nic __unused, int phyad, int regad,
-		       int data)
-{
-    long miiport = mtdx.ioaddr + MANAGEMENT;
-    u32 miir;
-    unsigned int mask;
-
-    miir = m80x_send_cmd_to_phy(miiport, OP_WRITE, phyad, regad);
-
-    /* write data */
-    mask = 0x8000;
-    while (mask)
-    {
-        /* low MDC, prepare MDO */
-        miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO);
-        if (mask & data)
-            miir |= MASK_MIIR_MII_MDO;
-        outl(miir, miiport);
-
-        /* high MDC */
-        miir |= MASK_MIIR_MII_MDC;
-        outl(miir, miiport);
-
-        /* next */
-        mask >>= 1;
-    }
-
-    /* low MDC */
-    miir &= ~MASK_MIIR_MII_MDC;
-    outl(miir, miiport);
-
-    return;
-}
-#endif
-
-static void getlinkstatus(struct nic *nic)
-/* function: Routine will read MII Status Register to get link status.       */
-/* input   : dev... pointer to the adapter block.                            */
-/* output  : none.                                                           */
-{
-    unsigned int i, DelayTime = 0x1000;
-
-    mtdx.linkok = 0;
-
-    if (mtdx.PHYType == MysonPHY)
-    {
-        for (i = 0; i < DelayTime; ++i) {
-            if (inl(mtdx.ioaddr + BMCRSR) & LinkIsUp2) {
-                mtdx.linkok = 1;
-                return;
-            }
-            // delay
-            m80x_delay(100);
-        }
-    } else
-    {
-        for (i = 0; i < DelayTime; ++i) {
-            if (mdio_read(nic, mtdx.phys[0], MII_BMSR) & BMSR_LSTATUS) {
-                mtdx.linkok = 1;
-                return;
-            }
-            // delay
-            m80x_delay(100);
-        }
-    }
-}
-
-
-static void getlinktype(struct nic *dev)
-{
-    if (mtdx.PHYType == MysonPHY)
-    { /* 3-in-1 case */
-        if (inl(mtdx.ioaddr + TCRRCR) & FD)
-            mtdx.duplexmode = 2; /* full duplex */
-        else
-            mtdx.duplexmode = 1; /* half duplex */
-        if (inl(mtdx.ioaddr + TCRRCR) & PS10)
-            mtdx.line_speed = 1; /* 10M */
-        else
-            mtdx.line_speed = 2; /* 100M */
-    } else
-    {
-        if (mtdx.PHYType == SeeqPHY) { /* this PHY is SEEQ 80225 */
-            unsigned int data;
-
-            data = mdio_read(dev, mtdx.phys[0], MIIRegister18);
-            if (data & SPD_DET_100)
-                mtdx.line_speed = 2; /* 100M */
-            else
-                mtdx.line_speed = 1; /* 10M */
-            if (data & DPLX_DET_FULL)
-                mtdx.duplexmode = 2; /* full duplex mode */
-            else
-                mtdx.duplexmode = 1; /* half duplex mode */
-        } else if (mtdx.PHYType == AhdocPHY) {
-            unsigned int data;
-
-            data = mdio_read(dev, mtdx.phys[0], DiagnosticReg);
-            if (data & Speed_100)
-                mtdx.line_speed = 2; /* 100M */
-            else
-                mtdx.line_speed = 1; /* 10M */
-            if (data & DPLX_FULL)
-                mtdx.duplexmode = 2; /* full duplex mode */
-            else
-                mtdx.duplexmode = 1; /* half duplex mode */
-        }
-        /* 89/6/13 add, (begin) */
-        else if (mtdx.PHYType == MarvellPHY) {
-            unsigned int data;
-
-            data = mdio_read(dev, mtdx.phys[0], SpecificReg);
-            if (data & Full_Duplex)
-                mtdx.duplexmode = 2; /* full duplex mode */
-            else
-                mtdx.duplexmode = 1; /* half duplex mode */
-            data &= SpeedMask;
-            if (data == Speed_1000M)
-                mtdx.line_speed = 3; /* 1000M */
-            else if (data == Speed_100M)
-                mtdx.line_speed = 2; /* 100M */
-            else
-                mtdx.line_speed = 1; /* 10M */
-        }
-        /* 89/6/13 add, (end) */
-        /* 89/7/27 add, (begin) */
-        else if (mtdx.PHYType == Myson981) {
-            unsigned int data;
-
-            data = mdio_read(dev, mtdx.phys[0], StatusRegister);
-
-            if (data & SPEED100)
-                mtdx.line_speed = 2;
-            else
-                mtdx.line_speed = 1;
-
-            if (data & FULLMODE)
-                mtdx.duplexmode = 2;
-            else
-                mtdx.duplexmode = 1;
-        }
-        /* 89/7/27 add, (end) */
-        /* 89/12/29 add */
-        else if (mtdx.PHYType == LevelOnePHY) {
-            unsigned int data;
-
-            data = mdio_read(dev, mtdx.phys[0], SpecificReg);
-            if (data & LXT1000_Full)
-                mtdx.duplexmode = 2; /* full duplex mode */
-            else
-                mtdx.duplexmode = 1; /* half duplex mode */
-            data &= SpeedMask;
-            if (data == LXT1000_1000M)
-                mtdx.line_speed = 3; /* 1000M */
-            else if (data == LXT1000_100M)
-                mtdx.line_speed = 2; /* 100M */
-            else
-                mtdx.line_speed = 1; /* 10M */
-        }
-        // chage crvalue
-        // mtdx.crvalue&=(~PS10)&(~FD);
-        mtdx.crvalue &= (~PS10) & (~FD) & (~PS1000);
-        if (mtdx.line_speed == 1)
-            mtdx.crvalue |= PS10;
-        else if (mtdx.line_speed == 3)
-            mtdx.crvalue |= PS1000;
-        if (mtdx.duplexmode == 2)
-            mtdx.crvalue |= FD;
-    }
-}
-
-DRIVER ( "MTD80X", nic_driver, pci_driver, mtd80x_driver,
-	 mtd_probe, mtd_disable );
diff --git a/roms/ipxe/src/drivers/net/myri10ge.c b/roms/ipxe/src/drivers/net/myri10ge.c
index 5bb555d8216fd6345a125cf0f000..ae6b6c21e2245e1de3f87a685fe3 100644
--- a/roms/ipxe/src/drivers/net/myri10ge.c
+++ b/roms/ipxe/src/drivers/net/myri10ge.c
@@ -13,7 +13,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  ****************************************************************/
 
 FILE_LICENCE ( GPL2_ONLY );
@@ -304,10 +305,10 @@ static int myri10ge_command ( struct myri10ge_private *priv,
 	command->response_addr.high = 0;
 	command->response_addr.low
 		= htonl ( virt_to_bus ( &priv->dma->command_response ) );
-	for ( i=0; i<36; i+=4 )
-		* ( uint32 * ) &command->pad[i] = 0;
+	for ( i=0; i<9; i++ )
+		command->pad[i] = 0;
 	wmb();
-	* ( uint32 * ) &command->pad[36] = 0;
+	command->pad[9] = 0;
 
 	/* Wait up to 2 seconds for a response. */
 
@@ -718,7 +719,7 @@ static int myri10ge_nv_init ( struct myri10ge_private *priv )
 		return 0;
 	}
 
-	/* Initilize NonVolatile Storage state. */
+	/* Initialize NonVolatile Storage state. */
 
 	priv->nvs.word_len_log2 = 0;
 	priv->nvs.size		= hdr.eeprom_len;
diff --git a/roms/ipxe/src/drivers/net/myri10ge_mcp.h b/roms/ipxe/src/drivers/net/myri10ge_mcp.h
index 397f8b0ddfd13e19606687061075..6c82b3c76c226d164dcbf27fa5d7 100644
--- a/roms/ipxe/src/drivers/net/myri10ge_mcp.h
+++ b/roms/ipxe/src/drivers/net/myri10ge_mcp.h
@@ -13,7 +13,8 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  ****************************************************************/
 
 FILE_LICENCE ( GPL2_ONLY );
@@ -80,7 +81,7 @@ struct mcp_cmd {
   /* 16 */
   struct mcp_dma_addr response_addr;
   /* 24 */
-  uint8_t pad[40];
+  uint32_t pad[10];
 };
 typedef struct mcp_cmd mcp_cmd_t;
 
diff --git a/roms/ipxe/src/drivers/net/myson.c b/roms/ipxe/src/drivers/net/myson.c
new file mode 100644
index 0000000000000000000000000000000000000000..237f8721056158e6661bd5b1704dad69b9eb8f8d
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/myson.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+#include <ipxe/mii.h>
+#include "myson.h"
+
+/** @file
+ *
+ * Myson Technology network card driver
+ *
+ */
+
+/******************************************************************************
+ *
+ * Device reset
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Reset controller chip
+ *
+ * @v myson		Myson device
+ * @ret rc		Return status code
+ */
+static int myson_soft_reset ( struct myson_nic *myson ) {
+	uint32_t bcr;
+	unsigned int i;
+
+	/* Initiate reset */
+	bcr = readl ( myson->regs + MYSON_BCR );
+	writel ( ( bcr | MYSON_BCR_SWR ), myson->regs + MYSON_BCR );
+
+	/* Wait for reset to complete */
+	for ( i = 0 ; i < MYSON_RESET_MAX_WAIT_MS ; i++ ) {
+
+		/* If reset is not complete, delay 1ms and retry */
+		if ( readl ( myson->regs + MYSON_BCR ) & MYSON_BCR_SWR ) {
+			mdelay ( 1 );
+			continue;
+		}
+
+		/* Apply a sensible default bus configuration */
+		bcr = readl ( myson->regs + MYSON_BCR );
+		bcr &= ~MYSON_BCR_PBL_MASK;
+		bcr |= ( MYSON_BCR_RLE | MYSON_BCR_RME | MYSON_BCR_WIE |
+			 MYSON_BCR_PBL_DEFAULT );
+		writel ( bcr, myson->regs + MYSON_BCR );
+		DBGC ( myson, "MYSON %p using configuration %08x\n",
+		       myson, bcr );
+
+		return 0;
+	}
+
+	DBGC ( myson, "MYSON %p timed out waiting for reset\n", myson );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Reload configuration from EEPROM
+ *
+ * @v myson		Myson device
+ * @ret rc		Return status code
+ */
+static int myson_reload_config ( struct myson_nic *myson ) {
+	unsigned int i;
+
+	/* Initiate reload */
+	writel ( MYSON_ROM_AUTOLD, myson->regs + MYSON_ROM_MII );
+
+	/* Wait for reload to complete */
+	for ( i = 0 ; i < MYSON_AUTOLD_MAX_WAIT_MS ; i++ ) {
+
+		/* If reload is not complete, delay 1ms and retry */
+		if ( readl ( myson->regs + MYSON_ROM_MII ) & MYSON_ROM_AUTOLD ){
+			mdelay ( 1 );
+			continue;
+		}
+
+		return 0;
+	}
+
+	DBGC ( myson, "MYSON %p timed out waiting for configuration "
+	       "reload\n", myson );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Reset hardware
+ *
+ * @v myson		Myson device
+ * @ret rc		Return status code
+ */
+static int myson_reset ( struct myson_nic *myson ) {
+	int rc;
+
+	/* Disable all interrupts */
+	writel ( 0, myson->regs + MYSON_IMR );
+
+	/* Perform soft reset */
+	if ( ( rc = myson_soft_reset ( myson ) ) != 0 )
+		return rc;
+
+	/* Reload configuration from EEPROM */
+	if ( ( rc = myson_reload_config ( myson ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ * Network device interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Create descriptor ring
+ *
+ * @v myson		Myson device
+ * @v ring		Descriptor ring
+ * @ret rc		Return status code
+ */
+static int myson_create_ring ( struct myson_nic *myson,
+			       struct myson_ring *ring ) {
+	size_t len = ( ring->count * sizeof ( ring->desc[0] ) );
+	struct myson_descriptor *desc;
+	struct myson_descriptor *next;
+	physaddr_t address;
+	unsigned int i;
+	int rc;
+
+	/* Allocate descriptor ring */
+	ring->desc = malloc_dma ( len, MYSON_RING_ALIGN );
+	if ( ! ring->desc ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	address = virt_to_bus ( ring->desc );
+
+	/* Check address is usable by card */
+	if ( ! myson_address_ok ( address + len ) ) {
+		DBGC ( myson, "MYSON %p cannot support 64-bit ring address\n",
+		       myson );
+		rc = -ENOTSUP;
+		goto err_64bit;
+	}
+
+	/* Initialise descriptor ring */
+	memset ( ring->desc, 0, len );
+	for ( i = 0 ; i < ring->count ; i++ ) {
+		desc = &ring->desc[i];
+		next = &ring->desc[ ( i + 1 ) % ring->count ];
+		desc->next = cpu_to_le32 ( virt_to_bus ( next ) );
+	}
+
+	/* Program ring address */
+	writel ( address, myson->regs + ring->reg );
+	DBGC ( myson, "MYSON %p ring %02x is at [%08llx,%08llx)\n",
+	       myson, ring->reg, ( ( unsigned long long ) address ),
+	       ( ( unsigned long long ) address + len ) );
+
+	return 0;
+
+ err_64bit:
+	free_dma ( ring->desc, len );
+	ring->desc = NULL;
+ err_alloc:
+	return rc;
+}
+
+/**
+ * Destroy descriptor ring
+ *
+ * @v myson		Myson device
+ * @v ring		Descriptor ring
+ */
+static void myson_destroy_ring ( struct myson_nic *myson,
+				 struct myson_ring *ring ) {
+	size_t len = ( ring->count * sizeof ( ring->desc[0] ) );
+
+	/* Clear ring address */
+	writel ( 0, myson->regs + ring->reg );
+
+	/* Free descriptor ring */
+	free_dma ( ring->desc, len );
+	ring->desc = NULL;
+	ring->prod = 0;
+	ring->cons = 0;
+}
+
+/**
+ * Refill receive descriptor ring
+ *
+ * @v netdev		Network device
+ */
+static void myson_refill_rx ( struct net_device *netdev ) {
+	struct myson_nic *myson = netdev->priv;
+	struct myson_descriptor *rx;
+	struct io_buffer *iobuf;
+	unsigned int rx_idx;
+	physaddr_t address;
+
+	while ( ( myson->rx.prod - myson->rx.cons ) < MYSON_NUM_RX_DESC ) {
+
+		/* Allocate I/O buffer */
+		iobuf = alloc_iob ( MYSON_RX_MAX_LEN );
+		if ( ! iobuf ) {
+			/* Wait for next refill */
+			return;
+		}
+
+		/* Check address is usable by card */
+		address = virt_to_bus ( iobuf->data );
+		if ( ! myson_address_ok ( address ) ) {
+			DBGC ( myson, "MYSON %p cannot support 64-bit RX "
+			       "buffer address\n", myson );
+			netdev_rx_err ( netdev, iobuf, -ENOTSUP );
+			return;
+		}
+
+		/* Get next receive descriptor */
+		rx_idx = ( myson->rx.prod++ % MYSON_NUM_RX_DESC );
+		rx = &myson->rx.desc[rx_idx];
+
+		/* Populate receive descriptor */
+		rx->address = cpu_to_le32 ( address );
+		rx->control =
+			cpu_to_le32 ( MYSON_RX_CTRL_RBS ( MYSON_RX_MAX_LEN ) );
+		wmb();
+		rx->status = cpu_to_le32 ( MYSON_RX_STAT_OWN );
+		wmb();
+
+		/* Record I/O buffer */
+		assert ( myson->rx_iobuf[rx_idx] == NULL );
+		myson->rx_iobuf[rx_idx] = iobuf;
+
+		/* Notify card that there are descriptors available */
+		writel ( 0, myson->regs + MYSON_RXPDR );
+
+		DBGC2 ( myson, "MYSON %p RX %d is [%llx,%llx)\n", myson,
+			rx_idx, ( ( unsigned long long ) address ),
+			( ( unsigned long long ) address + MYSON_RX_MAX_LEN ) );
+	}
+}
+
+/**
+ * Open network device
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int myson_open ( struct net_device *netdev ) {
+	struct myson_nic *myson = netdev->priv;
+	union myson_physical_address mac;
+	int rc;
+
+	/* Set MAC address */
+	memset ( &mac, 0, sizeof ( mac ) );
+	memcpy ( mac.raw, netdev->ll_addr, ETH_ALEN );
+	writel ( le32_to_cpu ( mac.reg.low ), myson->regs + MYSON_PAR0 );
+	writel ( le32_to_cpu ( mac.reg.high ), myson->regs + MYSON_PAR4 );
+
+	/* Create transmit descriptor ring */
+	if ( ( rc = myson_create_ring ( myson, &myson->tx ) ) != 0 )
+		goto err_create_tx;
+
+	/* Create receive descriptor ring */
+	if ( ( rc = myson_create_ring ( myson, &myson->rx ) ) != 0 )
+		goto err_create_rx;
+
+	/* Configure transmitter and receiver */
+	writel ( ( MYSON_TCR_TE | MYSON_RCR_PROM | MYSON_RCR_AB | MYSON_RCR_AM |
+		   MYSON_RCR_ARP | MYSON_RCR_ALP | MYSON_RCR_RE ),
+		 myson->regs + MYSON_TCR_RCR );
+
+	/* Fill receive ring */
+	myson_refill_rx ( netdev );
+
+	return 0;
+
+	myson_destroy_ring ( myson, &myson->rx );
+ err_create_rx:
+	myson_destroy_ring ( myson, &myson->tx );
+ err_create_tx:
+	return rc;
+}
+
+/**
+ * Wait for transmit and receive to become idle
+ *
+ * @v myson		Myson device
+ * @ret rc		Return status code
+ */
+static int myson_wait_idle ( struct myson_nic *myson ) {
+	uint32_t tcr_rcr;
+	unsigned int i;
+
+	/* Wait for both transmit and receive to be idle */
+	for ( i = 0 ; i < MYSON_IDLE_MAX_WAIT_MS ; i++ ) {
+
+		/* If either process is running, delay 1ms and retry */
+		tcr_rcr = readl ( myson->regs + MYSON_TCR_RCR );
+		if ( tcr_rcr & ( MYSON_TCR_TXS | MYSON_RCR_RXS ) ) {
+			mdelay ( 1 );
+			continue;
+		}
+
+		return 0;
+	}
+
+	DBGC ( myson, "MYSON %p timed out waiting for idle state (status "
+	       "%08x)\n", myson, tcr_rcr );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev		Network device
+ */
+static void myson_close ( struct net_device *netdev ) {
+	struct myson_nic *myson = netdev->priv;
+	unsigned int i;
+
+	/* Disable receiver and transmitter */
+	writel ( 0, myson->regs + MYSON_TCR_RCR );
+
+	/* Allow time for receiver and transmitter to become idle */
+	myson_wait_idle ( myson );
+
+	/* Destroy receive descriptor ring */
+	myson_destroy_ring ( myson, &myson->rx );
+
+	/* Discard any unused receive buffers */
+	for ( i = 0 ; i < MYSON_NUM_RX_DESC ; i++ ) {
+		if ( myson->rx_iobuf[i] )
+			free_iob ( myson->rx_iobuf[i] );
+		myson->rx_iobuf[i] = NULL;
+	}
+
+	/* Destroy transmit descriptor ring */
+	myson_destroy_ring ( myson, &myson->tx );
+}
+
+/**
+ * Transmit packet
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int myson_transmit ( struct net_device *netdev,
+			    struct io_buffer *iobuf ) {
+	struct myson_nic *myson = netdev->priv;
+	struct myson_descriptor *tx;
+	unsigned int tx_idx;
+	physaddr_t address;
+
+	/* Check address is usable by card */
+	address = virt_to_bus ( iobuf->data );
+	if ( ! myson_address_ok ( address ) ) {
+		DBGC ( myson, "MYSON %p cannot support 64-bit TX buffer "
+		       "address\n", myson );
+		return -ENOTSUP;
+	}
+
+	/* Get next transmit descriptor */
+	if ( ( myson->tx.prod - myson->tx.cons ) >= MYSON_NUM_TX_DESC ) {
+		DBGC ( myson, "MYSON %p out of transmit descriptors\n",
+		       myson );
+		return -ENOBUFS;
+	}
+	tx_idx = ( myson->tx.prod++ % MYSON_NUM_TX_DESC );
+	tx = &myson->tx.desc[tx_idx];
+
+	/* Populate transmit descriptor */
+	tx->address = cpu_to_le32 ( address );
+	tx->control = cpu_to_le32 ( MYSON_TX_CTRL_IC | MYSON_TX_CTRL_LD |
+				    MYSON_TX_CTRL_FD | MYSON_TX_CTRL_CRC |
+				    MYSON_TX_CTRL_PAD | MYSON_TX_CTRL_RTLC |
+				    MYSON_TX_CTRL_PKTS ( iob_len ( iobuf ) ) |
+				    MYSON_TX_CTRL_TBS ( iob_len ( iobuf ) ) );
+	wmb();
+	tx->status = cpu_to_le32 ( MYSON_TX_STAT_OWN );
+	wmb();
+
+	/* Notify card that there are packets ready to transmit */
+	writel ( 0, myson->regs + MYSON_TXPDR );
+
+	DBGC2 ( myson, "MYSON %p TX %d is [%llx,%llx)\n", myson, tx_idx,
+		( ( unsigned long long ) address ),
+		( ( unsigned long long ) address + iob_len ( iobuf ) ) );
+
+	return 0;
+}
+
+/**
+ * Poll for completed packets
+ *
+ * @v netdev		Network device
+ */
+static void myson_poll_tx ( struct net_device *netdev ) {
+	struct myson_nic *myson = netdev->priv;
+	struct myson_descriptor *tx;
+	unsigned int tx_idx;
+
+	/* Check for completed packets */
+	while ( myson->tx.cons != myson->tx.prod ) {
+
+		/* Get next transmit descriptor */
+		tx_idx = ( myson->tx.cons % MYSON_NUM_TX_DESC );
+		tx = &myson->tx.desc[tx_idx];
+
+		/* Stop if descriptor is still in use */
+		if ( tx->status & cpu_to_le32 ( MYSON_TX_STAT_OWN ) )
+			return;
+
+		/* Complete TX descriptor */
+		if ( tx->status & cpu_to_le32 ( MYSON_TX_STAT_ABORT |
+						MYSON_TX_STAT_CSL ) ) {
+			DBGC ( myson, "MYSON %p TX %d completion error "
+			       "(%08x)\n", myson, tx_idx,
+			       le32_to_cpu ( tx->status ) );
+			netdev_tx_complete_next_err ( netdev, -EIO );
+		} else {
+			DBGC2 ( myson, "MYSON %p TX %d complete\n",
+				myson, tx_idx );
+			netdev_tx_complete_next ( netdev );
+		}
+		myson->tx.cons++;
+	}
+}
+
+/**
+ * Poll for received packets
+ *
+ * @v netdev		Network device
+ */
+static void myson_poll_rx ( struct net_device *netdev ) {
+	struct myson_nic *myson = netdev->priv;
+	struct myson_descriptor *rx;
+	struct io_buffer *iobuf;
+	unsigned int rx_idx;
+	size_t len;
+
+	/* Check for received packets */
+	while ( myson->rx.cons != myson->rx.prod ) {
+
+		/* Get next receive descriptor */
+		rx_idx = ( myson->rx.cons % MYSON_NUM_RX_DESC );
+		rx = &myson->rx.desc[rx_idx];
+
+		/* Stop if descriptor is still in use */
+		if ( rx->status & MYSON_RX_STAT_OWN )
+			return;
+
+		/* Populate I/O buffer */
+		iobuf = myson->rx_iobuf[rx_idx];
+		myson->rx_iobuf[rx_idx] = NULL;
+		len = MYSON_RX_STAT_FLNG ( le32_to_cpu ( rx->status ) );
+		iob_put ( iobuf, len - 4 /* strip CRC */ );
+
+		/* Hand off to network stack */
+		if ( rx->status & cpu_to_le32 ( MYSON_RX_STAT_ES ) ) {
+			DBGC ( myson, "MYSON %p RX %d error (length %zd, "
+			       "status %08x)\n", myson, rx_idx, len,
+			       le32_to_cpu ( rx->status ) );
+			netdev_rx_err ( netdev, iobuf, -EIO );
+		} else {
+			DBGC2 ( myson, "MYSON %p RX %d complete (length "
+				"%zd)\n", myson, rx_idx, len );
+			netdev_rx ( netdev, iobuf );
+		}
+		myson->rx.cons++;
+	}
+}
+
+/**
+ * Poll for completed and received packets
+ *
+ * @v netdev		Network device
+ */
+static void myson_poll ( struct net_device *netdev ) {
+	struct myson_nic *myson = netdev->priv;
+	uint32_t isr;
+	unsigned int i;
+
+	/* Polling the ISR seems to really upset this card; it ends up
+	 * getting no useful PCI transfers done and, for some reason,
+	 * flooding the network with invalid packets.  Work around
+	 * this by introducing deliberate delays between ISR reads.
+	 */
+	for ( i = 0 ; i < MYSON_ISR_IODELAY_COUNT ; i++ )
+		iodelay();
+
+	/* Check for and acknowledge interrupts */
+	isr = readl ( myson->regs + MYSON_ISR );
+	if ( ! isr )
+		return;
+	writel ( isr, myson->regs + MYSON_ISR );
+
+	/* Poll for TX completions, if applicable */
+	if ( isr & MYSON_IRQ_TI )
+		myson_poll_tx ( netdev );
+
+	/* Poll for RX completionsm, if applicable */
+	if ( isr & MYSON_IRQ_RI )
+		myson_poll_rx ( netdev );
+
+	/* Refill RX ring */
+	myson_refill_rx ( netdev );
+}
+
+/**
+ * Enable or disable interrupts
+ *
+ * @v netdev		Network device
+ * @v enable		Interrupts should be enabled
+ */
+static void myson_irq ( struct net_device *netdev, int enable ) {
+	struct myson_nic *myson = netdev->priv;
+	uint32_t imr;
+
+	imr = ( enable ? ( MYSON_IRQ_TI | MYSON_IRQ_RI ) : 0 );
+	writel ( imr, myson->regs + MYSON_IMR );
+}
+
+/** Myson network device operations */
+static struct net_device_operations myson_operations = {
+	.open		= myson_open,
+	.close		= myson_close,
+	.transmit	= myson_transmit,
+	.poll		= myson_poll,
+	.irq		= myson_irq,
+};
+
+/******************************************************************************
+ *
+ * PCI interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Probe PCI device
+ *
+ * @v pci		PCI device
+ * @ret rc		Return status code
+ */
+static int myson_probe ( struct pci_device *pci ) {
+	struct net_device *netdev;
+	struct myson_nic *myson;
+	union myson_physical_address mac;
+	int rc;
+
+	/* Allocate and initialise net device */
+	netdev = alloc_etherdev ( sizeof ( *myson ) );
+	if ( ! netdev ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	netdev_init ( netdev, &myson_operations );
+	myson = netdev->priv;
+	pci_set_drvdata ( pci, netdev );
+	netdev->dev = &pci->dev;
+	memset ( myson, 0, sizeof ( *myson ) );
+	myson_init_ring ( &myson->tx, MYSON_NUM_TX_DESC, MYSON_TXLBA );
+	myson_init_ring ( &myson->rx, MYSON_NUM_RX_DESC, MYSON_RXLBA );
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pci );
+
+	/* Map registers */
+	myson->regs = ioremap ( pci->membase, MYSON_BAR_SIZE );
+
+	/* Reset the NIC */
+	if ( ( rc = myson_reset ( myson ) ) != 0 )
+		goto err_reset;
+
+	/* Read MAC address */
+	mac.reg.low = cpu_to_le32 ( readl ( myson->regs + MYSON_PAR0 ) );
+	mac.reg.high = cpu_to_le32 ( readl ( myson->regs + MYSON_PAR4 ) );
+	memcpy ( netdev->hw_addr, mac.raw, ETH_ALEN );
+
+	/* Register network device */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
+		goto err_register_netdev;
+
+	/* Mark as link up; we don't yet handle link state */
+	netdev_link_up ( netdev );
+
+	return 0;
+
+	unregister_netdev ( netdev );
+ err_register_netdev:
+	myson_reset ( myson );
+ err_reset:
+	iounmap ( myson->regs );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+ err_alloc:
+	return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci		PCI device
+ */
+static void myson_remove ( struct pci_device *pci ) {
+	struct net_device *netdev = pci_get_drvdata ( pci );
+	struct myson_nic *myson = netdev->priv;
+
+	/* Unregister network device */
+	unregister_netdev ( netdev );
+
+	/* Reset card */
+	myson_reset ( myson );
+
+	/* Free network device */
+	iounmap ( myson->regs );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+/** Myson PCI device IDs */
+static struct pci_device_id myson_nics[] = {
+        PCI_ROM ( 0x1516, 0x0800, "mtd800", "MTD-8xx", 0 ),
+        PCI_ROM ( 0x1516, 0x0803, "mtd803", "Surecom EP-320X-S", 0 ),
+        PCI_ROM ( 0x1516, 0x0891, "mtd891", "MTD-8xx", 0 ),
+};
+
+/** Myson PCI driver */
+struct pci_driver myson_driver __pci_driver = {
+	.ids = myson_nics,
+	.id_count = ( sizeof ( myson_nics ) / sizeof ( myson_nics[0] ) ),
+	.probe = myson_probe,
+	.remove = myson_remove,
+};
diff --git a/roms/ipxe/src/drivers/net/myson.h b/roms/ipxe/src/drivers/net/myson.h
new file mode 100644
index 0000000000000000000000000000000000000000..8d7cc5855d07270b63c5d0ded676fc2b99cfdb6a
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/myson.h
@@ -0,0 +1,200 @@
+#ifndef _MYSON_H
+#define _MYSON_H
+
+/** @file
+ *
+ * Myson Technology network card driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/if_ether.h>
+
+/** BAR size */
+#define MYSON_BAR_SIZE 256
+
+/** A packet descriptor */
+struct myson_descriptor {
+	/** Status */
+	uint32_t status;
+	/** Control */
+	uint32_t control;
+	/** Buffer start address */
+	uint32_t address;
+	/** Next descriptor address */
+	uint32_t next;
+} __attribute__ (( packed ));
+
+/* Transmit status */
+#define MYSON_TX_STAT_OWN	0x80000000UL	/**< Owner */
+#define MYSON_TX_STAT_ABORT	0x00002000UL	/**< Abort */
+#define MYSON_TX_STAT_CSL	0x00001000UL	/**< Carrier sense lost */
+
+/* Transmit control */
+#define MYSON_TX_CTRL_IC	0x80000000UL	/**< Interrupt control */
+#define MYSON_TX_CTRL_LD	0x20000000UL	/**< Last descriptor */
+#define MYSON_TX_CTRL_FD	0x10000000UL	/**< First descriptor */
+#define MYSON_TX_CTRL_CRC	0x08000000UL	/**< CRC append */
+#define MYSON_TX_CTRL_PAD	0x04000000UL	/**< Pad control */
+#define MYSON_TX_CTRL_RTLC	0x02000000UL	/**< Retry late collision */
+#define MYSON_TX_CTRL_PKTS(x)	( (x) << 11 )	/**< Packet size */
+#define MYSON_TX_CTRL_TBS(x)	( (x) << 0 )	/**< Transmit buffer size */
+
+/* Receive status */
+#define MYSON_RX_STAT_OWN	0x80000000UL	/**< Owner */
+#define MYSON_RX_STAT_FLNG(status) ( ( (status) >> 16 ) & 0xfff )
+#define MYSON_RX_STAT_ES	0x00000080UL	/**< Error summary */
+
+/* Receive control */
+#define MYSON_RX_CTRL_RBS(x)	( (x) << 0 )	/**< Receive buffer size */
+
+/** Descriptor ring alignment */
+#define MYSON_RING_ALIGN 4
+
+/** Physical Address Register 0 */
+#define MYSON_PAR0 0x00
+
+/** Physical Address Register 4 */
+#define MYSON_PAR4 0x04
+
+/** Physical address */
+union myson_physical_address {
+	struct {
+		uint32_t low;
+		uint32_t high;
+	} __attribute__ (( packed )) reg;
+	uint8_t raw[ETH_ALEN];
+};
+
+/** Transmit and Receive Configuration Register */
+#define MYSON_TCR_RCR 0x18
+#define MYSON_TCR_TXS		0x80000000UL	/**< Transmit status */
+#define MYSON_TCR_TE		0x00040000UL	/**< Transmit enable */
+#define MYSON_RCR_RXS		0x00008000UL	/**< Receive status */
+#define MYSON_RCR_PROM		0x00000080UL	/**< Promiscuous mode */
+#define MYSON_RCR_AB		0x00000040UL	/**< Accept broadcast */
+#define MYSON_RCR_AM		0x00000020UL	/**< Accept multicast */
+#define MYSON_RCR_ARP		0x00000008UL	/**< Accept runt packet */
+#define MYSON_RCR_ALP		0x00000004UL	/**< Accept long packet */
+#define MYSON_RCR_RE		0x00000001UL	/**< Receive enable */
+
+/** Maximum time to wait for transmit and receive to be idle, in milliseconds */
+#define MYSON_IDLE_MAX_WAIT_MS 100
+
+/** Bus Command Register */
+#define MYSON_BCR 0x1c
+#define MYSON_BCR_RLE		0x00000100UL	/**< Read line enable */
+#define MYSON_BCR_RME		0x00000080UL	/**< Read multiple enable */
+#define MYSON_BCR_WIE		0x00000040UL	/**< Write and invalidate */
+#define MYSON_BCR_PBL(x)	( (x) << 3 )	/**< Burst length */
+#define MYSON_BCR_PBL_MASK	MYSON_BCR_PBL ( 0x7 )
+#define MYSON_BCR_PBL_DEFAULT	MYSON_BCR_PBL ( 0x6 )
+#define MYSON_BCR_SWR		0x00000001UL	/**< Software reset */
+
+/** Maximum time to wait for a reset, in milliseconds */
+#define MYSON_RESET_MAX_WAIT_MS 100
+
+/** Transmit Poll Demand Register */
+#define MYSON_TXPDR 0x20
+
+/** Receive Poll Demand Register */
+#define MYSON_RXPDR 0x24
+
+/** Transmit List Base Address */
+#define MYSON_TXLBA 0x2c
+
+/** Number of transmit descriptors */
+#define MYSON_NUM_TX_DESC 4
+
+/** Receive List Base Address */
+#define MYSON_RXLBA 0x30
+
+/** Number of receive descriptors */
+#define MYSON_NUM_RX_DESC 4
+
+/** Receive buffer length */
+#define MYSON_RX_MAX_LEN ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ )
+
+/** Interrupt Status Register */
+#define MYSON_ISR 0x34
+#define MYSON_IRQ_TI		0x00000008UL	/**< Transmit interrupt */
+#define MYSON_IRQ_RI		0x00000004UL	/**< Receive interrupt */
+
+/** Number of I/O delays between ISR reads */
+#define MYSON_ISR_IODELAY_COUNT 4
+
+/** Interrupt Mask Register */
+#define MYSON_IMR 0x38
+
+/** Boot ROM / EEPROM / MII Management Register */
+#define MYSON_ROM_MII 0x40
+#define MYSON_ROM_AUTOLD	0x00100000UL	/**< Auto load */
+
+/** Maximum time to wait for a configuration reload, in milliseconds */
+#define MYSON_AUTOLD_MAX_WAIT_MS 100
+
+/** A Myson descriptor ring */
+struct myson_ring {
+	/** Descriptors */
+	struct myson_descriptor *desc;
+	/** Producer index */
+	unsigned int prod;
+	/** Consumer index */
+	unsigned int cons;
+
+	/** Number of descriptors */
+	unsigned int count;
+	/** Descriptor start address register */
+	unsigned int reg;
+};
+
+/**
+ * Initialise descriptor ring
+ *
+ * @v ring		Descriptor ring
+ * @v count		Number of descriptors
+ * @v reg		Descriptor base address register
+ */
+static inline __attribute__ (( always_inline)) void
+myson_init_ring ( struct myson_ring *ring, unsigned int count,
+		  unsigned int reg ) {
+	ring->count = count;
+	ring->reg = reg;
+}
+
+/** A myson network card */
+struct myson_nic {
+	/** Registers */
+	void *regs;
+
+	/** Transmit descriptor ring */
+	struct myson_ring tx;
+	/** Receive descriptor ring */
+	struct myson_ring rx;
+	/** Receive I/O buffers */
+	struct io_buffer *rx_iobuf[MYSON_NUM_RX_DESC];
+};
+
+/**
+ * Check if card can access physical address
+ *
+ * @v address		Physical address
+ * @v address_ok	Card can access physical address
+ */
+static inline __attribute__ (( always_inline )) int
+myson_address_ok ( physaddr_t address ) {
+
+	/* In a 32-bit build, all addresses can be accessed */
+	if ( sizeof ( physaddr_t ) <= sizeof ( uint32_t ) )
+		return 1;
+
+	/* Card can access all addresses below 4GB */
+	if ( ( address & ~0xffffffffULL ) == 0 )
+		return 1;
+
+	return 0;
+}
+
+#endif /* _MYSON_H */
diff --git a/roms/ipxe/src/drivers/net/natsemi.c b/roms/ipxe/src/drivers/net/natsemi.c
index 171542818f5f1da26e404f809da2..669fb8775235dbe0b852ad88d3f9 100644
--- a/roms/ipxe/src/drivers/net/natsemi.c
+++ b/roms/ipxe/src/drivers/net/natsemi.c
@@ -1,604 +1,929 @@
-/* 
-   natsemi.c - iPXE driver for the NatSemi DP8381x series.
- 
-   Based on:
-
-   natsemi.c: An Etherboot driver for the NatSemi DP8381x series.
-
-   Copyright (C) 2001 Entity Cyber, Inc.
-   
-   This development of this Etherboot driver was funded by 
-   
-      Sicom Systems: http://www.sicompos.com/
-   
-   Author: Marty Connor <mdc@etherboot.org>
-   Adapted from a Linux driver which was written by Donald Becker
-   
-   This software may be used and distributed according to the terms
-   of the GNU Public License (GPL), incorporated herein by reference.
-   
-   Original Copyright Notice:
-   
-   Written/copyright 1999-2001 by Donald Becker.
-   
-   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.  This file is not
-   a complete program and may only be used when the entire operating
-   system is licensed under the GPL.  License for under other terms may be
-   available.  Contact the original author for details.
-   
-   The original author may be reached as becker@scyld.com, or at
-   Scyld Computing Corporation
-   410 Severn Ave., Suite 210
-   Annapolis MD 21403
-   
-   Support information and updates available at
-   http://www.scyld.com/network/netsemi.html
-   
-   References:
-   
-   http://www.scyld.com/expert/100mbps.html
-   http://www.scyld.com/expert/NWay.html
-   Datasheet is available from:
-   http://www.national.com/pf/DP/DP83815.html
-
-*/
-
-FILE_LICENCE ( GPL_ANY );
-
-/* Revision History */
-
 /*
-  02 Jul 2007  Udayan Kumar	 1.2 ported the driver from etherboot to iPXE API.
-				     Fully rewritten,adapting the old driver.
-		      	      	     Added a circular buffer for transmit and receive.
-		                     transmit routine will not wait for transmission to finish.
-			             poll routine deals with it.
-  13 Dec 2003  Tim Legge         1.1 Enabled Multicast Support
-  29 May 2001  Marty Connor	 1.0 Initial Release. Tested with Netgear FA311 and FA312 boards
-*/
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
 #include <string.h>
-#include <ipxe/io.h>
+#include <unistd.h>
 #include <errno.h>
 #include <byteswap.h>
-#include <unistd.h>
-#include <ipxe/pci.h>
-#include <ipxe/if_ether.h>
+#include <ipxe/netdevice.h>
 #include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
 #include <ipxe/iobuf.h>
-#include <ipxe/netdevice.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+#include <ipxe/nvs.h>
+#include <ipxe/bitbash.h>
 #include <ipxe/spi_bit.h>
 #include <ipxe/threewire.h>
-#include <ipxe/nvo.h>
 #include "natsemi.h"
 
-/*  Function Prototypes: */
- 
-static int natsemi_spi_read_bit ( struct bit_basher *, unsigned int );
-static void natsemi_spi_write_bit ( struct bit_basher *,unsigned int, unsigned long ); 
-static void natsemi_init_eeprom ( struct natsemi_private * ); 
-static int natsemi_probe (struct pci_device *pci);
-static void natsemi_reset (struct net_device *netdev);
-static int natsemi_open (struct net_device *netdev);
-static int natsemi_transmit (struct net_device *netdev, struct io_buffer *iobuf);
-static void natsemi_poll (struct net_device *netdev);
-static void natsemi_close (struct net_device *netdev);
-static void natsemi_irq (struct net_device *netdev, int enable);
-static void natsemi_remove (struct pci_device *pci);
-
-/** natsemi net device operations */
-static struct net_device_operations natsemi_operations = {
-        .open           = natsemi_open,
-        .close          = natsemi_close,
-        .transmit       = natsemi_transmit,
-        .poll           = natsemi_poll,
-	.irq		= natsemi_irq,
+/** @file
+ *
+ * National Semiconductor "MacPhyter" network card driver
+ *
+ * Based on the following datasheets:
+ *
+ *    http://www.ti.com/lit/ds/symlink/dp83820.pdf
+ *    http://www.datasheets.org.uk/indexdl/Datasheet-03/DSA0041338.pdf
+ *
+ */
+
+/******************************************************************************
+ *
+ * EEPROM interface
+ *
+ ******************************************************************************
+ */
+
+/** Pin mapping for SPI bit-bashing interface */
+static const uint8_t natsemi_eeprom_bits[] = {
+	[SPI_BIT_SCLK]	= NATSEMI_MEAR_EECLK,
+	[SPI_BIT_MOSI]	= NATSEMI_MEAR_EEDI,
+	[SPI_BIT_MISO]	= NATSEMI_MEAR_EEDO,
+	[SPI_BIT_SS(0)]	= NATSEMI_MEAR_EESEL,
 };
 
+/**
+ * Read input bit
+ *
+ * @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 natsemi_spi_read_bit ( struct bit_basher *basher,
-			      unsigned int bit_id ) {
-	struct natsemi_private *np = container_of ( basher, struct natsemi_private,
-						 spibit.basher );
-	uint8_t mask = natsemi_ee_bits[bit_id];
-	uint8_t eereg;
-
-	eereg = inb ( np->ioaddr + EE_REG );
-	return ( eereg & mask );
+				  unsigned int bit_id ) {
+	struct natsemi_nic *natsemi = container_of ( basher, struct natsemi_nic,
+						     spibit.basher );
+	uint32_t mask = natsemi_eeprom_bits[bit_id];
+	uint32_t reg;
+
+	DBG_DISABLE ( DBGLVL_IO );
+	reg = readl ( natsemi->regs + NATSEMI_MEAR );
+	DBG_ENABLE ( DBGLVL_IO );
+	return ( reg & mask );
 }
 
+/**
+ * Set/clear output bit
+ *
+ * @v basher		Bit-bashing interface
+ * @v bit_id		Bit number
+ * @v data		Value to write
+ */
 static void natsemi_spi_write_bit ( struct bit_basher *basher,
-				unsigned int bit_id, unsigned long data ) {
-	struct natsemi_private *np = container_of ( basher, struct natsemi_private,
-						 spibit.basher );
-	uint8_t mask = natsemi_ee_bits[bit_id];
-	uint8_t eereg;
-
-	eereg = inb ( np->ioaddr + EE_REG );
-	eereg &= ~mask;
-	eereg |= ( data & mask );
-	outb ( eereg, np->ioaddr + EE_REG );
+				    unsigned int bit_id, unsigned long data ) {
+	struct natsemi_nic *natsemi = container_of ( basher, struct natsemi_nic,
+						     spibit.basher );
+	uint32_t mask = natsemi_eeprom_bits[bit_id];
+	uint32_t reg;
+
+	DBG_DISABLE ( DBGLVL_IO );
+	reg = readl ( natsemi->regs + NATSEMI_MEAR );
+	reg &= ~mask;
+	reg |= ( data & mask );
+	writel ( reg, natsemi->regs + NATSEMI_MEAR );
+	DBG_ENABLE ( DBGLVL_IO );
 }
 
+/** SPI bit-bashing interface */
 static struct bit_basher_operations natsemi_basher_ops = {
 	.read = natsemi_spi_read_bit,
 	.write = natsemi_spi_write_bit,
 };
 
-/*
- * Set up for EEPROM access
+/**
+ * Initialise EEPROM
  *
- * @v NAT		NATSEMI NIC
+ * @v natsemi		National Semiconductor device
  */
-static void natsemi_init_eeprom ( struct natsemi_private *np ) {
+static void natsemi_init_eeprom ( struct natsemi_nic *natsemi ) {
+
+	/* Initialise SPI bit-bashing interface */
+	natsemi->spibit.basher.op = &natsemi_basher_ops;
+	natsemi->spibit.bus.mode = SPI_MODE_THREEWIRE;
+	natsemi->spibit.endianness =
+		( ( natsemi->flags & NATSEMI_EEPROM_LITTLE_ENDIAN ) ?
+		  SPI_BIT_LITTLE_ENDIAN : SPI_BIT_BIG_ENDIAN );
+	init_spi_bit_basher ( &natsemi->spibit );
+
+	/* Initialise EEPROM device */
+	init_at93c06 ( &natsemi->eeprom, 16 );
+	natsemi->eeprom.bus = &natsemi->spibit.bus;
+}
 
-	/* Initialise three-wire bus 
-	 */
-	np->spibit.basher.op = &natsemi_basher_ops;
-	np->spibit.bus.mode = SPI_MODE_THREEWIRE;
-	np->spibit.endianness = SPI_BIT_LITTLE_ENDIAN;
-	init_spi_bit_basher ( &np->spibit );
+/**
+ * Get hardware address from sane EEPROM data
+ *
+ * @v natsemi		National Semiconductor device
+ * @v eeprom		EEPROM data
+ * @v hw_addr		Hardware address to fill in
+ */
+static void natsemi_hwaddr_sane ( struct natsemi_nic *natsemi,
+				  const uint16_t *eeprom, uint16_t *hw_addr ) {
+	int i;
 
-	/*natsemi DP 83815 only supports at93c46
-	 */
-	init_at93c46 ( &np->eeprom, 16 );
-	np->eeprom.bus = &np->spibit.bus;
+	/* Copy MAC address from EEPROM data */
+	for ( i = ( ( ETH_ALEN / 2 ) - 1 ) ; i >= 0 ; i-- )
+		*(hw_addr++) = eeprom[ NATSEMI_EEPROM_MAC_SANE + i ];
 
-	/* It looks that this portion of EEPROM can be used for
-	 * non-volatile stored options. Data sheet does not talk about
-	 * this region.  Currently it is not working. But with some
-	 * efforts it can.
-	 */
-	nvo_init ( &np->nvo, &np->eeprom.nvs, 0x0c, 0x68, NULL, NULL );
+	DBGC ( natsemi, "NATSEMI %p has sane EEPROM layout\n", natsemi );
 }
 
 /**
- * Probe PCI device
+ * Get hardware address from insane EEPROM data
  *
- * @v pci	PCI device
- * @v id	PCI ID
- * @ret rc	Return status code
+ * @v natsemi		National Semiconductor device
+ * @v eeprom		EEPROM data
+ * @v hw_addr		Hardware address to fill in
  */
-static int natsemi_probe (struct pci_device *pci) {
-	struct net_device *netdev;
-	struct natsemi_private *np = NULL;
-	uint8_t ll_addr_encoded[MAX_LL_ADDR_LEN];
-	uint8_t last=0,last1=0;
-	uint8_t prev_bytes[2];
-	int i;
-	int rc;
+static void natsemi_hwaddr_insane ( struct natsemi_nic *natsemi,
+				    const uint16_t *eeprom,
+				    uint16_t *hw_addr ) {
+	unsigned int i;
+	unsigned int offset;
+	uint16_t word;
+
+	/* Copy MAC address from EEPROM data */
+	for ( i = 0 ; i < ( ETH_ALEN / 2 ) ; i++ ) {
+		offset = ( NATSEMI_EEPROM_MAC_INSANE + i );
+		word = ( ( le16_to_cpu ( eeprom[ offset ] ) >> 15 ) |
+			 ( le16_to_cpu ( eeprom[ offset + 1 ] << 1 ) ) );
+		hw_addr[i] = cpu_to_le16 ( word );
+	}
 
-	/* Allocate net device 
-	 */
-	netdev = alloc_etherdev (sizeof (*np));
-	if (! netdev) 
-		return -ENOMEM;
+	DBGC ( natsemi, "NATSEMI %p has insane EEPROM layout\n", natsemi );
+}
 
-	netdev_init (netdev, &natsemi_operations);
-	np = netdev->priv;
-	pci_set_drvdata (pci, netdev);
-	netdev->dev = &pci->dev;
-	memset (np, 0, sizeof (*np));
-	np->ioaddr = pci->ioaddr;
-
-	adjust_pci_device (pci);
-
-	natsemi_reset (netdev);
-	natsemi_init_eeprom ( np );
-	nvs_read ( &np->eeprom.nvs, EE_MAC-1, prev_bytes, 1 );
-	nvs_read ( &np->eeprom.nvs, EE_MAC, ll_addr_encoded, ETH_ALEN );
-
-	/* decoding the MAC address read from NVS 
-	 * and save it in netdev->ll_addr
-         */
-	last = prev_bytes[1] >> 7;
-	for ( i = 0 ; i < ETH_ALEN ; i++ ) {
-		last1 = ll_addr_encoded[i] >> 7;
-		netdev->hw_addr[i] = ll_addr_encoded[i] << 1 | last;
-		last = last1;
-	}
+/**
+ * Get hardware address from EEPROM
+ *
+ * @v natsemi		National Semiconductor device
+ * @v hw_addr		Hardware address to fill in
+ * @ret rc		Return status code
+ */
+static int natsemi_hwaddr ( struct natsemi_nic *natsemi, void *hw_addr ) {
+	uint16_t buf[NATSEMI_EEPROM_SIZE];
+	void ( * extract ) ( struct natsemi_nic *natsemi,
+			     const uint16_t *eeprom, uint16_t *hw_addr );
+	int rc;
 
-	if ((rc = register_netdev (netdev)) != 0)
-		goto err_register_netdev;
+	/* Read EEPROM contents */
+	if ( ( rc = nvs_read ( &natsemi->eeprom.nvs, 0, buf,
+			       sizeof ( buf ) ) ) != 0 ) {
+		DBGC ( natsemi, "NATSEMI %p could not read EEPROM: %s\n",
+		       natsemi, strerror ( rc ) );
+		return rc;
+	}
+	DBGC2 ( natsemi, "NATSEMI %p EEPROM contents:\n", natsemi );
+	DBGC2_HDA ( natsemi, 0, buf, sizeof ( buf ) );
 
-	/* Mark as link up; we don't yet handle link state */
-	netdev_link_up ( netdev );
+	/* Extract MAC address from EEPROM contents */
+	extract = ( ( natsemi->flags & NATSEMI_EEPROM_INSANE ) ?
+		    natsemi_hwaddr_insane : natsemi_hwaddr_sane );
+	extract ( natsemi, buf, hw_addr );
 
 	return 0;
+}
 
-err_register_netdev:
+/******************************************************************************
+ *
+ * Device reset
+ *
+ ******************************************************************************
+ */
 
-	natsemi_reset (netdev);
-	netdev_put (netdev);
-	return rc;
+/**
+ * Reset controller chip
+ *
+ * @v natsemi		National Semiconductor device
+ * @ret rc		Return status code
+ */
+static int natsemi_soft_reset ( struct natsemi_nic *natsemi ) {
+	unsigned int i;
+
+	/* Initiate reset */
+	writel ( NATSEMI_CR_RST, natsemi->regs + NATSEMI_CR );
+
+	/* Wait for reset to complete */
+	for ( i = 0 ; i < NATSEMI_RESET_MAX_WAIT_MS ; i++ ) {
+
+		/* If reset is not complete, delay 1ms and retry */
+		if ( readl ( natsemi->regs + NATSEMI_CR ) & NATSEMI_CR_RST ) {
+			mdelay ( 1 );
+			continue;
+		}
+
+		return 0;
+	}
+
+	DBGC ( natsemi, "NATSEMI %p timed out waiting for reset\n", natsemi );
+	return -ETIMEDOUT;
 }
 
 /**
- * Remove PCI device
+ * Reload configuration from EEPROM
  *
- * @v pci	PCI device
+ * @v natsemi		National Semiconductor device
+ * @ret rc		Return status code
  */
-static void natsemi_remove (struct pci_device *pci) {
-	struct net_device *netdev = pci_get_drvdata (pci);
- 
-	unregister_netdev (netdev);
-	natsemi_reset (netdev);
-	netdev_nullify ( netdev );
-	netdev_put (netdev);
+static int natsemi_reload_config ( struct natsemi_nic *natsemi ) {
+	unsigned int i;
+
+	/* Initiate reload */
+	writel ( NATSEMI_PTSCR_EELOAD_EN, natsemi->regs + NATSEMI_PTSCR );
+
+	/* Wait for reload to complete */
+	for ( i = 0 ; i < NATSEMI_EELOAD_MAX_WAIT_MS ; i++ ) {
+
+		/* If reload is not complete, delay 1ms and retry */
+		if ( readl ( natsemi->regs + NATSEMI_PTSCR ) &
+		     NATSEMI_PTSCR_EELOAD_EN ) {
+			mdelay ( 1 );
+			continue;
+		}
+
+		return 0;
+	}
+
+	DBGC ( natsemi, "NATSEMI %p timed out waiting for configuration "
+	       "reload\n", natsemi );
+	return -ETIMEDOUT;
 }
 
 /**
- * Reset NIC
+ * Reset hardware
  *
- * @v		NATSEMI NIC
- *
- * Issues a hardware reset and waits for the reset to complete.
+ * @v natsemi		National Semiconductor device
+ * @ret rc		Return status code
  */
-static void natsemi_reset (struct net_device *netdev) 
-{
-	struct natsemi_private *np = netdev->priv;
-	int i;
-        u32 cfg;
-        u32 wcsr;
-        u32 rfcr;
-        u16 pmatch[3];
-        u16 sopass[3];
-
-	natsemi_irq (netdev, 0);
-
-        /*
-         * Resetting the chip causes some registers to be lost.
-         * Natsemi suggests NOT reloading the EEPROM while live, so instead
-         * we save the state that would have been loaded from EEPROM
-         * on a normal power-up (see the spec EEPROM map).
-         */
-
-        /* CFG */
-        cfg = inl (np->ioaddr + ChipConfig) & CFG_RESET_SAVE;
-
-        /* WCSR */
-        wcsr = inl (np->ioaddr + WOLCmd) & WCSR_RESET_SAVE;
-
-        /* RFCR */
-        rfcr = inl (np->ioaddr + RxFilterAddr) & RFCR_RESET_SAVE;
-
-        /* PMATCH */
-        for (i = 0; i < 3; i++) {
-		outl(i*2, np->ioaddr + RxFilterAddr);
-		pmatch[i] = inw(np->ioaddr + RxFilterData);
-        }
-
-        /* SOPAS */
-        for (i = 0; i < 3; i++) {
-	  	outl(0xa+(i*2), np->ioaddr + RxFilterAddr);
-		sopass[i] = inw(np->ioaddr + RxFilterData);
-        }
-
-        /* now whack the chip */
-        outl(ChipReset, np->ioaddr + ChipCmd);
-        for (i=0; i<NATSEMI_HW_TIMEOUT; i++) {
-		if (! (inl (np->ioaddr + ChipCmd) & ChipReset))
-		       break;
-		udelay(5);
-        }
-        if (i == NATSEMI_HW_TIMEOUT) {
-	  	DBG ("natsemi_reset: reset did not complete in %d usec.\n", i*5);
-        }
-
-        /* restore CFG */
-        cfg |= inl(np->ioaddr + ChipConfig) & ~CFG_RESET_SAVE;
-	cfg &= ~(CfgExtPhy | CfgPhyDis);
-        outl (cfg, np->ioaddr + ChipConfig);
-
-        /* restore WCSR */
-        wcsr |= inl (np->ioaddr + WOLCmd) & ~WCSR_RESET_SAVE;
-        outl (wcsr, np->ioaddr + WOLCmd);
-
-        /* read RFCR */
-        rfcr |= inl (np->ioaddr + RxFilterAddr) & ~RFCR_RESET_SAVE;
-
-        /* restore PMATCH */
-        for (i = 0; i < 3; i++) {
-	  	outl (i*2, np->ioaddr + RxFilterAddr);
-		outw (pmatch[i], np->ioaddr + RxFilterData);
-        }
-        for (i = 0; i < 3; i++) {
-		outl (0xa+(i*2), np->ioaddr + RxFilterAddr);
-		outw (sopass[i], np->ioaddr + RxFilterData);
-        }
-        /* restore RFCR */
-        outl (rfcr, np->ioaddr + RxFilterAddr);
+static int natsemi_reset ( struct natsemi_nic *natsemi ) {
+	uint32_t cfg;
+	int rc;
+
+	/* Perform soft reset */
+	if ( ( rc = natsemi_soft_reset ( natsemi ) ) != 0 )
+		return rc;
+
+	/* Reload configuration from EEPROM */
+	if ( ( rc = natsemi_reload_config ( natsemi ) ) != 0 )
+		return rc;
+
+	/* Configure 64-bit operation, if applicable */
+	cfg = readl ( natsemi->regs + NATSEMI_CFG );
+	if ( natsemi->flags & NATSEMI_64BIT ) {
+		cfg |= ( NATSEMI_CFG_M64ADDR | NATSEMI_CFG_EXTSTS_EN );
+		if ( ! ( cfg & NATSEMI_CFG_PCI64_DET ) )
+			cfg &= ~NATSEMI_CFG_DATA64_EN;
+	}
+	writel ( cfg, natsemi->regs + NATSEMI_CFG );
+
+	/* Invalidate link status cache to force an update */
+	natsemi->cfg = ~cfg;
+
+	DBGC ( natsemi, "NATSEMI %p using configuration %08x\n",
+	       natsemi, cfg );
+	return 0;
 }
 
+/******************************************************************************
+ *
+ * Link state
+ *
+ ******************************************************************************
+ */
+
 /**
- * Open NIC
+ * Check link state
  *
- * @v netdev		Net device
- * @ret rc		Return status code
+ * @v netdev		Network device
  */
-static int natsemi_open (struct net_device *netdev)
-{
-	struct natsemi_private *np = netdev->priv;
-	uint32_t tx_config, rx_config;
-	int i;
-	
-	/* Disable PME:
-         * The PME bit is initialized from the EEPROM contents.
-         * PCI cards probably have PME disabled, but motherboard
-         * implementations may have PME set to enable WakeOnLan. 
-         * With PME set the chip will scan incoming packets but
-         * nothing will be written to memory. 
-         */
-        outl (inl (np->ioaddr + ClkRun) & ~0x100, np->ioaddr + ClkRun);
-
-	/* Set MAC address in NIC
-	 */
-	for (i = 0 ; i < ETH_ALEN ; i+=2) {
-		outl (i, np->ioaddr + RxFilterAddr);
-		outw (netdev->ll_addr[i] + (netdev->ll_addr[i + 1] << 8),
-		       np->ioaddr + RxFilterData);
+static void natsemi_check_link ( struct net_device *netdev ) {
+	struct natsemi_nic *natsemi = netdev->priv;
+	uint32_t cfg;
+
+	/* Read link status */
+	cfg = readl ( natsemi->regs + NATSEMI_CFG );
+
+	/* Do nothing unless link status has changed */
+	if ( cfg == natsemi->cfg )
+		return;
+
+	/* Set gigabit mode (if applicable) */
+	if ( natsemi->flags & NATSEMI_1000 ) {
+		cfg &= ~NATSEMI_CFG_MODE_1000;
+		if ( ! ( cfg & NATSEMI_CFG_SPDSTS1 ) )
+			cfg |= NATSEMI_CFG_MODE_1000;
+		writel ( cfg, natsemi->regs + NATSEMI_CFG );
 	}
 
-	/* Setup Tx Ring 
-	 */
-	np->tx_cur = 0;
-	np->tx_dirty = 0;
-	for (i = 0 ; i < TX_RING_SIZE ; i++) {
-		np->tx[i].link   = virt_to_bus ((i + 1 < TX_RING_SIZE) ? &np->tx[i + 1] : &np->tx[0]);
-		np->tx[i].cmdsts = 0;
-		np->tx[i].bufptr = 0;
+	/* Update link status */
+	natsemi->cfg = cfg;
+	DBGC ( natsemi, "NATSEMI %p link status is %08x\n", natsemi, cfg );
+
+	/* Update network device */
+	if ( cfg & NATSEMI_CFG_LNKSTS ) {
+		netdev_link_up ( netdev );
+	} else {
+		netdev_link_down ( netdev );
 	}
-	outl (virt_to_bus (&np->tx[0]),np->ioaddr + TxRingPtr);
+}
 
-	DBG ("Natsemi Tx descriptor loaded with: %#08x\n",
-	     inl (np->ioaddr + TxRingPtr));
+/******************************************************************************
+ *
+ * Network device interface
+ *
+ ******************************************************************************
+ */
 
-	/* Setup RX ring
-	 */
-	np->rx_cur = 0;
-	for (i = 0 ; i < NUM_RX_DESC ; i++) {
-		np->iobuf[i] = alloc_iob (RX_BUF_SIZE);
-		if (! np->iobuf[i])
-			goto memory_alloc_err;
-		np->rx[i].link   = virt_to_bus ((i + 1 < NUM_RX_DESC) 
-						? &np->rx[i + 1] : &np->rx[0]);
-		np->rx[i].cmdsts = RX_BUF_SIZE;
-		np->rx[i].bufptr = virt_to_bus (np->iobuf[i]->data);
-		DBG (" Address of iobuf [%d] = %p and iobuf->data = %p \n", i, 
-		      &np->iobuf[i],  &np->iobuf[i]->data);
+/**
+ * Set perfect match filter address
+ *
+ * @v natsemi		National Semiconductor device
+ * @v mac		MAC address
+ */
+static void natsemi_pmatch ( struct natsemi_nic *natsemi, const void *mac ) {
+	const uint16_t *pmatch = mac;
+	uint32_t rfcr;
+	unsigned int rfaddr;
+	unsigned int i;
+
+	for ( i = 0 ; i < ETH_ALEN ; i += sizeof ( *pmatch ) ) {
+
+		/* Select receive filter register address */
+		rfaddr = ( NATSEMI_RFADDR_PMATCH_BASE + i );
+		rfcr = readl ( natsemi->regs + NATSEMI_RFCR );
+		rfcr &= ~NATSEMI_RFCR_RFADDR_MASK;
+		rfcr |= NATSEMI_RFCR_RFADDR ( rfaddr );
+		writel ( rfcr, natsemi->regs + NATSEMI_RFCR );
+
+		/* Write receive filter data */
+		writel ( ( le16_to_cpu ( *(pmatch++) ) | NATSEMI_RFDR_BMASK ),
+			 natsemi->regs + NATSEMI_RFDR );
 	}
-	outl (virt_to_bus (&np->rx[0]), np->ioaddr + RxRingPtr);
+}
 
-	DBG ("Natsemi Rx descriptor loaded with: %#08x\n",
-	      inl (np->ioaddr + RxRingPtr));		
+/**
+ * Create descriptor ring
+ *
+ * @v natsemi		National Semiconductor device
+ * @v ring		Descriptor ring
+ * @ret rc		Return status code
+ */
+static int natsemi_create_ring ( struct natsemi_nic *natsemi,
+				 struct natsemi_ring *ring ) {
+	size_t len = ( ring->count * sizeof ( ring->desc[0] ) );
+	union natsemi_descriptor *desc;
+	union natsemi_descriptor *linked_desc;
+	physaddr_t address;
+	physaddr_t link;
+	size_t offset;
+	unsigned int i;
+	int rc;
 
-	/* Setup RX Filter 
-	 */
-	outl (RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys,
-	      np->ioaddr + RxFilterAddr);
+	/* Calculate descriptor offset */
+	offset = ( ( natsemi->flags & NATSEMI_64BIT ) ? 0 :
+		   offsetof ( typeof ( desc[i].d32pad ), d32 ) );
 
-	/* Initialize other registers. 
-	 * Configure the PCI bus bursts and FIFO thresholds. 
-	 * Configure for standard, in-spec Ethernet. 
+	/* Allocate descriptor ring.  Align ring on its own size to
+	 * ensure that it can't possibly cross the boundary of 32-bit
+	 * address space.
 	 */
-	if (inl (np->ioaddr + ChipConfig) & 0x20000000) {	/* Full duplex */
-		DBG ("Full duplex\n");
-		tx_config = 0xD0801002 |  0xC0000000;
-		rx_config = 0x10000020 |  0x10000000;
-	} else {
-		DBG ("Half duplex\n");
-		tx_config = 0x10801002 & ~0xC0000000;
-		rx_config = 0x00000020 & ~0x10000000;
+	ring->desc = malloc_dma ( len, len );
+	if ( ! ring->desc ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	address = ( virt_to_bus ( ring->desc ) + offset );
+
+	/* Check address is usable by card */
+	if ( ! natsemi_address_ok ( natsemi, address ) ) {
+		DBGC ( natsemi, "NATSEMI %p cannot support 64-bit ring "
+		       "address\n", natsemi );
+		rc = -ENOTSUP;
+		goto err_64bit;
 	}
-	outl (tx_config, np->ioaddr + TxConfig);
-	outl (rx_config, np->ioaddr + RxConfig);
 
-	DBG ("Tx config register = %#08x Rx config register = %#08x\n", 
-               inl (np->ioaddr + TxConfig),
-	       inl (np->ioaddr + RxConfig));
+	/* Initialise descriptor ring */
+	memset ( ring->desc, 0, len );
+	for ( i = 0 ; i < ring->count ; i++ ) {
+		linked_desc = &ring->desc [ ( i + 1 ) % ring->count ];
+		link = ( virt_to_bus ( linked_desc ) + offset );
+		if ( natsemi->flags & NATSEMI_64BIT ) {
+			ring->desc[i].d64.link = cpu_to_le64 ( link );
+		} else {
+			ring->desc[i].d32pad.d32.link = cpu_to_le32 ( link );
+		}
+	}
+
+	/* Program ring address */
+	writel ( ( address & 0xffffffffUL ), natsemi->regs + ring->reg );
+	if ( natsemi->flags & NATSEMI_64BIT ) {
+		if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) {
+			writel ( ( ( ( uint64_t ) address ) >> 32 ),
+				 natsemi->regs + ring->reg + 4 );
+		} else {
+			writel ( 0, natsemi->regs + ring->reg + 4 );
+		}
+	}
+
+	DBGC ( natsemi, "NATSEMI %p ring %02x is at [%08llx,%08llx)\n",
+	       natsemi, ring->reg,
+	       ( ( unsigned long long ) virt_to_bus ( ring->desc ) ),
+	       ( ( unsigned long long ) virt_to_bus ( ring->desc ) + len ) );
 
-	/*Set the Interrupt Mask register
-	 */
-	outl((RxOk|RxErr|TxOk|TxErr),np->ioaddr + IntrMask);
-	/*start the receiver 
-	 */
-        outl (RxOn, np->ioaddr + ChipCmd);
-	
 	return 0;
-		       
-memory_alloc_err:
 
-	/* Frees any allocated buffers when memory
-	 * for all buffers requested is not available
-	 */
-	i = 0;
-	while (np->rx[i].cmdsts == RX_BUF_SIZE) {
-		free_iob (np->iobuf[i]);
-		i++;
-	}
-	return -ENOMEM;	
+ err_64bit:
+	free_dma ( ring->desc, len );
+	ring->desc = NULL;
+ err_alloc:
+	return rc;
 }
 
 /**
- * Close NIC
+ * Destroy descriptor ring
  *
- * @v netdev		Net device
+ * @v natsemi		National Semiconductor device
+ * @v ring		Descriptor ring
  */
-static void natsemi_close (struct net_device *netdev) 
-{
-	struct natsemi_private *np = netdev->priv;
-	int i;
+static void natsemi_destroy_ring ( struct natsemi_nic *natsemi,
+				   struct natsemi_ring *ring ) {
+	size_t len = ( ring->count * sizeof ( ring->desc[0] ) );
+
+	/* Clear ring address */
+	writel ( 0, natsemi->regs + ring->reg );
+	if ( natsemi->flags & NATSEMI_64BIT )
+		writel ( 0, natsemi->regs + ring->reg + 4 );
+
+	/* Free descriptor ring */
+	free_dma ( ring->desc, len );
+	ring->desc = NULL;
+	ring->prod = 0;
+	ring->cons = 0;
+}
+
+/**
+ * Refill receive descriptor ring
+ *
+ * @v netdev		Network device
+ */
+static void natsemi_refill_rx ( struct net_device *netdev ) {
+	struct natsemi_nic *natsemi = netdev->priv;
+	union natsemi_descriptor *rx;
+	struct io_buffer *iobuf;
+	unsigned int rx_idx;
+	physaddr_t address;
+
+	while ( ( natsemi->rx.prod - natsemi->rx.cons ) < NATSEMI_NUM_RX_DESC ){
+
+		/* Allocate I/O buffer */
+		iobuf = alloc_iob ( NATSEMI_RX_MAX_LEN );
+		if ( ! iobuf ) {
+			/* Wait for next refill */
+			return;
+		}
+
+		/* Check address is usable by card */
+		address = virt_to_bus ( iobuf->data );
+		if ( ! natsemi_address_ok ( natsemi, address ) ) {
+			DBGC ( natsemi, "NATSEMI %p cannot support 64-bit RX "
+			       "buffer address\n", natsemi );
+			netdev_rx_err ( netdev, iobuf, -ENOTSUP );
+			return;
+		}
 
-	natsemi_reset (netdev);
+		/* Get next receive descriptor */
+		rx_idx = ( natsemi->rx.prod++ % NATSEMI_NUM_RX_DESC );
+		rx = &natsemi->rx.desc[rx_idx];
 
-	for (i = 0; i < NUM_RX_DESC ; i++) {
-		free_iob (np->iobuf[i]);
+		/* Populate receive descriptor */
+		if ( natsemi->flags & NATSEMI_64BIT ) {
+			rx->d64.bufptr = cpu_to_le64 ( address );
+		} else {
+			rx->d32pad.d32.bufptr = cpu_to_le32 ( address );
+		}
+		wmb();
+		rx->common.cmdsts = cpu_to_le32 ( NATSEMI_DESC_INTR |
+						  NATSEMI_RX_MAX_LEN );
+		wmb();
+
+		/* Record I/O buffer */
+		assert ( natsemi->rx_iobuf[rx_idx] == NULL );
+		natsemi->rx_iobuf[rx_idx] = iobuf;
+
+		/* Notify card that there are descriptors available */
+		writel ( NATSEMI_CR_RXE, natsemi->regs + NATSEMI_CR );
+
+		DBGC2 ( natsemi, "NATSEMI %p RX %d is [%llx,%llx)\n", natsemi,
+			rx_idx, ( ( unsigned long long ) address ),
+			( ( unsigned long long ) address + NATSEMI_RX_MAX_LEN));
 	}
 }
 
-/** 
- * Transmit packet
+/**
+ * Open network device
  *
- * @v netdev	Network device
- * @v iobuf	I/O buffer
- * @ret rc	Return status code
+ * @v netdev		Network device
+ * @ret rc		Return status code
  */
-static int natsemi_transmit (struct net_device *netdev, struct io_buffer *iobuf)
-{
-	struct natsemi_private *np = netdev->priv;
+static int natsemi_open ( struct net_device *netdev ) {
+	struct natsemi_nic *natsemi = netdev->priv;
+	int rc;
 
-	if (np->tx[np->tx_cur].cmdsts != 0) {
-		DBG ("TX overflow\n");
-		return -ENOBUFS;
-	}
+	/* Set MAC address */
+	natsemi_pmatch ( natsemi, netdev->ll_addr );
 
-	/* Used by netdev_tx_complete ()
-	 */
-	np->tx_iobuf[np->tx_cur] = iobuf;
+	/* Create transmit descriptor ring */
+	if ( ( rc = natsemi_create_ring ( natsemi, &natsemi->tx ) ) != 0 )
+		goto err_create_tx;
 
-	/* Pad and align packet has not been used because its not required 
-	 * by the hardware.
-	 * 	iob_pad (iobuf, ETH_ZLEN); 
-	 * can be used to achieve it, if required
-	 */
+	/* Set transmit configuration */
+	writel ( ( NATSEMI_TXCFG_CSI | NATSEMI_TXCFG_HBI | NATSEMI_TXCFG_ATP |
+		   NATSEMI_TXCFG_ECRETRY | NATSEMI_TXCFG_MXDMA_DEFAULT |
+		   NATSEMI_TXCFG_FLTH_DEFAULT | NATSEMI_TXCFG_DRTH_DEFAULT ),
+		 ( natsemi->regs + ( ( natsemi->flags & NATSEMI_64BIT ) ?
+				     NATSEMI_TXCFG_64 : NATSEMI_TXCFG_32 ) ) );
 
-	/* Add the packet to TX ring
-	 */
-	np->tx[np->tx_cur].bufptr = virt_to_bus (iobuf->data);
-	np->tx[np->tx_cur].cmdsts = iob_len (iobuf) | OWN;
+	/* Create receive descriptor ring */
+	if ( ( rc = natsemi_create_ring ( natsemi, &natsemi->rx ) ) != 0 )
+		goto err_create_rx;
 
-	DBG ("TX id %d at %#08lx + %#08zx\n", np->tx_cur,
-	     virt_to_bus (&iobuf->data), iob_len (iobuf));
+	/* Set receive configuration */
+	writel ( ( NATSEMI_RXCFG_ARP | NATSEMI_RXCFG_ATX | NATSEMI_RXCFG_ALP |
+		   NATSEMI_RXCFG_MXDMA_DEFAULT | NATSEMI_RXCFG_DRTH_DEFAULT ),
+		 ( natsemi->regs + ( ( natsemi->flags & NATSEMI_64BIT ) ?
+				     NATSEMI_RXCFG_64 : NATSEMI_RXCFG_32 ) ) );
 
-	/* increment the circular buffer pointer to the next buffer location
-	 */
-	np->tx_cur = (np->tx_cur + 1) % TX_RING_SIZE;
+	/* Set receive filter configuration */
+	writel ( ( NATSEMI_RFCR_RFEN | NATSEMI_RFCR_AAB | NATSEMI_RFCR_AAM |
+		   NATSEMI_RFCR_AAU ), natsemi->regs + NATSEMI_RFCR );
+
+	/* Fill receive ring */
+	natsemi_refill_rx ( netdev );
 
-	/*start the transmitter 
+	/* Unmask transmit and receive interrupts.  (Interrupts will
+	 * not be generated unless enabled via the IER.)
 	 */
-        outl (TxOn, np->ioaddr + ChipCmd);
+	writel ( ( NATSEMI_IRQ_TXDESC | NATSEMI_IRQ_RXDESC ),
+		 natsemi->regs + NATSEMI_IMR );
+
+	/* Update link state */
+	natsemi_check_link ( netdev );
 
 	return 0;
+
+	natsemi_destroy_ring ( natsemi, &natsemi->rx );
+ err_create_rx:
+	natsemi_destroy_ring ( natsemi, &natsemi->tx );
+ err_create_tx:
+	return rc;
 }
 
-/** 
- * Poll for received packets
+/**
+ * Close network device
  *
- * @v netdev	Network device
+ * @v netdev		Network device
  */
-static void natsemi_poll (struct net_device *netdev)
-{
-	struct natsemi_private *np = netdev->priv;
-	unsigned int tx_status;
-	unsigned int rx_status;
-	unsigned int intr_status;
-	unsigned int rx_len;
-	struct io_buffer *rx_iob;
-	int i;
-	
-	/* read the interrupt register
-	 */
-	intr_status = inl (np->ioaddr + IntrStatus);
+static void natsemi_close ( struct net_device *netdev ) {
+	struct natsemi_nic *natsemi = netdev->priv;
+	unsigned int i;
+
+	/* Mask transmit and receive interrupts */
+	writel ( 0, natsemi->regs + NATSEMI_IMR );
+
+	/* Reset and disable transmitter and receiver */
+	writel ( ( NATSEMI_CR_RXR | NATSEMI_CR_TXR ),
+		 natsemi->regs + NATSEMI_CR );
+
+	/* Discard any unused receive buffers */
+	for ( i = 0 ; i < NATSEMI_NUM_RX_DESC ; i++ ) {
+		if ( natsemi->rx_iobuf[i] )
+			free_iob ( natsemi->rx_iobuf[i] );
+		natsemi->rx_iobuf[i] = NULL;
+	}
 
-	if (!intr_status)
-		goto end;
+	/* Destroy receive descriptor ring */
+	natsemi_destroy_ring ( natsemi, &natsemi->rx );
 
-        DBG ("natsemi_poll: intr_status = %#08x\n", intr_status);
+	/* Destroy transmit descriptor ring */
+	natsemi_destroy_ring ( natsemi, &natsemi->tx );
+}
 
-	/* Check status of transmitted packets
-	 */
-	i = np->tx_dirty;
-	while (i != np->tx_cur) {
-	  	tx_status = np->tx[np->tx_dirty].cmdsts;
-
-		DBG ("tx_dirty = %d tx_cur=%d tx_status=%#08x\n",
-		     np->tx_dirty, np->tx_cur, tx_status);
-		
-		if (tx_status & OWN) 
-			break;
-
-		if (! (tx_status & DescPktOK)) {
-			netdev_tx_complete_err (netdev,np->tx_iobuf[np->tx_dirty],-EINVAL);
-			DBG ("Error transmitting packet, tx_status: %#08x\n",
-			     tx_status);
+/**
+ * Transmit packet
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int natsemi_transmit ( struct net_device *netdev,
+			       struct io_buffer *iobuf ) {
+	struct natsemi_nic *natsemi = netdev->priv;
+	union natsemi_descriptor *tx;
+	unsigned int tx_idx;
+	physaddr_t address;
+
+	/* Check address is usable by card */
+	address = virt_to_bus ( iobuf->data );
+	if ( ! natsemi_address_ok ( natsemi, address ) ) {
+		DBGC ( natsemi, "NATSEMI %p cannot support 64-bit TX buffer "
+		       "address\n", natsemi );
+		return -ENOTSUP;
+	}
+
+	/* Get next transmit descriptor */
+	if ( ( natsemi->tx.prod - natsemi->tx.cons ) >= NATSEMI_NUM_TX_DESC ) {
+		DBGC ( natsemi, "NATSEMI %p out of transmit descriptors\n",
+		       natsemi );
+		return -ENOBUFS;
+	}
+	tx_idx = ( natsemi->tx.prod++ % NATSEMI_NUM_TX_DESC );
+	tx = &natsemi->tx.desc[tx_idx];
+
+	/* Populate transmit descriptor */
+	if ( natsemi->flags & NATSEMI_64BIT ) {
+		tx->d64.bufptr = cpu_to_le64 ( address );
+	} else {
+		tx->d32pad.d32.bufptr = cpu_to_le32 ( address );
+	}
+	wmb();
+	tx->common.cmdsts = cpu_to_le32 ( NATSEMI_DESC_OWN | NATSEMI_DESC_INTR |
+					  iob_len ( iobuf ) );
+	wmb();
+
+	/* Notify card that there are packets ready to transmit */
+	writel ( NATSEMI_CR_TXE, natsemi->regs + NATSEMI_CR );
+
+	DBGC2 ( natsemi, "NATSEMI %p TX %d is [%llx,%llx)\n", natsemi, tx_idx,
+		( ( unsigned long long ) address ),
+		( ( unsigned long long ) address + iob_len ( iobuf ) ) );
+
+	return 0;
+}
+
+/**
+ * Poll for completed packets
+ *
+ * @v netdev		Network device
+ */
+static void natsemi_poll_tx ( struct net_device *netdev ) {
+	struct natsemi_nic *natsemi = netdev->priv;
+	union natsemi_descriptor *tx;
+	unsigned int tx_idx;
+
+	/* Check for completed packets */
+	while ( natsemi->tx.cons != natsemi->tx.prod ) {
+
+		/* Get next transmit descriptor */
+		tx_idx = ( natsemi->tx.cons % NATSEMI_NUM_TX_DESC );
+		tx = &natsemi->tx.desc[tx_idx];
+
+		/* Stop if descriptor is still in use */
+		if ( tx->common.cmdsts & cpu_to_le32 ( NATSEMI_DESC_OWN ) )
+			return;
+
+		/* Complete TX descriptor */
+		if ( tx->common.cmdsts & cpu_to_le32 ( NATSEMI_DESC_OK ) ) {
+			DBGC2 ( natsemi, "NATSEMI %p TX %d complete\n",
+				natsemi, tx_idx );
+			netdev_tx_complete_next ( netdev );
 		} else {
-			netdev_tx_complete (netdev, np->tx_iobuf[np->tx_dirty]);
-			DBG ("Success transmitting packet\n");
+			DBGC ( natsemi, "NATSEMI %p TX %d completion error "
+			       "(%08x)\n", natsemi, tx_idx,
+			       le32_to_cpu ( tx->common.cmdsts ) );
+			netdev_tx_complete_next_err ( netdev, -EIO );
 		}
-
-		np->tx[np->tx_dirty].cmdsts = 0;
-		np->tx_dirty = (np->tx_dirty + 1) % TX_RING_SIZE;
-		i = (i + 1) % TX_RING_SIZE;
+		natsemi->tx.cons++;
 	}
-	
-	/* Process received packets 
-	 */
-	rx_status = (unsigned int) np->rx[np->rx_cur].cmdsts; 
-	while ((rx_status & OWN)) {
-		rx_len = (rx_status & DSIZE) - CRC_SIZE;
-
-                DBG ("Received packet, rx_curr = %d, rx_status = %#08x, rx_len = %d\n",
-                     np->rx_cur, rx_status, rx_len);
-                
-		if ((rx_status & (DescMore | DescPktOK | RxTooLong)) != DescPktOK) {
-			netdev_rx_err (netdev, NULL, -EINVAL);
-
-			DBG ("natsemi_poll: Corrupted packet received!"
-			     " Status = %#08x\n",
-			      np->rx[np->rx_cur].cmdsts);
-
-		} else 	{
-
-
-			/* If unable allocate space for this packet,
-			 *  try again next poll
-			 */
-			rx_iob = alloc_iob (rx_len);
-			if (! rx_iob) 
-				goto end;
-			memcpy (iob_put (rx_iob, rx_len), 
-				np->iobuf[np->rx_cur]->data, rx_len);
-			/* Add this packet to the receive queue. 
-			 */
-			netdev_rx (netdev, rx_iob);
+}
+
+/**
+ * Poll for received packets
+ *
+ * @v netdev		Network device
+ */
+static void natsemi_poll_rx ( struct net_device *netdev ) {
+	struct natsemi_nic *natsemi = netdev->priv;
+	union natsemi_descriptor *rx;
+	struct io_buffer *iobuf;
+	unsigned int rx_idx;
+	size_t len;
+
+	/* Check for received packets */
+	while ( natsemi->rx.cons != natsemi->rx.prod ) {
+
+		/* Get next receive descriptor */
+		rx_idx = ( natsemi->rx.cons % NATSEMI_NUM_RX_DESC );
+		rx = &natsemi->rx.desc[rx_idx];
+
+		/* Stop if descriptor is still in use */
+		if ( ! ( rx->common.cmdsts & NATSEMI_DESC_OWN ) )
+			return;
+
+		/* Populate I/O buffer */
+		iobuf = natsemi->rx_iobuf[rx_idx];
+		natsemi->rx_iobuf[rx_idx] = NULL;
+		len = ( le32_to_cpu ( rx->common.cmdsts ) &
+			NATSEMI_DESC_SIZE_MASK );
+		iob_put ( iobuf, len - 4 /* strip CRC */ );
+
+		/* Hand off to network stack */
+		if ( rx->common.cmdsts & cpu_to_le32 ( NATSEMI_DESC_OK ) ) {
+			DBGC2 ( natsemi, "NATSEMI %p RX %d complete (length "
+				"%zd)\n", natsemi, rx_idx, len );
+			netdev_rx ( netdev, iobuf );
+		} else {
+			DBGC ( natsemi, "NATSEMI %p RX %d error (length %zd, "
+			       "status %08x)\n", natsemi, rx_idx, len,
+			       le32_to_cpu ( rx->common.cmdsts ) );
+			netdev_rx_err ( netdev, iobuf, -EIO );
 		}
-		np->rx[np->rx_cur].cmdsts = RX_BUF_SIZE;
-		np->rx_cur = (np->rx_cur + 1) % NUM_RX_DESC;
-		rx_status = np->rx[np->rx_cur].cmdsts; 
+		natsemi->rx.cons++;
 	}
-end:
-	/* re-enable the potentially idle receive state machine 
+}
+
+/**
+ * Poll for completed and received packets
+ *
+ * @v netdev		Network device
+ */
+static void natsemi_poll ( struct net_device *netdev ) {
+	struct natsemi_nic *natsemi = netdev->priv;
+	uint32_t isr;
+
+	/* Poll for link state.  The PHY interrupt seems not to
+	 * function as expected, and polling for the link state is
+	 * only a single register read.
 	 */
-	outl (RxOn, np->ioaddr + ChipCmd);	
-}				
+	natsemi_check_link ( netdev );
+
+	/* Check for and acknowledge interrupts */
+	isr = readl ( natsemi->regs + NATSEMI_ISR );
+	if ( ! isr )
+		return;
+
+	/* Poll for TX completions, if applicable */
+	if ( isr & NATSEMI_IRQ_TXDESC )
+		natsemi_poll_tx ( netdev );
+
+	/* Poll for RX completionsm, if applicable */
+	if ( isr & NATSEMI_IRQ_RXDESC )
+		natsemi_poll_rx ( netdev );
+
+	/* Refill RX ring */
+	natsemi_refill_rx ( netdev );
+}
+
+/**
+ * Enable or disable interrupts
+ *
+ * @v netdev		Network device
+ * @v enable		Interrupts should be enabled
+ */
+static void natsemi_irq ( struct net_device *netdev, int enable ) {
+	struct natsemi_nic *natsemi = netdev->priv;
+
+	/* Enable or disable interrupts */
+	writel ( ( enable ? NATSEMI_IER_IE : 0 ), natsemi->regs + NATSEMI_IER );
+}
+
+/** National Semiconductor network device operations */
+static struct net_device_operations natsemi_operations = {
+	.open		= natsemi_open,
+	.close		= natsemi_close,
+	.transmit	= natsemi_transmit,
+	.poll		= natsemi_poll,
+	.irq		= natsemi_irq,
+};
+
+/******************************************************************************
+ *
+ * PCI interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Probe PCI device
+ *
+ * @v pci		PCI device
+ * @ret rc		Return status code
+ */
+static int natsemi_probe ( struct pci_device *pci ) {
+	struct net_device *netdev;
+	struct natsemi_nic *natsemi;
+	int rc;
+
+	/* Allocate and initialise net device */
+	netdev = alloc_etherdev ( sizeof ( *natsemi ) );
+	if ( ! netdev ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	netdev_init ( netdev, &natsemi_operations );
+	natsemi = netdev->priv;
+	pci_set_drvdata ( pci, netdev );
+	netdev->dev = &pci->dev;
+	memset ( natsemi, 0, sizeof ( *natsemi ) );
+	natsemi->flags = pci->id->driver_data;
+	natsemi_init_ring ( &natsemi->tx, NATSEMI_NUM_TX_DESC, NATSEMI_TXDP );
+	natsemi_init_ring ( &natsemi->rx, NATSEMI_NUM_RX_DESC, NATSEMI_RXDP );
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pci );
+
+	/* Map registers */
+	natsemi->regs = ioremap ( pci->membase, NATSEMI_BAR_SIZE );
+
+	/* Reset the NIC */
+	if ( ( rc = natsemi_reset ( natsemi ) ) != 0 )
+		goto err_reset;
+
+	/* Initialise EEPROM */
+	natsemi_init_eeprom ( natsemi );
+
+	/* Read initial MAC address */
+	if ( ( rc = natsemi_hwaddr ( natsemi, netdev->hw_addr ) ) != 0 )
+		goto err_hwaddr;
+
+	/* Register network device */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
+		goto err_register_netdev;
+
+	/* Set initial link state */
+	natsemi_check_link ( netdev );
+
+	return 0;
+
+	unregister_netdev ( netdev );
+ err_register_netdev:
+ err_hwaddr:
+	natsemi_reset ( natsemi );
+ err_reset:
+	iounmap ( natsemi->regs );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+ err_alloc:
+	return rc;
+}
 
 /**
- * Enable/disable interrupts
+ * Remove PCI device
  *
- * @v netdev    Network device
- * @v enable    Non-zero for enable, zero for disable
+ * @v pci		PCI device
  */
-static void natsemi_irq (struct net_device *netdev, int enable)
-{
-        struct natsemi_private *np = netdev->priv;
+static void natsemi_remove ( struct pci_device *pci ) {
+	struct net_device *netdev = pci_get_drvdata ( pci );
+	struct natsemi_nic *natsemi = netdev->priv;
+
+	/* Unregister network device */
+	unregister_netdev ( netdev );
 
-	outl ((enable ? (RxOk | RxErr | TxOk|TxErr) : 0),
-	      np->ioaddr + IntrMask); 
-	outl ((enable ? 1 : 0), np->ioaddr + IntrEnable);
+	/* Reset card */
+	natsemi_reset ( natsemi );
+
+	/* Free network device */
+	iounmap ( natsemi->regs );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
 }
 
+/** Flags for DP83815 */
+#define DP83815_FLAGS ( NATSEMI_EEPROM_LITTLE_ENDIAN | NATSEMI_EEPROM_INSANE )
+
+/** Flags for DP83820 */
+#define DP83820_FLAGS ( NATSEMI_64BIT | NATSEMI_1000 )
+
+/** National Semiconductor PCI device IDs */
 static struct pci_device_id natsemi_nics[] = {
-	PCI_ROM(0x100b, 0x0020, "dp83815", "DP83815", 0),
+	PCI_ROM ( 0x100b, 0x0020, "dp83815", "DP83815", DP83815_FLAGS ),
+	PCI_ROM ( 0x100b, 0x0022, "dp83820", "DP83820", DP83820_FLAGS ),
 };
 
+/** National Semiconductor PCI driver */
 struct pci_driver natsemi_driver __pci_driver = {
 	.ids = natsemi_nics,
-	.id_count = (sizeof (natsemi_nics) / sizeof (natsemi_nics[0])),
+	.id_count = ( sizeof ( natsemi_nics ) / sizeof ( natsemi_nics[0] ) ),
 	.probe = natsemi_probe,
 	.remove = natsemi_remove,
 };
diff --git a/roms/ipxe/src/drivers/net/natsemi.h b/roms/ipxe/src/drivers/net/natsemi.h
index ae827ba39903a29c19601142ad90..7e8d6f8002d62bc941a4b3ab4176 100644
--- a/roms/ipxe/src/drivers/net/natsemi.h
+++ b/roms/ipxe/src/drivers/net/natsemi.h
@@ -1,232 +1,329 @@
-FILE_LICENCE ( GPL_ANY );
+#ifndef _NATSEMI_H
+#define _NATSEMI_H
 
-#define NATSEMI_HW_TIMEOUT 400
+/** @file
+ *
+ * National Semiconductor "MacPhyter" network card driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
 
-#define TX_RING_SIZE 4
-#define NUM_RX_DESC  4
-#define RX_BUF_SIZE 1536
-#define OWN       0x80000000
-#define DSIZE     0x00000FFF
-#define CRC_SIZE  4
+#include <stdint.h>
+#include <ipxe/spi.h>
+#include <ipxe/spi_bit.h>
 
-struct natsemi_tx {
+/** BAR size */
+#define NATSEMI_BAR_SIZE 0x100
+
+/** A 32-bit packet descriptor */
+struct natsemi_descriptor_32 {
+	/** Link to next descriptor */
 	uint32_t link;
+	/** Command / status */
 	uint32_t cmdsts;
+	/** Buffer pointer */
 	uint32_t bufptr;
-};
+} __attribute__ (( packed ));
 
-struct natsemi_rx {
-	uint32_t link;
+/** A 64-bit packet descriptor */
+struct natsemi_descriptor_64 {
+	/** Link to next descriptor */
+	uint64_t link;
+	/** Buffer pointer */
+	uint64_t bufptr;
+	/** Command / status */
 	uint32_t cmdsts;
-	uint32_t bufptr;
-};
+	/** Extended status */
+	uint32_t extsts;
+} __attribute__ (( packed ));
 
-struct natsemi_private {
-	unsigned short ioaddr;
-	unsigned short tx_cur;
-	unsigned short tx_dirty;
-	unsigned short rx_cur;
-	struct natsemi_tx tx[TX_RING_SIZE];
-	struct natsemi_rx rx[NUM_RX_DESC];
-
-	/* need to add iobuf as we cannot free iobuf->data in close without this 
-	 * alternatively substracting sizeof(head) and sizeof(list_head) can also 
-	 * give the same.
-	 */
-	struct io_buffer *iobuf[NUM_RX_DESC];
-
-	/* netdev_tx_complete needs pointer to the iobuf of the data so as to free 
-	 * it from the memory.
-	 */
-	struct io_buffer *tx_iobuf[TX_RING_SIZE];
-	struct spi_bit_basher spibit;
-	struct spi_device eeprom;
-	struct nvo_block nvo;
+/** A packet descriptor
+ *
+ * The 32-bit and 64-bit variants are overlaid such that "cmdsts" can
+ * be accessed as a common field, and the overall size is a power of
+ * two (to allow the descriptor ring length to be used as an
+ * alignment).
+ */
+union natsemi_descriptor {
+	/** Common fields */
+	struct {
+		/** Reserved */
+		uint8_t reserved_a[16];
+		/** Command / status */
+		uint32_t cmdsts;
+		/** Reserved */
+		uint8_t reserved_b[12];
+	} __attribute__ (( packed )) common;
+	/** 64-bit descriptor */
+	struct natsemi_descriptor_64 d64;
+	/** 32-bit descriptor */
+	struct {
+		/** Reserved */
+		uint8_t reserved[12];
+		/** Descriptor */
+		struct natsemi_descriptor_32 d32;
+	} __attribute__ (( packed )) d32pad;
 };
 
-/*
- * Support for fibre connections on Am79C874:
- * This phy needs a special setup when connected to a fibre cable.
- * http://www.amd.com/files/connectivitysolutions/networking/archivednetworking/22235.pdf
- */
-#define PHYID_AM79C874	0x0022561b
+/** Descriptor buffer size mask */
+#define NATSEMI_DESC_SIZE_MASK 0xfff
 
-enum {
-	MII_MCTRL	= 0x15,		/* mode control register */
-	MII_FX_SEL	= 0x0001,	/* 100BASE-FX (fiber) */
-	MII_EN_SCRM	= 0x0004,	/* enable scrambler (tp) */
+/** Packet descriptor flags */
+enum natsemi_descriptor_flags {
+	/** Descriptor is owned by NIC */
+	NATSEMI_DESC_OWN = 0x80000000UL,
+	/** Request descriptor interrupt */
+	NATSEMI_DESC_INTR = 0x20000000UL,
+	/** Packet OK */
+	NATSEMI_DESC_OK = 0x08000000UL,
 };
 
+/** Command Register */
+#define NATSEMI_CR 0x0000
+#define NATSEMI_CR_RST		0x00000100UL	/**< Reset */
+#define NATSEMI_CR_RXR		0x00000020UL	/**< Receiver reset */
+#define NATSEMI_CR_TXR		0x00000010UL	/**< Transmit reset */
+#define NATSEMI_CR_RXE		0x00000004UL	/**< Receiver enable */
+#define NATSEMI_CR_TXE		0x00000001UL	/**< Transmit enable */
+
+/** Maximum time to wait for a reset, in milliseconds */
+#define NATSEMI_RESET_MAX_WAIT_MS 100
+
+/** Configuration and Media Status Register */
+#define NATSEMI_CFG 0x0004
+#define NATSEMI_CFG_LNKSTS	0x80000000UL	/**< Link status */
+#define NATSEMI_CFG_SPDSTS1	0x40000000UL	/**< Speed status bit 1 */
+#define NATSEMI_CFG_MODE_1000	0x00400000UL	/**< 1000 Mb/s mode control */
+#define NATSEMI_CFG_PCI64_DET	0x00002000UL	/**< PCI 64-bit bus detected */
+#define NATSEMI_CFG_DATA64_EN	0x00001000UL	/**< 64-bit data enable */
+#define NATSEMI_CFG_M64ADDR	0x00000800UL	/**< 64-bit address enable */
+#define NATSEMI_CFG_EXTSTS_EN	0x00000100UL	/**< Extended status enable */
+
+/** EEPROM Access Register */
+#define NATSEMI_MEAR 0x0008
+#define NATSEMI_MEAR_EESEL	0x00000008UL	/**< EEPROM chip select */
+#define NATSEMI_MEAR_EECLK	0x00000004UL	/**< EEPROM serial clock */
+#define NATSEMI_MEAR_EEDO	0x00000002UL	/**< EEPROM data out */
+#define NATSEMI_MEAR_EEDI	0x00000001UL	/**< EEPROM data in */
+
+/** Size of EEPROM (in bytes) */
+#define NATSEMI_EEPROM_SIZE 32
+
+/** Word offset of MAC address within sane EEPROM layout */
+#define NATSEMI_EEPROM_MAC_SANE 0x0a
+
+/** Word offset of MAC address within insane EEPROM layout */
+#define NATSEMI_EEPROM_MAC_INSANE 0x06
+
+/** PCI Test Control Register */
+#define NATSEMI_PTSCR 0x000c
+#define NATSEMI_PTSCR_EELOAD_EN	0x00000004UL	/**< Enable EEPROM load */
+
+/** Maximum time to wait for a configuration reload, in milliseconds */
+#define NATSEMI_EELOAD_MAX_WAIT_MS 100
+
+/** Interrupt Status Register */
+#define NATSEMI_ISR 0x0010
+#define NATSEMI_IRQ_TXDESC	0x00000080UL	/**< TX descriptor */
+#define NATSEMI_IRQ_RXDESC	0x00000002UL	/**< RX descriptor */
+
+/** Interrupt Mask Register */
+#define NATSEMI_IMR 0x0014
+
+/** Interrupt Enable Register */
+#define NATSEMI_IER 0x0018
+#define NATSEMI_IER_IE		0x00000001UL	/**< Interrupt enable */
+
+/** Transmit Descriptor Pointer */
+#define NATSEMI_TXDP 0x0020
+
+/** Transmit Descriptor Pointer High Dword (64-bit) */
+#define NATSEMI_TXDP_HI_64 0x0024
+
+/** Number of transmit descriptors */
+#define NATSEMI_NUM_TX_DESC 4
 
+/** Transmit configuration register (32-bit) */
+#define NATSEMI_TXCFG_32 0x24
 
-/* values we might find in the silicon revision register */
-#define SRR_DP83815_C	0x0302
-#define SRR_DP83815_D	0x0403
-#define SRR_DP83816_A4	0x0504
-#define SRR_DP83816_A5	0x0505
+/** Transmit configuration register (64-bit) */
+#define NATSEMI_TXCFG_64 0x28
+#define NATSEMI_TXCFG_CSI	0x80000000UL	/**< Carrier sense ignore */
+#define NATSEMI_TXCFG_HBI	0x40000000UL	/**< Heartbeat ignore */
+#define NATSEMI_TXCFG_ATP	0x10000000UL	/**< Automatic padding */
+#define NATSEMI_TXCFG_ECRETRY	0x00800000UL	/**< Excess collision retry */
+#define NATSEMI_TXCFG_MXDMA(x)	( (x) << 20 )	/**< Max DMA burst size */
+#define NATSEMI_TXCFG_FLTH(x)	( (x) << 8 )	/**< Fill threshold */
+#define NATSEMI_TXCFG_DRTH(x)	( (x) << 0 )	/**< Drain threshold */
 
-/* NATSEMI: Offsets to the device registers.
- * Unlike software-only systems, device drivers interact with complex hardware.
- * It's not useful to define symbolic names for every register bit in the
- * device.
+/** Max DMA burst size (encoded value)
+ *
+ * This represents 256-byte bursts on 83815 controllers and 512-byte
+ * bursts on 83820 controllers.
  */
-enum register_offsets {
-    ChipCmd      = 0x00, 
-    ChipConfig   = 0x04, 
-    EECtrl       = 0x08, 
-    PCIBusCfg    = 0x0C,
-    IntrStatus   = 0x10, 
-    IntrMask     = 0x14, 
-    IntrEnable   = 0x18,
-    TxRingPtr    = 0x20, 
-    TxConfig     = 0x24,
-    RxRingPtr    = 0x30,
-    RxConfig     = 0x34, 
-    ClkRun       = 0x3C,
-    WOLCmd       = 0x40, 
-    PauseCmd     = 0x44,
-    RxFilterAddr = 0x48, 
-    RxFilterData = 0x4C,
-    BootRomAddr  = 0x50, 
-    BootRomData  = 0x54, 
-    SiliconRev   = 0x58, 
-    StatsCtrl    = 0x5C,
-    StatsData    = 0x60, 
-    RxPktErrs    = 0x60, 
-    RxMissed     = 0x68, 
-    RxCRCErrs    = 0x64,
-    PCIPM        = 0x44,
-    PhyStatus    = 0xC0, 
-    MIntrCtrl    = 0xC4, 
-    MIntrStatus  = 0xC8,
-
-    /* These are from the spec, around page 78... on a separate table. 
-     */
-    PGSEL        = 0xCC, 
-    PMDCSR       = 0xE4, 
-    TSTDAT       = 0xFC, 
-    DSPCFG       = 0xF4, 
-    SDCFG        = 0x8C,
-    BasicControl = 0x80,	
-    BasicStatus  = 0x84
-	    
-};
+#define NATSEMI_TXCFG_MXDMA_DEFAULT NATSEMI_TXCFG_MXDMA ( 0x7 )
 
-/* the values for the 'magic' registers above (PGSEL=1) */
-#define PMDCSR_VAL	0x189c	/* enable preferred adaptation circuitry */
-#define TSTDAT_VAL	0x0
-#define DSPCFG_VAL	0x5040
-#define SDCFG_VAL	0x008c	/* set voltage thresholds for Signal Detect */
-#define DSPCFG_LOCK	0x20	/* coefficient lock bit in DSPCFG */
-#define DSPCFG_COEF	0x1000	/* see coefficient (in TSTDAT) bit in DSPCFG */
-#define TSTDAT_FIXED	0xe8	/* magic number for bad coefficients */
+/** Fill threshold (in units of 32 bytes)
+ *
+ * Must be at least as large as the max DMA burst size, so use a value
+ * of 512 bytes.
+ */
+#define NATSEMI_TXCFG_FLTH_DEFAULT NATSEMI_TXCFG_FLTH ( 512 / 32 )
 
-/* Bit in ChipCmd.
+/** Drain threshold (in units of 32 bytes)
+ *
+ * Start transmission once we receive a conservative 1024 bytes, to
+ * avoid FIFO underrun errors.  (83815 does not allow us to specify a
+ * value of 0 for "wait until whole packet is present".)
+ *
+ * Fill threshold plus drain threshold must be less than the transmit
+ * FIFO size, which is 2kB on 83815 and 8kB on 83820.
  */
-enum ChipCmdBits {
-    ChipReset = 0x100, 
-    RxReset   = 0x20, 
-    TxReset   = 0x10, 
-    RxOff     = 0x08, 
-    RxOn      = 0x04,
-    TxOff     = 0x02, 
-    TxOn      = 0x01
-};
+#define NATSEMI_TXCFG_DRTH_DEFAULT NATSEMI_TXCFG_DRTH ( 1024 / 32 )
 
-enum ChipConfig_bits {
-	CfgPhyDis		= 0x200,
-	CfgPhyRst		= 0x400,
-	CfgExtPhy		= 0x1000,
-	CfgAnegEnable		= 0x2000,
-	CfgAneg100		= 0x4000,
-	CfgAnegFull		= 0x8000,
-	CfgAnegDone		= 0x8000000,
-	CfgFullDuplex		= 0x20000000,
-	CfgSpeed100		= 0x40000000,
-	CfgLink			= 0x80000000,
-};
+/** Receive Descriptor Pointer */
+#define NATSEMI_RXDP 0x0030
 
+/** Receive Descriptor Pointer High Dword (64-bit) */
+#define NATSEMI_RXDP_HI_64 0x0034
 
-/* Bits in the RxMode register.
- */
-enum rx_mode_bits {
-    AcceptErr          = 0x20,
-    AcceptRunt         = 0x10,
-    AcceptBroadcast    = 0xC0000000,
-    AcceptMulticast    = 0x00200000, 
-    AcceptAllMulticast = 0x20000000,
-    AcceptAllPhys      = 0x10000000, 
-    AcceptMyPhys       = 0x08000000,
-    RxFilterEnable     = 0x80000000
-};
+/** Number of receive descriptors */
+#define NATSEMI_NUM_RX_DESC 4
+
+/** Receive buffer length */
+#define NATSEMI_RX_MAX_LEN ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ )
 
-/* Bits in network_desc.status
+/** Receive configuration register (32-bit) */
+#define NATSEMI_RXCFG_32 0x34
+
+/** Receive configuration register (64-bit) */
+#define NATSEMI_RXCFG_64 0x38
+#define NATSEMI_RXCFG_ARP	0x40000000UL	/**< Accept runt packets */
+#define NATSEMI_RXCFG_ATX	0x10000000UL	/**< Accept transmit packets */
+#define NATSEMI_RXCFG_ALP	0x08000000UL	/**< Accept long packets */
+#define NATSEMI_RXCFG_MXDMA(x)	( (x) << 20 )	/**< Max DMA burst size */
+#define NATSEMI_RXCFG_DRTH(x)	( (x) << 1 )	/**< Drain threshold */
+
+/** Max DMA burst size (encoded value)
+ *
+ * This represents 256-byte bursts on 83815 controllers and 512-byte
+ * bursts on 83820 controllers.
  */
-enum desc_status_bits {
-    DescOwn   = 0x80000000, 
-    DescMore  = 0x40000000, 
-    DescIntr  = 0x20000000,
-    DescNoCRC = 0x10000000,
-    DescPktOK = 0x08000000, 
-    RxTooLong = 0x00400000
-};
+#define NATSEMI_RXCFG_MXDMA_DEFAULT NATSEMI_RXCFG_MXDMA ( 0x7 )
 
-/*Bits in Interrupt Mask register
+/** Drain threshold (in units of 8 bytes)
+ *
+ * Start draining after 64 bytes.
+ *
+ * Must be large enough to allow packet's accept/reject status to be
+ * determined before draining begins.
  */
-enum Intr_mask_register_bits {
-    RxOk       = 0x001,
-    RxErr      = 0x004,
-    TxOk       = 0x040,
-    TxErr      = 0x100 
-};	
-
-enum MIntrCtrl_bits {
-  MICRIntEn               = 0x2,
-};
+#define NATSEMI_RXCFG_DRTH_DEFAULT NATSEMI_RXCFG_DRTH ( 64 / 8 )
+
+/** Receive Filter/Match Control Register */
+#define NATSEMI_RFCR 0x0048
+#define NATSEMI_RFCR_RFEN	0x80000000UL	/**< RX filter enable */
+#define NATSEMI_RFCR_AAB	0x40000000UL	/**< Accept all broadcast */
+#define NATSEMI_RFCR_AAM	0x20000000UL	/**< Accept all multicast */
+#define NATSEMI_RFCR_AAU	0x10000000UL	/**< Accept all unicast */
+#define NATSEMI_RFCR_RFADDR( addr ) ( (addr) << 0 ) /**< Extended address */
+#define NATSEMI_RFCR_RFADDR_MASK NATSEMI_RFCR_RFADDR ( 0x3ff )
+
+/** Perfect match filter address base */
+#define NATSEMI_RFADDR_PMATCH_BASE 0x000
 
-/* CFG bits [13:16] [18:23] */
-#define CFG_RESET_SAVE 0xfde000
-/* WCSR bits [0:4] [9:10] */
-#define WCSR_RESET_SAVE 0x61f
-/* RFCR bits [20] [22] [27:31] */
-#define RFCR_RESET_SAVE 0xf8500000;
-
-/* Delay between EEPROM clock transitions.
-   No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need
-   a delay. */
-#define eeprom_delay(ee_addr)   inl(ee_addr)
-
-enum EEPROM_Ctrl_Bits {
-	EE_ShiftClk   = 0x04,
-	EE_DataIn     = 0x01,
-	EE_ChipSelect = 0x08,
-	EE_DataOut    = 0x02
+/** Receive Filter/Match Data Register */
+#define NATSEMI_RFDR 0x004c
+#define NATSEMI_RFDR_BMASK	0x00030000UL	/**< Byte mask */
+#define NATSEMI_RFDR_DATA( value ) ( (value) & 0xffff ) /**< Filter data */
+
+/** National Semiconductor network card flags */
+enum natsemi_nic_flags {
+	/** EEPROM is little-endian */
+	NATSEMI_EEPROM_LITTLE_ENDIAN = 0x0001,
+	/** EEPROM layout is insane */
+	NATSEMI_EEPROM_INSANE = 0x0002,
+	/** Card supports 64-bit operation */
+	NATSEMI_64BIT = 0x0004,
+	/** Card supports 1000Mbps link */
+	NATSEMI_1000 = 0x0008,
 };
 
-#define EE_Write0 (EE_ChipSelect)
-#define EE_Write1 (EE_ChipSelect | EE_DataIn)
+/** A National Semiconductor descriptor ring */
+struct natsemi_ring {
+	/** Descriptors */
+	union natsemi_descriptor *desc;
+	/** Producer index */
+	unsigned int prod;
+	/** Consumer index */
+	unsigned int cons;
 
-/* The EEPROM commands include the alway-set leading bit. */
-enum EEPROM_Cmds {
-  EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
+	/** Number of descriptors */
+	unsigned int count;
+	/** Descriptor start address register */
+	unsigned int reg;
 };
 
-/*  EEPROM access , values are devices specific
+/**
+ * Initialise descriptor ring
+ *
+ * @v ring		Descriptor ring
+ * @v count		Number of descriptors
+ * @v reg		Descriptor start address register
  */
-#define EE_CS		0x08	/* EEPROM chip select */
-#define EE_SK		0x04	/* EEPROM shift clock */
-#define EE_DI		0x01	/* Data in */
-#define EE_DO		0x02	/* Data out */
+static inline __attribute__ (( always_inline)) void
+natsemi_init_ring ( struct natsemi_ring *ring, unsigned int count,
+		    unsigned int reg ) {
+	ring->count = count;
+	ring->reg = reg;
+}
 
-/* Offsets within EEPROM (these are word offsets)
- */
-#define EE_MAC 7
-#define EE_REG  EECtrl
-
-static const uint8_t natsemi_ee_bits[] = {
-	[SPI_BIT_SCLK]	= EE_SK,
-	[SPI_BIT_MOSI]	= EE_DI,
-	[SPI_BIT_MISO]	= EE_DO,
-	[SPI_BIT_SS(0)]	= EE_CS,
+/** A National Semiconductor network card */
+struct natsemi_nic {
+	/** Flags */
+	unsigned int flags;
+	/** Registers */
+	void *regs;
+	/** SPI bit-bashing interface */
+	struct spi_bit_basher spibit;
+	/** EEPROM */
+	struct spi_device eeprom;
+
+	/** Transmit descriptor ring */
+	struct natsemi_ring tx;
+	/** Receive descriptor ring */
+	struct natsemi_ring rx;
+	/** Receive I/O buffers */
+	struct io_buffer *rx_iobuf[NATSEMI_NUM_RX_DESC];
+
+	/** Link status (cache) */
+	uint32_t cfg;
 };
 
+/**
+ * Check if card can access physical address
+ *
+ * @v natsemi		National Semiconductor device
+ * @v address		Physical address
+ * @v address_ok	Card can access physical address
+ */
+static inline __attribute__ (( always_inline )) int
+natsemi_address_ok ( struct natsemi_nic *natsemi, physaddr_t address ) {
+
+	/* In a 32-bit build, all addresses can be accessed */
+	if ( sizeof ( physaddr_t ) <= sizeof ( uint32_t ) )
+		return 1;
+
+	/* A 64-bit card can access all addresses */
+	if ( natsemi->flags & NATSEMI_64BIT )
+		return 1;
+
+	/* A 32-bit card can access all addresses below 4GB */
+	if ( ( address & ~0xffffffffULL ) == 0 )
+		return 1;
+
+	return 0;
+}
+
+#endif /* _NATSEMI_H */
diff --git a/roms/ipxe/src/drivers/net/ns83820.c b/roms/ipxe/src/drivers/net/ns83820.c
deleted file mode 100644
index 0b92a91b4f166bce9aed46838936103595866d66..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/ns83820.c
+++ /dev/null
@@ -1,1007 +0,0 @@
-/**************************************************************************
-*    ns83820.c: Etherboot device driver for the National Semiconductor 83820
-*    Written 2004 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:
-*	ns83820.c by Benjamin LaHaise with contributions
-* 		for Linux kernel 2.4.x.
-*	
-*    Linux Driver Version 0.20, 20020610
-* 
-*    This development of this Etherboot driver was funded by:
-*
-*    NXTV: http://www.nxtv.com/
-*    	
-*    REVISION HISTORY:
-*    ================
-*
-*    v1.0	02-16-2004	timlegge	Initial port of Linux driver
-*    v1.1	02-19-2004	timlegge	More rohbust transmit and poll
-*    
-*    Indent Options: indent -kr -i8
-***************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/* to get some global routines like printf */
-#include "etherboot.h"
-/* to get the interface to the body of the program */
-#include "nic.h"
-/* to get the PCI support functions, if this is a PCI NIC */
-#include <ipxe/pci.h>
-
-#if ARCH == ia64		/* Support 64-bit addressing */
-#define USE_64BIT_ADDR
-#endif
-
-#define HZ 100
-
-/* 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))
-
-/* NIC specific static variables go here */
-
-/* Global parameters.  See MODULE_PARM near the bottom. */
-// static int ihr = 2;
-static int reset_phy = 0;
-static int lnksts = 0;		/* CFG_LNKSTS bit polarity */
-
-#if defined(CONFIG_HIGHMEM64G) || defined(__ia64__)
-#define USE_64BIT_ADDR	"+"
-#endif
-
-#if defined(USE_64BIT_ADDR)
-#define TRY_DAC	1
-#else
-#define TRY_DAC	0
-#endif
-
-/* tunables */
-#define RX_BUF_SIZE	1500	/* 8192 */
-
-/* Must not exceed ~65000. */
-#define NR_RX_DESC	64
-#define NR_TX_DESC	1
-
-		   /* not tunable *//* Extra 6 bytes for 64 bit alignment (divisable by 8) */
-#define REAL_RX_BUF_SIZE (RX_BUF_SIZE + 14 + 6)	/* rx/tx mac addr + type */
-
-#define MIN_TX_DESC_FREE	8
-
-/* register defines */
-#define CFGCS		0x04
-
-#define CR_TXE		0x00000001
-#define CR_TXD		0x00000002
-/* Ramit : Here's a tip, don't do a RXD immediately followed by an RXE
- * The Receive engine skips one descriptor and moves
- * onto the next one!! */
-#define CR_RXE		0x00000004
-#define CR_RXD		0x00000008
-#define CR_TXR		0x00000010
-#define CR_RXR		0x00000020
-#define CR_SWI		0x00000080
-#define CR_RST		0x00000100
-
-#define PTSCR_EEBIST_FAIL       0x00000001
-#define PTSCR_EEBIST_EN         0x00000002
-#define PTSCR_EELOAD_EN         0x00000004
-#define PTSCR_RBIST_FAIL        0x000001b8
-#define PTSCR_RBIST_DONE        0x00000200
-#define PTSCR_RBIST_EN          0x00000400
-#define PTSCR_RBIST_RST         0x00002000
-
-#define MEAR_EEDI		0x00000001
-#define MEAR_EEDO		0x00000002
-#define MEAR_EECLK		0x00000004
-#define MEAR_EESEL		0x00000008
-#define MEAR_MDIO		0x00000010
-#define MEAR_MDDIR		0x00000020
-#define MEAR_MDC		0x00000040
-
-#define ISR_TXDESC3	0x40000000
-#define ISR_TXDESC2	0x20000000
-#define ISR_TXDESC1	0x10000000
-#define ISR_TXDESC0	0x08000000
-#define ISR_RXDESC3	0x04000000
-#define ISR_RXDESC2	0x02000000
-#define ISR_RXDESC1	0x01000000
-#define ISR_RXDESC0	0x00800000
-#define ISR_TXRCMP	0x00400000
-#define ISR_RXRCMP	0x00200000
-#define ISR_DPERR	0x00100000
-#define ISR_SSERR	0x00080000
-#define ISR_RMABT	0x00040000
-#define ISR_RTABT	0x00020000
-#define ISR_RXSOVR	0x00010000
-#define ISR_HIBINT	0x00008000
-#define ISR_PHY		0x00004000
-#define ISR_PME		0x00002000
-#define ISR_SWI		0x00001000
-#define ISR_MIB		0x00000800
-#define ISR_TXURN	0x00000400
-#define ISR_TXIDLE	0x00000200
-#define ISR_TXERR	0x00000100
-#define ISR_TXDESC	0x00000080
-#define ISR_TXOK	0x00000040
-#define ISR_RXORN	0x00000020
-#define ISR_RXIDLE	0x00000010
-#define ISR_RXEARLY	0x00000008
-#define ISR_RXERR	0x00000004
-#define ISR_RXDESC	0x00000002
-#define ISR_RXOK	0x00000001
-
-#define TXCFG_CSI	0x80000000
-#define TXCFG_HBI	0x40000000
-#define TXCFG_MLB	0x20000000
-#define TXCFG_ATP	0x10000000
-#define TXCFG_ECRETRY	0x00800000
-#define TXCFG_BRST_DIS	0x00080000
-#define TXCFG_MXDMA1024	0x00000000
-#define TXCFG_MXDMA512	0x00700000
-#define TXCFG_MXDMA256	0x00600000
-#define TXCFG_MXDMA128	0x00500000
-#define TXCFG_MXDMA64	0x00400000
-#define TXCFG_MXDMA32	0x00300000
-#define TXCFG_MXDMA16	0x00200000
-#define TXCFG_MXDMA8	0x00100000
-
-#define CFG_LNKSTS	0x80000000
-#define CFG_SPDSTS	0x60000000
-#define CFG_SPDSTS1	0x40000000
-#define CFG_SPDSTS0	0x20000000
-#define CFG_DUPSTS	0x10000000
-#define CFG_TBI_EN	0x01000000
-#define CFG_MODE_1000	0x00400000
-/* Ramit : Dont' ever use AUTO_1000, it never works and is buggy.
- * Read the Phy response and then configure the MAC accordingly */
-#define CFG_AUTO_1000	0x00200000
-#define CFG_PINT_CTL	0x001c0000
-#define CFG_PINT_DUPSTS	0x00100000
-#define CFG_PINT_LNKSTS	0x00080000
-#define CFG_PINT_SPDSTS	0x00040000
-#define CFG_TMRTEST	0x00020000
-#define CFG_MRM_DIS	0x00010000
-#define CFG_MWI_DIS	0x00008000
-#define CFG_T64ADDR	0x00004000
-#define CFG_PCI64_DET	0x00002000
-#define CFG_DATA64_EN	0x00001000
-#define CFG_M64ADDR	0x00000800
-#define CFG_PHY_RST	0x00000400
-#define CFG_PHY_DIS	0x00000200
-#define CFG_EXTSTS_EN	0x00000100
-#define CFG_REQALG	0x00000080
-#define CFG_SB		0x00000040
-#define CFG_POW		0x00000020
-#define CFG_EXD		0x00000010
-#define CFG_PESEL	0x00000008
-#define CFG_BROM_DIS	0x00000004
-#define CFG_EXT_125	0x00000002
-#define CFG_BEM		0x00000001
-
-#define EXTSTS_UDPPKT	0x00200000
-#define EXTSTS_TCPPKT	0x00080000
-#define EXTSTS_IPPKT	0x00020000
-
-#define SPDSTS_POLARITY	(CFG_SPDSTS1 | CFG_SPDSTS0 | CFG_DUPSTS | (lnksts ? CFG_LNKSTS : 0))
-
-#define MIBC_MIBS	0x00000008
-#define MIBC_ACLR	0x00000004
-#define MIBC_FRZ	0x00000002
-#define MIBC_WRN	0x00000001
-
-#define PCR_PSEN	(1 << 31)
-#define PCR_PS_MCAST	(1 << 30)
-#define PCR_PS_DA	(1 << 29)
-#define PCR_STHI_8	(3 << 23)
-#define PCR_STLO_4	(1 << 23)
-#define PCR_FFHI_8K	(3 << 21)
-#define PCR_FFLO_4K	(1 << 21)
-#define PCR_PAUSE_CNT	0xFFFE
-
-#define RXCFG_AEP	0x80000000
-#define RXCFG_ARP	0x40000000
-#define RXCFG_STRIPCRC	0x20000000
-#define RXCFG_RX_FD	0x10000000
-#define RXCFG_ALP	0x08000000
-#define RXCFG_AIRL	0x04000000
-#define RXCFG_MXDMA512	0x00700000
-#define RXCFG_DRTH	0x0000003e
-#define RXCFG_DRTH0	0x00000002
-
-#define RFCR_RFEN	0x80000000
-#define RFCR_AAB	0x40000000
-#define RFCR_AAM	0x20000000
-#define RFCR_AAU	0x10000000
-#define RFCR_APM	0x08000000
-#define RFCR_APAT	0x07800000
-#define RFCR_APAT3	0x04000000
-#define RFCR_APAT2	0x02000000
-#define RFCR_APAT1	0x01000000
-#define RFCR_APAT0	0x00800000
-#define RFCR_AARP	0x00400000
-#define RFCR_MHEN	0x00200000
-#define RFCR_UHEN	0x00100000
-#define RFCR_ULM	0x00080000
-
-#define VRCR_RUDPE	0x00000080
-#define VRCR_RTCPE	0x00000040
-#define VRCR_RIPE	0x00000020
-#define VRCR_IPEN	0x00000010
-#define VRCR_DUTF	0x00000008
-#define VRCR_DVTF	0x00000004
-#define VRCR_VTREN	0x00000002
-#define VRCR_VTDEN	0x00000001
-
-#define VTCR_PPCHK	0x00000008
-#define VTCR_GCHK	0x00000004
-#define VTCR_VPPTI	0x00000002
-#define VTCR_VGTI	0x00000001
-
-#define CR		0x00
-#define CFG		0x04
-#define MEAR		0x08
-#define PTSCR		0x0c
-#define	ISR		0x10
-#define	IMR		0x14
-#define	IER		0x18
-#define	IHR		0x1c
-#define TXDP		0x20
-#define TXDP_HI		0x24
-#define TXCFG		0x28
-#define GPIOR		0x2c
-#define RXDP		0x30
-#define RXDP_HI		0x34
-#define RXCFG		0x38
-#define PQCR		0x3c
-#define WCSR		0x40
-#define PCR		0x44
-#define RFCR		0x48
-#define RFDR		0x4c
-
-#define SRR		0x58
-
-#define VRCR		0xbc
-#define VTCR		0xc0
-#define VDR		0xc4
-#define CCSR		0xcc
-
-#define TBICR		0xe0
-#define TBISR		0xe4
-#define TANAR		0xe8
-#define TANLPAR		0xec
-#define TANER		0xf0
-#define TESR		0xf4
-
-#define TBICR_MR_AN_ENABLE	0x00001000
-#define TBICR_MR_RESTART_AN	0x00000200
-
-#define TBISR_MR_LINK_STATUS	0x00000020
-#define TBISR_MR_AN_COMPLETE	0x00000004
-
-#define TANAR_PS2 		0x00000100
-#define TANAR_PS1 		0x00000080
-#define TANAR_HALF_DUP 		0x00000040
-#define TANAR_FULL_DUP 		0x00000020
-
-#define GPIOR_GP5_OE		0x00000200
-#define GPIOR_GP4_OE		0x00000100
-#define GPIOR_GP3_OE		0x00000080
-#define GPIOR_GP2_OE		0x00000040
-#define GPIOR_GP1_OE		0x00000020
-#define GPIOR_GP3_OUT		0x00000004
-#define GPIOR_GP1_OUT		0x00000001
-
-#define LINK_AUTONEGOTIATE	0x01
-#define LINK_DOWN		0x02
-#define LINK_UP			0x04
-
-
-#define __kick_rx()	writel(CR_RXE, ns->base + CR)
-
-#define kick_rx() do { \
-	DBG("kick_rx: maybe kicking\n"); \
-		writel(virt_to_le32desc(&rx_ring[ns->cur_rx]), ns->base + RXDP); \
-		if (ns->next_rx == ns->next_empty) \
-			printf("uh-oh: next_rx == next_empty???\n"); \
-		__kick_rx(); \
-} while(0)
-
-
-#ifdef USE_64BIT_ADDR
-#define HW_ADDR_LEN	8
-#else
-#define HW_ADDR_LEN	4
-#endif
-
-#define CMDSTS_OWN	0x80000000
-#define CMDSTS_MORE	0x40000000
-#define CMDSTS_INTR	0x20000000
-#define CMDSTS_ERR	0x10000000
-#define CMDSTS_OK	0x08000000
-#define CMDSTS_LEN_MASK	0x0000ffff
-
-#define CMDSTS_DEST_MASK	0x01800000
-#define CMDSTS_DEST_SELF	0x00800000
-#define CMDSTS_DEST_MULTI	0x01000000
-
-#define DESC_SIZE	8	/* Should be cache line sized */
-
-#ifdef USE_64BIT_ADDR
-struct ring_desc {
-	uint64_t link;
-	uint64_t bufptr;
-	u32 cmdsts;
-	u32 extsts;		/* Extended status field */
-};
-#else
-struct ring_desc {
-	u32 link;
-	u32 bufptr;
-	u32 cmdsts;
-	u32 extsts;		/* Extended status field */
-};
-#endif
-
-/* Private Storage for the NIC */
-static struct ns83820_private {
-	u8 *base;
-	int up;
-	long idle;
-	u32 *next_rx_desc;
-	u16 next_rx, next_empty;
-	u32 cur_rx;
-	u32 *descs;
-	unsigned ihr;
-	u32 CFG_cache;
-	u32 MEAR_cache;
-	u32 IMR_cache;
-	int linkstate;
-	u16 tx_done_idx;
-	u16 tx_idx;
-	u16 tx_intr_idx;
-	u32 phy_descs;
-	u32 *tx_descs;
-
-} nsx;
-static struct ns83820_private *ns;
-
-/* Define the TX and RX Descriptor and Buffers */
-struct {
-	struct ring_desc tx_ring[NR_TX_DESC] __attribute__ ((aligned(8)));
-	unsigned char txb[NR_TX_DESC * REAL_RX_BUF_SIZE];
-	struct ring_desc rx_ring[NR_RX_DESC] __attribute__ ((aligned(8)));
-	unsigned char rxb[NR_RX_DESC * REAL_RX_BUF_SIZE]
-	__attribute__ ((aligned(8)));
-} ns83820_bufs __shared;
-#define tx_ring ns83820_bufs.tx_ring
-#define rx_ring ns83820_bufs.rx_ring
-#define txb ns83820_bufs.txb
-#define rxb ns83820_bufs.rxb
-
-static void phy_intr(struct nic *nic __unused)
-{
-	static char *speeds[] =
-	    { "10", "100", "1000", "1000(?)", "1000F" };
-	u32 cfg, new_cfg;
-	u32 tbisr, tanar, tanlpar;
-	int speed, fullduplex, newlinkstate;
-
-	cfg = readl(ns->base + CFG) ^ SPDSTS_POLARITY;
-	if (ns->CFG_cache & CFG_TBI_EN) {
-		/* we have an optical transceiver */
-		tbisr = readl(ns->base + TBISR);
-		tanar = readl(ns->base + TANAR);
-		tanlpar = readl(ns->base + TANLPAR);
-		DBG("phy_intr: tbisr=%hX, tanar=%hX, tanlpar=%hX\n",
-		    tbisr, tanar, tanlpar);
-
-		if ((fullduplex = (tanlpar & TANAR_FULL_DUP)
-		     && (tanar & TANAR_FULL_DUP))) {
-
-			/* both of us are full duplex */
-			writel(readl(ns->base + TXCFG)
-			       | TXCFG_CSI | TXCFG_HBI | TXCFG_ATP,
-			       ns->base + TXCFG);
-			writel(readl(ns->base + RXCFG) | RXCFG_RX_FD,
-			       ns->base + RXCFG);
-			/* Light up full duplex LED */
-			writel(readl(ns->base + GPIOR) | GPIOR_GP1_OUT,
-			       ns->base + GPIOR);
-
-		} else if (((tanlpar & TANAR_HALF_DUP)
-			    && (tanar & TANAR_HALF_DUP))
-			   || ((tanlpar & TANAR_FULL_DUP)
-			       && (tanar & TANAR_HALF_DUP))
-			   || ((tanlpar & TANAR_HALF_DUP)
-			       && (tanar & TANAR_FULL_DUP))) {
-
-			/* one or both of us are half duplex */
-			writel((readl(ns->base + TXCFG)
-				& ~(TXCFG_CSI | TXCFG_HBI)) | TXCFG_ATP,
-			       ns->base + TXCFG);
-			writel(readl(ns->base + RXCFG) & ~RXCFG_RX_FD,
-			       ns->base + RXCFG);
-			/* Turn off full duplex LED */
-			writel(readl(ns->base + GPIOR) & ~GPIOR_GP1_OUT,
-			       ns->base + GPIOR);
-		}
-
-		speed = 4;	/* 1000F */
-
-	} else {
-		/* we have a copper transceiver */
-		new_cfg =
-		    ns->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS);
-
-		if (cfg & CFG_SPDSTS1)
-			new_cfg |= CFG_MODE_1000;
-		else
-			new_cfg &= ~CFG_MODE_1000;
-
-		speed = ((cfg / CFG_SPDSTS0) & 3);
-		fullduplex = (cfg & CFG_DUPSTS);
-
-		if (fullduplex)
-			new_cfg |= CFG_SB;
-
-		if ((cfg & CFG_LNKSTS) &&
-		    ((new_cfg ^ ns->CFG_cache) & CFG_MODE_1000)) {
-			writel(new_cfg, ns->base + CFG);
-			ns->CFG_cache = new_cfg;
-		}
-
-		ns->CFG_cache &= ~CFG_SPDSTS;
-		ns->CFG_cache |= cfg & CFG_SPDSTS;
-	}
-
-	newlinkstate = (cfg & CFG_LNKSTS) ? LINK_UP : LINK_DOWN;
-
-	if (newlinkstate & LINK_UP && ns->linkstate != newlinkstate) {
-		printf("link now %s mbps, %s duplex and up.\n",
-		       speeds[speed], fullduplex ? "full" : "half");
-	} else if (newlinkstate & LINK_DOWN
-		   && ns->linkstate != newlinkstate) {
-		printf("link now down.\n");
-	}
-	ns->linkstate = newlinkstate;
-}
-static void ns83820_set_multicast(struct nic *nic __unused);
-static void ns83820_setup_rx(struct nic *nic)
-{
-	unsigned i;
-	ns->idle = 1;
-	ns->next_rx = 0;
-	ns->next_rx_desc = ns->descs;
-	ns->next_empty = 0;
-	ns->cur_rx = 0;
-
-
-	for (i = 0; i < NR_RX_DESC; i++) {
-		rx_ring[i].link = virt_to_le32desc(&rx_ring[i + 1]);
-		rx_ring[i].bufptr =
-		    virt_to_le32desc(&rxb[i * REAL_RX_BUF_SIZE]);
-		rx_ring[i].cmdsts = cpu_to_le32(REAL_RX_BUF_SIZE);
-		rx_ring[i].extsts = cpu_to_le32(0);
-	}
-//      No need to wrap the ring 
-//      rx_ring[i].link = virt_to_le32desc(&rx_ring[0]);
-	writel(0, ns->base + RXDP_HI);
-	writel(virt_to_le32desc(&rx_ring[0]), ns->base + RXDP);
-
-	DBG("starting receiver\n");
-
-	writel(0x0001, ns->base + CCSR);
-	writel(0, ns->base + RFCR);
-	writel(0x7fc00000, ns->base + RFCR);
-	writel(0xffc00000, ns->base + RFCR);
-
-	ns->up = 1;
-
-	phy_intr(nic);
-
-	/* Okay, let it rip */
-	ns->IMR_cache |= ISR_PHY;
-	ns->IMR_cache |= ISR_RXRCMP;
-	//dev->IMR_cache |= ISR_RXERR;
-	//dev->IMR_cache |= ISR_RXOK;
-	ns->IMR_cache |= ISR_RXORN;
-	ns->IMR_cache |= ISR_RXSOVR;
-	ns->IMR_cache |= ISR_RXDESC;
-	ns->IMR_cache |= ISR_RXIDLE;
-	ns->IMR_cache |= ISR_TXDESC;
-	ns->IMR_cache |= ISR_TXIDLE;
-
-	// No reason to enable interupts...
-	// writel(ns->IMR_cache, ns->base + IMR);
-	// writel(1, ns->base + IER);
-	ns83820_set_multicast(nic);
-	kick_rx();
-}
-
-
-static void ns83820_do_reset(struct nic *nic __unused, u32 which)
-{
-	DBG("resetting chip...\n");
-	writel(which, ns->base + CR);
-	do {
-
-	} while (readl(ns->base + CR) & which);
-	DBG("okay!\n");
-}
-
-static void ns83820_reset(struct nic *nic)
-{
-	unsigned i;
-	DBG("ns83820_reset\n");
-
-	writel(0, ns->base + PQCR);
-
-	ns83820_setup_rx(nic);
-
-	for (i = 0; i < NR_TX_DESC; i++) {
-		tx_ring[i].link = 0;
-		tx_ring[i].bufptr = 0;
-		tx_ring[i].cmdsts = cpu_to_le32(0);
-		tx_ring[i].extsts = cpu_to_le32(0);
-	}
-
-	ns->tx_idx = 0;
-	ns->tx_done_idx = 0;
-	writel(0, ns->base + TXDP_HI);
-	return;
-}
-static void ns83820_getmac(struct nic *nic __unused, u8 * mac)
-{
-	unsigned i;
-	for (i = 0; i < 3; i++) {
-		u32 data;
-		/* Read from the perfect match memory: this is loaded by
-		 * the chip from the EEPROM via the EELOAD self test.
-		 */
-		writel(i * 2, ns->base + RFCR);
-		data = readl(ns->base + RFDR);
-		*mac++ = data;
-		*mac++ = data >> 8;
-	}
-}
-
-static void ns83820_set_multicast(struct nic *nic __unused)
-{
-	u8 *rfcr = ns->base + RFCR;
-	u32 and_mask = 0xffffffff;
-	u32 or_mask = 0;
-	u32 val;
-
-	/* Support Multicast */
-	and_mask &= ~(RFCR_AAU | RFCR_AAM);
-	or_mask |= RFCR_AAM;
-	val = (readl(rfcr) & and_mask) | or_mask;
-	/* Ramit : RFCR Write Fix doc says RFEN must be 0 modify other bits */
-	writel(val & ~RFCR_RFEN, rfcr);
-	writel(val, rfcr);
-
-}
-static void ns83820_run_bist(struct nic *nic __unused, const char *name,
-			     u32 enable, u32 done, u32 fail)
-{
-	int timed_out = 0;
-	long start;
-	u32 status;
-	int loops = 0;
-
-	DBG("start %s\n", name);
-
-	    start = currticks();
-
-	writel(enable, ns->base + PTSCR);
-	for (;;) {
-		loops++;
-		status = readl(ns->base + PTSCR);
-		if (!(status & enable))
-			break;
-		if (status & done)
-			break;
-		if (status & fail)
-			break;
-		if ((currticks() - start) >= HZ) {
-			timed_out = 1;
-			break;
-		}
-	}
-
-	if (status & fail)
-	  printf("%s failed! (0x%hX & 0x%hX)\n", name, (unsigned int) status, 
-		 (unsigned int) fail);
-	else if (timed_out)
-		printf("run_bist %s timed out! (%hX)\n", name, (unsigned int) status);
-	DBG("done %s in %d loops\n", name, loops);
-}
-
-/*************************************
-Check Link
-*************************************/
-static void ns83820_check_intr(struct nic *nic) {
-	int i;
-	u32 isr = readl(ns->base + ISR);
-	if(ISR_PHY & isr)
-		phy_intr(nic);
-	if(( ISR_RXIDLE | ISR_RXDESC | ISR_RXERR) & isr)
-		kick_rx();
-	for (i = 0; i < NR_RX_DESC; i++) {
-		if (rx_ring[i].cmdsts == CMDSTS_OWN) {
-//			rx_ring[i].link = virt_to_le32desc(&rx_ring[i + 1]);
-			rx_ring[i].cmdsts = cpu_to_le32(REAL_RX_BUF_SIZE);
-		}
-	}
-}
-/**************************************************************************
-POLL - Wait for a frame
-***************************************************************************/
-static int ns83820_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 */
-	u32 cmdsts;
-	int entry = ns->cur_rx;
-
-	ns83820_check_intr(nic);
-
-	cmdsts = le32_to_cpu(rx_ring[entry].cmdsts);
-
-	if ( ! ( (CMDSTS_OWN & (cmdsts)) && (cmdsts != (CMDSTS_OWN)) ) )
-	  return 0;
-
-	if ( ! retrieve ) return 1;
-
-	if (! (CMDSTS_OK & cmdsts) )
-	  return 0;
-
-	nic->packetlen = cmdsts & 0xffff;
-	memcpy(nic->packet,
-	       rxb + (entry * REAL_RX_BUF_SIZE),
-	       nic->packetlen);
-	//			rx_ring[entry].link = 0;
-	rx_ring[entry].cmdsts = cpu_to_le32(CMDSTS_OWN);
-
-	ns->cur_rx = (ns->cur_rx + 1) % NR_RX_DESC;
-
-	if (ns->cur_rx == 0)	/* We have wrapped the ring */
-	  kick_rx();
-
-	return 1;
-}
-
-static inline void kick_tx(struct nic *nic __unused)
-{
-	DBG("kick_tx\n");
-	writel(CR_TXE, ns->base + CR);
-}
-
-/**************************************************************************
-TRANSMIT - Transmit a frame
-***************************************************************************/
-static void ns83820_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 cmdsts, extsts;
-	int cur_tx = 0;
-	u32 isr = readl(ns->base + ISR);
-	if (ISR_TXIDLE & isr)
-		kick_tx(nic);
-	/* point to the current txb incase multiple tx_rings are used */
-	memcpy(txb, d, ETH_ALEN);
-	memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);
-	nstype = htons((u16) t);
-	memcpy(txb + 2 * ETH_ALEN, (u8 *) & nstype, 2);
-	memcpy(txb + ETH_HLEN, p, s);
-	s += ETH_HLEN;
-	s &= 0x0FFF;
-	while (s < ETH_ZLEN)
-		txb[s++] = '\0';
-
-	/* Setup the transmit descriptor */
-	extsts = 0;
-	extsts |= EXTSTS_UDPPKT;
-
-	tx_ring[cur_tx].bufptr = virt_to_le32desc(&txb);
-	tx_ring[cur_tx].extsts = cpu_to_le32(extsts);
-
-	cmdsts = cpu_to_le32(0);
-	cmdsts |= cpu_to_le32(CMDSTS_OWN | s);
-	tx_ring[cur_tx].cmdsts = cpu_to_le32(cmdsts);
-
-	writel(virt_to_le32desc(&tx_ring[0]), ns->base + TXDP);
-	kick_tx(nic);
-}
-
-/**************************************************************************
-DISABLE - Turn off ethernet interface
-***************************************************************************/
-static void ns83820_disable ( struct nic *nic ) {
-
-	/* put the card in its initial state */
-	/* This function serves 3 purposes.
-	 * This disables DMA and interrupts so we don't receive
-	 *  unexpected packets or interrupts from the card after
-	 *  etherboot has finished. 
-	 * This frees resources so etherboot may use
-	 *  this driver on another interface
-	 * This allows etherboot to reinitialize the interface
-	 *  if something is something goes wrong.
-	 */
-	/* disable interrupts */
-	writel(0, ns->base + IMR);
-	writel(0, ns->base + IER);
-	readl(ns->base + IER);
-
-	ns->up = 0;
-
-	ns83820_do_reset(nic, CR_RST);
-
-	ns->IMR_cache &=
-	    ~(ISR_RXOK | ISR_RXDESC | ISR_RXERR | ISR_RXEARLY |
-	      ISR_RXIDLE);
-	writel(ns->IMR_cache, ns->base + IMR);
-
-	/* touch the pci bus... */
-	readl(ns->base + IMR);
-
-	/* assumes the transmitter is already disabled and reset */
-	writel(0, ns->base + RXDP_HI);
-	writel(0, ns->base + RXDP);
-}
-
-/**************************************************************************
-IRQ - Enable, Disable, or Force interrupts
-***************************************************************************/
-static void ns83820_irq(struct nic *nic __unused, irq_action_t action __unused)
-{
-  switch ( action ) {
-  case DISABLE :
-    break;
-  case ENABLE :
-    break;
-  case FORCE :
-    break;
-  }
-}
-
-static struct nic_operations ns83820_operations = {
-	.connect	= dummy_connect,
-	.poll		= ns83820_poll,
-	.transmit	= ns83820_transmit,
-	.irq		= ns83820_irq,
-
-};
-
-static struct pci_device_id ns83820_nics[] = {
-	PCI_ROM(0x100b, 0x0022, "ns83820", "National Semiconductor 83820", 0),
-};
-
-PCI_DRIVER ( ns83820_driver, ns83820_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 ns83820_probe ( struct nic *nic, struct pci_device *pci ) {
-
-	long addr;
-	int using_dac = 0;
-
-	if (pci->ioaddr == 0)
-		return 0;
-
-	printf("ns83820.c: Found %s, vendor=0x%hX, device=0x%hX\n",
-	       pci->id->name, pci->vendor, pci->device);
-
-	/* point to private storage */
-	ns = &nsx;
-
-	adjust_pci_device(pci);
-
-	addr = pci_bar_start(pci, PCI_BASE_ADDRESS_1);
-
-	ns->base = ioremap(addr, (1UL << 12));
-
-	if (!ns->base)
-		return 0;
-
-	nic->irqno  = 0;
-	nic->ioaddr = pci->ioaddr & ~3;
-
-	/* disable interrupts */
-	writel(0, ns->base + IMR);
-	writel(0, ns->base + IER);
-	readl(ns->base + IER);
-
-	ns->IMR_cache = 0;
-
-	ns83820_do_reset(nic, CR_RST);
-
-	/* Must reset the ram bist before running it */
-	writel(PTSCR_RBIST_RST, ns->base + PTSCR);
-	ns83820_run_bist(nic, "sram bist", PTSCR_RBIST_EN,
-			 PTSCR_RBIST_DONE, PTSCR_RBIST_FAIL);
-	ns83820_run_bist(nic, "eeprom bist", PTSCR_EEBIST_EN, 0,
-			 PTSCR_EEBIST_FAIL);
-	ns83820_run_bist(nic, "eeprom load", PTSCR_EELOAD_EN, 0, 0);
-
-	/* I love config registers */
-	ns->CFG_cache = readl(ns->base + CFG);
-
-	if ((ns->CFG_cache & CFG_PCI64_DET)) {
-		printf("%s: detected 64 bit PCI data bus.\n", pci->id->name);
-		/*dev->CFG_cache |= CFG_DATA64_EN; */
-		if (!(ns->CFG_cache & CFG_DATA64_EN))
-			printf
-			    ("%s: EEPROM did not enable 64 bit bus.  Disabled.\n",
-			     pci->id->name);
-	} else
-		ns->CFG_cache &= ~(CFG_DATA64_EN);
-
-	ns->CFG_cache &= (CFG_TBI_EN | CFG_MRM_DIS | CFG_MWI_DIS |
-			  CFG_T64ADDR | CFG_DATA64_EN | CFG_EXT_125 |
-			  CFG_M64ADDR);
-	ns->CFG_cache |=
-	    CFG_PINT_DUPSTS | CFG_PINT_LNKSTS | CFG_PINT_SPDSTS |
-	    CFG_EXTSTS_EN | CFG_EXD | CFG_PESEL;
-	ns->CFG_cache |= CFG_REQALG;
-	ns->CFG_cache |= CFG_POW;
-	ns->CFG_cache |= CFG_TMRTEST;
-
-	/* When compiled with 64 bit addressing, we must always enable
-	 * the 64 bit descriptor format.
-	 */
-#ifdef USE_64BIT_ADDR
-	ns->CFG_cache |= CFG_M64ADDR;
-#endif
-
-//FIXME: Enable section on dac or remove this
-	if (using_dac)
-		ns->CFG_cache |= CFG_T64ADDR;
-
-	/* Big endian mode does not seem to do what the docs suggest */
-	ns->CFG_cache &= ~CFG_BEM;
-
-	/* setup optical transceiver if we have one */
-	if (ns->CFG_cache & CFG_TBI_EN) {
-		DBG("%s: enabling optical transceiver\n", pci->id->name);
-		writel(readl(ns->base + GPIOR) | 0x3e8, ns->base + GPIOR);
-
-		/* setup auto negotiation feature advertisement */
-		writel(readl(ns->base + TANAR)
-		       | TANAR_HALF_DUP | TANAR_FULL_DUP,
-		       ns->base + TANAR);
-
-		/* start auto negotiation */
-		writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN,
-		       ns->base + TBICR);
-		writel(TBICR_MR_AN_ENABLE, ns->base + TBICR);
-		ns->linkstate = LINK_AUTONEGOTIATE;
-
-		ns->CFG_cache |= CFG_MODE_1000;
-	}
-	writel(ns->CFG_cache, ns->base + CFG);
-	DBG("CFG: %hX\n", ns->CFG_cache);
-
-	/* FIXME: reset_phy is defaulted to 0, should we reset anyway? */
-	if (reset_phy) {
-		DBG("%s: resetting phy\n", pci->id->name);
-		writel(ns->CFG_cache | CFG_PHY_RST, ns->base + CFG);
-		writel(ns->CFG_cache, ns->base + CFG);
-	}
-#if 0				/* Huh?  This sets the PCI latency register.  Should be done via 
-				 * the PCI layer.  FIXME.
-				 */
-	if (readl(dev->base + SRR))
-		writel(readl(dev->base + 0x20c) | 0xfe00,
-		       dev->base + 0x20c);
-#endif
-
-	/* Note!  The DMA burst size interacts with packet
-	 * transmission, such that the largest packet that
-	 * can be transmitted is 8192 - FLTH - burst size.
-	 * If only the transmit fifo was larger...
-	 */
-	/* Ramit : 1024 DMA is not a good idea, it ends up banging 
-	 * some DELL and COMPAQ SMP systems */
-	writel(TXCFG_CSI | TXCFG_HBI | TXCFG_ATP | TXCFG_MXDMA512
-	       | ((1600 / 32) * 0x100), ns->base + TXCFG);
-
-	/* Set Rx to full duplex, don't accept runt, errored, long or length
-	 * range errored packets.  Use 512 byte DMA.
-	 */
-	/* Ramit : 1024 DMA is not a good idea, it ends up banging 
-	 * some DELL and COMPAQ SMP systems 
-	 * Turn on ALP, only we are accpeting Jumbo Packets */
-	writel(RXCFG_AEP | RXCFG_ARP | RXCFG_AIRL | RXCFG_RX_FD
-	       | RXCFG_STRIPCRC
-	       //| RXCFG_ALP
-	       | (RXCFG_MXDMA512) | 0, ns->base + RXCFG);
-
-	/* Disable priority queueing */
-	writel(0, ns->base + PQCR);
-
-	/* Enable IP checksum validation and detetion of VLAN headers.
-	 * Note: do not set the reject options as at least the 0x102
-	 * revision of the chip does not properly accept IP fragments
-	 * at least for UDP.
-	 */
-	/* Ramit : Be sure to turn on RXCFG_ARP if VLAN's are enabled, since
-	 * the MAC it calculates the packetsize AFTER stripping the VLAN
-	 * header, and if a VLAN Tagged packet of 64 bytes is received (like
-	 * a ping with a VLAN header) then the card, strips the 4 byte VLAN
-	 * tag and then checks the packet size, so if RXCFG_ARP is not enabled,
-	 * it discrards it!.  These guys......
-	 */
-	writel(VRCR_IPEN | VRCR_VTDEN, ns->base + VRCR);
-
-	/* Enable per-packet TCP/UDP/IP checksumming */
-	writel(VTCR_PPCHK, ns->base + VTCR);
-
-	/* Ramit : Enable async and sync pause frames */
-//      writel(0, ns->base + PCR); 
-	writel((PCR_PS_MCAST | PCR_PS_DA | PCR_PSEN | PCR_FFLO_4K |
-		PCR_FFHI_8K | PCR_STLO_4 | PCR_STHI_8 | PCR_PAUSE_CNT),
-	       ns->base + PCR);
-
-	/* Disable Wake On Lan */
-	writel(0, ns->base + WCSR);
-
-	ns83820_getmac(nic, nic->node_addr);
-
-	if (using_dac) {
-		DBG("%s: using 64 bit addressing.\n", pci->id->name);
-	}
-
-	DBG("%s: DP83820 %d.%d: io=%#04lx\n",
-	    pci->id->name,
-	    (unsigned) readl(ns->base + SRR) >> 8,
-	    (unsigned) readl(ns->base + SRR) & 0xff,
-	    pci->ioaddr);
-
-#ifdef PHY_CODE_IS_FINISHED
-	ns83820_probe_phy(dev);
-#endif
-
-	ns83820_reset(nic);
-	/* point to NIC specific routines */
-	nic->nic_op	= &ns83820_operations;
-	return 1;
-}
-
-DRIVER ( "NS83820/PCI", nic_driver, pci_driver, ns83820_driver,
-	 ns83820_probe, ns83820_disable );
-
-/*
- * Local variables:
- *  c-basic-offset: 8
- *  c-indent-level: 8
- *  tab-width: 8
- * End:
- */
diff --git a/roms/ipxe/src/drivers/net/p80211hdr.h b/roms/ipxe/src/drivers/net/p80211hdr.h
index 83546712274f62d5b6a7015d5734..110905c5f9b76ddce4bc1cd5f2b3 100644
--- a/roms/ipxe/src/drivers/net/p80211hdr.h
+++ b/roms/ipxe/src/drivers/net/p80211hdr.h
@@ -258,7 +258,7 @@ typedef union p80211_hdr
 /*================================================================*/
 /* Function Declarations */
 
-/* Frame and header lenght macros */
+/* Frame and header length macros */
 
 #define WLAN_CTL_FRAMELEN(fstype) (\
 	(fstype) == WLAN_FSTYPE_BLOCKACKREQ	? 24 : \
diff --git a/roms/ipxe/src/drivers/net/pcnet32.c b/roms/ipxe/src/drivers/net/pcnet32.c
index d6da3c5e524c19daa195663a5c99..26633a248f33b1dcb606db6fb4d0 100644
--- a/roms/ipxe/src/drivers/net/pcnet32.c
+++ b/roms/ipxe/src/drivers/net/pcnet32.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  *
  */
 
@@ -406,7 +407,7 @@ pcnet32_chip_detect ( struct pcnet32_private *priv )
 	/*
 	 * On selected chips turn on the BCR18:NOUFLO bit. This stops transmit
 	 * starting until the packet is loaded. Strike one for reliability, lose
-	 * one for latency - although on PCI this isnt a big loss. Older chips
+	 * one for latency - although on PCI this isn't a big loss. Older chips
 	 * have FIFO's smaller than a packet, so you can't do this.
 	 * Turn on BCR18:BurstRdEn and BCR18:BurstWrEn.
 	 */
diff --git a/roms/ipxe/src/drivers/net/pcnet32.h b/roms/ipxe/src/drivers/net/pcnet32.h
index bd03cbc017d1a15fe1e7811534c5..5e4492ef93f5b368fd9fb55acdc9 100644
--- a/roms/ipxe/src/drivers/net/pcnet32.h
+++ b/roms/ipxe/src/drivers/net/pcnet32.h
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  *
  */
 
diff --git a/roms/ipxe/src/drivers/net/phantom/nx_bitops.h b/roms/ipxe/src/drivers/net/phantom/nx_bitops.h
index 40686326a6609e134444d7f154c3..15f3d37679110c79a62d98553aef 100644
--- a/roms/ipxe/src/drivers/net/phantom/nx_bitops.h
+++ b/roms/ipxe/src/drivers/net/phantom/nx_bitops.h
@@ -16,7 +16,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/net/phantom/phantom.c b/roms/ipxe/src/drivers/net/phantom/phantom.c
index a55319ea67a7083fb6f57d2af2c5..1c798e04a4e61899196173751a46 100644
--- a/roms/ipxe/src/drivers/net/phantom/phantom.c
+++ b/roms/ipxe/src/drivers/net/phantom/phantom.c
@@ -14,7 +14,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/net/phantom/phantom.h b/roms/ipxe/src/drivers/net/phantom/phantom.h
index a55f32fbbf92df504b271f26890d..1647168ba49bc3053a5ae5165b88 100644
--- a/roms/ipxe/src/drivers/net/phantom/phantom.h
+++ b/roms/ipxe/src/drivers/net/phantom/phantom.h
@@ -17,7 +17,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/net/phantom/phantom_hw.h b/roms/ipxe/src/drivers/net/phantom/phantom_hw.h
index 950f36a4f0bcfdb872044a330862..7dfff52b22dc046e18ec971e7b85 100644
--- a/roms/ipxe/src/drivers/net/phantom/phantom_hw.h
+++ b/roms/ipxe/src/drivers/net/phantom/phantom_hw.h
@@ -17,7 +17,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/net/r8169.c b/roms/ipxe/src/drivers/net/r8169.c
deleted file mode 100644
index 13ab65ba504b1d365b5ec77a3efe1ef0b7aaa051..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/r8169.c
+++ /dev/null
@@ -1,2232 +0,0 @@
-/*
- * 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.
- */
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#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 <ipxe/ethernet.h>
-#include <ipxe/if_ether.h>
-#include <ipxe/io.h>
-#include <ipxe/iobuf.h>
-#include <ipxe/malloc.h>
-#include <ipxe/netdevice.h>
-#include <ipxe/pci.h>
-#include <ipxe/timer.h>
-#include <mii.h>
-
-#include "r8169.h"
-
-/*** Low level hardware routines ***/
-
-static void mdio_write(void *ioaddr, int reg_addr, int value)
-{
-	int i;
-
-	DBGP ( "mdio_write\n" );
-
-	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;
-		udelay(25);
-	}
-}
-
-static int mdio_read(void *ioaddr, int reg_addr)
-{
-	int i, value = -1;
-
-	DBGP ( "mdio_read\n" );
-
-	RTL_W32(PHYAR, 0x0 | (reg_addr & 0x1f) << 16);
-
-	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 = RTL_R32(PHYAR) & 0xffff;
-			break;
-		}
-		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);
-}
-
-static void rtl_ephy_write(void *ioaddr, int reg_addr, int value)
-{
-	unsigned int i;
-
-	DBGP ( "rtl_ephy_write\n" );
-
-	RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
-		(reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
-
-	for (i = 0; i < 100; i++) {
-		if (!(RTL_R32(EPHYAR) & EPHYAR_FLAG))
-			break;
-		udelay(10);
-	}
-}
-
-static u16 rtl_ephy_read(void *ioaddr, int reg_addr)
-{
-	u16 value = 0xffff;
-	unsigned int i;
-
-	DBGP ( "rtl_ephy_read\n" );
-
-	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;
-		}
-		udelay(10);
-	}
-
-	return value;
-}
-
-static void rtl_csi_write(void *ioaddr, int addr, int value)
-{
-	unsigned int i;
-
-	DBGP ( "rtl_csi_write\n" );
-
-	RTL_W32(CSIDR, value);
-	RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
-		CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
-
-	for (i = 0; i < 100; i++) {
-		if (!(RTL_R32(CSIAR) & CSIAR_FLAG))
-			break;
-		udelay(10);
-	}
-}
-
-static u32 rtl_csi_read(void *ioaddr, int addr)
-{
-	u32 value = ~0x00;
-	unsigned int i;
-
-	DBGP ( "rtl_csi_read\n" );
-
-	RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) |
-		CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
-
-	for (i = 0; i < 100; i++) {
-		if (RTL_R32(CSIAR) & CSIAR_FLAG) {
-			value = RTL_R32(CSIDR);
-			break;
-		}
-		udelay(10);
-	}
-
-	return value;
-}
-
-static void rtl8169_irq_mask_and_ack(void *ioaddr)
-{
-	DBGP ( "rtl8169_irq_mask_and_ack\n" );
-
-	RTL_W16(IntrMask, 0x0000);
-
-	RTL_W16(IntrStatus, 0xffff);
-}
-
-static unsigned int rtl8169_tbi_reset_pending(void *ioaddr)
-{
-	DBGP ( "rtl8169_tbi_reset_pending\n" );
-
-	return RTL_R32(TBICSR) & TBIReset;
-}
-
-static unsigned int rtl8169_xmii_reset_pending(void *ioaddr)
-{
-	DBGP ( "rtl8169_xmii_reset_pending\n" );
-
-	return mdio_read(ioaddr, MII_BMCR) & BMCR_RESET;
-}
-
-static unsigned int rtl8169_tbi_link_ok(void *ioaddr)
-{
-	DBGP ( "rtl8169_tbi_link_ok\n" );
-
-	return RTL_R32(TBICSR) & TBILinkOk;
-}
-
-static unsigned int rtl8169_xmii_link_ok(void *ioaddr)
-{
-	DBGP ( "rtl8169_xmii_link_ok\n" );
-
-	return RTL_R8(PHYstatus) & LinkStatus;
-}
-
-static void rtl8169_tbi_reset_enable(void *ioaddr)
-{
-	DBGP ( "rtl8169_tbi_reset_enable\n" );
-
-	RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
-}
-
-static void rtl8169_xmii_reset_enable(void *ioaddr)
-{
-	unsigned int val;
-
-	DBGP ( "rtl8169_xmii_reset_enable\n" );
-
-	val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET;
-	mdio_write(ioaddr, MII_BMCR, val & 0xffff);
-}
-
-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;
-}
-
-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" );
-
-	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 (autoneg == AUTONEG_ENABLE) {
-		auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL |
-			      ADVERTISE_100HALF | ADVERTISE_100FULL);
-		giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
-	} else {
-		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;
-		}
-	}
-
-	/* 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);
-	}
-
-	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);
-	}
-
-	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 int rtl8169_set_speed(struct net_device *dev,
-			     u8 autoneg, u16 speed, u8 duplex)
-{
-	struct rtl8169_private *tp = netdev_priv(dev);
-	int ret;
-
-	DBGP ( "rtl8169_set_speed\n" );
-
-	ret = tp->set_speed(dev, autoneg, speed, duplex);
-
-	return ret;
-}
-
-static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg,
-				       int bitnum, int bitval)
-{
-	int val;
-
-	DBGP ( "rtl8169_write_gmii_reg_bit\n" );
-
-	val = mdio_read(ioaddr, reg);
-	val = (bitval == 1) ?
-		val | (bitval << bitnum) :  val & ~(0x0001 << bitnum);
-	mdio_write(ioaddr, reg, val & 0xffff);
-}
-
-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
-	 */
-	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 },
-
-		/* 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, 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 },
-
-		/* 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;
-	u32 reg;
-
-	DBGP ( "rtl8169_get_mac_version\n" );
-
-	reg = RTL_R32(TxConfig);
-	while ((reg & p->mask) != p->val)
-		p++;
-	tp->mac_version = p->mac_version;
-
-	DBG ( "tp->mac_version = %d\n", tp->mac_version );
-
-	if (p->mask == 0x00000000) {
-		DBG ( "unknown MAC (%08x)\n", reg );
-	}
-}
-
-struct phy_reg {
-	u16 reg;
-	u16 val;
-};
-
-static void rtl_phy_write(void *ioaddr, struct phy_reg *regs, int len)
-{
-	DBGP ( "rtl_phy_write\n" );
-
-	while (len-- > 0) {
-		mdio_write(ioaddr, regs->reg, regs->val);
-		regs++;
-	}
-}
-
-static void rtl8169s_hw_phy_config(void *ioaddr)
-{
-	struct {
-		u16 regs[5]; /* Beware of bit-sign propagation */
-	} phy_magic[5] = { {
-		{ 0x0000,	//w 4 15 12 0
-		  0x00a1,	//w 3 15 0 00a1
-		  0x0008,	//w 2 15 0 0008
-		  0x1020,	//w 1 15 0 1020
-		  0x1000 } },{	//w 0 15 0 1000
-		{ 0x7000,	//w 4 15 12 7
-		  0xff41,	//w 3 15 0 ff41
-		  0xde60,	//w 2 15 0 de60
-		  0x0140,	//w 1 15 0 0140
-		  0x0077 } },{	//w 0 15 0 0077
-		{ 0xa000,	//w 4 15 12 a
-		  0xdf01,	//w 3 15 0 df01
-		  0xdf20,	//w 2 15 0 df20
-		  0xff95,	//w 1 15 0 ff95
-		  0xfa00 } },{	//w 0 15 0 fa00
-		{ 0xb000,	//w 4 15 12 b
-		  0xff41,	//w 3 15 0 ff41
-		  0xde20,	//w 2 15 0 de20
-		  0x0140,	//w 1 15 0 0140
-		  0x00bb } },{	//w 0 15 0 00bb
-		{ 0xf000,	//w 4 15 12 f
-		  0xdf01,	//w 3 15 0 df01
-		  0xdf20,	//w 2 15 0 df20
-		  0xff95,	//w 1 15 0 ff95
-		  0xbf00 }	//w 0 15 0 bf00
-		}
-	}, *p = phy_magic;
-	unsigned int i;
-
-	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 = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff);
-		mdio_write(ioaddr, pos, val);
-		while (--pos >= 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
-	}
-	mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0
-}
-
-static void rtl8169sb_hw_phy_config(void *ioaddr)
-{
-	struct phy_reg phy_reg_init[] = {
-		{ 0x1f, 0x0002 },
-		{ 0x01, 0x90d0 },
-		{ 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_1_hw_phy_config(void *ioaddr)
-{
-	struct phy_reg phy_reg_init[] = {
-		{ 0x1f, 0x0000 },
-		{ 0x1d, 0x0f00 },
-		{ 0x1f, 0x0002 },
-		{ 0x0c, 0x1ec8 },
-		{ 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_1_hw_phy_config(void *ioaddr)
-{
-	struct phy_reg phy_reg_init[] = {
-		{ 0x1f, 0x0001 },
-		{ 0x12, 0x2300 },
-		{ 0x1f, 0x0002 },
-		{ 0x00, 0x88d4 },
-		{ 0x01, 0x82b1 },
-		{ 0x03, 0x7002 },
-		{ 0x08, 0x9e30 },
-		{ 0x09, 0x01f0 },
-		{ 0x0a, 0x5500 },
-		{ 0x0c, 0x00c8 },
-		{ 0x1f, 0x0003 },
-		{ 0x12, 0xc096 },
-		{ 0x16, 0x000a },
-		{ 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 rtl8168c_2_hw_phy_config(void *ioaddr)
-{
-	struct phy_reg phy_reg_init[] = {
-		{ 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 }
-	};
-
-	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 rtl_hw_phy_config(struct net_device *dev)
-{
-	struct rtl8169_private *tp = netdev_priv(dev);
-	void *ioaddr = tp->mmio_addr;
-
-	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:
-		break;
-	case RTL_GIGA_MAC_VER_02:
-	case RTL_GIGA_MAC_VER_03:
-		rtl8169s_hw_phy_config(ioaddr);
-		break;
-	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_1_hw_phy_config(ioaddr);
-		break;
-	case RTL_GIGA_MAC_VER_19:
-		rtl8168c_1_hw_phy_config(ioaddr);
-		break;
-	case RTL_GIGA_MAC_VER_20:
-		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);
-}
-
-/*** iPXE API Support Routines ***/
-
-/**
- * setup_tx_resources - allocate tx resources (descriptors)
- *
- * @v tp	 Driver private storage
- *
- * @ret rc       Returns 0 on success, negative on failure
- **/
-static int
-rtl8169_setup_tx_resources ( struct rtl8169_private *tp )
-{
-	DBGP ( "rtl8169_setup_tx_resources\n" );
-
-	tp->tx_base = malloc_dma ( R8169_TX_RING_BYTES, TX_RING_ALIGN );
-
-	if ( ! tp->tx_base ) {
-		return -ENOMEM;
-	}
-
-	memset ( tp->tx_base, 0, R8169_TX_RING_BYTES );
-
-	DBG ( "tp->tx_base      = %#08lx\n", virt_to_bus ( tp->tx_base ) );
-
-	tp->tx_fill_ctr = 0;
-	tp->tx_curr = 0;
-	tp->tx_tail = 0;
-
-	return 0;
-}
-
-static void
-rtl8169_process_tx_packets ( struct net_device *netdev )
-{
-	struct rtl8169_private *tp = netdev_priv ( netdev );
-
-	uint32_t tx_status;
-	struct TxDesc *tx_curr_desc;
-
-	DBGP ( "rtl8169_process_tx_packets\n" );
-
-	while ( tp->tx_tail != tp->tx_curr ) {
-
-		tx_curr_desc = tp->tx_base  + tp->tx_tail;
-
-		tx_status = tx_curr_desc->opts1;
-
-		DBG2 ( "Before DescOwn check tx_status: %#08x\n", tx_status );
-
-		/* if the packet at tx_tail is not owned by hardware it is for us */
-		if ( tx_status & DescOwn )
-			break;
-
-		DBG ( "Transmitted packet.\n" );
-		DBG ( "tp->tx_fill_ctr     = %d\n", tp->tx_fill_ctr );
-		DBG ( "tp->tx_tail         = %d\n", tp->tx_tail );
-		DBG ( "tp->tx_curr         = %d\n", tp->tx_curr );
-		DBG ( "tx_status           = %d\n", tx_status );
-		DBG ( "tx_curr_desc        = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
-
-		/* Pass packet to core for processing */
-		netdev_tx_complete ( netdev, tp->tx_iobuf[tp->tx_tail] );
-
-		memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
-
-		/* Decrement count of used descriptors */
-		tp->tx_fill_ctr--;
-
-		/* Increment sent packets index */
-		tp->tx_tail = ( tp->tx_tail + 1 ) % NUM_TX_DESC;
-	}
-}
-
-static void
-rtl8169_free_tx_resources ( struct rtl8169_private *tp )
-{
-	DBGP ( "rtl8169_free_tx_resources\n" );
-
-	free_dma ( tp->tx_base, R8169_TX_RING_BYTES );
-}
-
-static void
-rtl8169_populate_rx_descriptor ( struct rtl8169_private *tp, struct RxDesc *rx_desc, uint32_t index )
-{
-	DBGP ( "rtl8169_populate_rx_descriptor\n" );
-
-	DBG ( "Populating rx descriptor %d\n", index );
-
-	memset ( rx_desc, 0, sizeof ( *rx_desc ) );
-
-	rx_desc->addr_hi = 0;
-	rx_desc->addr_lo = virt_to_bus ( tp->rx_iobuf[index]->data );
-	rx_desc->opts2 = 0;
-	rx_desc->opts1 = ( index == ( NUM_RX_DESC - 1 ) ? RingEnd : 0 ) |
-		RX_BUF_SIZE;
-	rx_desc->opts1 |= DescOwn;
-}
-
-/**
- * Refill descriptor ring
- *
- * @v netdev		Net device
- */
-static void rtl8169_refill_rx_ring ( struct rtl8169_private *tp )
-{
-	struct RxDesc *rx_curr_desc;
-	int i;
-
-	DBGP ( "rtl8169_refill_rx_ring\n" );
-
-	for ( i = 0; i < NUM_RX_DESC; i++ ) {
-
-		rx_curr_desc = ( tp->rx_base ) + i;
-
-		/* Don't touch descriptors owned by the NIC */
-		if ( rx_curr_desc->opts1 & DescOwn )
-			continue;
-
-		/* Don't touch descriptors with iobufs, they still need to be
-		   processed by the poll routine */
-		if ( tp->rx_iobuf[tp->rx_curr] != NULL )
-			continue;
-
-		/** If we can't get an iobuf for this descriptor
-		    try again later (next poll).
-		 */
-		if ( ! ( tp->rx_iobuf[i] = alloc_iob ( RX_BUF_SIZE ) ) ) {
-			DBG ( "Refill rx ring failed!!\n" );
-			break;
-		}
-
-		rtl8169_populate_rx_descriptor ( tp, rx_curr_desc, i );
-	}
-}
-
-/**
- * setup_rx_resources - allocate Rx resources (Descriptors)
- *
- * @v tp:	 Driver private structure
- *
- * @ret rc       Returns 0 on success, negative on failure
- *
- **/
-static int
-rtl8169_setup_rx_resources ( struct rtl8169_private *tp )
-{
-	DBGP ( "rtl8169_setup_rx_resources\n" );
-
-	tp->rx_base = malloc_dma ( R8169_RX_RING_BYTES, RX_RING_ALIGN );
-
-	DBG ( "tp->rx_base      = %#08lx\n", virt_to_bus ( tp->rx_base ) );
-
-	if ( ! tp->rx_base ) {
-		return -ENOMEM;
-	}
-	memset ( tp->rx_base, 0, R8169_RX_RING_BYTES );
-
-	rtl8169_refill_rx_ring ( tp );
-
-	tp->rx_curr = 0;
-
-	return 0;
-}
-
-static void
-rtl8169_process_rx_packets ( struct net_device *netdev )
-{
-	struct rtl8169_private *tp = netdev_priv ( netdev );
-	uint32_t rx_status;
-	uint16_t rx_len;
-	struct RxDesc *rx_curr_desc;
-	int i;
-
-	DBGP ( "rtl8169_process_rx_packets\n" );
-
-	for ( i = 0; i < NUM_RX_DESC; i++ ) {
-
-		rx_curr_desc = tp->rx_base  + tp->rx_curr;
-
-		rx_status = rx_curr_desc->opts1;
-
-		DBG2 ( "Before DescOwn check rx_status: %#08x\n", rx_status );
-
-		/* Hardware still owns the descriptor */
-		if ( rx_status & DescOwn )
-			break;
-
-		/* We own the descriptor, but it has not been refilled yet */
-		if ( tp->rx_iobuf[tp->rx_curr] == NULL )
-			break;
-
-		rx_len = rx_status & 0x3fff;
-
-		DBG ( "Received packet.\n" );
-		DBG ( "tp->rx_curr         = %d\n", tp->rx_curr );
-		DBG ( "rx_len              = %d\n", rx_len );
-		DBG ( "rx_status           = %#08x\n", rx_status );
-		DBG ( "rx_curr_desc        = %#08lx\n", virt_to_bus ( rx_curr_desc ) );
-
-		if ( rx_status & RxRES ) {
-
-			netdev_rx_err ( netdev, tp->rx_iobuf[tp->rx_curr], -EINVAL );
-
-			DBG ( "rtl8169_poll: Corrupted packet received!\n"
-			       " rx_status: %#08x\n", rx_status );
-
-		} else 	{
-
-			/* Adjust size of the iobuf to reflect received data */
-			iob_put ( tp->rx_iobuf[tp->rx_curr], rx_len );
-
-			/* Add this packet to the receive queue.  */
-			netdev_rx ( netdev, tp->rx_iobuf[tp->rx_curr] );
-		}
-
-		/* Invalidate this iobuf and descriptor */
-		tp->rx_iobuf[tp->rx_curr] = NULL;
-		memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
-
-		/* Update pointer to next available rx descriptor */
-		tp->rx_curr = ( tp->rx_curr + 1 ) % NUM_RX_DESC;
-	}
-	rtl8169_refill_rx_ring ( tp );
-}
-
-static void
-rtl8169_free_rx_resources ( struct rtl8169_private *tp )
-{
-	int i;
-
-	DBGP ( "rtl8169_free_rx_resources\n" );
-
-	free_dma ( tp->rx_base, R8169_RX_RING_BYTES );
-
-	for ( i = 0; i < NUM_RX_DESC; i++ ) {
-		free_iob ( tp->rx_iobuf[i] );
-		tp->rx_iobuf[i] = NULL;
-	}
-}
-
-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" );
-
-	RTL_W16 ( IntrMask, 0x0000 );
-}
-
-/*** iPXE Core API Routines ***/
-
-/**
- * open - Called when a network interface is made active
- *
- * @v netdev	network interface device structure
- * @ret rc	Return status code, 0 on success, negative value on failure
- *
- **/
-static int
-rtl8169_open ( struct net_device *netdev )
-{
-	struct rtl8169_private *tp = netdev_priv ( netdev );
-	void *ioaddr = tp->mmio_addr;
-	int rc;
-
-	DBGP ( "rtl8169_open\n" );
-
-	/* allocate transmit descriptors */
-	rc = rtl8169_setup_tx_resources ( tp );
-	if ( rc ) {
-		DBG ( "Error setting up TX resources!\n" );
-		goto err_setup_tx;
-	}
-
-	/* allocate receive descriptors */
-	rc = rtl8169_setup_rx_resources ( tp );
-	if ( rc ) {
-		DBG ( "Error setting up RX resources!\n" );
-		goto err_setup_rx;
-	}
-
-	rtl_hw_start ( netdev );
-
-	DBG ( "TxDescStartAddrHigh   = %#08lx\n", RTL_R32 ( TxDescStartAddrHigh ) );
-	DBG ( "TxDescStartAddrLow    = %#08lx\n", RTL_R32 ( TxDescStartAddrLow  ) );
-	DBG ( "RxDescAddrHigh        = %#08lx\n", RTL_R32 ( RxDescAddrHigh ) );
-	DBG ( "RxDescAddrLow         = %#08lx\n", RTL_R32 ( RxDescAddrLow  ) );
-
-	return 0;
-
-err_setup_rx:
-	rtl8169_free_tx_resources ( tp );
-err_setup_tx:
-	rtl8169_hw_reset ( ioaddr );
-
-	return rc;
-}
-
-/**
- * transmit - Transmit a packet
- *
- * @v netdev	Network device
- * @v iobuf	I/O buffer
- *
- * @ret rc       Returns 0 on success, negative on failure
- */
-static int
-rtl8169_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
-{
-	struct rtl8169_private *tp = netdev_priv ( netdev );
-	void *ioaddr = tp->mmio_addr;
-	uint32_t tx_len = iob_len ( iobuf );
-
-	struct TxDesc *tx_curr_desc;
-
-	DBGP ("rtl8169_transmit\n");
-
-	if ( tp->tx_fill_ctr == NUM_TX_DESC ) {
-		DBG ("TX overflow\n");
-		return -ENOBUFS;
-	}
-
-	/**
-	 *  The rtl8169 family automatically pads short packets to a
-	 *  minimum size, but if it did not, like some older cards,
-	 *  we could do:
-	 *  iob_pad ( iobuf, ETH_ZLEN );
-	 */
-
-	/* Save pointer to this iobuf we have been given to transmit so
-	   we can pass it to netdev_tx_complete() later */
-	tp->tx_iobuf[tp->tx_curr] = iobuf;
-
-	tx_curr_desc = tp->tx_base + tp->tx_curr;
-
-	DBG ( "tp->tx_fill_ctr = %d\n", tp->tx_fill_ctr );
-	DBG ( "tp->tx_curr     = %d\n", tp->tx_curr );
-	DBG ( "tx_curr_desc    = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
-	DBG ( "iobuf->data     = %#08lx\n", virt_to_bus ( iobuf->data ) );
-	DBG ( "tx_len          = %d\n", tx_len );
-
-	/* Configure current descriptor to transmit supplied packet */
-	tx_curr_desc->addr_hi = 0;
-	tx_curr_desc->addr_lo = virt_to_bus ( iobuf->data );
-	tx_curr_desc->opts2 = 0;
-	tx_curr_desc->opts1 = FirstFrag | LastFrag |
-		( tp->tx_curr == ( NUM_TX_DESC - 1 ) ? RingEnd : 0 ) |
-		tx_len;
-
-	/* Mark descriptor as owned by NIC */
-	tx_curr_desc->opts1 |= DescOwn;
-
-	DBG ( "tx_curr_desc->opts1   = %#08x\n", tx_curr_desc->opts1 );
-	DBG ( "tx_curr_desc->opts2   = %#08x\n", tx_curr_desc->opts2 );
-	DBG ( "tx_curr_desc->addr_hi = %#08x\n", tx_curr_desc->addr_hi );
-	DBG ( "tx_curr_desc->addr_lo = %#08x\n", tx_curr_desc->addr_lo );
-
-	RTL_W8 ( TxPoll, NPQ );	/* set polling bit */
-
-	/* Point to next free descriptor */
-	tp->tx_curr = ( tp->tx_curr + 1 ) % NUM_TX_DESC;
-
-	/* Increment number of tx descriptors in use */
-	tp->tx_fill_ctr++;
-
-	return 0;
-}
-
-/**
- * poll - Poll for received packets
- *
- * @v netdev	Network device
- */
-static void
-rtl8169_poll ( struct net_device *netdev )
-{
-	struct rtl8169_private *tp = netdev_priv ( netdev );
-	void *ioaddr = tp->mmio_addr;
-
-	uint16_t intr_status;
-	uint16_t intr_mask;
-
-	DBGP ( "rtl8169_poll\n" );
-
-	intr_status = RTL_R16 ( IntrStatus );
-	intr_mask   = RTL_R16 ( IntrMask );
-
-	DBG2 ( "rtl8169_poll (before): intr_mask = %#04x  intr_status = %#04x\n",
-	      intr_mask, intr_status );
-
-	RTL_W16 ( IntrStatus, 0xffff );
-
-	/* hotplug / major error / no more work / shared irq */
-	if ( intr_status == 0xffff )
-		return;
-
-	/* Process transmitted packets */
-	rtl8169_process_tx_packets ( netdev );
-
-	/* Process received packets  */
-	rtl8169_process_rx_packets ( netdev );
-}
-
-/**
- * close - Disable network interface
- *
- * @v netdev	network interface device structure
- *
- **/
-static void
-rtl8169_close ( struct net_device *netdev )
-{
-	struct rtl8169_private *tp = netdev_priv ( netdev );
-	void *ioaddr = tp->mmio_addr;
-
-	DBGP ( "r8169_close\n" );
-
-	rtl8169_hw_reset ( ioaddr );
-
-	rtl8169_free_tx_resources ( tp );
-	rtl8169_free_rx_resources ( tp );
-}
-
-/**
- * irq - enable or Disable interrupts
- *
- * @v netdev    network adapter
- * @v action    requested interrupt action
- *
- **/
-static void
-rtl8169_irq ( struct net_device *netdev, int action )
-{
-	struct rtl8169_private *tp = netdev_priv ( netdev );
-
-	DBGP ( "rtl8169_irq\n" );
-
-	switch ( action ) {
-	case 0 :
-		rtl8169_irq_disable ( tp );
-		break;
-	default :
-		rtl8169_irq_enable ( tp );
-		break;
-	}
-}
-
-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 )
-{
-	int i, rc;
-	struct net_device *netdev;
-	struct rtl8169_private *tp;
-	void *ioaddr;
-
-	const struct rtl_cfg_info *cfg = rtl_cfg_infos + pdev->id->driver_data;
-
-	DBGP ( "rtl8169_probe\n" );
-
-	DBG ( "id->vendor = %#04x, id->device = %#04x\n",
-	      pdev->id->vendor, pdev->id->device );
-
-	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->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->hw_addr[i] = RTL_R8 ( MAC0 + i );
-
-	DBG ( "%s\n", eth_ntoa ( netdev->hw_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", RTL_CFG_0),
-	PCI_ROM(0x10ec, 0x8136, "rtl8169-0x8136", "rtl8169-0x8136", RTL_CFG_2),
-	PCI_ROM(0x10ec, 0x8167, "rtl8169-0x8167", "rtl8169-0x8167", RTL_CFG_0),
-	PCI_ROM(0x10ec, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168", RTL_CFG_1),
-	PCI_ROM(0x10ec, 0x8169, "rtl8169-0x8169", "rtl8169-0x8169", RTL_CFG_0),
-	PCI_ROM(0x1186, 0x4300, "rtl8169-0x4300", "rtl8169-0x4300", RTL_CFG_0),
-	PCI_ROM(0x1259, 0xc107, "rtl8169-0xc107", "rtl8169-0xc107", RTL_CFG_0),
-	PCI_ROM(0x16ec, 0x0116, "rtl8169-0x0116", "rtl8169-0x0116", RTL_CFG_0),
-	PCI_ROM(0x1737, 0x1032, "rtl8169-0x1032", "rtl8169-0x1032", RTL_CFG_0),
-	PCI_ROM(0x0001, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168", RTL_CFG_2),
-};
-
-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:
- *  c-basic-offset: 8
- *  c-indent-level: 8
- *  tab-width: 8
- * End:
- */
diff --git a/roms/ipxe/src/drivers/net/r8169.h b/roms/ipxe/src/drivers/net/r8169.h
deleted file mode 100644
index bcf3df0bbcf28e40385b04e49bd7065b85f3d099..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/r8169.h
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
- * 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.
- *
- */
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-#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 iPXE?
-**/
-#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
-
-#define AUTONEG_DISABLE		0x00
-#define AUTONEG_ENABLE		0x01
-
-/* 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;
-	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/roms/ipxe/src/drivers/net/realtek.c b/roms/ipxe/src/drivers/net/realtek.c
new file mode 100644
index 0000000000000000000000000000000000000000..76fa47bbc3991b7abcf9ff3a0feb991612a97892
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/realtek.c
@@ -0,0 +1,1169 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * (EEPROM code originally implemented for rtl8139.c)
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+#include <ipxe/nvs.h>
+#include <ipxe/threewire.h>
+#include <ipxe/bitbash.h>
+#include <ipxe/mii.h>
+#include "realtek.h"
+
+/** @file
+ *
+ * Realtek 10/100/1000 network card driver
+ *
+ * Based on the following datasheets:
+ *
+ *    http://www.datasheetarchive.com/dl/Datasheets-8/DSA-153536.pdf
+ *    http://www.datasheetarchive.com/indexdl/Datasheet-028/DSA00494723.pdf
+ */
+
+/******************************************************************************
+ *
+ * EEPROM interface
+ *
+ ******************************************************************************
+ */
+
+/** Pin mapping for SPI bit-bashing interface */
+static const uint8_t realtek_eeprom_bits[] = {
+	[SPI_BIT_SCLK]	= RTL_9346CR_EESK,
+	[SPI_BIT_MOSI]	= RTL_9346CR_EEDI,
+	[SPI_BIT_MISO]	= RTL_9346CR_EEDO,
+	[SPI_BIT_SS(0)]	= RTL_9346CR_EECS,
+};
+
+/**
+ * Open bit-bashing interface
+ *
+ * @v basher		Bit-bashing interface
+ */
+static void realtek_spi_open_bit ( struct bit_basher *basher ) {
+	struct realtek_nic *rtl = container_of ( basher, struct realtek_nic,
+						 spibit.basher );
+
+	/* Enable EEPROM access */
+	writeb ( RTL_9346CR_EEM_EEPROM, rtl->regs + RTL_9346CR );
+}
+
+/**
+ * Close bit-bashing interface
+ *
+ * @v basher		Bit-bashing interface
+ */
+static void realtek_spi_close_bit ( struct bit_basher *basher ) {
+	struct realtek_nic *rtl = container_of ( basher, struct realtek_nic,
+						 spibit.basher );
+
+	/* Disable EEPROM access */
+	writeb ( RTL_9346CR_EEM_NORMAL, rtl->regs + RTL_9346CR );
+}
+
+/**
+ * Read input bit
+ *
+ * @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 realtek_spi_read_bit ( struct bit_basher *basher,
+				  unsigned int bit_id ) {
+	struct realtek_nic *rtl = container_of ( basher, struct realtek_nic,
+						 spibit.basher );
+	uint8_t mask = realtek_eeprom_bits[bit_id];
+	uint8_t reg;
+
+	DBG_DISABLE ( DBGLVL_IO );
+	reg = readb ( rtl->regs + RTL_9346CR );
+	DBG_ENABLE ( DBGLVL_IO );
+	return ( reg & mask );
+}
+
+/**
+ * Set/clear output bit
+ *
+ * @v basher		Bit-bashing interface
+ * @v bit_id		Bit number
+ * @v data		Value to write
+ */
+static void realtek_spi_write_bit ( struct bit_basher *basher,
+				    unsigned int bit_id, unsigned long data ) {
+	struct realtek_nic *rtl = container_of ( basher, struct realtek_nic,
+						 spibit.basher );
+	uint8_t mask = realtek_eeprom_bits[bit_id];
+	uint8_t reg;
+
+	DBG_DISABLE ( DBGLVL_IO );
+	reg = readb ( rtl->regs + RTL_9346CR );
+	reg &= ~mask;
+	reg |= ( data & mask );
+	writeb ( reg, rtl->regs + RTL_9346CR );
+	DBG_ENABLE ( DBGLVL_IO );
+}
+
+/** SPI bit-bashing interface */
+static struct bit_basher_operations realtek_basher_ops = {
+	.open = realtek_spi_open_bit,
+	.close = realtek_spi_close_bit,
+	.read = realtek_spi_read_bit,
+	.write = realtek_spi_write_bit,
+};
+
+/**
+ * Initialise EEPROM
+ *
+ * @v netdev		Network device
+ */
+static void realtek_init_eeprom ( struct net_device *netdev ) {
+	struct realtek_nic *rtl = netdev->priv;
+
+	/* Initialise SPI bit-bashing interface */
+	rtl->spibit.basher.op = &realtek_basher_ops;
+	rtl->spibit.bus.mode = SPI_MODE_THREEWIRE;
+	init_spi_bit_basher ( &rtl->spibit );
+
+	/* Detect EEPROM type and initialise three-wire device */
+	if ( readl ( rtl->regs + RTL_RCR ) & RTL_RCR_9356SEL ) {
+		DBGC ( rtl, "REALTEK %p EEPROM is a 93C56\n", rtl );
+		init_at93c56 ( &rtl->eeprom, 16 );
+	} else {
+		DBGC ( rtl, "REALTEK %p EEPROM is a 93C46\n", rtl );
+		init_at93c46 ( &rtl->eeprom, 16 );
+	}
+	rtl->eeprom.bus = &rtl->spibit.bus;
+
+	/* Initialise space for non-volatile options, if available
+	 *
+	 * We use offset 0x40 (i.e. address 0x20), length 0x40.  This
+	 * block is marked as VPD in the Realtek datasheets, so we use
+	 * it only if we detect that the card is not supporting VPD.
+	 */
+	if ( readb ( rtl->regs + RTL_CONFIG1 ) & RTL_CONFIG1_VPD ) {
+		DBGC ( rtl, "REALTEK %p EEPROM in use for VPD; cannot use "
+		       "for options\n", rtl );
+	} else {
+		nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, RTL_EEPROM_VPD,
+			   RTL_EEPROM_VPD_LEN, NULL, &netdev->refcnt );
+	}
+}
+
+/******************************************************************************
+ *
+ * MII interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Read from MII register
+ *
+ * @v mii		MII interface
+ * @v reg		Register address
+ * @ret value		Data read, or negative error
+ */
+static int realtek_mii_read ( struct mii_interface *mii, unsigned int reg ) {
+	struct realtek_nic *rtl = container_of ( mii, struct realtek_nic, mii );
+	unsigned int i;
+	uint32_t value;
+
+	/* Fail if PHYAR register is not present */
+	if ( ! rtl->have_phy_regs )
+		return -ENOTSUP;
+
+	/* Initiate read */
+	writel ( RTL_PHYAR_VALUE ( 0, reg, 0 ), rtl->regs + RTL_PHYAR );
+
+	/* Wait for read to complete */
+	for ( i = 0 ; i < RTL_MII_MAX_WAIT_US ; i++ ) {
+
+		/* If read is not complete, delay 1us and retry */
+		value = readl ( rtl->regs + RTL_PHYAR );
+		if ( ! ( value & RTL_PHYAR_FLAG ) ) {
+			udelay ( 1 );
+			continue;
+		}
+
+		/* Return register value */
+		return ( RTL_PHYAR_DATA ( value ) );
+	}
+
+	DBGC ( rtl, "REALTEK %p timed out waiting for MII read\n", rtl );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Write to MII register
+ *
+ * @v mii		MII interface
+ * @v reg		Register address
+ * @v data		Data to write
+ * @ret rc		Return status code
+ */
+static int realtek_mii_write ( struct mii_interface *mii, unsigned int reg,
+			       unsigned int data) {
+	struct realtek_nic *rtl = container_of ( mii, struct realtek_nic, mii );
+	unsigned int i;
+
+	/* Fail if PHYAR register is not present */
+	if ( ! rtl->have_phy_regs )
+		return -ENOTSUP;
+
+	/* Initiate write */
+	writel ( RTL_PHYAR_VALUE ( RTL_PHYAR_FLAG, reg, data ),
+		 rtl->regs + RTL_PHYAR );
+
+	/* Wait for write to complete */
+	for ( i = 0 ; i < RTL_MII_MAX_WAIT_US ; i++ ) {
+
+		/* If write is not complete, delay 1us and retry */
+		if ( readl ( rtl->regs + RTL_PHYAR ) & RTL_PHYAR_FLAG ) {
+			udelay ( 1 );
+			continue;
+		}
+
+		return 0;
+	}
+
+	DBGC ( rtl, "REALTEK %p timed out waiting for MII write\n", rtl );
+	return -ETIMEDOUT;
+}
+
+/** Realtek MII operations */
+static struct mii_operations realtek_mii_operations = {
+	.read = realtek_mii_read,
+	.write = realtek_mii_write,
+};
+
+/******************************************************************************
+ *
+ * Device reset
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Reset hardware
+ *
+ * @v rtl		Realtek device
+ * @ret rc		Return status code
+ */
+static int realtek_reset ( struct realtek_nic *rtl ) {
+	unsigned int i;
+
+	/* Issue reset */
+	writeb ( RTL_CR_RST, rtl->regs + RTL_CR );
+
+	/* Wait for reset to complete */
+	for ( i = 0 ; i < RTL_RESET_MAX_WAIT_MS ; i++ ) {
+
+		/* If reset is not complete, delay 1ms and retry */
+		if ( readb ( rtl->regs + RTL_CR ) & RTL_CR_RST ) {
+			mdelay ( 1 );
+			continue;
+		}
+
+		return 0;
+	}
+
+	DBGC ( rtl, "REALTEK %p timed out waiting for reset\n", rtl );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Configure PHY for Gigabit operation
+ *
+ * @v rtl		Realtek device
+ * @ret rc		Return status code
+ */
+static int realtek_phy_speed ( struct realtek_nic *rtl ) {
+	int ctrl1000;
+	int rc;
+
+	/* Read CTRL1000 register */
+	ctrl1000 = mii_read ( &rtl->mii, MII_CTRL1000 );
+	if ( ctrl1000 < 0 ) {
+		rc = ctrl1000;
+		DBGC ( rtl, "REALTEK %p could not read CTRL1000: %s\n",
+		       rtl, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Advertise 1000Mbps speeds */
+	ctrl1000 |= ( ADVERTISE_1000FULL | ADVERTISE_1000HALF );
+	if ( ( rc = mii_write ( &rtl->mii, MII_CTRL1000, ctrl1000 ) ) != 0 ) {
+		DBGC ( rtl, "REALTEK %p could not write CTRL1000: %s\n",
+		       rtl, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Reset PHY
+ *
+ * @v rtl		Realtek device
+ * @ret rc		Return status code
+ */
+static int realtek_phy_reset ( struct realtek_nic *rtl ) {
+	int rc;
+
+	/* Do nothing if we have no separate PHY register access */
+	if ( ! rtl->have_phy_regs )
+		return 0;
+
+	/* Perform MII reset */
+	if ( ( rc = mii_reset ( &rtl->mii ) ) != 0 ) {
+		DBGC ( rtl, "REALTEK %p could not reset MII: %s\n",
+		       rtl, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Some cards (e.g. RTL8169SC) do not advertise Gigabit by
+	 * default.  Try to enable advertisement of Gigabit speeds.
+	 */
+	if ( ( rc = realtek_phy_speed ( rtl ) ) != 0 ) {
+		/* Ignore failures, since the register may not be
+		 * present on non-Gigabit PHYs (e.g. RTL8101).
+		 */
+	}
+
+	/* Restart autonegotiation */
+	if ( ( rc = mii_restart ( &rtl->mii ) ) != 0 ) {
+		DBGC ( rtl, "REALTEK %p could not restart MII: %s\n",
+		       rtl, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ * Link state
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Check link state
+ *
+ * @v netdev		Network device
+ */
+static void realtek_check_link ( struct net_device *netdev ) {
+	struct realtek_nic *rtl = netdev->priv;
+	uint8_t phystatus;
+	uint8_t msr;
+	int link_up;
+
+	/* Determine link state */
+	if ( rtl->have_phy_regs ) {
+		phystatus = readb ( rtl->regs + RTL_PHYSTATUS );
+		link_up = ( phystatus & RTL_PHYSTATUS_LINKSTS );
+		DBGC ( rtl, "REALTEK %p PHY status is %02x\n", rtl, phystatus );
+	} else {
+		msr = readb ( rtl->regs + RTL_MSR );
+		link_up = ( ! ( msr & RTL_MSR_LINKB ) );
+		DBGC ( rtl, "REALTEK %p media status is %02x\n", rtl, msr );
+	}
+
+	/* Report link state */
+	if ( link_up ) {
+		netdev_link_up ( netdev );
+	} else {
+		netdev_link_down ( netdev );
+	}
+}
+
+/******************************************************************************
+ *
+ * Network device interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Create receive buffer (legacy mode)
+ *
+ * @v rtl		Realtek device
+ * @ret rc		Return status code
+ */
+static int realtek_create_buffer ( struct realtek_nic *rtl ) {
+	size_t len = ( RTL_RXBUF_LEN + RTL_RXBUF_PAD );
+	physaddr_t address;
+	int rc;
+
+	/* Do nothing unless in legacy mode */
+	if ( ! rtl->legacy )
+		return 0;
+
+	/* Allocate buffer */
+	rtl->rx_buffer = malloc_dma ( len, RTL_RXBUF_ALIGN );
+	if ( ! rtl->rx_buffer ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	address = virt_to_bus ( rtl->rx_buffer );
+
+	/* Check that card can support address */
+	if ( address & ~0xffffffffULL ) {
+		DBGC ( rtl, "REALTEK %p cannot support 64-bit RX buffer "
+		       "address\n", rtl );
+		rc = -ENOTSUP;
+		goto err_64bit;
+	}
+
+	/* Program buffer address */
+	writel ( address, rtl->regs + RTL_RBSTART );
+	DBGC ( rtl, "REALTEK %p receive buffer is at [%08llx,%08llx,%08llx)\n",
+	       rtl, ( ( unsigned long long ) address ),
+	       ( ( unsigned long long ) address + RTL_RXBUF_LEN ),
+	       ( ( unsigned long long ) address + len ) );
+
+	return 0;
+
+ err_64bit:
+	free_dma ( rtl->rx_buffer, len );
+	rtl->rx_buffer = NULL;
+ err_alloc:
+	return rc;
+}
+
+/**
+ * Destroy receive buffer (legacy mode)
+ *
+ * @v rtl		Realtek device
+ */
+static void realtek_destroy_buffer ( struct realtek_nic *rtl ) {
+	size_t len = ( RTL_RXBUF_LEN + RTL_RXBUF_PAD );
+
+	/* Do nothing unless in legacy mode */
+	if ( ! rtl->legacy )
+		return;
+
+	/* Clear buffer address */
+	writel ( 0, rtl->regs + RTL_RBSTART );
+
+	/* Free buffer */
+	free_dma ( rtl->rx_buffer, len );
+	rtl->rx_buffer = NULL;
+	rtl->rx_offset = 0;
+}
+
+/**
+ * Create descriptor ring
+ *
+ * @v rtl		Realtek device
+ * @v ring		Descriptor ring
+ * @ret rc		Return status code
+ */
+static int realtek_create_ring ( struct realtek_nic *rtl,
+				 struct realtek_ring *ring ) {
+	physaddr_t address;
+
+	/* Do nothing in legacy mode */
+	if ( rtl->legacy )
+		return 0;
+
+	/* Allocate descriptor ring */
+	ring->desc = malloc_dma ( ring->len, RTL_RING_ALIGN );
+	if ( ! ring->desc )
+		return -ENOMEM;
+
+	/* Initialise descriptor ring */
+	memset ( ring->desc, 0, ring->len );
+
+	/* Program ring address */
+	address = virt_to_bus ( ring->desc );
+	writel ( ( ( ( uint64_t ) address ) >> 32 ),
+		 rtl->regs + ring->reg + 4 );
+	writel ( ( address & 0xffffffffUL ), rtl->regs + ring->reg );
+	DBGC ( rtl, "REALTEK %p ring %02x is at [%08llx,%08llx)\n",
+	       rtl, ring->reg, ( ( unsigned long long ) address ),
+	       ( ( unsigned long long ) address + ring->len ) );
+
+	return 0;
+}
+
+/**
+ * Destroy descriptor ring
+ *
+ * @v rtl		Realtek device
+ * @v ring		Descriptor ring
+ */
+static void realtek_destroy_ring ( struct realtek_nic *rtl,
+				   struct realtek_ring *ring ) {
+
+	/* Do nothing in legacy mode */
+	if ( rtl->legacy )
+		return;
+
+	/* Clear ring address */
+	writel ( 0, rtl->regs + ring->reg );
+	writel ( 0, rtl->regs + ring->reg + 4 );
+
+	/* Free descriptor ring */
+	free_dma ( ring->desc, ring->len );
+	ring->desc = NULL;
+	ring->prod = 0;
+	ring->cons = 0;
+}
+
+/**
+ * Refill receive descriptor ring
+ *
+ * @v rtl		Realtek device
+ */
+static void realtek_refill_rx ( struct realtek_nic *rtl ) {
+	struct realtek_descriptor *rx;
+	struct io_buffer *iobuf;
+	unsigned int rx_idx;
+	physaddr_t address;
+	int is_last;
+
+	/* Do nothing in legacy mode */
+	if ( rtl->legacy )
+		return;
+
+	while ( ( rtl->rx.prod - rtl->rx.cons ) < RTL_NUM_RX_DESC ) {
+
+		/* Allocate I/O buffer */
+		iobuf = alloc_iob ( RTL_RX_MAX_LEN );
+		if ( ! iobuf ) {
+			/* Wait for next refill */
+			return;
+		}
+
+		/* Get next receive descriptor */
+		rx_idx = ( rtl->rx.prod++ % RTL_NUM_RX_DESC );
+		is_last = ( rx_idx == ( RTL_NUM_RX_DESC - 1 ) );
+		rx = &rtl->rx.desc[rx_idx];
+
+		/* Populate receive descriptor */
+		address = virt_to_bus ( iobuf->data );
+		rx->address = cpu_to_le64 ( address );
+		rx->length = cpu_to_le16 ( RTL_RX_MAX_LEN );
+		wmb();
+		rx->flags = ( cpu_to_le16 ( RTL_DESC_OWN ) |
+			      ( is_last ? cpu_to_le16 ( RTL_DESC_EOR ) : 0 ) );
+		wmb();
+
+		/* Record I/O buffer */
+		assert ( rtl->rx_iobuf[rx_idx] == NULL );
+		rtl->rx_iobuf[rx_idx] = iobuf;
+
+		DBGC2 ( rtl, "REALTEK %p RX %d is [%llx,%llx)\n", rtl, rx_idx,
+			( ( unsigned long long ) address ),
+			( ( unsigned long long ) address + RTL_RX_MAX_LEN ) );
+	}
+}
+
+/**
+ * Open network device
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int realtek_open ( struct net_device *netdev ) {
+	struct realtek_nic *rtl = netdev->priv;
+	uint32_t tcr;
+	uint32_t rcr;
+	int rc;
+
+	/* Create transmit descriptor ring */
+	if ( ( rc = realtek_create_ring ( rtl, &rtl->tx ) ) != 0 )
+		goto err_create_tx;
+
+	/* Create receive descriptor ring */
+	if ( ( rc = realtek_create_ring ( rtl, &rtl->rx ) ) != 0 )
+		goto err_create_rx;
+
+	/* Create receive buffer */
+	if ( ( rc = realtek_create_buffer ( rtl ) ) != 0 )
+		goto err_create_buffer;
+
+	/* Accept all packets */
+	writel ( 0xffffffffUL, rtl->regs + RTL_MAR0 );
+	writel ( 0xffffffffUL, rtl->regs + RTL_MAR4 );
+
+	/* Enable transmitter and receiver.  RTL8139 requires that
+	 * this happens before writing to RCR.
+	 */
+	writeb ( ( RTL_CR_TE | RTL_CR_RE ), rtl->regs + RTL_CR );
+
+	/* Configure transmitter */
+	tcr = readl ( rtl->regs + RTL_TCR );
+	tcr &= ~RTL_TCR_MXDMA_MASK;
+	tcr |= RTL_TCR_MXDMA_DEFAULT;
+	writel ( tcr, rtl->regs + RTL_TCR );
+
+	/* Configure receiver */
+	rcr = readl ( rtl->regs + RTL_RCR );
+	rcr &= ~( RTL_RCR_RXFTH_MASK | RTL_RCR_RBLEN_MASK |
+		  RTL_RCR_MXDMA_MASK );
+	rcr |= ( RTL_RCR_RXFTH_DEFAULT | RTL_RCR_RBLEN_DEFAULT |
+		 RTL_RCR_MXDMA_DEFAULT | RTL_RCR_WRAP | RTL_RCR_AB |
+		 RTL_RCR_AM | RTL_RCR_APM | RTL_RCR_AAP );
+	writel ( rcr, rtl->regs + RTL_RCR );
+
+	/* Fill receive ring */
+	realtek_refill_rx ( rtl );
+
+	/* Update link state */
+	realtek_check_link ( netdev );
+
+	return 0;
+
+	realtek_destroy_buffer ( rtl );
+ err_create_buffer:
+	realtek_destroy_ring ( rtl, &rtl->rx );
+ err_create_rx:
+	realtek_destroy_ring ( rtl, &rtl->tx );
+ err_create_tx:
+	return rc;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev		Network device
+ */
+static void realtek_close ( struct net_device *netdev ) {
+	struct realtek_nic *rtl = netdev->priv;
+	unsigned int i;
+
+	/* Disable receiver and transmitter */
+	writeb ( 0, rtl->regs + RTL_CR );
+
+	/* Destroy receive buffer */
+	realtek_destroy_buffer ( rtl );
+
+	/* Destroy receive descriptor ring */
+	realtek_destroy_ring ( rtl, &rtl->rx );
+
+	/* Discard any unused receive buffers */
+	for ( i = 0 ; i < RTL_NUM_RX_DESC ; i++ ) {
+		if ( rtl->rx_iobuf[i] )
+			free_iob ( rtl->rx_iobuf[i] );
+		rtl->rx_iobuf[i] = NULL;
+	}
+
+	/* Destroy transmit descriptor ring */
+	realtek_destroy_ring ( rtl, &rtl->tx );
+}
+
+/**
+ * Transmit packet
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int realtek_transmit ( struct net_device *netdev,
+			      struct io_buffer *iobuf ) {
+	struct realtek_nic *rtl = netdev->priv;
+	struct realtek_descriptor *tx;
+	unsigned int tx_idx;
+	physaddr_t address;
+	int is_last;
+
+	/* Get next transmit descriptor */
+	if ( ( rtl->tx.prod - rtl->tx.cons ) >= RTL_NUM_TX_DESC ) {
+		DBGC ( rtl, "REALTEK %p out of transmit descriptors\n", rtl );
+		return -ENOBUFS;
+	}
+	tx_idx = ( rtl->tx.prod++ % RTL_NUM_TX_DESC );
+
+	/* Transmit packet */
+	if ( rtl->legacy ) {
+
+		/* Pad and align packet */
+		iob_pad ( iobuf, ETH_ZLEN );
+		address = virt_to_bus ( iobuf->data );
+
+		/* Check that card can support address */
+		if ( address & ~0xffffffffULL ) {
+			DBGC ( rtl, "REALTEK %p cannot support 64-bit TX "
+			       "buffer address\n", rtl );
+			return -ENOTSUP;
+		}
+
+		/* Add to transmit ring */
+		writel ( address, rtl->regs + RTL_TSAD ( tx_idx ) );
+		writel ( ( RTL_TSD_ERTXTH_DEFAULT | iob_len ( iobuf ) ),
+			 rtl->regs + RTL_TSD ( tx_idx ) );
+
+	} else {
+
+		/* Populate transmit descriptor */
+		address = virt_to_bus ( iobuf->data );
+		is_last = ( tx_idx == ( RTL_NUM_TX_DESC - 1 ) );
+		tx = &rtl->tx.desc[tx_idx];
+		tx->address = cpu_to_le64 ( address );
+		tx->length = cpu_to_le16 ( iob_len ( iobuf ) );
+		wmb();
+		tx->flags = ( cpu_to_le16 ( RTL_DESC_OWN | RTL_DESC_FS |
+					    RTL_DESC_LS ) |
+			      ( is_last ? cpu_to_le16 ( RTL_DESC_EOR ) : 0 ) );
+		wmb();
+
+		/* Notify card that there are packets ready to transmit */
+		writeb ( RTL_TPPOLL_NPQ, rtl->regs + rtl->tppoll );
+	}
+
+	DBGC2 ( rtl, "REALTEK %p TX %d is [%llx,%llx)\n", rtl, tx_idx,
+		( ( unsigned long long ) virt_to_bus ( iobuf->data ) ),
+		( ( ( unsigned long long ) virt_to_bus ( iobuf->data ) ) +
+		  iob_len ( iobuf ) ) );
+
+	return 0;
+}
+
+/**
+ * Poll for completed packets
+ *
+ * @v netdev		Network device
+ */
+static void realtek_poll_tx ( struct net_device *netdev ) {
+	struct realtek_nic *rtl = netdev->priv;
+	struct realtek_descriptor *tx;
+	unsigned int tx_idx;
+
+	/* Check for completed packets */
+	while ( rtl->tx.cons != rtl->tx.prod ) {
+
+		/* Get next transmit descriptor */
+		tx_idx = ( rtl->tx.cons % RTL_NUM_TX_DESC );
+
+		/* Stop if descriptor is still in use */
+		if ( rtl->legacy ) {
+
+			/* Check ownership bit in transmit status register */
+			if ( ! ( readl ( rtl->regs + RTL_TSD ( tx_idx ) ) &
+				 RTL_TSD_OWN ) )
+				return;
+
+		} else {
+
+			/* Check ownership bit in descriptor */
+			tx = &rtl->tx.desc[tx_idx];
+			if ( tx->flags & cpu_to_le16 ( RTL_DESC_OWN ) )
+				return;
+		}
+
+		DBGC2 ( rtl, "REALTEK %p TX %d complete\n", rtl, tx_idx );
+
+		/* Complete TX descriptor */
+		netdev_tx_complete_next ( netdev );
+		rtl->tx.cons++;
+	}
+}
+
+/**
+ * Poll for received packets (legacy mode)
+ *
+ * @v netdev		Network device
+ */
+static void realtek_legacy_poll_rx ( struct net_device *netdev ) {
+	struct realtek_nic *rtl = netdev->priv;
+	struct realtek_legacy_header *rx;
+	struct io_buffer *iobuf;
+	size_t len;
+
+	/* Check for received packets */
+	while ( ! ( readb ( rtl->regs + RTL_CR ) & RTL_CR_BUFE ) ) {
+
+		/* Extract packet from receive buffer */
+		rx = ( rtl->rx_buffer + rtl->rx_offset );
+		len = le16_to_cpu ( rx->length );
+		if ( rx->status & cpu_to_le16 ( RTL_STAT_ROK ) ) {
+
+			DBGC2 ( rtl, "REALTEK %p RX offset %x+%zx\n",
+				rtl, rtl->rx_offset, len );
+
+			/* Allocate I/O buffer */
+			iobuf = alloc_iob ( len );
+			if ( ! iobuf ) {
+				netdev_rx_err ( netdev, NULL, -ENOMEM );
+				/* Leave packet for next poll */
+				break;
+			}
+
+			/* Copy data to I/O buffer */
+			memcpy ( iob_put ( iobuf, len ), rx->data, len );
+			iob_unput ( iobuf, 4 /* strip CRC */ );
+
+			/* Hand off to network stack */
+			netdev_rx ( netdev, iobuf );
+
+		} else {
+
+			DBGC ( rtl, "REALTEK %p RX offset %x+%zx error %04x\n",
+			       rtl, rtl->rx_offset, len,
+			       le16_to_cpu ( rx->status ) );
+			netdev_rx_err ( netdev, NULL, -EIO );
+		}
+
+		/* Update buffer offset */
+		rtl->rx_offset = ( rtl->rx_offset + sizeof ( *rx ) + len );
+		rtl->rx_offset = ( ( rtl->rx_offset + 3 ) & ~3 );
+		rtl->rx_offset = ( rtl->rx_offset % RTL_RXBUF_LEN );
+		writew ( ( rtl->rx_offset - 16 ), rtl->regs + RTL_CAPR );
+	}
+}
+
+/**
+ * Poll for received packets
+ *
+ * @v netdev		Network device
+ */
+static void realtek_poll_rx ( struct net_device *netdev ) {
+	struct realtek_nic *rtl = netdev->priv;
+	struct realtek_descriptor *rx;
+	struct io_buffer *iobuf;
+	unsigned int rx_idx;
+	size_t len;
+
+	/* Poll receive buffer if in legacy mode */
+	if ( rtl->legacy ) {
+		realtek_legacy_poll_rx ( netdev );
+		return;
+	}
+
+	/* Check for received packets */
+	while ( rtl->rx.cons != rtl->rx.prod ) {
+
+		/* Get next receive descriptor */
+		rx_idx = ( rtl->rx.cons % RTL_NUM_RX_DESC );
+		rx = &rtl->rx.desc[rx_idx];
+
+		/* Stop if descriptor is still in use */
+		if ( rx->flags & cpu_to_le16 ( RTL_DESC_OWN ) )
+			return;
+
+		/* Populate I/O buffer */
+		iobuf = rtl->rx_iobuf[rx_idx];
+		rtl->rx_iobuf[rx_idx] = NULL;
+		len = ( le16_to_cpu ( rx->length ) & RTL_DESC_SIZE_MASK );
+		iob_put ( iobuf, ( len - 4 /* strip CRC */ ) );
+
+		DBGC2 ( rtl, "REALTEK %p RX %d complete (length %zd)\n",
+			rtl, rx_idx, len );
+
+		/* Hand off to network stack */
+		if ( rx->flags & cpu_to_le16 ( RTL_DESC_RES ) ) {
+			netdev_rx_err ( netdev, iobuf, -EIO );
+		} else {
+			netdev_rx ( netdev, iobuf );
+		}
+		rtl->rx.cons++;
+	}
+}
+
+/**
+ * Poll for completed and received packets
+ *
+ * @v netdev		Network device
+ */
+static void realtek_poll ( struct net_device *netdev ) {
+	struct realtek_nic *rtl = netdev->priv;
+	uint16_t isr;
+
+	/* Check for and acknowledge interrupts */
+	isr = readw ( rtl->regs + RTL_ISR );
+	if ( ! isr )
+		return;
+	writew ( isr, rtl->regs + RTL_ISR );
+
+	/* Poll for TX completions, if applicable */
+	if ( isr & ( RTL_IRQ_TER | RTL_IRQ_TOK ) )
+		realtek_poll_tx ( netdev );
+
+	/* Poll for RX completionsm, if applicable */
+	if ( isr & ( RTL_IRQ_RER | RTL_IRQ_ROK ) )
+		realtek_poll_rx ( netdev );
+
+	/* Check link state, if applicable */
+	if ( isr & RTL_IRQ_PUN_LINKCHG )
+		realtek_check_link ( netdev );
+
+	/* Refill RX ring */
+	realtek_refill_rx ( rtl );
+}
+
+/**
+ * Enable or disable interrupts
+ *
+ * @v netdev		Network device
+ * @v enable		Interrupts should be enabled
+ */
+static void realtek_irq ( struct net_device *netdev, int enable ) {
+	struct realtek_nic *rtl = netdev->priv;
+	uint16_t imr;
+
+	/* Set interrupt mask */
+	imr = ( enable ? ( RTL_IRQ_PUN_LINKCHG | RTL_IRQ_TER | RTL_IRQ_TOK |
+			   RTL_IRQ_RER | RTL_IRQ_ROK ) : 0 );
+	writew ( imr, rtl->regs + RTL_IMR );
+}
+
+/** Realtek network device operations */
+static struct net_device_operations realtek_operations = {
+	.open		= realtek_open,
+	.close		= realtek_close,
+	.transmit	= realtek_transmit,
+	.poll		= realtek_poll,
+	.irq		= realtek_irq,
+};
+
+/******************************************************************************
+ *
+ * PCI interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Detect device type
+ *
+ * @v rtl		Realtek device
+ */
+static void realtek_detect ( struct realtek_nic *rtl ) {
+	uint16_t rms;
+	uint16_t check_rms;
+	uint16_t cpcr;
+	uint16_t check_cpcr;
+
+	/* The RX Packet Maximum Size register is present only on
+	 * 8169.  Try to set to our intended MTU.
+	 */
+	rms = RTL_RX_MAX_LEN;
+	writew ( rms, rtl->regs + RTL_RMS );
+	check_rms = readw ( rtl->regs + RTL_RMS );
+
+	/* The C+ Command register is present only on 8169 and 8139C+.
+	 * Try to enable C+ mode and PCI Dual Address Cycle (for
+	 * 64-bit systems), if supported.
+	 *
+	 * Note that enabling DAC seems to cause bizarre behaviour
+	 * (lockups, garbage data on the wire) on some systems, even
+	 * if only 32-bit addresses are used.
+	 */
+	cpcr = readw ( rtl->regs + RTL_CPCR );
+	cpcr |= ( RTL_CPCR_MULRW | RTL_CPCR_CPRX | RTL_CPCR_CPTX );
+	if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) )
+		cpcr |= RTL_CPCR_DAC;
+	writew ( cpcr, rtl->regs + RTL_CPCR );
+	check_cpcr = readw ( rtl->regs + RTL_CPCR );
+
+	/* Detect device type */
+	if ( check_rms == rms ) {
+		DBGC ( rtl, "REALTEK %p appears to be an RTL8169\n", rtl );
+		rtl->have_phy_regs = 1;
+		rtl->tppoll = RTL_TPPOLL_8169;
+	} else {
+		if ( ( check_cpcr == cpcr ) && ( cpcr != 0xffff ) ) {
+			DBGC ( rtl, "REALTEK %p appears to be an RTL8139C+\n",
+			       rtl );
+			rtl->tppoll = RTL_TPPOLL_8139CP;
+		} else {
+			DBGC ( rtl, "REALTEK %p appears to be an RTL8139\n",
+			       rtl );
+			rtl->legacy = 1;
+		}
+	}
+}
+
+/**
+ * Probe PCI device
+ *
+ * @v pci		PCI device
+ * @ret rc		Return status code
+ */
+static int realtek_probe ( struct pci_device *pci ) {
+	struct net_device *netdev;
+	struct realtek_nic *rtl;
+	unsigned int i;
+	int rc;
+
+	/* Allocate and initialise net device */
+	netdev = alloc_etherdev ( sizeof ( *rtl ) );
+	if ( ! netdev ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	netdev_init ( netdev, &realtek_operations );
+	rtl = netdev->priv;
+	pci_set_drvdata ( pci, netdev );
+	netdev->dev = &pci->dev;
+	memset ( rtl, 0, sizeof ( *rtl ) );
+	realtek_init_ring ( &rtl->tx, RTL_NUM_TX_DESC, RTL_TNPDS );
+	realtek_init_ring ( &rtl->rx, RTL_NUM_RX_DESC, RTL_RDSAR );
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pci );
+
+	/* Map registers */
+	rtl->regs = ioremap ( pci->membase, RTL_BAR_SIZE );
+
+	/* Reset the NIC */
+	if ( ( rc = realtek_reset ( rtl ) ) != 0 )
+		goto err_reset;
+
+	/* Detect device type */
+	realtek_detect ( rtl );
+
+	/* Initialise EEPROM */
+	realtek_init_eeprom ( netdev );
+
+	/* Read MAC address from EEPROM */
+	if ( ( rc = nvs_read ( &rtl->eeprom.nvs, RTL_EEPROM_MAC,
+			       netdev->hw_addr, ETH_ALEN ) ) != 0 ) {
+		DBGC ( rtl, "REALTEK %p could not read MAC address: %s\n",
+		       rtl, strerror ( rc ) );
+		goto err_nvs_read;
+	}
+
+	/* The EEPROM may not be present for onboard NICs.  Fall back
+	 * to reading the current ID register value, which will
+	 * hopefully have been programmed by the platform firmware.
+	 */
+	if ( ! is_valid_ether_addr ( netdev->hw_addr ) ) {
+		DBGC ( rtl, "REALTEK %p seems to have no EEPROM\n", rtl );
+		for ( i = 0 ; i < ETH_ALEN ; i++ )
+			netdev->hw_addr[i] = readb ( rtl->regs + RTL_IDR0 + i );
+	}
+
+	/* Initialise and reset MII interface */
+	mii_init ( &rtl->mii, &realtek_mii_operations );
+	if ( ( rc = realtek_phy_reset ( rtl ) ) != 0 )
+		goto err_phy_reset;
+
+	/* Register network device */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
+		goto err_register_netdev;
+
+	/* Set initial link state */
+	realtek_check_link ( netdev );
+
+	/* Register non-volatile options, if applicable */
+	if ( rtl->nvo.nvs ) {
+		if ( ( rc = register_nvo ( &rtl->nvo,
+					   netdev_settings ( netdev ) ) ) != 0)
+			goto err_register_nvo;
+	}
+
+	return 0;
+
+ err_register_nvo:
+	unregister_netdev ( netdev );
+ err_register_netdev:
+ err_phy_reset:
+ err_nvs_read:
+	realtek_reset ( rtl );
+ err_reset:
+	iounmap ( rtl->regs );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+ err_alloc:
+	return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci		PCI device
+ */
+static void realtek_remove ( struct pci_device *pci ) {
+	struct net_device *netdev = pci_get_drvdata ( pci );
+	struct realtek_nic *rtl = netdev->priv;
+
+	/* Unregister non-volatile options, if applicable */
+	if ( rtl->nvo.nvs )
+		unregister_nvo ( &rtl->nvo );
+
+	/* Unregister network device */
+	unregister_netdev ( netdev );
+
+	/* Reset card */
+	realtek_reset ( rtl );
+
+	/* Free network device */
+	iounmap ( rtl->regs );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+/** Realtek PCI device IDs */
+static struct pci_device_id realtek_nics[] = {
+	PCI_ROM ( 0x0001, 0x8168, "clone8169",	"Cloned 8169", 0 ),
+	PCI_ROM ( 0x018a, 0x0106, "fpc0106tx",	"LevelOne FPC-0106TX", 0 ),
+	PCI_ROM ( 0x021b, 0x8139, "hne300",	"Compaq HNE-300", 0 ),
+	PCI_ROM ( 0x02ac, 0x1012, "s1012",	"SpeedStream 1012", 0 ),
+	PCI_ROM ( 0x0357, 0x000a, "ttpmon",	"TTTech TTP-Monitoring", 0 ),
+	PCI_ROM ( 0x10ec, 0x8129, "rtl8129",	"RTL-8129", 0 ),
+	PCI_ROM ( 0x10ec, 0x8136, "rtl8136",	"RTL8101E/RTL8102E", 0 ),
+	PCI_ROM ( 0x10ec, 0x8138, "rtl8138",	"RT8139 (B/C)", 0 ),
+	PCI_ROM ( 0x10ec, 0x8139, "rtl8139",	"RTL-8139/8139C/8139C+", 0 ),
+	PCI_ROM ( 0x10ec, 0x8167, "rtl8167",	"RTL-8110SC/8169SC", 0 ),
+	PCI_ROM ( 0x10ec, 0x8168, "rtl8168",	"RTL8111/8168B", 0 ),
+	PCI_ROM ( 0x10ec, 0x8169, "rtl8169",	"RTL-8169", 0 ),
+	PCI_ROM ( 0x1113, 0x1211, "smc1211",	"SMC2-1211TX", 0 ),
+	PCI_ROM ( 0x1186, 0x1300, "dfe538",	"DFE530TX+/DFE538TX", 0 ),
+	PCI_ROM ( 0x1186, 0x1340, "dfe690",	"DFE-690TXD", 0 ),
+	PCI_ROM ( 0x1186, 0x4300, "dge528t",	"DGE-528T", 0 ),
+	PCI_ROM ( 0x11db, 0x1234, "sega8139",	"Sega Enterprises 8139", 0 ),
+	PCI_ROM ( 0x1259, 0xa117, "allied8139",	"Allied Telesyn 8139", 0 ),
+	PCI_ROM ( 0x1259, 0xa11e, "allied81xx",	"Allied Telesyn 81xx", 0 ),
+	PCI_ROM ( 0x1259, 0xc107, "allied8169",	"Allied Telesyn 8169", 0 ),
+	PCI_ROM ( 0x126c, 0x1211, "northen8139","Northern Telecom 8139", 0 ),
+	PCI_ROM ( 0x13d1, 0xab06, "fe2000vx",	"Abocom FE2000VX", 0 ),
+	PCI_ROM ( 0x1432, 0x9130, "edi8139",	"Edimax 8139", 0 ),
+	PCI_ROM ( 0x14ea, 0xab06, "fnw3603tx",	"Planex FNW-3603-TX", 0 ),
+	PCI_ROM ( 0x14ea, 0xab07, "fnw3800tx",	"Planex FNW-3800-TX", 0 ),
+	PCI_ROM ( 0x1500, 0x1360, "delta8139",	"Delta Electronics 8139", 0 ),
+	PCI_ROM ( 0x16ec, 0x0116, "usr997902",	"USR997902", 0 ),
+	PCI_ROM ( 0x1737, 0x1032, "linksys8169","Linksys 8169", 0 ),
+	PCI_ROM ( 0x1743, 0x8139, "rolf100",	"Peppercorn ROL/F-100", 0 ),
+	PCI_ROM ( 0x4033, 0x1360, "addron8139",	"Addtron 8139", 0 ),
+	PCI_ROM ( 0xffff, 0x8139, "clonse8139",	"Cloned 8139", 0 ),
+};
+
+/** Realtek PCI driver */
+struct pci_driver realtek_driver __pci_driver = {
+	.ids = realtek_nics,
+	.id_count = ( sizeof ( realtek_nics ) / sizeof ( realtek_nics[0] ) ),
+	.probe = realtek_probe,
+	.remove = realtek_remove,
+};
diff --git a/roms/ipxe/src/drivers/net/realtek.h b/roms/ipxe/src/drivers/net/realtek.h
new file mode 100644
index 0000000000000000000000000000000000000000..6a7b10a9314bc19f6306b8d481646fe016019a7f
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/realtek.h
@@ -0,0 +1,286 @@
+#ifndef _REALTEK_H
+#define _REALTEK_H
+
+/** @file
+ *
+ * Realtek 10/100/1000 network card driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/spi.h>
+#include <ipxe/spi_bit.h>
+#include <ipxe/nvo.h>
+#include <ipxe/if_ether.h>
+
+/** PCI memory BAR size */
+#define RTL_BAR_SIZE 0x100
+
+/** A packet descriptor */
+struct realtek_descriptor {
+	/** Buffer size */
+	uint16_t length;
+	/** Flags */
+	uint16_t flags;
+	/** Reserved */
+	uint32_t reserved;
+	/** Buffer address */
+	uint64_t address;
+} __attribute__ (( packed ));
+
+/** Descriptor buffer size mask */
+#define RTL_DESC_SIZE_MASK 0x3fff
+
+/** Packet descriptor flags */
+enum realtek_descriptor_flags {
+	/** Descriptor is owned by NIC */
+	RTL_DESC_OWN = 0x8000,
+	/** End of descriptor ring */
+	RTL_DESC_EOR = 0x4000,
+	/** First segment descriptor */
+	RTL_DESC_FS = 0x2000,
+	/** Last segment descriptor */
+	RTL_DESC_LS = 0x1000,
+	/** Receive error summary */
+	RTL_DESC_RES = 0x0020,
+};
+
+/** Descriptor ring alignment */
+#define RTL_RING_ALIGN 256
+
+/** A legacy mode receive packet header */
+struct realtek_legacy_header {
+	/** Status */
+	uint16_t status;
+	/** Length */
+	uint16_t length;
+	/** Packet data */
+	uint8_t data[0];
+} __attribute__ (( packed ));
+
+/** Legacy mode status bits */
+enum realtek_legacy_status {
+	/** Received OK */
+	RTL_STAT_ROK = 0x0001,
+};
+
+/** ID Register 0 (6 bytes) */
+#define RTL_IDR0 0x00
+
+/** Multicast Register 0 (dword) */
+#define RTL_MAR0 0x08
+
+/** Multicast Register 4 (dword) */
+#define RTL_MAR4 0x0c
+
+/** Transmit Status of Descriptor N (dword, 8139 only) */
+#define RTL_TSD(n) ( 0x10 + 4 * (n) )
+#define RTL_TSD_ERTXTH(x)	( (x) << 16 ) /**< Early TX threshold */
+#define RTL_TSD_ERTXTH_DEFAULT RTL_TSD_ERTXTH ( 256 / 32 )
+#define RTL_TSD_OWN		0x00002000UL /**< Ownership */
+
+/** Transmit Start Address of Descriptor N (dword, 8139 only) */
+#define RTL_TSAD(n) ( 0x20 + 4 * (n) )
+
+/** Transmit Normal Priority Descriptors (qword) */
+#define RTL_TNPDS 0x20
+
+/** Number of transmit descriptors
+ *
+ * This is a hardware limit when using legacy mode.
+ */
+#define RTL_NUM_TX_DESC 4
+
+/** Receive Buffer Start Address (dword, 8139 only) */
+#define RTL_RBSTART 0x30
+
+/** Receive buffer length */
+#define RTL_RXBUF_LEN 8192
+
+/** Receive buffer padding */
+#define RTL_RXBUF_PAD 2038 /* Allow space for WRAP */
+
+/** Receive buffer alignment */
+#define RTL_RXBUF_ALIGN 16
+
+/** Command Register (byte) */
+#define RTL_CR 0x37
+#define RTL_CR_RST		0x10	/**< Reset */
+#define RTL_CR_RE		0x08	/**< Receiver Enable */
+#define RTL_CR_TE		0x04	/**< Transmit Enable */
+#define RTL_CR_BUFE		0x01	/**< Receive buffer empty */
+
+/** Maximum time to wait for a reset, in milliseconds */
+#define RTL_RESET_MAX_WAIT_MS 100
+
+/** Current Address of Packet Read (word, 8139 only) */
+#define RTL_CAPR 0x38
+
+/** Transmit Priority Polling Register (byte, 8169 only) */
+#define RTL_TPPOLL_8169 0x38
+#define RTL_TPPOLL_NPQ		0x40	/**< Normal Priority Queue Polling */
+
+/** Interrupt Mask Register (word) */
+#define RTL_IMR 0x3c
+#define RTL_IRQ_PUN_LINKCHG	0x0020	/**< Packet underrun / link change */
+#define RTL_IRQ_TER		0x0008	/**< Transmit error */
+#define RTL_IRQ_TOK		0x0004	/**< Transmit OK */
+#define RTL_IRQ_RER		0x0002	/**< Receive error */
+#define RTL_IRQ_ROK		0x0001	/**< Receive OK */
+
+/** Interrupt Status Register (word) */
+#define RTL_ISR 0x3e
+
+/** Transmit (Tx) Configuration Register (dword) */
+#define RTL_TCR 0x40
+#define RTL_TCR_MXDMA(x)	( (x) << 8 ) /**< Max DMA burst size */
+#define RTL_TCR_MXDMA_MASK	RTL_TCR_MXDMA ( 0x7 )
+#define RTL_TCR_MXDMA_DEFAULT	RTL_TCR_MXDMA ( 0x7 /* Unlimited */ )
+
+/** Receive (Rx) Configuration Register (dword) */
+#define RTL_RCR 0x44
+#define RTL_RCR_RXFTH(x)	( (x) << 13 ) /**< Receive FIFO threshold */
+#define RTL_RCR_RXFTH_MASK	RTL_RCR_RXFTH ( 0x7 )
+#define RTL_RCR_RXFTH_DEFAULT	RTL_RCR_RXFTH ( 0x7 /* Whole packet */ )
+#define RTL_RCR_RBLEN(x)	( (x) << 11 ) /**< Receive buffer length */
+#define RTL_RCR_RBLEN_MASK	RTL_RCR_RBLEN ( 0x3 )
+#define RTL_RCR_RBLEN_DEFAULT	RTL_RCR_RBLEN ( 0 /* 8kB */ )
+#define RTL_RCR_MXDMA(x)	( (x) << 8 ) /**< Max DMA burst size */
+#define RTL_RCR_MXDMA_MASK	RTL_RCR_MXDMA ( 0x7 )
+#define RTL_RCR_MXDMA_DEFAULT	RTL_RCR_MXDMA ( 0x7 /* Unlimited */ )
+#define RTL_RCR_WRAP		0x00000080UL /**< Overrun receive buffer */
+#define RTL_RCR_9356SEL		0x00000040UL /**< EEPROM is a 93C56 */
+#define RTL_RCR_AB		0x00000008UL /**< Accept broadcast packets */
+#define RTL_RCR_AM		0x00000004UL /**< Accept multicast packets */
+#define RTL_RCR_APM		0x00000002UL /**< Accept physical match */
+#define RTL_RCR_AAP		0x00000001UL /**< Accept all packets */
+
+/** 93C46 (93C56) Command Register (byte) */
+#define RTL_9346CR 0x50
+#define RTL_9346CR_EEM(x)	( (x) << 6 ) /**< Mode select */
+#define RTL_9346CR_EEM_EEPROM	RTL_9346CR_EEM ( 0x2 ) /**< EEPROM mode */
+#define RTL_9346CR_EEM_NORMAL	RTL_9346CR_EEM ( 0x0 ) /**< Normal mode */
+#define RTL_9346CR_EECS		0x08	/**< Chip select */
+#define RTL_9346CR_EESK		0x04	/**< Clock */
+#define RTL_9346CR_EEDI		0x02	/**< Data in */
+#define RTL_9346CR_EEDO		0x01	/**< Data out */
+
+/** Word offset of MAC address within EEPROM */
+#define RTL_EEPROM_MAC ( 0x0e / 2 )
+
+/** Word offset of VPD / non-volatile options within EEPROM */
+#define RTL_EEPROM_VPD ( 0x40 / 2 )
+
+/** Length of VPD / non-volatile options within EEPROM */
+#define RTL_EEPROM_VPD_LEN 0x40
+
+/** Configuration Register 1 (byte) */
+#define RTL_CONFIG1 0x52
+#define RTL_CONFIG1_VPD		0x02	/**< Vital Product Data enabled */
+
+/** Media Status Register (byte, 8139 only) */
+#define RTL_MSR 0x58
+#define RTL_MSR_LINKB		0x04	/**< Inverse of link status */
+
+/** PHY Access Register (dword, 8169 only) */
+#define RTL_PHYAR 0x60
+#define RTL_PHYAR_FLAG		0x80000000UL /**< Read/write flag */
+
+/** Construct PHY Access Register value */
+#define RTL_PHYAR_VALUE( flag, reg, data ) ( (flag) | ( (reg) << 16 ) | (data) )
+
+/** Extract PHY Access Register data */
+#define RTL_PHYAR_DATA( value ) ( (value) & 0xffff )
+
+/** Maximum time to wait for PHY access, in microseconds */
+#define RTL_MII_MAX_WAIT_US 500
+
+/** PHY (GMII, MII, or TBI) Status Register (byte, 8169 only) */
+#define RTL_PHYSTATUS 0x6c
+#define RTL_PHYSTATUS_LINKSTS	0x02	/**< Link ok */
+
+/** Transmit Priority Polling Register (byte, 8139C+ only) */
+#define RTL_TPPOLL_8139CP 0xd9
+
+/** RX Packet Maximum Size Register (word) */
+#define RTL_RMS 0xda
+
+/** C+ Command Register (word) */
+#define RTL_CPCR 0xe0
+#define RTL_CPCR_DAC		0x0010	/**< PCI Dual Address Cycle Enable */
+#define RTL_CPCR_MULRW		0x0008	/**< PCI Multiple Read/Write Enable */
+#define RTL_CPCR_CPRX		0x0002	/**< C+ receive enable */
+#define RTL_CPCR_CPTX		0x0001	/**< C+ transmit enable */
+
+/** Receive Descriptor Start Address Register (qword) */
+#define RTL_RDSAR 0xe4
+
+/** Number of receive descriptors */
+#define RTL_NUM_RX_DESC 4
+
+/** Receive buffer length */
+#define RTL_RX_MAX_LEN ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ )
+
+/** A Realtek descriptor ring */
+struct realtek_ring {
+	/** Descriptors */
+	struct realtek_descriptor *desc;
+	/** Producer index */
+	unsigned int prod;
+	/** Consumer index */
+	unsigned int cons;
+
+	/** Descriptor start address register */
+	unsigned int reg;
+	/** Length (in bytes) */
+	size_t len;
+};
+
+/**
+ * Initialise descriptor ring
+ *
+ * @v ring		Descriptor ring
+ * @v count		Number of descriptors
+ * @v reg		Descriptor start address register
+ */
+static inline __attribute__ (( always_inline)) void
+realtek_init_ring ( struct realtek_ring *ring, unsigned int count,
+		    unsigned int reg ) {
+	ring->len = ( count * sizeof ( ring->desc[0] ) );
+	ring->reg = reg;
+}
+
+/** A Realtek network card */
+struct realtek_nic {
+	/** Registers */
+	void *regs;
+	/** SPI bit-bashing interface */
+	struct spi_bit_basher spibit;
+	/** EEPROM */
+	struct spi_device eeprom;
+	/** Non-volatile options */
+	struct nvo_block nvo;
+	/** MII interface */
+	struct mii_interface mii;
+
+	/** Legacy datapath mode */
+	int legacy;
+	/** PHYAR and PHYSTATUS registers are present */
+	int have_phy_regs;
+	/** TPPoll register offset */
+	unsigned int tppoll;
+
+	/** Transmit descriptor ring */
+	struct realtek_ring tx;
+	/** Receive descriptor ring */
+	struct realtek_ring rx;
+	/** Receive I/O buffers */
+	struct io_buffer *rx_iobuf[RTL_NUM_RX_DESC];
+	/** Receive buffer (legacy mode) */
+	void *rx_buffer;
+	/** Offset within receive buffer (legacy mode) */
+	unsigned int rx_offset;
+};
+
+#endif /* _REALTEK_H */
diff --git a/roms/ipxe/src/drivers/net/rtl8139.c b/roms/ipxe/src/drivers/net/rtl8139.c
deleted file mode 100644
index ebe84fb108db7f58c1b0619826acaeba825c786b..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/rtl8139.c
+++ /dev/null
@@ -1,596 +0,0 @@
-/* rtl8139.c - etherboot driver for the Realtek 8139 chipset
-
-  ported from the linux driver written by Donald Becker
-  by Rainer Bawidamann (Rainer.Bawidamann@informatik.uni-ulm.de) 1999
-
-  This software may be used and distributed according to the terms
-  of the GNU Public License, incorporated herein by reference.
-
-  changes to the original driver:
-  - removed support for interrupts, switching to polling mode (yuck!)
-  - removed support for the 8129 chip (external MII)
-
-*/
-
-FILE_LICENCE ( GPL_ANY );
-
-/*********************************************************************/
-/* Revision History                                                  */
-/*********************************************************************/
-
-/*
-  27 May 2006	mcb30@users.sourceforge.net (Michael Brown)
-     Rewrote to use the new net driver API, the updated PCI API, and
-     the generic three-wire serial device support for EEPROM access.
-
-  28 Dec 2002	ken_yap@users.sourceforge.net (Ken Yap)
-     Put in virt_to_bus calls to allow Etherboot relocation.
-
-  06 Apr 2001	ken_yap@users.sourceforge.net (Ken Yap)
-     Following email from Hyun-Joon Cha, added a disable routine, otherwise
-     NIC remains live and can crash the kernel later.
-
-  4 Feb 2000	espenlaub@informatik.uni-ulm.de (Klaus Espenlaub)
-     Shuffled things around, removed the leftovers from the 8129 support
-     that was in the Linux driver and added a bit more 8139 definitions.
-     Moved the 8K receive buffer to a fixed, available address outside the
-     0x98000-0x9ffff range.  This is a bit of a hack, but currently the only
-     way to make room for the Etherboot features that need substantial amounts
-     of code like the ANSI console support.  Currently the buffer is just below
-     0x10000, so this even conforms to the tagged boot image specification,
-     which reserves the ranges 0x00000-0x10000 and 0x98000-0xA0000.  My
-     interpretation of this "reserved" is that Etherboot may do whatever it
-     likes, as long as its environment is kept intact (like the BIOS
-     variables).  Hopefully fixed rtl_poll() once and for all.  The symptoms
-     were that if Etherboot was left at the boot menu for several minutes, the
-     first eth_poll failed.  Seems like I am the only person who does this.
-     First of all I fixed the debugging code and then set out for a long bug
-     hunting session.  It took me about a week full time work - poking around
-     various places in the driver, reading Don Becker's and Jeff Garzik's Linux
-     driver and even the FreeBSD driver (what a piece of crap!) - and
-     eventually spotted the nasty thing: the transmit routine was acknowledging
-     each and every interrupt pending, including the RxOverrun and RxFIFIOver
-     interrupts.  This confused the RTL8139 thoroughly.  It destroyed the
-     Rx ring contents by dumping the 2K FIFO contents right where we wanted to
-     get the next packet.  Oh well, what fun.
-
-  18 Jan 2000   mdc@etherboot.org (Marty Connor)
-     Drastically simplified error handling.  Basically, if any error
-     in transmission or reception occurs, the card is reset.
-     Also, pointed all transmit descriptors to the same buffer to
-     save buffer space.  This should decrease driver size and avoid
-     corruption because of exceeding 32K during runtime.
-
-  28 Jul 1999   (Matthias Meixner - meixner@rbg.informatik.tu-darmstadt.de)
-     rtl_poll was quite broken: it used the RxOK interrupt flag instead
-     of the RxBufferEmpty flag which often resulted in very bad
-     transmission performace - below 1kBytes/s.
-
-*/
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ipxe/io.h>
-#include <errno.h>
-#include <unistd.h>
-#include <byteswap.h>
-#include <ipxe/pci.h>
-#include <ipxe/if_ether.h>
-#include <ipxe/ethernet.h>
-#include <ipxe/iobuf.h>
-#include <ipxe/netdevice.h>
-#include <ipxe/spi_bit.h>
-#include <ipxe/threewire.h>
-#include <ipxe/nvo.h>
-
-#define TX_RING_SIZE 4
-#define TX_MAX_LEN 8192
-
-struct rtl8139_tx {
-	unsigned int next;
-	struct io_buffer *iobuf[TX_RING_SIZE];
-};
-
-struct rtl8139_rx {
-	void *ring;
-	unsigned int offset;
-};
-
-struct rtl8139_nic {
-	unsigned short ioaddr;
-	struct rtl8139_tx tx;
-	struct rtl8139_rx rx;
-	struct spi_bit_basher spibit;
-	struct spi_device eeprom;
-	struct nvo_block nvo;
-};
-
-/* Tuning Parameters */
-#define TX_FIFO_THRESH	256	/* In bytes, rounded down to 32 byte units. */
-#define RX_FIFO_THRESH	4	/* Rx buffer level before first PCI xfer.  */
-#define RX_DMA_BURST	4	/* Maximum PCI burst, '4' is 256 bytes */
-#define TX_DMA_BURST	4	/* Calculate as 16<<val. */
-#define TX_IPG		3	/* This is the only valid value */
-#define RX_BUF_LEN_IDX	0	/* 0, 1, 2 is allowed - 8,16,32K rx buffer */
-#define RX_BUF_LEN ( (8192 << RX_BUF_LEN_IDX) )
-#define RX_BUF_PAD 4
-
-/* Symbolic offsets to registers. */
-enum RTL8139_registers {
-	MAC0=0,			/* Ethernet hardware address. */
-	MAR0=8,			/* Multicast filter. */
-	TxStatus0=0x10,		/* Transmit status (four 32bit registers). */
-	TxAddr0=0x20,		/* Tx descriptors (also four 32bit). */
-	RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
-	ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
-	IntrMask=0x3C, IntrStatus=0x3E,
-	TxConfig=0x40, RxConfig=0x44,
-	Timer=0x48,		/* general-purpose counter. */
-	RxMissed=0x4C,		/* 24 bits valid, write clears. */
-	Cfg9346=0x50, Config0=0x51, Config1=0x52,
-	TimerIntrReg=0x54,	/* intr if gp counter reaches this value */
-	MediaStatus=0x58,
-	Config3=0x59,
-	MultiIntr=0x5C,
-	RevisionID=0x5E,	/* revision of the RTL8139 chip */
-	TxSummary=0x60,
-	MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68,
-	NWayExpansion=0x6A,
-	DisconnectCnt=0x6C, FalseCarrierCnt=0x6E,
-	NWayTestReg=0x70,
-	RxCnt=0x72,		/* packet received counter */
-	CSCR=0x74,		/* chip status and configuration register */
-	PhyParm1=0x78,TwisterParm=0x7c,PhyParm2=0x80,	/* undocumented */
-	/* from 0x84 onwards are a number of power management/wakeup frame
-	 * definitions we will probably never need to know about.  */
-};
-
-enum RxEarlyStatusBits {
-	ERGood=0x08, ERBad=0x04, EROVW=0x02, EROK=0x01
-};
-
-enum ChipCmdBits {
-	CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, };
-
-enum IntrMaskBits {
-	SERR=0x8000, TimeOut=0x4000, LenChg=0x2000,
-	FOVW=0x40, PUN_LinkChg=0x20, RXOVW=0x10,
-	TER=0x08, TOK=0x04, RER=0x02, ROK=0x01
-};
-
-/* Interrupt register bits, using my own meaningful names. */
-enum IntrStatusBits {
-	PCIErr=0x8000, PCSTimeout=0x4000, CableLenChange= 0x2000,
-	RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10,
-	TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01,
-};
-enum TxStatusBits {
-	TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000,
-	TxOutOfWindow=0x20000000, TxAborted=0x40000000,
-	TxCarrierLost=0x80000000,
-};
-enum RxStatusBits {
-	RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000,
-	RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004,
-	RxBadAlign=0x0002, RxStatusOK=0x0001,
-};
-
-enum MediaStatusBits {
-	MSRTxFlowEnable=0x80, MSRRxFlowEnable=0x40, MSRSpeed10=0x08,
-	MSRLinkFail=0x04, MSRRxPauseFlag=0x02, MSRTxPauseFlag=0x01,
-};
-
-enum MIIBMCRBits {
-	BMCRReset=0x8000, BMCRSpeed100=0x2000, BMCRNWayEnable=0x1000,
-	BMCRRestartNWay=0x0200, BMCRDuplex=0x0100,
-};
-
-enum CSCRBits {
-	CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
-	CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
-	CSCR_LinkDownCmd=0x0f3c0,
-};
-
-enum RxConfigBits {
-	RxCfgWrap=0x80,
-	Eeprom9356=0x40,
-	AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08,
-	AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,
-};
-
-enum Config1Bits {
-	VPDEnable=0x02,
-};
-
-/*  EEPROM access */
-#define EE_M1		0x80	/* Mode select bit 1 */
-#define EE_M0		0x40	/* Mode select bit 0 */
-#define EE_CS		0x08	/* EEPROM chip select */
-#define EE_SK		0x04	/* EEPROM shift clock */
-#define EE_DI		0x02	/* Data in */
-#define EE_DO		0x01	/* Data out */
-
-/* Offsets within EEPROM (these are word offsets) */
-#define EE_MAC 7
-
-static const uint8_t rtl_ee_bits[] = {
-	[SPI_BIT_SCLK]	= EE_SK,
-	[SPI_BIT_MOSI]	= EE_DI,
-	[SPI_BIT_MISO]	= EE_DO,
-	[SPI_BIT_SS(0)]	= ( EE_CS | EE_M1 ),
-};
-
-static int rtl_spi_read_bit ( struct bit_basher *basher,
-			      unsigned int bit_id ) {
-	struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic,
-						 spibit.basher );
-	uint8_t mask = rtl_ee_bits[bit_id];
-	uint8_t eereg;
-
-	eereg = inb ( rtl->ioaddr + Cfg9346 );
-	return ( eereg & mask );
-}
-
-static void rtl_spi_write_bit ( struct bit_basher *basher,
-				unsigned int bit_id, unsigned long data ) {
-	struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic,
-						 spibit.basher );
-	uint8_t mask = rtl_ee_bits[bit_id];
-	uint8_t eereg;
-
-	eereg = inb ( rtl->ioaddr + Cfg9346 );
-	eereg &= ~mask;
-	eereg |= ( data & mask );
-	outb ( eereg, rtl->ioaddr + Cfg9346 );
-}
-
-static struct bit_basher_operations rtl_basher_ops = {
-	.read = rtl_spi_read_bit,
-	.write = rtl_spi_write_bit,
-};
-
-/**
- * Set up for EEPROM access
- *
- * @v netdev		Net device
- */
-static void rtl_init_eeprom ( struct net_device *netdev ) {
-	struct rtl8139_nic *rtl = netdev->priv;
-	int ee9356;
-	int vpd;
-
-	/* Initialise three-wire bus */
-	rtl->spibit.basher.op = &rtl_basher_ops;
-	rtl->spibit.bus.mode = SPI_MODE_THREEWIRE;
-	init_spi_bit_basher ( &rtl->spibit );
-
-	/* Detect EEPROM type and initialise three-wire device */
-	ee9356 = ( inw ( rtl->ioaddr + RxConfig ) & Eeprom9356 );
-	if ( ee9356 ) {
-		DBGC ( rtl, "rtl8139 %p EEPROM is an AT93C56\n", rtl );
-		init_at93c56 ( &rtl->eeprom, 16 );
-	} else {
-		DBGC ( rtl, "rtl8139 %p EEPROM is an AT93C46\n", rtl );
-		init_at93c46 ( &rtl->eeprom, 16 );
-	}
-	rtl->eeprom.bus = &rtl->spibit.bus;
-
-	/* Initialise space for non-volatile options, if available
-	 *
-	 * We use offset 0x40 (i.e. address 0x20), length 0x40.  This
-	 * block is marked as VPD in the rtl8139 datasheets, so we use
-	 * it only if we detect that the card is not supporting VPD.
-	 */
-	vpd = ( inw ( rtl->ioaddr + Config1 ) & VPDEnable );
-	if ( vpd ) {
-		DBGC ( rtl, "rtl8139 %p EEPROM in use for VPD; cannot use "
-		       "for options\n", rtl );
-	} else {
-		nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, 0x20, 0x40, NULL,
-			   &netdev->refcnt );
-	}
-}
-
-/**
- * Reset NIC
- *
- * @v netdev		Net device
- *
- * Issues a hardware reset and waits for the reset to complete.
- */
-static void rtl_reset ( struct net_device *netdev ) {
-	struct rtl8139_nic *rtl = netdev->priv;
-
-	/* Reset chip */
-	outb ( CmdReset, rtl->ioaddr + ChipCmd );
-	mdelay ( 10 );
-	memset ( &rtl->tx, 0, sizeof ( rtl->tx ) );
-	rtl->rx.offset = 0;
-}
-
-/**
- * Open NIC
- *
- * @v netdev		Net device
- * @ret rc		Return status code
- */
-static int rtl_open ( struct net_device *netdev ) {
-	struct rtl8139_nic *rtl = netdev->priv;
-	int i;
-
-	/* Program the MAC address */
-	for ( i = 0 ; i < ETH_ALEN ; i++ )
-		outb ( netdev->ll_addr[i], rtl->ioaddr + MAC0 + i );
-
-	/* Set up RX ring */
-	rtl->rx.ring = malloc ( RX_BUF_LEN + RX_BUF_PAD );
-	if ( ! rtl->rx.ring )
-		return -ENOMEM;
-	outl ( virt_to_bus ( rtl->rx.ring ), rtl->ioaddr + RxBuf );
-	DBGC ( rtl, "rtl8139 %p RX ring at %lx\n",
-	       rtl, virt_to_bus ( rtl->rx.ring ) );
-
-	/* Enable TX and RX */
-	outb ( ( CmdRxEnb | CmdTxEnb ), rtl->ioaddr + ChipCmd );
-	outl ( ( ( RX_FIFO_THRESH << 13 ) | ( RX_BUF_LEN_IDX << 11 ) |
-		 ( RX_DMA_BURST << 8 ) | AcceptBroadcast | AcceptMulticast |
-		 AcceptMyPhys | AcceptAllPhys ), rtl->ioaddr + RxConfig );
-	outl ( 0xffffffffUL, rtl->ioaddr + MAR0 + 0 );
-	outl ( 0xffffffffUL, rtl->ioaddr + MAR0 + 4 );
-	outl ( ( ( TX_DMA_BURST << 8 ) | ( TX_IPG << 24 ) ),
-	       rtl->ioaddr + TxConfig );
-
-	return 0;
-}
-
-/**
- * Close NIC
- *
- * @v netdev		Net device
- */
-static void rtl_close ( struct net_device *netdev ) {
-	struct rtl8139_nic *rtl = netdev->priv;
-
-	/* Reset the hardware to disable everything in one go */
-	rtl_reset ( netdev );
-
-	/* Free RX ring */
-	free ( rtl->rx.ring );
-	rtl->rx.ring = NULL;
-}
-
-/** 
- * Transmit packet
- *
- * @v netdev	Network device
- * @v iobuf	I/O buffer
- * @ret rc	Return status code
- */
-static int rtl_transmit ( struct net_device *netdev,
-			  struct io_buffer *iobuf ) {
-	struct rtl8139_nic *rtl = netdev->priv;
-
-	/* Check for space in TX ring */
-	if ( rtl->tx.iobuf[rtl->tx.next] != NULL ) {
-		DBGC ( rtl, "rtl8139 %p TX overflow\n", rtl );
-		return -ENOBUFS;
-	}
-
-	/* Check for oversized packets */
-	if ( iob_len ( iobuf ) >= TX_MAX_LEN ) {
-		DBGC ( rtl, "rtl8139 %p TX too large (%zd bytes)\n",
-		       rtl, iob_len ( iobuf ) );
-		return -ERANGE;
-	}
-
-	/* Pad and align packet */
-	iob_pad ( iobuf, ETH_ZLEN );
-
-	/* Add to TX ring */
-	DBGC2 ( rtl, "rtl8139 %p TX id %d at %lx+%zx\n", rtl, rtl->tx.next,
-		virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
-	rtl->tx.iobuf[rtl->tx.next] = iobuf;
-	outl ( virt_to_bus ( iobuf->data ),
-	       rtl->ioaddr + TxAddr0 + 4 * rtl->tx.next );
-	outl ( ( ( ( TX_FIFO_THRESH & 0x7e0 ) << 11 ) | iob_len ( iobuf ) ),
-	       rtl->ioaddr + TxStatus0 + 4 * rtl->tx.next );
-	rtl->tx.next = ( rtl->tx.next + 1 ) % TX_RING_SIZE;
-
-	return 0;
-}
-
-/**
- * Poll for received packets
- *
- * @v netdev	Network device
- */
-static void rtl_poll ( struct net_device *netdev ) {
-	struct rtl8139_nic *rtl = netdev->priv;
-	unsigned int status;
-	unsigned int tsad;
-	unsigned int rx_status;
-	unsigned int rx_len;
-	struct io_buffer *rx_iob;
-	int wrapped_len;
-	int i;
-
-	/* Acknowledge interrupts */
-	status = inw ( rtl->ioaddr + IntrStatus );
-	if ( ! status )
-		return;
-	outw ( status, rtl->ioaddr + IntrStatus );
-
-	/* Handle TX completions */
-	tsad = inw ( rtl->ioaddr + TxSummary );
-	for ( i = 0 ; i < TX_RING_SIZE ; i++ ) {
-		if ( ( rtl->tx.iobuf[i] != NULL ) && ( tsad & ( 1 << i ) ) ) {
-			DBGC2 ( rtl, "rtl8139 %p TX id %d complete\n",
-				rtl, i );
-			netdev_tx_complete ( netdev, rtl->tx.iobuf[i] );
-			rtl->tx.iobuf[i] = NULL;
-		}
-	}
-
-	/* Handle received packets */
-	while ( ! ( inw ( rtl->ioaddr + ChipCmd ) & RxBufEmpty ) ) {
-		rx_status = * ( ( uint16_t * )
-				( rtl->rx.ring + rtl->rx.offset ) );
-		rx_len = * ( ( uint16_t * )
-			     ( rtl->rx.ring + rtl->rx.offset + 2 ) );
-		if ( rx_status & RxOK ) {
-			DBGC2 ( rtl, "rtl8139 %p RX packet at offset "
-				"%x+%x\n", rtl, rtl->rx.offset, rx_len );
-
-			rx_iob = alloc_iob ( rx_len );
-			if ( ! rx_iob ) {
-				netdev_rx_err ( netdev, NULL, -ENOMEM );
-				/* Leave packet for next call to poll() */
-				break;
-			}
-
-			wrapped_len = ( ( rtl->rx.offset + 4 + rx_len )
-					- RX_BUF_LEN );
-			if ( wrapped_len < 0 )
-				wrapped_len = 0;
-
-			memcpy ( iob_put ( rx_iob, rx_len - wrapped_len ),
-				 rtl->rx.ring + rtl->rx.offset + 4,
-				 rx_len - wrapped_len );
-			memcpy ( iob_put ( rx_iob, wrapped_len ),
-				 rtl->rx.ring, wrapped_len );
-			iob_unput ( rx_iob, 4 ); /* Strip CRC */
-
-			netdev_rx ( netdev, rx_iob );
-		} else {
-			DBGC ( rtl, "rtl8139 %p RX bad packet (status %#04x "
-			       "len %d)\n", rtl, rx_status, rx_len );
-			netdev_rx_err ( netdev, NULL, -EINVAL );
-		}
-		rtl->rx.offset = ( ( ( rtl->rx.offset + 4 + rx_len + 3 ) & ~3 )
-				   % RX_BUF_LEN );
-		outw ( rtl->rx.offset - 16, rtl->ioaddr + RxBufPtr );
-	}
-}
-
-/**
- * Enable/disable interrupts
- *
- * @v netdev	Network device
- * @v enable	Interrupts should be enabled
- */
-static void rtl_irq ( struct net_device *netdev, int enable ) {
-	struct rtl8139_nic *rtl = netdev->priv;
-
-	DBGC ( rtl, "rtl8139 %p interrupts %s\n",
-	       rtl, ( enable ? "enabled" : "disabled" ) );
-	outw ( ( enable ? ( ROK | RER | TOK | TER ) : 0 ),
-	       rtl->ioaddr + IntrMask );
-}
-
-/** RTL8139 net device operations */
-static struct net_device_operations rtl_operations = {
-	.open		= rtl_open,
-	.close		= rtl_close,
-	.transmit	= rtl_transmit,
-	.poll		= rtl_poll,
-	.irq		= rtl_irq,
-};
-
-/**
- * Probe PCI device
- *
- * @v pci	PCI device
- * @v id	PCI ID
- * @ret rc	Return status code
- */
-static int rtl_probe ( struct pci_device *pci ) {
-	struct net_device *netdev;
-	struct rtl8139_nic *rtl;
-	int rc;
-
-	/* Allocate net device */
-	netdev = alloc_etherdev ( sizeof ( *rtl ) );
-	if ( ! netdev )
-		return -ENOMEM;
-	netdev_init ( netdev, &rtl_operations );
-	rtl = netdev->priv;
-	pci_set_drvdata ( pci, netdev );
-	netdev->dev = &pci->dev;
-	memset ( rtl, 0, sizeof ( *rtl ) );
-	rtl->ioaddr = pci->ioaddr;
-
-	/* Fix up PCI device */
-	adjust_pci_device ( pci );
-
-	/* Reset the NIC, set up EEPROM access and read MAC address */
-	rtl_reset ( netdev );
-	rtl_init_eeprom ( netdev );
-	nvs_read ( &rtl->eeprom.nvs, EE_MAC, netdev->hw_addr, ETH_ALEN );
-
-	/* Register network device */
-	if ( ( rc = register_netdev ( netdev ) ) != 0 )
-		goto err_register_netdev;
-
-	/* Mark as link up; we don't yet handle link state */
-	netdev_link_up ( netdev );
-
-	/* Register non-volatile storage */
-	if ( rtl->nvo.nvs ) {
-		if ( ( rc = register_nvo ( &rtl->nvo,
-					   netdev_settings ( netdev ) ) ) != 0)
-			goto err_register_nvo;
-	}
-
-	return 0;
-
- err_register_nvo:
-	unregister_netdev ( netdev );
- err_register_netdev:
-	rtl_reset ( netdev );
-	netdev_nullify ( netdev );
-	netdev_put ( netdev );
-	return rc;
-}
-
-/**
- * Remove PCI device
- *
- * @v pci	PCI device
- */
-static void rtl_remove ( struct pci_device *pci ) {
-	struct net_device *netdev = pci_get_drvdata ( pci );
-	struct rtl8139_nic *rtl = netdev->priv;
-
-	if ( rtl->nvo.nvs )
-		unregister_nvo ( &rtl->nvo );
-	unregister_netdev ( netdev );
-	rtl_reset ( netdev );
-	netdev_nullify ( netdev );
-	netdev_put ( netdev );
-}
-
-static struct pci_device_id rtl8139_nics[] = {
-PCI_ROM(0x10ec, 0x8129, "rtl8129",       "Realtek 8129", 0),
-PCI_ROM(0x10ec, 0x8139, "rtl8139",       "Realtek 8139", 0),
-PCI_ROM(0x10ec, 0x8138, "rtl8139b",      "Realtek 8139B", 0),
-PCI_ROM(0x1186, 0x1300, "dfe538",        "DFE530TX+/DFE538TX", 0),
-PCI_ROM(0x1113, 0x1211, "smc1211-1",     "SMC EZ10/100", 0),
-PCI_ROM(0x1112, 0x1211, "smc1211",       "SMC EZ10/100", 0),
-PCI_ROM(0x1500, 0x1360, "delta8139",     "Delta Electronics 8139", 0),
-PCI_ROM(0x4033, 0x1360, "addtron8139",   "Addtron Technology 8139", 0),
-PCI_ROM(0x1186, 0x1340, "dfe690txd",     "D-Link DFE690TXD", 0),
-PCI_ROM(0x13d1, 0xab06, "fe2000vx",      "AboCom FE2000VX", 0),
-PCI_ROM(0x1259, 0xa117, "allied8139",    "Allied Telesyn 8139", 0),
-PCI_ROM(0x14ea, 0xab06, "fnw3603tx",     "Planex FNW-3603-TX", 0),
-PCI_ROM(0x14ea, 0xab07, "fnw3800tx",     "Planex FNW-3800-TX", 0),
-PCI_ROM(0xffff, 0x8139, "clone-rtl8139", "Cloned 8139", 0),
-};
-
-struct pci_driver rtl8139_driver __pci_driver = {
-	.ids = rtl8139_nics,
-	.id_count = ( sizeof ( rtl8139_nics ) / sizeof ( rtl8139_nics[0] ) ),
-	.probe = rtl_probe,
-	.remove = rtl_remove,
-};
diff --git a/roms/ipxe/src/drivers/net/sis190.h b/roms/ipxe/src/drivers/net/sis190.h
index fc6cb4b65d22f49042e6dae4122f..0551333d50da4ccf66fba9752c79 100644
--- a/roms/ipxe/src/drivers/net/sis190.h
+++ b/roms/ipxe/src/drivers/net/sis190.h
@@ -77,7 +77,7 @@ enum sis190_registers {
 	IntrStatus		= 0x20,
 	IntrMask		= 0x24,
 	IntrControl		= 0x28,
-	IntrTimer		= 0x2c,	// unused (Interupt Timer)
+	IntrTimer		= 0x2c,	// unused (Interrupt Timer)
 	PMControl		= 0x30,	// unused (Power Mgmt Control/Status)
 	rsv2			= 0x34,	// reserved
 	ROMControl		= 0x38,
@@ -218,7 +218,7 @@ enum _DescStatusBit {
 	RxSizeMask	= 0x0000ffff
 	/*
 	* The asic could apparently do vlan, TSO, jumbo (sis191 only) and
-	* provide two (unused with Linux) Tx queues. No publically
+	* provide two (unused with Linux) Tx queues. No publicly
 	* available documentation alas.
 	*/
 };
diff --git a/roms/ipxe/src/drivers/net/sis900.c b/roms/ipxe/src/drivers/net/sis900.c
index 92eb5ce244d5b7719e4cbcbac555..75e9ef962e4cc74ca042a1774c78 100644
--- a/roms/ipxe/src/drivers/net/sis900.c
+++ b/roms/ipxe/src/drivers/net/sis900.c
@@ -328,7 +328,7 @@ static int sis635_get_mac_addr(struct pci_device * pci_dev __unused, struct nic
  *
  * Side effects:
  *            leaves the ioaddress of the sis900 chip in the variable ioaddr.
- *            leaves the sis900 initialized, and ready to recieve packets.
+ *            leaves the sis900 initialized, and ready to receive packets.
  *
  * Returns:   struct nic *:          pointer to NIC data structure
  */
@@ -394,7 +394,7 @@ static int sis900_probe ( struct nic *nic, struct pci_device *pci ) {
 
         mii_status = sis900_mdio_read(phy_addr, MII_STATUS);
         if (mii_status == 0xffff || mii_status == 0x0000)
-            /* the mii is not accessable, try next one */
+            /* the mii is not accessible, try next one */
             continue;
                 
         phy_id0 = sis900_mdio_read(phy_addr, MII_PHY_ID0);
@@ -508,7 +508,7 @@ static u16 sis900_read_eeprom(int location)
 /* 
    Read and write the MII management registers using software-generated
    serial MDIO protocol. Note that the command bits and data bits are
-   send out seperately 
+   sent out separately
 */
 
 static void sis900_mdio_idle(long mdio_addr)
@@ -1171,8 +1171,8 @@ sis900_transmit(struct nic  *nic,
  *
  * Arguments: struct nic *nic:          NIC data structure
  *
- * Returns:   1 if a packet was recieved.
- *            0 if no pacet was recieved.
+ * Returns:   1 if a packet was received.
+ *            0 if no packet was received.
  *
  * Side effects:
  *            Returns (copies) the packet to the array nic->packet.
diff --git a/roms/ipxe/src/drivers/net/skeleton.c b/roms/ipxe/src/drivers/net/skeleton.c
new file mode 100644
index 0000000000000000000000000000000000000000..e50b778a89ae381ae46185cc228ec95f70c4a465
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/skeleton.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+#include <ipxe/mii.h>
+#include "skeleton.h"
+
+/** @file
+ *
+ * Skeleton network driver
+ *
+ */
+
+/******************************************************************************
+ *
+ * MII interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Read from MII register
+ *
+ * @v mii		MII interface
+ * @v reg		Register address
+ * @ret value		Data read, or negative error
+ */
+static int skeleton_mii_read ( struct mii_interface *mii, unsigned int reg ) {
+	struct skeleton_nic *skel =
+		container_of ( mii, struct skeleton_nic, mii );
+
+	DBGC ( skel, "SKELETON %p does not yet support MII read\n", skel );
+	( void ) reg;
+	return -ENOTSUP;
+}
+
+/**
+ * Write to MII register
+ *
+ * @v mii		MII interface
+ * @v reg		Register address
+ * @v data		Data to write
+ * @ret rc		Return status code
+ */
+static int skeleton_mii_write ( struct mii_interface *mii, unsigned int reg,
+				unsigned int data) {
+	struct skeleton_nic *skel =
+		container_of ( mii, struct skeleton_nic, mii );
+
+	DBGC ( skel, "SKELETON %p does not yet support MII write\n", skel );
+	( void ) reg;
+	( void ) data;
+	return -ENOTSUP;
+}
+
+/** Skeleton MII operations */
+static struct mii_operations skeleton_mii_operations = {
+	.read = skeleton_mii_read,
+	.write = skeleton_mii_write,
+};
+
+/******************************************************************************
+ *
+ * Device reset
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Reset hardware
+ *
+ * @v skel		Skeleton device
+ * @ret rc		Return status code
+ */
+static int skeleton_reset ( struct skeleton_nic *skel ) {
+
+	DBGC ( skel, "SKELETON %p does not yet support reset\n", skel );
+	return -ENOTSUP;
+}
+
+/******************************************************************************
+ *
+ * Link state
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Check link state
+ *
+ * @v netdev		Network device
+ */
+static void skeleton_check_link ( struct net_device *netdev ) {
+	struct skeleton_nic *skel = netdev->priv;
+
+	DBGC ( skel, "SKELETON %p does not yet support link state\n", skel );
+	netdev_link_err ( netdev, -ENOTSUP );
+}
+
+/******************************************************************************
+ *
+ * Network device interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open network device
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int skeleton_open ( struct net_device *netdev ) {
+	struct skeleton_nic *skel = netdev->priv;
+
+	DBGC ( skel, "SKELETON %p does not yet support open\n", skel );
+	return -ENOTSUP;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev		Network device
+ */
+static void skeleton_close ( struct net_device *netdev ) {
+	struct skeleton_nic *skel = netdev->priv;
+
+	DBGC ( skel, "SKELETON %p does not yet support close\n", skel );
+}
+
+/**
+ * Transmit packet
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int skeleton_transmit ( struct net_device *netdev,
+			       struct io_buffer *iobuf ) {
+	struct skeleton_nic *skel = netdev->priv;
+
+	DBGC ( skel, "SKELETON %p does not yet support transmit\n", skel );
+	( void ) iobuf;
+	return -ENOTSUP;
+}
+
+/**
+ * Poll for completed and received packets
+ *
+ * @v netdev		Network device
+ */
+static void skeleton_poll ( struct net_device *netdev ) {
+	struct skeleton_nic *skel = netdev->priv;
+
+	/* Not yet implemented */
+	( void ) skel;
+}
+
+/**
+ * Enable or disable interrupts
+ *
+ * @v netdev		Network device
+ * @v enable		Interrupts should be enabled
+ */
+static void skeleton_irq ( struct net_device *netdev, int enable ) {
+	struct skeleton_nic *skel = netdev->priv;
+
+	DBGC ( skel, "SKELETON %p does not yet support interrupts\n", skel );
+	( void ) enable;
+}
+
+/** Skeleton network device operations */
+static struct net_device_operations skeleton_operations = {
+	.open		= skeleton_open,
+	.close		= skeleton_close,
+	.transmit	= skeleton_transmit,
+	.poll		= skeleton_poll,
+	.irq		= skeleton_irq,
+};
+
+/******************************************************************************
+ *
+ * PCI interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Probe PCI device
+ *
+ * @v pci		PCI device
+ * @ret rc		Return status code
+ */
+static int skeleton_probe ( struct pci_device *pci ) {
+	struct net_device *netdev;
+	struct skeleton_nic *skel;
+	int rc;
+
+	/* Allocate and initialise net device */
+	netdev = alloc_etherdev ( sizeof ( *skel ) );
+	if ( ! netdev ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	netdev_init ( netdev, &skeleton_operations );
+	skel = netdev->priv;
+	pci_set_drvdata ( pci, netdev );
+	netdev->dev = &pci->dev;
+	memset ( skel, 0, sizeof ( *skel ) );
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pci );
+
+	/* Map registers */
+	skel->regs = ioremap ( pci->membase, SKELETON_BAR_SIZE );
+
+	/* Reset the NIC */
+	if ( ( rc = skeleton_reset ( skel ) ) != 0 )
+		goto err_reset;
+
+	/* Initialise and reset MII interface */
+	mii_init ( &skel->mii, &skeleton_mii_operations );
+	if ( ( rc = mii_reset ( &skel->mii ) ) != 0 ) {
+		DBGC ( skel, "SKELETON %p could not reset MII: %s\n",
+		       skel, strerror ( rc ) );
+		goto err_mii_reset;
+	}
+
+	/* Register network device */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
+		goto err_register_netdev;
+
+	/* Set initial link state */
+	skeleton_check_link ( netdev );
+
+	return 0;
+
+	unregister_netdev ( netdev );
+ err_register_netdev:
+ err_mii_reset:
+	skeleton_reset ( skel );
+ err_reset:
+	iounmap ( skel->regs );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+ err_alloc:
+	return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci		PCI device
+ */
+static void skeleton_remove ( struct pci_device *pci ) {
+	struct net_device *netdev = pci_get_drvdata ( pci );
+	struct skeleton_nic *skel = netdev->priv;
+
+	/* Unregister network device */
+	unregister_netdev ( netdev );
+
+	/* Reset card */
+	skeleton_reset ( skel );
+
+	/* Free network device */
+	iounmap ( skel->regs );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+/** Skeleton PCI device IDs */
+static struct pci_device_id skeleton_nics[] = {
+	PCI_ROM ( 0x5ce1, 0x5ce1, "skel",	"Skeleton", 0 ),
+};
+
+/** Skeleton PCI driver */
+struct pci_driver skeleton_driver __pci_driver = {
+	.ids = skeleton_nics,
+	.id_count = ( sizeof ( skeleton_nics ) / sizeof ( skeleton_nics[0] ) ),
+	.probe = skeleton_probe,
+	.remove = skeleton_remove,
+};
diff --git a/roms/ipxe/src/drivers/net/skeleton.h b/roms/ipxe/src/drivers/net/skeleton.h
new file mode 100644
index 0000000000000000000000000000000000000000..3de2afa5b98dac2670ec9133f5184775e91597e1
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/skeleton.h
@@ -0,0 +1,23 @@
+#ifndef _SKELETON_H
+#define _SKELETON_H
+
+/** @file
+ *
+ * Skeleton network driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** Skeleton BAR size */
+#define SKELETON_BAR_SIZE 256
+
+/** A skeleton network card */
+struct skeleton_nic {
+	/** Registers */
+	void *regs;
+	/** MII interface */
+	struct mii_interface mii;
+};
+
+#endif /* _SKELETON_H */
diff --git a/roms/ipxe/src/drivers/net/skge.c b/roms/ipxe/src/drivers/net/skge.c
index fea338414910a34792b35a928a33..6384e76479cc2c0b71ce8c88e0a2 100755
--- a/roms/ipxe/src/drivers/net/skge.c
+++ b/roms/ipxe/src/drivers/net/skge.c
@@ -24,7 +24,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_ONLY );
diff --git a/roms/ipxe/src/drivers/net/skge.h b/roms/ipxe/src/drivers/net/skge.h
index 8a6ba6b25dac5867a0dee5759c19..d9e91457ab43ca01df09d8a1ffe4 100755
--- a/roms/ipxe/src/drivers/net/skge.h
+++ b/roms/ipxe/src/drivers/net/skge.h
@@ -1095,7 +1095,7 @@ enum {
 
 	PHY_ST_PRE_SUP	= 1<<6, /* Bit  6:	Preamble Suppression */
 	PHY_ST_AN_OVER	= 1<<5, /* Bit  5:	Auto-Negotiation Over */
-	PHY_ST_REM_FLT	= 1<<4, /* Bit  4:	Remote Fault Condition Occured */
+	PHY_ST_REM_FLT	= 1<<4, /* Bit  4:	Remote Fault Condition Occurred */
 	PHY_ST_AN_CAP	= 1<<3, /* Bit  3:	Auto-Negotiation Capability */
 	PHY_ST_LSYNC	= 1<<2, /* Bit  2:	Link Synchronized */
 	PHY_ST_JAB_DET	= 1<<1, /* Bit  1:	Jabber Detected */
@@ -1778,8 +1778,8 @@ enum {
 	GM_GPSR_LINK_UP		= 1<<12, /* Bit 12:	Link Up Status */
 	GM_GPSR_PAUSE		= 1<<11, /* Bit 11:	Pause State */
 	GM_GPSR_TX_ACTIVE	= 1<<10, /* Bit 10:	Tx in Progress */
-	GM_GPSR_EXC_COL		= 1<<9,	/* Bit  9:	Excessive Collisions Occured */
-	GM_GPSR_LAT_COL		= 1<<8,	/* Bit  8:	Late Collisions Occured */
+	GM_GPSR_EXC_COL		= 1<<9,	/* Bit  9:	Excessive Collisions Occurred */
+	GM_GPSR_LAT_COL		= 1<<8,	/* Bit  8:	Late Collisions Occurred */
 
 	GM_GPSR_PHY_ST_CH	= 1<<5,	/* Bit  5:	PHY Status Change */
 	GM_GPSR_GIG_SPEED	= 1<<4,	/* Bit  4:	Gigabit Speed (1 = 1000 Mbps) */
@@ -2284,7 +2284,7 @@ enum {
 	XM_ST_BC	= 1<<7,		/* Bit  7:	Broadcast packet */
 	XM_ST_MC	= 1<<6,		/* Bit  6:	Multicast packet */
 	XM_ST_UC	= 1<<5,		/* Bit  5:	Unicast packet */
-	XM_ST_TX_UR	= 1<<4,		/* Bit  4:	FIFO Underrun occured */
+	XM_ST_TX_UR	= 1<<4,		/* Bit  4:	FIFO Underrun occurred */
 	XM_ST_CS_ERR	= 1<<3,		/* Bit  3:	Carrier Sense Error */
 	XM_ST_LAT_COL	= 1<<2,		/* Bit  2:	Late Collision Error */
 	XM_ST_MUL_COL	= 1<<1,		/* Bit  1:	Multiple Collisions */
diff --git a/roms/ipxe/src/drivers/net/sky2.c b/roms/ipxe/src/drivers/net/sky2.c
index 5b5bd6b019aba1d11282df0a7cf4..35ff66c6dc62344ec4e59c2b1476 100644
--- a/roms/ipxe/src/drivers/net/sky2.c
+++ b/roms/ipxe/src/drivers/net/sky2.c
@@ -21,7 +21,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_ONLY );
@@ -782,7 +783,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
 	sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
 	sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
 
-	/* On chips without ram buffer, pause is controled by MAC level */
+	/* On chips without ram buffer, pause is controlled by MAC level */
 	if (!(hw->flags & SKY2_HW_RAM_BUFFER)) {
 		sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
 		sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
@@ -2334,7 +2335,7 @@ static int sky2_probe(struct pci_device *pdev)
 			sky2_show_addr(dev1);
 	}
 
-	pci_set_drvdata(pdev, dev);
+	pci_set_drvdata(pdev, hw);
 
 	return 0;
 
diff --git a/roms/ipxe/src/drivers/net/sky2.h b/roms/ipxe/src/drivers/net/sky2.h
index 3e86b1dedf9f9f42e39e795ef218..9bb63010e1e5be48f42bdd4c9b1b 100644
--- a/roms/ipxe/src/drivers/net/sky2.h
+++ b/roms/ipxe/src/drivers/net/sky2.h
@@ -1056,7 +1056,7 @@ enum {
 
 	PHY_ST_PRE_SUP	= 1<<6, /* Bit  6:	Preamble Suppression */
 	PHY_ST_AN_OVER	= 1<<5, /* Bit  5:	Auto-Negotiation Over */
-	PHY_ST_REM_FLT	= 1<<4, /* Bit  4:	Remote Fault Condition Occured */
+	PHY_ST_REM_FLT	= 1<<4, /* Bit  4:	Remote Fault Condition Occurred */
 	PHY_ST_AN_CAP	= 1<<3, /* Bit  3:	Auto-Negotiation Capability */
 	PHY_ST_LSYNC	= 1<<2, /* Bit  2:	Link Synchronized */
 	PHY_ST_JAB_DET	= 1<<1, /* Bit  1:	Jabber Detected */
@@ -1587,8 +1587,8 @@ enum {
 	GM_GPSR_LINK_UP		= 1<<12, /* Bit 12:	Link Up Status */
 	GM_GPSR_PAUSE		= 1<<11, /* Bit 11:	Pause State */
 	GM_GPSR_TX_ACTIVE	= 1<<10, /* Bit 10:	Tx in Progress */
-	GM_GPSR_EXC_COL		= 1<<9,	/* Bit  9:	Excessive Collisions Occured */
-	GM_GPSR_LAT_COL		= 1<<8,	/* Bit  8:	Late Collisions Occured */
+	GM_GPSR_EXC_COL		= 1<<9,	/* Bit  9:	Excessive Collisions Occurred */
+	GM_GPSR_LAT_COL		= 1<<8,	/* Bit  8:	Late Collisions Occurred */
 
 	GM_GPSR_PHY_ST_CH	= 1<<5,	/* Bit  5:	PHY Status Change */
 	GM_GPSR_GIG_SPEED	= 1<<4,	/* Bit  4:	Gigabit Speed (1 = 1000 Mbps) */
diff --git a/roms/ipxe/src/drivers/net/smc9000.h b/roms/ipxe/src/drivers/net/smc9000.h
index 22b0e18932bf8cb4681c356a8bc9..02b1c831c45b4cd8f9f07de94c5b 100644
--- a/roms/ipxe/src/drivers/net/smc9000.h
+++ b/roms/ipxe/src/drivers/net/smc9000.h
@@ -107,7 +107,7 @@ typedef unsigned long int		dword;
 #define RPC_LED_10      (0x02)  // LED = 10Mbps link detect
 #define RPC_LED_FD      (0x03)  // LED = Full Duplex Mode
 #define RPC_LED_TX_RX   (0x04)  // LED = TX or RX packet occurred
-#define RPC_LED_100     (0x05)  // LED = 100Mbps link dectect
+#define RPC_LED_100     (0x05)  // LED = 100Mbps link detect
 #define RPC_LED_TX      (0x06)  // LED = TX packet occurred
 #define RPC_LED_RX      (0x07)  // LED = RX packet occurred
 #define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX)
@@ -125,7 +125,7 @@ typedef unsigned long int		dword;
 #define RPC_LED_10      (0x02)  // LED = 10Mbps link detect
 #define RPC_LED_FD      (0x03)  // LED = Full Duplex Mode
 #define RPC_LED_TX_RX   (0x04)  // LED = TX or RX packet occurred
-#define RPC_LED_100     (0x05)  // LED = 100Mbps link dectect
+#define RPC_LED_100     (0x05)  // LED = 100Mbps link detect
 #define RPC_LED_TX      (0x06)  // LED = TX packet occurred
 #define RPC_LED_RX      (0x07)  // LED = RX packet occurred
 #define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX)
diff --git a/roms/ipxe/src/drivers/net/sundance.c b/roms/ipxe/src/drivers/net/sundance.c
index 63a9ea5f1c885fb3968f83cb3a77..eef7c9c7cd8ac96221a81067a0cd 100644
--- a/roms/ipxe/src/drivers/net/sundance.c
+++ b/roms/ipxe/src/drivers/net/sundance.c
@@ -15,7 +15,8 @@
 *
 *    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.
+*    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+*    02110-1301, USA.
 *
 *    Portions of this code based on:
 *               sundance.c: A Linux device driver for the Sundance ST201 "Alta"
@@ -257,7 +258,7 @@ static struct sundance_private {
 	const char *nic_name;
 	/* Frequently used values */
 
-	unsigned int cur_rx;	/* Producer/consumer ring indicies */
+	unsigned int cur_rx;	/* Producer/consumer ring indices */
 	unsigned int mtu;
 
 	/* These values keep track of the tranceiver/media in use */
@@ -440,7 +441,7 @@ static void sundance_irq ( struct nic *nic, irq_action_t action ) {
 /**************************************************************************
 POLL - Wait for a frame
 ***************************************************************************/
-static int sundance_poll(struct nic *nic, int retreive)
+static int sundance_poll(struct nic *nic, int retrieve)
 {
 	/* return true if there's an ethernet packet ready to read */
 	/* nic->packet should contain data on return */
@@ -454,7 +455,7 @@ static int sundance_poll(struct nic *nic, int retreive)
 		return 0;
 
 	/* There is a packet ready */
-	if(!retreive)
+	if(!retrieve)
 		return 1;
 
 	intr_status = inw(nic->ioaddr + IntrStatus);
diff --git a/roms/ipxe/src/drivers/net/tg3.c b/roms/ipxe/src/drivers/net/tg3.c
deleted file mode 100644
index e1562d4c882ee53aef69fe504a72b9b54233e2cd..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/tg3.c
+++ /dev/null
@@ -1,3435 +0,0 @@
-/* $Id$
- * tg3.c: Broadcom Tigon3 ethernet driver.
- *
- * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
- * Copyright (C) 2001, 2002 Jeff Garzik (jgarzik@mandrakesoft.com)
- * Copyright (C) 2003 Eric Biederman (ebiederman@lnxi.com)  [etherboot port]
- */
-
-FILE_LICENCE ( GPL2_ONLY );
-
-/* 11-13-2003	timlegge	Fix Issue with NetGear GA302T 
- * 11-18-2003   ebiederm        Generalize NetGear Fix to what the code was supposed to be.
- * 01-06-2005   Alf (Frederic Olivie) Add Dell bcm 5751 (0x1677) support
- * 04-15-2005   Martin Vogt Add Fujitsu Siemens Computer (FSC) 0x1734 bcm 5751 0x105d support
- */
-
-#include "etherboot.h"
-#include "nic.h"
-#include <errno.h>
-#include <ipxe/pci.h>
-#include <ipxe/ethernet.h>
-#include "string.h"
-#include <mii.h>
-#include "tg3.h"
-
-#define SUPPORT_COPPER_PHY  1
-#define SUPPORT_FIBER_PHY   1
-#define SUPPORT_LINK_REPORT 1
-#define SUPPORT_PARTNO_STR  1
-#define SUPPORT_PHY_STR     1
-
-static struct tg3 tg3;
-
-/* These numbers seem to be hard coded in the NIC firmware somehow.
- * You can't change the ring sizes, but you can change where you place
- * them in the NIC onboard memory.
- */
-#define TG3_RX_RING_SIZE		512
-#define TG3_DEF_RX_RING_PENDING		20	/* RX_RING_PENDING seems to be o.k. at 20 and 200 */
-#define TG3_RX_RCB_RING_SIZE	1024
-
-/*	(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ? \
-	 512 : 1024) */
-#define TG3_TX_RING_SIZE		512
-#define TG3_DEF_TX_RING_PENDING		(TG3_TX_RING_SIZE - 1)
-
-#define TG3_RX_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * TG3_RX_RING_SIZE)
-#define TG3_RX_RCB_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * TG3_RX_RCB_RING_SIZE)
-
-#define TG3_TX_RING_BYTES	(sizeof(struct tg3_tx_buffer_desc) * TG3_TX_RING_SIZE)
-#define NEXT_TX(N)		(((N) + 1) & (TG3_TX_RING_SIZE - 1))
-#define PREV_TX(N)		(((N) - 1) & (TG3_TX_RING_SIZE - 1))
-
-#define RX_PKT_BUF_SZ		(1536 + 2 + 64)
-
-struct eth_frame {
-	uint8_t  dst_addr[ETH_ALEN];
-	uint8_t  src_addr[ETH_ALEN];
-	uint16_t type;
-	uint8_t  data [ETH_FRAME_LEN - ETH_HLEN];
-};
-
-struct bss {
-	struct tg3_rx_buffer_desc rx_std[TG3_RX_RING_SIZE];
-	struct tg3_rx_buffer_desc rx_rcb[TG3_RX_RCB_RING_SIZE];
-	struct tg3_tx_buffer_desc tx_ring[TG3_TX_RING_SIZE];
-	struct tg3_hw_status      hw_status;
-	struct tg3_hw_stats       hw_stats;
-	unsigned char             rx_bufs[TG3_DEF_RX_RING_PENDING][RX_PKT_BUF_SZ];
-	struct eth_frame	  tx_frame[2];
-} tg3_bss __shared;
-
-/**
- * pci_save_state - save the PCI configuration space of a device before suspending
- * @dev: - PCI device that we're dealing with
- * @buffer: - buffer to hold config space context
- *
- * @buffer must be large enough to hold the entire PCI 2.2 config space 
- * (>= 64 bytes).
- */
-static int pci_save_state(struct pci_device *dev, uint32_t *buffer)
-{
-	int i;
-	for (i = 0; i < 16; i++)
-		pci_read_config_dword(dev, i * 4,&buffer[i]);
-	return 0;
-}
-
-/** 
- * pci_restore_state - Restore the saved state of a PCI device
- * @dev: - PCI device that we're dealing with
- * @buffer: - saved PCI config space
- *
- */
-static int pci_restore_state(struct pci_device *dev, uint32_t *buffer)
-{
-	int i;
-
-	for (i = 0; i < 16; i++)
-		pci_write_config_dword(dev,i * 4, buffer[i]);
-	return 0;
-}
-
-static void tg3_write_indirect_reg32(uint32_t off, uint32_t val)
-{
-	pci_write_config_dword(tg3.pdev, TG3PCI_REG_BASE_ADDR, off);
-	pci_write_config_dword(tg3.pdev, TG3PCI_REG_DATA, val);
-}
-
-#define tw32(reg,val)		tg3_write_indirect_reg32((reg),(val))
-#define tw32_mailbox(reg, val)	writel(((val) & 0xffffffff), tg3.regs + (reg))
-#define tw16(reg,val)		writew(((val) & 0xffff), tg3.regs + (reg))
-#define tw8(reg,val)		writeb(((val) & 0xff), tg3.regs + (reg))
-#define tr32(reg)		readl(tg3.regs + (reg))
-#define tr16(reg)		readw(tg3.regs + (reg))
-#define tr8(reg)		readb(tg3.regs + (reg))
-
-static void tw32_carefully(uint32_t reg, uint32_t val)
-{
-	tw32(reg, val);
-	tr32(reg);
-	udelay(100);
-}
-
-static void tw32_mailbox2(uint32_t reg, uint32_t val)
-{
-	tw32_mailbox(reg, val);
-	tr32(reg);
-}
-
-static void tg3_write_mem(uint32_t off, uint32_t val)
-{
-	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
-	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_DATA, val);
-
-	/* Always leave this as zero. */
-	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
-}
-
-static void tg3_read_mem(uint32_t off, uint32_t *val)
-{
-	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
-	pci_read_config_dword(tg3.pdev, TG3PCI_MEM_WIN_DATA, val);
-
-	/* Always leave this as zero. */
-	pci_write_config_dword(tg3.pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
-}
-
-static void tg3_disable_ints(struct tg3 *tp)
-{
-	tw32(TG3PCI_MISC_HOST_CTRL,
-	     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
-	tw32_mailbox2(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
-}
-
-static void tg3_switch_clocks(struct tg3 *tp)
-{
-	uint32_t orig_clock_ctrl, clock_ctrl;
-
-	clock_ctrl = tr32(TG3PCI_CLOCK_CTRL);
-
-	orig_clock_ctrl = clock_ctrl;
-	clock_ctrl &= (CLOCK_CTRL_FORCE_CLKRUN | CLOCK_CTRL_CLKRUN_OENABLE | 0x1f);
-	tp->pci_clock_ctrl = clock_ctrl;
-	
-	if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) &&
-	    (!((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
-	       && (tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) &&
-		(orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE)!=0) {
-		tw32_carefully(TG3PCI_CLOCK_CTRL, 
-			clock_ctrl | (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK));
-		tw32_carefully(TG3PCI_CLOCK_CTRL, 
-			clock_ctrl | (CLOCK_CTRL_ALTCLK));
-	}
-	tw32_carefully(TG3PCI_CLOCK_CTRL, clock_ctrl);
-}
-
-#define PHY_BUSY_LOOPS	5000
-
-static int tg3_readphy(struct tg3 *tp, int reg, uint32_t *val)
-{
-	uint32_t frame_val;
-	int loops, ret;
-
-	tw32_carefully(MAC_MI_MODE, tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL);
-
-	*val = 0xffffffff;
-
-	frame_val  = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
-		      MI_COM_PHY_ADDR_MASK);
-	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
-		      MI_COM_REG_ADDR_MASK);
-	frame_val |= (MI_COM_CMD_READ | MI_COM_START);
-	
-	tw32_carefully(MAC_MI_COM, frame_val);
-
-	loops = PHY_BUSY_LOOPS;
-	while (loops-- > 0) {
-		udelay(10);
-		frame_val = tr32(MAC_MI_COM);
-
-		if ((frame_val & MI_COM_BUSY) == 0) {
-			udelay(5);
-			frame_val = tr32(MAC_MI_COM);
-			break;
-		}
-	}
-
-	ret = -EBUSY;
-	if (loops > 0) {
-		*val = frame_val & MI_COM_DATA_MASK;
-		ret = 0;
-	}
-
-	tw32_carefully(MAC_MI_MODE, tp->mi_mode);
-
-	return ret;
-}
-
-static int tg3_writephy(struct tg3 *tp, int reg, uint32_t val)
-{
-	uint32_t frame_val;
-	int loops, ret;
-
-	tw32_carefully(MAC_MI_MODE, tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL);
-
-	frame_val  = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
-		      MI_COM_PHY_ADDR_MASK);
-	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
-		      MI_COM_REG_ADDR_MASK);
-	frame_val |= (val & MI_COM_DATA_MASK);
-	frame_val |= (MI_COM_CMD_WRITE | MI_COM_START);
-	
-	tw32_carefully(MAC_MI_COM, frame_val);
-
-	loops = PHY_BUSY_LOOPS;
-	while (loops-- > 0) {
-		udelay(10);
-		frame_val = tr32(MAC_MI_COM);
-		if ((frame_val & MI_COM_BUSY) == 0) {
-			udelay(5);
-			frame_val = tr32(MAC_MI_COM);
-			break;
-		}
-	}
-
-	ret = -EBUSY;
-	if (loops > 0)
-		ret = 0;
-
-	tw32_carefully(MAC_MI_MODE, tp->mi_mode);
-
-	return ret;
-}
-
-static int tg3_writedsp(struct tg3 *tp, uint16_t addr, uint16_t val)
-{
-	int err;
-	err  = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, addr);
-	err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val);
-	return err;
-}
-
-
-static void tg3_phy_set_wirespeed(struct tg3 *tp)
-{
-	uint32_t val;
-
-	if (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED)
-		return;
-
-	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007);
-	tg3_readphy(tp, MII_TG3_AUX_CTRL, &val);
-	tg3_writephy(tp, MII_TG3_AUX_CTRL, (val | (1 << 15) | (1 << 4)));
-}
-
-static int tg3_bmcr_reset(struct tg3 *tp)
-{
-	uint32_t phy_control;
-	int limit, err;
-
-	/* OK, reset it, and poll the BMCR_RESET bit until it
-	 * clears or we time out.
-	 */
-	phy_control = BMCR_RESET;
-	err = tg3_writephy(tp, MII_BMCR, phy_control);
-	if (err != 0)
-		return -EBUSY;
-
-	limit = 5000;
-	while (limit--) {
-		err = tg3_readphy(tp, MII_BMCR, &phy_control);
-		if (err != 0)
-			return -EBUSY;
-
-		if ((phy_control & BMCR_RESET) == 0) {
-			udelay(40);
-			break;
-		}
-		udelay(10);
-	}
-	if (limit <= 0)
-		return -EBUSY;
-
-	return 0;
-}
-
-static int tg3_wait_macro_done(struct tg3 *tp)
-{
-	int limit = 100;
-
-	while (limit--) {
-		uint32_t tmp32;
-
-		tg3_readphy(tp, 0x16, &tmp32);
-		if ((tmp32 & 0x1000) == 0)
-			break;
-	}
-	if (limit <= 0)
-		return -EBUSY;
-
-	return 0;
-}
-
-static int tg3_phy_write_and_check_testpat(struct tg3 *tp, int *resetp)
-{
-	static const uint32_t test_pat[4][6] = {
-	{ 0x00005555, 0x00000005, 0x00002aaa, 0x0000000a, 0x00003456, 0x00000003 },
-	{ 0x00002aaa, 0x0000000a, 0x00003333, 0x00000003, 0x0000789a, 0x00000005 },
-	{ 0x00005a5a, 0x00000005, 0x00002a6a, 0x0000000a, 0x00001bcd, 0x00000003 },
-	{ 0x00002a5a, 0x0000000a, 0x000033c3, 0x00000003, 0x00002ef1, 0x00000005 }
-	};
-	int chan;
-
-	for (chan = 0; chan < 4; chan++) {
-		int i;
-
-		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
-			(chan * 0x2000) | 0x0200);
-		tg3_writephy(tp, 0x16, 0x0002);
-
-		for (i = 0; i < 6; i++)
-			tg3_writephy(tp, MII_TG3_DSP_RW_PORT,
-				test_pat[chan][i]);
-
-		tg3_writephy(tp, 0x16, 0x0202);
-		if (tg3_wait_macro_done(tp)) {
-			*resetp = 1;
-			return -EBUSY;
-		}
-
-		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
-			     (chan * 0x2000) | 0x0200);
-		tg3_writephy(tp, 0x16, 0x0082);
-		if (tg3_wait_macro_done(tp)) {
-			*resetp = 1;
-			return -EBUSY;
-		}
-
-		tg3_writephy(tp, 0x16, 0x0802);
-		if (tg3_wait_macro_done(tp)) {
-			*resetp = 1;
-			return -EBUSY;
-		}
-
-		for (i = 0; i < 6; i += 2) {
-			uint32_t low, high;
-
-			tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &low);
-			tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &high);
-			if (tg3_wait_macro_done(tp)) {
-				*resetp = 1;
-				return -EBUSY;
-			}
-			low &= 0x7fff;
-			high &= 0x000f;
-			if (low != test_pat[chan][i] ||
-			    high != test_pat[chan][i+1]) {
-				tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000b);
-				tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4001);
-				tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4005);
-
-				return -EBUSY;
-			}
-		}
-	}
-
-	return 0;
-}
-
-static int tg3_phy_reset_chanpat(struct tg3 *tp)
-{
-	int chan;
-
-	for (chan = 0; chan < 4; chan++) {
-		int i;
-
-		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
-			     (chan * 0x2000) | 0x0200);
-		tg3_writephy(tp, 0x16, 0x0002);
-		for (i = 0; i < 6; i++)
-			tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x000);
-		tg3_writephy(tp, 0x16, 0x0202);
-		if (tg3_wait_macro_done(tp))
-			return -EBUSY;
-	}
-
-	return 0;
-}
-
-static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
-{
-	uint32_t reg32, phy9_orig;
-	int retries, do_phy_reset, err;
-
-	retries = 10;
-	do_phy_reset = 1;
-	do {
-		if (do_phy_reset) {
-			err = tg3_bmcr_reset(tp);
-			if (err)
-				return err;
-			do_phy_reset = 0;
-		}
-		
-		/* Disable transmitter and interrupt.  */
-		tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);
-		reg32 |= 0x3000;
-		tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
-
-		/* Set full-duplex, 1000 mbps.  */
-		tg3_writephy(tp, MII_BMCR,
-			BMCR_FULLDPLX | TG3_BMCR_SPEED1000);
-
-		/* Set to master mode.  */
-		tg3_readphy(tp, MII_TG3_CTRL, &phy9_orig);
-		tg3_writephy(tp, MII_TG3_CTRL,
-			(MII_TG3_CTRL_AS_MASTER |
-				MII_TG3_CTRL_ENABLE_AS_MASTER));
-
-		/* Enable SM_DSP_CLOCK and 6dB.  */
-		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
-
-		/* Block the PHY control access.  */
-		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);
-		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0800);
-
-		err = tg3_phy_write_and_check_testpat(tp, &do_phy_reset);
-		if (!err)
-			break;
-	} while (--retries);
-
-	err = tg3_phy_reset_chanpat(tp);
-	if (err)
-		return err;
-
-	tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8005);
-	tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0000);
-
-	tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200);
-	tg3_writephy(tp, 0x16, 0x0000);
-
-	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
-
-	tg3_writephy(tp, MII_TG3_CTRL, phy9_orig);
-
-	tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);
-	reg32 &= ~0x3000;
-	tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
-
-	return err;
-}
-
-/* This will reset the tigon3 PHY if there is no valid
- * link.
- */
-static int tg3_phy_reset(struct tg3 *tp)
-{
-	uint32_t phy_status;
-	int err;
-
-	err  = tg3_readphy(tp, MII_BMSR, &phy_status);
-	err |= tg3_readphy(tp, MII_BMSR, &phy_status);
-	if (err != 0)
-		return -EBUSY;
-
-	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
-		(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
-		(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) {
-		err = tg3_phy_reset_5703_4_5(tp);
-		if (err)
-			return err;
-		goto out;
-	}
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
-	  // Taken from Broadcom's source code
-	  tg3_writephy(tp, 0x18, 0x0c00);
-	  tg3_writephy(tp, 0x17, 0x000a);
-	  tg3_writephy(tp, 0x15, 0x310b);
-	  tg3_writephy(tp, 0x17, 0x201f);
-	  tg3_writephy(tp, 0x15, 0x9506);
-	  tg3_writephy(tp, 0x17, 0x401f);
-	  tg3_writephy(tp, 0x15, 0x14e2);
-	  tg3_writephy(tp, 0x18, 0x0400);
-	}
-	err = tg3_bmcr_reset(tp);
-	if (err)
-		return err;
- out:
-	tg3_phy_set_wirespeed(tp);
-	return 0;
-}
-
-static void tg3_set_power_state_0(struct tg3 *tp)
-{
-	uint16_t power_control;
-	int pm = tp->pm_cap;
-
-	/* Make sure register accesses (indirect or otherwise)
-	 * will function correctly.
-	 */
-	pci_write_config_dword(tp->pdev,  TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl);
-
-	pci_read_config_word(tp->pdev, pm + PCI_PM_CTRL, &power_control);
-
-	power_control |= PCI_PM_CTRL_PME_STATUS;
-	power_control &= ~(PCI_PM_CTRL_STATE_MASK);
-	power_control |= 0;
-	pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
-
-	tw32_carefully(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
-
-	return;
-}
-
-
-#if SUPPORT_LINK_REPORT
-static void tg3_link_report(struct tg3 *tp)
-{
-	if (!tp->carrier_ok) {
-		printf("Link is down.\n");
-	} else {
-		printf("Link is up at %d Mbps, %s duplex. %s %s %s\n",
-			(tp->link_config.active_speed == SPEED_1000 ?
-			       1000 :
-			(tp->link_config.active_speed == SPEED_100 ?
-				100 : 10)),
-			(tp->link_config.active_duplex == DUPLEX_FULL ?  
-				"full" : "half"),
-			(tp->tg3_flags & TG3_FLAG_TX_PAUSE) ? "TX" : "",
-			(tp->tg3_flags & TG3_FLAG_RX_PAUSE) ? "RX" : "",
-			(tp->tg3_flags & (TG3_FLAG_TX_PAUSE |TG3_FLAG_RX_PAUSE)) ? "flow control" : "");
-	}
-}
-#else
-#define tg3_link_report(tp)
-#endif
-
-static void tg3_setup_flow_control(struct tg3 *tp, uint32_t local_adv, uint32_t remote_adv)
-{
-	uint32_t new_tg3_flags = 0;
-
-	if (local_adv & ADVERTISE_PAUSE_CAP) {
-		if (local_adv & ADVERTISE_PAUSE_ASYM) {
-			if (remote_adv & LPA_PAUSE_CAP)
-				new_tg3_flags |=
-					(TG3_FLAG_RX_PAUSE |
-					 TG3_FLAG_TX_PAUSE);
-			else if (remote_adv & LPA_PAUSE_ASYM)
-				new_tg3_flags |=
-					(TG3_FLAG_RX_PAUSE);
-		} else {
-			if (remote_adv & LPA_PAUSE_CAP)
-				new_tg3_flags |=
-					(TG3_FLAG_RX_PAUSE |
-					 TG3_FLAG_TX_PAUSE);
-		}
-	} else if (local_adv & ADVERTISE_PAUSE_ASYM) {
-		if ((remote_adv & LPA_PAUSE_CAP) &&
-		    (remote_adv & LPA_PAUSE_ASYM))
-			new_tg3_flags |= TG3_FLAG_TX_PAUSE;
-	}
-
-	tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE);
-	tp->tg3_flags |= new_tg3_flags;
-
-	if (new_tg3_flags & TG3_FLAG_RX_PAUSE)
-		tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
-	else
-		tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
-
-	if (new_tg3_flags & TG3_FLAG_TX_PAUSE)
-		tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
-	else
-		tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
-}
-
-#if SUPPORT_COPPER_PHY
-static void tg3_aux_stat_to_speed_duplex(
-	struct tg3 *tp __unused, uint32_t val, uint8_t *speed, uint8_t *duplex)
-{
-	static const uint8_t map[] = {
-		[0] = (SPEED_INVALID << 2) | DUPLEX_INVALID,
-		[MII_TG3_AUX_STAT_10HALF >> 8]   = (SPEED_10 << 2) | DUPLEX_HALF,
-		[MII_TG3_AUX_STAT_10FULL >> 8]   = (SPEED_10 << 2) | DUPLEX_FULL,
-		[MII_TG3_AUX_STAT_100HALF >> 8]  = (SPEED_100 << 2) | DUPLEX_HALF,
-		[MII_TG3_AUX_STAT_100_4 >> 8] = (SPEED_INVALID << 2) | DUPLEX_INVALID,
-		[MII_TG3_AUX_STAT_100FULL >> 8]  = (SPEED_100 << 2) | DUPLEX_FULL,
-		[MII_TG3_AUX_STAT_1000HALF >> 8] = (SPEED_1000 << 2) | DUPLEX_HALF,
-		[MII_TG3_AUX_STAT_1000FULL >> 8] = (SPEED_1000 << 2) | DUPLEX_FULL,
-	};
-	uint8_t result;
-	result = map[(val & MII_TG3_AUX_STAT_SPDMASK) >> 8];
-	*speed = result >> 2;
-	*duplex = result & 3;
-}
-
-static int tg3_phy_copper_begin(struct tg3 *tp)
-{
-	uint32_t new_adv;
-
-	tp->link_config.advertising =
-		(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
-			ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
-			ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full |
-			ADVERTISED_Autoneg | ADVERTISED_MII);
-	
-	if (tp->tg3_flags & TG3_FLAG_10_100_ONLY) {
-		tp->link_config.advertising &=
-			~(ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full);
-	}
-	
-	new_adv = (ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
-	if (tp->link_config.advertising & ADVERTISED_10baseT_Half) {
-		new_adv |= ADVERTISE_10HALF;
-	}
-	if (tp->link_config.advertising & ADVERTISED_10baseT_Full) {
-		new_adv |= ADVERTISE_10FULL;
-	}
-	if (tp->link_config.advertising & ADVERTISED_100baseT_Half) {
-		new_adv |= ADVERTISE_100HALF;
-	}
-	if (tp->link_config.advertising & ADVERTISED_100baseT_Full) {
-		new_adv |= ADVERTISE_100FULL;
-	}
-	tg3_writephy(tp, MII_ADVERTISE, new_adv);
-	
-	if (tp->link_config.advertising &
-		(ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) {
-		new_adv = 0;
-		if (tp->link_config.advertising & ADVERTISED_1000baseT_Half) {
-			new_adv |= MII_TG3_CTRL_ADV_1000_HALF;
-		}
-		if (tp->link_config.advertising & ADVERTISED_1000baseT_Full) {
-			new_adv |= MII_TG3_CTRL_ADV_1000_FULL;
-		}
-		if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
-			(tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
-				tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)) {
-			new_adv |= (MII_TG3_CTRL_AS_MASTER |
-				MII_TG3_CTRL_ENABLE_AS_MASTER);
-		}
-		tg3_writephy(tp, MII_TG3_CTRL, new_adv);
-	} else {
-		tg3_writephy(tp, MII_TG3_CTRL, 0);
-	}
-
-	tg3_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
-
-	return 0;
-}
-
-static int tg3_init_5401phy_dsp(struct tg3 *tp)
-{
-	int err;
-
-	/* Turn off tap power management. */
-	err  = tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c20);
-	
-	err |= tg3_writedsp(tp, 0x0012, 0x1804);
-	err |= tg3_writedsp(tp, 0x0013, 0x1204);
-	err |= tg3_writedsp(tp, 0x8006, 0x0132);
-	err |= tg3_writedsp(tp, 0x8006, 0x0232);
-	err |= tg3_writedsp(tp, 0x201f, 0x0a20);
-
-	udelay(40);
-
-	return err;
-}
-
-static int tg3_setup_copper_phy(struct tg3 *tp)
-{
-	int current_link_up;
-	uint32_t bmsr, dummy;
-	int i, err;
-
-	tw32_carefully(MAC_STATUS,
-		(MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED
-		 | MAC_STATUS_LNKSTATE_CHANGED));
-
-	tp->mi_mode = MAC_MI_MODE_BASE;
-	tw32_carefully(MAC_MI_MODE, tp->mi_mode);
-
-	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02);
-
-	/* Some third-party PHYs need to be reset on link going
-	 * down.
-	 */
-	if (	(	(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
-			(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
-			(tp->pci_chip_rev_id == CHIPREV_ID_5705_A0)) &&
-		(tp->carrier_ok)) {
-		tg3_readphy(tp, MII_BMSR, &bmsr);
-		tg3_readphy(tp, MII_BMSR, &bmsr);
-		if (!(bmsr & BMSR_LSTATUS))
-			tg3_phy_reset(tp);
-	}
-
-	if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
-		tg3_readphy(tp, MII_BMSR, &bmsr);
-		tg3_readphy(tp, MII_BMSR, &bmsr);
-
-		if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE))
-			bmsr = 0;
-
-		if (!(bmsr & BMSR_LSTATUS)) {
-			err = tg3_init_5401phy_dsp(tp);
-			if (err)
-				return err;
-
-			tg3_readphy(tp, MII_BMSR, &bmsr);
-			for (i = 0; i < 1000; i++) {
-				udelay(10);
-				tg3_readphy(tp, MII_BMSR, &bmsr);
-				if (bmsr & BMSR_LSTATUS) {
-					udelay(40);
-					break;
-				}
-			}
-
-			if ((tp->phy_id & PHY_ID_REV_MASK) == PHY_REV_BCM5401_B0 &&
-			    !(bmsr & BMSR_LSTATUS) &&
-			    tp->link_config.active_speed == SPEED_1000) {
-				err = tg3_phy_reset(tp);
-				if (!err)
-					err = tg3_init_5401phy_dsp(tp);
-				if (err)
-					return err;
-			}
-		}
-	} else if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
-		   tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
-		/* 5701 {A0,B0} CRC bug workaround */
-		tg3_writephy(tp, 0x15, 0x0a75);
-		tg3_writephy(tp, 0x1c, 0x8c68);
-		tg3_writephy(tp, 0x1c, 0x8d68);
-		tg3_writephy(tp, 0x1c, 0x8c68);
-	}
-
-	/* Clear pending interrupts... */
-	tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
-	tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
-
-	tg3_writephy(tp, MII_TG3_IMASK, ~0);
-
-	if (tp->led_mode == led_mode_three_link)
-		tg3_writephy(tp, MII_TG3_EXT_CTRL,
-			     MII_TG3_EXT_CTRL_LNK3_LED_MODE);
-	else
-		tg3_writephy(tp, MII_TG3_EXT_CTRL, 0);
-
-	current_link_up = 0;
-
-	tg3_readphy(tp, MII_BMSR, &bmsr);
-	tg3_readphy(tp, MII_BMSR, &bmsr);
-
-	if (bmsr & BMSR_LSTATUS) {
-		uint32_t aux_stat, bmcr;
-
-		tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
-		for (i = 0; i < 2000; i++) {
-			udelay(10);
-			tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
-			if (aux_stat)
-				break;
-		}
-
-		tg3_aux_stat_to_speed_duplex(tp, aux_stat,
-			&tp->link_config.active_speed,
-			&tp->link_config.active_duplex);
-		tg3_readphy(tp, MII_BMCR, &bmcr);
-		tg3_readphy(tp, MII_BMCR, &bmcr);
-		if (bmcr & BMCR_ANENABLE) {
-			uint32_t gig_ctrl;
-			
-			current_link_up = 1;
-			
-			/* Force autoneg restart if we are exiting
-			 * low power mode.
-			 */
-			tg3_readphy(tp, MII_TG3_CTRL, &gig_ctrl);
-			if (!(gig_ctrl & (MII_TG3_CTRL_ADV_1000_HALF |
-				      MII_TG3_CTRL_ADV_1000_FULL))) {
-				current_link_up = 0;
-			}
-		} else {
-			current_link_up = 0;
-		}
-	}
-
-	if (current_link_up == 1 &&
-		(tp->link_config.active_duplex == DUPLEX_FULL)) {
-		uint32_t local_adv, remote_adv;
-
-		tg3_readphy(tp, MII_ADVERTISE, &local_adv);
-		local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
-
-		tg3_readphy(tp, MII_LPA, &remote_adv);
-		remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
-
-		/* If we are not advertising full pause capability,
-		 * something is wrong.  Bring the link down and reconfigure.
-		 */
-		if (local_adv != ADVERTISE_PAUSE_CAP) {
-			current_link_up = 0;
-		} else {
-			tg3_setup_flow_control(tp, local_adv, remote_adv);
-		}
-	}
-
-	if (current_link_up == 0) {
-		uint32_t tmp;
-
-		tg3_phy_copper_begin(tp);
-
-		tg3_readphy(tp, MII_BMSR, &tmp);
-		tg3_readphy(tp, MII_BMSR, &tmp);
-		if (tmp & BMSR_LSTATUS)
-			current_link_up = 1;
-	}
-
-	tp->mac_mode &= ~MAC_MODE_PORT_MODE_MASK;
-	if (current_link_up == 1) {
-		if (tp->link_config.active_speed == SPEED_100 ||
-		    tp->link_config.active_speed == SPEED_10)
-			tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
-		else
-			tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
-	} else
-		tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
-
-	tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
-	if (tp->link_config.active_duplex == DUPLEX_HALF)
-		tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
-
-	tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
-		if ((tp->led_mode == led_mode_link10) ||
-		    (current_link_up == 1 &&
-		     tp->link_config.active_speed == SPEED_10))
-			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
-	} else {
-		if (current_link_up == 1)
-			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
-		tw32(MAC_LED_CTRL, LED_CTRL_PHY_MODE_1);
-	}
-
-	/* ??? Without this setting Netgear GA302T PHY does not
-	 * ??? send/receive packets...
-	 * With this other PHYs cannot bring up the link
-	 */
-	if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5411 &&
-		tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) {
-		tp->mi_mode |= MAC_MI_MODE_AUTO_POLL;
-		tw32_carefully(MAC_MI_MODE, tp->mi_mode);
-	}
-
-	tw32_carefully(MAC_MODE, tp->mac_mode);
-
-	/* Link change polled. */
-	tw32_carefully(MAC_EVENT, 0);
-
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 &&
-	    current_link_up == 1 &&
-	    tp->link_config.active_speed == SPEED_1000 &&
-	    ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ||
-	     (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED))) {
-		udelay(120);
-		tw32_carefully(MAC_STATUS,
-			(MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED));
-		tg3_write_mem(
-			      NIC_SRAM_FIRMWARE_MBOX,
-			      NIC_SRAM_FIRMWARE_MBOX_MAGIC2);
-	}
-
-	if (current_link_up != tp->carrier_ok) {
-		tp->carrier_ok = current_link_up;
-		tg3_link_report(tp);
-	}
-
-	return 0;
-}
-#else
-#define tg3_setup_copper_phy(TP) (-EINVAL)
-#endif /* SUPPORT_COPPER_PHY */
-
-#if SUPPORT_FIBER_PHY
-struct tg3_fiber_aneginfo {
-	int state;
-#define ANEG_STATE_UNKNOWN		0
-#define ANEG_STATE_AN_ENABLE		1
-#define ANEG_STATE_RESTART_INIT		2
-#define ANEG_STATE_RESTART		3
-#define ANEG_STATE_DISABLE_LINK_OK	4
-#define ANEG_STATE_ABILITY_DETECT_INIT	5
-#define ANEG_STATE_ABILITY_DETECT	6
-#define ANEG_STATE_ACK_DETECT_INIT	7
-#define ANEG_STATE_ACK_DETECT		8
-#define ANEG_STATE_COMPLETE_ACK_INIT	9
-#define ANEG_STATE_COMPLETE_ACK		10
-#define ANEG_STATE_IDLE_DETECT_INIT	11
-#define ANEG_STATE_IDLE_DETECT		12
-#define ANEG_STATE_LINK_OK		13
-#define ANEG_STATE_NEXT_PAGE_WAIT_INIT	14
-#define ANEG_STATE_NEXT_PAGE_WAIT	15
-
-	uint32_t flags;
-#define MR_AN_ENABLE		0x00000001
-#define MR_RESTART_AN		0x00000002
-#define MR_AN_COMPLETE		0x00000004
-#define MR_PAGE_RX		0x00000008
-#define MR_NP_LOADED		0x00000010
-#define MR_TOGGLE_TX		0x00000020
-#define MR_LP_ADV_FULL_DUPLEX	0x00000040
-#define MR_LP_ADV_HALF_DUPLEX	0x00000080
-#define MR_LP_ADV_SYM_PAUSE	0x00000100
-#define MR_LP_ADV_ASYM_PAUSE	0x00000200
-#define MR_LP_ADV_REMOTE_FAULT1	0x00000400
-#define MR_LP_ADV_REMOTE_FAULT2	0x00000800
-#define MR_LP_ADV_NEXT_PAGE	0x00001000
-#define MR_TOGGLE_RX		0x00002000
-#define MR_NP_RX		0x00004000
-
-#define MR_LINK_OK		0x80000000
-
-	unsigned long link_time, cur_time;
-
-	uint32_t ability_match_cfg;
-	int ability_match_count;
-
-	char ability_match, idle_match, ack_match;
-
-	uint32_t txconfig, rxconfig;
-#define ANEG_CFG_NP		0x00000080
-#define ANEG_CFG_ACK		0x00000040
-#define ANEG_CFG_RF2		0x00000020
-#define ANEG_CFG_RF1		0x00000010
-#define ANEG_CFG_PS2		0x00000001
-#define ANEG_CFG_PS1		0x00008000
-#define ANEG_CFG_HD		0x00004000
-#define ANEG_CFG_FD		0x00002000
-#define ANEG_CFG_INVAL		0x00001f06
-
-};
-#define ANEG_OK		0
-#define ANEG_DONE	1
-#define ANEG_TIMER_ENAB	2
-#define ANEG_FAILED	-1
-
-#define ANEG_STATE_SETTLE_TIME	10000
-
-static int tg3_fiber_aneg_smachine(struct tg3 *tp,
-				   struct tg3_fiber_aneginfo *ap)
-{
-	unsigned long delta;
-	uint32_t rx_cfg_reg;
-	int ret;
-
-	if (ap->state == ANEG_STATE_UNKNOWN) {
-		ap->rxconfig = 0;
-		ap->link_time = 0;
-		ap->cur_time = 0;
-		ap->ability_match_cfg = 0;
-		ap->ability_match_count = 0;
-		ap->ability_match = 0;
-		ap->idle_match = 0;
-		ap->ack_match = 0;
-	}
-	ap->cur_time++;
-
-	if (tr32(MAC_STATUS) & MAC_STATUS_RCVD_CFG) {
-		rx_cfg_reg = tr32(MAC_RX_AUTO_NEG);
-
-		if (rx_cfg_reg != ap->ability_match_cfg) {
-			ap->ability_match_cfg = rx_cfg_reg;
-			ap->ability_match = 0;
-			ap->ability_match_count = 0;
-		} else {
-			if (++ap->ability_match_count > 1) {
-				ap->ability_match = 1;
-				ap->ability_match_cfg = rx_cfg_reg;
-			}
-		}
-		if (rx_cfg_reg & ANEG_CFG_ACK)
-			ap->ack_match = 1;
-		else
-			ap->ack_match = 0;
-
-		ap->idle_match = 0;
-	} else {
-		ap->idle_match = 1;
-		ap->ability_match_cfg = 0;
-		ap->ability_match_count = 0;
-		ap->ability_match = 0;
-		ap->ack_match = 0;
-
-		rx_cfg_reg = 0;
-	}
-
-	ap->rxconfig = rx_cfg_reg;
-	ret = ANEG_OK;
-
-	switch(ap->state) {
-	case ANEG_STATE_UNKNOWN:
-		if (ap->flags & (MR_AN_ENABLE | MR_RESTART_AN))
-			ap->state = ANEG_STATE_AN_ENABLE;
-
-		/* fallthru */
-	case ANEG_STATE_AN_ENABLE:
-		ap->flags &= ~(MR_AN_COMPLETE | MR_PAGE_RX);
-		if (ap->flags & MR_AN_ENABLE) {
-			ap->link_time = 0;
-			ap->cur_time = 0;
-			ap->ability_match_cfg = 0;
-			ap->ability_match_count = 0;
-			ap->ability_match = 0;
-			ap->idle_match = 0;
-			ap->ack_match = 0;
-
-			ap->state = ANEG_STATE_RESTART_INIT;
-		} else {
-			ap->state = ANEG_STATE_DISABLE_LINK_OK;
-		}
-		break;
-
-	case ANEG_STATE_RESTART_INIT:
-		ap->link_time = ap->cur_time;
-		ap->flags &= ~(MR_NP_LOADED);
-		ap->txconfig = 0;
-		tw32(MAC_TX_AUTO_NEG, 0);
-		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
-		tw32_carefully(MAC_MODE, tp->mac_mode);
-
-		ret = ANEG_TIMER_ENAB;
-		ap->state = ANEG_STATE_RESTART;
-
-		/* fallthru */
-	case ANEG_STATE_RESTART:
-		delta = ap->cur_time - ap->link_time;
-		if (delta > ANEG_STATE_SETTLE_TIME) {
-			ap->state = ANEG_STATE_ABILITY_DETECT_INIT;
-		} else {
-			ret = ANEG_TIMER_ENAB;
-		}
-		break;
-
-	case ANEG_STATE_DISABLE_LINK_OK:
-		ret = ANEG_DONE;
-		break;
-
-	case ANEG_STATE_ABILITY_DETECT_INIT:
-		ap->flags &= ~(MR_TOGGLE_TX);
-		ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1);
-		tw32(MAC_TX_AUTO_NEG, ap->txconfig);
-		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
-		tw32_carefully(MAC_MODE, tp->mac_mode);
-
-		ap->state = ANEG_STATE_ABILITY_DETECT;
-		break;
-
-	case ANEG_STATE_ABILITY_DETECT:
-		if (ap->ability_match != 0 && ap->rxconfig != 0) {
-			ap->state = ANEG_STATE_ACK_DETECT_INIT;
-		}
-		break;
-
-	case ANEG_STATE_ACK_DETECT_INIT:
-		ap->txconfig |= ANEG_CFG_ACK;
-		tw32(MAC_TX_AUTO_NEG, ap->txconfig);
-		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
-		tw32_carefully(MAC_MODE, tp->mac_mode);
-
-		ap->state = ANEG_STATE_ACK_DETECT;
-
-		/* fallthru */
-	case ANEG_STATE_ACK_DETECT:
-		if (ap->ack_match != 0) {
-			if ((ap->rxconfig & ~ANEG_CFG_ACK) ==
-			    (ap->ability_match_cfg & ~ANEG_CFG_ACK)) {
-				ap->state = ANEG_STATE_COMPLETE_ACK_INIT;
-			} else {
-				ap->state = ANEG_STATE_AN_ENABLE;
-			}
-		} else if (ap->ability_match != 0 &&
-			   ap->rxconfig == 0) {
-			ap->state = ANEG_STATE_AN_ENABLE;
-		}
-		break;
-
-	case ANEG_STATE_COMPLETE_ACK_INIT:
-		if (ap->rxconfig & ANEG_CFG_INVAL) {
-			ret = ANEG_FAILED;
-			break;
-		}
-		ap->flags &= ~(MR_LP_ADV_FULL_DUPLEX |
-			       MR_LP_ADV_HALF_DUPLEX |
-			       MR_LP_ADV_SYM_PAUSE |
-			       MR_LP_ADV_ASYM_PAUSE |
-			       MR_LP_ADV_REMOTE_FAULT1 |
-			       MR_LP_ADV_REMOTE_FAULT2 |
-			       MR_LP_ADV_NEXT_PAGE |
-			       MR_TOGGLE_RX |
-			       MR_NP_RX);
-		if (ap->rxconfig & ANEG_CFG_FD)
-			ap->flags |= MR_LP_ADV_FULL_DUPLEX;
-		if (ap->rxconfig & ANEG_CFG_HD)
-			ap->flags |= MR_LP_ADV_HALF_DUPLEX;
-		if (ap->rxconfig & ANEG_CFG_PS1)
-			ap->flags |= MR_LP_ADV_SYM_PAUSE;
-		if (ap->rxconfig & ANEG_CFG_PS2)
-			ap->flags |= MR_LP_ADV_ASYM_PAUSE;
-		if (ap->rxconfig & ANEG_CFG_RF1)
-			ap->flags |= MR_LP_ADV_REMOTE_FAULT1;
-		if (ap->rxconfig & ANEG_CFG_RF2)
-			ap->flags |= MR_LP_ADV_REMOTE_FAULT2;
-		if (ap->rxconfig & ANEG_CFG_NP)
-			ap->flags |= MR_LP_ADV_NEXT_PAGE;
-
-		ap->link_time = ap->cur_time;
-
-		ap->flags ^= (MR_TOGGLE_TX);
-		if (ap->rxconfig & 0x0008)
-			ap->flags |= MR_TOGGLE_RX;
-		if (ap->rxconfig & ANEG_CFG_NP)
-			ap->flags |= MR_NP_RX;
-		ap->flags |= MR_PAGE_RX;
-
-		ap->state = ANEG_STATE_COMPLETE_ACK;
-		ret = ANEG_TIMER_ENAB;
-		break;
-
-	case ANEG_STATE_COMPLETE_ACK:
-		if (ap->ability_match != 0 &&
-		    ap->rxconfig == 0) {
-			ap->state = ANEG_STATE_AN_ENABLE;
-			break;
-		}
-		delta = ap->cur_time - ap->link_time;
-		if (delta > ANEG_STATE_SETTLE_TIME) {
-			if (!(ap->flags & (MR_LP_ADV_NEXT_PAGE))) {
-				ap->state = ANEG_STATE_IDLE_DETECT_INIT;
-			} else {
-				if ((ap->txconfig & ANEG_CFG_NP) == 0 &&
-				    !(ap->flags & MR_NP_RX)) {
-					ap->state = ANEG_STATE_IDLE_DETECT_INIT;
-				} else {
-					ret = ANEG_FAILED;
-				}
-			}
-		}
-		break;
-
-	case ANEG_STATE_IDLE_DETECT_INIT:
-		ap->link_time = ap->cur_time;
-		tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
-		tw32_carefully(MAC_MODE, tp->mac_mode);
-
-		ap->state = ANEG_STATE_IDLE_DETECT;
-		ret = ANEG_TIMER_ENAB;
-		break;
-
-	case ANEG_STATE_IDLE_DETECT:
-		if (ap->ability_match != 0 &&
-		    ap->rxconfig == 0) {
-			ap->state = ANEG_STATE_AN_ENABLE;
-			break;
-		}
-		delta = ap->cur_time - ap->link_time;
-		if (delta > ANEG_STATE_SETTLE_TIME) {
-			/* XXX another gem from the Broadcom driver :( */
-			ap->state = ANEG_STATE_LINK_OK;
-		}
-		break;
-
-	case ANEG_STATE_LINK_OK:
-		ap->flags |= (MR_AN_COMPLETE | MR_LINK_OK);
-		ret = ANEG_DONE;
-		break;
-
-	case ANEG_STATE_NEXT_PAGE_WAIT_INIT:
-		/* ??? unimplemented */
-		break;
-
-	case ANEG_STATE_NEXT_PAGE_WAIT:
-		/* ??? unimplemented */
-		break;
-
-	default:
-		ret = ANEG_FAILED;
-		break;
-	};
-
-	return ret;
-}
-
-static int tg3_setup_fiber_phy(struct tg3 *tp)
-{
-	uint32_t orig_pause_cfg;
-	uint16_t orig_active_speed;
-	uint8_t orig_active_duplex;
-	int current_link_up;
-	int i;
-
-	orig_pause_cfg =
-		(tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
-				  TG3_FLAG_TX_PAUSE));
-	orig_active_speed = tp->link_config.active_speed;
-	orig_active_duplex = tp->link_config.active_duplex;
-
-	tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
-	tp->mac_mode |= MAC_MODE_PORT_MODE_TBI;
-	tw32_carefully(MAC_MODE, tp->mac_mode);
-
-	/* Reset when initting first time or we have a link. */
-	if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
-	    (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) {
-		/* Set PLL lock range. */
-		tg3_writephy(tp, 0x16, 0x8007);
-
-		/* SW reset */
-		tg3_writephy(tp, MII_BMCR, BMCR_RESET);
-
-		/* Wait for reset to complete. */
-		mdelay(5);
-
-		/* Config mode; select PMA/Ch 1 regs. */
-		tg3_writephy(tp, 0x10, 0x8411);
-
-		/* Enable auto-lock and comdet, select txclk for tx. */
-		tg3_writephy(tp, 0x11, 0x0a10);
-
-		tg3_writephy(tp, 0x18, 0x00a0);
-		tg3_writephy(tp, 0x16, 0x41ff);
-
-		/* Assert and deassert POR. */
-		tg3_writephy(tp, 0x13, 0x0400);
-		udelay(40);
-		tg3_writephy(tp, 0x13, 0x0000);
-
-		tg3_writephy(tp, 0x11, 0x0a50);
-		udelay(40);
-		tg3_writephy(tp, 0x11, 0x0a10);
-
-		/* Wait for signal to stabilize */
-		mdelay(150);
-
-		/* Deselect the channel register so we can read the PHYID
-		 * later.
-		 */
-		tg3_writephy(tp, 0x10, 0x8011);
-	}
-
-	/* Disable link change interrupt.  */
-	tw32_carefully(MAC_EVENT, 0);
-
-	current_link_up = 0;
-	if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) {
-		if (!(tp->tg3_flags & TG3_FLAG_GOT_SERDES_FLOWCTL)) {
-			struct tg3_fiber_aneginfo aninfo;
-			int status = ANEG_FAILED;
-			unsigned int tick;
-			uint32_t tmp;
-
-			memset(&aninfo, 0, sizeof(aninfo));
-			aninfo.flags |= (MR_AN_ENABLE);
-
-			tw32(MAC_TX_AUTO_NEG, 0);
-
-			tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
-			tw32_carefully(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII);
-
-			tw32_carefully(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS);
-
-			aninfo.state = ANEG_STATE_UNKNOWN;
-			aninfo.cur_time = 0;
-			tick = 0;
-			while (++tick < 195000) {
-				status = tg3_fiber_aneg_smachine(tp, &aninfo);
-				if (status == ANEG_DONE ||
-				    status == ANEG_FAILED)
-					break;
-
-				udelay(1);
-			}
-
-			tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
-			tw32_carefully(MAC_MODE, tp->mac_mode);
-
-			if (status == ANEG_DONE &&
-			    (aninfo.flags &
-			     (MR_AN_COMPLETE | MR_LINK_OK |
-			      MR_LP_ADV_FULL_DUPLEX))) {
-				uint32_t local_adv, remote_adv;
-
-				local_adv = ADVERTISE_PAUSE_CAP;
-				remote_adv = 0;
-				if (aninfo.flags & MR_LP_ADV_SYM_PAUSE)
-					remote_adv |= LPA_PAUSE_CAP;
-				if (aninfo.flags & MR_LP_ADV_ASYM_PAUSE)
-					remote_adv |= LPA_PAUSE_ASYM;
-
-				tg3_setup_flow_control(tp, local_adv, remote_adv);
-
-				tp->tg3_flags |=
-					TG3_FLAG_GOT_SERDES_FLOWCTL;
-				current_link_up = 1;
-			}
-			for (i = 0; i < 60; i++) {
-				udelay(20);
-				tw32_carefully(MAC_STATUS,
-					(MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED));
-				if ((tr32(MAC_STATUS) &
-				     (MAC_STATUS_SYNC_CHANGED |
-				      MAC_STATUS_CFG_CHANGED)) == 0)
-					break;
-			}
-			if (current_link_up == 0 &&
-			    (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) {
-				current_link_up = 1;
-			}
-		} else {
-			/* Forcing 1000FD link up. */
-			current_link_up = 1;
-		}
-	}
-
-	tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
-	tw32_carefully(MAC_MODE, tp->mac_mode);
-
-	tp->hw_status->status =
-		(SD_STATUS_UPDATED |
-		 (tp->hw_status->status & ~SD_STATUS_LINK_CHG));
-
-	for (i = 0; i < 100; i++) {
-		udelay(20);
-		tw32_carefully(MAC_STATUS,
-			(MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED));
-		if ((tr32(MAC_STATUS) &
-		     (MAC_STATUS_SYNC_CHANGED |
-		      MAC_STATUS_CFG_CHANGED)) == 0)
-			break;
-	}
-
-	if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0)
-		current_link_up = 0;
-
-	if (current_link_up == 1) {
-		tp->link_config.active_speed = SPEED_1000;
-		tp->link_config.active_duplex = DUPLEX_FULL;
-	} else {
-		tp->link_config.active_speed = SPEED_INVALID;
-		tp->link_config.active_duplex = DUPLEX_INVALID;
-	}
-
-	if (current_link_up != tp->carrier_ok) {
-		tp->carrier_ok = current_link_up;
-		tg3_link_report(tp);
-	} else {
-		uint32_t now_pause_cfg =
-			tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
-					 TG3_FLAG_TX_PAUSE);
-		if (orig_pause_cfg != now_pause_cfg ||
-		    orig_active_speed != tp->link_config.active_speed ||
-		    orig_active_duplex != tp->link_config.active_duplex)
-			tg3_link_report(tp);
-	}
-
-	if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) {
-		tw32_carefully(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY);
-		if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) {
-			tw32_carefully(MAC_MODE, tp->mac_mode);
-		}
-	}
-
-	return 0;
-}
-#else
-#define tg3_setup_fiber_phy(TP) (-EINVAL)
-#endif /* SUPPORT_FIBER_PHY */
-
-static int tg3_setup_phy(struct tg3 *tp)
-{
-	int err;
-
-	if (tp->phy_id == PHY_ID_SERDES) {
-		err = tg3_setup_fiber_phy(tp);
-	} else {
-		err = tg3_setup_copper_phy(tp);
-	}
-
-	if (tp->link_config.active_speed == SPEED_1000 &&
-	    tp->link_config.active_duplex == DUPLEX_HALF)
-		tw32(MAC_TX_LENGTHS,
-		     ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
-		      (6 << TX_LENGTHS_IPG_SHIFT) |
-		      (0xff << TX_LENGTHS_SLOT_TIME_SHIFT)));
-	else
-		tw32(MAC_TX_LENGTHS,
-		     ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
-		      (6 << TX_LENGTHS_IPG_SHIFT) |
-		      (32 << TX_LENGTHS_SLOT_TIME_SHIFT)));
-
-	return err;
-}
-
-
-#define MAX_WAIT_CNT 1000
-
-/* To stop a block, clear the enable bit and poll till it
- * clears.  
- */
-static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, uint32_t enable_bit)
-{
-	unsigned int i;
-	uint32_t val;
-
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
-		switch(ofs) {
-		case RCVLSC_MODE:
-		case DMAC_MODE:
-		case MBFREE_MODE:
-		case BUFMGR_MODE:
-		case MEMARB_MODE:
-			/* We can't enable/disable these bits of the
-			 * 5705 or 5787, just say success.
-			 */
-			return 0;
-		default:
-			break;
-		}
-	}
-	val = tr32(ofs);
-	val &= ~enable_bit;
-	tw32(ofs, val);
-	tr32(ofs);
-
-	for (i = 0; i < MAX_WAIT_CNT; i++) {
-		udelay(100);
-		val = tr32(ofs);
-		if ((val & enable_bit) == 0)
-			break;
-	}
-
-	if (i == MAX_WAIT_CNT) {
-		printf( "tg3_stop_block timed out, ofs=%#lx enable_bit=%3x\n",
-		       ofs, enable_bit );
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static int tg3_abort_hw(struct tg3 *tp)
-{
-	int i, err;
-	uint32_t val;
-
-	tg3_disable_ints(tp);
-
-	tp->rx_mode &= ~RX_MODE_ENABLE;
-	tw32_carefully(MAC_RX_MODE, tp->rx_mode);
-
-	err  = tg3_stop_block(tp, RCVBDI_MODE,   RCVBDI_MODE_ENABLE);
-	err |= tg3_stop_block(tp, RCVLPC_MODE,   RCVLPC_MODE_ENABLE);
-	err |= tg3_stop_block(tp, RCVLSC_MODE,   RCVLSC_MODE_ENABLE);
-	err |= tg3_stop_block(tp, RCVDBDI_MODE,  RCVDBDI_MODE_ENABLE);
-	err |= tg3_stop_block(tp, RCVDCC_MODE,   RCVDCC_MODE_ENABLE);
-	err |= tg3_stop_block(tp, RCVCC_MODE,    RCVCC_MODE_ENABLE);
-
-	err |= tg3_stop_block(tp, SNDBDS_MODE,   SNDBDS_MODE_ENABLE);
-	err |= tg3_stop_block(tp, SNDBDI_MODE,   SNDBDI_MODE_ENABLE);
-	err |= tg3_stop_block(tp, SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
-	err |= tg3_stop_block(tp, RDMAC_MODE,    RDMAC_MODE_ENABLE);
-	err |= tg3_stop_block(tp, SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
-	err |= tg3_stop_block(tp, SNDBDC_MODE,   SNDBDC_MODE_ENABLE);
-	if (err)
-		goto out;
-
-	tp->mac_mode &= ~MAC_MODE_TDE_ENABLE;
-	tw32_carefully(MAC_MODE, tp->mac_mode);
-
-	tp->tx_mode &= ~TX_MODE_ENABLE;
-	tw32_carefully(MAC_TX_MODE, tp->tx_mode);
-
-	for (i = 0; i < MAX_WAIT_CNT; i++) {
-		udelay(100);
-		if (!(tr32(MAC_TX_MODE) & TX_MODE_ENABLE))
-			break;
-	}
-	if (i >= MAX_WAIT_CNT) {
-		printf("tg3_abort_hw timed out TX_MODE_ENABLE will not clear MAC_TX_MODE=%x\n",
-		       (unsigned int) tr32(MAC_TX_MODE));
-		return -ENODEV;
-	}
-
-	err  = tg3_stop_block(tp, HOSTCC_MODE, HOSTCC_MODE_ENABLE);
-	err |= tg3_stop_block(tp, WDMAC_MODE,  WDMAC_MODE_ENABLE);
-	err |= tg3_stop_block(tp, MBFREE_MODE, MBFREE_MODE_ENABLE);
-
-	val = tr32(FTQ_RESET);
-	val |= FTQ_RESET_DMA_READ_QUEUE | FTQ_RESET_DMA_HIGH_PRI_READ |
-	       FTQ_RESET_SEND_BD_COMPLETION | FTQ_RESET_DMA_WRITE |
-	       FTQ_RESET_DMA_HIGH_PRI_WRITE | FTQ_RESET_SEND_DATA_COMPLETION |
-	       FTQ_RESET_HOST_COALESCING | FTQ_RESET_MAC_TX |
-	       FTQ_RESET_RX_BD_COMPLETE | FTQ_RESET_RX_LIST_PLCMT |
-               FTQ_RESET_RX_DATA_COMPLETION;
-	tw32(FTQ_RESET, val);
-
-	err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE);
-	err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE);
-	if (err)
-		goto out;
-
-	memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
-
-out:
-	return err;
-}
-
-static void tg3_chip_reset(struct tg3 *tp)
-{
-	uint32_t val;
-
-	if (!(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) {
-		/* Force NVRAM to settle.
-		 * This deals with a chip bug which can result in EEPROM
-		 * corruption.
-		 */
-		if (tp->tg3_flags & TG3_FLAG_NVRAM) {
-			int i;
-	
-			tw32(NVRAM_SWARB, SWARB_REQ_SET1);
-			for (i = 0; i < 100000; i++) {
-				if (tr32(NVRAM_SWARB) & SWARB_GNT1)
-					break;
-				udelay(10);
-			}
-		}
-	}
-	/* In Etherboot we don't need to worry about the 5701
-	 * REG_WRITE_BUG because we do all register writes indirectly.
-	 */
-
-	// Alf: here patched
-	/* do the reset */
-	val = GRC_MISC_CFG_CORECLK_RESET;
-	if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
-		if (tr32(0x7e2c) == 0x60) {
-			tw32(0x7e2c, 0x20);
-		}
-		if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) {
-			tw32(GRC_MISC_CFG, (1 << 29));
-			val |= (1 << 29);
-		}
-	}
-	
-	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
-	    || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
-	    || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)) {
-		val |= GRC_MISC_CFG_KEEP_GPHY_POWER;
-	}
-
-	// Alf : Please VALIDATE THIS.
-	// It is necessary in my case (5751) to prevent a reboot, but
-	// I have no idea about a side effect on any other version.
-	// It appears to be what's done in tigon3.c from Broadcom
-	if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) {
-	  tw32(GRC_MISC_CFG, 0x20000000) ;
-	  val |= 0x20000000 ;
-	}
-
-	tw32(GRC_MISC_CFG, val);
-
-	/* Flush PCI posted writes.  The normal MMIO registers
-	 * are inaccessible at this time so this is the only
-	 * way to make this reliably.  I tried to use indirect
-	 * register read/write but this upset some 5701 variants.
-	 */
-	pci_read_config_dword(tp->pdev, PCI_COMMAND, &val);
-
-	udelay(120);
-
-	/* Re-enable indirect register accesses. */
-	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
-			       tp->misc_host_ctrl);
-
-	/* Set MAX PCI retry to zero. */
-	val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
-	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
-		val |= PCISTATE_RETRY_SAME_DMA;
-	pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
-
-	pci_restore_state(tp->pdev, tp->pci_cfg_state);
-
-	/* Make sure PCI-X relaxed ordering bit is clear. */
-	pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
-	val &= ~PCIX_CAPS_RELAXED_ORDERING;
-	pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val);
-
-	tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
-
-	if (((tp->nic_sram_data_cfg & NIC_SRAM_DATA_CFG_MINI_PCI) != 0) &&
-		(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) {
-		tp->pci_clock_ctrl |=
-			(CLOCK_CTRL_FORCE_CLKRUN | CLOCK_CTRL_CLKRUN_OENABLE);
-		tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
-	}
-
-	tw32(TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl);
-}
-
-static void tg3_stop_fw(struct tg3 *tp)
-{
-	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
-		uint32_t val;
-		int i;
-
-		tg3_write_mem(NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_PAUSE_FW);
-		val = tr32(GRC_RX_CPU_EVENT);
-		val |= (1 << 14);
-		tw32(GRC_RX_CPU_EVENT, val);
-
-		/* Wait for RX cpu to ACK the event.  */
-		for (i = 0; i < 100; i++) {
-			if (!(tr32(GRC_RX_CPU_EVENT) & (1 << 14)))
-				break;
-			udelay(1);
-		}
-	}
-}
-
-static int tg3_restart_fw(struct tg3 *tp, uint32_t state)
-{
-	uint32_t val;
-	int i;
-	
-	tg3_write_mem(NIC_SRAM_FIRMWARE_MBOX, 
-		NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
-	/* Wait for firmware initialization to complete. */
-	for (i = 0; i < 100000; i++) {
-		tg3_read_mem(NIC_SRAM_FIRMWARE_MBOX, &val);
-		if (val == (uint32_t) ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
-			break;
-		udelay(10);
-	}
-	if (i >= 100000 &&
-		    !(tp->tg3_flags2 & TG3_FLG2_SUN_5704) &&
-		    !(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)) {
-		printf ( "Firmware will not restart magic=%#x\n",
-			val );
-		return -ENODEV;
-	}
-	if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
-	  state = DRV_STATE_SUSPEND;
-	}
-
-	if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
-	    (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0)) {
-	  // Enable PCIE bug fix
-	  tg3_read_mem(0x7c00, &val);
-	  tg3_write_mem(0x7c00, val | 0x02000000);
-	}
-	tg3_write_mem(NIC_SRAM_FW_DRV_STATE_MBOX, state);
-	return 0;
-}
-
-static int tg3_halt(struct tg3 *tp)
-{
-	tg3_stop_fw(tp);
-	tg3_abort_hw(tp);
-	tg3_chip_reset(tp);
-	return tg3_restart_fw(tp, DRV_STATE_UNLOAD);
-}
-
-static void __tg3_set_mac_addr(struct tg3 *tp)
-{
-	uint32_t addr_high, addr_low;
-	int i;
-
-	addr_high = ((tp->nic->node_addr[0] << 8) |
-		     tp->nic->node_addr[1]);
-	addr_low = ((tp->nic->node_addr[2] << 24) |
-		    (tp->nic->node_addr[3] << 16) |
-		    (tp->nic->node_addr[4] <<  8) |
-		    (tp->nic->node_addr[5] <<  0));
-	for (i = 0; i < 4; i++) {
-		tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high);
-		tw32(MAC_ADDR_0_LOW + (i * 8), addr_low);
-	}
-
-	if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) &&
-		(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) &&
-		(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705)) {
-		for(i = 0; i < 12; i++) {
-			tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high);
-			tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low);
-		}
-	}
-	addr_high = (tp->nic->node_addr[0] +
-		     tp->nic->node_addr[1] +
-		     tp->nic->node_addr[2] +
-		     tp->nic->node_addr[3] +
-		     tp->nic->node_addr[4] +
-		     tp->nic->node_addr[5]) &
-		TX_BACKOFF_SEED_MASK;
-	tw32(MAC_TX_BACKOFF_SEED, addr_high);
-}
-
-static void tg3_set_bdinfo(struct tg3 *tp, uint32_t bdinfo_addr,
-			   dma_addr_t mapping, uint32_t maxlen_flags,
-			   uint32_t nic_addr)
-{
-	tg3_write_mem((bdinfo_addr +
-		       TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH),
-		      ((uint64_t) mapping >> 32));
-	tg3_write_mem((bdinfo_addr +
-		       TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW),
-		      ((uint64_t) mapping & 0xffffffff));
-	tg3_write_mem((bdinfo_addr +
-		       TG3_BDINFO_MAXLEN_FLAGS),
-		       maxlen_flags);
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
-		tg3_write_mem((bdinfo_addr + TG3_BDINFO_NIC_ADDR), nic_addr);
-	}
-}
-
-
-static void tg3_init_rings(struct tg3 *tp)
-{
-	unsigned i;
-
-	/* Zero out the tg3 variables */
-	memset(&tg3_bss, 0, sizeof(tg3_bss));
-	tp->rx_std    = &tg3_bss.rx_std[0];
-	tp->rx_rcb    = &tg3_bss.rx_rcb[0];
-	tp->tx_ring   = &tg3_bss.tx_ring[0];
-	tp->hw_status = &tg3_bss.hw_status;
-	tp->hw_stats  = &tg3_bss.hw_stats;
-	tp->mac_mode  = 0;
-
-
-	/* Initialize tx/rx rings for packet processing.
-	 *
-	 * The chip has been shut down and the driver detached from
-	 * the networking, so no interrupts or new tx packets will
-	 * end up in the driver.
-	 */
-
-	/* Initialize invariants of the rings, we only set this
-	 * stuff once.  This works because the card does not
-	 * write into the rx buffer posting rings.
-	 */
-	for (i = 0; i < TG3_RX_RING_SIZE; i++) {
-		struct tg3_rx_buffer_desc *rxd;
-
-		rxd = &tp->rx_std[i];
-		rxd->idx_len = (RX_PKT_BUF_SZ - 2 - 64)	<< RXD_LEN_SHIFT;
-		rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT);
-		rxd->opaque = (RXD_OPAQUE_RING_STD | (i << RXD_OPAQUE_INDEX_SHIFT));
-
-		/* Note where the receive buffer for the ring is placed */
-		rxd->addr_hi = 0;
-		rxd->addr_lo = virt_to_bus(
-			&tg3_bss.rx_bufs[i%TG3_DEF_RX_RING_PENDING][2]);
-	}
-}
-
-#define TG3_WRITE_SETTINGS(TABLE) \
-do { \
-	const uint32_t *_table, *_end; \
-	_table = TABLE; \
-	_end = _table + sizeof(TABLE)/sizeof(TABLE[0]);  \
-	for(; _table < _end; _table += 2) { \
-		tw32(_table[0], _table[1]); \
-	} \
-} while(0)
-
-
-/* initialize/reset the tg3 */
-static int tg3_setup_hw(struct tg3 *tp)
-{
-	uint32_t val, rdmac_mode;
-	int i, err, limit;
-
-	/* Simply don't support setups with extremly buggy firmware in etherboot */
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) {
-		printf("Error 5701_A0 firmware bug detected\n");
-		return -EINVAL;
-	}
-
-	tg3_disable_ints(tp);
-
-	/* Originally this was all in tg3_init_hw */
-
-	/* Force the chip into D0. */
-	tg3_set_power_state_0(tp);
-
-	tg3_switch_clocks(tp);
-
-	tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
-
-	// This should go somewhere else
-#define T3_PCIE_CAPABILITY_ID_REG           0xD0
-#define T3_PCIE_CAPABILITY_ID               0x10
-#define T3_PCIE_CAPABILITY_REG              0xD2
-
-	/* Originally this was all in tg3_reset_hw */
-
-	tg3_stop_fw(tp);
-
-	/* No need to call tg3_abort_hw here, it is called before tg3_setup_hw. */
-
-	tg3_chip_reset(tp);
-
-	tw32(GRC_MODE, tp->grc_mode);  /* Redundant? */
-
-	err = tg3_restart_fw(tp, DRV_STATE_START);
-	if (err)
-		return err;
-
-	if (tp->phy_id == PHY_ID_SERDES) {
-		tp->mac_mode = MAC_MODE_PORT_MODE_TBI;
-	}
-	tw32_carefully(MAC_MODE, tp->mac_mode);
-
-
-	/* This works around an issue with Athlon chipsets on
-	 * B3 tigon3 silicon.  This bit has no effect on any
-	 * other revision.
-	 * Alf: Except 5750 ! (which reboots)
-	 */
-
-        if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
-	  tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT;
-	tw32_carefully(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
-
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
-	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) {
-		val = tr32(TG3PCI_PCISTATE);
-		val |= PCISTATE_RETRY_SAME_DMA;
-		tw32(TG3PCI_PCISTATE, val);
-	}
-
-	/* Descriptor ring init may make accesses to the
-	 * NIC SRAM area to setup the TX descriptors, so we
-	 * can only do this after the hardware has been
-	 * successfully reset.
-	 */
-	tg3_init_rings(tp);
-
-	/* Clear statistics/status block in chip */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
-		for (i = NIC_SRAM_STATS_BLK;
-		     i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE;
-		     i += sizeof(uint32_t)) {
-			tg3_write_mem(i, 0);
-			udelay(40);
-		}
-	}
-
-	/* This value is determined during the probe time DMA
-	 * engine test, tg3_setup_dma.
-	 */
-	tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
-
-	tp->grc_mode &= ~(GRC_MODE_HOST_SENDBDS |
-			  GRC_MODE_4X_NIC_SEND_RINGS |
-			  GRC_MODE_NO_TX_PHDR_CSUM |
-			  GRC_MODE_NO_RX_PHDR_CSUM);
-	tp->grc_mode |= GRC_MODE_HOST_SENDBDS;
-	tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM;
-	tp->grc_mode |= GRC_MODE_NO_RX_PHDR_CSUM;
-
-	tw32(GRC_MODE,
-		tp->grc_mode | 
-		(GRC_MODE_IRQ_ON_MAC_ATTN | GRC_MODE_HOST_STACKUP));
-
-	/* Setup the timer prescalar register.  Clock is always 66Mhz. */
-	tw32(GRC_MISC_CFG,
-	     (65 << GRC_MISC_CFG_PRESCALAR_SHIFT));
-
-	/* Initialize MBUF/DESC pool. */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
-		/* Do nothing. */
-	} else if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) &&
-		(tp->pci_chip_rev_id != CHIPREV_ID_5721)) {
-		tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE);
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
-			tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE64);
-		else
-			tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE96);
-		tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
-		tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
-	}
-	if (!(tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE)) {
-		tw32(BUFMGR_MB_RDMA_LOW_WATER,
-		     tp->bufmgr_config.mbuf_read_dma_low_water);
-		tw32(BUFMGR_MB_MACRX_LOW_WATER,
-		     tp->bufmgr_config.mbuf_mac_rx_low_water);
-		tw32(BUFMGR_MB_HIGH_WATER,
-		     tp->bufmgr_config.mbuf_high_water);
-	} else {
-		tw32(BUFMGR_MB_RDMA_LOW_WATER,
-		     tp->bufmgr_config.mbuf_read_dma_low_water_jumbo);
-		tw32(BUFMGR_MB_MACRX_LOW_WATER,
-		     tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo);
-		tw32(BUFMGR_MB_HIGH_WATER,
-		     tp->bufmgr_config.mbuf_high_water_jumbo);
-	}
-	tw32(BUFMGR_DMA_LOW_WATER,
-	     tp->bufmgr_config.dma_low_water);
-	tw32(BUFMGR_DMA_HIGH_WATER,
-	     tp->bufmgr_config.dma_high_water);
-
-	tw32(BUFMGR_MODE, BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE);
-	for (i = 0; i < 2000; i++) {
-		if (tr32(BUFMGR_MODE) & BUFMGR_MODE_ENABLE)
-			break;
-		udelay(10);
-	}
-	if (i >= 2000) {
-		printf("tg3_setup_hw cannot enable BUFMGR\n");
-		return -ENODEV;
-	}
-
-	tw32(FTQ_RESET, 0xffffffff);
-	tw32(FTQ_RESET, 0x00000000);
-	for (i = 0; i < 2000; i++) {
-		if (tr32(FTQ_RESET) == 0x00000000)
-			break;
-		udelay(10);
-	}
-	if (i >= 2000) {
-		printf("tg3_setup_hw cannot reset FTQ\n");
-		return -ENODEV;
-	}
-
-	/* Initialize TG3_BDINFO's at:
-	 *  RCVDBDI_STD_BD:	standard eth size rx ring
-	 *  RCVDBDI_JUMBO_BD:	jumbo frame rx ring
-	 *  RCVDBDI_MINI_BD:	small frame rx ring (??? does not work)
-	 *
-	 * like so:
-	 *  TG3_BDINFO_HOST_ADDR:	high/low parts of DMA address of ring
-	 *  TG3_BDINFO_MAXLEN_FLAGS:	(rx max buffer size << 16) |
-	 *                              ring attribute flags
-	 *  TG3_BDINFO_NIC_ADDR:	location of descriptors in nic SRAM
-	 *
-	 * Standard receive ring @ NIC_SRAM_RX_BUFFER_DESC, 512 entries.
-	 * Jumbo receive ring @ NIC_SRAM_RX_JUMBO_BUFFER_DESC, 256 entries.
-	 *
-	 * ??? No space allocated for mini receive ring? :(
-	 *
-	 * The size of each ring is fixed in the firmware, but the location is
-	 * configurable.
-	 */
-	{
-		static const uint32_t table_all[] = {
-			/* Setup replenish thresholds. */
-			RCVBDI_STD_THRESH, TG3_DEF_RX_RING_PENDING / 8,
-
-			/* Etherboot lives below 4GB */
-			RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH, 0,
-			RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR, NIC_SRAM_RX_BUFFER_DESC,
-		};
-		static const uint32_t table_not_5705[] = {
-			/* Buffer maximum length */
-			RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT,
-			
-			/* Disable the mini frame rx ring */
-			RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS,	BDINFO_FLAGS_DISABLED,
-			
-			/* Disable the jumbo frame rx ring */
-			RCVBDI_JUMBO_THRESH, 0,
-			RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS, BDINFO_FLAGS_DISABLED,
-			
-			
-		};
-		TG3_WRITE_SETTINGS(table_all);
-		tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW, 
-			virt_to_bus(tp->rx_std));
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
-			tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS,
-				RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT);
-		} else {
-			TG3_WRITE_SETTINGS(table_not_5705);
-		}
-	}
-
-	
-	/* There is only one send ring on 5705 and 5787, no need to explicitly
-	 * disable the others.
-	 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) {
-		/* Clear out send RCB ring in SRAM. */
-		for (i = NIC_SRAM_SEND_RCB; i < NIC_SRAM_RCV_RET_RCB; i += TG3_BDINFO_SIZE)
-			tg3_write_mem(i + TG3_BDINFO_MAXLEN_FLAGS, BDINFO_FLAGS_DISABLED);
-	}
-
-	tp->tx_prod = 0;
-	tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
-	tw32_mailbox2(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
-
-	tg3_set_bdinfo(tp,
-		NIC_SRAM_SEND_RCB,
-		virt_to_bus(tp->tx_ring),
-		(TG3_TX_RING_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT),
-		NIC_SRAM_TX_BUFFER_DESC);
-
-	/* There is only one receive return ring on 5705 and 5787, no need to
-	 * explicitly disable the others.
-	 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) {
-		for (i = NIC_SRAM_RCV_RET_RCB; i < NIC_SRAM_STATS_BLK; i += TG3_BDINFO_SIZE) {
-			tg3_write_mem(i + TG3_BDINFO_MAXLEN_FLAGS,
-				BDINFO_FLAGS_DISABLED);
-		}
-	}
-
-	tp->rx_rcb_ptr = 0;
-	tw32_mailbox2(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, 0);
-
-	tg3_set_bdinfo(tp,
-		NIC_SRAM_RCV_RET_RCB,
-		virt_to_bus(tp->rx_rcb),
-		(TG3_RX_RCB_RING_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT),
-		0);
-
-	tp->rx_std_ptr = TG3_DEF_RX_RING_PENDING;
-	tw32_mailbox2(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW,
-		     tp->rx_std_ptr);
-
-	tw32_mailbox2(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, 0);
-
-	/* Initialize MAC address and backoff seed. */
-	__tg3_set_mac_addr(tp);
-
-	/* Calculate RDMAC_MODE setting early, we need it to determine
-	 * the RCVLPC_STATE_ENABLE mask.
-	 */
-	rdmac_mode = (RDMAC_MODE_ENABLE | RDMAC_MODE_TGTABORT_ENAB |
-		RDMAC_MODE_MSTABORT_ENAB | RDMAC_MODE_PARITYERR_ENAB |
-		RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB |
-		RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
-		RDMAC_MODE_LNGREAD_ENAB);
-	if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
-		rdmac_mode |= RDMAC_MODE_SPLIT_ENABLE;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
-		if (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) {
-			if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) &&
-				!(tp->tg3_flags2 & TG3_FLG2_IS_5788)) {
-				rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
-			}
-		}
-	}
-
-	/* Setup host coalescing engine. */
-	tw32(HOSTCC_MODE, 0);
-	for (i = 0; i < 2000; i++) {
-		if (!(tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE))
-			break;
-		udelay(10);
-	}
-
-	tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
-		MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE;
-	tw32_carefully(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR);
-
-	tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
-		tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 |
-				       GRC_LCLCTRL_GPIO_OUTPUT1);
-	tw32_carefully(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
-
-	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0);
-	tr32(MAILBOX_INTERRUPT_0);
-
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
-		tw32_carefully(DMAC_MODE, DMAC_MODE_ENABLE);
-	}
-
-	val = (	WDMAC_MODE_ENABLE | WDMAC_MODE_TGTABORT_ENAB |
-		WDMAC_MODE_MSTABORT_ENAB | WDMAC_MODE_PARITYERR_ENAB |
-		WDMAC_MODE_ADDROFLOW_ENAB | WDMAC_MODE_FIFOOFLOW_ENAB |
-		WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB |
-		WDMAC_MODE_LNGREAD_ENAB);
-	if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) &&
-		((tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) != 0) &&
-		!(tp->tg3_flags2 & TG3_FLG2_IS_5788)) {
-		val |= WDMAC_MODE_RX_ACCEL;
-	}
-
-	/* Host coalescing bug fix */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
-		val |= (1 << 29);
-
-	tw32_carefully(WDMAC_MODE, val);
-
-	if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) {
-		val = tr32(TG3PCI_X_CAPS);
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
-			val &= PCIX_CAPS_BURST_MASK;
-			val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT);
-		} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
-			val &= ~(PCIX_CAPS_SPLIT_MASK | PCIX_CAPS_BURST_MASK);
-			val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT);
-			if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
-				val |= (tp->split_mode_max_reqs <<
-					PCIX_CAPS_SPLIT_SHIFT);
-		}
-		tw32(TG3PCI_X_CAPS, val);
-	}
-
-	tw32_carefully(RDMAC_MODE, rdmac_mode);
-	{
-		static const uint32_t table_all[] = {
-			/* MTU + ethernet header + FCS + optional VLAN tag */
-			MAC_RX_MTU_SIZE, ETH_MAX_MTU + ETH_HLEN + 8,
-			
-			/* The slot time is changed by tg3_setup_phy if we
-			 * run at gigabit with half duplex.
-			 */
-			MAC_TX_LENGTHS,	
-			(2 << TX_LENGTHS_IPG_CRS_SHIFT) |
-			(6 << TX_LENGTHS_IPG_SHIFT) |
-			(32 << TX_LENGTHS_SLOT_TIME_SHIFT),
-			
-			/* Receive rules. */
-			MAC_RCV_RULE_CFG, RCV_RULE_CFG_DEFAULT_CLASS,
-			RCVLPC_CONFIG, 0x0181,
-			
-			/* Receive/send statistics. */
-			RCVLPC_STATS_ENABLE, 0xffffff,
-			RCVLPC_STATSCTRL, RCVLPC_STATSCTRL_ENABLE,
-			SNDDATAI_STATSENAB, 0xffffff,
-			SNDDATAI_STATSCTRL, (SNDDATAI_SCTRL_ENABLE |SNDDATAI_SCTRL_FASTUPD),
-			
-			/* Host coalescing engine */
-			HOSTCC_RXCOL_TICKS, 0,
-			HOSTCC_TXCOL_TICKS, LOW_TXCOL_TICKS,
-			HOSTCC_RXMAX_FRAMES, 1,
-			HOSTCC_TXMAX_FRAMES, LOW_RXMAX_FRAMES,
-			HOSTCC_RXCOAL_MAXF_INT, 1,
-			HOSTCC_TXCOAL_MAXF_INT, 0,
-			
-			/* Status/statistics block address. */
-			/* Etherboot lives below 4GB, so HIGH == 0 */
-			HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, 0,
-
-			/* No need to enable 32byte coalesce mode. */
-			HOSTCC_MODE, HOSTCC_MODE_ENABLE | 0,
-			
-			RCVCC_MODE, RCVCC_MODE_ENABLE | RCVCC_MODE_ATTN_ENABLE,
-			RCVLPC_MODE, RCVLPC_MODE_ENABLE,
-			
-			RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE,
-
-			SNDDATAC_MODE, SNDDATAC_MODE_ENABLE,
-			SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE,
-			RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB,
-			RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ,
-			SNDDATAI_MODE, SNDDATAI_MODE_ENABLE,
-			SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE,
-			SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE,
-			
-			/* Accept all multicast frames. */
-			MAC_HASH_REG_0, 0xffffffff,
-			MAC_HASH_REG_1, 0xffffffff,
-			MAC_HASH_REG_2, 0xffffffff,
-			MAC_HASH_REG_3, 0xffffffff,
-		};
-		static const uint32_t table_not_5705[] = {
-			/* Host coalescing engine */
-			HOSTCC_RXCOAL_TICK_INT, 0,
-			HOSTCC_TXCOAL_TICK_INT, 0,
-
-			/* Status/statistics block address. */
-			/* Etherboot lives below 4GB, so HIGH == 0 */
-			HOSTCC_STAT_COAL_TICKS, DEFAULT_STAT_COAL_TICKS,
-			HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH, 0,
-			HOSTCC_STATS_BLK_NIC_ADDR, NIC_SRAM_STATS_BLK,
-			HOSTCC_STATUS_BLK_NIC_ADDR, NIC_SRAM_STATUS_BLK,
-
-			RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE,
-
-			MBFREE_MODE, MBFREE_MODE_ENABLE,
-		};
-		TG3_WRITE_SETTINGS(table_all);
-		tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
-			virt_to_bus(tp->hw_stats));
-		tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
-			virt_to_bus(tp->hw_status));
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-		    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) {
-			TG3_WRITE_SETTINGS(table_not_5705);
-		}
-	}
-
-	tp->tx_mode = TX_MODE_ENABLE;
-	tw32_carefully(MAC_TX_MODE, tp->tx_mode);
-
-	tp->rx_mode = RX_MODE_ENABLE;
-	tw32_carefully(MAC_RX_MODE, tp->rx_mode);
-
-	tp->mi_mode = MAC_MI_MODE_BASE;
-	tw32_carefully(MAC_MI_MODE, tp->mi_mode);
-
-	tw32(MAC_LED_CTRL, 0);
-	tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
-	if (tp->phy_id == PHY_ID_SERDES) {
-		tw32_carefully(MAC_RX_MODE, RX_MODE_RESET);
-	}
-	tp->rx_mode |= RX_MODE_KEEP_VLAN_TAG; /* drop tagged vlan packets */
-	tw32_carefully(MAC_RX_MODE, tp->rx_mode);
-
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1)
-		tw32(MAC_SERDES_CFG, 0x616000);
-
-	/* Prevent chip from dropping frames when flow control
-	 * is enabled.
-	 */
-	tw32(MAC_LOW_WMARK_MAX_RX_FRAME, 2);
-	tr32(MAC_LOW_WMARK_MAX_RX_FRAME);
-
-	err = tg3_setup_phy(tp);
-
-	/* Ignore CRC stats */
-
-	/* Initialize receive rules. */
-	tw32(MAC_RCV_RULE_0,  0xc2000000 & RCV_RULE_DISABLE_MASK);
-	tw32(MAC_RCV_VALUE_0, 0xffffffff & RCV_RULE_DISABLE_MASK);
-	tw32(MAC_RCV_RULE_1,  0x86000004 & RCV_RULE_DISABLE_MASK);
-	tw32(MAC_RCV_VALUE_1, 0xffffffff & RCV_RULE_DISABLE_MASK);
-
-	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
-	    || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750))
-		limit = 8;
-	else
-		limit = 16;
-	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF)
-		limit -= 4;
-	switch (limit) {
-	case 16:	tw32(MAC_RCV_RULE_15,  0); tw32(MAC_RCV_VALUE_15,  0);
-	case 15:	tw32(MAC_RCV_RULE_14,  0); tw32(MAC_RCV_VALUE_14,  0);
-	case 14:	tw32(MAC_RCV_RULE_13,  0); tw32(MAC_RCV_VALUE_13,  0);
-	case 13:	tw32(MAC_RCV_RULE_12,  0); tw32(MAC_RCV_VALUE_12,  0);
-	case 12:	tw32(MAC_RCV_RULE_11,  0); tw32(MAC_RCV_VALUE_11,  0);
-	case 11:	tw32(MAC_RCV_RULE_10,  0); tw32(MAC_RCV_VALUE_10,  0);
-	case 10:	tw32(MAC_RCV_RULE_9,  0);  tw32(MAC_RCV_VALUE_9,  0);
-	case 9:		tw32(MAC_RCV_RULE_8,  0);  tw32(MAC_RCV_VALUE_8,  0);
-	case 8:		tw32(MAC_RCV_RULE_7,  0);  tw32(MAC_RCV_VALUE_7,  0);
-	case 7:		tw32(MAC_RCV_RULE_6,  0);  tw32(MAC_RCV_VALUE_6,  0);
-	case 6:		tw32(MAC_RCV_RULE_5,  0);  tw32(MAC_RCV_VALUE_5,  0);
-	case 5:		tw32(MAC_RCV_RULE_4,  0);  tw32(MAC_RCV_VALUE_4,  0);
-	case 4:		/* tw32(MAC_RCV_RULE_3,  0); tw32(MAC_RCV_VALUE_3,  0); */
-	case 3:		/* tw32(MAC_RCV_RULE_2,  0); tw32(MAC_RCV_VALUE_2,  0); */
-	case 2:
-	case 1:
-	default:
-		break;
-	};
-
-	return err;
-}
-
-
-
-/* Chips other than 5700/5701 use the NVRAM for fetching info. */
-static void tg3_nvram_init(struct tg3 *tp)
-{
-	tw32(GRC_EEPROM_ADDR,
-	     (EEPROM_ADDR_FSM_RESET |
-	      (EEPROM_DEFAULT_CLOCK_PERIOD <<
-	       EEPROM_ADDR_CLKPERD_SHIFT)));
-
-	mdelay(1);
-
-	/* Enable seeprom accesses. */
-	tw32_carefully(GRC_LOCAL_CTRL,
-		tr32(GRC_LOCAL_CTRL) | GRC_LCLCTRL_AUTO_SEEPROM);
-
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
-	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {
-		uint32_t nvcfg1 = tr32(NVRAM_CFG1);
-
-		tp->tg3_flags |= TG3_FLAG_NVRAM;
-		if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) {
-			if (nvcfg1 & NVRAM_CFG1_BUFFERED_MODE)
-				tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
-		} else {
-			nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
-			tw32(NVRAM_CFG1, nvcfg1);
-		}
-
-	} else {
-		tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED);
-	}
-}
-
-
-static int tg3_nvram_read_using_eeprom(
-	struct tg3 *tp __unused, uint32_t offset, uint32_t *val)
-{
-	uint32_t tmp;
-	int i;
-
-	if (offset > EEPROM_ADDR_ADDR_MASK ||
-		(offset % 4) != 0) {
-		return -EINVAL;
-	}
-
-	tmp = tr32(GRC_EEPROM_ADDR) & ~(EEPROM_ADDR_ADDR_MASK |
-					EEPROM_ADDR_DEVID_MASK |
-					EEPROM_ADDR_READ);
-	tw32(GRC_EEPROM_ADDR,
-	     tmp |
-	     (0 << EEPROM_ADDR_DEVID_SHIFT) |
-	     ((offset << EEPROM_ADDR_ADDR_SHIFT) &
-	      EEPROM_ADDR_ADDR_MASK) |
-	     EEPROM_ADDR_READ | EEPROM_ADDR_START);
-
-	for (i = 0; i < 10000; i++) {
-		tmp = tr32(GRC_EEPROM_ADDR);
-
-		if (tmp & EEPROM_ADDR_COMPLETE)
-			break;
-		udelay(100);
-	}
-	if (!(tmp & EEPROM_ADDR_COMPLETE)) {
-		return -EBUSY;
-	}
-
-	*val = tr32(GRC_EEPROM_DATA);
-	return 0;
-}
-
-static int tg3_nvram_read(struct tg3 *tp, uint32_t offset, uint32_t *val)
-{
-	int i, saw_done_clear;
-
-	if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
-		return tg3_nvram_read_using_eeprom(tp, offset, val);
-
-	if (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED)
-		offset = ((offset / NVRAM_BUFFERED_PAGE_SIZE) <<
-			  NVRAM_BUFFERED_PAGE_POS) +
-			(offset % NVRAM_BUFFERED_PAGE_SIZE);
-
-	if (offset > NVRAM_ADDR_MSK)
-		return -EINVAL;
-
-	tw32(NVRAM_SWARB, SWARB_REQ_SET1);
-	for (i = 0; i < 1000; i++) {
-		if (tr32(NVRAM_SWARB) & SWARB_GNT1)
-			break;
-		udelay(20);
-	}
-
-	tw32(NVRAM_ADDR, offset);
-	tw32(NVRAM_CMD,
-	     NVRAM_CMD_RD | NVRAM_CMD_GO |
-	     NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
-
-	/* Wait for done bit to clear then set again. */
-	saw_done_clear = 0;
-	for (i = 0; i < 1000; i++) {
-		udelay(10);
-		if (!saw_done_clear &&
-		    !(tr32(NVRAM_CMD) & NVRAM_CMD_DONE))
-			saw_done_clear = 1;
-		else if (saw_done_clear &&
-			 (tr32(NVRAM_CMD) & NVRAM_CMD_DONE))
-			break;
-	}
-	if (i >= 1000) {
-		tw32(NVRAM_SWARB, SWARB_REQ_CLR1);
-		return -EBUSY;
-	}
-
-	*val = bswap_32(tr32(NVRAM_RDDATA));
-	tw32(NVRAM_SWARB, 0x20);
-
-	return 0;
-}
-
-struct subsys_tbl_ent {
-	uint16_t subsys_vendor, subsys_devid;
-	uint32_t phy_id;
-};
-
-static struct subsys_tbl_ent subsys_id_to_phy_id[] = {
-	/* Broadcom boards. */
-	{ 0x14e4, 0x1644, PHY_ID_BCM5401 }, /* BCM95700A6 */
-	{ 0x14e4, 0x0001, PHY_ID_BCM5701 }, /* BCM95701A5 */
-	{ 0x14e4, 0x0002, PHY_ID_BCM8002 }, /* BCM95700T6 */
-	{ 0x14e4, 0x0003, PHY_ID_SERDES  }, /* BCM95700A9 */
-	{ 0x14e4, 0x0005, PHY_ID_BCM5701 }, /* BCM95701T1 */
-	{ 0x14e4, 0x0006, PHY_ID_BCM5701 }, /* BCM95701T8 */
-	{ 0x14e4, 0x0007, PHY_ID_SERDES  }, /* BCM95701A7 */
-	{ 0x14e4, 0x0008, PHY_ID_BCM5701 }, /* BCM95701A10 */
-	{ 0x14e4, 0x8008, PHY_ID_BCM5701 }, /* BCM95701A12 */
-	{ 0x14e4, 0x0009, PHY_ID_BCM5701 }, /* BCM95703Ax1 */
-	{ 0x14e4, 0x8009, PHY_ID_BCM5701 }, /* BCM95703Ax2 */
-
-	/* 3com boards. */
-	{ PCI_VENDOR_ID_3COM, 0x1000, PHY_ID_BCM5401 }, /* 3C996T */
-	{ PCI_VENDOR_ID_3COM, 0x1006, PHY_ID_BCM5701 }, /* 3C996BT */
-	/* { PCI_VENDOR_ID_3COM, 0x1002, PHY_ID_XXX },     3C996CT */
-	/* { PCI_VENDOR_ID_3COM, 0x1003, PHY_ID_XXX },     3C997T */
-	{ PCI_VENDOR_ID_3COM, 0x1004, PHY_ID_SERDES  }, /* 3C996SX */
-	/* { PCI_VENDOR_ID_3COM, 0x1005, PHY_ID_XXX },     3C997SZ */
-	{ PCI_VENDOR_ID_3COM, 0x1007, PHY_ID_BCM5701 }, /* 3C1000T */
-	{ PCI_VENDOR_ID_3COM, 0x1008, PHY_ID_BCM5701 }, /* 3C940BR01 */
-
-	/* DELL boards. */
-	{ PCI_VENDOR_ID_DELL, 0x00d1, PHY_ID_BCM5401 }, /* VIPER */
-	{ PCI_VENDOR_ID_DELL, 0x0106, PHY_ID_BCM5401 }, /* JAGUAR */
-	{ PCI_VENDOR_ID_DELL, 0x0109, PHY_ID_BCM5411 }, /* MERLOT */
-	{ PCI_VENDOR_ID_DELL, 0x010a, PHY_ID_BCM5411 }, /* SLIM_MERLOT */
-	{ PCI_VENDOR_ID_DELL, 0x0179, PHY_ID_BCM5751 }, /* EtherXpress */
-	
-	/* Fujitsu Siemens Computer */
-	{ PCI_VENDOR_ID_FSC, 0x105d, PHY_ID_BCM5751 }, /* Futro C200 */	
-
-	/* Compaq boards. */
-	{ PCI_VENDOR_ID_COMPAQ, 0x007c, PHY_ID_BCM5701 }, /* BANSHEE */
-	{ PCI_VENDOR_ID_COMPAQ, 0x009a, PHY_ID_BCM5701 }, /* BANSHEE_2 */
-	{ PCI_VENDOR_ID_COMPAQ, 0x007d, PHY_ID_SERDES  }, /* CHANGELING */
-	{ PCI_VENDOR_ID_COMPAQ, 0x0085, PHY_ID_BCM5701 }, /* NC7780 */
-	{ PCI_VENDOR_ID_COMPAQ, 0x0099, PHY_ID_BCM5701 }  /* NC7780_2 */
-};
-
-static int tg3_phy_probe(struct tg3 *tp)
-{
-	uint32_t eeprom_phy_id, hw_phy_id_1, hw_phy_id_2;
-	uint32_t hw_phy_id, hw_phy_id_masked;
-	enum phy_led_mode eeprom_led_mode;
-	uint32_t val;
-	unsigned i;
-	int eeprom_signature_found, err;
-
-	tp->phy_id = PHY_ID_INVALID;
-
-	for (i = 0; i < sizeof(subsys_id_to_phy_id)/sizeof(subsys_id_to_phy_id[0]); i++) {
-		if ((subsys_id_to_phy_id[i].subsys_vendor == tp->subsystem_vendor) &&
-			(subsys_id_to_phy_id[i].subsys_devid == tp->subsystem_device)) {
-			tp->phy_id = subsys_id_to_phy_id[i].phy_id;
-			break;
-		}
-	}
-
-	eeprom_phy_id = PHY_ID_INVALID;
-	eeprom_led_mode = led_mode_auto;
-	eeprom_signature_found = 0;
-	tg3_read_mem(NIC_SRAM_DATA_SIG, &val);
-	if (val == NIC_SRAM_DATA_SIG_MAGIC) {
-		uint32_t nic_cfg;
-
-		tg3_read_mem(NIC_SRAM_DATA_CFG, &nic_cfg);
-		tp->nic_sram_data_cfg = nic_cfg;
-
-		eeprom_signature_found = 1;
-
-		if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) ==
-		    NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) {
-			eeprom_phy_id = PHY_ID_SERDES;
-		} else {
-			uint32_t nic_phy_id;
-
-			tg3_read_mem(NIC_SRAM_DATA_PHY_ID, &nic_phy_id);
-			if (nic_phy_id != 0) {
-				uint32_t id1 = nic_phy_id & NIC_SRAM_DATA_PHY_ID1_MASK;
-				uint32_t id2 = nic_phy_id & NIC_SRAM_DATA_PHY_ID2_MASK;
-
-				eeprom_phy_id  = (id1 >> 16) << 10;
-				eeprom_phy_id |= (id2 & 0xfc00) << 16;
-				eeprom_phy_id |= (id2 & 0x03ff) <<  0;
-			}
-		}
-
-		switch (nic_cfg & NIC_SRAM_DATA_CFG_LED_MODE_MASK) {
-		case NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD:
-			eeprom_led_mode = led_mode_three_link;
-			break;
-
-		case NIC_SRAM_DATA_CFG_LED_LINK_SPD:
-			eeprom_led_mode = led_mode_link10;
-			break;
-
-		default:
-			eeprom_led_mode = led_mode_auto;
-			break;
-		};
-		if (((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
-			(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
-			(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) &&
-			(nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP)) {
-			tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
-		}
-
-		if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE)
-			tp->tg3_flags |= TG3_FLAG_ENABLE_ASF;
-		if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)
-			tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP;
-	}
-
-	/* Now read the physical PHY_ID from the chip and verify
-	 * that it is sane.  If it doesn't look good, we fall back
-	 * to either the hard-coded table based PHY_ID and failing
-	 * that the value found in the eeprom area.
-	 */
-	err  = tg3_readphy(tp, MII_PHYSID1, &hw_phy_id_1);
-	err |= tg3_readphy(tp, MII_PHYSID2, &hw_phy_id_2);
-
-	hw_phy_id  = (hw_phy_id_1 & 0xffff) << 10;
-	hw_phy_id |= (hw_phy_id_2 & 0xfc00) << 16;
-	hw_phy_id |= (hw_phy_id_2 & 0x03ff) <<  0;
-
-	hw_phy_id_masked = hw_phy_id & PHY_ID_MASK;
-
-	if (!err && KNOWN_PHY_ID(hw_phy_id_masked)) {
-		tp->phy_id = hw_phy_id;
-	} else {
-		/* phy_id currently holds the value found in the
-		 * subsys_id_to_phy_id[] table or PHY_ID_INVALID
-		 * if a match was not found there.
-		 */
-		if (tp->phy_id == PHY_ID_INVALID) {
-			if (!eeprom_signature_found ||
-			    !KNOWN_PHY_ID(eeprom_phy_id & PHY_ID_MASK))
-				return -ENODEV;
-			tp->phy_id = eeprom_phy_id;
-		}
-	}
-
-	err = tg3_phy_reset(tp);
-	if (err)
-		return err;
-
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
-	    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
-		uint32_t mii_tg3_ctrl;
-		
-		/* These chips, when reset, only advertise 10Mb
-		 * capabilities.  Fix that.
-		 */
-		err  = tg3_writephy(tp, MII_ADVERTISE,
-				    (ADVERTISE_CSMA |
-				     ADVERTISE_PAUSE_CAP |
-				     ADVERTISE_10HALF |
-				     ADVERTISE_10FULL |
-				     ADVERTISE_100HALF |
-				     ADVERTISE_100FULL));
-		mii_tg3_ctrl = (MII_TG3_CTRL_ADV_1000_HALF |
-				MII_TG3_CTRL_ADV_1000_FULL |
-				MII_TG3_CTRL_AS_MASTER |
-				MII_TG3_CTRL_ENABLE_AS_MASTER);
-		if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
-			mii_tg3_ctrl = 0;
-
-		err |= tg3_writephy(tp, MII_TG3_CTRL, mii_tg3_ctrl);
-		err |= tg3_writephy(tp, MII_BMCR,
-				    (BMCR_ANRESTART | BMCR_ANENABLE));
-	}
-
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
-		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
-		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
-		tg3_writedsp(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
-	}
-
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
-		tg3_writephy(tp, 0x1c, 0x8d68);
-		tg3_writephy(tp, 0x1c, 0x8d68);
-	}
-
-	/* Enable Ethernet@WireSpeed */
-	tg3_phy_set_wirespeed(tp);
-
-	if (!err && ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)) {
-		err = tg3_init_5401phy_dsp(tp);
-	}
-
-	/* Determine the PHY led mode. 
-	 * Be careful if this gets set wrong it can result in an inability to 
-	 * establish a link.
-	 */
-	if (tp->phy_id == PHY_ID_SERDES) {
-		tp->led_mode = led_mode_three_link;
-	}
-	else if (tp->subsystem_vendor == PCI_VENDOR_ID_DELL) {
-		tp->led_mode = led_mode_link10;
-	} else {
-		tp->led_mode = led_mode_three_link;
-		if (eeprom_signature_found &&
-		    eeprom_led_mode != led_mode_auto)
-			tp->led_mode = eeprom_led_mode;
-	}
-
-	if (tp->phy_id == PHY_ID_SERDES)
-		tp->link_config.advertising =
-			(ADVERTISED_1000baseT_Half |
-			 ADVERTISED_1000baseT_Full |
-			 ADVERTISED_Autoneg |
-			 ADVERTISED_FIBRE);
-	if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
-		tp->link_config.advertising &=
-			~(ADVERTISED_1000baseT_Half |
-			  ADVERTISED_1000baseT_Full);
-
-	return err;
-}
-
-#if SUPPORT_PARTNO_STR
-static void tg3_read_partno(struct tg3 *tp)
-{
-	unsigned char vpd_data[256];
-	int i;
-
-	for (i = 0; i < 256; i += 4) {
-		uint32_t tmp;
-
-		if (tg3_nvram_read(tp, 0x100 + i, &tmp))
-			goto out_not_found;
-
-		vpd_data[i + 0] = ((tmp >>  0) & 0xff);
-		vpd_data[i + 1] = ((tmp >>  8) & 0xff);
-		vpd_data[i + 2] = ((tmp >> 16) & 0xff);
-		vpd_data[i + 3] = ((tmp >> 24) & 0xff);
-	}
-
-	/* Now parse and find the part number. */
-	for (i = 0; i < 256; ) {
-		unsigned char val = vpd_data[i];
-		int block_end;
-
-		if (val == 0x82 || val == 0x91) {
-			i = (i + 3 +
-			     (vpd_data[i + 1] +
-			      (vpd_data[i + 2] << 8)));
-			continue;
-		}
-
-		if (val != 0x90)
-			goto out_not_found;
-
-		block_end = (i + 3 +
-			     (vpd_data[i + 1] +
-			      (vpd_data[i + 2] << 8)));
-		i += 3;
-		while (i < block_end) {
-			if (vpd_data[i + 0] == 'P' &&
-			    vpd_data[i + 1] == 'N') {
-				int partno_len = vpd_data[i + 2];
-
-				if (partno_len > 24)
-					goto out_not_found;
-
-				memcpy(tp->board_part_number,
-				       &vpd_data[i + 3],
-				       partno_len);
-
-				/* Success. */
-				return;
-			}
-		}
-
-		/* Part number not found. */
-		goto out_not_found;
-	}
-
-out_not_found:
-	memcpy(tp->board_part_number, "none", sizeof("none"));
-}
-#else
-#define tg3_read_partno(TP) ((TP)->board_part_number[0] = '\0')
-#endif
-
-static int tg3_get_invariants(struct tg3 *tp)
-{
-	uint32_t misc_ctrl_reg;
-	uint32_t pci_state_reg, grc_misc_cfg;
-	uint16_t pci_cmd;
-	uint8_t  pci_latency;
-	uint32_t val ;
-	int err;
-
-	/* Read the subsystem vendor and device ids */
-	pci_read_config_word(tp->pdev, PCI_SUBSYSTEM_VENDOR_ID, &tp->subsystem_vendor);
-	pci_read_config_word(tp->pdev, PCI_SUBSYSTEM_ID, &tp->subsystem_device);
-
-	/* The sun_5704 code needs infrastructure etherboot does have
-	 * ignore it for now.
-	 */
-
-	/* If we have an AMD 762 or Intel ICH/ICH0 chipset, write
-	 * reordering to the mailbox registers done by the host
-	 * controller can cause major troubles.  We read back from
-	 * every mailbox register write to force the writes to be
-	 * posted to the chip in order.
-	 *
-	 * TG3_FLAG_MBOX_WRITE_REORDER has been forced on.
-	 */
-
-	/* Force memory write invalidate off.  If we leave it on,
-	 * then on 5700_BX chips we have to enable a workaround.
-	 * The workaround is to set the TG3PCI_DMA_RW_CTRL boundry
-	 * to match the cacheline size.  The Broadcom driver have this
-	 * workaround but turns MWI off all the times so never uses
-	 * it.  This seems to suggest that the workaround is insufficient.
-	 */
-	pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd);
-	pci_cmd &= ~PCI_COMMAND_INVALIDATE;
-	/* Also, force SERR#/PERR# in PCI command. */
-	pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
-	pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
-
-	/* It is absolutely critical that TG3PCI_MISC_HOST_CTRL
-	 * has the register indirect write enable bit set before
-	 * we try to access any of the MMIO registers.  It is also
-	 * critical that the PCI-X hw workaround situation is decided
-	 * before that as well.
-	 */
-	pci_read_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, &misc_ctrl_reg);
-
-	tp->pci_chip_rev_id = (misc_ctrl_reg >> MISC_HOST_CTRL_CHIPREV_SHIFT);
-
-	/* Initialize misc host control in PCI block. */
-	tp->misc_host_ctrl |= (misc_ctrl_reg &
-			       MISC_HOST_CTRL_CHIPREV);
-	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
-			       tp->misc_host_ctrl);
-
-	pci_read_config_byte(tp->pdev, PCI_LATENCY_TIMER, &pci_latency);
-	if (pci_latency < 64) {
-		pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER, 64);
-	}
-
-	pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &pci_state_reg);
-
-	/* If this is a 5700 BX chipset, and we are in PCI-X
-	 * mode, enable register write workaround.
-	 *
-	 * The workaround is to use indirect register accesses
-	 * for all chip writes not to mailbox registers.
-	 *
-	 * In etherboot to simplify things we just always use this work around.
-	 */
-	if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) {
-		tp->tg3_flags |= TG3_FLAG_PCIX_MODE;
-	}
-	/* Back to back register writes can cause problems on the 5701,
-	 * the workaround is to read back all reg writes except those to
-	 * mailbox regs.
-	 * In etherboot we always use indirect register accesses so
-	 * we don't see this.
-	 */
-
-	if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0)
-		tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED;
-	if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0)
-		tp->tg3_flags |= TG3_FLAG_PCI_32BIT;
-
-	/* Chip-specific fixup from Broadcom driver */
-	if ((tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) &&
-	    (!(pci_state_reg & PCISTATE_RETRY_SAME_DMA))) {
-		pci_state_reg |= PCISTATE_RETRY_SAME_DMA;
-		pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, pci_state_reg);
-	}
-
-	/* determine if it is PCIE system */
-	// Alf : I have no idea what this is about...
-	// But it's definitely usefull
-	val = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP);
-	if (val)
-		tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS;
-
-	/* Force the chip into D0. */
-	tg3_set_power_state_0(tp);
-
-	/* Etherboot does not ask the tg3 to do checksums */
-	/* Etherboot does not ask the tg3 to do jumbo frames */
-	/* Ehterboot does not ask the tg3 to use WakeOnLan. */
-
-	/* A few boards don't want Ethernet@WireSpeed phy feature */
-	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) ||
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) ||
-		((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
-			(tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) &&
-			(tp->pci_chip_rev_id != CHIPREV_ID_5705_A1))) {
-		tp->tg3_flags2 |= TG3_FLG2_NO_ETH_WIRE_SPEED;
-	}
-
-	/* Avoid tagged irq status etherboot does not use irqs */
-
-	/* Only 5701 and later support tagged irq status mode.
-	 * Also, 5788 chips cannot use tagged irq status.
-	 *
-	 * However, since etherboot does not use irqs avoid tagged irqs
-	 * status  because the interrupt condition is more difficult to
-	 * fully clear in that mode.
-	 */
-	
-	/* Since some 5700_AX && 5700_BX have problems with 32BYTE
-	 * coalesce_mode, and the rest work fine anything set.
-	 * Don't enable HOST_CC_MODE_32BYTE in etherboot.
-	 */
-
-	/* Initialize MAC MI mode, polling disabled. */
-	tw32_carefully(MAC_MI_MODE, tp->mi_mode);
-
-	/* Initialize data/descriptor byte/word swapping. */
-	tw32(GRC_MODE, tp->grc_mode);
-
-	tg3_switch_clocks(tp);
-
-	/* Clear this out for sanity. */
-	tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
-
-	/* Etherboot does not need to check if the PCIX_TARGET_HWBUG
-	 * is needed.  It always uses it.
-	 */
-	
-	udelay(50);
-	tg3_nvram_init(tp);
-
-	/* The TX descriptors will reside in main memory.
-	 */
-
-	/* See which board we are using.
-	 */
-	grc_misc_cfg = tr32(GRC_MISC_CFG);
-	grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
-
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
-	    grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5704CIOBE) {
-		tp->tg3_flags |= TG3_FLAG_SPLIT_MODE;
-		tp->split_mode_max_reqs = SPLIT_MODE_5704_MAX_REQ;
-	}
-
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
-	    (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 ||
-	     grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M))
-		tp->tg3_flags2 |= TG3_FLG2_IS_5788;
-
-#define PCI_DEVICE_ID_TIGON3_5901	0x170d
-#define PCI_DEVICE_ID_TIGON3_5901_2	0x170e
-
-	/* these are limited to 10/100 only */
-	if (((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) &&
-		    ((grc_misc_cfg == 0x8000) || (grc_misc_cfg == 0x4000))) ||
-		((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
-			(tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM) &&
-			((tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901) ||
-				(tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901_2)))) {
-		tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
-	}
-
-	err = tg3_phy_probe(tp);
-	if (err) {
-		printf("phy probe failed, err %d\n", err);
-	}
-
-	tg3_read_partno(tp);
-
-
-	/* 5700 BX chips need to have their TX producer index mailboxes
-	 * written twice to workaround a bug.
-	 * In etherboot we do this unconditionally to simplify things.
-	 */
-
-	/* 5700 chips can get confused if TX buffers straddle the
-	 * 4GB address boundary in some cases.
-	 * 
-	 * In etherboot we can ignore the problem as etherboot lives below 4GB.
-	 */
-
-	/* In etherboot wake-on-lan is unconditionally disabled */
-	return err;
-}
-
-static int  tg3_get_device_address(struct tg3 *tp)
-{
-	struct nic *nic = tp->nic;
-	uint32_t hi, lo, mac_offset;
-
-	if (PCI_FUNC(tp->pdev->busdevfn) == 0)
-		mac_offset = 0x7c;
-	else
-		mac_offset = 0xcc;
-
-	/* First try to get it from MAC address mailbox. */
-	tg3_read_mem(NIC_SRAM_MAC_ADDR_HIGH_MBOX, &hi);
-	if ((hi >> 16) == 0x484b) {
-		nic->node_addr[0] = (hi >>  8) & 0xff;
-		nic->node_addr[1] = (hi >>  0) & 0xff;
-
-		tg3_read_mem(NIC_SRAM_MAC_ADDR_LOW_MBOX, &lo);
-		nic->node_addr[2] = (lo >> 24) & 0xff;
-		nic->node_addr[3] = (lo >> 16) & 0xff;
-		nic->node_addr[4] = (lo >>  8) & 0xff;
-		nic->node_addr[5] = (lo >>  0) & 0xff;
-	}
-	/* Next, try NVRAM. */
-	else if (!tg3_nvram_read(tp, mac_offset + 0, &hi) &&
-		 !tg3_nvram_read(tp, mac_offset + 4, &lo)) {
-		nic->node_addr[0] = ((hi >> 16) & 0xff);
-		nic->node_addr[1] = ((hi >> 24) & 0xff);
-		nic->node_addr[2] = ((lo >>  0) & 0xff);
-		nic->node_addr[3] = ((lo >>  8) & 0xff);
-		nic->node_addr[4] = ((lo >> 16) & 0xff);
-		nic->node_addr[5] = ((lo >> 24) & 0xff);
-	}
-	/* Finally just fetch it out of the MAC control regs. */
-	else {
-		hi = tr32(MAC_ADDR_0_HIGH);
-		lo = tr32(MAC_ADDR_0_LOW);
-
-		nic->node_addr[5] = lo & 0xff;
-		nic->node_addr[4] = (lo >> 8) & 0xff;
-		nic->node_addr[3] = (lo >> 16) & 0xff;
-		nic->node_addr[2] = (lo >> 24) & 0xff;
-		nic->node_addr[1] = hi & 0xff;
-		nic->node_addr[0] = (hi >> 8) & 0xff;
-	}
-
-	return 0;
-}
-
-
-static int tg3_setup_dma(struct tg3 *tp)
-{
-	tw32(TG3PCI_CLOCK_CTRL, 0);
-
-	if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) == 0) {
-		tp->dma_rwctrl =
-			(0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
-			(0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
-			(0x7 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
-			(0x7 << DMA_RWCTRL_READ_WATER_SHIFT) |
-			(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
-			tp->dma_rwctrl &= ~(DMA_RWCTRL_MIN_DMA << DMA_RWCTRL_MIN_DMA_SHIFT);
-		}
-	} else {
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
-			tp->dma_rwctrl =
-				(0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
-				(0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
-				(0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
-				(0x7 << DMA_RWCTRL_READ_WATER_SHIFT) |
-				(0x00 << DMA_RWCTRL_MIN_DMA_SHIFT);
-		else
-			tp->dma_rwctrl =
-				(0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
-				(0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
-				(0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
-				(0x3 << DMA_RWCTRL_READ_WATER_SHIFT) |
-				(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
-
-		/* Wheee, some more chip bugs... */
-		if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
-			(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)) {
-			uint32_t ccval = tr32(TG3PCI_CLOCK_CTRL) & 0x1f;
-
-			if ((ccval == 0x6) || (ccval == 0x7)) {
-				tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
-			}
-		}
-	}
-
-	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
-		(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)) {
-		tp->dma_rwctrl &= ~(DMA_RWCTRL_MIN_DMA << DMA_RWCTRL_MIN_DMA_SHIFT);
-	}
-
-	/*
-	  Alf : Tried that, but it does not work. Should be this way though :-(
-	if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
-    	  tp->dma_rwctrl |= 0x001f0000;
-	}
-	*/
-	tp->dma_rwctrl |= DMA_RWCTRL_ASSERT_ALL_BE;
-
-	tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
-
-	return 0;
-}
-
-static void tg3_init_link_config(struct tg3 *tp)
-{
-	tp->link_config.advertising =
-		(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
-		 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
-		 ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full |
-		 ADVERTISED_Autoneg | ADVERTISED_MII);
-	tp->carrier_ok = 0;
-	tp->link_config.active_speed = SPEED_INVALID;
-	tp->link_config.active_duplex = DUPLEX_INVALID;
-}
-
-
-#if SUPPORT_PHY_STR
-static const char * tg3_phy_string(struct tg3 *tp)
-{
-	switch (tp->phy_id & PHY_ID_MASK) {
-	case PHY_ID_BCM5400:	return "5400";
-	case PHY_ID_BCM5401:	return "5401";
-	case PHY_ID_BCM5411:	return "5411";
-	case PHY_ID_BCM5701:	return "5701";
-	case PHY_ID_BCM5703:	return "5703";
-	case PHY_ID_BCM5704:	return "5704";
-        case PHY_ID_BCM5705:    return "5705";
-        case PHY_ID_BCM5750:    return "5750";
-	case PHY_ID_BCM5751:	return "5751"; 
-	case PHY_ID_BCM5787:	return "5787";
-	case PHY_ID_BCM8002:	return "8002/serdes";
-	case PHY_ID_SERDES:	return "serdes";
-	default:		return "unknown";
-	};
-}
-#else
-#define tg3_phy_string(TP) "?"
-#endif
-
-
-static void tg3_poll_link(struct tg3 *tp)
-{
-	uint32_t mac_stat;
-
-	mac_stat = tr32(MAC_STATUS);
-	if (tp->phy_id == PHY_ID_SERDES) {
-		if (tp->carrier_ok?
-			(mac_stat & MAC_STATUS_LNKSTATE_CHANGED):
-			(mac_stat & MAC_STATUS_PCS_SYNCED)) {
-			tw32_carefully(MAC_MODE, tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK);
-			tw32_carefully(MAC_MODE, tp->mac_mode);
-
-			tg3_setup_phy(tp);
-		}
-	}
-	else {
-		if (mac_stat & MAC_STATUS_LNKSTATE_CHANGED) {
-			tg3_setup_phy(tp);
-		}
-	}
-}
-
-/**************************************************************************
-POLL - Wait for a frame
-***************************************************************************/
-static void tg3_ack_irqs(struct tg3 *tp)
-{
-	if (tp->hw_status->status & SD_STATUS_UPDATED) {
-		/*
-		 * writing any value to intr-mbox-0 clears PCI INTA# and
-		 * chip-internal interrupt pending events.
-		 * writing non-zero to intr-mbox-0 additional tells the
-		 * NIC to stop sending us irqs, engaging "in-intr-handler"
-		 * event coalescing.
-		 */
-		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 
-			0x00000001);
-		/*
-		 * Flush PCI write.  This also guarantees that our
-		 * status block has been flushed to host memory.
-		 */
-		tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
-		tp->hw_status->status &= ~SD_STATUS_UPDATED;
-	}
-}
-
-static int tg3_poll(struct nic *nic, int retrieve)
-{
-	/* return true if there's an ethernet packet ready to read */
-	/* nic->packet should contain data on return */
-	/* nic->packetlen should contain length of data */
-
-	struct tg3 *tp = &tg3;
-	int result;
-
-	result = 0;
-
-	if ( (tp->hw_status->idx[0].rx_producer != tp->rx_rcb_ptr) && !retrieve ) 
-	  return 1;
-
-	tg3_ack_irqs(tp);
-
-	if (tp->hw_status->idx[0].rx_producer != tp->rx_rcb_ptr) {
-		struct tg3_rx_buffer_desc *desc;
-		unsigned int len;
-		desc = &tp->rx_rcb[tp->rx_rcb_ptr];
-		if ((desc->opaque & RXD_OPAQUE_RING_MASK) == RXD_OPAQUE_RING_STD) {
-			len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */
-			
-			nic->packetlen = len;
-			memcpy(nic->packet, bus_to_virt(desc->addr_lo), len);
-			result = 1;
-		}
-		tp->rx_rcb_ptr = (tp->rx_rcb_ptr + 1) % TG3_RX_RCB_RING_SIZE;
-		
-		/* ACK the status ring */
-		tw32_mailbox2(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, tp->rx_rcb_ptr);
-
-		/* Refill RX ring. */
-		if (result) {
-			tp->rx_std_ptr = (tp->rx_std_ptr + 1) % TG3_RX_RING_SIZE;
-			tw32_mailbox2(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, tp->rx_std_ptr);
-		}
-	}
-	tg3_poll_link(tp);
-	return result;
-}
-
-/**************************************************************************
-TRANSMIT - Transmit a frame
-***************************************************************************/
-#if 0
-static void tg3_set_txd(struct tg3 *tp, int entry,
-	dma_addr_t mapping, int len, uint32_t flags,
-	uint32_t mss_and_is_end)
-{
-	struct tg3_tx_buffer_desc *txd =  &tp->tx_ring[entry];
-	int is_end = (mss_and_is_end & 0x1);
-	if (is_end) {
-		flags |= TXD_FLAG_END;
-	}
-
-	txd->addr_hi   = 0;
-	txd->addr_lo   = mapping & 0xffffffff;
-	txd->len_flags = (len << TXD_LEN_SHIFT) | flags;
-	txd->vlan_tag  = 0 << TXD_VLAN_TAG_SHIFT;
-}
-#endif
-
-static void tg3_transmit(struct nic *nic, const char *dst_addr,
-	unsigned int type, unsigned int size, const char *packet)
-{
-	static int frame_idx;
-	struct eth_frame *frame;
-	
-	/* send the packet to destination */
-	struct tg3_tx_buffer_desc *txd;
-	struct tg3 *tp;
-	uint32_t entry;
-	int i;
-
-	/* Wait until there is a free packet frame */
-	tp = &tg3;
-	i = 0;
-	entry = tp->tx_prod;
-	while((tp->hw_status->idx[0].tx_consumer != entry) &&
-		(tp->hw_status->idx[0].tx_consumer != PREV_TX(entry))) {
-		mdelay(10);	/* give the nick a chance */
-		if (++i > 500) { /* timeout 5s for transmit */
-			printf("transmit timed out\n");
-			tg3_halt(tp);
-			tg3_setup_hw(tp);
-			return;
-		}
-	}
-	if (i != 0) {
-		printf("#");
-	}
-	
-	/* Copy the packet to the our local buffer */
-	frame = &tg3_bss.tx_frame[frame_idx];
-	memcpy(frame->dst_addr, dst_addr, ETH_ALEN);
-	memcpy(frame->src_addr, nic->node_addr, ETH_ALEN);
-	frame->type = htons(type);
-	memset(frame->data, 0, sizeof(frame->data));
-	memcpy(frame->data, packet, size);
-
-	/* Setup the ring buffer entry to transmit */
-	txd            = &tp->tx_ring[entry];
-	txd->addr_hi   = 0; /* Etherboot runs under 4GB */
-	txd->addr_lo   = virt_to_bus(frame);
-	txd->len_flags = ((size + ETH_HLEN) << TXD_LEN_SHIFT) | TXD_FLAG_END;
-	txd->vlan_tag  = 0 << TXD_VLAN_TAG_SHIFT;
-
-	/* Advance to the next entry */
-	entry = NEXT_TX(entry);
-	frame_idx ^= 1;
-
-	/* Packets are ready, update Tx producer idx local and on card */
-	tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
-	tw32_mailbox2((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
-	tp->tx_prod = entry;
-}
-
-/**************************************************************************
-DISABLE - Turn off ethernet interface
-***************************************************************************/
-static void tg3_disable ( struct nic *nic __unused ) {
-	struct tg3 *tp = &tg3;
-	/* put the card in its initial state */
-	/* This function serves 3 purposes.
-	 * This disables DMA and interrupts so we don't receive
-	 *  unexpected packets or interrupts from the card after
-	 *  etherboot has finished. 
-	 * This frees resources so etherboot may use
-	 *  this driver on another interface
-	 * This allows etherboot to reinitialize the interface
-	 *  if something is something goes wrong.
-	 */
-	tg3_halt(tp);
-	tp->tg3_flags &= ~(TG3_FLAG_INIT_COMPLETE|TG3_FLAG_GOT_SERDES_FLOWCTL);
-	tp->carrier_ok = 0;
-	iounmap((void *)tp->regs);
-}
-
-/**************************************************************************
-IRQ - Enable, Disable, or Force interrupts
-***************************************************************************/
-static void tg3_irq(struct nic *nic __unused, irq_action_t action __unused)
-{
-  switch ( action ) {
-  case DISABLE :
-    break;
-  case ENABLE :
-    break;
-  case FORCE :
-    break;
-  }
-}
-
-static struct nic_operations tg3_operations = {
-	.connect	= dummy_connect,
-	.poll		= tg3_poll,
-	.transmit	= tg3_transmit,
-	.irq		= tg3_irq,
-
-};
-
-/**************************************************************************
-PROBE - Look for an adapter, this routine's visible to the outside
-You should omit the last argument struct pci_device * for a non-PCI NIC
-***************************************************************************/
-static int tg3_probe ( struct nic *nic, struct pci_device *pdev ) {
-
-	struct tg3 *tp = &tg3;
-	unsigned long tg3reg_base, tg3reg_len;
-	int i, err, pm_cap;
-
-	memset(tp, 0, sizeof(*tp));
-
-	adjust_pci_device(pdev);
-
-	nic->irqno  = 0;
-        nic->ioaddr = pdev->ioaddr;
-
-	/* Find power-management capability. */
-	pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
-	if (pm_cap == 0) {
-		printf("Cannot find PowerManagement capability, aborting.\n");
-		return 0;
-	}
-	tg3reg_base = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
-	if (tg3reg_base == -1UL) {
-		printf("Unuseable bar\n");
-		return 0;
-	}
-	tg3reg_len  = pci_bar_size(pdev,  PCI_BASE_ADDRESS_0);
-
-	tp->pdev       = pdev;
-	tp->nic        = nic;
-	tp->pm_cap     = pm_cap;
-	tp->rx_mode    = 0;
-	tp->tx_mode    = 0;
-	tp->mi_mode    = MAC_MI_MODE_BASE;
-	tp->tg3_flags  = 0 & ~TG3_FLAG_INIT_COMPLETE; 
-	
-	/* The word/byte swap controls here control register access byte
-	 * swapping.  DMA data byte swapping is controlled in the GRC_MODE
-	 * setting below.
-	 */
-	tp->misc_host_ctrl =
-		MISC_HOST_CTRL_MASK_PCI_INT |
-		MISC_HOST_CTRL_WORD_SWAP |
-		MISC_HOST_CTRL_INDIR_ACCESS |
-		MISC_HOST_CTRL_PCISTATE_RW;
-
-	/* The NONFRM (non-frame) byte/word swap controls take effect
-	 * on descriptor entries, anything which isn't packet data.
-	 *
-	 * The StrongARM chips on the board (one for tx, one for rx)
-	 * are running in big-endian mode.
-	 */
-	tp->grc_mode = (GRC_MODE_WSWAP_DATA | GRC_MODE_BSWAP_DATA |
-			GRC_MODE_WSWAP_NONFRM_DATA);
-#if __BYTE_ORDER == __BIG_ENDIAN
-	tp->grc_mode |= GRC_MODE_BSWAP_NONFRM_DATA;
-#endif
-	tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len);
-	if (tp->regs == 0UL) {
-		printf("Cannot map device registers, aborting\n");
-		return 0;
-	}
-
-	tg3_init_link_config(tp);
-
-	err = tg3_get_invariants(tp);
-	if (err) {
-		printf("Problem fetching invariants of chip, aborting.\n");
-		goto err_out_iounmap;
-	}
-
-	err = tg3_get_device_address(tp);
-	if (err) {
-		printf("Could not obtain valid ethernet address, aborting.\n");
-		goto err_out_iounmap;
-	}
-
-	DBG ( "Ethernet addr: %s\n", eth_ntoa ( nic->node_addr ) );
-
-	tg3_setup_dma(tp);
-
-	/* Now that we have fully setup the chip, save away a snapshot
-	 * of the PCI config space.  We need to restore this after
-	 * GRC_MISC_CFG core clock resets and some resume events.
-	 */
-	pci_save_state(tp->pdev, tp->pci_cfg_state);
-
-	printf("Tigon3 [partno(%s) rev %hx PHY(%s)] (PCI%s:%s:%s)\n",
-		tp->board_part_number,
-		tp->pci_chip_rev_id,
-		tg3_phy_string(tp),
-		((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "X" : ""),
-		((tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED) ?
-			((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "133MHz" : "66MHz") :
-			((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "100MHz" : "33MHz")),
-		((tp->tg3_flags & TG3_FLAG_PCI_32BIT) ? "32-bit" : "64-bit"));
-
-
-	err = tg3_setup_hw(tp); 
-	if (err) {
-		goto err_out_disable;
-	} 
-	tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
-
-	/* Wait for a reasonable time for the link to come up */
-	tg3_poll_link(tp);
-	for(i = 0; !tp->carrier_ok && (i < VALID_LINK_TIMEOUT*100); i++) {
-		mdelay(1);
-		tg3_poll_link(tp);
-	}
-	if (!tp->carrier_ok){
-		printf("Valid link not established\n");
-		goto err_out_disable;
-	}
-
-	nic->nic_op	= &tg3_operations;
-	return 1;
-
- err_out_iounmap:
-	iounmap((void *)tp->regs);
-	return 0;
- err_out_disable:
-	tg3_disable(nic);
-	return 0;
-}
-
-
-static struct pci_device_id tg3_nics[] = {
-PCI_ROM(0x14e4, 0x1644, "tg3-5700",        "Broadcom Tigon 3 5700", 0),
-PCI_ROM(0x14e4, 0x1645, "tg3-5701",        "Broadcom Tigon 3 5701", 0),
-PCI_ROM(0x14e4, 0x1646, "tg3-5702",        "Broadcom Tigon 3 5702", 0),
-PCI_ROM(0x14e4, 0x1647, "tg3-5703",        "Broadcom Tigon 3 5703", 0),
-PCI_ROM(0x14e4, 0x1648, "tg3-5704",        "Broadcom Tigon 3 5704", 0),
-PCI_ROM(0x14e4, 0x164d, "tg3-5702FE",      "Broadcom Tigon 3 5702FE", 0),
-PCI_ROM(0x14e4, 0x1653, "tg3-5705",        "Broadcom Tigon 3 5705", 0),
-PCI_ROM(0x14e4, 0x1654, "tg3-5705_2",      "Broadcom Tigon 3 5705_2", 0),
-PCI_ROM(0x14e4, 0x1659, "tg3-5721",        "Broadcom Tigon 3 5721", 0),
-PCI_ROM(0x14e4, 0x165d, "tg3-5705M",       "Broadcom Tigon 3 5705M", 0),
-PCI_ROM(0x14e4, 0x165e, "tg3-5705M_2",     "Broadcom Tigon 3 5705M_2", 0),
-PCI_ROM(0x14e4, 0x1677, "tg3-5751",        "Broadcom Tigon 3 5751", 0),
-PCI_ROM(0x14e4, 0x167a, "tg3-5754",        "Broadcom Tigon 3 5754", 0),
-PCI_ROM(0x14e4, 0x1693, "tg3-5787",	   "Broadcom Tigon 3 5787", 0),
-PCI_ROM(0x14e4, 0x1696, "tg3-5782",        "Broadcom Tigon 3 5782", 0),
-PCI_ROM(0x14e4, 0x169a, "tg3-5786",        "Broadcom Tigon 3 5786", 0),
-PCI_ROM(0x14e4, 0x169c, "tg3-5788",        "Broadcom Tigon 3 5788", 0),
-PCI_ROM(0x14e4, 0x169d, "tg3-5789",        "Broadcom Tigon 3 5789", 0),
-PCI_ROM(0x14e4, 0x16a6, "tg3-5702X",       "Broadcom Tigon 3 5702X", 0),
-PCI_ROM(0x14e4, 0x16a7, "tg3-5703X",       "Broadcom Tigon 3 5703X", 0),
-PCI_ROM(0x14e4, 0x16a8, "tg3-5704S",       "Broadcom Tigon 3 5704S", 0),
-PCI_ROM(0x14e4, 0x16c6, "tg3-5702A3",      "Broadcom Tigon 3 5702A3", 0),
-PCI_ROM(0x14e4, 0x16c7, "tg3-5703A3",      "Broadcom Tigon 3 5703A3", 0),
-PCI_ROM(0x14e4, 0x170d, "tg3-5901",        "Broadcom Tigon 3 5901", 0),
-PCI_ROM(0x14e4, 0x170e, "tg3-5901_2",      "Broadcom Tigon 3 5901_2", 0),
-PCI_ROM(0x1148, 0x4400, "tg3-9DXX",        "Syskonnect 9DXX", 0),
-PCI_ROM(0x1148, 0x4500, "tg3-9MXX",        "Syskonnect 9MXX", 0),
-PCI_ROM(0x173b, 0x03e8, "tg3-ac1000",      "Altima AC1000", 0),
-PCI_ROM(0x173b, 0x03e9, "tg3-ac1001",      "Altima AC1001", 0),
-PCI_ROM(0x173b, 0x03ea, "tg3-ac9100",      "Altima AC9100", 0),
-PCI_ROM(0x173b, 0x03eb, "tg3-ac1003",      "Altima AC1003", 0),
-PCI_ROM(0x0e11, 0x00ca, "tg3-hp",	   "HP Tigon 3", 0),
-};
-
-PCI_DRIVER ( tg3_driver, tg3_nics, PCI_NO_CLASS );
-
-DRIVER ( "TG3", nic_driver, pci_driver, tg3_driver,
-	 tg3_probe, tg3_disable );
-
-/*
- * Local variables:
- *  c-basic-offset: 8
- *  c-indent-level: 8
- *  tab-width: 8
- * End:
- */
diff --git a/roms/ipxe/src/drivers/net/tg3.h b/roms/ipxe/src/drivers/net/tg3.h
deleted file mode 100644
index deeb0adde1c539d44d53419a4591a0e9d93ec720..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/drivers/net/tg3.h
+++ /dev/null
@@ -1,2121 +0,0 @@
-/* $Id$
- * tg3.h: Definitions for Broadcom Tigon3 ethernet driver.
- *
- * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
- * Copyright (C) 2001 Jeff Garzik (jgarzik@mandrakesoft.com)
- */
-
-FILE_LICENCE ( GPL2_ONLY );
-
-#ifndef _T3_H
-#define _T3_H
-
-#include "stdint.h"
-
-typedef unsigned long dma_addr_t;
-
-/* From mii.h */
-
-/* Indicates what features are advertised by the interface. */
-#define ADVERTISED_10baseT_Half		(1 << 0)
-#define ADVERTISED_10baseT_Full		(1 << 1)
-#define ADVERTISED_100baseT_Half	(1 << 2)
-#define ADVERTISED_100baseT_Full	(1 << 3)
-#define ADVERTISED_1000baseT_Half	(1 << 4)
-#define ADVERTISED_1000baseT_Full	(1 << 5)
-#define ADVERTISED_Autoneg		(1 << 6)
-#define ADVERTISED_TP			(1 << 7)
-#define ADVERTISED_AUI			(1 << 8)
-#define ADVERTISED_MII			(1 << 9)
-#define ADVERTISED_FIBRE		(1 << 10)
-#define ADVERTISED_BNC			(1 << 11)
-
-/* The following are all involved in forcing a particular link
- * mode for the device for setting things.  When getting the
- * devices settings, these indicate the current mode and whether
- * it was foced up into this mode or autonegotiated.
- */
-
-/* The forced speed, 10Mb, 100Mb, gigabit. */
-#define SPEED_10		0
-#define SPEED_100		1
-#define SPEED_1000		2
-#define SPEED_INVALID           3
-
-
-/* Duplex, half or full. */
-#define DUPLEX_HALF		0x00
-#define DUPLEX_FULL		0x01
-#define DUPLEX_INVALID          0x02
-
-/* Which connector port. */
-#define PORT_TP			0x00
-#define PORT_AUI		0x01
-#define PORT_MII		0x02
-#define PORT_FIBRE		0x03
-#define PORT_BNC		0x04
-
-/* Which tranceiver to use. */
-#define XCVR_INTERNAL		0x00
-#define XCVR_EXTERNAL		0x01
-#define XCVR_DUMMY1		0x02
-#define XCVR_DUMMY2		0x03
-#define XCVR_DUMMY3		0x04
-
-/* Enable or disable autonegotiation.  If this is set to enable,
- * the forced link modes above are completely ignored.
- */
-#define AUTONEG_DISABLE		0x00
-#define AUTONEG_ENABLE		0x01
-
-/* Wake-On-Lan options. */
-#define WAKE_PHY		(1 << 0)
-#define WAKE_UCAST		(1 << 1)
-#define WAKE_MCAST		(1 << 2)
-#define WAKE_BCAST		(1 << 3)
-#define WAKE_ARP		(1 << 4)
-#define WAKE_MAGIC		(1 << 5)
-#define WAKE_MAGICSECURE	(1 << 6) /* only meaningful if WAKE_MAGIC */
-
-/* From tg3.h */
-
-#define TG3_64BIT_REG_HIGH		0x00UL
-#define TG3_64BIT_REG_LOW		0x04UL
-
-/* Descriptor block info. */
-#define TG3_BDINFO_HOST_ADDR		0x0UL /* 64-bit */
-#define TG3_BDINFO_MAXLEN_FLAGS		0x8UL /* 32-bit */
-#define  BDINFO_FLAGS_USE_EXT_RECV	 0x00000001 /* ext rx_buffer_desc */
-#define  BDINFO_FLAGS_DISABLED		 0x00000002
-#define  BDINFO_FLAGS_MAXLEN_MASK	 0xffff0000
-#define  BDINFO_FLAGS_MAXLEN_SHIFT	 16
-#define TG3_BDINFO_NIC_ADDR		0xcUL /* 32-bit */
-#define TG3_BDINFO_SIZE			0x10UL
-
-#define RX_COPY_THRESHOLD  		256
-
-#define RX_STD_MAX_SIZE			1536
-#define RX_STD_MAX_SIZE_5705		512
-#define RX_JUMBO_MAX_SIZE		0xdeadbeef /* XXX */
-
-/* First 256 bytes are a mirror of PCI config space. */
-#define TG3PCI_VENDOR			0x00000000
-#define  TG3PCI_VENDOR_BROADCOM		 0x14e4
-#define TG3PCI_DEVICE			0x00000002
-#define  TG3PCI_DEVICE_TIGON3_1		 0x1644 /* BCM5700 */
-#define  TG3PCI_DEVICE_TIGON3_2		 0x1645 /* BCM5701 */
-#define  TG3PCI_DEVICE_TIGON3_3		 0x1646 /* BCM5702 */
-#define  TG3PCI_DEVICE_TIGON3_4		 0x1647 /* BCM5703 */
-#define TG3PCI_COMMAND			0x00000004
-#define TG3PCI_STATUS			0x00000006
-#define TG3PCI_CCREVID			0x00000008
-#define TG3PCI_CACHELINESZ		0x0000000c
-#define TG3PCI_LATTIMER			0x0000000d
-#define TG3PCI_HEADERTYPE		0x0000000e
-#define TG3PCI_BIST			0x0000000f
-#define TG3PCI_BASE0_LOW		0x00000010
-#define TG3PCI_BASE0_HIGH		0x00000014
-/* 0x18 --> 0x2c unused */
-#define TG3PCI_SUBSYSVENID		0x0000002c
-#define TG3PCI_SUBSYSID			0x0000002e
-#define TG3PCI_ROMADDR			0x00000030
-#define TG3PCI_CAPLIST			0x00000034
-/* 0x35 --> 0x3c unused */
-#define TG3PCI_IRQ_LINE			0x0000003c
-#define TG3PCI_IRQ_PIN			0x0000003d
-#define TG3PCI_MIN_GNT			0x0000003e
-#define TG3PCI_MAX_LAT			0x0000003f
-#define TG3PCI_X_CAPS			0x00000040
-#define  PCIX_CAPS_RELAXED_ORDERING	 0x00020000
-#define  PCIX_CAPS_SPLIT_MASK		 0x00700000
-#define  PCIX_CAPS_SPLIT_SHIFT		 20
-#define  PCIX_CAPS_BURST_MASK		 0x000c0000
-#define  PCIX_CAPS_BURST_SHIFT		 18
-#define  PCIX_CAPS_MAX_BURST_CPIOB	 2
-#define TG3PCI_PM_CAP_PTR		0x00000041
-#define TG3PCI_X_COMMAND		0x00000042
-#define TG3PCI_X_STATUS			0x00000044
-#define TG3PCI_PM_CAP_ID		0x00000048
-#define TG3PCI_VPD_CAP_PTR		0x00000049
-#define TG3PCI_PM_CAPS			0x0000004a
-#define TG3PCI_PM_CTRL_STAT		0x0000004c
-#define TG3PCI_BR_SUPP_EXT		0x0000004e
-#define TG3PCI_PM_DATA			0x0000004f
-#define TG3PCI_VPD_CAP_ID		0x00000050
-#define TG3PCI_MSI_CAP_PTR		0x00000051
-#define TG3PCI_VPD_ADDR_FLAG		0x00000052
-#define  VPD_ADDR_FLAG_WRITE		0x00008000
-#define TG3PCI_VPD_DATA			0x00000054
-#define TG3PCI_MSI_CAP_ID		0x00000058
-#define TG3PCI_NXT_CAP_PTR		0x00000059
-#define TG3PCI_MSI_CTRL			0x0000005a
-#define TG3PCI_MSI_ADDR_LOW		0x0000005c
-#define TG3PCI_MSI_ADDR_HIGH		0x00000060
-#define TG3PCI_MSI_DATA			0x00000064
-/* 0x66 --> 0x68 unused */
-#define TG3PCI_MISC_HOST_CTRL		0x00000068
-#define  MISC_HOST_CTRL_CLEAR_INT	 0x00000001
-#define  MISC_HOST_CTRL_MASK_PCI_INT	 0x00000002
-#define  MISC_HOST_CTRL_BYTE_SWAP	 0x00000004
-#define  MISC_HOST_CTRL_WORD_SWAP	 0x00000008
-#define  MISC_HOST_CTRL_PCISTATE_RW	 0x00000010
-#define  MISC_HOST_CTRL_CLKREG_RW	 0x00000020
-#define  MISC_HOST_CTRL_REGWORD_SWAP	 0x00000040
-#define  MISC_HOST_CTRL_INDIR_ACCESS	 0x00000080
-#define  MISC_HOST_CTRL_IRQ_MASK_MODE	 0x00000100
-#define  MISC_HOST_CTRL_TAGGED_STATUS	 0x00000200
-#define  MISC_HOST_CTRL_CHIPREV		 0xffff0000
-#define  MISC_HOST_CTRL_CHIPREV_SHIFT	 16
-#define  GET_CHIP_REV_ID(MISC_HOST_CTRL) \
-	 (((MISC_HOST_CTRL) & MISC_HOST_CTRL_CHIPREV) >> \
-	  MISC_HOST_CTRL_CHIPREV_SHIFT)
-#define  CHIPREV_ID_5700_A0		 0x7000
-#define  CHIPREV_ID_5700_A1		 0x7001
-#define  CHIPREV_ID_5700_B0		 0x7100
-#define  CHIPREV_ID_5700_B1		 0x7101
-#define  CHIPREV_ID_5700_B3		 0x7102
-#define  CHIPREV_ID_5700_ALTIMA		 0x7104
-#define  CHIPREV_ID_5700_C0		 0x7200
-#define  CHIPREV_ID_5701_A0		 0x0000
-#define  CHIPREV_ID_5701_B0		 0x0100
-#define  CHIPREV_ID_5701_B2		 0x0102
-#define  CHIPREV_ID_5701_B5		 0x0105
-#define  CHIPREV_ID_5703_A0		 0x1000
-#define  CHIPREV_ID_5703_A1		 0x1001
-#define  CHIPREV_ID_5703_A2		 0x1002
-#define  CHIPREV_ID_5703_A3		 0x1003
-#define  CHIPREV_ID_5704_A0		 0x2000
-#define  CHIPREV_ID_5704_A1		 0x2001
-#define  CHIPREV_ID_5704_A2		 0x2002
-#define  CHIPREV_ID_5705_A0		 0x3000
-#define  CHIPREV_ID_5705_A1		 0x3001
-#define	 CHIPREV_ID_5705_A2              0x3002
-#define  CHIPREV_ID_5705_A3              0x3003
-#define  CHIPREV_ID_5721                 0x4101
-#define  CHIPREV_ID_5750_A0              0x4000
-#define  CHIPREV_ID_5750_A1              0x4001
-#define  CHIPREV_ID_5750_A3              0x4003
-#define  GET_ASIC_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 12)
-#define   ASIC_REV_5700			 0x07
-#define   ASIC_REV_5701			 0x00
-#define   ASIC_REV_5703			 0x01
-#define   ASIC_REV_5704			 0x02
-#define   ASIC_REV_5705			 0x03
-#define   ASIC_REV_5750			 0x04
-#define   ASIC_REV_5787			 0x0b
-#define  GET_CHIP_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 8)
-#define   CHIPREV_5700_AX		 0x70
-#define   CHIPREV_5700_BX		 0x71
-#define   CHIPREV_5700_CX		 0x72
-#define   CHIPREV_5701_AX		 0x00
-#define  GET_METAL_REV(CHIP_REV_ID)	((CHIP_REV_ID) & 0xff)
-#define   METAL_REV_A0			 0x00
-#define   METAL_REV_A1			 0x01
-#define   METAL_REV_B0			 0x00
-#define   METAL_REV_B1			 0x01
-#define   METAL_REV_B2			 0x02
-#define TG3PCI_DMA_RW_CTRL		0x0000006c
-#define  DMA_RWCTRL_MIN_DMA		 0x000000ff
-#define  DMA_RWCTRL_MIN_DMA_SHIFT	 0
-#define  DMA_RWCTRL_READ_BNDRY_MASK	 0x00000700
-#define  DMA_RWCTRL_READ_BNDRY_DISAB	 0x00000000
-#define  DMA_RWCTRL_READ_BNDRY_16	 0x00000100
-#define  DMA_RWCTRL_READ_BNDRY_32	 0x00000200
-#define  DMA_RWCTRL_READ_BNDRY_64	 0x00000300
-#define  DMA_RWCTRL_READ_BNDRY_128	 0x00000400
-#define  DMA_RWCTRL_READ_BNDRY_256	 0x00000500
-#define  DMA_RWCTRL_READ_BNDRY_512	 0x00000600
-#define  DMA_RWCTRL_READ_BNDRY_1024	 0x00000700
-#define  DMA_RWCTRL_WRITE_BNDRY_MASK	 0x00003800
-#define  DMA_RWCTRL_WRITE_BNDRY_DISAB	 0x00000000
-#define  DMA_RWCTRL_WRITE_BNDRY_16	 0x00000800
-#define  DMA_RWCTRL_WRITE_BNDRY_32	 0x00001000
-#define  DMA_RWCTRL_WRITE_BNDRY_64	 0x00001800
-#define  DMA_RWCTRL_WRITE_BNDRY_128	 0x00002000
-#define  DMA_RWCTRL_WRITE_BNDRY_256	 0x00002800
-#define  DMA_RWCTRL_WRITE_BNDRY_512	 0x00003000
-#define  DMA_RWCTRL_WRITE_BNDRY_1024	 0x00003800
-#define  DMA_RWCTRL_ONE_DMA		 0x00004000
-#define  DMA_RWCTRL_READ_WATER		 0x00070000
-#define  DMA_RWCTRL_READ_WATER_SHIFT	 16
-#define  DMA_RWCTRL_WRITE_WATER		 0x00380000
-#define  DMA_RWCTRL_WRITE_WATER_SHIFT	 19
-#define  DMA_RWCTRL_USE_MEM_READ_MULT	 0x00400000
-#define  DMA_RWCTRL_ASSERT_ALL_BE	 0x00800000
-#define  DMA_RWCTRL_PCI_READ_CMD	 0x0f000000
-#define  DMA_RWCTRL_PCI_READ_CMD_SHIFT	 24
-#define  DMA_RWCTRL_PCI_WRITE_CMD	 0xf0000000
-#define  DMA_RWCTRL_PCI_WRITE_CMD_SHIFT	 28
-#define TG3PCI_PCISTATE			0x00000070
-#define  PCISTATE_FORCE_RESET		 0x00000001
-#define  PCISTATE_INT_NOT_ACTIVE	 0x00000002
-#define  PCISTATE_CONV_PCI_MODE		 0x00000004
-#define  PCISTATE_BUS_SPEED_HIGH	 0x00000008
-#define  PCISTATE_BUS_32BIT		 0x00000010
-#define  PCISTATE_ROM_ENABLE		 0x00000020
-#define  PCISTATE_ROM_RETRY_ENABLE	 0x00000040
-#define  PCISTATE_FLAT_VIEW		 0x00000100
-#define  PCISTATE_RETRY_SAME_DMA	 0x00002000
-#define TG3PCI_CLOCK_CTRL		0x00000074
-#define  CLOCK_CTRL_CORECLK_DISABLE	 0x00000200
-#define  CLOCK_CTRL_RXCLK_DISABLE	 0x00000400
-#define  CLOCK_CTRL_TXCLK_DISABLE	 0x00000800
-#define  CLOCK_CTRL_ALTCLK		 0x00001000
-#define  CLOCK_CTRL_PWRDOWN_PLL133	 0x00008000
-#define  CLOCK_CTRL_44MHZ_CORE		 0x00040000
-#define  CLOCK_CTRL_625_CORE		 0x00100000
-#define  CLOCK_CTRL_FORCE_CLKRUN	 0x00200000
-#define  CLOCK_CTRL_CLKRUN_OENABLE	 0x00400000
-#define  CLOCK_CTRL_DELAY_PCI_GRANT	 0x80000000
-#define TG3PCI_REG_BASE_ADDR		0x00000078
-#define TG3PCI_MEM_WIN_BASE_ADDR	0x0000007c
-#define TG3PCI_REG_DATA			0x00000080
-#define TG3PCI_MEM_WIN_DATA		0x00000084
-#define TG3PCI_MODE_CTRL		0x00000088
-#define TG3PCI_MISC_CFG			0x0000008c
-#define TG3PCI_MISC_LOCAL_CTRL		0x00000090
-/* 0x94 --> 0x98 unused */
-#define TG3PCI_STD_RING_PROD_IDX	0x00000098 /* 64-bit */
-#define TG3PCI_RCV_RET_RING_CON_IDX	0x000000a0 /* 64-bit */
-#define TG3PCI_SND_PROD_IDX		0x000000a8 /* 64-bit */
-/* 0xb0 --> 0x100 unused */
-
-/* 0x100 --> 0x200 unused */
-
-/* Mailbox registers */
-#define MAILBOX_INTERRUPT_0		0x00000200 /* 64-bit */
-#define MAILBOX_INTERRUPT_1		0x00000208 /* 64-bit */
-#define MAILBOX_INTERRUPT_2		0x00000210 /* 64-bit */
-#define MAILBOX_INTERRUPT_3		0x00000218 /* 64-bit */
-#define MAILBOX_GENERAL_0		0x00000220 /* 64-bit */
-#define MAILBOX_GENERAL_1		0x00000228 /* 64-bit */
-#define MAILBOX_GENERAL_2		0x00000230 /* 64-bit */
-#define MAILBOX_GENERAL_3		0x00000238 /* 64-bit */
-#define MAILBOX_GENERAL_4		0x00000240 /* 64-bit */
-#define MAILBOX_GENERAL_5		0x00000248 /* 64-bit */
-#define MAILBOX_GENERAL_6		0x00000250 /* 64-bit */
-#define MAILBOX_GENERAL_7		0x00000258 /* 64-bit */
-#define MAILBOX_RELOAD_STAT		0x00000260 /* 64-bit */
-#define MAILBOX_RCV_STD_PROD_IDX	0x00000268 /* 64-bit */
-#define MAILBOX_RCV_JUMBO_PROD_IDX	0x00000270 /* 64-bit */
-#define MAILBOX_RCV_MINI_PROD_IDX	0x00000278 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_0	0x00000280 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_1	0x00000288 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_2	0x00000290 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_3	0x00000298 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_4	0x000002a0 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_5	0x000002a8 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_6	0x000002b0 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_7	0x000002b8 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_8	0x000002c0 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_9	0x000002c8 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_10	0x000002d0 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_11	0x000002d8 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_12	0x000002e0 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_13	0x000002e8 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_14	0x000002f0 /* 64-bit */
-#define MAILBOX_RCVRET_CON_IDX_15	0x000002f8 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_0	0x00000300 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_1	0x00000308 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_2	0x00000310 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_3	0x00000318 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_4	0x00000320 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_5	0x00000328 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_6	0x00000330 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_7	0x00000338 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_8	0x00000340 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_9	0x00000348 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_10	0x00000350 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_11	0x00000358 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_12	0x00000360 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_13	0x00000368 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_14	0x00000370 /* 64-bit */
-#define MAILBOX_SNDHOST_PROD_IDX_15	0x00000378 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_0	0x00000380 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_1	0x00000388 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_2	0x00000390 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_3	0x00000398 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_4	0x000003a0 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_5	0x000003a8 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_6	0x000003b0 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_7	0x000003b8 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_8	0x000003c0 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_9	0x000003c8 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_10	0x000003d0 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_11	0x000003d8 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_12	0x000003e0 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_13	0x000003e8 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_14	0x000003f0 /* 64-bit */
-#define MAILBOX_SNDNIC_PROD_IDX_15	0x000003f8 /* 64-bit */
-
-/* MAC control registers */
-#define MAC_MODE			0x00000400
-#define  MAC_MODE_RESET			 0x00000001
-#define  MAC_MODE_HALF_DUPLEX		 0x00000002
-#define  MAC_MODE_PORT_MODE_MASK	 0x0000000c
-#define  MAC_MODE_PORT_MODE_TBI		 0x0000000c
-#define  MAC_MODE_PORT_MODE_GMII	 0x00000008
-#define  MAC_MODE_PORT_MODE_MII		 0x00000004
-#define  MAC_MODE_PORT_MODE_NONE	 0x00000000
-#define  MAC_MODE_PORT_INT_LPBACK	 0x00000010
-#define  MAC_MODE_TAGGED_MAC_CTRL	 0x00000080
-#define  MAC_MODE_TX_BURSTING		 0x00000100
-#define  MAC_MODE_MAX_DEFER		 0x00000200
-#define  MAC_MODE_LINK_POLARITY		 0x00000400
-#define  MAC_MODE_RXSTAT_ENABLE		 0x00000800
-#define  MAC_MODE_RXSTAT_CLEAR		 0x00001000
-#define  MAC_MODE_RXSTAT_FLUSH		 0x00002000
-#define  MAC_MODE_TXSTAT_ENABLE		 0x00004000
-#define  MAC_MODE_TXSTAT_CLEAR		 0x00008000
-#define  MAC_MODE_TXSTAT_FLUSH		 0x00010000
-#define  MAC_MODE_SEND_CONFIGS		 0x00020000
-#define  MAC_MODE_MAGIC_PKT_ENABLE	 0x00040000
-#define  MAC_MODE_ACPI_ENABLE		 0x00080000
-#define  MAC_MODE_MIP_ENABLE		 0x00100000
-#define  MAC_MODE_TDE_ENABLE		 0x00200000
-#define  MAC_MODE_RDE_ENABLE		 0x00400000
-#define  MAC_MODE_FHDE_ENABLE		 0x00800000
-#define MAC_STATUS			0x00000404
-#define  MAC_STATUS_PCS_SYNCED		 0x00000001
-#define  MAC_STATUS_SIGNAL_DET		 0x00000002
-#define  MAC_STATUS_RCVD_CFG		 0x00000004
-#define  MAC_STATUS_CFG_CHANGED		 0x00000008
-#define  MAC_STATUS_SYNC_CHANGED	 0x00000010
-#define  MAC_STATUS_PORT_DEC_ERR	 0x00000400
-#define  MAC_STATUS_LNKSTATE_CHANGED	 0x00001000
-#define  MAC_STATUS_MI_COMPLETION	 0x00400000
-#define  MAC_STATUS_MI_INTERRUPT	 0x00800000
-#define  MAC_STATUS_AP_ERROR		 0x01000000
-#define  MAC_STATUS_ODI_ERROR		 0x02000000
-#define  MAC_STATUS_RXSTAT_OVERRUN	 0x04000000
-#define  MAC_STATUS_TXSTAT_OVERRUN	 0x08000000
-#define MAC_EVENT			0x00000408
-#define  MAC_EVENT_PORT_DECODE_ERR	 0x00000400
-#define  MAC_EVENT_LNKSTATE_CHANGED	 0x00001000
-#define  MAC_EVENT_MI_COMPLETION	 0x00400000
-#define  MAC_EVENT_MI_INTERRUPT		 0x00800000
-#define  MAC_EVENT_AP_ERROR		 0x01000000
-#define  MAC_EVENT_ODI_ERROR		 0x02000000
-#define  MAC_EVENT_RXSTAT_OVERRUN	 0x04000000
-#define  MAC_EVENT_TXSTAT_OVERRUN	 0x08000000
-#define MAC_LED_CTRL			0x0000040c
-#define  LED_CTRL_LNKLED_OVERRIDE	 0x00000001
-#define  LED_CTRL_1000MBPS_ON		 0x00000002
-#define  LED_CTRL_100MBPS_ON		 0x00000004
-#define  LED_CTRL_10MBPS_ON		 0x00000008
-#define  LED_CTRL_TRAFFIC_OVERRIDE	 0x00000010
-#define  LED_CTRL_TRAFFIC_BLINK		 0x00000020
-#define  LED_CTRL_TRAFFIC_LED		 0x00000040
-#define  LED_CTRL_1000MBPS_STATUS	 0x00000080
-#define  LED_CTRL_100MBPS_STATUS	 0x00000100
-#define  LED_CTRL_10MBPS_STATUS		 0x00000200
-#define  LED_CTRL_TRAFFIC_STATUS	 0x00000400
-#define  LED_CTRL_MAC_MODE		 0x00000000
-#define  LED_CTRL_PHY_MODE_1		 0x00000800
-#define  LED_CTRL_PHY_MODE_2		 0x00001000
-#define  LED_CTRL_BLINK_RATE_MASK	 0x7ff80000
-#define  LED_CTRL_BLINK_RATE_SHIFT	 19
-#define  LED_CTRL_BLINK_PER_OVERRIDE	 0x00080000
-#define  LED_CTRL_BLINK_RATE_OVERRIDE	 0x80000000
-#define MAC_ADDR_0_HIGH			0x00000410 /* upper 2 bytes */
-#define MAC_ADDR_0_LOW			0x00000414 /* lower 4 bytes */
-#define MAC_ADDR_1_HIGH			0x00000418 /* upper 2 bytes */
-#define MAC_ADDR_1_LOW			0x0000041c /* lower 4 bytes */
-#define MAC_ADDR_2_HIGH			0x00000420 /* upper 2 bytes */
-#define MAC_ADDR_2_LOW			0x00000424 /* lower 4 bytes */
-#define MAC_ADDR_3_HIGH			0x00000428 /* upper 2 bytes */
-#define MAC_ADDR_3_LOW			0x0000042c /* lower 4 bytes */
-#define MAC_ACPI_MBUF_PTR		0x00000430
-#define MAC_ACPI_LEN_OFFSET		0x00000434
-#define  ACPI_LENOFF_LEN_MASK		 0x0000ffff
-#define  ACPI_LENOFF_LEN_SHIFT		 0
-#define  ACPI_LENOFF_OFF_MASK		 0x0fff0000
-#define  ACPI_LENOFF_OFF_SHIFT		 16
-#define MAC_TX_BACKOFF_SEED		0x00000438
-#define  TX_BACKOFF_SEED_MASK		 0x000003ff
-#define MAC_RX_MTU_SIZE			0x0000043c
-#define  RX_MTU_SIZE_MASK		 0x0000ffff
-#define MAC_PCS_TEST			0x00000440
-#define  PCS_TEST_PATTERN_MASK		 0x000fffff
-#define  PCS_TEST_PATTERN_SHIFT		 0
-#define  PCS_TEST_ENABLE		 0x00100000
-#define MAC_TX_AUTO_NEG			0x00000444
-#define  TX_AUTO_NEG_MASK		 0x0000ffff
-#define  TX_AUTO_NEG_SHIFT		 0
-#define MAC_RX_AUTO_NEG			0x00000448
-#define  RX_AUTO_NEG_MASK		 0x0000ffff
-#define  RX_AUTO_NEG_SHIFT		 0
-#define MAC_MI_COM			0x0000044c
-#define  MI_COM_CMD_MASK		 0x0c000000
-#define  MI_COM_CMD_WRITE		 0x04000000
-#define  MI_COM_CMD_READ		 0x08000000
-#define  MI_COM_READ_FAILED		 0x10000000
-#define  MI_COM_START			 0x20000000
-#define  MI_COM_BUSY			 0x20000000
-#define  MI_COM_PHY_ADDR_MASK		 0x03e00000
-#define  MI_COM_PHY_ADDR_SHIFT		 21
-#define  MI_COM_REG_ADDR_MASK		 0x001f0000
-#define  MI_COM_REG_ADDR_SHIFT		 16
-#define  MI_COM_DATA_MASK		 0x0000ffff
-#define MAC_MI_STAT			0x00000450
-#define  MAC_MI_STAT_LNKSTAT_ATTN_ENAB	 0x00000001
-#define MAC_MI_MODE			0x00000454
-#define  MAC_MI_MODE_CLK_10MHZ		 0x00000001
-#define  MAC_MI_MODE_SHORT_PREAMBLE	 0x00000002
-#define  MAC_MI_MODE_AUTO_POLL		 0x00000010
-#define  MAC_MI_MODE_CORE_CLK_62MHZ	 0x00008000
-#define  MAC_MI_MODE_BASE		 0x000c0000 /* XXX magic values XXX */
-#define MAC_AUTO_POLL_STATUS		0x00000458
-#define  MAC_AUTO_POLL_ERROR		 0x00000001
-#define MAC_TX_MODE			0x0000045c
-#define  TX_MODE_RESET			 0x00000001
-#define  TX_MODE_ENABLE			 0x00000002
-#define  TX_MODE_FLOW_CTRL_ENABLE	 0x00000010
-#define  TX_MODE_BIG_BCKOFF_ENABLE	 0x00000020
-#define  TX_MODE_LONG_PAUSE_ENABLE	 0x00000040
-#define MAC_TX_STATUS			0x00000460
-#define  TX_STATUS_XOFFED		 0x00000001
-#define  TX_STATUS_SENT_XOFF		 0x00000002
-#define  TX_STATUS_SENT_XON		 0x00000004
-#define  TX_STATUS_LINK_UP		 0x00000008
-#define  TX_STATUS_ODI_UNDERRUN		 0x00000010
-#define  TX_STATUS_ODI_OVERRUN		 0x00000020
-#define MAC_TX_LENGTHS			0x00000464
-#define  TX_LENGTHS_SLOT_TIME_MASK	 0x000000ff
-#define  TX_LENGTHS_SLOT_TIME_SHIFT	 0
-#define  TX_LENGTHS_IPG_MASK		 0x00000f00
-#define  TX_LENGTHS_IPG_SHIFT		 8
-#define  TX_LENGTHS_IPG_CRS_MASK	 0x00003000
-#define  TX_LENGTHS_IPG_CRS_SHIFT	 12
-#define MAC_RX_MODE			0x00000468
-#define  RX_MODE_RESET			 0x00000001
-#define  RX_MODE_ENABLE			 0x00000002
-#define  RX_MODE_FLOW_CTRL_ENABLE	 0x00000004
-#define  RX_MODE_KEEP_MAC_CTRL		 0x00000008
-#define  RX_MODE_KEEP_PAUSE		 0x00000010
-#define  RX_MODE_ACCEPT_OVERSIZED	 0x00000020
-#define  RX_MODE_ACCEPT_RUNTS		 0x00000040
-#define  RX_MODE_LEN_CHECK		 0x00000080
-#define  RX_MODE_PROMISC		 0x00000100
-#define  RX_MODE_NO_CRC_CHECK		 0x00000200
-#define  RX_MODE_KEEP_VLAN_TAG		 0x00000400
-#define MAC_RX_STATUS			0x0000046c
-#define  RX_STATUS_REMOTE_TX_XOFFED	 0x00000001
-#define  RX_STATUS_XOFF_RCVD		 0x00000002
-#define  RX_STATUS_XON_RCVD		 0x00000004
-#define MAC_HASH_REG_0			0x00000470
-#define MAC_HASH_REG_1			0x00000474
-#define MAC_HASH_REG_2			0x00000478
-#define MAC_HASH_REG_3			0x0000047c
-#define MAC_RCV_RULE_0			0x00000480
-#define MAC_RCV_VALUE_0			0x00000484
-#define MAC_RCV_RULE_1			0x00000488
-#define MAC_RCV_VALUE_1			0x0000048c
-#define MAC_RCV_RULE_2			0x00000490
-#define MAC_RCV_VALUE_2			0x00000494
-#define MAC_RCV_RULE_3			0x00000498
-#define MAC_RCV_VALUE_3			0x0000049c
-#define MAC_RCV_RULE_4			0x000004a0
-#define MAC_RCV_VALUE_4			0x000004a4
-#define MAC_RCV_RULE_5			0x000004a8
-#define MAC_RCV_VALUE_5			0x000004ac
-#define MAC_RCV_RULE_6			0x000004b0
-#define MAC_RCV_VALUE_6			0x000004b4
-#define MAC_RCV_RULE_7			0x000004b8
-#define MAC_RCV_VALUE_7			0x000004bc
-#define MAC_RCV_RULE_8			0x000004c0
-#define MAC_RCV_VALUE_8			0x000004c4
-#define MAC_RCV_RULE_9			0x000004c8
-#define MAC_RCV_VALUE_9			0x000004cc
-#define MAC_RCV_RULE_10			0x000004d0
-#define MAC_RCV_VALUE_10		0x000004d4
-#define MAC_RCV_RULE_11			0x000004d8
-#define MAC_RCV_VALUE_11		0x000004dc
-#define MAC_RCV_RULE_12			0x000004e0
-#define MAC_RCV_VALUE_12		0x000004e4
-#define MAC_RCV_RULE_13			0x000004e8
-#define MAC_RCV_VALUE_13		0x000004ec
-#define MAC_RCV_RULE_14			0x000004f0
-#define MAC_RCV_VALUE_14		0x000004f4
-#define MAC_RCV_RULE_15			0x000004f8
-#define MAC_RCV_VALUE_15		0x000004fc
-#define  RCV_RULE_DISABLE_MASK		 0x7fffffff
-#define MAC_RCV_RULE_CFG		0x00000500
-#define  RCV_RULE_CFG_DEFAULT_CLASS	0x00000008
-#define MAC_LOW_WMARK_MAX_RX_FRAME	0x00000504
-/* 0x508 --> 0x520 unused */
-#define MAC_HASHREGU_0			0x00000520
-#define MAC_HASHREGU_1			0x00000524
-#define MAC_HASHREGU_2			0x00000528
-#define MAC_HASHREGU_3			0x0000052c
-#define MAC_EXTADDR_0_HIGH		0x00000530
-#define MAC_EXTADDR_0_LOW		0x00000534
-#define MAC_EXTADDR_1_HIGH		0x00000538
-#define MAC_EXTADDR_1_LOW		0x0000053c
-#define MAC_EXTADDR_2_HIGH		0x00000540
-#define MAC_EXTADDR_2_LOW		0x00000544
-#define MAC_EXTADDR_3_HIGH		0x00000548
-#define MAC_EXTADDR_3_LOW		0x0000054c
-#define MAC_EXTADDR_4_HIGH		0x00000550
-#define MAC_EXTADDR_4_LOW		0x00000554
-#define MAC_EXTADDR_5_HIGH		0x00000558
-#define MAC_EXTADDR_5_LOW		0x0000055c
-#define MAC_EXTADDR_6_HIGH		0x00000560
-#define MAC_EXTADDR_6_LOW		0x00000564
-#define MAC_EXTADDR_7_HIGH		0x00000568
-#define MAC_EXTADDR_7_LOW		0x0000056c
-#define MAC_EXTADDR_8_HIGH		0x00000570
-#define MAC_EXTADDR_8_LOW		0x00000574
-#define MAC_EXTADDR_9_HIGH		0x00000578
-#define MAC_EXTADDR_9_LOW		0x0000057c
-#define MAC_EXTADDR_10_HIGH		0x00000580
-#define MAC_EXTADDR_10_LOW		0x00000584
-#define MAC_EXTADDR_11_HIGH		0x00000588
-#define MAC_EXTADDR_11_LOW		0x0000058c
-#define MAC_SERDES_CFG			0x00000590
-#define MAC_SERDES_STAT			0x00000594
-/* 0x598 --> 0x600 unused */
-#define MAC_TX_MAC_STATE_BASE		0x00000600 /* 16 bytes */
-#define MAC_RX_MAC_STATE_BASE		0x00000610 /* 20 bytes */
-/* 0x624 --> 0x800 unused */
-#define MAC_TX_STATS_OCTETS		0x00000800
-#define MAC_TX_STATS_RESV1		0x00000804
-#define MAC_TX_STATS_COLLISIONS		0x00000808
-#define MAC_TX_STATS_XON_SENT		0x0000080c
-#define MAC_TX_STATS_XOFF_SENT		0x00000810
-#define MAC_TX_STATS_RESV2		0x00000814
-#define MAC_TX_STATS_MAC_ERRORS		0x00000818
-#define MAC_TX_STATS_SINGLE_COLLISIONS	0x0000081c
-#define MAC_TX_STATS_MULT_COLLISIONS	0x00000820
-#define MAC_TX_STATS_DEFERRED		0x00000824
-#define MAC_TX_STATS_RESV3		0x00000828
-#define MAC_TX_STATS_EXCESSIVE_COL	0x0000082c
-#define MAC_TX_STATS_LATE_COL		0x00000830
-#define MAC_TX_STATS_RESV4_1		0x00000834
-#define MAC_TX_STATS_RESV4_2		0x00000838
-#define MAC_TX_STATS_RESV4_3		0x0000083c
-#define MAC_TX_STATS_RESV4_4		0x00000840
-#define MAC_TX_STATS_RESV4_5		0x00000844
-#define MAC_TX_STATS_RESV4_6		0x00000848
-#define MAC_TX_STATS_RESV4_7		0x0000084c
-#define MAC_TX_STATS_RESV4_8		0x00000850
-#define MAC_TX_STATS_RESV4_9		0x00000854
-#define MAC_TX_STATS_RESV4_10		0x00000858
-#define MAC_TX_STATS_RESV4_11		0x0000085c
-#define MAC_TX_STATS_RESV4_12		0x00000860
-#define MAC_TX_STATS_RESV4_13		0x00000864
-#define MAC_TX_STATS_RESV4_14		0x00000868
-#define MAC_TX_STATS_UCAST		0x0000086c
-#define MAC_TX_STATS_MCAST		0x00000870
-#define MAC_TX_STATS_BCAST		0x00000874
-#define MAC_TX_STATS_RESV5_1		0x00000878
-#define MAC_TX_STATS_RESV5_2		0x0000087c
-#define MAC_RX_STATS_OCTETS		0x00000880
-#define MAC_RX_STATS_RESV1		0x00000884
-#define MAC_RX_STATS_FRAGMENTS		0x00000888
-#define MAC_RX_STATS_UCAST		0x0000088c
-#define MAC_RX_STATS_MCAST		0x00000890
-#define MAC_RX_STATS_BCAST		0x00000894
-#define MAC_RX_STATS_FCS_ERRORS		0x00000898
-#define MAC_RX_STATS_ALIGN_ERRORS	0x0000089c
-#define MAC_RX_STATS_XON_PAUSE_RECVD	0x000008a0
-#define MAC_RX_STATS_XOFF_PAUSE_RECVD	0x000008a4
-#define MAC_RX_STATS_MAC_CTRL_RECVD	0x000008a8
-#define MAC_RX_STATS_XOFF_ENTERED	0x000008ac
-#define MAC_RX_STATS_FRAME_TOO_LONG	0x000008b0
-#define MAC_RX_STATS_JABBERS		0x000008b4
-#define MAC_RX_STATS_UNDERSIZE		0x000008b8
-/* 0x8bc --> 0xc00 unused */
-
-/* Send data initiator control registers */
-#define SNDDATAI_MODE			0x00000c00
-#define  SNDDATAI_MODE_RESET		 0x00000001
-#define  SNDDATAI_MODE_ENABLE		 0x00000002
-#define  SNDDATAI_MODE_STAT_OFLOW_ENAB	 0x00000004
-#define SNDDATAI_STATUS			0x00000c04
-#define  SNDDATAI_STATUS_STAT_OFLOW	 0x00000004
-#define SNDDATAI_STATSCTRL		0x00000c08
-#define  SNDDATAI_SCTRL_ENABLE		 0x00000001
-#define  SNDDATAI_SCTRL_FASTUPD		 0x00000002
-#define  SNDDATAI_SCTRL_CLEAR		 0x00000004
-#define  SNDDATAI_SCTRL_FLUSH		 0x00000008
-#define  SNDDATAI_SCTRL_FORCE_ZERO	 0x00000010
-#define SNDDATAI_STATSENAB		0x00000c0c
-#define SNDDATAI_STATSINCMASK		0x00000c10
-/* 0xc14 --> 0xc80 unused */
-#define SNDDATAI_COS_CNT_0		0x00000c80
-#define SNDDATAI_COS_CNT_1		0x00000c84
-#define SNDDATAI_COS_CNT_2		0x00000c88
-#define SNDDATAI_COS_CNT_3		0x00000c8c
-#define SNDDATAI_COS_CNT_4		0x00000c90
-#define SNDDATAI_COS_CNT_5		0x00000c94
-#define SNDDATAI_COS_CNT_6		0x00000c98
-#define SNDDATAI_COS_CNT_7		0x00000c9c
-#define SNDDATAI_COS_CNT_8		0x00000ca0
-#define SNDDATAI_COS_CNT_9		0x00000ca4
-#define SNDDATAI_COS_CNT_10		0x00000ca8
-#define SNDDATAI_COS_CNT_11		0x00000cac
-#define SNDDATAI_COS_CNT_12		0x00000cb0
-#define SNDDATAI_COS_CNT_13		0x00000cb4
-#define SNDDATAI_COS_CNT_14		0x00000cb8
-#define SNDDATAI_COS_CNT_15		0x00000cbc
-#define SNDDATAI_DMA_RDQ_FULL_CNT	0x00000cc0
-#define SNDDATAI_DMA_PRIO_RDQ_FULL_CNT	0x00000cc4
-#define SNDDATAI_SDCQ_FULL_CNT		0x00000cc8
-#define SNDDATAI_NICRNG_SSND_PIDX_CNT	0x00000ccc
-#define SNDDATAI_STATS_UPDATED_CNT	0x00000cd0
-#define SNDDATAI_INTERRUPTS_CNT		0x00000cd4
-#define SNDDATAI_AVOID_INTERRUPTS_CNT	0x00000cd8
-#define SNDDATAI_SND_THRESH_HIT_CNT	0x00000cdc
-/* 0xce0 --> 0x1000 unused */
-
-/* Send data completion control registers */
-#define SNDDATAC_MODE			0x00001000
-#define  SNDDATAC_MODE_RESET		 0x00000001
-#define  SNDDATAC_MODE_ENABLE		 0x00000002
-/* 0x1004 --> 0x1400 unused */
-
-/* Send BD ring selector */
-#define SNDBDS_MODE			0x00001400
-#define  SNDBDS_MODE_RESET		 0x00000001
-#define  SNDBDS_MODE_ENABLE		 0x00000002
-#define  SNDBDS_MODE_ATTN_ENABLE	 0x00000004
-#define SNDBDS_STATUS			0x00001404
-#define  SNDBDS_STATUS_ERROR_ATTN	 0x00000004
-#define SNDBDS_HWDIAG			0x00001408
-/* 0x140c --> 0x1440 */
-#define SNDBDS_SEL_CON_IDX_0		0x00001440
-#define SNDBDS_SEL_CON_IDX_1		0x00001444
-#define SNDBDS_SEL_CON_IDX_2		0x00001448
-#define SNDBDS_SEL_CON_IDX_3		0x0000144c
-#define SNDBDS_SEL_CON_IDX_4		0x00001450
-#define SNDBDS_SEL_CON_IDX_5		0x00001454
-#define SNDBDS_SEL_CON_IDX_6		0x00001458
-#define SNDBDS_SEL_CON_IDX_7		0x0000145c
-#define SNDBDS_SEL_CON_IDX_8		0x00001460
-#define SNDBDS_SEL_CON_IDX_9		0x00001464
-#define SNDBDS_SEL_CON_IDX_10		0x00001468
-#define SNDBDS_SEL_CON_IDX_11		0x0000146c
-#define SNDBDS_SEL_CON_IDX_12		0x00001470
-#define SNDBDS_SEL_CON_IDX_13		0x00001474
-#define SNDBDS_SEL_CON_IDX_14		0x00001478
-#define SNDBDS_SEL_CON_IDX_15		0x0000147c
-/* 0x1480 --> 0x1800 unused */
-
-/* Send BD initiator control registers */
-#define SNDBDI_MODE			0x00001800
-#define  SNDBDI_MODE_RESET		 0x00000001
-#define  SNDBDI_MODE_ENABLE		 0x00000002
-#define  SNDBDI_MODE_ATTN_ENABLE	 0x00000004
-#define SNDBDI_STATUS			0x00001804
-#define  SNDBDI_STATUS_ERROR_ATTN	 0x00000004
-#define SNDBDI_IN_PROD_IDX_0		0x00001808
-#define SNDBDI_IN_PROD_IDX_1		0x0000180c
-#define SNDBDI_IN_PROD_IDX_2		0x00001810
-#define SNDBDI_IN_PROD_IDX_3		0x00001814
-#define SNDBDI_IN_PROD_IDX_4		0x00001818
-#define SNDBDI_IN_PROD_IDX_5		0x0000181c
-#define SNDBDI_IN_PROD_IDX_6		0x00001820
-#define SNDBDI_IN_PROD_IDX_7		0x00001824
-#define SNDBDI_IN_PROD_IDX_8		0x00001828
-#define SNDBDI_IN_PROD_IDX_9		0x0000182c
-#define SNDBDI_IN_PROD_IDX_10		0x00001830
-#define SNDBDI_IN_PROD_IDX_11		0x00001834
-#define SNDBDI_IN_PROD_IDX_12		0x00001838
-#define SNDBDI_IN_PROD_IDX_13		0x0000183c
-#define SNDBDI_IN_PROD_IDX_14		0x00001840
-#define SNDBDI_IN_PROD_IDX_15		0x00001844
-/* 0x1848 --> 0x1c00 unused */
-
-/* Send BD completion control registers */
-#define SNDBDC_MODE			0x00001c00
-#define SNDBDC_MODE_RESET		 0x00000001
-#define SNDBDC_MODE_ENABLE		 0x00000002
-#define SNDBDC_MODE_ATTN_ENABLE		 0x00000004
-/* 0x1c04 --> 0x2000 unused */
-
-/* Receive list placement control registers */
-#define RCVLPC_MODE			0x00002000
-#define  RCVLPC_MODE_RESET		 0x00000001
-#define  RCVLPC_MODE_ENABLE		 0x00000002
-#define  RCVLPC_MODE_CLASS0_ATTN_ENAB	 0x00000004
-#define  RCVLPC_MODE_MAPOOR_AATTN_ENAB	 0x00000008
-#define  RCVLPC_MODE_STAT_OFLOW_ENAB	 0x00000010
-#define RCVLPC_STATUS			0x00002004
-#define  RCVLPC_STATUS_CLASS0		 0x00000004
-#define  RCVLPC_STATUS_MAPOOR		 0x00000008
-#define  RCVLPC_STATUS_STAT_OFLOW	 0x00000010
-#define RCVLPC_LOCK			0x00002008
-#define  RCVLPC_LOCK_REQ_MASK		 0x0000ffff
-#define  RCVLPC_LOCK_REQ_SHIFT		 0
-#define  RCVLPC_LOCK_GRANT_MASK		 0xffff0000
-#define  RCVLPC_LOCK_GRANT_SHIFT	 16
-#define RCVLPC_NON_EMPTY_BITS		0x0000200c
-#define  RCVLPC_NON_EMPTY_BITS_MASK	 0x0000ffff
-#define RCVLPC_CONFIG			0x00002010
-#define RCVLPC_STATSCTRL		0x00002014
-#define  RCVLPC_STATSCTRL_ENABLE	 0x00000001
-#define  RCVLPC_STATSCTRL_FASTUPD	 0x00000002
-#define RCVLPC_STATS_ENABLE		0x00002018
-#define  RCVLPC_STATSENAB_LNGBRST_RFIX	 0x00400000
-#define RCVLPC_STATS_INCMASK		0x0000201c
-/* 0x2020 --> 0x2100 unused */
-#define RCVLPC_SELLST_BASE		0x00002100 /* 16 16-byte entries */
-#define  SELLST_TAIL			0x00000004
-#define  SELLST_CONT			0x00000008
-#define  SELLST_UNUSED			0x0000000c
-#define RCVLPC_COS_CNTL_BASE		0x00002200 /* 16 4-byte entries */
-#define RCVLPC_DROP_FILTER_CNT		0x00002240
-#define RCVLPC_DMA_WQ_FULL_CNT		0x00002244
-#define RCVLPC_DMA_HIPRIO_WQ_FULL_CNT	0x00002248
-#define RCVLPC_NO_RCV_BD_CNT		0x0000224c
-#define RCVLPC_IN_DISCARDS_CNT		0x00002250
-#define RCVLPC_IN_ERRORS_CNT		0x00002254
-#define RCVLPC_RCV_THRESH_HIT_CNT	0x00002258
-/* 0x225c --> 0x2400 unused */
-
-/* Receive Data and Receive BD Initiator Control */
-#define RCVDBDI_MODE			0x00002400
-#define  RCVDBDI_MODE_RESET		 0x00000001
-#define  RCVDBDI_MODE_ENABLE		 0x00000002
-#define  RCVDBDI_MODE_JUMBOBD_NEEDED	 0x00000004
-#define  RCVDBDI_MODE_FRM_TOO_BIG	 0x00000008
-#define  RCVDBDI_MODE_INV_RING_SZ	 0x00000010
-#define RCVDBDI_STATUS			0x00002404
-#define  RCVDBDI_STATUS_JUMBOBD_NEEDED	 0x00000004
-#define  RCVDBDI_STATUS_FRM_TOO_BIG	 0x00000008
-#define  RCVDBDI_STATUS_INV_RING_SZ	 0x00000010
-#define RCVDBDI_SPLIT_FRAME_MINSZ	0x00002408
-/* 0x240c --> 0x2440 unused */
-#define RCVDBDI_JUMBO_BD		0x00002440 /* TG3_BDINFO_... */
-#define RCVDBDI_STD_BD			0x00002450 /* TG3_BDINFO_... */
-#define RCVDBDI_MINI_BD			0x00002460 /* TG3_BDINFO_... */
-#define RCVDBDI_JUMBO_CON_IDX		0x00002470
-#define RCVDBDI_STD_CON_IDX		0x00002474
-#define RCVDBDI_MINI_CON_IDX		0x00002478
-/* 0x247c --> 0x2480 unused */
-#define RCVDBDI_BD_PROD_IDX_0		0x00002480
-#define RCVDBDI_BD_PROD_IDX_1		0x00002484
-#define RCVDBDI_BD_PROD_IDX_2		0x00002488
-#define RCVDBDI_BD_PROD_IDX_3		0x0000248c
-#define RCVDBDI_BD_PROD_IDX_4		0x00002490
-#define RCVDBDI_BD_PROD_IDX_5		0x00002494
-#define RCVDBDI_BD_PROD_IDX_6		0x00002498
-#define RCVDBDI_BD_PROD_IDX_7		0x0000249c
-#define RCVDBDI_BD_PROD_IDX_8		0x000024a0
-#define RCVDBDI_BD_PROD_IDX_9		0x000024a4
-#define RCVDBDI_BD_PROD_IDX_10		0x000024a8
-#define RCVDBDI_BD_PROD_IDX_11		0x000024ac
-#define RCVDBDI_BD_PROD_IDX_12		0x000024b0
-#define RCVDBDI_BD_PROD_IDX_13		0x000024b4
-#define RCVDBDI_BD_PROD_IDX_14		0x000024b8
-#define RCVDBDI_BD_PROD_IDX_15		0x000024bc
-#define RCVDBDI_HWDIAG			0x000024c0
-/* 0x24c4 --> 0x2800 unused */
-
-/* Receive Data Completion Control */
-#define RCVDCC_MODE			0x00002800
-#define  RCVDCC_MODE_RESET		 0x00000001
-#define  RCVDCC_MODE_ENABLE		 0x00000002
-#define  RCVDCC_MODE_ATTN_ENABLE	 0x00000004
-/* 0x2804 --> 0x2c00 unused */
-
-/* Receive BD Initiator Control Registers */
-#define RCVBDI_MODE			0x00002c00
-#define  RCVBDI_MODE_RESET		 0x00000001
-#define  RCVBDI_MODE_ENABLE		 0x00000002
-#define  RCVBDI_MODE_RCB_ATTN_ENAB	 0x00000004
-#define RCVBDI_STATUS			0x00002c04
-#define  RCVBDI_STATUS_RCB_ATTN		 0x00000004
-#define RCVBDI_JUMBO_PROD_IDX		0x00002c08
-#define RCVBDI_STD_PROD_IDX		0x00002c0c
-#define RCVBDI_MINI_PROD_IDX		0x00002c10
-#define RCVBDI_MINI_THRESH		0x00002c14
-#define RCVBDI_STD_THRESH		0x00002c18
-#define RCVBDI_JUMBO_THRESH		0x00002c1c
-/* 0x2c20 --> 0x3000 unused */
-
-/* Receive BD Completion Control Registers */
-#define RCVCC_MODE			0x00003000
-#define  RCVCC_MODE_RESET		 0x00000001
-#define  RCVCC_MODE_ENABLE		 0x00000002
-#define  RCVCC_MODE_ATTN_ENABLE		 0x00000004
-#define RCVCC_STATUS			0x00003004
-#define  RCVCC_STATUS_ERROR_ATTN	 0x00000004
-#define RCVCC_JUMP_PROD_IDX		0x00003008
-#define RCVCC_STD_PROD_IDX		0x0000300c
-#define RCVCC_MINI_PROD_IDX		0x00003010
-/* 0x3014 --> 0x3400 unused */
-
-/* Receive list selector control registers */
-#define RCVLSC_MODE			0x00003400
-#define  RCVLSC_MODE_RESET		 0x00000001
-#define  RCVLSC_MODE_ENABLE		 0x00000002
-#define  RCVLSC_MODE_ATTN_ENABLE	 0x00000004
-#define RCVLSC_STATUS			0x00003404
-#define  RCVLSC_STATUS_ERROR_ATTN	 0x00000004
-/* 0x3408 --> 0x3800 unused */
-
-/* Mbuf cluster free registers */
-#define MBFREE_MODE			0x00003800
-#define  MBFREE_MODE_RESET		 0x00000001
-#define  MBFREE_MODE_ENABLE		 0x00000002
-#define MBFREE_STATUS			0x00003804
-/* 0x3808 --> 0x3c00 unused */
-
-/* Host coalescing control registers */
-#define HOSTCC_MODE			0x00003c00
-#define  HOSTCC_MODE_RESET		 0x00000001
-#define  HOSTCC_MODE_ENABLE		 0x00000002
-#define  HOSTCC_MODE_ATTN		 0x00000004
-#define  HOSTCC_MODE_NOW		 0x00000008
-#define  HOSTCC_MODE_FULL_STATUS	 0x00000000
-#define  HOSTCC_MODE_64BYTE		 0x00000080
-#define  HOSTCC_MODE_32BYTE		 0x00000100
-#define  HOSTCC_MODE_CLRTICK_RXBD	 0x00000200
-#define  HOSTCC_MODE_CLRTICK_TXBD	 0x00000400
-#define  HOSTCC_MODE_NOINT_ON_NOW	 0x00000800
-#define  HOSTCC_MODE_NOINT_ON_FORCE	 0x00001000
-#define HOSTCC_STATUS			0x00003c04
-#define  HOSTCC_STATUS_ERROR_ATTN	 0x00000004
-#define HOSTCC_RXCOL_TICKS		0x00003c08
-#define  LOW_RXCOL_TICKS		 0x00000032
-#define  DEFAULT_RXCOL_TICKS		 0x00000048
-#define  HIGH_RXCOL_TICKS		 0x00000096
-#define HOSTCC_TXCOL_TICKS		0x00003c0c
-#define  LOW_TXCOL_TICKS		 0x00000096
-#define  DEFAULT_TXCOL_TICKS		 0x0000012c
-#define  HIGH_TXCOL_TICKS		 0x00000145
-#define HOSTCC_RXMAX_FRAMES		0x00003c10
-#define  LOW_RXMAX_FRAMES		 0x00000005
-#define  DEFAULT_RXMAX_FRAMES		 0x00000008
-#define  HIGH_RXMAX_FRAMES		 0x00000012
-#define HOSTCC_TXMAX_FRAMES		0x00003c14
-#define  LOW_TXMAX_FRAMES		 0x00000035
-#define  DEFAULT_TXMAX_FRAMES		 0x0000004b
-#define  HIGH_TXMAX_FRAMES		 0x00000052
-#define HOSTCC_RXCOAL_TICK_INT		0x00003c18
-#define  DEFAULT_RXCOAL_TICK_INT	 0x00000019
-#define HOSTCC_TXCOAL_TICK_INT		0x00003c1c
-#define  DEFAULT_TXCOAL_TICK_INT	 0x00000019
-#define HOSTCC_RXCOAL_MAXF_INT		0x00003c20
-#define  DEFAULT_RXCOAL_MAXF_INT	 0x00000005
-#define HOSTCC_TXCOAL_MAXF_INT		0x00003c24
-#define  DEFAULT_TXCOAL_MAXF_INT	 0x00000005
-#define HOSTCC_STAT_COAL_TICKS		0x00003c28
-#define  DEFAULT_STAT_COAL_TICKS	 0x000f4240
-/* 0x3c2c --> 0x3c30 unused */
-#define HOSTCC_STATS_BLK_HOST_ADDR	0x00003c30 /* 64-bit */
-#define HOSTCC_STATUS_BLK_HOST_ADDR	0x00003c38 /* 64-bit */
-#define HOSTCC_STATS_BLK_NIC_ADDR	0x00003c40
-#define HOSTCC_STATUS_BLK_NIC_ADDR	0x00003c44
-#define HOSTCC_FLOW_ATTN		0x00003c48
-/* 0x3c4c --> 0x3c50 unused */
-#define HOSTCC_JUMBO_CON_IDX		0x00003c50
-#define HOSTCC_STD_CON_IDX		0x00003c54
-#define HOSTCC_MINI_CON_IDX		0x00003c58
-/* 0x3c5c --> 0x3c80 unused */
-#define HOSTCC_RET_PROD_IDX_0		0x00003c80
-#define HOSTCC_RET_PROD_IDX_1		0x00003c84
-#define HOSTCC_RET_PROD_IDX_2		0x00003c88
-#define HOSTCC_RET_PROD_IDX_3		0x00003c8c
-#define HOSTCC_RET_PROD_IDX_4		0x00003c90
-#define HOSTCC_RET_PROD_IDX_5		0x00003c94
-#define HOSTCC_RET_PROD_IDX_6		0x00003c98
-#define HOSTCC_RET_PROD_IDX_7		0x00003c9c
-#define HOSTCC_RET_PROD_IDX_8		0x00003ca0
-#define HOSTCC_RET_PROD_IDX_9		0x00003ca4
-#define HOSTCC_RET_PROD_IDX_10		0x00003ca8
-#define HOSTCC_RET_PROD_IDX_11		0x00003cac
-#define HOSTCC_RET_PROD_IDX_12		0x00003cb0
-#define HOSTCC_RET_PROD_IDX_13		0x00003cb4
-#define HOSTCC_RET_PROD_IDX_14		0x00003cb8
-#define HOSTCC_RET_PROD_IDX_15		0x00003cbc
-#define HOSTCC_SND_CON_IDX_0		0x00003cc0
-#define HOSTCC_SND_CON_IDX_1		0x00003cc4
-#define HOSTCC_SND_CON_IDX_2		0x00003cc8
-#define HOSTCC_SND_CON_IDX_3		0x00003ccc
-#define HOSTCC_SND_CON_IDX_4		0x00003cd0
-#define HOSTCC_SND_CON_IDX_5		0x00003cd4
-#define HOSTCC_SND_CON_IDX_6		0x00003cd8
-#define HOSTCC_SND_CON_IDX_7		0x00003cdc
-#define HOSTCC_SND_CON_IDX_8		0x00003ce0
-#define HOSTCC_SND_CON_IDX_9		0x00003ce4
-#define HOSTCC_SND_CON_IDX_10		0x00003ce8
-#define HOSTCC_SND_CON_IDX_11		0x00003cec
-#define HOSTCC_SND_CON_IDX_12		0x00003cf0
-#define HOSTCC_SND_CON_IDX_13		0x00003cf4
-#define HOSTCC_SND_CON_IDX_14		0x00003cf8
-#define HOSTCC_SND_CON_IDX_15		0x00003cfc
-/* 0x3d00 --> 0x4000 unused */
-
-/* Memory arbiter control registers */
-#define MEMARB_MODE			0x00004000
-#define  MEMARB_MODE_RESET		 0x00000001
-#define  MEMARB_MODE_ENABLE		 0x00000002
-#define MEMARB_STATUS			0x00004004
-#define MEMARB_TRAP_ADDR_LOW		0x00004008
-#define MEMARB_TRAP_ADDR_HIGH		0x0000400c
-/* 0x4010 --> 0x4400 unused */
-
-/* Buffer manager control registers */
-#define BUFMGR_MODE			0x00004400
-#define  BUFMGR_MODE_RESET		 0x00000001
-#define  BUFMGR_MODE_ENABLE		 0x00000002
-#define  BUFMGR_MODE_ATTN_ENABLE	 0x00000004
-#define  BUFMGR_MODE_BM_TEST		 0x00000008
-#define  BUFMGR_MODE_MBLOW_ATTN_ENAB	 0x00000010
-#define BUFMGR_STATUS			0x00004404
-#define  BUFMGR_STATUS_ERROR		 0x00000004
-#define  BUFMGR_STATUS_MBLOW		 0x00000010
-#define BUFMGR_MB_POOL_ADDR		0x00004408
-#define BUFMGR_MB_POOL_SIZE		0x0000440c
-#define BUFMGR_MB_RDMA_LOW_WATER	0x00004410
-#define  DEFAULT_MB_RDMA_LOW_WATER	 0x00000050
-#define  DEFAULT_MB_RDMA_LOW_WATER_5705	 0x00000000
-#define  DEFAULT_MB_RDMA_LOW_WATER_JUMBO 0x00000130
-#define BUFMGR_MB_MACRX_LOW_WATER	0x00004414
-#define  DEFAULT_MB_MACRX_LOW_WATER	  0x00000020
-#define  DEFAULT_MB_MACRX_LOW_WATER_5705  0x00000010
-#define  DEFAULT_MB_MACRX_LOW_WATER_JUMBO 0x00000098
-#define BUFMGR_MB_HIGH_WATER		0x00004418
-#define  DEFAULT_MB_HIGH_WATER		 0x00000060
-#define  DEFAULT_MB_HIGH_WATER_5705	 0x00000060
-#define  DEFAULT_MB_HIGH_WATER_JUMBO	 0x0000017c
-#define BUFMGR_RX_MB_ALLOC_REQ		0x0000441c
-#define  BUFMGR_MB_ALLOC_BIT		 0x10000000
-#define BUFMGR_RX_MB_ALLOC_RESP		0x00004420
-#define BUFMGR_TX_MB_ALLOC_REQ		0x00004424
-#define BUFMGR_TX_MB_ALLOC_RESP		0x00004428
-#define BUFMGR_DMA_DESC_POOL_ADDR	0x0000442c
-#define BUFMGR_DMA_DESC_POOL_SIZE	0x00004430
-#define BUFMGR_DMA_LOW_WATER		0x00004434
-#define  DEFAULT_DMA_LOW_WATER		 0x00000005
-#define BUFMGR_DMA_HIGH_WATER		0x00004438
-#define  DEFAULT_DMA_HIGH_WATER		 0x0000000a
-#define BUFMGR_RX_DMA_ALLOC_REQ		0x0000443c
-#define BUFMGR_RX_DMA_ALLOC_RESP	0x00004440
-#define BUFMGR_TX_DMA_ALLOC_REQ		0x00004444
-#define BUFMGR_TX_DMA_ALLOC_RESP	0x00004448
-#define BUFMGR_HWDIAG_0			0x0000444c
-#define BUFMGR_HWDIAG_1			0x00004450
-#define BUFMGR_HWDIAG_2			0x00004454
-/* 0x4458 --> 0x4800 unused */
-
-/* Read DMA control registers */
-#define RDMAC_MODE			0x00004800
-#define  RDMAC_MODE_RESET		 0x00000001
-#define  RDMAC_MODE_ENABLE		 0x00000002
-#define  RDMAC_MODE_TGTABORT_ENAB	 0x00000004
-#define  RDMAC_MODE_MSTABORT_ENAB	 0x00000008
-#define  RDMAC_MODE_PARITYERR_ENAB	 0x00000010
-#define  RDMAC_MODE_ADDROFLOW_ENAB	 0x00000020
-#define  RDMAC_MODE_FIFOOFLOW_ENAB	 0x00000040
-#define  RDMAC_MODE_FIFOURUN_ENAB	 0x00000080
-#define  RDMAC_MODE_FIFOOREAD_ENAB	 0x00000100
-#define  RDMAC_MODE_LNGREAD_ENAB	 0x00000200
-#define  RDMAC_MODE_SPLIT_ENABLE	 0x00000800
-#define  RDMAC_MODE_SPLIT_RESET		 0x00001000
-#define  RDMAC_MODE_FIFO_SIZE_128	 0x00020000
-#define  RDMAC_MODE_FIFO_LONG_BURST	 0x00030000
-#define RDMAC_STATUS			0x00004804
-#define  RDMAC_STATUS_TGTABORT		 0x00000004
-#define  RDMAC_STATUS_MSTABORT		 0x00000008
-#define  RDMAC_STATUS_PARITYERR		 0x00000010
-#define  RDMAC_STATUS_ADDROFLOW		 0x00000020
-#define  RDMAC_STATUS_FIFOOFLOW		 0x00000040
-#define  RDMAC_STATUS_FIFOURUN		 0x00000080
-#define  RDMAC_STATUS_FIFOOREAD		 0x00000100
-#define  RDMAC_STATUS_LNGREAD		 0x00000200
-/* 0x4808 --> 0x4c00 unused */
-
-/* Write DMA control registers */
-#define WDMAC_MODE			0x00004c00
-#define  WDMAC_MODE_RESET		 0x00000001
-#define  WDMAC_MODE_ENABLE		 0x00000002
-#define  WDMAC_MODE_TGTABORT_ENAB	 0x00000004
-#define  WDMAC_MODE_MSTABORT_ENAB	 0x00000008
-#define  WDMAC_MODE_PARITYERR_ENAB	 0x00000010
-#define  WDMAC_MODE_ADDROFLOW_ENAB	 0x00000020
-#define  WDMAC_MODE_FIFOOFLOW_ENAB	 0x00000040
-#define  WDMAC_MODE_FIFOURUN_ENAB	 0x00000080
-#define  WDMAC_MODE_FIFOOREAD_ENAB	 0x00000100
-#define  WDMAC_MODE_LNGREAD_ENAB	 0x00000200
-#define  WDMAC_MODE_RX_ACCEL	 	 0x00000400
-#define WDMAC_STATUS			0x00004c04
-#define  WDMAC_STATUS_TGTABORT		 0x00000004
-#define  WDMAC_STATUS_MSTABORT		 0x00000008
-#define  WDMAC_STATUS_PARITYERR		 0x00000010
-#define  WDMAC_STATUS_ADDROFLOW		 0x00000020
-#define  WDMAC_STATUS_FIFOOFLOW		 0x00000040
-#define  WDMAC_STATUS_FIFOURUN		 0x00000080
-#define  WDMAC_STATUS_FIFOOREAD		 0x00000100
-#define  WDMAC_STATUS_LNGREAD		 0x00000200
-/* 0x4c08 --> 0x5000 unused */
-
-/* Per-cpu register offsets (arm9) */
-#define CPU_MODE			0x00000000
-#define  CPU_MODE_RESET			 0x00000001
-#define  CPU_MODE_HALT			 0x00000400
-#define CPU_STATE			0x00000004
-#define CPU_EVTMASK			0x00000008
-/* 0xc --> 0x1c reserved */
-#define CPU_PC				0x0000001c
-#define CPU_INSN			0x00000020
-#define CPU_SPAD_UFLOW			0x00000024
-#define CPU_WDOG_CLEAR			0x00000028
-#define CPU_WDOG_VECTOR			0x0000002c
-#define CPU_WDOG_PC			0x00000030
-#define CPU_HW_BP			0x00000034
-/* 0x38 --> 0x44 unused */
-#define CPU_WDOG_SAVED_STATE		0x00000044
-#define CPU_LAST_BRANCH_ADDR		0x00000048
-#define CPU_SPAD_UFLOW_SET		0x0000004c
-/* 0x50 --> 0x200 unused */
-#define CPU_R0				0x00000200
-#define CPU_R1				0x00000204
-#define CPU_R2				0x00000208
-#define CPU_R3				0x0000020c
-#define CPU_R4				0x00000210
-#define CPU_R5				0x00000214
-#define CPU_R6				0x00000218
-#define CPU_R7				0x0000021c
-#define CPU_R8				0x00000220
-#define CPU_R9				0x00000224
-#define CPU_R10				0x00000228
-#define CPU_R11				0x0000022c
-#define CPU_R12				0x00000230
-#define CPU_R13				0x00000234
-#define CPU_R14				0x00000238
-#define CPU_R15				0x0000023c
-#define CPU_R16				0x00000240
-#define CPU_R17				0x00000244
-#define CPU_R18				0x00000248
-#define CPU_R19				0x0000024c
-#define CPU_R20				0x00000250
-#define CPU_R21				0x00000254
-#define CPU_R22				0x00000258
-#define CPU_R23				0x0000025c
-#define CPU_R24				0x00000260
-#define CPU_R25				0x00000264
-#define CPU_R26				0x00000268
-#define CPU_R27				0x0000026c
-#define CPU_R28				0x00000270
-#define CPU_R29				0x00000274
-#define CPU_R30				0x00000278
-#define CPU_R31				0x0000027c
-/* 0x280 --> 0x400 unused */
-
-#define RX_CPU_BASE			0x00005000
-#define TX_CPU_BASE			0x00005400
-
-/* Mailboxes */
-#define GRCMBOX_INTERRUPT_0		0x00005800 /* 64-bit */
-#define GRCMBOX_INTERRUPT_1		0x00005808 /* 64-bit */
-#define GRCMBOX_INTERRUPT_2		0x00005810 /* 64-bit */
-#define GRCMBOX_INTERRUPT_3		0x00005818 /* 64-bit */
-#define GRCMBOX_GENERAL_0		0x00005820 /* 64-bit */
-#define GRCMBOX_GENERAL_1		0x00005828 /* 64-bit */
-#define GRCMBOX_GENERAL_2		0x00005830 /* 64-bit */
-#define GRCMBOX_GENERAL_3		0x00005838 /* 64-bit */
-#define GRCMBOX_GENERAL_4		0x00005840 /* 64-bit */
-#define GRCMBOX_GENERAL_5		0x00005848 /* 64-bit */
-#define GRCMBOX_GENERAL_6		0x00005850 /* 64-bit */
-#define GRCMBOX_GENERAL_7		0x00005858 /* 64-bit */
-#define GRCMBOX_RELOAD_STAT		0x00005860 /* 64-bit */
-#define GRCMBOX_RCVSTD_PROD_IDX		0x00005868 /* 64-bit */
-#define GRCMBOX_RCVJUMBO_PROD_IDX	0x00005870 /* 64-bit */
-#define GRCMBOX_RCVMINI_PROD_IDX	0x00005878 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_0	0x00005880 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_1	0x00005888 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_2	0x00005890 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_3	0x00005898 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_4	0x000058a0 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_5	0x000058a8 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_6	0x000058b0 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_7	0x000058b8 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_8	0x000058c0 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_9	0x000058c8 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_10	0x000058d0 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_11	0x000058d8 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_12	0x000058e0 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_13	0x000058e8 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_14	0x000058f0 /* 64-bit */
-#define GRCMBOX_RCVRET_CON_IDX_15	0x000058f8 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_0	0x00005900 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_1	0x00005908 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_2	0x00005910 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_3	0x00005918 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_4	0x00005920 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_5	0x00005928 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_6	0x00005930 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_7	0x00005938 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_8	0x00005940 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_9	0x00005948 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_10	0x00005950 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_11	0x00005958 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_12	0x00005960 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_13	0x00005968 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_14	0x00005970 /* 64-bit */
-#define GRCMBOX_SNDHOST_PROD_IDX_15	0x00005978 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_0	0x00005980 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_1	0x00005988 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_2	0x00005990 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_3	0x00005998 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_4	0x000059a0 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_5	0x000059a8 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_6	0x000059b0 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_7	0x000059b8 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_8	0x000059c0 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_9	0x000059c8 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_10	0x000059d0 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_11	0x000059d8 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_12	0x000059e0 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_13	0x000059e8 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_14	0x000059f0 /* 64-bit */
-#define GRCMBOX_SNDNIC_PROD_IDX_15	0x000059f8 /* 64-bit */
-#define GRCMBOX_HIGH_PRIO_EV_VECTOR	0x00005a00
-#define GRCMBOX_HIGH_PRIO_EV_MASK	0x00005a04
-#define GRCMBOX_LOW_PRIO_EV_VEC		0x00005a08
-#define GRCMBOX_LOW_PRIO_EV_MASK	0x00005a0c
-/* 0x5a10 --> 0x5c00 */
-
-/* Flow Through queues */
-#define FTQ_RESET			0x00005c00
-#define FTQ_RESET_DMA_READ_QUEUE	(1 << 1)
-#define FTQ_RESET_DMA_HIGH_PRI_READ	(1 << 2)
-#define FTQ_RESET_SEND_BD_COMPLETION	(1 << 4)
-#define FTQ_RESET_DMA_WRITE		(1 << 6)
-#define FTQ_RESET_DMA_HIGH_PRI_WRITE	(1 << 7)
-#define FTQ_RESET_SEND_DATA_COMPLETION	(1 << 9)
-#define FTQ_RESET_HOST_COALESCING	(1 << 10)
-#define FTQ_RESET_MAC_TX		(1 << 11)
-#define FTQ_RESET_RX_BD_COMPLETE	(1 << 13)
-#define FTQ_RESET_RX_LIST_PLCMT		(1 << 14)
-#define FTQ_RESET_RX_DATA_COMPLETION	(1 << 16)
-/* 0x5c04 --> 0x5c10 unused */
-#define FTQ_DMA_NORM_READ_CTL		0x00005c10
-#define FTQ_DMA_NORM_READ_FULL_CNT	0x00005c14
-#define FTQ_DMA_NORM_READ_FIFO_ENQDEQ	0x00005c18
-#define FTQ_DMA_NORM_READ_WRITE_PEEK	0x00005c1c
-#define FTQ_DMA_HIGH_READ_CTL		0x00005c20
-#define FTQ_DMA_HIGH_READ_FULL_CNT	0x00005c24
-#define FTQ_DMA_HIGH_READ_FIFO_ENQDEQ	0x00005c28
-#define FTQ_DMA_HIGH_READ_WRITE_PEEK	0x00005c2c
-#define FTQ_DMA_COMP_DISC_CTL		0x00005c30
-#define FTQ_DMA_COMP_DISC_FULL_CNT	0x00005c34
-#define FTQ_DMA_COMP_DISC_FIFO_ENQDEQ	0x00005c38
-#define FTQ_DMA_COMP_DISC_WRITE_PEEK	0x00005c3c
-#define FTQ_SEND_BD_COMP_CTL		0x00005c40
-#define FTQ_SEND_BD_COMP_FULL_CNT	0x00005c44
-#define FTQ_SEND_BD_COMP_FIFO_ENQDEQ	0x00005c48
-#define FTQ_SEND_BD_COMP_WRITE_PEEK	0x00005c4c
-#define FTQ_SEND_DATA_INIT_CTL		0x00005c50
-#define FTQ_SEND_DATA_INIT_FULL_CNT	0x00005c54
-#define FTQ_SEND_DATA_INIT_FIFO_ENQDEQ	0x00005c58
-#define FTQ_SEND_DATA_INIT_WRITE_PEEK	0x00005c5c
-#define FTQ_DMA_NORM_WRITE_CTL		0x00005c60
-#define FTQ_DMA_NORM_WRITE_FULL_CNT	0x00005c64
-#define FTQ_DMA_NORM_WRITE_FIFO_ENQDEQ	0x00005c68
-#define FTQ_DMA_NORM_WRITE_WRITE_PEEK	0x00005c6c
-#define FTQ_DMA_HIGH_WRITE_CTL		0x00005c70
-#define FTQ_DMA_HIGH_WRITE_FULL_CNT	0x00005c74
-#define FTQ_DMA_HIGH_WRITE_FIFO_ENQDEQ	0x00005c78
-#define FTQ_DMA_HIGH_WRITE_WRITE_PEEK	0x00005c7c
-#define FTQ_SWTYPE1_CTL			0x00005c80
-#define FTQ_SWTYPE1_FULL_CNT		0x00005c84
-#define FTQ_SWTYPE1_FIFO_ENQDEQ		0x00005c88
-#define FTQ_SWTYPE1_WRITE_PEEK		0x00005c8c
-#define FTQ_SEND_DATA_COMP_CTL		0x00005c90
-#define FTQ_SEND_DATA_COMP_FULL_CNT	0x00005c94
-#define FTQ_SEND_DATA_COMP_FIFO_ENQDEQ	0x00005c98
-#define FTQ_SEND_DATA_COMP_WRITE_PEEK	0x00005c9c
-#define FTQ_HOST_COAL_CTL		0x00005ca0
-#define FTQ_HOST_COAL_FULL_CNT		0x00005ca4
-#define FTQ_HOST_COAL_FIFO_ENQDEQ	0x00005ca8
-#define FTQ_HOST_COAL_WRITE_PEEK	0x00005cac
-#define FTQ_MAC_TX_CTL			0x00005cb0
-#define FTQ_MAC_TX_FULL_CNT		0x00005cb4
-#define FTQ_MAC_TX_FIFO_ENQDEQ		0x00005cb8
-#define FTQ_MAC_TX_WRITE_PEEK		0x00005cbc
-#define FTQ_MB_FREE_CTL			0x00005cc0
-#define FTQ_MB_FREE_FULL_CNT		0x00005cc4
-#define FTQ_MB_FREE_FIFO_ENQDEQ		0x00005cc8
-#define FTQ_MB_FREE_WRITE_PEEK		0x00005ccc
-#define FTQ_RCVBD_COMP_CTL		0x00005cd0
-#define FTQ_RCVBD_COMP_FULL_CNT		0x00005cd4
-#define FTQ_RCVBD_COMP_FIFO_ENQDEQ	0x00005cd8
-#define FTQ_RCVBD_COMP_WRITE_PEEK	0x00005cdc
-#define FTQ_RCVLST_PLMT_CTL		0x00005ce0
-#define FTQ_RCVLST_PLMT_FULL_CNT	0x00005ce4
-#define FTQ_RCVLST_PLMT_FIFO_ENQDEQ	0x00005ce8
-#define FTQ_RCVLST_PLMT_WRITE_PEEK	0x00005cec
-#define FTQ_RCVDATA_INI_CTL		0x00005cf0
-#define FTQ_RCVDATA_INI_FULL_CNT	0x00005cf4
-#define FTQ_RCVDATA_INI_FIFO_ENQDEQ	0x00005cf8
-#define FTQ_RCVDATA_INI_WRITE_PEEK	0x00005cfc
-#define FTQ_RCVDATA_COMP_CTL		0x00005d00
-#define FTQ_RCVDATA_COMP_FULL_CNT	0x00005d04
-#define FTQ_RCVDATA_COMP_FIFO_ENQDEQ	0x00005d08
-#define FTQ_RCVDATA_COMP_WRITE_PEEK	0x00005d0c
-#define FTQ_SWTYPE2_CTL			0x00005d10
-#define FTQ_SWTYPE2_FULL_CNT		0x00005d14
-#define FTQ_SWTYPE2_FIFO_ENQDEQ		0x00005d18
-#define FTQ_SWTYPE2_WRITE_PEEK		0x00005d1c
-/* 0x5d20 --> 0x6000 unused */
-
-/* Message signaled interrupt registers */
-#define MSGINT_MODE			0x00006000
-#define  MSGINT_MODE_RESET		 0x00000001
-#define  MSGINT_MODE_ENABLE		 0x00000002
-#define MSGINT_STATUS			0x00006004
-#define MSGINT_FIFO			0x00006008
-/* 0x600c --> 0x6400 unused */
-
-/* DMA completion registers */
-#define DMAC_MODE			0x00006400
-#define  DMAC_MODE_RESET		 0x00000001
-#define  DMAC_MODE_ENABLE		 0x00000002
-/* 0x6404 --> 0x6800 unused */
-
-/* GRC registers */
-#define GRC_MODE			0x00006800
-#define  GRC_MODE_UPD_ON_COAL		0x00000001
-#define  GRC_MODE_BSWAP_NONFRM_DATA	0x00000002
-#define  GRC_MODE_WSWAP_NONFRM_DATA	0x00000004
-#define  GRC_MODE_BSWAP_DATA		0x00000010
-#define  GRC_MODE_WSWAP_DATA		0x00000020
-#define  GRC_MODE_SPLITHDR		0x00000100
-#define  GRC_MODE_NOFRM_CRACKING	0x00000200
-#define  GRC_MODE_INCL_CRC		0x00000400
-#define  GRC_MODE_ALLOW_BAD_FRMS	0x00000800
-#define  GRC_MODE_NOIRQ_ON_SENDS	0x00002000
-#define  GRC_MODE_NOIRQ_ON_RCV		0x00004000
-#define  GRC_MODE_FORCE_PCI32BIT	0x00008000
-#define  GRC_MODE_HOST_STACKUP		0x00010000
-#define  GRC_MODE_HOST_SENDBDS		0x00020000
-#define  GRC_MODE_NO_TX_PHDR_CSUM	0x00100000
-#define  GRC_MODE_NO_RX_PHDR_CSUM	0x00800000
-#define  GRC_MODE_IRQ_ON_TX_CPU_ATTN	0x01000000
-#define  GRC_MODE_IRQ_ON_RX_CPU_ATTN	0x02000000
-#define  GRC_MODE_IRQ_ON_MAC_ATTN	0x04000000
-#define  GRC_MODE_IRQ_ON_DMA_ATTN	0x08000000
-#define  GRC_MODE_IRQ_ON_FLOW_ATTN	0x10000000
-#define  GRC_MODE_4X_NIC_SEND_RINGS	0x20000000
-#define  GRC_MODE_MCAST_FRM_ENABLE	0x40000000
-#define GRC_MISC_CFG			0x00006804
-#define  GRC_MISC_CFG_CORECLK_RESET	0x00000001
-#define  GRC_MISC_CFG_PRESCALAR_MASK	0x000000fe
-#define  GRC_MISC_CFG_PRESCALAR_SHIFT	1
-#define  GRC_MISC_CFG_BOARD_ID_MASK	0x0001e000
-#define  GRC_MISC_CFG_BOARD_ID_5700	0x0001e000
-#define  GRC_MISC_CFG_BOARD_ID_5701	0x00000000
-#define  GRC_MISC_CFG_BOARD_ID_5702FE	0x00004000
-#define  GRC_MISC_CFG_BOARD_ID_5703	0x00000000
-#define  GRC_MISC_CFG_BOARD_ID_5703S	0x00002000
-#define  GRC_MISC_CFG_BOARD_ID_5704	0x00000000
-#define  GRC_MISC_CFG_BOARD_ID_5704CIOBE 0x00004000
-#define  GRC_MISC_CFG_BOARD_ID_5704_A2	0x00008000
-#define  GRC_MISC_CFG_BOARD_ID_5788	0x00010000
-#define  GRC_MISC_CFG_BOARD_ID_5788M	0x00018000
-#define  GRC_MISC_CFG_BOARD_ID_AC91002A1 0x00018000
-#define  GRC_MISC_CFG_KEEP_GPHY_POWER	0x04000000
-#define GRC_LOCAL_CTRL			0x00006808
-#define  GRC_LCLCTRL_INT_ACTIVE		0x00000001
-#define  GRC_LCLCTRL_CLEARINT		0x00000002
-#define  GRC_LCLCTRL_SETINT		0x00000004
-#define  GRC_LCLCTRL_INT_ON_ATTN	0x00000008
-#define  GRC_LCLCTRL_GPIO_INPUT0	0x00000100
-#define  GRC_LCLCTRL_GPIO_INPUT1	0x00000200
-#define  GRC_LCLCTRL_GPIO_INPUT2	0x00000400
-#define  GRC_LCLCTRL_GPIO_OE0		0x00000800
-#define  GRC_LCLCTRL_GPIO_OE1		0x00001000
-#define  GRC_LCLCTRL_GPIO_OE2		0x00002000
-#define  GRC_LCLCTRL_GPIO_OUTPUT0	0x00004000
-#define  GRC_LCLCTRL_GPIO_OUTPUT1	0x00008000
-#define  GRC_LCLCTRL_GPIO_OUTPUT2	0x00010000
-#define  GRC_LCLCTRL_EXTMEM_ENABLE	0x00020000
-#define  GRC_LCLCTRL_MEMSZ_MASK		0x001c0000
-#define  GRC_LCLCTRL_MEMSZ_256K		0x00000000
-#define  GRC_LCLCTRL_MEMSZ_512K		0x00040000
-#define  GRC_LCLCTRL_MEMSZ_1M		0x00080000
-#define  GRC_LCLCTRL_MEMSZ_2M		0x000c0000
-#define  GRC_LCLCTRL_MEMSZ_4M		0x00100000
-#define  GRC_LCLCTRL_MEMSZ_8M		0x00140000
-#define  GRC_LCLCTRL_MEMSZ_16M		0x00180000
-#define  GRC_LCLCTRL_BANK_SELECT	0x00200000
-#define  GRC_LCLCTRL_SSRAM_TYPE		0x00400000
-#define  GRC_LCLCTRL_AUTO_SEEPROM	0x01000000
-#define GRC_TIMER			0x0000680c
-#define GRC_RX_CPU_EVENT		0x00006810
-#define GRC_RX_TIMER_REF		0x00006814
-#define GRC_RX_CPU_SEM			0x00006818
-#define GRC_REMOTE_RX_CPU_ATTN		0x0000681c
-#define GRC_TX_CPU_EVENT		0x00006820
-#define GRC_TX_TIMER_REF		0x00006824
-#define GRC_TX_CPU_SEM			0x00006828
-#define GRC_REMOTE_TX_CPU_ATTN		0x0000682c
-#define GRC_MEM_POWER_UP		0x00006830 /* 64-bit */
-#define GRC_EEPROM_ADDR			0x00006838
-#define  EEPROM_ADDR_WRITE		0x00000000
-#define  EEPROM_ADDR_READ		0x80000000
-#define  EEPROM_ADDR_COMPLETE		0x40000000
-#define  EEPROM_ADDR_FSM_RESET		0x20000000
-#define  EEPROM_ADDR_DEVID_MASK		0x1c000000
-#define  EEPROM_ADDR_DEVID_SHIFT	26
-#define  EEPROM_ADDR_START		0x02000000
-#define  EEPROM_ADDR_CLKPERD_SHIFT	16
-#define  EEPROM_ADDR_ADDR_MASK		0x0000ffff
-#define  EEPROM_ADDR_ADDR_SHIFT		0
-#define  EEPROM_DEFAULT_CLOCK_PERIOD	0x60
-#define  EEPROM_CHIP_SIZE		(64 * 1024)
-#define GRC_EEPROM_DATA			0x0000683c
-#define GRC_EEPROM_CTRL			0x00006840
-#define GRC_MDI_CTRL			0x00006844
-#define GRC_SEEPROM_DELAY		0x00006848
-/* 0x684c --> 0x6c00 unused */
-
-/* 0x6c00 --> 0x7000 unused */
-
-/* NVRAM Control registers */
-#define NVRAM_CMD			0x00007000
-#define  NVRAM_CMD_RESET		 0x00000001
-#define  NVRAM_CMD_DONE			 0x00000008
-#define  NVRAM_CMD_GO			 0x00000010
-#define  NVRAM_CMD_WR			 0x00000020
-#define  NVRAM_CMD_RD			 0x00000000
-#define  NVRAM_CMD_ERASE		 0x00000040
-#define  NVRAM_CMD_FIRST		 0x00000080
-#define  NVRAM_CMD_LAST			 0x00000100
-#define NVRAM_STAT			0x00007004
-#define NVRAM_WRDATA			0x00007008
-#define NVRAM_ADDR			0x0000700c
-#define  NVRAM_ADDR_MSK			0x00ffffff
-#define NVRAM_RDDATA			0x00007010
-#define NVRAM_CFG1			0x00007014
-#define  NVRAM_CFG1_FLASHIF_ENAB	 0x00000001
-#define  NVRAM_CFG1_BUFFERED_MODE	 0x00000002
-#define  NVRAM_CFG1_PASS_THRU		 0x00000004
-#define  NVRAM_CFG1_BIT_BANG		 0x00000008
-#define  NVRAM_CFG1_COMPAT_BYPASS	 0x80000000
-#define NVRAM_CFG2			0x00007018
-#define NVRAM_CFG3			0x0000701c
-#define NVRAM_SWARB			0x00007020
-#define  SWARB_REQ_SET0			 0x00000001
-#define  SWARB_REQ_SET1			 0x00000002
-#define  SWARB_REQ_SET2			 0x00000004
-#define  SWARB_REQ_SET3			 0x00000008
-#define  SWARB_REQ_CLR0			 0x00000010
-#define  SWARB_REQ_CLR1			 0x00000020
-#define  SWARB_REQ_CLR2			 0x00000040
-#define  SWARB_REQ_CLR3			 0x00000080
-#define  SWARB_GNT0			 0x00000100
-#define  SWARB_GNT1			 0x00000200
-#define  SWARB_GNT2			 0x00000400
-#define  SWARB_GNT3			 0x00000800
-#define  SWARB_REQ0			 0x00001000
-#define  SWARB_REQ1			 0x00002000
-#define  SWARB_REQ2			 0x00004000
-#define  SWARB_REQ3			 0x00008000
-#define    NVRAM_BUFFERED_PAGE_SIZE	   264
-#define    NVRAM_BUFFERED_PAGE_POS	   9
-/* 0x7024 --> 0x7400 unused */
-
-/* 0x7400 --> 0x8000 unused */
-
-/* 32K Window into NIC internal memory */
-#define NIC_SRAM_WIN_BASE		0x00008000
-
-/* Offsets into first 32k of NIC internal memory. */
-#define NIC_SRAM_PAGE_ZERO		0x00000000
-#define NIC_SRAM_SEND_RCB		0x00000100 /* 16 * TG3_BDINFO_... */
-#define NIC_SRAM_RCV_RET_RCB		0x00000200 /* 16 * TG3_BDINFO_... */
-#define NIC_SRAM_STATS_BLK		0x00000300
-#define NIC_SRAM_STATUS_BLK		0x00000b00
-
-#define NIC_SRAM_FIRMWARE_MBOX		0x00000b50
-#define  NIC_SRAM_FIRMWARE_MBOX_MAGIC1	 0x4B657654
-#define  NIC_SRAM_FIRMWARE_MBOX_MAGIC2	 0x4861764b /* !dma on linkchg */
-
-#define NIC_SRAM_DATA_SIG		0x00000b54
-#define  NIC_SRAM_DATA_SIG_MAGIC	 0x4b657654 /* ascii for 'KevT' */
-
-#define NIC_SRAM_DATA_CFG			0x00000b58
-#define  NIC_SRAM_DATA_CFG_LED_MODE_MASK	 0x0000000c
-#define  NIC_SRAM_DATA_CFG_LED_MODE_UNKNOWN	 0x00000000
-#define  NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD	 0x00000004
-#define  NIC_SRAM_DATA_CFG_LED_OPEN_DRAIN	 0x00000004
-#define  NIC_SRAM_DATA_CFG_LED_LINK_SPD		 0x00000008
-#define  NIC_SRAM_DATA_CFG_LED_OUTPUT		 0x00000008
-#define  NIC_SRAM_DATA_CFG_PHY_TYPE_MASK	 0x00000030
-#define  NIC_SRAM_DATA_CFG_PHY_TYPE_UNKNOWN	 0x00000000
-#define  NIC_SRAM_DATA_CFG_PHY_TYPE_COPPER	 0x00000010
-#define  NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER	 0x00000020
-#define  NIC_SRAM_DATA_CFG_WOL_ENABLE		 0x00000040
-#define  NIC_SRAM_DATA_CFG_ASF_ENABLE		 0x00000080
-#define  NIC_SRAM_DATA_CFG_EEPROM_WP		 0x00000100
-#define  NIC_SRAM_DATA_CFG_MINI_PCI		 0x00001000
-#define  NIC_SRAM_DATA_CFG_FIBER_WOL		 0x00004000
-
-#define NIC_SRAM_DATA_PHY_ID		0x00000b74
-#define  NIC_SRAM_DATA_PHY_ID1_MASK	 0xffff0000
-#define  NIC_SRAM_DATA_PHY_ID2_MASK	 0x0000ffff
-
-#define NIC_SRAM_FW_CMD_MBOX		0x00000b78
-#define  FWCMD_NICDRV_ALIVE		 0x00000001
-#define  FWCMD_NICDRV_PAUSE_FW		 0x00000002
-#define  FWCMD_NICDRV_IPV4ADDR_CHG	 0x00000003
-#define  FWCMD_NICDRV_IPV6ADDR_CHG	 0x00000004
-#define  FWCMD_NICDRV_FIX_DMAR		 0x00000005
-#define  FWCMD_NICDRV_FIX_DMAW		 0x00000006
-#define NIC_SRAM_FW_CMD_LEN_MBOX	0x00000b7c
-#define NIC_SRAM_FW_CMD_DATA_MBOX	0x00000b80
-#define NIC_SRAM_FW_ASF_STATUS_MBOX	0x00000c00
-#define NIC_SRAM_FW_DRV_STATE_MBOX	0x00000c04
-#define  DRV_STATE_START		 0x00000001
-#define  DRV_STATE_UNLOAD		 0x00000002
-#define  DRV_STATE_WOL			 0x00000003
-#define  DRV_STATE_SUSPEND		 0x00000004
-
-#define NIC_SRAM_FW_RESET_TYPE_MBOX	0x00000c08
-
-#define NIC_SRAM_MAC_ADDR_HIGH_MBOX	0x00000c14
-#define NIC_SRAM_MAC_ADDR_LOW_MBOX	0x00000c18
-
-#define NIC_SRAM_RX_MINI_BUFFER_DESC	0x00001000
-
-#define NIC_SRAM_DMA_DESC_POOL_BASE	0x00002000
-#define  NIC_SRAM_DMA_DESC_POOL_SIZE	 0x00002000
-#define NIC_SRAM_TX_BUFFER_DESC		0x00004000 /* 512 entries */
-#define NIC_SRAM_RX_BUFFER_DESC		0x00006000 /* 256 entries */
-#define NIC_SRAM_RX_JUMBO_BUFFER_DESC	0x00007000 /* 256 entries */
-#define NIC_SRAM_MBUF_POOL_BASE		0x00008000
-#define  NIC_SRAM_MBUF_POOL_SIZE96	 0x00018000
-#define  NIC_SRAM_MBUF_POOL_SIZE64	 0x00010000
-#define  NIC_SRAM_MBUF_POOL_BASE5705	0x00010000
-#define  NIC_SRAM_MBUF_POOL_SIZE5705	0x0000e000
-
-/* Currently this is fixed. */
-#define PHY_ADDR		0x01
-
-/* Tigon3 specific PHY MII registers. */
-#define  TG3_BMCR_SPEED1000		0x0040
-
-#define MII_TG3_CTRL			0x09 /* 1000-baseT control register */
-#define  MII_TG3_CTRL_ADV_1000_HALF	0x0100
-#define  MII_TG3_CTRL_ADV_1000_FULL	0x0200
-#define  MII_TG3_CTRL_AS_MASTER		0x0800
-#define  MII_TG3_CTRL_ENABLE_AS_MASTER	0x1000
-
-#define MII_TG3_EXT_CTRL		0x10 /* Extended control register */
-#define  MII_TG3_EXT_CTRL_LNK3_LED_MODE	0x0002
-#define  MII_TG3_EXT_CTRL_TBI		0x8000
-
-#define MII_TG3_EXT_STAT		0x11 /* Extended status register */
-#define  MII_TG3_EXT_STAT_LPASS		0x0100
-
-#define MII_TG3_DSP_RW_PORT		0x15 /* DSP coefficient read/write port */
-
-#define MII_TG3_DSP_ADDRESS		0x17 /* DSP address register */
-
-#define MII_TG3_AUX_CTRL		0x18 /* auxilliary control register */
-
-#define MII_TG3_AUX_STAT		0x19 /* auxilliary status register */
-#define MII_TG3_AUX_STAT_LPASS		0x0004
-#define MII_TG3_AUX_STAT_SPDMASK	0x0700
-#define MII_TG3_AUX_STAT_10HALF		0x0100
-#define MII_TG3_AUX_STAT_10FULL		0x0200
-#define MII_TG3_AUX_STAT_100HALF	0x0300
-#define MII_TG3_AUX_STAT_100_4		0x0400
-#define MII_TG3_AUX_STAT_100FULL	0x0500
-#define MII_TG3_AUX_STAT_1000HALF	0x0600
-#define MII_TG3_AUX_STAT_1000FULL	0x0700
-
-#define MII_TG3_ISTAT			0x1a /* IRQ status register */
-#define MII_TG3_IMASK			0x1b /* IRQ mask register */
-
-/* ISTAT/IMASK event bits */
-#define MII_TG3_INT_LINKCHG		0x0002
-#define MII_TG3_INT_SPEEDCHG		0x0004
-#define MII_TG3_INT_DUPLEXCHG		0x0008
-#define MII_TG3_INT_ANEG_PAGE_RX	0x0400
-
-
-/* There are two ways to manage the TX descriptors on the tigon3.
- * Either the descriptors are in host DMA'able memory, or they
- * exist only in the cards on-chip SRAM.  All 16 send bds are under
- * the same mode, they may not be configured individually.
- *
- * The mode we use is controlled by TG3_FLAG_HOST_TXDS in tp->tg3_flags.
- *
- * To use host memory TX descriptors:
- *	1) Set GRC_MODE_HOST_SENDBDS in GRC_MODE register.
- *	   Make sure GRC_MODE_4X_NIC_SEND_RINGS is clear.
- *	2) Allocate DMA'able memory.
- *	3) In NIC_SRAM_SEND_RCB (of desired index) of on-chip SRAM:
- *	   a) Set TG3_BDINFO_HOST_ADDR to DMA address of memory
- *	      obtained in step 2
- *	   b) Set TG3_BDINFO_NIC_ADDR to NIC_SRAM_TX_BUFFER_DESC.
- *	   c) Set len field of TG3_BDINFO_MAXLEN_FLAGS to number
- *            of TX descriptors.  Leave flags field clear.
- *	4) Access TX descriptors via host memory.  The chip
- *	   will refetch into local SRAM as needed when producer
- *	   index mailboxes are updated.
- *
- * To use on-chip TX descriptors:
- *	1) Set GRC_MODE_4X_NIC_SEND_RINGS in GRC_MODE register.
- *	   Make sure GRC_MODE_HOST_SENDBDS is clear.
- *	2) In NIC_SRAM_SEND_RCB (of desired index) of on-chip SRAM:
- *	   a) Set TG3_BDINFO_HOST_ADDR to zero.
- *	   b) Set TG3_BDINFO_NIC_ADDR to NIC_SRAM_TX_BUFFER_DESC
- *	   c) TG3_BDINFO_MAXLEN_FLAGS is don't care.
- *	3) Access TX descriptors directly in on-chip SRAM
- *	   using normal {read,write}l().  (and not using
- *         pointer dereferencing of ioremap()'d memory like
- *	   the broken Broadcom driver does)
- *
- * Note that BDINFO_FLAGS_DISABLED should be set in the flags field of
- * TG3_BDINFO_MAXLEN_FLAGS of all unused SEND_RCB indices.
- */
-struct tg3_tx_buffer_desc {
-	uint32_t			addr_hi;
-	uint32_t			addr_lo;
-
-	uint32_t			len_flags;
-#define TXD_FLAG_TCPUDP_CSUM		0x0001
-#define TXD_FLAG_IP_CSUM		0x0002
-#define TXD_FLAG_END			0x0004
-#define TXD_FLAG_IP_FRAG		0x0008
-#define TXD_FLAG_IP_FRAG_END		0x0010
-#define TXD_FLAG_VLAN			0x0040
-#define TXD_FLAG_COAL_NOW		0x0080
-#define TXD_FLAG_CPU_PRE_DMA		0x0100
-#define TXD_FLAG_CPU_POST_DMA		0x0200
-#define TXD_FLAG_ADD_SRC_ADDR		0x1000
-#define TXD_FLAG_CHOOSE_SRC_ADDR	0x6000
-#define TXD_FLAG_NO_CRC			0x8000
-#define TXD_LEN_SHIFT			16
-
-	uint32_t			vlan_tag;
-#define TXD_VLAN_TAG_SHIFT		0
-#define TXD_MSS_SHIFT			16
-};
-
-#define TXD_ADDR			0x00UL /* 64-bit */
-#define TXD_LEN_FLAGS			0x08UL /* 32-bit (upper 16-bits are len) */
-#define TXD_VLAN_TAG			0x0cUL /* 32-bit (upper 16-bits are tag) */
-#define TXD_SIZE			0x10UL
-
-struct tg3_rx_buffer_desc {
-	uint32_t			addr_hi;
-	uint32_t			addr_lo;
-
-	uint32_t			idx_len;
-#define RXD_IDX_MASK	0xffff0000
-#define RXD_IDX_SHIFT	16
-#define RXD_LEN_MASK	0x0000ffff
-#define RXD_LEN_SHIFT	0
-
-	uint32_t			type_flags;
-#define RXD_TYPE_SHIFT	16
-#define RXD_FLAGS_SHIFT	0
-
-#define RXD_FLAG_END			0x0004
-#define RXD_FLAG_MINI			0x0800
-#define RXD_FLAG_JUMBO			0x0020
-#define RXD_FLAG_VLAN			0x0040
-#define RXD_FLAG_ERROR			0x0400
-#define RXD_FLAG_IP_CSUM		0x1000
-#define RXD_FLAG_TCPUDP_CSUM		0x2000
-#define RXD_FLAG_IS_TCP			0x4000
-
-	uint32_t			ip_tcp_csum;
-#define RXD_IPCSUM_MASK		0xffff0000
-#define RXD_IPCSUM_SHIFT	16
-#define RXD_TCPCSUM_MASK	0x0000ffff
-#define RXD_TCPCSUM_SHIFT	0
-
-	uint32_t			err_vlan;
-
-#define RXD_VLAN_MASK			0x0000ffff
-
-#define RXD_ERR_BAD_CRC			0x00010000
-#define RXD_ERR_COLLISION		0x00020000
-#define RXD_ERR_LINK_LOST		0x00040000
-#define RXD_ERR_PHY_DECODE		0x00080000
-#define RXD_ERR_ODD_NIBBLE_RCVD_MII	0x00100000
-#define RXD_ERR_MAC_ABRT		0x00200000
-#define RXD_ERR_TOO_SMALL		0x00400000
-#define RXD_ERR_NO_RESOURCES		0x00800000
-#define RXD_ERR_HUGE_FRAME		0x01000000
-#define RXD_ERR_MASK			0xffff0000
-
-	uint32_t			reserved;
-	uint32_t			opaque;
-#define RXD_OPAQUE_INDEX_MASK		0x0000ffff
-#define RXD_OPAQUE_INDEX_SHIFT		0
-#define RXD_OPAQUE_RING_STD		0x00010000
-#define RXD_OPAQUE_RING_JUMBO		0x00020000
-#define RXD_OPAQUE_RING_MINI		0x00040000
-#define RXD_OPAQUE_RING_MASK		0x00070000
-};
-
-struct tg3_ext_rx_buffer_desc {
-	struct {
-		uint32_t		addr_hi;
-		uint32_t		addr_lo;
-	}				addrlist[3];
-	uint32_t			len2_len1;
-	uint32_t			resv_len3;
-	struct tg3_rx_buffer_desc	std;
-};
-
-/* We only use this when testing out the DMA engine
- * at probe time.  This is the internal format of buffer
- * descriptors used by the chip at NIC_SRAM_DMA_DESCS.
- */
-struct tg3_internal_buffer_desc {
-	uint32_t			addr_hi;
-	uint32_t			addr_lo;
-	uint32_t			nic_mbuf;
-	/* XXX FIX THIS */
-#if __BYTE_ORDER == __BIG_ENDIAN
-	uint16_t			cqid_sqid;
-	uint16_t			len;
-#else
-	uint16_t			len;
-	uint16_t			cqid_sqid;
-#endif
-	uint32_t			flags;
-	uint32_t			__cookie1;
-	uint32_t			__cookie2;
-	uint32_t			__cookie3;
-};
-
-#define TG3_HW_STATUS_SIZE		0x50
-struct tg3_hw_status {
-	uint32_t			status;
-#define SD_STATUS_UPDATED		0x00000001
-#define SD_STATUS_LINK_CHG		0x00000002
-#define SD_STATUS_ERROR			0x00000004
-
-	uint32_t			status_tag;
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-	uint16_t			rx_consumer;
-	uint16_t			rx_jumbo_consumer;
-#else
-	uint16_t			rx_jumbo_consumer;
-	uint16_t			rx_consumer;
-#endif
-
-#if __BYTE_ORDER ==  __BIG_ENDIAN
-	uint16_t			reserved;
-	uint16_t			rx_mini_consumer;
-#else
-	uint16_t			rx_mini_consumer;
-	uint16_t			reserved;
-#endif
-	struct {
-#if __BYTE_ORDER ==  __BIG_ENDIAN
-		uint16_t		tx_consumer;
-		uint16_t		rx_producer;
-#else
-		uint16_t		rx_producer;
-		uint16_t		tx_consumer;
-#endif
-	}				idx[16];
-};
-
-typedef struct {
-	uint32_t high, low;
-} tg3_stat64_t;
-
-struct tg3_hw_stats {
-	uint8_t				__reserved0[0x400-0x300];
-
-	/* Statistics maintained by Receive MAC. */
-	tg3_stat64_t			rx_octets;
-	uint64_t			__reserved1;
-	tg3_stat64_t			rx_fragments;
-	tg3_stat64_t			rx_ucast_packets;
-	tg3_stat64_t			rx_mcast_packets;
-	tg3_stat64_t			rx_bcast_packets;
-	tg3_stat64_t			rx_fcs_errors;
-	tg3_stat64_t			rx_align_errors;
-	tg3_stat64_t			rx_xon_pause_rcvd;
-	tg3_stat64_t			rx_xoff_pause_rcvd;
-	tg3_stat64_t			rx_mac_ctrl_rcvd;
-	tg3_stat64_t			rx_xoff_entered;
-	tg3_stat64_t			rx_frame_too_long_errors;
-	tg3_stat64_t			rx_jabbers;
-	tg3_stat64_t			rx_undersize_packets;
-	tg3_stat64_t			rx_in_length_errors;
-	tg3_stat64_t			rx_out_length_errors;
-	tg3_stat64_t			rx_64_or_less_octet_packets;
-	tg3_stat64_t			rx_65_to_127_octet_packets;
-	tg3_stat64_t			rx_128_to_255_octet_packets;
-	tg3_stat64_t			rx_256_to_511_octet_packets;
-	tg3_stat64_t			rx_512_to_1023_octet_packets;
-	tg3_stat64_t			rx_1024_to_1522_octet_packets;
-	tg3_stat64_t			rx_1523_to_2047_octet_packets;
-	tg3_stat64_t			rx_2048_to_4095_octet_packets;
-	tg3_stat64_t			rx_4096_to_8191_octet_packets;
-	tg3_stat64_t			rx_8192_to_9022_octet_packets;
-
-	uint64_t			__unused0[37];
-
-	/* Statistics maintained by Transmit MAC. */
-	tg3_stat64_t			tx_octets;
-	uint64_t			__reserved2;
-	tg3_stat64_t			tx_collisions;
-	tg3_stat64_t			tx_xon_sent;
-	tg3_stat64_t			tx_xoff_sent;
-	tg3_stat64_t			tx_flow_control;
-	tg3_stat64_t			tx_mac_errors;
-	tg3_stat64_t			tx_single_collisions;
-	tg3_stat64_t			tx_mult_collisions;
-	tg3_stat64_t			tx_deferred;
-	uint64_t			__reserved3;
-	tg3_stat64_t			tx_excessive_collisions;
-	tg3_stat64_t			tx_late_collisions;
-	tg3_stat64_t			tx_collide_2times;
-	tg3_stat64_t			tx_collide_3times;
-	tg3_stat64_t			tx_collide_4times;
-	tg3_stat64_t			tx_collide_5times;
-	tg3_stat64_t			tx_collide_6times;
-	tg3_stat64_t			tx_collide_7times;
-	tg3_stat64_t			tx_collide_8times;
-	tg3_stat64_t			tx_collide_9times;
-	tg3_stat64_t			tx_collide_10times;
-	tg3_stat64_t			tx_collide_11times;
-	tg3_stat64_t			tx_collide_12times;
-	tg3_stat64_t			tx_collide_13times;
-	tg3_stat64_t			tx_collide_14times;
-	tg3_stat64_t			tx_collide_15times;
-	tg3_stat64_t			tx_ucast_packets;
-	tg3_stat64_t			tx_mcast_packets;
-	tg3_stat64_t			tx_bcast_packets;
-	tg3_stat64_t			tx_carrier_sense_errors;
-	tg3_stat64_t			tx_discards;
-	tg3_stat64_t			tx_errors;
-
-	uint64_t			__unused1[31];
-
-	/* Statistics maintained by Receive List Placement. */
-	tg3_stat64_t			COS_rx_packets[16];
-	tg3_stat64_t			COS_rx_filter_dropped;
-	tg3_stat64_t			dma_writeq_full;
-	tg3_stat64_t			dma_write_prioq_full;
-	tg3_stat64_t			rxbds_empty;
-	tg3_stat64_t			rx_discards;
-	tg3_stat64_t			rx_errors;
-	tg3_stat64_t			rx_threshold_hit;
-
-	uint64_t			__unused2[9];
-
-	/* Statistics maintained by Send Data Initiator. */
-	tg3_stat64_t			COS_out_packets[16];
-	tg3_stat64_t			dma_readq_full;
-	tg3_stat64_t			dma_read_prioq_full;
-	tg3_stat64_t			tx_comp_queue_full;
-
-	/* Statistics maintained by Host Coalescing. */
-	tg3_stat64_t			ring_set_send_prod_index;
-	tg3_stat64_t			ring_status_update;
-	tg3_stat64_t			nic_irqs;
-	tg3_stat64_t			nic_avoided_irqs;
-	tg3_stat64_t			nic_tx_threshold_hit;
-
-	uint8_t				__reserved4[0xb00-0x9c0];
-};
-
-enum phy_led_mode {
-	led_mode_auto,
-	led_mode_three_link,
-	led_mode_link10
-};
-
-#if 0
-/* 'mapping' is superfluous as the chip does not write into
- * the tx/rx post rings so we could just fetch it from there.
- * But the cache behavior is better how we are doing it now.
- */
-struct ring_info {
-	struct sk_buff			*skb;
-	DECLARE_PCI_UNMAP_ADDR(mapping)
-};
-
-struct tx_ring_info {
-	struct sk_buff			*skb;
-	DECLARE_PCI_UNMAP_ADDR(mapping)
-	uint32_t			prev_vlan_tag;
-};
-#endif
-
-struct tg3_config_info {
-	uint32_t			flags;
-};
-
-struct tg3_link_config {
-	/* Describes what we're trying to get. */
-	uint32_t			advertising;
-#if 0
-	uint16_t			speed;
-	uint8_t				duplex;
-	uint8_t				autoneg;
-#define SPEED_INVALID		0xffff
-#define DUPLEX_INVALID		0xff
-#define AUTONEG_INVALID		0xff
-#endif
-
-	/* Describes what we actually have. */
-	uint8_t				active_speed;
-	uint8_t				active_duplex;
-
-	/* When we go in and out of low power mode we need
-	 * to swap with this state.
-	 */
-#if 0
-	int				phy_is_low_power;
-	uint16_t			orig_speed;
-	uint8_t				orig_duplex;
-	uint8_t				orig_autoneg;
-#endif
-};
-
-struct tg3_bufmgr_config {
-	uint32_t		mbuf_read_dma_low_water;
-	uint32_t		mbuf_mac_rx_low_water;
-	uint32_t		mbuf_high_water;
-
-	uint32_t		mbuf_read_dma_low_water_jumbo;
-	uint32_t		mbuf_mac_rx_low_water_jumbo;
-	uint32_t		mbuf_high_water_jumbo;
-
-	uint32_t		dma_low_water;
-	uint32_t		dma_high_water;
-};
-
-struct tg3 {
-#if 0
-	/* SMP locking strategy:
-	 *
-	 * lock: Held during all operations except TX packet
-	 *       processing.
-	 *
-	 * tx_lock: Held during tg3_start_xmit{,_4gbug} and tg3_tx
-	 *
-	 * If you want to shut up all asynchronous processing you must
-	 * acquire both locks, 'lock' taken before 'tx_lock'.  IRQs must
-	 * be disabled to take 'lock' but only softirq disabling is
-	 * necessary for acquisition of 'tx_lock'.
-	 */
-	spinlock_t			lock;
-	spinlock_t			tx_lock;
-#endif
-
-	uint32_t			tx_prod;
-#if 0
-	uint32_t			tx_cons;
-#endif
-	uint32_t			rx_rcb_ptr;
-	uint32_t			rx_std_ptr;
-#if 0
-	uint32_t			rx_jumbo_ptr;
-	spinlock_t			indirect_lock;
-
-	struct net_device_stats		net_stats;
-	struct net_device_stats		net_stats_prev;
-#endif
-	unsigned long			phy_crc_errors;
-
-#if 0
-	uint32_t			rx_offset;
-#endif
-	uint32_t			tg3_flags;
-#if 0
-#define TG3_FLAG_HOST_TXDS		0x00000001
-#endif
-#define TG3_FLAG_TXD_MBOX_HWBUG		0x00000002
-#define TG3_FLAG_RX_CHECKSUMS		0x00000004
-#define TG3_FLAG_USE_LINKCHG_REG	0x00000008
-#define TG3_FLAG_USE_MI_INTERRUPT	0x00000010
-#define TG3_FLAG_ENABLE_ASF		0x00000020
-#define TG3_FLAG_5701_REG_WRITE_BUG	0x00000040
-#define TG3_FLAG_POLL_SERDES		0x00000080
-#define TG3_FLAG_MBOX_WRITE_REORDER	0x00000100
-#define TG3_FLAG_PCIX_TARGET_HWBUG	0x00000200
-#define TG3_FLAG_WOL_SPEED_100MB	0x00000400
-#define TG3_FLAG_WOL_ENABLE		0x00000800
-#define TG3_FLAG_EEPROM_WRITE_PROT	0x00001000
-#define TG3_FLAG_NVRAM			0x00002000
-#define TG3_FLAG_NVRAM_BUFFERED		0x00004000
-#define TG3_FLAG_RX_PAUSE		0x00008000
-#define TG3_FLAG_TX_PAUSE		0x00010000
-#define TG3_FLAG_PCIX_MODE		0x00020000
-#define TG3_FLAG_PCI_HIGH_SPEED		0x00040000
-#define TG3_FLAG_PCI_32BIT		0x00080000
-#define TG3_FLAG_NO_TX_PSEUDO_CSUM	0x00100000
-#define TG3_FLAG_NO_RX_PSEUDO_CSUM	0x00200000
-#define TG3_FLAG_SERDES_WOL_CAP		0x00400000
-#define TG3_FLAG_JUMBO_ENABLE		0x00800000
-#define TG3_FLAG_10_100_ONLY		0x01000000
-#define TG3_FLAG_PAUSE_AUTONEG		0x02000000
-#define TG3_FLAG_PAUSE_RX		0x04000000
-#define TG3_FLAG_PAUSE_TX		0x08000000
-#define TG3_FLAG_BROKEN_CHECKSUMS	0x10000000
-#define TG3_FLAG_GOT_SERDES_FLOWCTL	0x20000000
-#define TG3_FLAG_SPLIT_MODE		0x40000000
-#define TG3_FLAG_INIT_COMPLETE		0x80000000
-
-	uint32_t			tg3_flags2;
-#define TG3_FLG2_RESTART_TIMER		0x00000001
-#define TG3_FLG2_SUN_5704		0x00000002
-#define TG3_FLG2_NO_ETH_WIRE_SPEED	0x00000004
-#define TG3_FLG2_IS_5788		0x00000008
-#define TG3_FLG2_MAX_RXPEND_64		0x00000010
-#define TG3_FLG2_TSO_CAPABLE		0x00000020
-  // Alf: Hope I'm not breaking anything here !
-#define TG3_FLG2_PCI_EXPRESS            0x00000040
-
-
-
-	uint32_t			split_mode_max_reqs;
-#define SPLIT_MODE_5704_MAX_REQ		3
-
-#if 0
-	struct timer_list		timer;
-	uint16_t			timer_counter;
-	uint16_t			timer_multiplier;
-	uint32_t			timer_offset;
-	uint16_t			asf_counter;
-	uint16_t			asf_multiplier;
-#endif
-
-	struct tg3_link_config		link_config;
-	struct tg3_bufmgr_config	bufmgr_config;
-
-#if 0
-	uint32_t			rx_pending;
-	uint32_t			rx_jumbo_pending;
-	uint32_t			tx_pending;
-#endif
-
-	/* cache h/w values, often passed straight to h/w */
-	uint32_t			rx_mode;
-	uint32_t			tx_mode;
-	uint32_t			mac_mode;
-	uint32_t			mi_mode;
-	uint32_t			misc_host_ctrl;
-	uint32_t			grc_mode;
-	uint32_t			grc_local_ctrl;
-	uint32_t			dma_rwctrl;
-#if 0
-	uint32_t			coalesce_mode;
-#endif
-
-	/* PCI block */
-	uint16_t			pci_chip_rev_id;
-#if 0
-	uint8_t				pci_cacheline_sz;
-	uint8_t				pci_lat_timer;
-	uint8_t				pci_hdr_type;
-	uint8_t				pci_bist;
-#endif
-	uint32_t			pci_cfg_state[64 / sizeof(uint32_t)];
-
-	int				pm_cap;
-
-	/* PHY info */
-	uint32_t			phy_id;
-#define PHY_ID_MASK			0xfffffff0
-#define PHY_ID_BCM5400			0x60008040
-#define PHY_ID_BCM5401			0x60008050
-#define PHY_ID_BCM5411			0x60008070
-#define PHY_ID_BCM5701			0x60008110
-#define PHY_ID_BCM5703			0x60008160
-#define PHY_ID_BCM5704			0x60008190
-#define PHY_ID_BCM5705			0x600081a0
-#define PHY_ID_BCM5750			0x60008180
-#define PHY_ID_BCM5787			0xbc050ce0
-#define PHY_ID_BCM8002			0x60010140
-#define PHY_ID_BCM5751			0x00206180
-#define PHY_ID_SERDES			0xfeedbee0
-#define PHY_ID_INVALID			0xffffffff
-#define PHY_ID_REV_MASK			0x0000000f
-#define PHY_REV_BCM5401_B0		0x1
-#define PHY_REV_BCM5401_B2		0x3
-#define PHY_REV_BCM5401_C0		0x6
-#define PHY_REV_BCM5411_X0		0x1 /* Found on Netgear GA302T */
-
-	enum phy_led_mode		led_mode;
-
-	char				board_part_number[24];
-	uint32_t			nic_sram_data_cfg;
-	uint32_t			pci_clock_ctrl;
-#if 0
-	struct pci_device		*pdev_peer;
-#endif
-
-	/* This macro assumes the passed PHY ID is already masked
-	 * with PHY_ID_MASK.
-	 */
-#define KNOWN_PHY_ID(X)		\
-	((X) == PHY_ID_BCM5400 || (X) == PHY_ID_BCM5401 || \
-	 (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \
-	 (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \
-	 (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \
-	 (X) == PHY_ID_BCM5751 || (X) == PHY_ID_BCM5787 || \
-	 (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES)
-
-	unsigned long			regs;
-	struct pci_device		*pdev;
-	struct nic			*nic;
-#if 0
-	struct net_device		*dev;
-#endif
-#if TG3_VLAN_TAG_USED
-	struct vlan_group		*vlgrp;
-#endif
-
-	struct tg3_rx_buffer_desc	*rx_std;
-#if 0
-	struct ring_info		*rx_std_buffers;
-	dma_addr_t			rx_std_mapping;
-	struct tg3_rx_buffer_desc	*rx_jumbo;
-	struct ring_info		*rx_jumbo_buffers;
-	dma_addr_t			rx_jumbo_mapping;
-#endif
-
-	struct tg3_rx_buffer_desc	*rx_rcb;
-#if 0
-	dma_addr_t			rx_rcb_mapping;
-#endif
-
-	/* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */
-	struct tg3_tx_buffer_desc	*tx_ring;
-#if 0
-	struct tx_ring_info		*tx_buffers;
-	dma_addr_t			tx_desc_mapping;
-#endif
-
-	struct tg3_hw_status		*hw_status;
-#if 0
-	dma_addr_t			status_mapping;
-#endif
-#if 0
-	uint32_t			msg_enable;
-#endif
-
-	struct tg3_hw_stats		*hw_stats;
-#if 0
-	dma_addr_t			stats_mapping;
-#endif
-
-	int				carrier_ok;
-	uint16_t			subsystem_vendor;
-	uint16_t			subsystem_device;
-};
-
-#endif /* !(_T3_H) */
diff --git a/roms/ipxe/src/drivers/net/tg3/tg3.c b/roms/ipxe/src/drivers/net/tg3/tg3.c
new file mode 100644
index 0000000000000000000000000000000000000000..32ca1609c127a2b4c076be1c64972d2c1d2f07bd
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/tg3/tg3.c
@@ -0,0 +1,945 @@
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include <mii.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <ipxe/pci.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/timer.h>
+#include <ipxe/malloc.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/netdevice.h>
+
+#include "tg3.h"
+
+#define TG3_DEF_RX_MODE		0
+#define TG3_DEF_TX_MODE		0
+
+static void tg3_refill_prod_ring(struct tg3 *tp);
+
+/* Do not place this n-ring entries value into the tp struct itself,
+ * we really want to expose these constants to GCC so that modulo et
+ * al.  operations are done with shifts and masks instead of with
+ * hw multiply/modulo instructions.  Another solution would be to
+ * replace things like '% foo' with '& (foo - 1)'.
+ */
+
+#define TG3_TX_RING_BYTES	(sizeof(struct tg3_tx_buffer_desc) * \
+				 TG3_TX_RING_SIZE)
+
+/* FIXME: does TG3_RX_RET_MAX_SIZE_5705 work for all cards? */
+#define TG3_RX_RCB_RING_BYTES(tp) \
+	(sizeof(struct tg3_rx_buffer_desc) * (TG3_RX_RET_MAX_SIZE_5705))
+
+#define TG3_RX_STD_RING_BYTES(tp) \
+	(sizeof(struct tg3_rx_buffer_desc) * TG3_RX_STD_MAX_SIZE_5700)
+
+void tg3_rx_prodring_fini(struct tg3_rx_prodring_set *tpr)
+{	DBGP("%s\n", __func__);
+
+	if (tpr->rx_std) {
+		free_dma(tpr->rx_std, TG3_RX_STD_RING_BYTES(tp));
+		tpr->rx_std = NULL;
+	}
+}
+
+/*
+ * Must not be invoked with interrupt sources disabled and
+ * the hardware shutdown down.
+ */
+static void tg3_free_consistent(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	if (tp->tx_ring) {
+		free_dma(tp->tx_ring, TG3_TX_RING_BYTES);
+		tp->tx_ring = NULL;
+	}
+
+	free(tp->tx_buffers);
+	tp->tx_buffers = NULL;
+
+	if (tp->rx_rcb) {
+		free_dma(tp->rx_rcb, TG3_RX_RCB_RING_BYTES(tp));
+		tp->rx_rcb_mapping = 0;
+		tp->rx_rcb = NULL;
+	}
+
+	tg3_rx_prodring_fini(&tp->prodring);
+
+	if (tp->hw_status) {
+		free_dma(tp->hw_status, TG3_HW_STATUS_SIZE);
+		tp->status_mapping = 0;
+		tp->hw_status = NULL;
+	}
+}
+
+/*
+ * Must not be invoked with interrupt sources disabled and
+ * the hardware shutdown down.  Can sleep.
+ */
+int tg3_alloc_consistent(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	struct tg3_hw_status *sblk;
+	struct tg3_rx_prodring_set *tpr = &tp->prodring;
+
+	tp->hw_status = malloc_dma(TG3_HW_STATUS_SIZE, TG3_DMA_ALIGNMENT);
+	if (!tp->hw_status) {
+		DBGC(tp->dev, "hw_status alloc failed\n");
+		goto err_out;
+	}
+	tp->status_mapping = virt_to_bus(tp->hw_status);
+
+	memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
+	sblk = tp->hw_status;
+
+	tpr->rx_std = malloc_dma(TG3_RX_STD_RING_BYTES(tp), TG3_DMA_ALIGNMENT);
+	if (!tpr->rx_std) {
+		DBGC(tp->dev, "rx prodring alloc failed\n");
+		goto err_out;
+	}
+	tpr->rx_std_mapping = virt_to_bus(tpr->rx_std);
+	memset(tpr->rx_std, 0, TG3_RX_STD_RING_BYTES(tp));
+
+	tp->tx_buffers = zalloc(sizeof(struct ring_info) * TG3_TX_RING_SIZE);
+	if (!tp->tx_buffers)
+		goto err_out;
+
+	tp->tx_ring = malloc_dma(TG3_TX_RING_BYTES, TG3_DMA_ALIGNMENT);
+	if (!tp->tx_ring)
+		goto err_out;
+	tp->tx_desc_mapping = virt_to_bus(tp->tx_ring);
+
+	/*
+	 * When RSS is enabled, the status block format changes
+	 * slightly.  The "rx_jumbo_consumer", "reserved",
+	 * and "rx_mini_consumer" members get mapped to the
+	 * other three rx return ring producer indexes.
+	 */
+
+	tp->rx_rcb_prod_idx = &sblk->idx[0].rx_producer;
+
+	tp->rx_rcb = malloc_dma(TG3_RX_RCB_RING_BYTES(tp), TG3_DMA_ALIGNMENT);
+	if (!tp->rx_rcb)
+		goto err_out;
+	tp->rx_rcb_mapping = virt_to_bus(tp->rx_rcb);
+
+	memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp));
+
+	return 0;
+
+err_out:
+	tg3_free_consistent(tp);
+	return -ENOMEM;
+}
+
+#define TG3_RX_STD_BUFF_RING_BYTES(tp) \
+	(sizeof(struct ring_info) * TG3_RX_STD_MAX_SIZE_5700)
+#define TG3_RX_STD_RING_BYTES(tp) \
+	(sizeof(struct tg3_rx_buffer_desc) * TG3_RX_STD_MAX_SIZE_5700)
+
+/* Initialize rx rings for packet processing.
+ *
+ * The chip has been shut down and the driver detached from
+ * the networking, so no interrupts or new tx packets will
+ * end up in the driver.
+ */
+static int tg3_rx_prodring_alloc(struct tg3 __unused *tp,
+				 struct tg3_rx_prodring_set *tpr)
+{	DBGP("%s\n", __func__);
+
+	u32 i;
+
+	tpr->rx_std_cons_idx = 0;
+	tpr->rx_std_prod_idx = 0;
+
+	/* Initialize invariants of the rings, we only set this
+	 * stuff once.  This works because the card does not
+	 * write into the rx buffer posting rings.
+	 */
+	/* FIXME: does TG3_RX_STD_MAX_SIZE_5700 work on all cards? */
+	for (i = 0; i < TG3_RX_STD_MAX_SIZE_5700; i++) {
+		struct tg3_rx_buffer_desc *rxd;
+
+		rxd = &tpr->rx_std[i];
+		rxd->idx_len = (TG3_RX_STD_DMA_SZ - 64 - 2) << RXD_LEN_SHIFT;
+		rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT);
+		rxd->opaque = (RXD_OPAQUE_RING_STD |
+			       (i << RXD_OPAQUE_INDEX_SHIFT));
+	}
+
+	return 0;
+}
+
+static void tg3_rx_iob_free(struct io_buffer *iobs[], int i)
+{	DBGP("%s\n", __func__);
+
+	if (iobs[i] == NULL)
+		return;
+
+	free_iob(iobs[i]);
+	iobs[i] = NULL;
+}
+
+static void tg3_rx_prodring_free(struct tg3_rx_prodring_set *tpr)
+{	DBGP("%s\n", __func__);
+
+	unsigned int i;
+
+	for (i = 0; i < TG3_DEF_RX_RING_PENDING; i++)
+		tg3_rx_iob_free(tpr->rx_iobufs, i);
+}
+
+/* Initialize tx/rx rings for packet processing.
+ *
+ * The chip has been shut down and the driver detached from
+ * the networking, so no interrupts or new tx packets will
+ * end up in the driver.
+ */
+int tg3_init_rings(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	/* Free up all the SKBs. */
+///	tg3_free_rings(tp);
+
+	tp->last_tag = 0;
+	tp->last_irq_tag = 0;
+	tp->hw_status->status = 0;
+	tp->hw_status->status_tag = 0;
+	memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
+
+	tp->tx_prod = 0;
+	tp->tx_cons = 0;
+	if (tp->tx_ring)
+		memset(tp->tx_ring, 0, TG3_TX_RING_BYTES);
+
+	tp->rx_rcb_ptr = 0;
+	if (tp->rx_rcb)
+		memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp));
+
+	if (tg3_rx_prodring_alloc(tp, &tp->prodring)) {
+		DBGC(tp->dev, "tg3_rx_prodring_alloc() failed\n");
+		tg3_rx_prodring_free(&tp->prodring);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int tg3_open(struct net_device *dev)
+{	DBGP("%s\n", __func__);
+
+	struct tg3 *tp = netdev_priv(dev);
+	struct tg3_rx_prodring_set *tpr = &tp->prodring;
+	int err = 0;
+
+	tg3_set_power_state_0(tp);
+
+	/* Initialize MAC address and backoff seed. */
+	__tg3_set_mac_addr(tp, 0);
+
+	err = tg3_alloc_consistent(tp);
+	if (err)
+		return err;
+
+	tpr->rx_std_iob_cnt = 0;
+
+	err = tg3_init_hw(tp, 1);
+	if (err != 0)
+		DBGC(tp->dev, "tg3_init_hw failed: %s\n", strerror(err));
+	else
+		tg3_refill_prod_ring(tp);
+
+	return err;
+}
+
+static inline u32 tg3_tx_avail(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	/* Tell compiler to fetch tx indices from memory. */
+	barrier();
+	return TG3_DEF_TX_RING_PENDING -
+	       ((tp->tx_prod - tp->tx_cons) & (TG3_TX_RING_SIZE - 1));
+}
+
+#if 0
+/**
+ *
+ * Prints all registers that could cause a set ERR bit in hw_status->status
+ */
+static void tg3_dump_err_reg(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+		printf("FLOW_ATTN: %#08x\n", tr32(HOSTCC_FLOW_ATTN));
+		printf("MAC ATTN: %#08x\n", tr32(MAC_STATUS));
+		printf("MSI STATUS: %#08x\n", tr32(MSGINT_STATUS));
+		printf("DMA RD: %#08x\n", tr32(RDMAC_STATUS));
+		printf("DMA WR: %#08x\n", tr32(WDMAC_STATUS));
+		printf("TX CPU STATE: %#08x\n", tr32(TX_CPU_STATE));
+		printf("RX CPU STATE: %#08x\n", tr32(RX_CPU_STATE));
+}
+
+static void __unused tw32_mailbox2(struct tg3 *tp, uint32_t reg, uint32_t val)
+{	DBGP("%s\n", __func__);
+
+	tw32_mailbox(reg, val);
+	tr32(reg);
+}
+#endif
+
+#define NEXT_TX(N)		(((N) + 1) & (TG3_TX_RING_SIZE - 1))
+
+/* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and
+ * support TG3_FLAG_HW_TSO_1 or firmware TSO only.
+ */
+static int tg3_transmit(struct net_device *dev, struct io_buffer *iob)
+{	DBGP("%s\n", __func__);
+
+	struct tg3 *tp = netdev_priv(dev);
+	u32 len, entry;
+	dma_addr_t mapping;
+
+	if (tg3_tx_avail(tp) < 1) {
+		DBGC(dev, "Transmit ring full\n");
+		return -ENOBUFS;
+	}
+
+	entry = tp->tx_prod;
+
+	iob_pad(iob, ETH_ZLEN);
+	mapping = virt_to_bus(iob->data);
+	len = iob_len(iob);
+
+	tp->tx_buffers[entry].iob = iob;
+
+	tg3_set_txd(tp, entry, mapping, len, TXD_FLAG_END);
+
+	entry = NEXT_TX(entry);
+
+	/* Packets are ready, update Tx producer idx local and on card. */
+	tw32_tx_mbox(tp->prodmbox, entry);
+
+	tp->tx_prod = entry;
+
+	mb();
+
+	return 0;
+}
+
+static void tg3_tx_complete(struct net_device *dev)
+{	DBGP("%s\n", __func__);
+
+	struct tg3 *tp = netdev_priv(dev);
+	u32 hw_idx = tp->hw_status->idx[0].tx_consumer;
+	u32 sw_idx = tp->tx_cons;
+
+	while (sw_idx != hw_idx) {
+		struct io_buffer *iob = tp->tx_buffers[sw_idx].iob;
+
+		DBGC2(dev, "Transmitted packet: %zd bytes\n", iob_len(iob));
+
+		netdev_tx_complete(dev, iob);
+		sw_idx = NEXT_TX(sw_idx);
+	}
+
+	tp->tx_cons = sw_idx;
+}
+
+#define TG3_RX_STD_BUFF_RING_BYTES(tp) \
+	(sizeof(struct ring_info) * TG3_RX_STD_MAX_SIZE_5700)
+#define TG3_RX_STD_RING_BYTES(tp) \
+	(sizeof(struct tg3_rx_buffer_desc) * TG3_RX_STD_MAX_SIZE_5700)
+
+/* Returns 0 or < 0 on error.
+ *
+ * We only need to fill in the address because the other members
+ * of the RX descriptor are invariant, see tg3_init_rings.
+ *
+ * Note the purposeful assymetry of cpu vs. chip accesses.  For
+ * posting buffers we only dirty the first cache line of the RX
+ * descriptor (containing the address).  Whereas for the RX status
+ * buffers the cpu only reads the last cacheline of the RX descriptor
+ * (to fetch the error flags, vlan tag, checksum, and opaque cookie).
+ */
+static int tg3_alloc_rx_iob(struct tg3_rx_prodring_set *tpr, u32 dest_idx_unmasked)
+{	DBGP("%s\n", __func__);
+
+	struct tg3_rx_buffer_desc *desc;
+	struct io_buffer *iob;
+	dma_addr_t mapping;
+	int dest_idx, iob_idx;
+
+	dest_idx = dest_idx_unmasked & (TG3_RX_STD_MAX_SIZE_5700 - 1);
+	desc = &tpr->rx_std[dest_idx];
+
+	/* Do not overwrite any of the map or rp information
+	 * until we are sure we can commit to a new buffer.
+	 *
+	 * Callers depend upon this behavior and assume that
+	 * we leave everything unchanged if we fail.
+	 */
+	iob = alloc_iob(TG3_RX_STD_DMA_SZ);
+	if (iob == NULL)
+		return -ENOMEM;
+
+	iob_idx = dest_idx % TG3_DEF_RX_RING_PENDING;
+	tpr->rx_iobufs[iob_idx] = iob;
+
+	mapping = virt_to_bus(iob->data);
+
+	desc->addr_hi = ((u64)mapping >> 32);
+	desc->addr_lo = ((u64)mapping & 0xffffffff);
+
+	return 0;
+}
+
+static void tg3_refill_prod_ring(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	struct tg3_rx_prodring_set *tpr = &tp->prodring;
+	int idx = tpr->rx_std_prod_idx;
+
+	DBGCP(tp->dev, "%s\n", __func__);
+
+	while (tpr->rx_std_iob_cnt < TG3_DEF_RX_RING_PENDING) {
+		if (tpr->rx_iobufs[idx % TG3_DEF_RX_RING_PENDING] == NULL) {
+			if (tg3_alloc_rx_iob(tpr, idx) < 0) {
+				DBGC(tp->dev, "alloc_iob() failed for descriptor %d\n", idx);
+				break;
+			}
+			DBGC2(tp->dev, "allocated iob_buffer for descriptor %d\n", idx);
+		}
+
+		idx = (idx + 1) % TG3_RX_STD_MAX_SIZE_5700;
+		tpr->rx_std_iob_cnt++;
+	}
+
+	if ((u32)idx != tpr->rx_std_prod_idx) {
+		tpr->rx_std_prod_idx = idx;
+		tw32_rx_mbox(TG3_RX_STD_PROD_IDX_REG, idx);
+	}
+}
+
+static void tg3_rx_complete(struct net_device *dev)
+{	DBGP("%s\n", __func__);
+
+	struct tg3 *tp = netdev_priv(dev);
+
+	u32 sw_idx = tp->rx_rcb_ptr;
+	u16 hw_idx;
+	struct tg3_rx_prodring_set *tpr = &tp->prodring;
+
+	hw_idx = *(tp->rx_rcb_prod_idx);
+
+	while (sw_idx != hw_idx) {
+		struct tg3_rx_buffer_desc *desc = &tp->rx_rcb[sw_idx];
+		u32 desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
+		int iob_idx = desc_idx % TG3_DEF_RX_RING_PENDING;
+		struct io_buffer *iob = tpr->rx_iobufs[iob_idx];
+		unsigned int len;
+
+		DBGC2(dev, "RX - desc_idx: %d sw_idx: %d hw_idx: %d\n", desc_idx, sw_idx, hw_idx);
+
+		assert(iob != NULL);
+
+		if ((desc->err_vlan & RXD_ERR_MASK) != 0 &&
+		    (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) {
+			/* drop packet */
+			DBGC(dev, "Corrupted packet received\n");
+			netdev_rx_err(dev, iob, -EINVAL);
+		} else {
+			len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) -
+			        ETH_FCS_LEN;
+			iob_put(iob, len);
+			netdev_rx(dev, iob);
+
+			DBGC2(dev, "Received packet: %d bytes %d %d\n", len, sw_idx, hw_idx);
+		}
+
+		sw_idx++;
+		sw_idx &= TG3_RX_RET_MAX_SIZE_5705 - 1;
+
+		tpr->rx_iobufs[iob_idx] = NULL;
+		tpr->rx_std_iob_cnt--;
+	}
+
+	if (tp->rx_rcb_ptr != sw_idx) {
+		tw32_rx_mbox(tp->consmbox, sw_idx);
+		tp->rx_rcb_ptr = sw_idx;
+	}
+
+	tg3_refill_prod_ring(tp);
+}
+
+static void tg3_poll(struct net_device *dev)
+{	DBGP("%s\n", __func__);
+
+	struct tg3 *tp = netdev_priv(dev);
+
+	/* ACK interrupts */
+	/*
+	 *tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00);
+	 */
+	tp->hw_status->status &= ~SD_STATUS_UPDATED;
+
+	tg3_poll_link(tp);
+	tg3_tx_complete(dev);
+	tg3_rx_complete(dev);
+}
+
+static void tg3_close(struct net_device *dev)
+{	DBGP("%s\n", __func__);
+
+	struct tg3 *tp = netdev_priv(dev);
+
+	DBGP("%s\n", __func__);
+
+	tg3_halt(tp);
+	tg3_rx_prodring_free(&tp->prodring);
+	tg3_flag_clear(tp, INIT_COMPLETE);
+
+	tg3_free_consistent(tp);
+
+}
+
+static void tg3_irq(struct net_device *dev, int enable)
+{	DBGP("%s\n", __func__);
+
+	struct tg3 *tp = netdev_priv(dev);
+
+	DBGP("%s: %d\n", __func__, enable);
+
+	if (enable)
+		tg3_enable_ints(tp);
+	else
+		tg3_disable_ints(tp);
+}
+
+static struct net_device_operations tg3_netdev_ops = {
+	.open = tg3_open,
+	.close = tg3_close,
+	.poll = tg3_poll,
+	.transmit = tg3_transmit,
+	.irq = tg3_irq,
+};
+
+#define TEST_BUFFER_SIZE	0x2000
+
+int tg3_do_test_dma(struct tg3 *tp, u32 __unused *buf, dma_addr_t buf_dma, int size, int to_device);
+void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val);
+
+static int tg3_test_dma(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	dma_addr_t buf_dma;
+	u32 *buf;
+	int ret = 0;
+
+	buf = malloc_dma(TEST_BUFFER_SIZE, TG3_DMA_ALIGNMENT);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto out_nofree;
+	}
+	buf_dma = virt_to_bus(buf);
+	DBGC2(tp->dev, "dma test buffer, virt: %p phys: %#08x\n", buf, buf_dma);
+
+	if (tg3_flag(tp, 57765_PLUS)) {
+		tp->dma_rwctrl = DMA_RWCTRL_DIS_CACHE_ALIGNMENT;
+		goto out;
+	}
+
+	tp->dma_rwctrl = ((0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
+	                 (0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT));
+
+	if (tg3_flag(tp, PCI_EXPRESS)) {
+		/* DMA read watermark not used on PCIE */
+		tp->dma_rwctrl |= 0x00180000;
+	} else if (!tg3_flag(tp, PCIX_MODE)) {
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+			tp->dma_rwctrl |= 0x003f0000;
+		else
+			tp->dma_rwctrl |= 0x003f000f;
+	} else {
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+			u32 ccval = (tr32(TG3PCI_CLOCK_CTRL) & 0x1f);
+			u32 read_water = 0x7;
+
+			if (ccval == 0x6 || ccval == 0x7)
+				tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
+
+			if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703)
+				read_water = 4;
+			/* Set bit 23 to enable PCIX hw bug fix */
+			tp->dma_rwctrl |=
+				(read_water << DMA_RWCTRL_READ_WATER_SHIFT) |
+				(0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
+				(1 << 23);
+		} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) {
+			/* 5780 always in PCIX mode */
+			tp->dma_rwctrl |= 0x00144000;
+		} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
+			/* 5714 always in PCIX mode */
+			tp->dma_rwctrl |= 0x00148000;
+		} else {
+			tp->dma_rwctrl |= 0x001b000f;
+		}
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+		tp->dma_rwctrl &= 0xfffffff0;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+		/* Remove this if it causes problems for some boards. */
+		tp->dma_rwctrl |= DMA_RWCTRL_USE_MEM_READ_MULT;
+
+		/* On 5700/5701 chips, we need to set this bit.
+		 * Otherwise the chip will issue cacheline transactions
+		 * to streamable DMA memory with not all the byte
+		 * enables turned on.  This is an error on several
+		 * RISC PCI controllers, in particular sparc64.
+		 *
+		 * On 5703/5704 chips, this bit has been reassigned
+		 * a different meaning.  In particular, it is used
+		 * on those chips to enable a PCI-X workaround.
+		 */
+		tp->dma_rwctrl |= DMA_RWCTRL_ASSERT_ALL_BE;
+	}
+
+	tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+
+#if 0
+	/* Unneeded, already done by tg3_get_invariants.  */
+	tg3_switch_clocks(tp);
+#endif
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
+		goto out;
+
+	/* It is best to perform DMA test with maximum write burst size
+	 * to expose the 5700/5701 write DMA bug.
+	 */
+	tp->dma_rwctrl &= ~DMA_RWCTRL_WRITE_BNDRY_MASK;
+	tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+
+	while (1) {
+		u32 *p = buf, i;
+
+		for (i = 0; i < TEST_BUFFER_SIZE / sizeof(u32); i++)
+			p[i] = i;
+
+		/* Send the buffer to the chip. */
+		ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 1);
+		if (ret) {
+			DBGC(&tp->pdev->dev,
+				"%s: Buffer write failed. err = %d\n",
+				__func__, ret);
+			break;
+		}
+
+		/* validate data reached card RAM correctly. */
+		for (i = 0; i < TEST_BUFFER_SIZE / sizeof(u32); i++) {
+			u32 val;
+			tg3_read_mem(tp, 0x2100 + (i*4), &val);
+			if (le32_to_cpu(val) != p[i]) {
+				DBGC(&tp->pdev->dev,
+					"%s: Buffer corrupted on device! "
+					"(%d != %d)\n", __func__, val, i);
+				/* ret = -ENODEV here? */
+			}
+			p[i] = 0;
+		}
+
+		/* Now read it back. */
+		ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 0);
+		if (ret) {
+			DBGC(&tp->pdev->dev, "%s: Buffer read failed. "
+				"err = %d\n", __func__, ret);
+			break;
+		}
+
+		/* Verify it. */
+		for (i = 0; i < TEST_BUFFER_SIZE / sizeof(u32); i++) {
+			if (p[i] == i)
+				continue;
+
+			if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) !=
+			    DMA_RWCTRL_WRITE_BNDRY_16) {
+				tp->dma_rwctrl &= ~DMA_RWCTRL_WRITE_BNDRY_MASK;
+				tp->dma_rwctrl |= DMA_RWCTRL_WRITE_BNDRY_16;
+				tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+				break;
+			} else {
+				DBGC(&tp->pdev->dev,
+					"%s: Buffer corrupted on read back! "
+					"(%d != %d)\n", __func__, p[i], i);
+				ret = -ENODEV;
+				goto out;
+			}
+		}
+
+		if (i == (TEST_BUFFER_SIZE / sizeof(u32))) {
+			/* Success. */
+			ret = 0;
+			break;
+		}
+	}
+
+	if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) !=
+	    DMA_RWCTRL_WRITE_BNDRY_16) {
+		/* DMA test passed without adjusting DMA boundary,
+		 * now look for chipsets that are known to expose the
+		 * DMA bug without failing the test.
+		 */
+		tp->dma_rwctrl &= ~DMA_RWCTRL_WRITE_BNDRY_MASK;
+		tp->dma_rwctrl |= DMA_RWCTRL_WRITE_BNDRY_16;
+
+		tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+	}
+
+out:
+	free_dma(buf, TEST_BUFFER_SIZE);
+out_nofree:
+	return ret;
+}
+
+static int tg3_init_one(struct pci_device *pdev)
+{	DBGP("%s\n", __func__);
+
+	struct net_device *dev;
+	struct tg3 *tp;
+	int err = 0;
+	unsigned long reg_base, reg_size;
+
+	adjust_pci_device(pdev);
+
+	dev = alloc_etherdev(sizeof(*tp));
+	if (!dev) {
+		DBGC(&pdev->dev, "Failed to allocate etherdev\n");
+		err = -ENOMEM;
+		goto err_out_disable_pdev;
+	}
+
+	netdev_init(dev, &tg3_netdev_ops);
+	pci_set_drvdata(pdev, dev);
+
+	dev->dev = &pdev->dev;
+
+	tp = netdev_priv(dev);
+	tp->pdev = pdev;
+	tp->dev = dev;
+	tp->rx_mode = TG3_DEF_RX_MODE;
+	tp->tx_mode = TG3_DEF_TX_MODE;
+
+	/* Subsystem IDs are required later */
+	pci_read_config_word(tp->pdev, PCI_SUBSYSTEM_VENDOR_ID, &tp->subsystem_vendor);
+	pci_read_config_word(tp->pdev, PCI_SUBSYSTEM_ID, &tp->subsystem_device);
+
+	/* The word/byte swap controls here control register access byte
+	 * swapping.  DMA data byte swapping is controlled in the GRC_MODE
+	 * setting below.
+	 */
+	tp->misc_host_ctrl =
+		MISC_HOST_CTRL_MASK_PCI_INT |
+		MISC_HOST_CTRL_WORD_SWAP |
+		MISC_HOST_CTRL_INDIR_ACCESS |
+		MISC_HOST_CTRL_PCISTATE_RW;
+
+	/* The NONFRM (non-frame) byte/word swap controls take effect
+	 * on descriptor entries, anything which isn't packet data.
+	 *
+	 * The StrongARM chips on the board (one for tx, one for rx)
+	 * are running in big-endian mode.
+	 */
+	tp->grc_mode = (GRC_MODE_WSWAP_DATA | GRC_MODE_BSWAP_DATA |
+			GRC_MODE_WSWAP_NONFRM_DATA);
+#if __BYTE_ORDER == __BIG_ENDIAN
+	tp->grc_mode |= GRC_MODE_BSWAP_NONFRM_DATA;
+#endif
+
+	/* FIXME: how can we detect errors here? */
+	reg_base = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
+	reg_size = pci_bar_size(pdev, PCI_BASE_ADDRESS_0);
+
+	tp->regs = ioremap(reg_base, reg_size);
+	if (!tp->regs) {
+		DBGC(&pdev->dev, "Failed to remap device registers\n");
+		errno = -ENOENT;
+		goto err_out_disable_pdev;
+	}
+
+	err = tg3_get_invariants(tp);
+	if (err) {
+		DBGC(&pdev->dev, "Problem fetching invariants of chip, aborting\n");
+		goto err_out_iounmap;
+	}
+
+	tg3_init_bufmgr_config(tp);
+
+	err = tg3_get_device_address(tp);
+	if (err) {
+		DBGC(&pdev->dev, "Could not obtain valid ethernet address, aborting\n");
+		goto err_out_iounmap;
+	}
+
+	/*
+	 * Reset chip in case UNDI or EFI driver did not shutdown
+	 * DMA self test will enable WDMAC and we'll see (spurious)
+	 * pending DMA on the PCI bus at that point.
+	 */
+	if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) ||
+	    (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
+		tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
+		tg3_halt(tp);
+	}
+
+	err = tg3_test_dma(tp);
+	if (err) {
+		DBGC(&pdev->dev, "DMA engine test failed, aborting\n");
+		goto err_out_iounmap;
+	}
+
+	tp->int_mbox = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW;
+	tp->consmbox = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW;
+	tp->prodmbox = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW;
+
+	tp->coal_now = HOSTCC_MODE_NOW;
+
+	err = register_netdev(dev);
+	if (err) {
+		DBGC(&pdev->dev, "Cannot register net device, aborting\n");
+		goto err_out_iounmap;
+	}
+
+	/* Call tg3_setup_phy() to start autoneg process, which saves time
+	 * over starting autoneg in tg3_open();
+	 */
+	err = tg3_setup_phy(tp, 0);
+	if (err) {
+		DBGC(tp->dev, "tg3_setup_phy() call failed in %s\n", __func__);
+		goto err_out_iounmap;
+	}
+
+	return 0;
+
+err_out_iounmap:
+	if (tp->regs) {
+		iounmap(tp->regs);
+		tp->regs = NULL;
+	}
+
+	netdev_put(dev);
+
+err_out_disable_pdev:
+	pci_set_drvdata(pdev, NULL);
+	return err;
+}
+
+static void tg3_remove_one(struct pci_device *pci)
+{	DBGP("%s\n", __func__);
+
+	struct net_device *netdev = pci_get_drvdata(pci);
+
+	unregister_netdev(netdev);
+	netdev_nullify(netdev);
+	netdev_put(netdev);
+}
+
+static struct pci_device_id tg3_nics[] = {
+	PCI_ROM(0x14e4, 0x1644, "14e4-1644", "14e4-1644", 0),
+	PCI_ROM(0x14e4, 0x1645, "14e4-1645", "14e4-1645", 0),
+	PCI_ROM(0x14e4, 0x1646, "14e4-1646", "14e4-1646", 0),
+	PCI_ROM(0x14e4, 0x1647, "14e4-1647", "14e4-1647", 0),
+	PCI_ROM(0x14e4, 0x1648, "14e4-1648", "14e4-1648", 0),
+	PCI_ROM(0x14e4, 0x164d, "14e4-164d", "14e4-164d", 0),
+	PCI_ROM(0x14e4, 0x1653, "14e4-1653", "14e4-1653", 0),
+	PCI_ROM(0x14e4, 0x1654, "14e4-1654", "14e4-1654", 0),
+	PCI_ROM(0x14e4, 0x165d, "14e4-165d", "14e4-165d", 0),
+	PCI_ROM(0x14e4, 0x165e, "14e4-165e", "14e4-165e", 0),
+	PCI_ROM(0x14e4, 0x16a6, "14e4-16a6", "14e4-16a6", 0),
+	PCI_ROM(0x14e4, 0x16a7, "14e4-16a7", "14e4-16a7", 0),
+	PCI_ROM(0x14e4, 0x16a8, "14e4-16a8", "14e4-16a8", 0),
+	PCI_ROM(0x14e4, 0x16c6, "14e4-16c6", "14e4-16c6", 0),
+	PCI_ROM(0x14e4, 0x16c7, "14e4-16c7", "14e4-16c7", 0),
+	PCI_ROM(0x14e4, 0x1696, "14e4-1696", "14e4-1696", 0),
+	PCI_ROM(0x14e4, 0x169c, "14e4-169c", "14e4-169c", 0),
+	PCI_ROM(0x14e4, 0x169d, "14e4-169d", "14e4-169d", 0),
+	PCI_ROM(0x14e4, 0x170d, "14e4-170d", "14e4-170d", 0),
+	PCI_ROM(0x14e4, 0x170e, "14e4-170e", "14e4-170e", 0),
+	PCI_ROM(0x14e4, 0x1649, "14e4-1649", "14e4-1649", 0),
+	PCI_ROM(0x14e4, 0x166e, "14e4-166e", "14e4-166e", 0),
+	PCI_ROM(0x14e4, 0x1659, "14e4-1659", "14e4-1659", 0),
+	PCI_ROM(0x14e4, 0x165a, "14e4-165a", "14e4-165a", 0),
+	PCI_ROM(0x14e4, 0x1677, "14e4-1677", "14e4-1677", 0),
+	PCI_ROM(0x14e4, 0x167d, "14e4-167d", "14e4-167d", 0),
+	PCI_ROM(0x14e4, 0x167e, "14e4-167e", "14e4-167e", 0),
+	PCI_ROM(0x14e4, 0x1600, "14e4-1600", "14e4-1600", 0),
+	PCI_ROM(0x14e4, 0x1601, "14e4-1601", "14e4-1601", 0),
+	PCI_ROM(0x14e4, 0x16f7, "14e4-16f7", "14e4-16f7", 0),
+	PCI_ROM(0x14e4, 0x16fd, "14e4-16fd", "14e4-16fd", 0),
+	PCI_ROM(0x14e4, 0x16fe, "14e4-16fe", "14e4-16fe", 0),
+	PCI_ROM(0x14e4, 0x167a, "14e4-167a", "14e4-167a", 0),
+	PCI_ROM(0x14e4, 0x1672, "14e4-1672", "14e4-1672", 0),
+	PCI_ROM(0x14e4, 0x167b, "14e4-167b", "14e4-167b", 0),
+	PCI_ROM(0x14e4, 0x1673, "14e4-1673", "14e4-1673", 0),
+	PCI_ROM(0x14e4, 0x1674, "14e4-1674", "14e4-1674", 0),
+	PCI_ROM(0x14e4, 0x169a, "14e4-169a", "14e4-169a", 0),
+	PCI_ROM(0x14e4, 0x169b, "14e4-169b", "14e4-169b", 0),
+	PCI_ROM(0x14e4, 0x1693, "14e4-1693", "14e4-1693", 0),
+	PCI_ROM(0x14e4, 0x167f, "14e4-167f", "14e4-167f", 0),
+	PCI_ROM(0x14e4, 0x1668, "14e4-1668", "14e4-1668", 0),
+	PCI_ROM(0x14e4, 0x1669, "14e4-1669", "14e4-1669", 0),
+	PCI_ROM(0x14e4, 0x1678, "14e4-1678", "14e4-1678", 0),
+	PCI_ROM(0x14e4, 0x1679, "14e4-1679", "14e4-1679", 0),
+	PCI_ROM(0x14e4, 0x166a, "14e4-166a", "14e4-166a", 0),
+	PCI_ROM(0x14e4, 0x166b, "14e4-166b", "14e4-166b", 0),
+	PCI_ROM(0x14e4, 0x16dd, "14e4-16dd", "14e4-16dd", 0),
+	PCI_ROM(0x14e4, 0x1712, "14e4-1712", "14e4-1712", 0),
+	PCI_ROM(0x14e4, 0x1713, "14e4-1713", "14e4-1713", 0),
+	PCI_ROM(0x14e4, 0x1698, "14e4-1698", "14e4-1698", 0),
+	PCI_ROM(0x14e4, 0x1684, "14e4-1684", "14e4-1684", 0),
+	PCI_ROM(0x14e4, 0x165b, "14e4-165b", "14e4-165b", 0),
+	PCI_ROM(0x14e4, 0x1681, "14e4-1681", "14e4-1681", 0),
+	PCI_ROM(0x14e4, 0x1682, "14e4-1682", "14e4-1682", 0),
+	PCI_ROM(0x14e4, 0x1680, "14e4-1680", "14e4-1680", 0),
+	PCI_ROM(0x14e4, 0x1688, "14e4-1688", "14e4-1688", 0),
+	PCI_ROM(0x14e4, 0x1689, "14e4-1689", "14e4-1689", 0),
+	PCI_ROM(0x14e4, 0x1699, "14e4-1699", "14e4-1699", 0),
+	PCI_ROM(0x14e4, 0x16a0, "14e4-16a0", "14e4-16a0", 0),
+	PCI_ROM(0x14e4, 0x1692, "14e4-1692", "14e4-1692", 0),
+	PCI_ROM(0x14e4, 0x1690, "14e4-1690", "14e4-1690", 0),
+	PCI_ROM(0x14e4, 0x1694, "14e4-1694", "14e4-1694", 0),
+	PCI_ROM(0x14e4, 0x1691, "14e4-1691", "14e4-1691", 0),
+	PCI_ROM(0x14e4, 0x1655, "14e4-1655", "14e4-1655", 0),
+	PCI_ROM(0x14e4, 0x1656, "14e4-1656", "14e4-1656", 0),
+	PCI_ROM(0x14e4, 0x16b1, "14e4-16b1", "14e4-16b1", 0),
+	PCI_ROM(0x14e4, 0x16b5, "14e4-16b5", "14e4-16b5", 0),
+	PCI_ROM(0x14e4, 0x16b0, "14e4-16b0", "14e4-16b0", 0),
+	PCI_ROM(0x14e4, 0x16b4, "14e4-16b4", "14e4-16b4", 0),
+	PCI_ROM(0x14e4, 0x16b2, "14e4-16b2", "14e4-16b2", 0),
+	PCI_ROM(0x14e4, 0x16b6, "14e4-16b6", "14e4-16b6", 0),
+	PCI_ROM(0x14e4, 0x1657, "14e4-1657", "14e4-1657", 0),
+	PCI_ROM(0x14e4, 0x165f, "14e4-165f", "14e4-165f", 0),
+	PCI_ROM(0x1148, 0x4400, "1148-4400", "1148-4400", 0),
+	PCI_ROM(0x1148, 0x4500, "1148-4500", "1148-4500", 0),
+	PCI_ROM(0x173b, 0x03e8, "173b-03e8", "173b-03e8", 0),
+	PCI_ROM(0x173b, 0x03e9, "173b-03e9", "173b-03e9", 0),
+	PCI_ROM(0x173b, 0x03eb, "173b-03eb", "173b-03eb", 0),
+	PCI_ROM(0x173b, 0x03ea, "173b-03ea", "173b-03ea", 0),
+	PCI_ROM(0x106b, 0x1645, "106b-1645", "106b-1645", 0),
+};
+
+struct pci_driver tg3_pci_driver __pci_driver = {
+	.ids = tg3_nics,
+	.id_count = ARRAY_SIZE(tg3_nics),
+	.probe = tg3_init_one,
+	.remove = tg3_remove_one,
+};
diff --git a/roms/ipxe/src/drivers/net/tg3/tg3.h b/roms/ipxe/src/drivers/net/tg3/tg3.h
new file mode 100644
index 0000000000000000000000000000000000000000..660368394896ce57562f656ec57834ffca05ca4e
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/tg3/tg3.h
@@ -0,0 +1,3431 @@
+/* $Id: tg3.h,v 1.37.2.32 2002/03/11 12:18:18 davem Exp $
+ * tg3.h: Definitions for Broadcom Tigon3 ethernet driver.
+ *
+ * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001 Jeff Garzik (jgarzik@pobox.com)
+ * Copyright (C) 2004 Sun Microsystems Inc.
+ * Copyright (C) 2007-2011 Broadcom Corporation.
+ */
+
+#ifndef _T3_H
+#define _T3_H
+
+#undef ERRFILE
+#define ERRFILE ERRFILE_tg3
+
+/* From linux/include/linux/pci_regs.h: */
+#define PCI_EXP_LNKCTL          16      /* Link Control */
+#define  PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */
+#define  PCI_CAP_ID_PCIX        0x07    /* PCI-X */
+
+#define  PCI_X_CMD_READ_2K      0x0008  /* 2Kbyte maximum read byte count */
+#define  PCI_X_CMD_MAX_READ     0x000c  /* Max Memory Read Byte Count */
+
+#define  PCI_X_CMD_MAX_SPLIT    0x0070  /* Max Outstanding Split Transactions */
+/* </pci_regs.h> */
+
+/* ethtool.h: */
+#define ADVERTISED_10baseT_Half         (1 << 0)
+#define ADVERTISED_10baseT_Full         (1 << 1)
+#define ADVERTISED_100baseT_Half        (1 << 2)
+#define ADVERTISED_100baseT_Full        (1 << 3)
+#define ADVERTISED_1000baseT_Half       (1 << 4)
+#define ADVERTISED_1000baseT_Full       (1 << 5)
+#define ADVERTISED_Autoneg              (1 << 6)
+/* </ethtool.h> */
+
+/* mdio.h: */
+#define MDIO_AN_EEE_ADV		60      /* EEE advertisement */
+
+#define MDIO_MMD_AN		7       /* Auto-Negotiation */
+
+#define MDIO_AN_EEE_ADV_100TX		0x0002  /* Advertise 100TX EEE cap */
+#define MDIO_AN_EEE_ADV_1000T		0x0004  /* Advertise 1000T EEE cap */
+/* </mdio.h> */
+
+/* mii.h */
+#define FLOW_CTRL_TX		0x01
+#define FLOW_CTRL_RX		0x02
+/* </mii.h> */
+
+/* pci_regs.h */
+#define PCI_X_CMD			2       /* Modes & Features */
+#define PCI_X_CMD_ERO			0x0002  /* Enable Relaxed Ordering */
+
+#define PCI_EXP_DEVCTL			8       /* Device Control */
+#define PCI_EXP_DEVCTL_RELAX_EN		0x0010 /* Enable relaxed ordering */
+#define PCI_EXP_DEVCTL_NOSNOOP_EN	0x0800  /* Enable No Snoop */
+#define PCI_EXP_DEVCTL_PAYLOAD		0x00e0  /* Max_Payload_Size */
+#define PCI_EXP_DEVSTA			10      /* Device Status */
+#define PCI_EXP_DEVSTA_CED		0x01    /* Correctable Error Detected */
+#define PCI_EXP_DEVSTA_NFED		0x02    /* Non-Fatal Error Detected */
+#define PCI_EXP_DEVSTA_FED		0x04    /* Fatal Error Detected */
+#define PCI_EXP_DEVSTA_URD		0x08    /* Unsupported Request Detected */
+/* </pci_regs.h> */
+
+/* pci_ids.h: */
+#define PCI_VENDOR_ID_BROADCOM		0x14e4
+#define PCI_DEVICE_ID_TIGON3_5752	0x1600
+#define PCI_DEVICE_ID_TIGON3_5752M	0x1601
+#define PCI_DEVICE_ID_NX2_5709		0x1639
+#define PCI_DEVICE_ID_NX2_5709S		0x163a
+#define PCI_DEVICE_ID_TIGON3_5700	0x1644
+#define PCI_DEVICE_ID_TIGON3_5701	0x1645
+#define PCI_DEVICE_ID_TIGON3_5702	0x1646
+#define PCI_DEVICE_ID_TIGON3_5703	0x1647
+#define PCI_DEVICE_ID_TIGON3_5704	0x1648
+#define PCI_DEVICE_ID_TIGON3_5704S_2	0x1649
+#define PCI_DEVICE_ID_NX2_5706		0x164a
+#define PCI_DEVICE_ID_NX2_5708		0x164c
+#define PCI_DEVICE_ID_TIGON3_5702FE	0x164d
+#define PCI_DEVICE_ID_NX2_57710		0x164e
+#define PCI_DEVICE_ID_NX2_57711		0x164f
+#define PCI_DEVICE_ID_NX2_57711E	0x1650
+#define PCI_DEVICE_ID_TIGON3_5705	0x1653
+#define PCI_DEVICE_ID_TIGON3_5705_2	0x1654
+#define PCI_DEVICE_ID_TIGON3_5721	0x1659
+#define PCI_DEVICE_ID_TIGON3_5722	0x165a
+#define PCI_DEVICE_ID_TIGON3_5723	0x165b
+#define PCI_DEVICE_ID_TIGON3_5705M	0x165d
+#define PCI_DEVICE_ID_TIGON3_5705M_2	0x165e
+#define PCI_DEVICE_ID_NX2_57712		0x1662
+#define PCI_DEVICE_ID_NX2_57712E	0x1663
+#define PCI_DEVICE_ID_TIGON3_5714	0x1668
+#define PCI_DEVICE_ID_TIGON3_5714S	0x1669
+#define PCI_DEVICE_ID_TIGON3_5780	0x166a
+#define PCI_DEVICE_ID_TIGON3_5780S	0x166b
+#define PCI_DEVICE_ID_TIGON3_5705F	0x166e
+#define PCI_DEVICE_ID_TIGON3_5754M	0x1672
+#define PCI_DEVICE_ID_TIGON3_5755M	0x1673
+#define PCI_DEVICE_ID_TIGON3_5756	0x1674
+#define PCI_DEVICE_ID_TIGON3_5751	0x1677
+#define PCI_DEVICE_ID_TIGON3_5715	0x1678
+#define PCI_DEVICE_ID_TIGON3_5715S	0x1679
+#define PCI_DEVICE_ID_TIGON3_5754	0x167a
+#define PCI_DEVICE_ID_TIGON3_5755	0x167b
+#define PCI_DEVICE_ID_TIGON3_5751M	0x167d
+#define PCI_DEVICE_ID_TIGON3_5751F	0x167e
+#define PCI_DEVICE_ID_TIGON3_5787F	0x167f
+#define PCI_DEVICE_ID_TIGON3_5761E	0x1680
+#define PCI_DEVICE_ID_TIGON3_5761	0x1681
+#define PCI_DEVICE_ID_TIGON3_5764	0x1684
+#define PCI_DEVICE_ID_TIGON3_5787M	0x1693
+#define PCI_DEVICE_ID_TIGON3_5782	0x1696
+#define PCI_DEVICE_ID_TIGON3_5784	0x1698
+#define PCI_DEVICE_ID_TIGON3_5786	0x169a
+#define PCI_DEVICE_ID_TIGON3_5787	0x169b
+#define PCI_DEVICE_ID_TIGON3_5788	0x169c
+#define PCI_DEVICE_ID_TIGON3_5789	0x169d
+#define PCI_DEVICE_ID_TIGON3_5702X	0x16a6
+#define PCI_DEVICE_ID_TIGON3_5703X	0x16a7
+#define PCI_DEVICE_ID_TIGON3_5704S	0x16a8
+#define PCI_DEVICE_ID_NX2_5706S		0x16aa
+#define PCI_DEVICE_ID_NX2_5708S		0x16ac
+#define PCI_DEVICE_ID_TIGON3_5702A3	0x16c6
+#define PCI_DEVICE_ID_TIGON3_5703A3	0x16c7
+#define PCI_DEVICE_ID_TIGON3_5781	0x16dd
+#define PCI_DEVICE_ID_TIGON3_5753	0x16f7
+#define PCI_DEVICE_ID_TIGON3_5753M	0x16fd
+#define PCI_DEVICE_ID_TIGON3_5753F	0x16fe
+#define PCI_DEVICE_ID_TIGON3_5901	0x170d
+#define PCI_DEVICE_ID_TIGON3_5901_2	0x170e
+#define PCI_DEVICE_ID_TIGON3_5906	0x1712
+#define PCI_DEVICE_ID_TIGON3_5906M	0x1713
+/* </pci_ids.h> */
+
+#define SPEED_10			10
+#define SPEED_100			100
+#define SPEED_1000			1000
+
+#define DUPLEX_HALF			0x00
+#define DUPLEX_FULL			0x01
+
+#define TG3_64BIT_REG_HIGH		0x00UL
+#define TG3_64BIT_REG_LOW		0x04UL
+
+/* Descriptor block info. */
+#define TG3_BDINFO_HOST_ADDR		0x0UL /* 64-bit */
+#define TG3_BDINFO_MAXLEN_FLAGS		0x8UL /* 32-bit */
+#define  BDINFO_FLAGS_USE_EXT_RECV	 0x00000001 /* ext rx_buffer_desc */
+#define  BDINFO_FLAGS_DISABLED		 0x00000002
+#define  BDINFO_FLAGS_MAXLEN_MASK	 0xffff0000
+#define  BDINFO_FLAGS_MAXLEN_SHIFT	 16
+#define TG3_BDINFO_NIC_ADDR		0xcUL /* 32-bit */
+#define TG3_BDINFO_SIZE			0x10UL
+
+#define RX_STD_MAX_SIZE                 1536
+#define TG3_RX_STD_MAX_SIZE_5700	512
+#define TG3_RX_STD_MAX_SIZE_5717	2048
+#define TG3_RX_JMB_MAX_SIZE_5700	256
+#define TG3_RX_JMB_MAX_SIZE_5717	1024
+#define TG3_RX_RET_MAX_SIZE_5700	1024
+#define TG3_RX_RET_MAX_SIZE_5705	512
+#define TG3_RX_RET_MAX_SIZE_5717	4096
+
+/* First 256 bytes are a mirror of PCI config space. */
+#define TG3PCI_VENDOR			0x00000000
+#define  TG3PCI_VENDOR_BROADCOM		 0x14e4
+#define TG3PCI_DEVICE			0x00000002
+#define  TG3PCI_DEVICE_TIGON3_1		 0x1644 /* BCM5700 */
+#define  TG3PCI_DEVICE_TIGON3_2		 0x1645 /* BCM5701 */
+#define  TG3PCI_DEVICE_TIGON3_3		 0x1646 /* BCM5702 */
+#define  TG3PCI_DEVICE_TIGON3_4		 0x1647 /* BCM5703 */
+#define  TG3PCI_DEVICE_TIGON3_5761S	 0x1688
+#define  TG3PCI_DEVICE_TIGON3_5761SE	 0x1689
+#define  TG3PCI_DEVICE_TIGON3_57780	 0x1692
+#define  TG3PCI_DEVICE_TIGON3_57760	 0x1690
+#define  TG3PCI_DEVICE_TIGON3_57790	 0x1694
+#define  TG3PCI_DEVICE_TIGON3_57788	 0x1691
+#define  TG3PCI_DEVICE_TIGON3_5785_G	 0x1699 /* GPHY */
+#define  TG3PCI_DEVICE_TIGON3_5785_F	 0x16a0 /* 10/100 only */
+#define  TG3PCI_DEVICE_TIGON3_5717	 0x1655
+#define  TG3PCI_DEVICE_TIGON3_5718	 0x1656
+#define  TG3PCI_DEVICE_TIGON3_57781	 0x16b1
+#define  TG3PCI_DEVICE_TIGON3_57785	 0x16b5
+#define  TG3PCI_DEVICE_TIGON3_57761	 0x16b0
+#define  TG3PCI_DEVICE_TIGON3_57762	 0x1682
+#define  TG3PCI_DEVICE_TIGON3_57765	 0x16b4
+#define  TG3PCI_DEVICE_TIGON3_57791	 0x16b2
+#define  TG3PCI_DEVICE_TIGON3_57795	 0x16b6
+#define  TG3PCI_DEVICE_TIGON3_5719	 0x1657
+#define  TG3PCI_DEVICE_TIGON3_5720	 0x165f
+/* 0x04 --> 0x2c unused */
+#define TG3PCI_SUBVENDOR_ID_BROADCOM		PCI_VENDOR_ID_BROADCOM
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95700A6	0x1644
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95701A5	0x0001
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95700T6	0x0002
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95700A9	0x0003
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95701T1	0x0005
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95701T8	0x0006
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95701A7	0x0007
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95701A10	0x0008
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95701A12	0x8008
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95703AX1	0x0009
+#define TG3PCI_SUBDEVICE_ID_BROADCOM_95703AX2	0x8009
+#define TG3PCI_SUBVENDOR_ID_3COM		PCI_VENDOR_ID_3COM
+#define TG3PCI_SUBDEVICE_ID_3COM_3C996T		0x1000
+#define TG3PCI_SUBDEVICE_ID_3COM_3C996BT	0x1006
+#define TG3PCI_SUBDEVICE_ID_3COM_3C996SX	0x1004
+#define TG3PCI_SUBDEVICE_ID_3COM_3C1000T	0x1007
+#define TG3PCI_SUBDEVICE_ID_3COM_3C940BR01	0x1008
+#define TG3PCI_SUBVENDOR_ID_DELL		PCI_VENDOR_ID_DELL
+#define TG3PCI_SUBDEVICE_ID_DELL_VIPER		0x00d1
+#define TG3PCI_SUBDEVICE_ID_DELL_JAGUAR		0x0106
+#define TG3PCI_SUBDEVICE_ID_DELL_MERLOT		0x0109
+#define TG3PCI_SUBDEVICE_ID_DELL_SLIM_MERLOT	0x010a
+#define TG3PCI_SUBVENDOR_ID_COMPAQ		PCI_VENDOR_ID_COMPAQ
+#define TG3PCI_SUBDEVICE_ID_COMPAQ_BANSHEE	0x007c
+#define TG3PCI_SUBDEVICE_ID_COMPAQ_BANSHEE_2	0x009a
+#define TG3PCI_SUBDEVICE_ID_COMPAQ_CHANGELING	0x007d
+#define TG3PCI_SUBDEVICE_ID_COMPAQ_NC7780	0x0085
+#define TG3PCI_SUBDEVICE_ID_COMPAQ_NC7780_2	0x0099
+#define TG3PCI_SUBVENDOR_ID_IBM			PCI_VENDOR_ID_IBM
+#define TG3PCI_SUBDEVICE_ID_IBM_5703SAX2	0x0281
+/* 0x30 --> 0x64 unused */
+#define TG3PCI_MSI_DATA			0x00000064
+/* 0x66 --> 0x68 unused */
+#define TG3PCI_MISC_HOST_CTRL		0x00000068
+#define  MISC_HOST_CTRL_CLEAR_INT	 0x00000001
+#define  MISC_HOST_CTRL_MASK_PCI_INT	 0x00000002
+#define  MISC_HOST_CTRL_BYTE_SWAP	 0x00000004
+#define  MISC_HOST_CTRL_WORD_SWAP	 0x00000008
+#define  MISC_HOST_CTRL_PCISTATE_RW	 0x00000010
+#define  MISC_HOST_CTRL_CLKREG_RW	 0x00000020
+#define  MISC_HOST_CTRL_REGWORD_SWAP	 0x00000040
+#define  MISC_HOST_CTRL_INDIR_ACCESS	 0x00000080
+#define  MISC_HOST_CTRL_IRQ_MASK_MODE	 0x00000100
+#define  MISC_HOST_CTRL_TAGGED_STATUS	 0x00000200
+#define  MISC_HOST_CTRL_CHIPREV		 0xffff0000
+#define  MISC_HOST_CTRL_CHIPREV_SHIFT	 16
+#define  GET_CHIP_REV_ID(MISC_HOST_CTRL) \
+	 (((MISC_HOST_CTRL) & MISC_HOST_CTRL_CHIPREV) >> \
+	  MISC_HOST_CTRL_CHIPREV_SHIFT)
+#define  CHIPREV_ID_5700_A0		 0x7000
+#define  CHIPREV_ID_5700_A1		 0x7001
+#define  CHIPREV_ID_5700_B0		 0x7100
+#define  CHIPREV_ID_5700_B1		 0x7101
+#define  CHIPREV_ID_5700_B3		 0x7102
+#define  CHIPREV_ID_5700_ALTIMA		 0x7104
+#define  CHIPREV_ID_5700_C0		 0x7200
+#define  CHIPREV_ID_5701_A0		 0x0000
+#define  CHIPREV_ID_5701_B0		 0x0100
+#define  CHIPREV_ID_5701_B2		 0x0102
+#define  CHIPREV_ID_5701_B5		 0x0105
+#define  CHIPREV_ID_5703_A0		 0x1000
+#define  CHIPREV_ID_5703_A1		 0x1001
+#define  CHIPREV_ID_5703_A2		 0x1002
+#define  CHIPREV_ID_5703_A3		 0x1003
+#define  CHIPREV_ID_5704_A0		 0x2000
+#define  CHIPREV_ID_5704_A1		 0x2001
+#define  CHIPREV_ID_5704_A2		 0x2002
+#define  CHIPREV_ID_5704_A3		 0x2003
+#define  CHIPREV_ID_5705_A0		 0x3000
+#define  CHIPREV_ID_5705_A1		 0x3001
+#define  CHIPREV_ID_5705_A2		 0x3002
+#define  CHIPREV_ID_5705_A3		 0x3003
+#define  CHIPREV_ID_5750_A0		 0x4000
+#define  CHIPREV_ID_5750_A1		 0x4001
+#define  CHIPREV_ID_5750_A3		 0x4003
+#define  CHIPREV_ID_5750_C2		 0x4202
+#define  CHIPREV_ID_5752_A0_HW		 0x5000
+#define  CHIPREV_ID_5752_A0		 0x6000
+#define  CHIPREV_ID_5752_A1		 0x6001
+#define  CHIPREV_ID_5714_A2		 0x9002
+#define  CHIPREV_ID_5906_A1		 0xc001
+#define  CHIPREV_ID_57780_A0		 0x57780000
+#define  CHIPREV_ID_57780_A1		 0x57780001
+#define  CHIPREV_ID_5717_A0		 0x05717000
+#define  CHIPREV_ID_57765_A0		 0x57785000
+#define  CHIPREV_ID_5719_A0		 0x05719000
+#define  CHIPREV_ID_5720_A0		 0x05720000
+#define  GET_ASIC_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 12)
+#define   ASIC_REV_5700			 0x07
+#define   ASIC_REV_5701			 0x00
+#define   ASIC_REV_5703			 0x01
+#define   ASIC_REV_5704			 0x02
+#define   ASIC_REV_5705			 0x03
+#define   ASIC_REV_5750			 0x04
+#define   ASIC_REV_5752			 0x06
+#define   ASIC_REV_5780			 0x08
+#define   ASIC_REV_5714			 0x09
+#define   ASIC_REV_5755			 0x0a
+#define   ASIC_REV_5787			 0x0b
+#define   ASIC_REV_5906			 0x0c
+#define   ASIC_REV_USE_PROD_ID_REG	 0x0f
+#define   ASIC_REV_5784			 0x5784
+#define   ASIC_REV_5761			 0x5761
+#define   ASIC_REV_5785			 0x5785
+#define   ASIC_REV_57780		 0x57780
+#define   ASIC_REV_5717			 0x5717
+#define   ASIC_REV_57765		 0x57785
+#define   ASIC_REV_57766		 0x57766
+#define   ASIC_REV_5719			 0x5719
+#define   ASIC_REV_5720			 0x5720
+#define  GET_CHIP_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 8)
+#define   CHIPREV_5700_AX		 0x70
+#define   CHIPREV_5700_BX		 0x71
+#define   CHIPREV_5700_CX		 0x72
+#define   CHIPREV_5701_AX		 0x00
+#define   CHIPREV_5703_AX		 0x10
+#define   CHIPREV_5704_AX		 0x20
+#define   CHIPREV_5704_BX		 0x21
+#define   CHIPREV_5750_AX		 0x40
+#define   CHIPREV_5750_BX		 0x41
+#define   CHIPREV_5784_AX		 0x57840
+#define   CHIPREV_5761_AX		 0x57610
+#define   CHIPREV_57765_AX		 0x577650
+#define  GET_METAL_REV(CHIP_REV_ID)	((CHIP_REV_ID) & 0xff)
+#define   METAL_REV_A0			 0x00
+#define   METAL_REV_A1			 0x01
+#define   METAL_REV_B0			 0x00
+#define   METAL_REV_B1			 0x01
+#define   METAL_REV_B2			 0x02
+#define TG3PCI_DMA_RW_CTRL		0x0000006c
+#define  DMA_RWCTRL_DIS_CACHE_ALIGNMENT  0x00000001
+#define  DMA_RWCTRL_TAGGED_STAT_WA	 0x00000080
+#define  DMA_RWCTRL_CRDRDR_RDMA_MRRS_MSK 0x00000380
+#define  DMA_RWCTRL_READ_BNDRY_MASK	 0x00000700
+#define  DMA_RWCTRL_READ_BNDRY_DISAB	 0x00000000
+#define  DMA_RWCTRL_READ_BNDRY_16	 0x00000100
+#define  DMA_RWCTRL_READ_BNDRY_128_PCIX	 0x00000100
+#define  DMA_RWCTRL_READ_BNDRY_32	 0x00000200
+#define  DMA_RWCTRL_READ_BNDRY_256_PCIX	 0x00000200
+#define  DMA_RWCTRL_READ_BNDRY_64	 0x00000300
+#define  DMA_RWCTRL_READ_BNDRY_384_PCIX	 0x00000300
+#define  DMA_RWCTRL_READ_BNDRY_128	 0x00000400
+#define  DMA_RWCTRL_READ_BNDRY_256	 0x00000500
+#define  DMA_RWCTRL_READ_BNDRY_512	 0x00000600
+#define  DMA_RWCTRL_READ_BNDRY_1024	 0x00000700
+#define  DMA_RWCTRL_WRITE_BNDRY_MASK	 0x00003800
+#define  DMA_RWCTRL_WRITE_BNDRY_DISAB	 0x00000000
+#define  DMA_RWCTRL_WRITE_BNDRY_16	 0x00000800
+#define  DMA_RWCTRL_WRITE_BNDRY_128_PCIX 0x00000800
+#define  DMA_RWCTRL_WRITE_BNDRY_32	 0x00001000
+#define  DMA_RWCTRL_WRITE_BNDRY_256_PCIX 0x00001000
+#define  DMA_RWCTRL_WRITE_BNDRY_64	 0x00001800
+#define  DMA_RWCTRL_WRITE_BNDRY_384_PCIX 0x00001800
+#define  DMA_RWCTRL_WRITE_BNDRY_128	 0x00002000
+#define  DMA_RWCTRL_WRITE_BNDRY_256	 0x00002800
+#define  DMA_RWCTRL_WRITE_BNDRY_512	 0x00003000
+#define  DMA_RWCTRL_WRITE_BNDRY_1024	 0x00003800
+#define  DMA_RWCTRL_ONE_DMA		 0x00004000
+#define  DMA_RWCTRL_READ_WATER		 0x00070000
+#define  DMA_RWCTRL_READ_WATER_SHIFT	 16
+#define  DMA_RWCTRL_WRITE_WATER		 0x00380000
+#define  DMA_RWCTRL_WRITE_WATER_SHIFT	 19
+#define  DMA_RWCTRL_USE_MEM_READ_MULT	 0x00400000
+#define  DMA_RWCTRL_ASSERT_ALL_BE	 0x00800000
+#define  DMA_RWCTRL_PCI_READ_CMD	 0x0f000000
+#define  DMA_RWCTRL_PCI_READ_CMD_SHIFT	 24
+#define  DMA_RWCTRL_PCI_WRITE_CMD	 0xf0000000
+#define  DMA_RWCTRL_PCI_WRITE_CMD_SHIFT	 28
+#define  DMA_RWCTRL_WRITE_BNDRY_64_PCIE	 0x10000000
+#define  DMA_RWCTRL_WRITE_BNDRY_128_PCIE 0x30000000
+#define  DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE 0x70000000
+#define TG3PCI_PCISTATE			0x00000070
+#define  PCISTATE_FORCE_RESET		 0x00000001
+#define  PCISTATE_INT_NOT_ACTIVE	 0x00000002
+#define  PCISTATE_CONV_PCI_MODE		 0x00000004
+#define  PCISTATE_BUS_SPEED_HIGH	 0x00000008
+#define  PCISTATE_BUS_32BIT		 0x00000010
+#define  PCISTATE_ROM_ENABLE		 0x00000020
+#define  PCISTATE_ROM_RETRY_ENABLE	 0x00000040
+#define  PCISTATE_FLAT_VIEW		 0x00000100
+#define  PCISTATE_RETRY_SAME_DMA	 0x00002000
+#define  PCISTATE_ALLOW_APE_CTLSPC_WR	 0x00010000
+#define  PCISTATE_ALLOW_APE_SHMEM_WR	 0x00020000
+#define  PCISTATE_ALLOW_APE_PSPACE_WR	 0x00040000
+#define TG3PCI_CLOCK_CTRL		0x00000074
+#define  CLOCK_CTRL_CORECLK_DISABLE	 0x00000200
+#define  CLOCK_CTRL_RXCLK_DISABLE	 0x00000400
+#define  CLOCK_CTRL_TXCLK_DISABLE	 0x00000800
+#define  CLOCK_CTRL_ALTCLK		 0x00001000
+#define  CLOCK_CTRL_PWRDOWN_PLL133	 0x00008000
+#define  CLOCK_CTRL_44MHZ_CORE		 0x00040000
+#define  CLOCK_CTRL_625_CORE		 0x00100000
+#define  CLOCK_CTRL_FORCE_CLKRUN	 0x00200000
+#define  CLOCK_CTRL_CLKRUN_OENABLE	 0x00400000
+#define  CLOCK_CTRL_DELAY_PCI_GRANT	 0x80000000
+#define TG3PCI_REG_BASE_ADDR		0x00000078
+#define TG3PCI_MEM_WIN_BASE_ADDR	0x0000007c
+#define TG3PCI_REG_DATA			0x00000080
+#define TG3PCI_MEM_WIN_DATA		0x00000084
+#define TG3PCI_MISC_LOCAL_CTRL		0x00000090
+/* 0x94 --> 0x98 unused */
+#define TG3PCI_STD_RING_PROD_IDX	0x00000098 /* 64-bit */
+#define TG3PCI_RCV_RET_RING_CON_IDX	0x000000a0 /* 64-bit */
+/* 0xa8 --> 0xb8 unused */
+#define TG3PCI_DUAL_MAC_CTRL		0x000000b8
+#define  DUAL_MAC_CTRL_CH_MASK		 0x00000003
+#define  DUAL_MAC_CTRL_ID		 0x00000004
+#define TG3PCI_PRODID_ASICREV		0x000000bc
+#define  PROD_ID_ASIC_REV_MASK		 0x0fffffff
+/* 0xc0 --> 0xf4 unused */
+
+#define TG3PCI_GEN2_PRODID_ASICREV	0x000000f4
+#define TG3PCI_GEN15_PRODID_ASICREV	0x000000fc
+/* 0xf8 --> 0x200 unused */
+
+#define TG3_CORR_ERR_STAT		0x00000110
+#define  TG3_CORR_ERR_STAT_CLEAR	0xffffffff
+/* 0x114 --> 0x200 unused */
+
+/* Mailbox registers */
+#define MAILBOX_INTERRUPT_0		0x00000200 /* 64-bit */
+#define MAILBOX_INTERRUPT_1		0x00000208 /* 64-bit */
+#define MAILBOX_INTERRUPT_2		0x00000210 /* 64-bit */
+#define MAILBOX_INTERRUPT_3		0x00000218 /* 64-bit */
+#define MAILBOX_GENERAL_0		0x00000220 /* 64-bit */
+#define MAILBOX_GENERAL_1		0x00000228 /* 64-bit */
+#define MAILBOX_GENERAL_2		0x00000230 /* 64-bit */
+#define MAILBOX_GENERAL_3		0x00000238 /* 64-bit */
+#define MAILBOX_GENERAL_4		0x00000240 /* 64-bit */
+#define MAILBOX_GENERAL_5		0x00000248 /* 64-bit */
+#define MAILBOX_GENERAL_6		0x00000250 /* 64-bit */
+#define MAILBOX_GENERAL_7		0x00000258 /* 64-bit */
+#define MAILBOX_RELOAD_STAT		0x00000260 /* 64-bit */
+#define MAILBOX_RCV_STD_PROD_IDX	0x00000268 /* 64-bit */
+#define TG3_RX_STD_PROD_IDX_REG		(MAILBOX_RCV_STD_PROD_IDX + \
+					 TG3_64BIT_REG_LOW)
+#define MAILBOX_RCV_JUMBO_PROD_IDX	0x00000270 /* 64-bit */
+#define TG3_RX_JMB_PROD_IDX_REG		(MAILBOX_RCV_JUMBO_PROD_IDX + \
+					 TG3_64BIT_REG_LOW)
+#define MAILBOX_RCV_MINI_PROD_IDX	0x00000278 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_0	0x00000280 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_1	0x00000288 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_2	0x00000290 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_3	0x00000298 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_4	0x000002a0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_5	0x000002a8 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_6	0x000002b0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_7	0x000002b8 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_8	0x000002c0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_9	0x000002c8 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_10	0x000002d0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_11	0x000002d8 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_12	0x000002e0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_13	0x000002e8 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_14	0x000002f0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_15	0x000002f8 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_0	0x00000300 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_1	0x00000308 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_2	0x00000310 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_3	0x00000318 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_4	0x00000320 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_5	0x00000328 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_6	0x00000330 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_7	0x00000338 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_8	0x00000340 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_9	0x00000348 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_10	0x00000350 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_11	0x00000358 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_12	0x00000360 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_13	0x00000368 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_14	0x00000370 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_15	0x00000378 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_0	0x00000380 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_1	0x00000388 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_2	0x00000390 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_3	0x00000398 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_4	0x000003a0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_5	0x000003a8 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_6	0x000003b0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_7	0x000003b8 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_8	0x000003c0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_9	0x000003c8 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_10	0x000003d0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_11	0x000003d8 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_12	0x000003e0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_13	0x000003e8 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_14	0x000003f0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_15	0x000003f8 /* 64-bit */
+
+/* MAC control registers */
+#define MAC_MODE			0x00000400
+#define  MAC_MODE_RESET			 0x00000001
+#define  MAC_MODE_HALF_DUPLEX		 0x00000002
+#define  MAC_MODE_PORT_MODE_MASK	 0x0000000c
+#define  MAC_MODE_PORT_MODE_TBI		 0x0000000c
+#define  MAC_MODE_PORT_MODE_GMII	 0x00000008
+#define  MAC_MODE_PORT_MODE_MII		 0x00000004
+#define  MAC_MODE_PORT_MODE_NONE	 0x00000000
+#define  MAC_MODE_PORT_INT_LPBACK	 0x00000010
+#define  MAC_MODE_TAGGED_MAC_CTRL	 0x00000080
+#define  MAC_MODE_TX_BURSTING		 0x00000100
+#define  MAC_MODE_MAX_DEFER		 0x00000200
+#define  MAC_MODE_LINK_POLARITY		 0x00000400
+#define  MAC_MODE_RXSTAT_ENABLE		 0x00000800
+#define  MAC_MODE_RXSTAT_CLEAR		 0x00001000
+#define  MAC_MODE_RXSTAT_FLUSH		 0x00002000
+#define  MAC_MODE_TXSTAT_ENABLE		 0x00004000
+#define  MAC_MODE_TXSTAT_CLEAR		 0x00008000
+#define  MAC_MODE_TXSTAT_FLUSH		 0x00010000
+#define  MAC_MODE_SEND_CONFIGS		 0x00020000
+#define  MAC_MODE_MAGIC_PKT_ENABLE	 0x00040000
+#define  MAC_MODE_ACPI_ENABLE		 0x00080000
+#define  MAC_MODE_MIP_ENABLE		 0x00100000
+#define  MAC_MODE_TDE_ENABLE		 0x00200000
+#define  MAC_MODE_RDE_ENABLE		 0x00400000
+#define  MAC_MODE_FHDE_ENABLE		 0x00800000
+#define  MAC_MODE_KEEP_FRAME_IN_WOL	 0x01000000
+#define  MAC_MODE_APE_RX_EN		 0x08000000
+#define  MAC_MODE_APE_TX_EN		 0x10000000
+#define MAC_STATUS			0x00000404
+#define  MAC_STATUS_PCS_SYNCED		 0x00000001
+#define  MAC_STATUS_SIGNAL_DET		 0x00000002
+#define  MAC_STATUS_RCVD_CFG		 0x00000004
+#define  MAC_STATUS_CFG_CHANGED		 0x00000008
+#define  MAC_STATUS_SYNC_CHANGED	 0x00000010
+#define  MAC_STATUS_PORT_DEC_ERR	 0x00000400
+#define  MAC_STATUS_LNKSTATE_CHANGED	 0x00001000
+#define  MAC_STATUS_MI_COMPLETION	 0x00400000
+#define  MAC_STATUS_MI_INTERRUPT	 0x00800000
+#define  MAC_STATUS_AP_ERROR		 0x01000000
+#define  MAC_STATUS_ODI_ERROR		 0x02000000
+#define  MAC_STATUS_RXSTAT_OVERRUN	 0x04000000
+#define  MAC_STATUS_TXSTAT_OVERRUN	 0x08000000
+#define MAC_EVENT			0x00000408
+#define  MAC_EVENT_PORT_DECODE_ERR	 0x00000400
+#define  MAC_EVENT_LNKSTATE_CHANGED	 0x00001000
+#define  MAC_EVENT_MI_COMPLETION	 0x00400000
+#define  MAC_EVENT_MI_INTERRUPT		 0x00800000
+#define  MAC_EVENT_AP_ERROR		 0x01000000
+#define  MAC_EVENT_ODI_ERROR		 0x02000000
+#define  MAC_EVENT_RXSTAT_OVERRUN	 0x04000000
+#define  MAC_EVENT_TXSTAT_OVERRUN	 0x08000000
+#define MAC_LED_CTRL			0x0000040c
+#define  LED_CTRL_LNKLED_OVERRIDE	 0x00000001
+#define  LED_CTRL_1000MBPS_ON		 0x00000002
+#define  LED_CTRL_100MBPS_ON		 0x00000004
+#define  LED_CTRL_10MBPS_ON		 0x00000008
+#define  LED_CTRL_TRAFFIC_OVERRIDE	 0x00000010
+#define  LED_CTRL_TRAFFIC_BLINK		 0x00000020
+#define  LED_CTRL_TRAFFIC_LED		 0x00000040
+#define  LED_CTRL_1000MBPS_STATUS	 0x00000080
+#define  LED_CTRL_100MBPS_STATUS	 0x00000100
+#define  LED_CTRL_10MBPS_STATUS		 0x00000200
+#define  LED_CTRL_TRAFFIC_STATUS	 0x00000400
+#define  LED_CTRL_MODE_MAC		 0x00000000
+#define  LED_CTRL_MODE_PHY_1		 0x00000800
+#define  LED_CTRL_MODE_PHY_2		 0x00001000
+#define  LED_CTRL_MODE_SHASTA_MAC	 0x00002000
+#define  LED_CTRL_MODE_SHARED		 0x00004000
+#define  LED_CTRL_MODE_COMBO		 0x00008000
+#define  LED_CTRL_BLINK_RATE_MASK	 0x7ff80000
+#define  LED_CTRL_BLINK_RATE_SHIFT	 19
+#define  LED_CTRL_BLINK_PER_OVERRIDE	 0x00080000
+#define  LED_CTRL_BLINK_RATE_OVERRIDE	 0x80000000
+#define MAC_ADDR_0_HIGH			0x00000410 /* upper 2 bytes */
+#define MAC_ADDR_0_LOW			0x00000414 /* lower 4 bytes */
+#define MAC_ADDR_1_HIGH			0x00000418 /* upper 2 bytes */
+#define MAC_ADDR_1_LOW			0x0000041c /* lower 4 bytes */
+#define MAC_ADDR_2_HIGH			0x00000420 /* upper 2 bytes */
+#define MAC_ADDR_2_LOW			0x00000424 /* lower 4 bytes */
+#define MAC_ADDR_3_HIGH			0x00000428 /* upper 2 bytes */
+#define MAC_ADDR_3_LOW			0x0000042c /* lower 4 bytes */
+#define MAC_ACPI_MBUF_PTR		0x00000430
+#define MAC_ACPI_LEN_OFFSET		0x00000434
+#define  ACPI_LENOFF_LEN_MASK		 0x0000ffff
+#define  ACPI_LENOFF_LEN_SHIFT		 0
+#define  ACPI_LENOFF_OFF_MASK		 0x0fff0000
+#define  ACPI_LENOFF_OFF_SHIFT		 16
+#define MAC_TX_BACKOFF_SEED		0x00000438
+#define  TX_BACKOFF_SEED_MASK		 0x000003ff
+#define MAC_RX_MTU_SIZE			0x0000043c
+#define  RX_MTU_SIZE_MASK		 0x0000ffff
+#define MAC_PCS_TEST			0x00000440
+#define  PCS_TEST_PATTERN_MASK		 0x000fffff
+#define  PCS_TEST_PATTERN_SHIFT		 0
+#define  PCS_TEST_ENABLE		 0x00100000
+#define MAC_TX_AUTO_NEG			0x00000444
+#define  TX_AUTO_NEG_MASK		 0x0000ffff
+#define  TX_AUTO_NEG_SHIFT		 0
+#define MAC_RX_AUTO_NEG			0x00000448
+#define  RX_AUTO_NEG_MASK		 0x0000ffff
+#define  RX_AUTO_NEG_SHIFT		 0
+#define MAC_MI_COM			0x0000044c
+#define  MI_COM_CMD_MASK		 0x0c000000
+#define  MI_COM_CMD_WRITE		 0x04000000
+#define  MI_COM_CMD_READ		 0x08000000
+#define  MI_COM_READ_FAILED		 0x10000000
+#define  MI_COM_START			 0x20000000
+#define  MI_COM_BUSY			 0x20000000
+#define  MI_COM_PHY_ADDR_MASK		 0x03e00000
+#define  MI_COM_PHY_ADDR_SHIFT		 21
+#define  MI_COM_REG_ADDR_MASK		 0x001f0000
+#define  MI_COM_REG_ADDR_SHIFT		 16
+#define  MI_COM_DATA_MASK		 0x0000ffff
+#define MAC_MI_STAT			0x00000450
+#define  MAC_MI_STAT_LNKSTAT_ATTN_ENAB	 0x00000001
+#define  MAC_MI_STAT_10MBPS_MODE	 0x00000002
+#define MAC_MI_MODE			0x00000454
+#define  MAC_MI_MODE_CLK_10MHZ		 0x00000001
+#define  MAC_MI_MODE_SHORT_PREAMBLE	 0x00000002
+#define  MAC_MI_MODE_AUTO_POLL		 0x00000010
+#define  MAC_MI_MODE_500KHZ_CONST	 0x00008000
+#define  MAC_MI_MODE_BASE		 0x000c0000 /* XXX magic values XXX */
+#define MAC_AUTO_POLL_STATUS		0x00000458
+#define  MAC_AUTO_POLL_ERROR		 0x00000001
+#define MAC_TX_MODE			0x0000045c
+#define  TX_MODE_RESET			 0x00000001
+#define  TX_MODE_ENABLE			 0x00000002
+#define  TX_MODE_FLOW_CTRL_ENABLE	 0x00000010
+#define  TX_MODE_BIG_BCKOFF_ENABLE	 0x00000020
+#define  TX_MODE_LONG_PAUSE_ENABLE	 0x00000040
+#define  TX_MODE_MBUF_LOCKUP_FIX	 0x00000100
+#define  TX_MODE_JMB_FRM_LEN		 0x00400000
+#define  TX_MODE_CNT_DN_MODE		 0x00800000
+#define MAC_TX_STATUS			0x00000460
+#define  TX_STATUS_XOFFED		 0x00000001
+#define  TX_STATUS_SENT_XOFF		 0x00000002
+#define  TX_STATUS_SENT_XON		 0x00000004
+#define  TX_STATUS_LINK_UP		 0x00000008
+#define  TX_STATUS_ODI_UNDERRUN		 0x00000010
+#define  TX_STATUS_ODI_OVERRUN		 0x00000020
+#define MAC_TX_LENGTHS			0x00000464
+#define  TX_LENGTHS_SLOT_TIME_MASK	 0x000000ff
+#define  TX_LENGTHS_SLOT_TIME_SHIFT	 0
+#define  TX_LENGTHS_IPG_MASK		 0x00000f00
+#define  TX_LENGTHS_IPG_SHIFT		 8
+#define  TX_LENGTHS_IPG_CRS_MASK	 0x00003000
+#define  TX_LENGTHS_IPG_CRS_SHIFT	 12
+#define  TX_LENGTHS_JMB_FRM_LEN_MSK	 0x00ff0000
+#define  TX_LENGTHS_CNT_DWN_VAL_MSK	 0xff000000
+#define MAC_RX_MODE			0x00000468
+#define  RX_MODE_RESET			 0x00000001
+#define  RX_MODE_ENABLE			 0x00000002
+#define  RX_MODE_FLOW_CTRL_ENABLE	 0x00000004
+#define  RX_MODE_KEEP_MAC_CTRL		 0x00000008
+#define  RX_MODE_KEEP_PAUSE		 0x00000010
+#define  RX_MODE_ACCEPT_OVERSIZED	 0x00000020
+#define  RX_MODE_ACCEPT_RUNTS		 0x00000040
+#define  RX_MODE_LEN_CHECK		 0x00000080
+#define  RX_MODE_PROMISC		 0x00000100
+#define  RX_MODE_NO_CRC_CHECK		 0x00000200
+#define  RX_MODE_KEEP_VLAN_TAG		 0x00000400
+#define  RX_MODE_RSS_IPV4_HASH_EN	 0x00010000
+#define  RX_MODE_RSS_TCP_IPV4_HASH_EN	 0x00020000
+#define  RX_MODE_RSS_IPV6_HASH_EN	 0x00040000
+#define  RX_MODE_RSS_TCP_IPV6_HASH_EN	 0x00080000
+#define  RX_MODE_RSS_ITBL_HASH_BITS_7	 0x00700000
+#define  RX_MODE_RSS_ENABLE		 0x00800000
+#define  RX_MODE_IPV6_CSUM_ENABLE	 0x01000000
+#define MAC_RX_STATUS			0x0000046c
+#define  RX_STATUS_REMOTE_TX_XOFFED	 0x00000001
+#define  RX_STATUS_XOFF_RCVD		 0x00000002
+#define  RX_STATUS_XON_RCVD		 0x00000004
+#define MAC_HASH_REG_0			0x00000470
+#define MAC_HASH_REG_1			0x00000474
+#define MAC_HASH_REG_2			0x00000478
+#define MAC_HASH_REG_3			0x0000047c
+#define MAC_RCV_RULE_0			0x00000480
+#define MAC_RCV_VALUE_0			0x00000484
+#define MAC_RCV_RULE_1			0x00000488
+#define MAC_RCV_VALUE_1			0x0000048c
+#define MAC_RCV_RULE_2			0x00000490
+#define MAC_RCV_VALUE_2			0x00000494
+#define MAC_RCV_RULE_3			0x00000498
+#define MAC_RCV_VALUE_3			0x0000049c
+#define MAC_RCV_RULE_4			0x000004a0
+#define MAC_RCV_VALUE_4			0x000004a4
+#define MAC_RCV_RULE_5			0x000004a8
+#define MAC_RCV_VALUE_5			0x000004ac
+#define MAC_RCV_RULE_6			0x000004b0
+#define MAC_RCV_VALUE_6			0x000004b4
+#define MAC_RCV_RULE_7			0x000004b8
+#define MAC_RCV_VALUE_7			0x000004bc
+#define MAC_RCV_RULE_8			0x000004c0
+#define MAC_RCV_VALUE_8			0x000004c4
+#define MAC_RCV_RULE_9			0x000004c8
+#define MAC_RCV_VALUE_9			0x000004cc
+#define MAC_RCV_RULE_10			0x000004d0
+#define MAC_RCV_VALUE_10		0x000004d4
+#define MAC_RCV_RULE_11			0x000004d8
+#define MAC_RCV_VALUE_11		0x000004dc
+#define MAC_RCV_RULE_12			0x000004e0
+#define MAC_RCV_VALUE_12		0x000004e4
+#define MAC_RCV_RULE_13			0x000004e8
+#define MAC_RCV_VALUE_13		0x000004ec
+#define MAC_RCV_RULE_14			0x000004f0
+#define MAC_RCV_VALUE_14		0x000004f4
+#define MAC_RCV_RULE_15			0x000004f8
+#define MAC_RCV_VALUE_15		0x000004fc
+#define  RCV_RULE_DISABLE_MASK		 0x7fffffff
+#define MAC_RCV_RULE_CFG		0x00000500
+#define  RCV_RULE_CFG_DEFAULT_CLASS	0x00000008
+#define MAC_LOW_WMARK_MAX_RX_FRAME	0x00000504
+/* 0x508 --> 0x520 unused */
+#define MAC_HASHREGU_0			0x00000520
+#define MAC_HASHREGU_1			0x00000524
+#define MAC_HASHREGU_2			0x00000528
+#define MAC_HASHREGU_3			0x0000052c
+#define MAC_EXTADDR_0_HIGH		0x00000530
+#define MAC_EXTADDR_0_LOW		0x00000534
+#define MAC_EXTADDR_1_HIGH		0x00000538
+#define MAC_EXTADDR_1_LOW		0x0000053c
+#define MAC_EXTADDR_2_HIGH		0x00000540
+#define MAC_EXTADDR_2_LOW		0x00000544
+#define MAC_EXTADDR_3_HIGH		0x00000548
+#define MAC_EXTADDR_3_LOW		0x0000054c
+#define MAC_EXTADDR_4_HIGH		0x00000550
+#define MAC_EXTADDR_4_LOW		0x00000554
+#define MAC_EXTADDR_5_HIGH		0x00000558
+#define MAC_EXTADDR_5_LOW		0x0000055c
+#define MAC_EXTADDR_6_HIGH		0x00000560
+#define MAC_EXTADDR_6_LOW		0x00000564
+#define MAC_EXTADDR_7_HIGH		0x00000568
+#define MAC_EXTADDR_7_LOW		0x0000056c
+#define MAC_EXTADDR_8_HIGH		0x00000570
+#define MAC_EXTADDR_8_LOW		0x00000574
+#define MAC_EXTADDR_9_HIGH		0x00000578
+#define MAC_EXTADDR_9_LOW		0x0000057c
+#define MAC_EXTADDR_10_HIGH		0x00000580
+#define MAC_EXTADDR_10_LOW		0x00000584
+#define MAC_EXTADDR_11_HIGH		0x00000588
+#define MAC_EXTADDR_11_LOW		0x0000058c
+#define MAC_SERDES_CFG			0x00000590
+#define  MAC_SERDES_CFG_EDGE_SELECT	 0x00001000
+#define MAC_SERDES_STAT			0x00000594
+/* 0x598 --> 0x5a0 unused */
+#define MAC_PHYCFG1			0x000005a0
+#define  MAC_PHYCFG1_RGMII_INT		 0x00000001
+#define  MAC_PHYCFG1_RXCLK_TO_MASK	 0x00001ff0
+#define  MAC_PHYCFG1_RXCLK_TIMEOUT	 0x00001000
+#define  MAC_PHYCFG1_TXCLK_TO_MASK	 0x01ff0000
+#define  MAC_PHYCFG1_TXCLK_TIMEOUT	 0x01000000
+#define  MAC_PHYCFG1_RGMII_EXT_RX_DEC	 0x02000000
+#define  MAC_PHYCFG1_RGMII_SND_STAT_EN	 0x04000000
+#define  MAC_PHYCFG1_TXC_DRV		 0x20000000
+#define MAC_PHYCFG2			0x000005a4
+#define  MAC_PHYCFG2_INBAND_ENABLE	 0x00000001
+#define  MAC_PHYCFG2_EMODE_MASK_MASK	 0x000001c0
+#define  MAC_PHYCFG2_EMODE_MASK_AC131	 0x000000c0
+#define  MAC_PHYCFG2_EMODE_MASK_50610	 0x00000100
+#define  MAC_PHYCFG2_EMODE_MASK_RT8211	 0x00000000
+#define  MAC_PHYCFG2_EMODE_MASK_RT8201	 0x000001c0
+#define  MAC_PHYCFG2_EMODE_COMP_MASK	 0x00000e00
+#define  MAC_PHYCFG2_EMODE_COMP_AC131	 0x00000600
+#define  MAC_PHYCFG2_EMODE_COMP_50610	 0x00000400
+#define  MAC_PHYCFG2_EMODE_COMP_RT8211	 0x00000800
+#define  MAC_PHYCFG2_EMODE_COMP_RT8201	 0x00000000
+#define  MAC_PHYCFG2_FMODE_MASK_MASK	 0x00007000
+#define  MAC_PHYCFG2_FMODE_MASK_AC131	 0x00006000
+#define  MAC_PHYCFG2_FMODE_MASK_50610	 0x00004000
+#define  MAC_PHYCFG2_FMODE_MASK_RT8211	 0x00000000
+#define  MAC_PHYCFG2_FMODE_MASK_RT8201	 0x00007000
+#define  MAC_PHYCFG2_FMODE_COMP_MASK	 0x00038000
+#define  MAC_PHYCFG2_FMODE_COMP_AC131	 0x00030000
+#define  MAC_PHYCFG2_FMODE_COMP_50610	 0x00008000
+#define  MAC_PHYCFG2_FMODE_COMP_RT8211	 0x00038000
+#define  MAC_PHYCFG2_FMODE_COMP_RT8201	 0x00000000
+#define  MAC_PHYCFG2_GMODE_MASK_MASK	 0x001c0000
+#define  MAC_PHYCFG2_GMODE_MASK_AC131	 0x001c0000
+#define  MAC_PHYCFG2_GMODE_MASK_50610	 0x00100000
+#define  MAC_PHYCFG2_GMODE_MASK_RT8211	 0x00000000
+#define  MAC_PHYCFG2_GMODE_MASK_RT8201	 0x001c0000
+#define  MAC_PHYCFG2_GMODE_COMP_MASK	 0x00e00000
+#define  MAC_PHYCFG2_GMODE_COMP_AC131	 0x00e00000
+#define  MAC_PHYCFG2_GMODE_COMP_50610	 0x00000000
+#define  MAC_PHYCFG2_GMODE_COMP_RT8211	 0x00200000
+#define  MAC_PHYCFG2_GMODE_COMP_RT8201	 0x00000000
+#define  MAC_PHYCFG2_ACT_MASK_MASK	 0x03000000
+#define  MAC_PHYCFG2_ACT_MASK_AC131	 0x03000000
+#define  MAC_PHYCFG2_ACT_MASK_50610	 0x01000000
+#define  MAC_PHYCFG2_ACT_MASK_RT8211	 0x03000000
+#define  MAC_PHYCFG2_ACT_MASK_RT8201	 0x01000000
+#define  MAC_PHYCFG2_ACT_COMP_MASK	 0x0c000000
+#define  MAC_PHYCFG2_ACT_COMP_AC131	 0x00000000
+#define  MAC_PHYCFG2_ACT_COMP_50610	 0x00000000
+#define  MAC_PHYCFG2_ACT_COMP_RT8211	 0x00000000
+#define  MAC_PHYCFG2_ACT_COMP_RT8201	 0x08000000
+#define  MAC_PHYCFG2_QUAL_MASK_MASK	 0x30000000
+#define  MAC_PHYCFG2_QUAL_MASK_AC131	 0x30000000
+#define  MAC_PHYCFG2_QUAL_MASK_50610	 0x30000000
+#define  MAC_PHYCFG2_QUAL_MASK_RT8211	 0x30000000
+#define  MAC_PHYCFG2_QUAL_MASK_RT8201	 0x30000000
+#define  MAC_PHYCFG2_QUAL_COMP_MASK	 0xc0000000
+#define  MAC_PHYCFG2_QUAL_COMP_AC131	 0x00000000
+#define  MAC_PHYCFG2_QUAL_COMP_50610	 0x00000000
+#define  MAC_PHYCFG2_QUAL_COMP_RT8211	 0x00000000
+#define  MAC_PHYCFG2_QUAL_COMP_RT8201	 0x00000000
+#define MAC_PHYCFG2_50610_LED_MODES \
+	(MAC_PHYCFG2_EMODE_MASK_50610 | \
+	 MAC_PHYCFG2_EMODE_COMP_50610 | \
+	 MAC_PHYCFG2_FMODE_MASK_50610 | \
+	 MAC_PHYCFG2_FMODE_COMP_50610 | \
+	 MAC_PHYCFG2_GMODE_MASK_50610 | \
+	 MAC_PHYCFG2_GMODE_COMP_50610 | \
+	 MAC_PHYCFG2_ACT_MASK_50610 | \
+	 MAC_PHYCFG2_ACT_COMP_50610 | \
+	 MAC_PHYCFG2_QUAL_MASK_50610 | \
+	 MAC_PHYCFG2_QUAL_COMP_50610)
+#define MAC_PHYCFG2_AC131_LED_MODES \
+	(MAC_PHYCFG2_EMODE_MASK_AC131 | \
+	 MAC_PHYCFG2_EMODE_COMP_AC131 | \
+	 MAC_PHYCFG2_FMODE_MASK_AC131 | \
+	 MAC_PHYCFG2_FMODE_COMP_AC131 | \
+	 MAC_PHYCFG2_GMODE_MASK_AC131 | \
+	 MAC_PHYCFG2_GMODE_COMP_AC131 | \
+	 MAC_PHYCFG2_ACT_MASK_AC131 | \
+	 MAC_PHYCFG2_ACT_COMP_AC131 | \
+	 MAC_PHYCFG2_QUAL_MASK_AC131 | \
+	 MAC_PHYCFG2_QUAL_COMP_AC131)
+#define MAC_PHYCFG2_RTL8211C_LED_MODES \
+	(MAC_PHYCFG2_EMODE_MASK_RT8211 | \
+	 MAC_PHYCFG2_EMODE_COMP_RT8211 | \
+	 MAC_PHYCFG2_FMODE_MASK_RT8211 | \
+	 MAC_PHYCFG2_FMODE_COMP_RT8211 | \
+	 MAC_PHYCFG2_GMODE_MASK_RT8211 | \
+	 MAC_PHYCFG2_GMODE_COMP_RT8211 | \
+	 MAC_PHYCFG2_ACT_MASK_RT8211 | \
+	 MAC_PHYCFG2_ACT_COMP_RT8211 | \
+	 MAC_PHYCFG2_QUAL_MASK_RT8211 | \
+	 MAC_PHYCFG2_QUAL_COMP_RT8211)
+#define MAC_PHYCFG2_RTL8201E_LED_MODES \
+	(MAC_PHYCFG2_EMODE_MASK_RT8201 | \
+	 MAC_PHYCFG2_EMODE_COMP_RT8201 | \
+	 MAC_PHYCFG2_FMODE_MASK_RT8201 | \
+	 MAC_PHYCFG2_FMODE_COMP_RT8201 | \
+	 MAC_PHYCFG2_GMODE_MASK_RT8201 | \
+	 MAC_PHYCFG2_GMODE_COMP_RT8201 | \
+	 MAC_PHYCFG2_ACT_MASK_RT8201 | \
+	 MAC_PHYCFG2_ACT_COMP_RT8201 | \
+	 MAC_PHYCFG2_QUAL_MASK_RT8201 | \
+	 MAC_PHYCFG2_QUAL_COMP_RT8201)
+#define MAC_EXT_RGMII_MODE		0x000005a8
+#define  MAC_RGMII_MODE_TX_ENABLE	 0x00000001
+#define  MAC_RGMII_MODE_TX_LOWPWR	 0x00000002
+#define  MAC_RGMII_MODE_TX_RESET	 0x00000004
+#define  MAC_RGMII_MODE_RX_INT_B	 0x00000100
+#define  MAC_RGMII_MODE_RX_QUALITY	 0x00000200
+#define  MAC_RGMII_MODE_RX_ACTIVITY	 0x00000400
+#define  MAC_RGMII_MODE_RX_ENG_DET	 0x00000800
+/* 0x5ac --> 0x5b0 unused */
+#define SERDES_RX_CTRL			0x000005b0	/* 5780/5714 only */
+#define  SERDES_RX_SIG_DETECT		 0x00000400
+#define SG_DIG_CTRL			0x000005b0
+#define  SG_DIG_USING_HW_AUTONEG	 0x80000000
+#define  SG_DIG_SOFT_RESET		 0x40000000
+#define  SG_DIG_DISABLE_LINKRDY		 0x20000000
+#define  SG_DIG_CRC16_CLEAR_N		 0x01000000
+#define  SG_DIG_EN10B			 0x00800000
+#define  SG_DIG_CLEAR_STATUS		 0x00400000
+#define  SG_DIG_LOCAL_DUPLEX_STATUS	 0x00200000
+#define  SG_DIG_LOCAL_LINK_STATUS	 0x00100000
+#define  SG_DIG_SPEED_STATUS_MASK	 0x000c0000
+#define  SG_DIG_SPEED_STATUS_SHIFT	 18
+#define  SG_DIG_JUMBO_PACKET_DISABLE	 0x00020000
+#define  SG_DIG_RESTART_AUTONEG		 0x00010000
+#define  SG_DIG_FIBER_MODE		 0x00008000
+#define  SG_DIG_REMOTE_FAULT_MASK	 0x00006000
+#define  SG_DIG_PAUSE_MASK		 0x00001800
+#define  SG_DIG_PAUSE_CAP		 0x00000800
+#define  SG_DIG_ASYM_PAUSE		 0x00001000
+#define  SG_DIG_GBIC_ENABLE		 0x00000400
+#define  SG_DIG_CHECK_END_ENABLE	 0x00000200
+#define  SG_DIG_SGMII_AUTONEG_TIMER	 0x00000100
+#define  SG_DIG_CLOCK_PHASE_SELECT	 0x00000080
+#define  SG_DIG_GMII_INPUT_SELECT	 0x00000040
+#define  SG_DIG_MRADV_CRC16_SELECT	 0x00000020
+#define  SG_DIG_COMMA_DETECT_ENABLE	 0x00000010
+#define  SG_DIG_AUTONEG_TIMER_REDUCE	 0x00000008
+#define  SG_DIG_AUTONEG_LOW_ENABLE	 0x00000004
+#define  SG_DIG_REMOTE_LOOPBACK		 0x00000002
+#define  SG_DIG_LOOPBACK		 0x00000001
+#define  SG_DIG_COMMON_SETUP (SG_DIG_CRC16_CLEAR_N | \
+			      SG_DIG_LOCAL_DUPLEX_STATUS | \
+			      SG_DIG_LOCAL_LINK_STATUS | \
+			      (0x2 << SG_DIG_SPEED_STATUS_SHIFT) | \
+			      SG_DIG_FIBER_MODE | SG_DIG_GBIC_ENABLE)
+#define SG_DIG_STATUS			0x000005b4
+#define  SG_DIG_CRC16_BUS_MASK		 0xffff0000
+#define  SG_DIG_PARTNER_FAULT_MASK	 0x00600000 /* If !MRADV_CRC16_SELECT */
+#define  SG_DIG_PARTNER_ASYM_PAUSE	 0x00100000 /* If !MRADV_CRC16_SELECT */
+#define  SG_DIG_PARTNER_PAUSE_CAPABLE	 0x00080000 /* If !MRADV_CRC16_SELECT */
+#define  SG_DIG_PARTNER_HALF_DUPLEX	 0x00040000 /* If !MRADV_CRC16_SELECT */
+#define  SG_DIG_PARTNER_FULL_DUPLEX	 0x00020000 /* If !MRADV_CRC16_SELECT */
+#define  SG_DIG_PARTNER_NEXT_PAGE	 0x00010000 /* If !MRADV_CRC16_SELECT */
+#define  SG_DIG_AUTONEG_STATE_MASK	 0x00000ff0
+#define  SG_DIG_IS_SERDES		 0x00000100
+#define  SG_DIG_COMMA_DETECTOR		 0x00000008
+#define  SG_DIG_MAC_ACK_STATUS		 0x00000004
+#define  SG_DIG_AUTONEG_COMPLETE	 0x00000002
+#define  SG_DIG_AUTONEG_ERROR		 0x00000001
+/* 0x5b8 --> 0x600 unused */
+#define MAC_TX_MAC_STATE_BASE		0x00000600 /* 16 bytes */
+#define MAC_RX_MAC_STATE_BASE		0x00000610 /* 20 bytes */
+/* 0x624 --> 0x670 unused */
+
+#define MAC_RSS_INDIR_TBL_0		0x00000630
+
+#define MAC_RSS_HASH_KEY_0		0x00000670
+#define MAC_RSS_HASH_KEY_1		0x00000674
+#define MAC_RSS_HASH_KEY_2		0x00000678
+#define MAC_RSS_HASH_KEY_3		0x0000067c
+#define MAC_RSS_HASH_KEY_4		0x00000680
+#define MAC_RSS_HASH_KEY_5		0x00000684
+#define MAC_RSS_HASH_KEY_6		0x00000688
+#define MAC_RSS_HASH_KEY_7		0x0000068c
+#define MAC_RSS_HASH_KEY_8		0x00000690
+#define MAC_RSS_HASH_KEY_9		0x00000694
+/* 0x698 --> 0x800 unused */
+
+#define MAC_TX_STATS_OCTETS		0x00000800
+#define MAC_TX_STATS_RESV1		0x00000804
+#define MAC_TX_STATS_COLLISIONS		0x00000808
+#define MAC_TX_STATS_XON_SENT		0x0000080c
+#define MAC_TX_STATS_XOFF_SENT		0x00000810
+#define MAC_TX_STATS_RESV2		0x00000814
+#define MAC_TX_STATS_MAC_ERRORS		0x00000818
+#define MAC_TX_STATS_SINGLE_COLLISIONS	0x0000081c
+#define MAC_TX_STATS_MULT_COLLISIONS	0x00000820
+#define MAC_TX_STATS_DEFERRED		0x00000824
+#define MAC_TX_STATS_RESV3		0x00000828
+#define MAC_TX_STATS_EXCESSIVE_COL	0x0000082c
+#define MAC_TX_STATS_LATE_COL		0x00000830
+#define MAC_TX_STATS_RESV4_1		0x00000834
+#define MAC_TX_STATS_RESV4_2		0x00000838
+#define MAC_TX_STATS_RESV4_3		0x0000083c
+#define MAC_TX_STATS_RESV4_4		0x00000840
+#define MAC_TX_STATS_RESV4_5		0x00000844
+#define MAC_TX_STATS_RESV4_6		0x00000848
+#define MAC_TX_STATS_RESV4_7		0x0000084c
+#define MAC_TX_STATS_RESV4_8		0x00000850
+#define MAC_TX_STATS_RESV4_9		0x00000854
+#define MAC_TX_STATS_RESV4_10		0x00000858
+#define MAC_TX_STATS_RESV4_11		0x0000085c
+#define MAC_TX_STATS_RESV4_12		0x00000860
+#define MAC_TX_STATS_RESV4_13		0x00000864
+#define MAC_TX_STATS_RESV4_14		0x00000868
+#define MAC_TX_STATS_UCAST		0x0000086c
+#define MAC_TX_STATS_MCAST		0x00000870
+#define MAC_TX_STATS_BCAST		0x00000874
+#define MAC_TX_STATS_RESV5_1		0x00000878
+#define MAC_TX_STATS_RESV5_2		0x0000087c
+#define MAC_RX_STATS_OCTETS		0x00000880
+#define MAC_RX_STATS_RESV1		0x00000884
+#define MAC_RX_STATS_FRAGMENTS		0x00000888
+#define MAC_RX_STATS_UCAST		0x0000088c
+#define MAC_RX_STATS_MCAST		0x00000890
+#define MAC_RX_STATS_BCAST		0x00000894
+#define MAC_RX_STATS_FCS_ERRORS		0x00000898
+#define MAC_RX_STATS_ALIGN_ERRORS	0x0000089c
+#define MAC_RX_STATS_XON_PAUSE_RECVD	0x000008a0
+#define MAC_RX_STATS_XOFF_PAUSE_RECVD	0x000008a4
+#define MAC_RX_STATS_MAC_CTRL_RECVD	0x000008a8
+#define MAC_RX_STATS_XOFF_ENTERED	0x000008ac
+#define MAC_RX_STATS_FRAME_TOO_LONG	0x000008b0
+#define MAC_RX_STATS_JABBERS		0x000008b4
+#define MAC_RX_STATS_UNDERSIZE		0x000008b8
+/* 0x8bc --> 0xc00 unused */
+
+/* Send data initiator control registers */
+#define SNDDATAI_MODE			0x00000c00
+#define  SNDDATAI_MODE_RESET		 0x00000001
+#define  SNDDATAI_MODE_ENABLE		 0x00000002
+#define  SNDDATAI_MODE_STAT_OFLOW_ENAB	 0x00000004
+#define SNDDATAI_STATUS			0x00000c04
+#define  SNDDATAI_STATUS_STAT_OFLOW	 0x00000004
+#define SNDDATAI_STATSCTRL		0x00000c08
+#define  SNDDATAI_SCTRL_ENABLE		 0x00000001
+#define  SNDDATAI_SCTRL_FASTUPD		 0x00000002
+#define  SNDDATAI_SCTRL_CLEAR		 0x00000004
+#define  SNDDATAI_SCTRL_FLUSH		 0x00000008
+#define  SNDDATAI_SCTRL_FORCE_ZERO	 0x00000010
+#define SNDDATAI_STATSENAB		0x00000c0c
+#define SNDDATAI_STATSINCMASK		0x00000c10
+#define ISO_PKT_TX			0x00000c20
+/* 0xc24 --> 0xc80 unused */
+#define SNDDATAI_COS_CNT_0		0x00000c80
+#define SNDDATAI_COS_CNT_1		0x00000c84
+#define SNDDATAI_COS_CNT_2		0x00000c88
+#define SNDDATAI_COS_CNT_3		0x00000c8c
+#define SNDDATAI_COS_CNT_4		0x00000c90
+#define SNDDATAI_COS_CNT_5		0x00000c94
+#define SNDDATAI_COS_CNT_6		0x00000c98
+#define SNDDATAI_COS_CNT_7		0x00000c9c
+#define SNDDATAI_COS_CNT_8		0x00000ca0
+#define SNDDATAI_COS_CNT_9		0x00000ca4
+#define SNDDATAI_COS_CNT_10		0x00000ca8
+#define SNDDATAI_COS_CNT_11		0x00000cac
+#define SNDDATAI_COS_CNT_12		0x00000cb0
+#define SNDDATAI_COS_CNT_13		0x00000cb4
+#define SNDDATAI_COS_CNT_14		0x00000cb8
+#define SNDDATAI_COS_CNT_15		0x00000cbc
+#define SNDDATAI_DMA_RDQ_FULL_CNT	0x00000cc0
+#define SNDDATAI_DMA_PRIO_RDQ_FULL_CNT	0x00000cc4
+#define SNDDATAI_SDCQ_FULL_CNT		0x00000cc8
+#define SNDDATAI_NICRNG_SSND_PIDX_CNT	0x00000ccc
+#define SNDDATAI_STATS_UPDATED_CNT	0x00000cd0
+#define SNDDATAI_INTERRUPTS_CNT		0x00000cd4
+#define SNDDATAI_AVOID_INTERRUPTS_CNT	0x00000cd8
+#define SNDDATAI_SND_THRESH_HIT_CNT	0x00000cdc
+/* 0xce0 --> 0x1000 unused */
+
+/* Send data completion control registers */
+#define SNDDATAC_MODE			0x00001000
+#define  SNDDATAC_MODE_RESET		 0x00000001
+#define  SNDDATAC_MODE_ENABLE		 0x00000002
+#define  SNDDATAC_MODE_CDELAY		 0x00000010
+/* 0x1004 --> 0x1400 unused */
+
+/* Send BD ring selector */
+#define SNDBDS_MODE			0x00001400
+#define  SNDBDS_MODE_RESET		 0x00000001
+#define  SNDBDS_MODE_ENABLE		 0x00000002
+#define  SNDBDS_MODE_ATTN_ENABLE	 0x00000004
+#define SNDBDS_STATUS			0x00001404
+#define  SNDBDS_STATUS_ERROR_ATTN	 0x00000004
+#define SNDBDS_HWDIAG			0x00001408
+/* 0x140c --> 0x1440 */
+#define SNDBDS_SEL_CON_IDX_0		0x00001440
+#define SNDBDS_SEL_CON_IDX_1		0x00001444
+#define SNDBDS_SEL_CON_IDX_2		0x00001448
+#define SNDBDS_SEL_CON_IDX_3		0x0000144c
+#define SNDBDS_SEL_CON_IDX_4		0x00001450
+#define SNDBDS_SEL_CON_IDX_5		0x00001454
+#define SNDBDS_SEL_CON_IDX_6		0x00001458
+#define SNDBDS_SEL_CON_IDX_7		0x0000145c
+#define SNDBDS_SEL_CON_IDX_8		0x00001460
+#define SNDBDS_SEL_CON_IDX_9		0x00001464
+#define SNDBDS_SEL_CON_IDX_10		0x00001468
+#define SNDBDS_SEL_CON_IDX_11		0x0000146c
+#define SNDBDS_SEL_CON_IDX_12		0x00001470
+#define SNDBDS_SEL_CON_IDX_13		0x00001474
+#define SNDBDS_SEL_CON_IDX_14		0x00001478
+#define SNDBDS_SEL_CON_IDX_15		0x0000147c
+/* 0x1480 --> 0x1800 unused */
+
+/* Send BD initiator control registers */
+#define SNDBDI_MODE			0x00001800
+#define  SNDBDI_MODE_RESET		 0x00000001
+#define  SNDBDI_MODE_ENABLE		 0x00000002
+#define  SNDBDI_MODE_ATTN_ENABLE	 0x00000004
+#define  SNDBDI_MODE_MULTI_TXQ_EN	 0x00000020
+#define SNDBDI_STATUS			0x00001804
+#define  SNDBDI_STATUS_ERROR_ATTN	 0x00000004
+#define SNDBDI_IN_PROD_IDX_0		0x00001808
+#define SNDBDI_IN_PROD_IDX_1		0x0000180c
+#define SNDBDI_IN_PROD_IDX_2		0x00001810
+#define SNDBDI_IN_PROD_IDX_3		0x00001814
+#define SNDBDI_IN_PROD_IDX_4		0x00001818
+#define SNDBDI_IN_PROD_IDX_5		0x0000181c
+#define SNDBDI_IN_PROD_IDX_6		0x00001820
+#define SNDBDI_IN_PROD_IDX_7		0x00001824
+#define SNDBDI_IN_PROD_IDX_8		0x00001828
+#define SNDBDI_IN_PROD_IDX_9		0x0000182c
+#define SNDBDI_IN_PROD_IDX_10		0x00001830
+#define SNDBDI_IN_PROD_IDX_11		0x00001834
+#define SNDBDI_IN_PROD_IDX_12		0x00001838
+#define SNDBDI_IN_PROD_IDX_13		0x0000183c
+#define SNDBDI_IN_PROD_IDX_14		0x00001840
+#define SNDBDI_IN_PROD_IDX_15		0x00001844
+/* 0x1848 --> 0x1c00 unused */
+
+/* Send BD completion control registers */
+#define SNDBDC_MODE			0x00001c00
+#define SNDBDC_MODE_RESET		 0x00000001
+#define SNDBDC_MODE_ENABLE		 0x00000002
+#define SNDBDC_MODE_ATTN_ENABLE		 0x00000004
+/* 0x1c04 --> 0x2000 unused */
+
+/* Receive list placement control registers */
+#define RCVLPC_MODE			0x00002000
+#define  RCVLPC_MODE_RESET		 0x00000001
+#define  RCVLPC_MODE_ENABLE		 0x00000002
+#define  RCVLPC_MODE_CLASS0_ATTN_ENAB	 0x00000004
+#define  RCVLPC_MODE_MAPOOR_AATTN_ENAB	 0x00000008
+#define  RCVLPC_MODE_STAT_OFLOW_ENAB	 0x00000010
+#define RCVLPC_STATUS			0x00002004
+#define  RCVLPC_STATUS_CLASS0		 0x00000004
+#define  RCVLPC_STATUS_MAPOOR		 0x00000008
+#define  RCVLPC_STATUS_STAT_OFLOW	 0x00000010
+#define RCVLPC_LOCK			0x00002008
+#define  RCVLPC_LOCK_REQ_MASK		 0x0000ffff
+#define  RCVLPC_LOCK_REQ_SHIFT		 0
+#define  RCVLPC_LOCK_GRANT_MASK		 0xffff0000
+#define  RCVLPC_LOCK_GRANT_SHIFT	 16
+#define RCVLPC_NON_EMPTY_BITS		0x0000200c
+#define  RCVLPC_NON_EMPTY_BITS_MASK	 0x0000ffff
+#define RCVLPC_CONFIG			0x00002010
+#define RCVLPC_STATSCTRL		0x00002014
+#define  RCVLPC_STATSCTRL_ENABLE	 0x00000001
+#define  RCVLPC_STATSCTRL_FASTUPD	 0x00000002
+#define RCVLPC_STATS_ENABLE		0x00002018
+#define  RCVLPC_STATSENAB_ASF_FIX	 0x00000002
+#define  RCVLPC_STATSENAB_DACK_FIX	 0x00040000
+#define  RCVLPC_STATSENAB_LNGBRST_RFIX	 0x00400000
+#define RCVLPC_STATS_INCMASK		0x0000201c
+/* 0x2020 --> 0x2100 unused */
+#define RCVLPC_SELLST_BASE		0x00002100 /* 16 16-byte entries */
+#define  SELLST_TAIL			0x00000004
+#define  SELLST_CONT			0x00000008
+#define  SELLST_UNUSED			0x0000000c
+#define RCVLPC_COS_CNTL_BASE		0x00002200 /* 16 4-byte entries */
+#define RCVLPC_DROP_FILTER_CNT		0x00002240
+#define RCVLPC_DMA_WQ_FULL_CNT		0x00002244
+#define RCVLPC_DMA_HIPRIO_WQ_FULL_CNT	0x00002248
+#define RCVLPC_NO_RCV_BD_CNT		0x0000224c
+#define RCVLPC_IN_DISCARDS_CNT		0x00002250
+#define RCVLPC_IN_ERRORS_CNT		0x00002254
+#define RCVLPC_RCV_THRESH_HIT_CNT	0x00002258
+/* 0x225c --> 0x2400 unused */
+
+/* Receive Data and Receive BD Initiator Control */
+#define RCVDBDI_MODE			0x00002400
+#define  RCVDBDI_MODE_RESET		 0x00000001
+#define  RCVDBDI_MODE_ENABLE		 0x00000002
+#define  RCVDBDI_MODE_JUMBOBD_NEEDED	 0x00000004
+#define  RCVDBDI_MODE_FRM_TOO_BIG	 0x00000008
+#define  RCVDBDI_MODE_INV_RING_SZ	 0x00000010
+#define  RCVDBDI_MODE_LRG_RING_SZ	 0x00010000
+#define RCVDBDI_STATUS			0x00002404
+#define  RCVDBDI_STATUS_JUMBOBD_NEEDED	 0x00000004
+#define  RCVDBDI_STATUS_FRM_TOO_BIG	 0x00000008
+#define  RCVDBDI_STATUS_INV_RING_SZ	 0x00000010
+#define RCVDBDI_SPLIT_FRAME_MINSZ	0x00002408
+/* 0x240c --> 0x2440 unused */
+#define RCVDBDI_JUMBO_BD		0x00002440 /* TG3_BDINFO_... */
+#define RCVDBDI_STD_BD			0x00002450 /* TG3_BDINFO_... */
+#define RCVDBDI_MINI_BD			0x00002460 /* TG3_BDINFO_... */
+#define RCVDBDI_JUMBO_CON_IDX		0x00002470
+#define RCVDBDI_STD_CON_IDX		0x00002474
+#define RCVDBDI_MINI_CON_IDX		0x00002478
+/* 0x247c --> 0x2480 unused */
+#define RCVDBDI_BD_PROD_IDX_0		0x00002480
+#define RCVDBDI_BD_PROD_IDX_1		0x00002484
+#define RCVDBDI_BD_PROD_IDX_2		0x00002488
+#define RCVDBDI_BD_PROD_IDX_3		0x0000248c
+#define RCVDBDI_BD_PROD_IDX_4		0x00002490
+#define RCVDBDI_BD_PROD_IDX_5		0x00002494
+#define RCVDBDI_BD_PROD_IDX_6		0x00002498
+#define RCVDBDI_BD_PROD_IDX_7		0x0000249c
+#define RCVDBDI_BD_PROD_IDX_8		0x000024a0
+#define RCVDBDI_BD_PROD_IDX_9		0x000024a4
+#define RCVDBDI_BD_PROD_IDX_10		0x000024a8
+#define RCVDBDI_BD_PROD_IDX_11		0x000024ac
+#define RCVDBDI_BD_PROD_IDX_12		0x000024b0
+#define RCVDBDI_BD_PROD_IDX_13		0x000024b4
+#define RCVDBDI_BD_PROD_IDX_14		0x000024b8
+#define RCVDBDI_BD_PROD_IDX_15		0x000024bc
+#define RCVDBDI_HWDIAG			0x000024c0
+/* 0x24c4 --> 0x2800 unused */
+
+/* Receive Data Completion Control */
+#define RCVDCC_MODE			0x00002800
+#define  RCVDCC_MODE_RESET		 0x00000001
+#define  RCVDCC_MODE_ENABLE		 0x00000002
+#define  RCVDCC_MODE_ATTN_ENABLE	 0x00000004
+/* 0x2804 --> 0x2c00 unused */
+
+/* Receive BD Initiator Control Registers */
+#define RCVBDI_MODE			0x00002c00
+#define  RCVBDI_MODE_RESET		 0x00000001
+#define  RCVBDI_MODE_ENABLE		 0x00000002
+#define  RCVBDI_MODE_RCB_ATTN_ENAB	 0x00000004
+#define RCVBDI_STATUS			0x00002c04
+#define  RCVBDI_STATUS_RCB_ATTN		 0x00000004
+#define RCVBDI_JUMBO_PROD_IDX		0x00002c08
+#define RCVBDI_STD_PROD_IDX		0x00002c0c
+#define RCVBDI_MINI_PROD_IDX		0x00002c10
+#define RCVBDI_MINI_THRESH		0x00002c14
+#define RCVBDI_STD_THRESH		0x00002c18
+#define RCVBDI_JUMBO_THRESH		0x00002c1c
+/* 0x2c20 --> 0x2d00 unused */
+
+#define STD_REPLENISH_LWM		0x00002d00
+#define JMB_REPLENISH_LWM		0x00002d04
+/* 0x2d08 --> 0x3000 unused */
+
+/* Receive BD Completion Control Registers */
+#define RCVCC_MODE			0x00003000
+#define  RCVCC_MODE_RESET		 0x00000001
+#define  RCVCC_MODE_ENABLE		 0x00000002
+#define  RCVCC_MODE_ATTN_ENABLE		 0x00000004
+#define RCVCC_STATUS			0x00003004
+#define  RCVCC_STATUS_ERROR_ATTN	 0x00000004
+#define RCVCC_JUMP_PROD_IDX		0x00003008
+#define RCVCC_STD_PROD_IDX		0x0000300c
+#define RCVCC_MINI_PROD_IDX		0x00003010
+/* 0x3014 --> 0x3400 unused */
+
+/* Receive list selector control registers */
+#define RCVLSC_MODE			0x00003400
+#define  RCVLSC_MODE_RESET		 0x00000001
+#define  RCVLSC_MODE_ENABLE		 0x00000002
+#define  RCVLSC_MODE_ATTN_ENABLE	 0x00000004
+#define RCVLSC_STATUS			0x00003404
+#define  RCVLSC_STATUS_ERROR_ATTN	 0x00000004
+/* 0x3408 --> 0x3600 unused */
+
+/* CPMU registers */
+#define TG3_CPMU_CTRL			0x00003600
+#define  CPMU_CTRL_LINK_IDLE_MODE	 0x00000200
+#define  CPMU_CTRL_LINK_AWARE_MODE	 0x00000400
+#define  CPMU_CTRL_LINK_SPEED_MODE	 0x00004000
+#define  CPMU_CTRL_GPHY_10MB_RXONLY	 0x00010000
+#define TG3_CPMU_LSPD_10MB_CLK		0x00003604
+#define  CPMU_LSPD_10MB_MACCLK_MASK	 0x001f0000
+#define  CPMU_LSPD_10MB_MACCLK_6_25	 0x00130000
+/* 0x3608 --> 0x360c unused */
+
+#define TG3_CPMU_LSPD_1000MB_CLK	0x0000360c
+#define  CPMU_LSPD_1000MB_MACCLK_62_5	 0x00000000
+#define  CPMU_LSPD_1000MB_MACCLK_12_5	 0x00110000
+#define  CPMU_LSPD_1000MB_MACCLK_MASK	 0x001f0000
+#define TG3_CPMU_LNK_AWARE_PWRMD	0x00003610
+#define  CPMU_LNK_AWARE_MACCLK_MASK	 0x001f0000
+#define  CPMU_LNK_AWARE_MACCLK_6_25	 0x00130000
+
+#define TG3_CPMU_D0_CLCK_POLICY		0x00003614
+/* 0x3614 --> 0x361c unused */
+
+#define TG3_CPMU_HST_ACC		0x0000361c
+#define  CPMU_HST_ACC_MACCLK_MASK	 0x001f0000
+#define  CPMU_HST_ACC_MACCLK_6_25	 0x00130000
+/* 0x3620 --> 0x3630 unused */
+
+#define TG3_CPMU_CLCK_ORIDE		0x00003624
+#define  CPMU_CLCK_ORIDE_MAC_ORIDE_EN	 0x80000000
+
+#define TG3_CPMU_CLCK_ORIDE_EN		0x00003628
+#define  CPMU_CLCK_ORIDE_MAC_CLCK_ORIDE_EN	 0x00002000
+
+#define TG3_CPMU_CLCK_STAT		0x00003630
+#define  CPMU_CLCK_STAT_MAC_CLCK_MASK	 0x001f0000
+#define  CPMU_CLCK_STAT_MAC_CLCK_62_5	 0x00000000
+#define  CPMU_CLCK_STAT_MAC_CLCK_12_5	 0x00110000
+#define  CPMU_CLCK_STAT_MAC_CLCK_6_25	 0x00130000
+/* 0x3634 --> 0x365c unused */
+
+#define TG3_CPMU_MUTEX_REQ		0x0000365c
+#define  CPMU_MUTEX_REQ_DRIVER		 0x00001000
+#define TG3_CPMU_MUTEX_GNT		0x00003660
+#define  CPMU_MUTEX_GNT_DRIVER		 0x00001000
+#define TG3_CPMU_PHY_STRAP		0x00003664
+#define TG3_CPMU_PHY_STRAP_IS_SERDES	 0x00000020
+/* 0x3664 --> 0x36b0 unused */
+
+#define TG3_CPMU_EEE_MODE		0x000036b0
+#define  TG3_CPMU_EEEMD_APE_TX_DET_EN	 0x00000004
+#define  TG3_CPMU_EEEMD_ERLY_L1_XIT_DET	 0x00000008
+#define  TG3_CPMU_EEEMD_SND_IDX_DET_EN	 0x00000040
+#define  TG3_CPMU_EEEMD_LPI_ENABLE	 0x00000080
+#define  TG3_CPMU_EEEMD_LPI_IN_TX	 0x00000100
+#define  TG3_CPMU_EEEMD_LPI_IN_RX	 0x00000200
+#define  TG3_CPMU_EEEMD_EEE_ENABLE	 0x00100000
+#define TG3_CPMU_EEE_DBTMR1		0x000036b4
+#define  TG3_CPMU_DBTMR1_PCIEXIT_2047US	 0x07ff0000
+#define  TG3_CPMU_DBTMR1_LNKIDLE_2047US	 0x000070ff
+#define TG3_CPMU_EEE_DBTMR2		0x000036b8
+#define  TG3_CPMU_DBTMR2_APE_TX_2047US	 0x07ff0000
+#define  TG3_CPMU_DBTMR2_TXIDXEQ_2047US	 0x000070ff
+#define TG3_CPMU_EEE_LNKIDL_CTRL	0x000036bc
+#define  TG3_CPMU_EEE_LNKIDL_PCIE_NL0	 0x01000000
+#define  TG3_CPMU_EEE_LNKIDL_UART_IDL	 0x00000004
+/* 0x36c0 --> 0x36d0 unused */
+
+#define TG3_CPMU_EEE_CTRL		0x000036d0
+#define TG3_CPMU_EEE_CTRL_EXIT_16_5_US	 0x0000019d
+#define TG3_CPMU_EEE_CTRL_EXIT_36_US	 0x00000384
+#define TG3_CPMU_EEE_CTRL_EXIT_20_1_US	 0x000001f8
+/* 0x36d4 --> 0x3800 unused */
+
+/* Mbuf cluster free registers */
+#define MBFREE_MODE			0x00003800
+#define  MBFREE_MODE_RESET		 0x00000001
+#define  MBFREE_MODE_ENABLE		 0x00000002
+#define MBFREE_STATUS			0x00003804
+/* 0x3808 --> 0x3c00 unused */
+
+/* Host coalescing control registers */
+#define HOSTCC_MODE			0x00003c00
+#define  HOSTCC_MODE_RESET		 0x00000001
+#define  HOSTCC_MODE_ENABLE		 0x00000002
+#define  HOSTCC_MODE_ATTN		 0x00000004
+#define  HOSTCC_MODE_NOW		 0x00000008
+#define  HOSTCC_MODE_FULL_STATUS	 0x00000000
+#define  HOSTCC_MODE_64BYTE		 0x00000080
+#define  HOSTCC_MODE_32BYTE		 0x00000100
+#define  HOSTCC_MODE_CLRTICK_RXBD	 0x00000200
+#define  HOSTCC_MODE_CLRTICK_TXBD	 0x00000400
+#define  HOSTCC_MODE_NOINT_ON_NOW	 0x00000800
+#define  HOSTCC_MODE_NOINT_ON_FORCE	 0x00001000
+#define  HOSTCC_MODE_COAL_VEC1_NOW	 0x00002000
+#define HOSTCC_STATUS			0x00003c04
+#define  HOSTCC_STATUS_ERROR_ATTN	 0x00000004
+#define HOSTCC_RXCOL_TICKS		0x00003c08
+#define  LOW_RXCOL_TICKS		 0x00000032
+#define  LOW_RXCOL_TICKS_CLRTCKS	 0x00000014
+#define  DEFAULT_RXCOL_TICKS		 0x00000048
+#define  HIGH_RXCOL_TICKS		 0x00000096
+#define  MAX_RXCOL_TICKS		 0x000003ff
+#define HOSTCC_TXCOL_TICKS		0x00003c0c
+#define  LOW_TXCOL_TICKS		 0x00000096
+#define  LOW_TXCOL_TICKS_CLRTCKS	 0x00000048
+#define  DEFAULT_TXCOL_TICKS		 0x0000012c
+#define  HIGH_TXCOL_TICKS		 0x00000145
+#define  MAX_TXCOL_TICKS		 0x000003ff
+#define HOSTCC_RXMAX_FRAMES		0x00003c10
+#define  LOW_RXMAX_FRAMES		 0x00000005
+#define  DEFAULT_RXMAX_FRAMES		 0x00000008
+#define  HIGH_RXMAX_FRAMES		 0x00000012
+#define  MAX_RXMAX_FRAMES		 0x000000ff
+#define HOSTCC_TXMAX_FRAMES		0x00003c14
+#define  LOW_TXMAX_FRAMES		 0x00000035
+#define  DEFAULT_TXMAX_FRAMES		 0x0000004b
+#define  HIGH_TXMAX_FRAMES		 0x00000052
+#define  MAX_TXMAX_FRAMES		 0x000000ff
+#define HOSTCC_RXCOAL_TICK_INT		0x00003c18
+#define  DEFAULT_RXCOAL_TICK_INT	 0x00000019
+#define  DEFAULT_RXCOAL_TICK_INT_CLRTCKS 0x00000014
+#define  MAX_RXCOAL_TICK_INT		 0x000003ff
+#define HOSTCC_TXCOAL_TICK_INT		0x00003c1c
+#define  DEFAULT_TXCOAL_TICK_INT	 0x00000019
+#define  DEFAULT_TXCOAL_TICK_INT_CLRTCKS 0x00000014
+#define  MAX_TXCOAL_TICK_INT		 0x000003ff
+#define HOSTCC_RXCOAL_MAXF_INT		0x00003c20
+#define  DEFAULT_RXCOAL_MAXF_INT	 0x00000005
+#define  MAX_RXCOAL_MAXF_INT		 0x000000ff
+#define HOSTCC_TXCOAL_MAXF_INT		0x00003c24
+#define  DEFAULT_TXCOAL_MAXF_INT	 0x00000005
+#define  MAX_TXCOAL_MAXF_INT		 0x000000ff
+#define HOSTCC_STAT_COAL_TICKS		0x00003c28
+#define  DEFAULT_STAT_COAL_TICKS	 0x000f4240
+#define  MAX_STAT_COAL_TICKS		 0xd693d400
+#define  MIN_STAT_COAL_TICKS		 0x00000064
+/* 0x3c2c --> 0x3c30 unused */
+#define HOSTCC_STATS_BLK_HOST_ADDR	0x00003c30 /* 64-bit */
+#define HOSTCC_STATUS_BLK_HOST_ADDR	0x00003c38 /* 64-bit */
+#define HOSTCC_STATS_BLK_NIC_ADDR	0x00003c40
+#define HOSTCC_STATUS_BLK_NIC_ADDR	0x00003c44
+#define HOSTCC_FLOW_ATTN		0x00003c48
+#define HOSTCC_FLOW_ATTN_MBUF_LWM	 0x00000040
+/* 0x3c4c --> 0x3c50 unused */
+#define HOSTCC_JUMBO_CON_IDX		0x00003c50
+#define HOSTCC_STD_CON_IDX		0x00003c54
+#define HOSTCC_MINI_CON_IDX		0x00003c58
+/* 0x3c5c --> 0x3c80 unused */
+#define HOSTCC_RET_PROD_IDX_0		0x00003c80
+#define HOSTCC_RET_PROD_IDX_1		0x00003c84
+#define HOSTCC_RET_PROD_IDX_2		0x00003c88
+#define HOSTCC_RET_PROD_IDX_3		0x00003c8c
+#define HOSTCC_RET_PROD_IDX_4		0x00003c90
+#define HOSTCC_RET_PROD_IDX_5		0x00003c94
+#define HOSTCC_RET_PROD_IDX_6		0x00003c98
+#define HOSTCC_RET_PROD_IDX_7		0x00003c9c
+#define HOSTCC_RET_PROD_IDX_8		0x00003ca0
+#define HOSTCC_RET_PROD_IDX_9		0x00003ca4
+#define HOSTCC_RET_PROD_IDX_10		0x00003ca8
+#define HOSTCC_RET_PROD_IDX_11		0x00003cac
+#define HOSTCC_RET_PROD_IDX_12		0x00003cb0
+#define HOSTCC_RET_PROD_IDX_13		0x00003cb4
+#define HOSTCC_RET_PROD_IDX_14		0x00003cb8
+#define HOSTCC_RET_PROD_IDX_15		0x00003cbc
+#define HOSTCC_SND_CON_IDX_0		0x00003cc0
+#define HOSTCC_SND_CON_IDX_1		0x00003cc4
+#define HOSTCC_SND_CON_IDX_2		0x00003cc8
+#define HOSTCC_SND_CON_IDX_3		0x00003ccc
+#define HOSTCC_SND_CON_IDX_4		0x00003cd0
+#define HOSTCC_SND_CON_IDX_5		0x00003cd4
+#define HOSTCC_SND_CON_IDX_6		0x00003cd8
+#define HOSTCC_SND_CON_IDX_7		0x00003cdc
+#define HOSTCC_SND_CON_IDX_8		0x00003ce0
+#define HOSTCC_SND_CON_IDX_9		0x00003ce4
+#define HOSTCC_SND_CON_IDX_10		0x00003ce8
+#define HOSTCC_SND_CON_IDX_11		0x00003cec
+#define HOSTCC_SND_CON_IDX_12		0x00003cf0
+#define HOSTCC_SND_CON_IDX_13		0x00003cf4
+#define HOSTCC_SND_CON_IDX_14		0x00003cf8
+#define HOSTCC_SND_CON_IDX_15		0x00003cfc
+#define HOSTCC_STATBLCK_RING1		0x00003d00
+/* 0x3d00 --> 0x3d80 unused */
+
+#define HOSTCC_RXCOL_TICKS_VEC1		0x00003d80
+#define HOSTCC_TXCOL_TICKS_VEC1		0x00003d84
+#define HOSTCC_RXMAX_FRAMES_VEC1	0x00003d88
+#define HOSTCC_TXMAX_FRAMES_VEC1	0x00003d8c
+#define HOSTCC_RXCOAL_MAXF_INT_VEC1	0x00003d90
+#define HOSTCC_TXCOAL_MAXF_INT_VEC1	0x00003d94
+/* 0x3d98 --> 0x4000 unused */
+
+/* Memory arbiter control registers */
+#define MEMARB_MODE			0x00004000
+#define  MEMARB_MODE_RESET		 0x00000001
+#define  MEMARB_MODE_ENABLE		 0x00000002
+#define MEMARB_STATUS			0x00004004
+#define MEMARB_TRAP_ADDR_LOW		0x00004008
+#define MEMARB_TRAP_ADDR_HIGH		0x0000400c
+/* 0x4010 --> 0x4400 unused */
+
+/* Buffer manager control registers */
+#define BUFMGR_MODE			0x00004400
+#define  BUFMGR_MODE_RESET		 0x00000001
+#define  BUFMGR_MODE_ENABLE		 0x00000002
+#define  BUFMGR_MODE_ATTN_ENABLE	 0x00000004
+#define  BUFMGR_MODE_BM_TEST		 0x00000008
+#define  BUFMGR_MODE_MBLOW_ATTN_ENAB	 0x00000010
+#define  BUFMGR_MODE_NO_TX_UNDERRUN	 0x80000000
+#define BUFMGR_STATUS			0x00004404
+#define  BUFMGR_STATUS_ERROR		 0x00000004
+#define  BUFMGR_STATUS_MBLOW		 0x00000010
+#define BUFMGR_MB_POOL_ADDR		0x00004408
+#define BUFMGR_MB_POOL_SIZE		0x0000440c
+#define BUFMGR_MB_RDMA_LOW_WATER	0x00004410
+#define  DEFAULT_MB_RDMA_LOW_WATER	 0x00000050
+#define  DEFAULT_MB_RDMA_LOW_WATER_5705	 0x00000000
+#define  DEFAULT_MB_RDMA_LOW_WATER_JUMBO 0x00000130
+#define  DEFAULT_MB_RDMA_LOW_WATER_JUMBO_5780 0x00000000
+#define BUFMGR_MB_MACRX_LOW_WATER	0x00004414
+#define  DEFAULT_MB_MACRX_LOW_WATER	  0x00000020
+#define  DEFAULT_MB_MACRX_LOW_WATER_5705  0x00000010
+#define  DEFAULT_MB_MACRX_LOW_WATER_5906  0x00000004
+#define  DEFAULT_MB_MACRX_LOW_WATER_57765 0x0000002a
+#define  DEFAULT_MB_MACRX_LOW_WATER_JUMBO 0x00000098
+#define  DEFAULT_MB_MACRX_LOW_WATER_JUMBO_5780 0x0000004b
+#define  DEFAULT_MB_MACRX_LOW_WATER_JUMBO_57765 0x0000007e
+#define BUFMGR_MB_HIGH_WATER		0x00004418
+#define  DEFAULT_MB_HIGH_WATER		 0x00000060
+#define  DEFAULT_MB_HIGH_WATER_5705	 0x00000060
+#define  DEFAULT_MB_HIGH_WATER_5906	 0x00000010
+#define  DEFAULT_MB_HIGH_WATER_57765	 0x000000a0
+#define  DEFAULT_MB_HIGH_WATER_JUMBO	 0x0000017c
+#define  DEFAULT_MB_HIGH_WATER_JUMBO_5780 0x00000096
+#define  DEFAULT_MB_HIGH_WATER_JUMBO_57765 0x000000ea
+#define BUFMGR_RX_MB_ALLOC_REQ		0x0000441c
+#define  BUFMGR_MB_ALLOC_BIT		 0x10000000
+#define BUFMGR_RX_MB_ALLOC_RESP		0x00004420
+#define BUFMGR_TX_MB_ALLOC_REQ		0x00004424
+#define BUFMGR_TX_MB_ALLOC_RESP		0x00004428
+#define BUFMGR_DMA_DESC_POOL_ADDR	0x0000442c
+#define BUFMGR_DMA_DESC_POOL_SIZE	0x00004430
+#define BUFMGR_DMA_LOW_WATER		0x00004434
+#define  DEFAULT_DMA_LOW_WATER		 0x00000005
+#define BUFMGR_DMA_HIGH_WATER		0x00004438
+#define  DEFAULT_DMA_HIGH_WATER		 0x0000000a
+#define BUFMGR_RX_DMA_ALLOC_REQ		0x0000443c
+#define BUFMGR_RX_DMA_ALLOC_RESP	0x00004440
+#define BUFMGR_TX_DMA_ALLOC_REQ		0x00004444
+#define BUFMGR_TX_DMA_ALLOC_RESP	0x00004448
+#define BUFMGR_HWDIAG_0			0x0000444c
+#define BUFMGR_HWDIAG_1			0x00004450
+#define BUFMGR_HWDIAG_2			0x00004454
+/* 0x4458 --> 0x4800 unused */
+
+/* Read DMA control registers */
+#define RDMAC_MODE			0x00004800
+#define  RDMAC_MODE_RESET		 0x00000001
+#define  RDMAC_MODE_ENABLE		 0x00000002
+#define  RDMAC_MODE_TGTABORT_ENAB	 0x00000004
+#define  RDMAC_MODE_MSTABORT_ENAB	 0x00000008
+#define  RDMAC_MODE_PARITYERR_ENAB	 0x00000010
+#define  RDMAC_MODE_ADDROFLOW_ENAB	 0x00000020
+#define  RDMAC_MODE_FIFOOFLOW_ENAB	 0x00000040
+#define  RDMAC_MODE_FIFOURUN_ENAB	 0x00000080
+#define  RDMAC_MODE_FIFOOREAD_ENAB	 0x00000100
+#define  RDMAC_MODE_LNGREAD_ENAB	 0x00000200
+#define  RDMAC_MODE_SPLIT_ENABLE	 0x00000800
+#define  RDMAC_MODE_BD_SBD_CRPT_ENAB	 0x00000800
+#define  RDMAC_MODE_SPLIT_RESET		 0x00001000
+#define  RDMAC_MODE_MBUF_RBD_CRPT_ENAB	 0x00001000
+#define  RDMAC_MODE_MBUF_SBD_CRPT_ENAB	 0x00002000
+#define  RDMAC_MODE_FIFO_SIZE_128	 0x00020000
+#define  RDMAC_MODE_FIFO_LONG_BURST	 0x00030000
+#define  RDMAC_MODE_MULT_DMA_RD_DIS	 0x01000000
+#define  RDMAC_MODE_IPV4_LSO_EN		 0x08000000
+#define  RDMAC_MODE_IPV6_LSO_EN		 0x10000000
+#define  RDMAC_MODE_H2BNC_VLAN_DET	 0x20000000
+#define RDMAC_STATUS			0x00004804
+#define  RDMAC_STATUS_TGTABORT		 0x00000004
+#define  RDMAC_STATUS_MSTABORT		 0x00000008
+#define  RDMAC_STATUS_PARITYERR		 0x00000010
+#define  RDMAC_STATUS_ADDROFLOW		 0x00000020
+#define  RDMAC_STATUS_FIFOOFLOW		 0x00000040
+#define  RDMAC_STATUS_FIFOURUN		 0x00000080
+#define  RDMAC_STATUS_FIFOOREAD		 0x00000100
+#define  RDMAC_STATUS_LNGREAD		 0x00000200
+/* 0x4808 --> 0x4900 unused */
+
+#define TG3_RDMA_RSRVCTRL_REG		0x00004900
+#define TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX	 0x00000004
+#define TG3_RDMA_RSRVCTRL_FIFO_LWM_1_5K	 0x00000c00
+#define TG3_RDMA_RSRVCTRL_FIFO_LWM_MASK	 0x00000ff0
+#define TG3_RDMA_RSRVCTRL_FIFO_HWM_1_5K	 0x000c0000
+#define TG3_RDMA_RSRVCTRL_FIFO_HWM_MASK	 0x000ff000
+#define TG3_RDMA_RSRVCTRL_TXMRGN_320B	 0x28000000
+#define TG3_RDMA_RSRVCTRL_TXMRGN_MASK	 0xffe00000
+/* 0x4904 --> 0x4910 unused */
+
+#define TG3_LSO_RD_DMA_CRPTEN_CTRL	0x00004910
+#define TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K	 0x00030000
+#define TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_LSO_4K	 0x000c0000
+/* 0x4914 --> 0x4c00 unused */
+
+/* Write DMA control registers */
+#define WDMAC_MODE			0x00004c00
+#define  WDMAC_MODE_RESET		 0x00000001
+#define  WDMAC_MODE_ENABLE		 0x00000002
+#define  WDMAC_MODE_TGTABORT_ENAB	 0x00000004
+#define  WDMAC_MODE_MSTABORT_ENAB	 0x00000008
+#define  WDMAC_MODE_PARITYERR_ENAB	 0x00000010
+#define  WDMAC_MODE_ADDROFLOW_ENAB	 0x00000020
+#define  WDMAC_MODE_FIFOOFLOW_ENAB	 0x00000040
+#define  WDMAC_MODE_FIFOURUN_ENAB	 0x00000080
+#define  WDMAC_MODE_FIFOOREAD_ENAB	 0x00000100
+#define  WDMAC_MODE_LNGREAD_ENAB	 0x00000200
+#define  WDMAC_MODE_RX_ACCEL		 0x00000400
+#define  WDMAC_MODE_STATUS_TAG_FIX	 0x20000000
+#define  WDMAC_MODE_BURST_ALL_DATA	 0xc0000000
+#define WDMAC_STATUS			0x00004c04
+#define  WDMAC_STATUS_TGTABORT		 0x00000004
+#define  WDMAC_STATUS_MSTABORT		 0x00000008
+#define  WDMAC_STATUS_PARITYERR		 0x00000010
+#define  WDMAC_STATUS_ADDROFLOW		 0x00000020
+#define  WDMAC_STATUS_FIFOOFLOW		 0x00000040
+#define  WDMAC_STATUS_FIFOURUN		 0x00000080
+#define  WDMAC_STATUS_FIFOOREAD		 0x00000100
+#define  WDMAC_STATUS_LNGREAD		 0x00000200
+/* 0x4c08 --> 0x5000 unused */
+
+/* Per-cpu register offsets (arm9) */
+#define CPU_MODE			0x00000000
+#define  CPU_MODE_RESET			 0x00000001
+#define  CPU_MODE_HALT			 0x00000400
+#define CPU_STATE			0x00000004
+#define CPU_EVTMASK			0x00000008
+/* 0xc --> 0x1c reserved */
+#define CPU_PC				0x0000001c
+#define CPU_INSN			0x00000020
+#define CPU_SPAD_UFLOW			0x00000024
+#define CPU_WDOG_CLEAR			0x00000028
+#define CPU_WDOG_VECTOR			0x0000002c
+#define CPU_WDOG_PC			0x00000030
+#define CPU_HW_BP			0x00000034
+/* 0x38 --> 0x44 unused */
+#define CPU_WDOG_SAVED_STATE		0x00000044
+#define CPU_LAST_BRANCH_ADDR		0x00000048
+#define CPU_SPAD_UFLOW_SET		0x0000004c
+/* 0x50 --> 0x200 unused */
+#define CPU_R0				0x00000200
+#define CPU_R1				0x00000204
+#define CPU_R2				0x00000208
+#define CPU_R3				0x0000020c
+#define CPU_R4				0x00000210
+#define CPU_R5				0x00000214
+#define CPU_R6				0x00000218
+#define CPU_R7				0x0000021c
+#define CPU_R8				0x00000220
+#define CPU_R9				0x00000224
+#define CPU_R10				0x00000228
+#define CPU_R11				0x0000022c
+#define CPU_R12				0x00000230
+#define CPU_R13				0x00000234
+#define CPU_R14				0x00000238
+#define CPU_R15				0x0000023c
+#define CPU_R16				0x00000240
+#define CPU_R17				0x00000244
+#define CPU_R18				0x00000248
+#define CPU_R19				0x0000024c
+#define CPU_R20				0x00000250
+#define CPU_R21				0x00000254
+#define CPU_R22				0x00000258
+#define CPU_R23				0x0000025c
+#define CPU_R24				0x00000260
+#define CPU_R25				0x00000264
+#define CPU_R26				0x00000268
+#define CPU_R27				0x0000026c
+#define CPU_R28				0x00000270
+#define CPU_R29				0x00000274
+#define CPU_R30				0x00000278
+#define CPU_R31				0x0000027c
+/* 0x280 --> 0x400 unused */
+
+#define RX_CPU_BASE			0x00005000
+#define RX_CPU_MODE			0x00005000
+#define RX_CPU_STATE			0x00005004
+#define RX_CPU_PGMCTR			0x0000501c
+#define RX_CPU_HWBKPT			0x00005034
+#define TX_CPU_BASE			0x00005400
+#define TX_CPU_MODE			0x00005400
+#define TX_CPU_STATE			0x00005404
+#define TX_CPU_PGMCTR			0x0000541c
+
+#define VCPU_STATUS			0x00005100
+#define  VCPU_STATUS_INIT_DONE		 0x04000000
+#define  VCPU_STATUS_DRV_RESET		 0x08000000
+
+#define VCPU_CFGSHDW			0x00005104
+#define  VCPU_CFGSHDW_WOL_ENABLE	 0x00000001
+#define  VCPU_CFGSHDW_WOL_MAGPKT	 0x00000004
+#define  VCPU_CFGSHDW_ASPM_DBNC		 0x00001000
+
+/* Mailboxes */
+#define GRCMBOX_BASE			0x00005600
+#define GRCMBOX_INTERRUPT_0		0x00005800 /* 64-bit */
+#define GRCMBOX_INTERRUPT_1		0x00005808 /* 64-bit */
+#define GRCMBOX_INTERRUPT_2		0x00005810 /* 64-bit */
+#define GRCMBOX_INTERRUPT_3		0x00005818 /* 64-bit */
+#define GRCMBOX_GENERAL_0		0x00005820 /* 64-bit */
+#define GRCMBOX_GENERAL_1		0x00005828 /* 64-bit */
+#define GRCMBOX_GENERAL_2		0x00005830 /* 64-bit */
+#define GRCMBOX_GENERAL_3		0x00005838 /* 64-bit */
+#define GRCMBOX_GENERAL_4		0x00005840 /* 64-bit */
+#define GRCMBOX_GENERAL_5		0x00005848 /* 64-bit */
+#define GRCMBOX_GENERAL_6		0x00005850 /* 64-bit */
+#define GRCMBOX_GENERAL_7		0x00005858 /* 64-bit */
+#define GRCMBOX_RELOAD_STAT		0x00005860 /* 64-bit */
+#define GRCMBOX_RCVSTD_PROD_IDX		0x00005868 /* 64-bit */
+#define GRCMBOX_RCVJUMBO_PROD_IDX	0x00005870 /* 64-bit */
+#define GRCMBOX_RCVMINI_PROD_IDX	0x00005878 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_0	0x00005880 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_1	0x00005888 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_2	0x00005890 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_3	0x00005898 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_4	0x000058a0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_5	0x000058a8 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_6	0x000058b0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_7	0x000058b8 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_8	0x000058c0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_9	0x000058c8 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_10	0x000058d0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_11	0x000058d8 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_12	0x000058e0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_13	0x000058e8 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_14	0x000058f0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_15	0x000058f8 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_0	0x00005900 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_1	0x00005908 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_2	0x00005910 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_3	0x00005918 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_4	0x00005920 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_5	0x00005928 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_6	0x00005930 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_7	0x00005938 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_8	0x00005940 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_9	0x00005948 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_10	0x00005950 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_11	0x00005958 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_12	0x00005960 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_13	0x00005968 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_14	0x00005970 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_15	0x00005978 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_0	0x00005980 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_1	0x00005988 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_2	0x00005990 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_3	0x00005998 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_4	0x000059a0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_5	0x000059a8 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_6	0x000059b0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_7	0x000059b8 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_8	0x000059c0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_9	0x000059c8 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_10	0x000059d0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_11	0x000059d8 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_12	0x000059e0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_13	0x000059e8 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_14	0x000059f0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_15	0x000059f8 /* 64-bit */
+#define GRCMBOX_HIGH_PRIO_EV_VECTOR	0x00005a00
+#define GRCMBOX_HIGH_PRIO_EV_MASK	0x00005a04
+#define GRCMBOX_LOW_PRIO_EV_VEC		0x00005a08
+#define GRCMBOX_LOW_PRIO_EV_MASK	0x00005a0c
+/* 0x5a10 --> 0x5c00 */
+
+/* Flow Through queues */
+#define FTQ_RESET			0x00005c00
+/* 0x5c04 --> 0x5c10 unused */
+#define FTQ_DMA_NORM_READ_CTL		0x00005c10
+#define FTQ_DMA_NORM_READ_FULL_CNT	0x00005c14
+#define FTQ_DMA_NORM_READ_FIFO_ENQDEQ	0x00005c18
+#define FTQ_DMA_NORM_READ_WRITE_PEEK	0x00005c1c
+#define FTQ_DMA_HIGH_READ_CTL		0x00005c20
+#define FTQ_DMA_HIGH_READ_FULL_CNT	0x00005c24
+#define FTQ_DMA_HIGH_READ_FIFO_ENQDEQ	0x00005c28
+#define FTQ_DMA_HIGH_READ_WRITE_PEEK	0x00005c2c
+#define FTQ_DMA_COMP_DISC_CTL		0x00005c30
+#define FTQ_DMA_COMP_DISC_FULL_CNT	0x00005c34
+#define FTQ_DMA_COMP_DISC_FIFO_ENQDEQ	0x00005c38
+#define FTQ_DMA_COMP_DISC_WRITE_PEEK	0x00005c3c
+#define FTQ_SEND_BD_COMP_CTL		0x00005c40
+#define FTQ_SEND_BD_COMP_FULL_CNT	0x00005c44
+#define FTQ_SEND_BD_COMP_FIFO_ENQDEQ	0x00005c48
+#define FTQ_SEND_BD_COMP_WRITE_PEEK	0x00005c4c
+#define FTQ_SEND_DATA_INIT_CTL		0x00005c50
+#define FTQ_SEND_DATA_INIT_FULL_CNT	0x00005c54
+#define FTQ_SEND_DATA_INIT_FIFO_ENQDEQ	0x00005c58
+#define FTQ_SEND_DATA_INIT_WRITE_PEEK	0x00005c5c
+#define FTQ_DMA_NORM_WRITE_CTL		0x00005c60
+#define FTQ_DMA_NORM_WRITE_FULL_CNT	0x00005c64
+#define FTQ_DMA_NORM_WRITE_FIFO_ENQDEQ	0x00005c68
+#define FTQ_DMA_NORM_WRITE_WRITE_PEEK	0x00005c6c
+#define FTQ_DMA_HIGH_WRITE_CTL		0x00005c70
+#define FTQ_DMA_HIGH_WRITE_FULL_CNT	0x00005c74
+#define FTQ_DMA_HIGH_WRITE_FIFO_ENQDEQ	0x00005c78
+#define FTQ_DMA_HIGH_WRITE_WRITE_PEEK	0x00005c7c
+#define FTQ_SWTYPE1_CTL			0x00005c80
+#define FTQ_SWTYPE1_FULL_CNT		0x00005c84
+#define FTQ_SWTYPE1_FIFO_ENQDEQ		0x00005c88
+#define FTQ_SWTYPE1_WRITE_PEEK		0x00005c8c
+#define FTQ_SEND_DATA_COMP_CTL		0x00005c90
+#define FTQ_SEND_DATA_COMP_FULL_CNT	0x00005c94
+#define FTQ_SEND_DATA_COMP_FIFO_ENQDEQ	0x00005c98
+#define FTQ_SEND_DATA_COMP_WRITE_PEEK	0x00005c9c
+#define FTQ_HOST_COAL_CTL		0x00005ca0
+#define FTQ_HOST_COAL_FULL_CNT		0x00005ca4
+#define FTQ_HOST_COAL_FIFO_ENQDEQ	0x00005ca8
+#define FTQ_HOST_COAL_WRITE_PEEK	0x00005cac
+#define FTQ_MAC_TX_CTL			0x00005cb0
+#define FTQ_MAC_TX_FULL_CNT		0x00005cb4
+#define FTQ_MAC_TX_FIFO_ENQDEQ		0x00005cb8
+#define FTQ_MAC_TX_WRITE_PEEK		0x00005cbc
+#define FTQ_MB_FREE_CTL			0x00005cc0
+#define FTQ_MB_FREE_FULL_CNT		0x00005cc4
+#define FTQ_MB_FREE_FIFO_ENQDEQ		0x00005cc8
+#define FTQ_MB_FREE_WRITE_PEEK		0x00005ccc
+#define FTQ_RCVBD_COMP_CTL		0x00005cd0
+#define FTQ_RCVBD_COMP_FULL_CNT		0x00005cd4
+#define FTQ_RCVBD_COMP_FIFO_ENQDEQ	0x00005cd8
+#define FTQ_RCVBD_COMP_WRITE_PEEK	0x00005cdc
+#define FTQ_RCVLST_PLMT_CTL		0x00005ce0
+#define FTQ_RCVLST_PLMT_FULL_CNT	0x00005ce4
+#define FTQ_RCVLST_PLMT_FIFO_ENQDEQ	0x00005ce8
+#define FTQ_RCVLST_PLMT_WRITE_PEEK	0x00005cec
+#define FTQ_RCVDATA_INI_CTL		0x00005cf0
+#define FTQ_RCVDATA_INI_FULL_CNT	0x00005cf4
+#define FTQ_RCVDATA_INI_FIFO_ENQDEQ	0x00005cf8
+#define FTQ_RCVDATA_INI_WRITE_PEEK	0x00005cfc
+#define FTQ_RCVDATA_COMP_CTL		0x00005d00
+#define FTQ_RCVDATA_COMP_FULL_CNT	0x00005d04
+#define FTQ_RCVDATA_COMP_FIFO_ENQDEQ	0x00005d08
+#define FTQ_RCVDATA_COMP_WRITE_PEEK	0x00005d0c
+#define FTQ_SWTYPE2_CTL			0x00005d10
+#define FTQ_SWTYPE2_FULL_CNT		0x00005d14
+#define FTQ_SWTYPE2_FIFO_ENQDEQ		0x00005d18
+#define FTQ_SWTYPE2_WRITE_PEEK		0x00005d1c
+/* 0x5d20 --> 0x6000 unused */
+
+/* Message signaled interrupt registers */
+#define MSGINT_MODE			0x00006000
+#define  MSGINT_MODE_RESET		 0x00000001
+#define  MSGINT_MODE_ENABLE		 0x00000002
+#define  MSGINT_MODE_ONE_SHOT_DISABLE	 0x00000020
+#define  MSGINT_MODE_MULTIVEC_EN	 0x00000080
+#define MSGINT_STATUS			0x00006004
+#define  MSGINT_STATUS_MSI_REQ		 0x00000001
+#define MSGINT_FIFO			0x00006008
+/* 0x600c --> 0x6400 unused */
+
+/* DMA completion registers */
+#define DMAC_MODE			0x00006400
+#define  DMAC_MODE_RESET		 0x00000001
+#define  DMAC_MODE_ENABLE		 0x00000002
+/* 0x6404 --> 0x6800 unused */
+
+/* GRC registers */
+#define GRC_MODE			0x00006800
+#define  GRC_MODE_UPD_ON_COAL		0x00000001
+#define  GRC_MODE_BSWAP_NONFRM_DATA	0x00000002
+#define  GRC_MODE_WSWAP_NONFRM_DATA	0x00000004
+#define  GRC_MODE_BSWAP_DATA		0x00000010
+#define  GRC_MODE_WSWAP_DATA		0x00000020
+#define  GRC_MODE_BYTE_SWAP_B2HRX_DATA	0x00000040
+#define  GRC_MODE_WORD_SWAP_B2HRX_DATA	0x00000080
+#define  GRC_MODE_SPLITHDR		0x00000100
+#define  GRC_MODE_NOFRM_CRACKING	0x00000200
+#define  GRC_MODE_INCL_CRC		0x00000400
+#define  GRC_MODE_ALLOW_BAD_FRMS	0x00000800
+#define  GRC_MODE_NOIRQ_ON_SENDS	0x00002000
+#define  GRC_MODE_NOIRQ_ON_RCV		0x00004000
+#define  GRC_MODE_FORCE_PCI32BIT	0x00008000
+#define  GRC_MODE_B2HRX_ENABLE		0x00008000
+#define  GRC_MODE_HOST_STACKUP		0x00010000
+#define  GRC_MODE_HOST_SENDBDS		0x00020000
+#define  GRC_MODE_HTX2B_ENABLE		0x00040000
+#define  GRC_MODE_NO_TX_PHDR_CSUM	0x00100000
+#define  GRC_MODE_NVRAM_WR_ENABLE	0x00200000
+#define  GRC_MODE_PCIE_TL_SEL		0x00000000
+#define  GRC_MODE_PCIE_PL_SEL		0x00400000
+#define  GRC_MODE_NO_RX_PHDR_CSUM	0x00800000
+#define  GRC_MODE_IRQ_ON_TX_CPU_ATTN	0x01000000
+#define  GRC_MODE_IRQ_ON_RX_CPU_ATTN	0x02000000
+#define  GRC_MODE_IRQ_ON_MAC_ATTN	0x04000000
+#define  GRC_MODE_IRQ_ON_DMA_ATTN	0x08000000
+#define  GRC_MODE_IRQ_ON_FLOW_ATTN	0x10000000
+#define  GRC_MODE_4X_NIC_SEND_RINGS	0x20000000
+#define  GRC_MODE_PCIE_DL_SEL		0x20000000
+#define  GRC_MODE_MCAST_FRM_ENABLE	0x40000000
+#define  GRC_MODE_PCIE_HI_1K_EN		0x80000000
+#define  GRC_MODE_PCIE_PORT_MASK	(GRC_MODE_PCIE_TL_SEL | \
+					 GRC_MODE_PCIE_PL_SEL | \
+					 GRC_MODE_PCIE_DL_SEL | \
+					 GRC_MODE_PCIE_HI_1K_EN)
+#define GRC_MISC_CFG			0x00006804
+#define  GRC_MISC_CFG_CORECLK_RESET	0x00000001
+#define  GRC_MISC_CFG_PRESCALAR_MASK	0x000000fe
+#define  GRC_MISC_CFG_PRESCALAR_SHIFT	1
+#define  GRC_MISC_CFG_BOARD_ID_MASK	0x0001e000
+#define  GRC_MISC_CFG_BOARD_ID_5700	0x0001e000
+#define  GRC_MISC_CFG_BOARD_ID_5701	0x00000000
+#define  GRC_MISC_CFG_BOARD_ID_5702FE	0x00004000
+#define  GRC_MISC_CFG_BOARD_ID_5703	0x00000000
+#define  GRC_MISC_CFG_BOARD_ID_5703S	0x00002000
+#define  GRC_MISC_CFG_BOARD_ID_5704	0x00000000
+#define  GRC_MISC_CFG_BOARD_ID_5704CIOBE 0x00004000
+#define  GRC_MISC_CFG_BOARD_ID_5704_A2	0x00008000
+#define  GRC_MISC_CFG_BOARD_ID_5788	0x00010000
+#define  GRC_MISC_CFG_BOARD_ID_5788M	0x00018000
+#define  GRC_MISC_CFG_BOARD_ID_AC91002A1 0x00018000
+#define  GRC_MISC_CFG_EPHY_IDDQ		0x00200000
+#define  GRC_MISC_CFG_KEEP_GPHY_POWER	0x04000000
+#define GRC_LOCAL_CTRL			0x00006808
+#define  GRC_LCLCTRL_INT_ACTIVE		0x00000001
+#define  GRC_LCLCTRL_CLEARINT		0x00000002
+#define  GRC_LCLCTRL_SETINT		0x00000004
+#define  GRC_LCLCTRL_INT_ON_ATTN	0x00000008
+#define  GRC_LCLCTRL_GPIO_UART_SEL	0x00000010	/* 5755 only */
+#define  GRC_LCLCTRL_USE_SIG_DETECT	0x00000010	/* 5714/5780 only */
+#define  GRC_LCLCTRL_USE_EXT_SIG_DETECT	0x00000020	/* 5714/5780 only */
+#define  GRC_LCLCTRL_GPIO_INPUT3	0x00000020
+#define  GRC_LCLCTRL_GPIO_OE3		0x00000040
+#define  GRC_LCLCTRL_GPIO_OUTPUT3	0x00000080
+#define  GRC_LCLCTRL_GPIO_INPUT0	0x00000100
+#define  GRC_LCLCTRL_GPIO_INPUT1	0x00000200
+#define  GRC_LCLCTRL_GPIO_INPUT2	0x00000400
+#define  GRC_LCLCTRL_GPIO_OE0		0x00000800
+#define  GRC_LCLCTRL_GPIO_OE1		0x00001000
+#define  GRC_LCLCTRL_GPIO_OE2		0x00002000
+#define  GRC_LCLCTRL_GPIO_OUTPUT0	0x00004000
+#define  GRC_LCLCTRL_GPIO_OUTPUT1	0x00008000
+#define  GRC_LCLCTRL_GPIO_OUTPUT2	0x00010000
+#define  GRC_LCLCTRL_EXTMEM_ENABLE	0x00020000
+#define  GRC_LCLCTRL_MEMSZ_MASK		0x001c0000
+#define  GRC_LCLCTRL_MEMSZ_256K		0x00000000
+#define  GRC_LCLCTRL_MEMSZ_512K		0x00040000
+#define  GRC_LCLCTRL_MEMSZ_1M		0x00080000
+#define  GRC_LCLCTRL_MEMSZ_2M		0x000c0000
+#define  GRC_LCLCTRL_MEMSZ_4M		0x00100000
+#define  GRC_LCLCTRL_MEMSZ_8M		0x00140000
+#define  GRC_LCLCTRL_MEMSZ_16M		0x00180000
+#define  GRC_LCLCTRL_BANK_SELECT	0x00200000
+#define  GRC_LCLCTRL_SSRAM_TYPE		0x00400000
+#define  GRC_LCLCTRL_AUTO_SEEPROM	0x01000000
+#define GRC_TIMER			0x0000680c
+#define GRC_RX_CPU_EVENT		0x00006810
+#define  GRC_RX_CPU_DRIVER_EVENT	0x00004000
+#define GRC_RX_TIMER_REF		0x00006814
+#define GRC_RX_CPU_SEM			0x00006818
+#define GRC_REMOTE_RX_CPU_ATTN		0x0000681c
+#define GRC_TX_CPU_EVENT		0x00006820
+#define GRC_TX_TIMER_REF		0x00006824
+#define GRC_TX_CPU_SEM			0x00006828
+#define GRC_REMOTE_TX_CPU_ATTN		0x0000682c
+#define GRC_MEM_POWER_UP		0x00006830 /* 64-bit */
+#define GRC_EEPROM_ADDR			0x00006838
+#define  EEPROM_ADDR_WRITE		0x00000000
+#define  EEPROM_ADDR_READ		0x80000000
+#define  EEPROM_ADDR_COMPLETE		0x40000000
+#define  EEPROM_ADDR_FSM_RESET		0x20000000
+#define  EEPROM_ADDR_DEVID_MASK		0x1c000000
+#define  EEPROM_ADDR_DEVID_SHIFT	26
+#define  EEPROM_ADDR_START		0x02000000
+#define  EEPROM_ADDR_CLKPERD_SHIFT	16
+#define  EEPROM_ADDR_ADDR_MASK		0x0000ffff
+#define  EEPROM_ADDR_ADDR_SHIFT		0
+#define  EEPROM_DEFAULT_CLOCK_PERIOD	0x60
+#define  EEPROM_CHIP_SIZE		(64 * 1024)
+#define GRC_EEPROM_DATA			0x0000683c
+#define GRC_EEPROM_CTRL			0x00006840
+#define GRC_MDI_CTRL			0x00006844
+#define GRC_SEEPROM_DELAY		0x00006848
+/* 0x684c --> 0x6890 unused */
+#define GRC_VCPU_EXT_CTRL		0x00006890
+#define GRC_VCPU_EXT_CTRL_HALT_CPU	 0x00400000
+#define GRC_VCPU_EXT_CTRL_DISABLE_WOL	 0x20000000
+#define GRC_FASTBOOT_PC			0x00006894	/* 5752, 5755, 5787 */
+
+/* 0x6c00 --> 0x7000 unused */
+
+/* NVRAM Control registers */
+#define NVRAM_CMD			0x00007000
+#define  NVRAM_CMD_RESET		 0x00000001
+#define  NVRAM_CMD_DONE			 0x00000008
+#define  NVRAM_CMD_GO			 0x00000010
+#define  NVRAM_CMD_WR			 0x00000020
+#define  NVRAM_CMD_RD			 0x00000000
+#define  NVRAM_CMD_ERASE		 0x00000040
+#define  NVRAM_CMD_FIRST		 0x00000080
+#define  NVRAM_CMD_LAST			 0x00000100
+#define  NVRAM_CMD_WREN			 0x00010000
+#define  NVRAM_CMD_WRDI			 0x00020000
+#define NVRAM_STAT			0x00007004
+#define NVRAM_WRDATA			0x00007008
+#define NVRAM_ADDR			0x0000700c
+#define  NVRAM_ADDR_MSK			0x00ffffff
+#define NVRAM_RDDATA			0x00007010
+#define NVRAM_CFG1			0x00007014
+#define  NVRAM_CFG1_FLASHIF_ENAB	 0x00000001
+#define  NVRAM_CFG1_BUFFERED_MODE	 0x00000002
+#define  NVRAM_CFG1_PASS_THRU		 0x00000004
+#define  NVRAM_CFG1_STATUS_BITS		 0x00000070
+#define  NVRAM_CFG1_BIT_BANG		 0x00000008
+#define  NVRAM_CFG1_FLASH_SIZE		 0x02000000
+#define  NVRAM_CFG1_COMPAT_BYPASS	 0x80000000
+#define  NVRAM_CFG1_VENDOR_MASK		 0x03000003
+#define  FLASH_VENDOR_ATMEL_EEPROM	 0x02000000
+#define  FLASH_VENDOR_ATMEL_FLASH_BUFFERED	 0x02000003
+#define  FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED	 0x00000003
+#define  FLASH_VENDOR_ST			 0x03000001
+#define  FLASH_VENDOR_SAIFUN		 0x01000003
+#define  FLASH_VENDOR_SST_SMALL		 0x00000001
+#define  FLASH_VENDOR_SST_LARGE		 0x02000001
+#define  NVRAM_CFG1_5752VENDOR_MASK	 0x03c00003
+#define  FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ	 0x00000000
+#define  FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ	 0x02000000
+#define  FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED	 0x02000003
+#define  FLASH_5752VENDOR_ST_M45PE10	 0x02400000
+#define  FLASH_5752VENDOR_ST_M45PE20	 0x02400002
+#define  FLASH_5752VENDOR_ST_M45PE40	 0x02400001
+#define  FLASH_5755VENDOR_ATMEL_FLASH_1	 0x03400001
+#define  FLASH_5755VENDOR_ATMEL_FLASH_2	 0x03400002
+#define  FLASH_5755VENDOR_ATMEL_FLASH_3	 0x03400000
+#define  FLASH_5755VENDOR_ATMEL_FLASH_4	 0x00000003
+#define  FLASH_5755VENDOR_ATMEL_FLASH_5	 0x02000003
+#define  FLASH_5755VENDOR_ATMEL_EEPROM_64KHZ	 0x03c00003
+#define  FLASH_5755VENDOR_ATMEL_EEPROM_376KHZ	 0x03c00002
+#define  FLASH_5787VENDOR_ATMEL_EEPROM_64KHZ	 0x03000003
+#define  FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ	 0x03000002
+#define  FLASH_5787VENDOR_MICRO_EEPROM_64KHZ	 0x03000000
+#define  FLASH_5787VENDOR_MICRO_EEPROM_376KHZ	 0x02000000
+#define  FLASH_5761VENDOR_ATMEL_MDB021D	 0x00800003
+#define  FLASH_5761VENDOR_ATMEL_MDB041D	 0x00800000
+#define  FLASH_5761VENDOR_ATMEL_MDB081D	 0x00800002
+#define  FLASH_5761VENDOR_ATMEL_MDB161D	 0x00800001
+#define  FLASH_5761VENDOR_ATMEL_ADB021D	 0x00000003
+#define  FLASH_5761VENDOR_ATMEL_ADB041D	 0x00000000
+#define  FLASH_5761VENDOR_ATMEL_ADB081D	 0x00000002
+#define  FLASH_5761VENDOR_ATMEL_ADB161D	 0x00000001
+#define  FLASH_5761VENDOR_ST_M_M45PE20	 0x02800001
+#define  FLASH_5761VENDOR_ST_M_M45PE40	 0x02800000
+#define  FLASH_5761VENDOR_ST_M_M45PE80	 0x02800002
+#define  FLASH_5761VENDOR_ST_M_M45PE16	 0x02800003
+#define  FLASH_5761VENDOR_ST_A_M45PE20	 0x02000001
+#define  FLASH_5761VENDOR_ST_A_M45PE40	 0x02000000
+#define  FLASH_5761VENDOR_ST_A_M45PE80	 0x02000002
+#define  FLASH_5761VENDOR_ST_A_M45PE16	 0x02000003
+#define  FLASH_57780VENDOR_ATMEL_AT45DB011D 0x00400000
+#define  FLASH_57780VENDOR_ATMEL_AT45DB011B 0x03400000
+#define  FLASH_57780VENDOR_ATMEL_AT45DB021D 0x00400002
+#define  FLASH_57780VENDOR_ATMEL_AT45DB021B 0x03400002
+#define  FLASH_57780VENDOR_ATMEL_AT45DB041D 0x00400001
+#define  FLASH_57780VENDOR_ATMEL_AT45DB041B 0x03400001
+#define  FLASH_5717VENDOR_ATMEL_EEPROM	 0x02000001
+#define  FLASH_5717VENDOR_MICRO_EEPROM	 0x02000003
+#define  FLASH_5717VENDOR_ATMEL_MDB011D	 0x01000001
+#define  FLASH_5717VENDOR_ATMEL_MDB021D	 0x01000003
+#define  FLASH_5717VENDOR_ST_M_M25PE10	 0x02000000
+#define  FLASH_5717VENDOR_ST_M_M25PE20	 0x02000002
+#define  FLASH_5717VENDOR_ST_M_M45PE10	 0x00000001
+#define  FLASH_5717VENDOR_ST_M_M45PE20	 0x00000003
+#define  FLASH_5717VENDOR_ATMEL_ADB011B	 0x01400000
+#define  FLASH_5717VENDOR_ATMEL_ADB021B	 0x01400002
+#define  FLASH_5717VENDOR_ATMEL_ADB011D	 0x01400001
+#define  FLASH_5717VENDOR_ATMEL_ADB021D	 0x01400003
+#define  FLASH_5717VENDOR_ST_A_M25PE10	 0x02400000
+#define  FLASH_5717VENDOR_ST_A_M25PE20	 0x02400002
+#define  FLASH_5717VENDOR_ST_A_M45PE10	 0x02400001
+#define  FLASH_5717VENDOR_ST_A_M45PE20	 0x02400003
+#define  FLASH_5717VENDOR_ATMEL_45USPT	 0x03400000
+#define  FLASH_5717VENDOR_ST_25USPT	 0x03400002
+#define  FLASH_5717VENDOR_ST_45USPT	 0x03400001
+#define  FLASH_5720_EEPROM_HD		 0x00000001
+#define  FLASH_5720_EEPROM_LD		 0x00000003
+#define  FLASH_5720VENDOR_M_ATMEL_DB011D 0x01000000
+#define  FLASH_5720VENDOR_M_ATMEL_DB021D 0x01000002
+#define  FLASH_5720VENDOR_M_ATMEL_DB041D 0x01000001
+#define  FLASH_5720VENDOR_M_ATMEL_DB081D 0x01000003
+#define  FLASH_5720VENDOR_M_ST_M25PE10	 0x02000000
+#define  FLASH_5720VENDOR_M_ST_M25PE20	 0x02000002
+#define  FLASH_5720VENDOR_M_ST_M25PE40	 0x02000001
+#define  FLASH_5720VENDOR_M_ST_M25PE80	 0x02000003
+#define  FLASH_5720VENDOR_M_ST_M45PE10	 0x03000000
+#define  FLASH_5720VENDOR_M_ST_M45PE20	 0x03000002
+#define  FLASH_5720VENDOR_M_ST_M45PE40	 0x03000001
+#define  FLASH_5720VENDOR_M_ST_M45PE80	 0x03000003
+#define  FLASH_5720VENDOR_A_ATMEL_DB011B 0x01800000
+#define  FLASH_5720VENDOR_A_ATMEL_DB021B 0x01800002
+#define  FLASH_5720VENDOR_A_ATMEL_DB041B 0x01800001
+#define  FLASH_5720VENDOR_A_ATMEL_DB011D 0x01c00000
+#define  FLASH_5720VENDOR_A_ATMEL_DB021D 0x01c00002
+#define  FLASH_5720VENDOR_A_ATMEL_DB041D 0x01c00001
+#define  FLASH_5720VENDOR_A_ATMEL_DB081D 0x01c00003
+#define  FLASH_5720VENDOR_A_ST_M25PE10	 0x02800000
+#define  FLASH_5720VENDOR_A_ST_M25PE20	 0x02800002
+#define  FLASH_5720VENDOR_A_ST_M25PE40	 0x02800001
+#define  FLASH_5720VENDOR_A_ST_M25PE80	 0x02800003
+#define  FLASH_5720VENDOR_A_ST_M45PE10	 0x02c00000
+#define  FLASH_5720VENDOR_A_ST_M45PE20	 0x02c00002
+#define  FLASH_5720VENDOR_A_ST_M45PE40	 0x02c00001
+#define  FLASH_5720VENDOR_A_ST_M45PE80	 0x02c00003
+#define  FLASH_5720VENDOR_ATMEL_45USPT	 0x03c00000
+#define  FLASH_5720VENDOR_ST_25USPT	 0x03c00002
+#define  FLASH_5720VENDOR_ST_45USPT	 0x03c00001
+#define  NVRAM_CFG1_5752PAGE_SIZE_MASK	 0x70000000
+#define  FLASH_5752PAGE_SIZE_256	 0x00000000
+#define  FLASH_5752PAGE_SIZE_512	 0x10000000
+#define  FLASH_5752PAGE_SIZE_1K		 0x20000000
+#define  FLASH_5752PAGE_SIZE_2K		 0x30000000
+#define  FLASH_5752PAGE_SIZE_4K		 0x40000000
+#define  FLASH_5752PAGE_SIZE_264	 0x50000000
+#define  FLASH_5752PAGE_SIZE_528	 0x60000000
+#define NVRAM_CFG2			0x00007018
+#define NVRAM_CFG3			0x0000701c
+#define NVRAM_SWARB			0x00007020
+#define  SWARB_REQ_SET0			 0x00000001
+#define  SWARB_REQ_SET1			 0x00000002
+#define  SWARB_REQ_SET2			 0x00000004
+#define  SWARB_REQ_SET3			 0x00000008
+#define  SWARB_REQ_CLR0			 0x00000010
+#define  SWARB_REQ_CLR1			 0x00000020
+#define  SWARB_REQ_CLR2			 0x00000040
+#define  SWARB_REQ_CLR3			 0x00000080
+#define  SWARB_GNT0			 0x00000100
+#define  SWARB_GNT1			 0x00000200
+#define  SWARB_GNT2			 0x00000400
+#define  SWARB_GNT3			 0x00000800
+#define  SWARB_REQ0			 0x00001000
+#define  SWARB_REQ1			 0x00002000
+#define  SWARB_REQ2			 0x00004000
+#define  SWARB_REQ3			 0x00008000
+#define NVRAM_ACCESS			0x00007024
+#define  ACCESS_ENABLE			 0x00000001
+#define  ACCESS_WR_ENABLE		 0x00000002
+#define NVRAM_WRITE1			0x00007028
+/* 0x702c unused */
+
+#define NVRAM_ADDR_LOCKOUT		0x00007030
+/* 0x7034 --> 0x7500 unused */
+
+#define OTP_MODE			0x00007500
+#define OTP_MODE_OTP_THRU_GRC		 0x00000001
+#define OTP_CTRL			0x00007504
+#define OTP_CTRL_OTP_PROG_ENABLE	 0x00200000
+#define OTP_CTRL_OTP_CMD_READ		 0x00000000
+#define OTP_CTRL_OTP_CMD_INIT		 0x00000008
+#define OTP_CTRL_OTP_CMD_START		 0x00000001
+#define OTP_STATUS			0x00007508
+#define OTP_STATUS_CMD_DONE		 0x00000001
+#define OTP_ADDRESS			0x0000750c
+#define OTP_ADDRESS_MAGIC1		 0x000000a0
+#define OTP_ADDRESS_MAGIC2		 0x00000080
+/* 0x7510 unused */
+
+#define OTP_READ_DATA			0x00007514
+/* 0x7518 --> 0x7c04 unused */
+
+#define PCIE_TRANSACTION_CFG		0x00007c04
+#define PCIE_TRANS_CFG_1SHOT_MSI	 0x20000000
+#define PCIE_TRANS_CFG_LOM		 0x00000020
+/* 0x7c08 --> 0x7d28 unused */
+
+#define PCIE_PWR_MGMT_THRESH		0x00007d28
+#define PCIE_PWR_MGMT_L1_THRESH_MSK	 0x0000ff00
+#define PCIE_PWR_MGMT_L1_THRESH_4MS	 0x0000ff00
+#define PCIE_PWR_MGMT_EXT_ASPM_TMR_EN	 0x01000000
+/* 0x7d2c --> 0x7d54 unused */
+
+#define TG3_PCIE_LNKCTL			0x00007d54
+#define  TG3_PCIE_LNKCTL_L1_PLL_PD_EN	 0x00000008
+#define  TG3_PCIE_LNKCTL_L1_PLL_PD_DIS	 0x00000080
+/* 0x7d58 --> 0x7e70 unused */
+
+#define TG3_PCIE_PHY_TSTCTL		0x00007e2c
+#define  TG3_PCIE_PHY_TSTCTL_PCIE10	 0x00000040
+#define  TG3_PCIE_PHY_TSTCTL_PSCRAM	 0x00000020
+
+#define TG3_PCIE_EIDLE_DELAY		0x00007e70
+#define  TG3_PCIE_EIDLE_DELAY_MASK	 0x0000001f
+#define  TG3_PCIE_EIDLE_DELAY_13_CLKS	 0x0000000c
+/* 0x7e74 --> 0x8000 unused */
+
+
+/* Alternate PCIE definitions */
+#define TG3_PCIE_TLDLPL_PORT		0x00007c00
+#define TG3_PCIE_DL_LO_FTSMAX		0x0000000c
+#define TG3_PCIE_DL_LO_FTSMAX_MSK	0x000000ff
+#define TG3_PCIE_DL_LO_FTSMAX_VAL	0x0000002c
+#define TG3_PCIE_PL_LO_PHYCTL1		 0x00000004
+#define TG3_PCIE_PL_LO_PHYCTL1_L1PLLPD_EN	  0x00001000
+#define TG3_PCIE_PL_LO_PHYCTL5		 0x00000014
+#define TG3_PCIE_PL_LO_PHYCTL5_DIS_L2CLKREQ	  0x80000000
+
+#define TG3_REG_BLK_SIZE		0x00008000
+
+/* OTP bit definitions */
+#define TG3_OTP_AGCTGT_MASK		0x000000e0
+#define TG3_OTP_AGCTGT_SHIFT		1
+#define TG3_OTP_HPFFLTR_MASK		0x00000300
+#define TG3_OTP_HPFFLTR_SHIFT		1
+#define TG3_OTP_HPFOVER_MASK		0x00000400
+#define TG3_OTP_HPFOVER_SHIFT		1
+#define TG3_OTP_LPFDIS_MASK		0x00000800
+#define TG3_OTP_LPFDIS_SHIFT		11
+#define TG3_OTP_VDAC_MASK		0xff000000
+#define TG3_OTP_VDAC_SHIFT		24
+#define TG3_OTP_10BTAMP_MASK		0x0000f000
+#define TG3_OTP_10BTAMP_SHIFT		8
+#define TG3_OTP_ROFF_MASK		0x00e00000
+#define TG3_OTP_ROFF_SHIFT		11
+#define TG3_OTP_RCOFF_MASK		0x001c0000
+#define TG3_OTP_RCOFF_SHIFT		16
+
+#define TG3_OTP_DEFAULT			0x286c1640
+
+
+/* Hardware Legacy NVRAM layout */
+#define TG3_NVM_VPD_OFF			0x100
+#define TG3_NVM_VPD_LEN			256
+
+/* Hardware Selfboot NVRAM layout */
+#define TG3_NVM_HWSB_CFG1		0x00000004
+#define  TG3_NVM_HWSB_CFG1_MAJMSK	0xf8000000
+#define  TG3_NVM_HWSB_CFG1_MAJSFT	27
+#define  TG3_NVM_HWSB_CFG1_MINMSK	0x07c00000
+#define  TG3_NVM_HWSB_CFG1_MINSFT	22
+
+#define TG3_EEPROM_MAGIC		0x669955aa
+#define TG3_EEPROM_MAGIC_FW		0xa5000000
+#define TG3_EEPROM_MAGIC_FW_MSK		0xff000000
+#define TG3_EEPROM_SB_FORMAT_MASK	0x00e00000
+#define TG3_EEPROM_SB_FORMAT_1		0x00200000
+#define TG3_EEPROM_SB_REVISION_MASK	0x001f0000
+#define TG3_EEPROM_SB_REVISION_0	0x00000000
+#define TG3_EEPROM_SB_REVISION_2	0x00020000
+#define TG3_EEPROM_SB_REVISION_3	0x00030000
+#define TG3_EEPROM_SB_REVISION_4	0x00040000
+#define TG3_EEPROM_SB_REVISION_5	0x00050000
+#define TG3_EEPROM_SB_REVISION_6	0x00060000
+#define TG3_EEPROM_MAGIC_HW		0xabcd
+#define TG3_EEPROM_MAGIC_HW_MSK		0xffff
+
+#define TG3_NVM_DIR_START		0x18
+#define TG3_NVM_DIR_END			0x78
+#define TG3_NVM_DIRENT_SIZE		0xc
+#define TG3_NVM_DIRTYPE_SHIFT		24
+#define TG3_NVM_DIRTYPE_LENMSK		0x003fffff
+#define TG3_NVM_DIRTYPE_ASFINI		1
+#define TG3_NVM_DIRTYPE_EXTVPD		20
+#define TG3_NVM_PTREV_BCVER		0x94
+#define TG3_NVM_BCVER_MAJMSK		0x0000ff00
+#define TG3_NVM_BCVER_MAJSFT		8
+#define TG3_NVM_BCVER_MINMSK		0x000000ff
+
+#define TG3_EEPROM_SB_F1R0_EDH_OFF	0x10
+#define TG3_EEPROM_SB_F1R2_EDH_OFF	0x14
+#define TG3_EEPROM_SB_F1R2_MBA_OFF	0x10
+#define TG3_EEPROM_SB_F1R3_EDH_OFF	0x18
+#define TG3_EEPROM_SB_F1R4_EDH_OFF	0x1c
+#define TG3_EEPROM_SB_F1R5_EDH_OFF	0x20
+#define TG3_EEPROM_SB_F1R6_EDH_OFF	0x4c
+#define TG3_EEPROM_SB_EDH_MAJ_MASK	0x00000700
+#define TG3_EEPROM_SB_EDH_MAJ_SHFT	8
+#define TG3_EEPROM_SB_EDH_MIN_MASK	0x000000ff
+#define TG3_EEPROM_SB_EDH_BLD_MASK	0x0000f800
+#define TG3_EEPROM_SB_EDH_BLD_SHFT	11
+
+
+/* 32K Window into NIC internal memory */
+#define NIC_SRAM_WIN_BASE		0x00008000
+
+/* Offsets into first 32k of NIC internal memory. */
+#define NIC_SRAM_PAGE_ZERO		0x00000000
+#define NIC_SRAM_SEND_RCB		0x00000100 /* 16 * TG3_BDINFO_... */
+#define NIC_SRAM_RCV_RET_RCB		0x00000200 /* 16 * TG3_BDINFO_... */
+#define NIC_SRAM_STATS_BLK		0x00000300
+#define NIC_SRAM_STATUS_BLK		0x00000b00
+
+#define NIC_SRAM_FIRMWARE_MBOX		0x00000b50
+#define  NIC_SRAM_FIRMWARE_MBOX_MAGIC1	 0x4B657654
+#define  NIC_SRAM_FIRMWARE_MBOX_MAGIC2	 0x4861764b /* !dma on linkchg */
+
+#define NIC_SRAM_DATA_SIG		0x00000b54
+#define  NIC_SRAM_DATA_SIG_MAGIC	 0x4b657654 /* ascii for 'KevT' */
+
+#define NIC_SRAM_DATA_CFG			0x00000b58
+#define  NIC_SRAM_DATA_CFG_LED_MODE_MASK	 0x0000000c
+#define  NIC_SRAM_DATA_CFG_LED_MODE_MAC		 0x00000000
+#define  NIC_SRAM_DATA_CFG_LED_MODE_PHY_1	 0x00000004
+#define  NIC_SRAM_DATA_CFG_LED_MODE_PHY_2	 0x00000008
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_MASK	 0x00000030
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_UNKNOWN	 0x00000000
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_COPPER	 0x00000010
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER	 0x00000020
+#define  NIC_SRAM_DATA_CFG_WOL_ENABLE		 0x00000040
+#define  NIC_SRAM_DATA_CFG_ASF_ENABLE		 0x00000080
+#define  NIC_SRAM_DATA_CFG_EEPROM_WP		 0x00000100
+#define  NIC_SRAM_DATA_CFG_MINI_PCI		 0x00001000
+#define  NIC_SRAM_DATA_CFG_FIBER_WOL		 0x00004000
+#define  NIC_SRAM_DATA_CFG_NO_GPIO2		 0x00100000
+#define  NIC_SRAM_DATA_CFG_APE_ENABLE		 0x00200000
+
+#define NIC_SRAM_DATA_VER			0x00000b5c
+#define  NIC_SRAM_DATA_VER_SHIFT		 16
+
+#define NIC_SRAM_DATA_PHY_ID		0x00000b74
+#define  NIC_SRAM_DATA_PHY_ID1_MASK	 0xffff0000
+#define  NIC_SRAM_DATA_PHY_ID2_MASK	 0x0000ffff
+
+#define NIC_SRAM_FW_CMD_MBOX		0x00000b78
+#define  FWCMD_NICDRV_ALIVE		 0x00000001
+#define  FWCMD_NICDRV_PAUSE_FW		 0x00000002
+#define  FWCMD_NICDRV_IPV4ADDR_CHG	 0x00000003
+#define  FWCMD_NICDRV_IPV6ADDR_CHG	 0x00000004
+#define  FWCMD_NICDRV_FIX_DMAR		 0x00000005
+#define  FWCMD_NICDRV_FIX_DMAW		 0x00000006
+#define  FWCMD_NICDRV_LINK_UPDATE	 0x0000000c
+#define  FWCMD_NICDRV_ALIVE2		 0x0000000d
+#define  FWCMD_NICDRV_ALIVE3		 0x0000000e
+#define NIC_SRAM_FW_CMD_LEN_MBOX	0x00000b7c
+#define NIC_SRAM_FW_CMD_DATA_MBOX	0x00000b80
+#define NIC_SRAM_FW_ASF_STATUS_MBOX	0x00000c00
+#define NIC_SRAM_FW_DRV_STATE_MBOX	0x00000c04
+#define  DRV_STATE_START		 0x00000001
+#define  DRV_STATE_START_DONE		 0x80000001
+#define  DRV_STATE_UNLOAD		 0x00000002
+#define  DRV_STATE_UNLOAD_DONE		 0x80000002
+#define  DRV_STATE_WOL			 0x00000003
+#define  DRV_STATE_SUSPEND		 0x00000004
+
+#define NIC_SRAM_FW_RESET_TYPE_MBOX	0x00000c08
+
+#define NIC_SRAM_MAC_ADDR_HIGH_MBOX	0x00000c14
+#define NIC_SRAM_MAC_ADDR_LOW_MBOX	0x00000c18
+
+#define NIC_SRAM_WOL_MBOX		0x00000d30
+#define  WOL_SIGNATURE			 0x474c0000
+#define  WOL_DRV_STATE_SHUTDOWN		 0x00000001
+#define  WOL_DRV_WOL			 0x00000002
+#define  WOL_SET_MAGIC_PKT		 0x00000004
+
+#define NIC_SRAM_DATA_CFG_2		0x00000d38
+
+#define  NIC_SRAM_DATA_CFG_2_APD_EN	 0x00000400
+#define  SHASTA_EXT_LED_MODE_MASK	 0x00018000
+#define  SHASTA_EXT_LED_LEGACY		 0x00000000
+#define  SHASTA_EXT_LED_SHARED		 0x00008000
+#define  SHASTA_EXT_LED_MAC		 0x00010000
+#define  SHASTA_EXT_LED_COMBO		 0x00018000
+
+#define NIC_SRAM_DATA_CFG_3		0x00000d3c
+#define  NIC_SRAM_ASPM_DEBOUNCE		 0x00000002
+
+#define NIC_SRAM_DATA_CFG_4		0x00000d60
+#define  NIC_SRAM_GMII_MODE		 0x00000002
+#define  NIC_SRAM_RGMII_INBAND_DISABLE	 0x00000004
+#define  NIC_SRAM_RGMII_EXT_IBND_RX_EN	 0x00000008
+#define  NIC_SRAM_RGMII_EXT_IBND_TX_EN	 0x00000010
+
+#define NIC_SRAM_RX_MINI_BUFFER_DESC	0x00001000
+
+#define NIC_SRAM_DMA_DESC_POOL_BASE	0x00002000
+#define  NIC_SRAM_DMA_DESC_POOL_SIZE	 0x00002000
+#define NIC_SRAM_TX_BUFFER_DESC		0x00004000 /* 512 entries */
+#define NIC_SRAM_RX_BUFFER_DESC		0x00006000 /* 256 entries */
+#define NIC_SRAM_RX_JUMBO_BUFFER_DESC	0x00007000 /* 256 entries */
+#define NIC_SRAM_MBUF_POOL_BASE		0x00008000
+#define  NIC_SRAM_MBUF_POOL_SIZE96	 0x00018000
+#define  NIC_SRAM_MBUF_POOL_SIZE64	 0x00010000
+#define  NIC_SRAM_MBUF_POOL_BASE5705	0x00010000
+#define  NIC_SRAM_MBUF_POOL_SIZE5705	0x0000e000
+
+#define TG3_SRAM_RX_STD_BDCACHE_SIZE_5700	128
+#define TG3_SRAM_RX_STD_BDCACHE_SIZE_5755	64
+#define TG3_SRAM_RX_STD_BDCACHE_SIZE_5906	32
+
+#define TG3_SRAM_RX_JMB_BDCACHE_SIZE_5700	64
+#define TG3_SRAM_RX_JMB_BDCACHE_SIZE_5717	16
+
+
+/* Currently this is fixed. */
+#define TG3_PHY_MII_ADDR		0x01
+
+
+/*** Tigon3 specific PHY MII registers. ***/
+#define  TG3_BMCR_SPEED1000		0x0040
+
+#define MII_TG3_CTRL			0x09 /* 1000-baseT control register */
+#define  MII_TG3_CTRL_ADV_1000_HALF	0x0100
+#define  MII_TG3_CTRL_ADV_1000_FULL	0x0200
+#define  MII_TG3_CTRL_AS_MASTER		0x0800
+#define  MII_TG3_CTRL_ENABLE_AS_MASTER	0x1000
+
+#define MII_TG3_MMD_CTRL		0x0d /* MMD Access Control register */
+#define MII_TG3_MMD_CTRL_DATA_NOINC	0x4000
+#define MII_TG3_MMD_ADDRESS		0x0e /* MMD Address Data register */
+
+#define MII_TG3_EXT_CTRL		0x10 /* Extended control register */
+#define  MII_TG3_EXT_CTRL_FIFO_ELASTIC	0x0001
+#define  MII_TG3_EXT_CTRL_LNK3_LED_MODE	0x0002
+#define  MII_TG3_EXT_CTRL_FORCE_LED_OFF	0x0008
+#define  MII_TG3_EXT_CTRL_TBI		0x8000
+
+#define MII_TG3_EXT_STAT		0x11 /* Extended status register */
+#define  MII_TG3_EXT_STAT_LPASS		0x0100
+
+#define MII_TG3_RXR_COUNTERS		0x14 /* Local/Remote Receiver Counts */
+#define MII_TG3_DSP_RW_PORT		0x15 /* DSP coefficient read/write port */
+#define MII_TG3_DSP_CONTROL		0x16 /* DSP control register */
+#define MII_TG3_DSP_ADDRESS		0x17 /* DSP address register */
+
+#define MII_TG3_DSP_TAP1		0x0001
+#define  MII_TG3_DSP_TAP1_AGCTGT_DFLT	0x0007
+#define MII_TG3_DSP_TAP26		0x001a
+#define  MII_TG3_DSP_TAP26_ALNOKO	0x0001
+#define  MII_TG3_DSP_TAP26_RMRXSTO	0x0002
+#define  MII_TG3_DSP_TAP26_OPCSINPT	0x0004
+#define MII_TG3_DSP_AADJ1CH0		0x001f
+#define MII_TG3_DSP_CH34TP2		0x4022
+#define MII_TG3_DSP_CH34TP2_HIBW01	0x017b
+#define MII_TG3_DSP_AADJ1CH3		0x601f
+#define  MII_TG3_DSP_AADJ1CH3_ADCCKADJ	0x0002
+#define MII_TG3_DSP_EXP1_INT_STAT	0x0f01
+#define MII_TG3_DSP_EXP8		0x0f08
+#define  MII_TG3_DSP_EXP8_REJ2MHz	0x0001
+#define  MII_TG3_DSP_EXP8_AEDW		0x0200
+#define MII_TG3_DSP_EXP75		0x0f75
+#define MII_TG3_DSP_EXP96		0x0f96
+#define MII_TG3_DSP_EXP97		0x0f97
+
+#define MII_TG3_AUX_CTRL		0x18 /* auxiliary control register */
+
+#define MII_TG3_AUXCTL_SHDWSEL_AUXCTL	0x0000
+#define MII_TG3_AUXCTL_ACTL_TX_6DB	0x0400
+#define MII_TG3_AUXCTL_ACTL_SMDSP_ENA	0x0800
+#define MII_TG3_AUXCTL_ACTL_EXTPKTLEN	0x4000
+
+#define MII_TG3_AUXCTL_SHDWSEL_PWRCTL	0x0002
+#define MII_TG3_AUXCTL_PCTL_WOL_EN	0x0008
+#define MII_TG3_AUXCTL_PCTL_100TX_LPWR	0x0010
+#define MII_TG3_AUXCTL_PCTL_SPR_ISOLATE	0x0020
+#define MII_TG3_AUXCTL_PCTL_CL_AB_TXDAC	0x0040
+#define MII_TG3_AUXCTL_PCTL_VREG_11V	0x0180
+
+#define MII_TG3_AUXCTL_SHDWSEL_MISCTEST	0x0004
+
+#define MII_TG3_AUXCTL_SHDWSEL_MISC	0x0007
+#define MII_TG3_AUXCTL_MISC_WIRESPD_EN	0x0010
+#define MII_TG3_AUXCTL_MISC_FORCE_AMDIX	0x0200
+#define MII_TG3_AUXCTL_MISC_RDSEL_SHIFT	12
+#define MII_TG3_AUXCTL_MISC_WREN	0x8000
+
+
+#define MII_TG3_AUX_STAT		0x19 /* auxiliary status register */
+#define MII_TG3_AUX_STAT_LPASS		0x0004
+#define MII_TG3_AUX_STAT_SPDMASK	0x0700
+#define MII_TG3_AUX_STAT_10HALF		0x0100
+#define MII_TG3_AUX_STAT_10FULL		0x0200
+#define MII_TG3_AUX_STAT_100HALF	0x0300
+#define MII_TG3_AUX_STAT_100_4		0x0400
+#define MII_TG3_AUX_STAT_100FULL	0x0500
+#define MII_TG3_AUX_STAT_1000HALF	0x0600
+#define MII_TG3_AUX_STAT_1000FULL	0x0700
+#define MII_TG3_AUX_STAT_100		0x0008
+#define MII_TG3_AUX_STAT_FULL		0x0001
+
+#define MII_TG3_ISTAT			0x1a /* IRQ status register */
+#define MII_TG3_IMASK			0x1b /* IRQ mask register */
+
+/* ISTAT/IMASK event bits */
+#define MII_TG3_INT_LINKCHG		0x0002
+#define MII_TG3_INT_SPEEDCHG		0x0004
+#define MII_TG3_INT_DUPLEXCHG		0x0008
+#define MII_TG3_INT_ANEG_PAGE_RX	0x0400
+
+#define MII_TG3_MISC_SHDW		0x1c
+#define MII_TG3_MISC_SHDW_WREN		0x8000
+
+#define MII_TG3_MISC_SHDW_APD_WKTM_84MS	0x0001
+#define MII_TG3_MISC_SHDW_APD_ENABLE	0x0020
+#define MII_TG3_MISC_SHDW_APD_SEL	0x2800
+
+#define MII_TG3_MISC_SHDW_SCR5_C125OE	0x0001
+#define MII_TG3_MISC_SHDW_SCR5_DLLAPD	0x0002
+#define MII_TG3_MISC_SHDW_SCR5_SDTL	0x0004
+#define MII_TG3_MISC_SHDW_SCR5_DLPTLM	0x0008
+#define MII_TG3_MISC_SHDW_SCR5_LPED	0x0010
+#define MII_TG3_MISC_SHDW_SCR5_SEL	0x1400
+
+#define MII_TG3_TEST1			0x1e
+#define MII_TG3_TEST1_TRIM_EN		0x0010
+#define MII_TG3_TEST1_CRC_EN		0x8000
+
+/* Clause 45 expansion registers */
+#define TG3_CL45_D7_EEERES_STAT		0x803e
+#define TG3_CL45_D7_EEERES_STAT_LP_100TX	0x0002
+#define TG3_CL45_D7_EEERES_STAT_LP_1000T	0x0004
+
+
+/* Fast Ethernet Tranceiver definitions */
+#define MII_TG3_FET_PTEST		0x17
+#define  MII_TG3_FET_PTEST_FRC_TX_LINK	0x1000
+#define  MII_TG3_FET_PTEST_FRC_TX_LOCK	0x0800
+
+#define MII_TG3_FET_TEST		0x1f
+#define  MII_TG3_FET_SHADOW_EN		0x0080
+
+#define MII_TG3_FET_SHDW_MISCCTRL	0x10
+#define  MII_TG3_FET_SHDW_MISCCTRL_MDIX	0x4000
+
+#define MII_TG3_FET_SHDW_AUXMODE4	0x1a
+#define MII_TG3_FET_SHDW_AUXMODE4_SBPD	0x0008
+
+#define MII_TG3_FET_SHDW_AUXSTAT2	0x1b
+#define  MII_TG3_FET_SHDW_AUXSTAT2_APD	0x0020
+
+
+/* APE registers.  Accessible through BAR1 */
+#define TG3_APE_EVENT			0x000c
+#define  APE_EVENT_1			 0x00000001
+#define TG3_APE_LOCK_REQ		0x002c
+#define  APE_LOCK_REQ_DRIVER		 0x00001000
+#define TG3_APE_LOCK_GRANT		0x004c
+#define  APE_LOCK_GRANT_DRIVER		 0x00001000
+#define TG3_APE_SEG_SIG			0x4000
+#define  APE_SEG_SIG_MAGIC		 0x41504521
+
+/* APE shared memory.  Accessible through BAR1 */
+#define TG3_APE_FW_STATUS		0x400c
+#define  APE_FW_STATUS_READY		 0x00000100
+#define TG3_APE_FW_FEATURES		0x4010
+#define  TG3_APE_FW_FEATURE_NCSI	 0x00000002
+#define TG3_APE_FW_VERSION		0x4018
+#define  APE_FW_VERSION_MAJMSK		 0xff000000
+#define  APE_FW_VERSION_MAJSFT		 24
+#define  APE_FW_VERSION_MINMSK		 0x00ff0000
+#define  APE_FW_VERSION_MINSFT		 16
+#define  APE_FW_VERSION_REVMSK		 0x0000ff00
+#define  APE_FW_VERSION_REVSFT		 8
+#define  APE_FW_VERSION_BLDMSK		 0x000000ff
+#define TG3_APE_HOST_SEG_SIG		0x4200
+#define  APE_HOST_SEG_SIG_MAGIC		 0x484f5354
+#define TG3_APE_HOST_SEG_LEN		0x4204
+#define  APE_HOST_SEG_LEN_MAGIC		 0x00000020
+#define TG3_APE_HOST_INIT_COUNT		0x4208
+#define TG3_APE_HOST_DRIVER_ID		0x420c
+#define  APE_HOST_DRIVER_ID_LINUX	 0xf0000000
+#define  APE_HOST_DRIVER_ID_MAGIC(maj, min)	\
+	(APE_HOST_DRIVER_ID_LINUX | (maj & 0xff) << 16 | (min & 0xff) << 8)
+#define TG3_APE_HOST_BEHAVIOR		0x4210
+#define  APE_HOST_BEHAV_NO_PHYLOCK	 0x00000001
+#define TG3_APE_HOST_HEARTBEAT_INT_MS	0x4214
+#define  APE_HOST_HEARTBEAT_INT_DISABLE	 0
+#define  APE_HOST_HEARTBEAT_INT_5SEC	 5000
+#define TG3_APE_HOST_HEARTBEAT_COUNT	0x4218
+#define TG3_APE_HOST_DRVR_STATE		0x421c
+#define TG3_APE_HOST_DRVR_STATE_START	 0x00000001
+#define TG3_APE_HOST_DRVR_STATE_UNLOAD	 0x00000002
+#define TG3_APE_HOST_DRVR_STATE_WOL	 0x00000003
+#define TG3_APE_HOST_WOL_SPEED		0x4224
+#define TG3_APE_HOST_WOL_SPEED_AUTO	 0x00008000
+
+#define TG3_APE_EVENT_STATUS		0x4300
+
+#define  APE_EVENT_STATUS_DRIVER_EVNT	 0x00000010
+#define  APE_EVENT_STATUS_STATE_CHNGE	 0x00000500
+#define  APE_EVENT_STATUS_STATE_START	 0x00010000
+#define  APE_EVENT_STATUS_STATE_UNLOAD	 0x00020000
+#define  APE_EVENT_STATUS_STATE_WOL	 0x00030000
+#define  APE_EVENT_STATUS_STATE_SUSPEND	 0x00040000
+#define  APE_EVENT_STATUS_EVENT_PENDING	 0x80000000
+
+#define TG3_APE_PER_LOCK_REQ		0x8400
+#define  APE_LOCK_PER_REQ_DRIVER	 0x00001000
+#define TG3_APE_PER_LOCK_GRANT		0x8420
+#define  APE_PER_LOCK_GRANT_DRIVER	 0x00001000
+
+/* APE convenience enumerations. */
+#define TG3_APE_LOCK_GRC                1
+#define TG3_APE_LOCK_MEM                4
+
+#define TG3_EEPROM_SB_F1R2_MBA_OFF	0x10
+
+
+/* There are two ways to manage the TX descriptors on the tigon3.
+ * Either the descriptors are in host DMA'able memory, or they
+ * exist only in the cards on-chip SRAM.  All 16 send bds are under
+ * the same mode, they may not be configured individually.
+ *
+ * This driver always uses host memory TX descriptors.
+ *
+ * To use host memory TX descriptors:
+ *	1) Set GRC_MODE_HOST_SENDBDS in GRC_MODE register.
+ *	   Make sure GRC_MODE_4X_NIC_SEND_RINGS is clear.
+ *	2) Allocate DMA'able memory.
+ *	3) In NIC_SRAM_SEND_RCB (of desired index) of on-chip SRAM:
+ *	   a) Set TG3_BDINFO_HOST_ADDR to DMA address of memory
+ *	      obtained in step 2
+ *	   b) Set TG3_BDINFO_NIC_ADDR to NIC_SRAM_TX_BUFFER_DESC.
+ *	   c) Set len field of TG3_BDINFO_MAXLEN_FLAGS to number
+ *            of TX descriptors.  Leave flags field clear.
+ *	4) Access TX descriptors via host memory.  The chip
+ *	   will refetch into local SRAM as needed when producer
+ *	   index mailboxes are updated.
+ *
+ * To use on-chip TX descriptors:
+ *	1) Set GRC_MODE_4X_NIC_SEND_RINGS in GRC_MODE register.
+ *	   Make sure GRC_MODE_HOST_SENDBDS is clear.
+ *	2) In NIC_SRAM_SEND_RCB (of desired index) of on-chip SRAM:
+ *	   a) Set TG3_BDINFO_HOST_ADDR to zero.
+ *	   b) Set TG3_BDINFO_NIC_ADDR to NIC_SRAM_TX_BUFFER_DESC
+ *	   c) TG3_BDINFO_MAXLEN_FLAGS is don't care.
+ *	3) Access TX descriptors directly in on-chip SRAM
+ *	   using normal {read,write}l().  (and not using
+ *         pointer dereferencing of ioremap()'d memory like
+ *	   the broken Broadcom driver does)
+ *
+ * Note that BDINFO_FLAGS_DISABLED should be set in the flags field of
+ * TG3_BDINFO_MAXLEN_FLAGS of all unused SEND_RCB indices.
+ */
+struct tg3_tx_buffer_desc {
+	u32				addr_hi;
+	u32				addr_lo;
+
+	u32				len_flags;
+#define TXD_FLAG_TCPUDP_CSUM		0x0001
+#define TXD_FLAG_IP_CSUM		0x0002
+#define TXD_FLAG_END			0x0004
+#define TXD_FLAG_IP_FRAG		0x0008
+#define TXD_FLAG_JMB_PKT		0x0008
+#define TXD_FLAG_IP_FRAG_END		0x0010
+#define TXD_FLAG_VLAN			0x0040
+#define TXD_FLAG_COAL_NOW		0x0080
+#define TXD_FLAG_CPU_PRE_DMA		0x0100
+#define TXD_FLAG_CPU_POST_DMA		0x0200
+#define TXD_FLAG_ADD_SRC_ADDR		0x1000
+#define TXD_FLAG_CHOOSE_SRC_ADDR	0x6000
+#define TXD_FLAG_NO_CRC			0x8000
+#define TXD_LEN_SHIFT			16
+
+	u32				vlan_tag;
+#define TXD_VLAN_TAG_SHIFT		0
+#define TXD_MSS_SHIFT			16
+};
+
+#define TXD_ADDR			0x00UL /* 64-bit */
+#define TXD_LEN_FLAGS			0x08UL /* 32-bit (upper 16-bits are len) */
+#define TXD_VLAN_TAG			0x0cUL /* 32-bit (upper 16-bits are tag) */
+#define TXD_SIZE			0x10UL
+
+struct tg3_rx_buffer_desc {
+	u32				addr_hi;
+	u32				addr_lo;
+
+	u32				idx_len;
+#define RXD_IDX_MASK	0xffff0000
+#define RXD_IDX_SHIFT	16
+#define RXD_LEN_MASK	0x0000ffff
+#define RXD_LEN_SHIFT	0
+
+	u32				type_flags;
+#define RXD_TYPE_SHIFT	16
+#define RXD_FLAGS_SHIFT	0
+
+#define RXD_FLAG_END			0x0004
+#define RXD_FLAG_MINI			0x0800
+#define RXD_FLAG_JUMBO			0x0020
+#define RXD_FLAG_VLAN			0x0040
+#define RXD_FLAG_ERROR			0x0400
+#define RXD_FLAG_IP_CSUM		0x1000
+#define RXD_FLAG_TCPUDP_CSUM		0x2000
+#define RXD_FLAG_IS_TCP			0x4000
+
+	u32				ip_tcp_csum;
+#define RXD_IPCSUM_MASK		0xffff0000
+#define RXD_IPCSUM_SHIFT	16
+#define RXD_TCPCSUM_MASK	0x0000ffff
+#define RXD_TCPCSUM_SHIFT	0
+
+	u32				err_vlan;
+
+#define RXD_VLAN_MASK			0x0000ffff
+
+#define RXD_ERR_BAD_CRC			0x00010000
+#define RXD_ERR_COLLISION		0x00020000
+#define RXD_ERR_LINK_LOST		0x00040000
+#define RXD_ERR_PHY_DECODE		0x00080000
+#define RXD_ERR_ODD_NIBBLE_RCVD_MII	0x00100000
+#define RXD_ERR_MAC_ABRT		0x00200000
+#define RXD_ERR_TOO_SMALL		0x00400000
+#define RXD_ERR_NO_RESOURCES		0x00800000
+#define RXD_ERR_HUGE_FRAME		0x01000000
+#define RXD_ERR_MASK			0xffff0000
+
+	u32				reserved;
+	u32				opaque;
+#define RXD_OPAQUE_INDEX_MASK		0x0000ffff
+#define RXD_OPAQUE_INDEX_SHIFT		0
+#define RXD_OPAQUE_RING_STD		0x00010000
+#define RXD_OPAQUE_RING_JUMBO		0x00020000
+#define RXD_OPAQUE_RING_MINI		0x00040000
+#define RXD_OPAQUE_RING_MASK		0x00070000
+};
+
+struct tg3_ext_rx_buffer_desc {
+	struct {
+		u32			addr_hi;
+		u32			addr_lo;
+	}				addrlist[3];
+	u32				len2_len1;
+	u32				resv_len3;
+	struct tg3_rx_buffer_desc	std;
+};
+
+/* We only use this when testing out the DMA engine
+ * at probe time.  This is the internal format of buffer
+ * descriptors used by the chip at NIC_SRAM_DMA_DESCS.
+ */
+struct tg3_internal_buffer_desc {
+	u32				addr_hi;
+	u32				addr_lo;
+	u32				nic_mbuf;
+	/* XXX FIX THIS */
+#if __BYTE_ORDER == __BIG_ENDIAN
+	u16				cqid_sqid;
+	u16				len;
+#else
+	u16				len;
+	u16				cqid_sqid;
+#endif
+	u32				flags;
+	u32				__cookie1;
+	u32				__cookie2;
+	u32				__cookie3;
+};
+
+#define TG3_HW_STATUS_SIZE		0x50
+struct tg3_hw_status {
+	u32				status;
+#define SD_STATUS_UPDATED		0x00000001
+#define SD_STATUS_LINK_CHG		0x00000002
+#define SD_STATUS_ERROR			0x00000004
+
+	u32				status_tag;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+	u16				rx_consumer;
+	u16				rx_jumbo_consumer;
+#else
+	u16				rx_jumbo_consumer;
+	u16				rx_consumer;
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+	u16				reserved;
+	u16				rx_mini_consumer;
+#else
+	u16				rx_mini_consumer;
+	u16				reserved;
+#endif
+	struct {
+#if __BYTE_ORDER == __BIG_ENDIAN
+		u16			tx_consumer;
+		u16			rx_producer;
+#else
+		u16			rx_producer;
+		u16			tx_consumer;
+#endif
+	}				idx[16];
+};
+
+typedef struct {
+	u32 high, low;
+} tg3_stat64_t;
+
+struct tg3_hw_stats {
+	u8				__reserved0[0x400-0x300];
+
+	/* Statistics maintained by Receive MAC. */
+	tg3_stat64_t			rx_octets;
+	u64				__reserved1;
+	tg3_stat64_t			rx_fragments;
+	tg3_stat64_t			rx_ucast_packets;
+	tg3_stat64_t			rx_mcast_packets;
+	tg3_stat64_t			rx_bcast_packets;
+	tg3_stat64_t			rx_fcs_errors;
+	tg3_stat64_t			rx_align_errors;
+	tg3_stat64_t			rx_xon_pause_rcvd;
+	tg3_stat64_t			rx_xoff_pause_rcvd;
+	tg3_stat64_t			rx_mac_ctrl_rcvd;
+	tg3_stat64_t			rx_xoff_entered;
+	tg3_stat64_t			rx_frame_too_long_errors;
+	tg3_stat64_t			rx_jabbers;
+	tg3_stat64_t			rx_undersize_packets;
+	tg3_stat64_t			rx_in_length_errors;
+	tg3_stat64_t			rx_out_length_errors;
+	tg3_stat64_t			rx_64_or_less_octet_packets;
+	tg3_stat64_t			rx_65_to_127_octet_packets;
+	tg3_stat64_t			rx_128_to_255_octet_packets;
+	tg3_stat64_t			rx_256_to_511_octet_packets;
+	tg3_stat64_t			rx_512_to_1023_octet_packets;
+	tg3_stat64_t			rx_1024_to_1522_octet_packets;
+	tg3_stat64_t			rx_1523_to_2047_octet_packets;
+	tg3_stat64_t			rx_2048_to_4095_octet_packets;
+	tg3_stat64_t			rx_4096_to_8191_octet_packets;
+	tg3_stat64_t			rx_8192_to_9022_octet_packets;
+
+	u64				__unused0[37];
+
+	/* Statistics maintained by Transmit MAC. */
+	tg3_stat64_t			tx_octets;
+	u64				__reserved2;
+	tg3_stat64_t			tx_collisions;
+	tg3_stat64_t			tx_xon_sent;
+	tg3_stat64_t			tx_xoff_sent;
+	tg3_stat64_t			tx_flow_control;
+	tg3_stat64_t			tx_mac_errors;
+	tg3_stat64_t			tx_single_collisions;
+	tg3_stat64_t			tx_mult_collisions;
+	tg3_stat64_t			tx_deferred;
+	u64				__reserved3;
+	tg3_stat64_t			tx_excessive_collisions;
+	tg3_stat64_t			tx_late_collisions;
+	tg3_stat64_t			tx_collide_2times;
+	tg3_stat64_t			tx_collide_3times;
+	tg3_stat64_t			tx_collide_4times;
+	tg3_stat64_t			tx_collide_5times;
+	tg3_stat64_t			tx_collide_6times;
+	tg3_stat64_t			tx_collide_7times;
+	tg3_stat64_t			tx_collide_8times;
+	tg3_stat64_t			tx_collide_9times;
+	tg3_stat64_t			tx_collide_10times;
+	tg3_stat64_t			tx_collide_11times;
+	tg3_stat64_t			tx_collide_12times;
+	tg3_stat64_t			tx_collide_13times;
+	tg3_stat64_t			tx_collide_14times;
+	tg3_stat64_t			tx_collide_15times;
+	tg3_stat64_t			tx_ucast_packets;
+	tg3_stat64_t			tx_mcast_packets;
+	tg3_stat64_t			tx_bcast_packets;
+	tg3_stat64_t			tx_carrier_sense_errors;
+	tg3_stat64_t			tx_discards;
+	tg3_stat64_t			tx_errors;
+
+	u64				__unused1[31];
+
+	/* Statistics maintained by Receive List Placement. */
+	tg3_stat64_t			COS_rx_packets[16];
+	tg3_stat64_t			COS_rx_filter_dropped;
+	tg3_stat64_t			dma_writeq_full;
+	tg3_stat64_t			dma_write_prioq_full;
+	tg3_stat64_t			rxbds_empty;
+	tg3_stat64_t			rx_discards;
+	tg3_stat64_t			rx_errors;
+	tg3_stat64_t			rx_threshold_hit;
+
+	u64				__unused2[9];
+
+	/* Statistics maintained by Send Data Initiator. */
+	tg3_stat64_t			COS_out_packets[16];
+	tg3_stat64_t			dma_readq_full;
+	tg3_stat64_t			dma_read_prioq_full;
+	tg3_stat64_t			tx_comp_queue_full;
+
+	/* Statistics maintained by Host Coalescing. */
+	tg3_stat64_t			ring_set_send_prod_index;
+	tg3_stat64_t			ring_status_update;
+	tg3_stat64_t			nic_irqs;
+	tg3_stat64_t			nic_avoided_irqs;
+	tg3_stat64_t			nic_tx_threshold_hit;
+
+	/* NOT a part of the hardware statistics block format.
+	 * These stats are here as storage for tg3_periodic_fetch_stats().
+	 */
+	tg3_stat64_t			mbuf_lwm_thresh_hit;
+
+	u8				__reserved4[0xb00-0x9c8];
+};
+
+typedef u32 dma_addr_t;
+
+/* 'mapping' is superfluous as the chip does not write into
+ * the tx/rx post rings so we could just fetch it from there.
+ * But the cache behavior is better how we are doing it now.
+ */
+struct ring_info {
+	struct io_buffer			*iob;
+///	dma_addr_t mapping;
+};
+
+struct tg3_link_config {
+	/* Describes what we're trying to get. */
+	u32				advertising;
+	u16				speed;
+	u8				duplex;
+	u8				autoneg;
+	u8				flowctrl;
+
+	/* Describes what we actually have. */
+	u8				active_flowctrl;
+
+	u8				active_duplex;
+#define SPEED_INVALID		0xffff
+#define DUPLEX_INVALID		0xff
+#define AUTONEG_INVALID		0xff
+	u16				active_speed;
+
+	/* When we go in and out of low power mode we need
+	 * to swap with this state.
+	 */
+	u16				orig_speed;
+	u8				orig_duplex;
+	u8				orig_autoneg;
+	u32				orig_advertising;
+};
+
+struct tg3_bufmgr_config {
+	u32		mbuf_read_dma_low_water;
+	u32		mbuf_mac_rx_low_water;
+	u32		mbuf_high_water;
+
+	u32		mbuf_read_dma_low_water_jumbo;
+	u32		mbuf_mac_rx_low_water_jumbo;
+	u32		mbuf_high_water_jumbo;
+
+	u32		dma_low_water;
+	u32		dma_high_water;
+};
+
+struct tg3_ethtool_stats {
+	/* Statistics maintained by Receive MAC. */
+	u64		rx_octets;
+	u64		rx_fragments;
+	u64		rx_ucast_packets;
+	u64		rx_mcast_packets;
+	u64		rx_bcast_packets;
+	u64		rx_fcs_errors;
+	u64		rx_align_errors;
+	u64		rx_xon_pause_rcvd;
+	u64		rx_xoff_pause_rcvd;
+	u64		rx_mac_ctrl_rcvd;
+	u64		rx_xoff_entered;
+	u64		rx_frame_too_long_errors;
+	u64		rx_jabbers;
+	u64		rx_undersize_packets;
+	u64		rx_in_length_errors;
+	u64		rx_out_length_errors;
+	u64		rx_64_or_less_octet_packets;
+	u64		rx_65_to_127_octet_packets;
+	u64		rx_128_to_255_octet_packets;
+	u64		rx_256_to_511_octet_packets;
+	u64		rx_512_to_1023_octet_packets;
+	u64		rx_1024_to_1522_octet_packets;
+	u64		rx_1523_to_2047_octet_packets;
+	u64		rx_2048_to_4095_octet_packets;
+	u64		rx_4096_to_8191_octet_packets;
+	u64		rx_8192_to_9022_octet_packets;
+
+	/* Statistics maintained by Transmit MAC. */
+	u64		tx_octets;
+	u64		tx_collisions;
+	u64		tx_xon_sent;
+	u64		tx_xoff_sent;
+	u64		tx_flow_control;
+	u64		tx_mac_errors;
+	u64		tx_single_collisions;
+	u64		tx_mult_collisions;
+	u64		tx_deferred;
+	u64		tx_excessive_collisions;
+	u64		tx_late_collisions;
+	u64		tx_collide_2times;
+	u64		tx_collide_3times;
+	u64		tx_collide_4times;
+	u64		tx_collide_5times;
+	u64		tx_collide_6times;
+	u64		tx_collide_7times;
+	u64		tx_collide_8times;
+	u64		tx_collide_9times;
+	u64		tx_collide_10times;
+	u64		tx_collide_11times;
+	u64		tx_collide_12times;
+	u64		tx_collide_13times;
+	u64		tx_collide_14times;
+	u64		tx_collide_15times;
+	u64		tx_ucast_packets;
+	u64		tx_mcast_packets;
+	u64		tx_bcast_packets;
+	u64		tx_carrier_sense_errors;
+	u64		tx_discards;
+	u64		tx_errors;
+
+	/* Statistics maintained by Receive List Placement. */
+	u64		dma_writeq_full;
+	u64		dma_write_prioq_full;
+	u64		rxbds_empty;
+	u64		rx_discards;
+	u64		rx_errors;
+	u64		rx_threshold_hit;
+
+	/* Statistics maintained by Send Data Initiator. */
+	u64		dma_readq_full;
+	u64		dma_read_prioq_full;
+	u64		tx_comp_queue_full;
+
+	/* Statistics maintained by Host Coalescing. */
+	u64		ring_set_send_prod_index;
+	u64		ring_status_update;
+	u64		nic_irqs;
+	u64		nic_avoided_irqs;
+	u64		nic_tx_threshold_hit;
+
+	u64		mbuf_lwm_thresh_hit;
+};
+
+/* number of io_buffers to allocate */
+#define TG3_DEF_RX_RING_PENDING		8
+
+struct tg3_rx_prodring_set {
+	u32				rx_std_prod_idx;
+	u32				rx_std_cons_idx;
+	u32				rx_std_iob_cnt;
+	struct tg3_rx_buffer_desc	*rx_std;
+	struct io_buffer		*rx_iobufs[TG3_DEF_RX_RING_PENDING];
+	dma_addr_t			rx_std_mapping;
+};
+
+#define TG3_IRQ_MAX_VECS_RSS		5
+#define TG3_IRQ_MAX_VECS		TG3_IRQ_MAX_VECS_RSS
+
+enum TG3_FLAGS {
+	TG3_FLAG_TAGGED_STATUS = 0,
+	TG3_FLAG_TXD_MBOX_HWBUG,
+	TG3_FLAG_USE_LINKCHG_REG,
+	TG3_FLAG_ERROR_PROCESSED,
+	TG3_FLAG_ENABLE_ASF,
+	TG3_FLAG_ASPM_WORKAROUND,
+	TG3_FLAG_POLL_SERDES,
+	TG3_FLAG_MBOX_WRITE_REORDER,
+	TG3_FLAG_PCIX_TARGET_HWBUG,
+	TG3_FLAG_WOL_SPEED_100MB,
+	TG3_FLAG_WOL_ENABLE,
+	TG3_FLAG_EEPROM_WRITE_PROT,
+	TG3_FLAG_NVRAM,
+	TG3_FLAG_NVRAM_BUFFERED,
+	TG3_FLAG_SUPPORT_MSI,
+	TG3_FLAG_SUPPORT_MSIX,
+	TG3_FLAG_PCIX_MODE,
+	TG3_FLAG_PCI_HIGH_SPEED,
+	TG3_FLAG_PCI_32BIT,
+	TG3_FLAG_SRAM_USE_CONFIG,
+	TG3_FLAG_TX_RECOVERY_PENDING,
+	TG3_FLAG_WOL_CAP,
+	TG3_FLAG_JUMBO_RING_ENABLE,
+	TG3_FLAG_PAUSE_AUTONEG,
+	TG3_FLAG_CPMU_PRESENT,
+	TG3_FLAG_BROKEN_CHECKSUMS,
+	TG3_FLAG_JUMBO_CAPABLE,
+	TG3_FLAG_CHIP_RESETTING,
+	TG3_FLAG_INIT_COMPLETE,
+	TG3_FLAG_RESTART_TIMER,
+	TG3_FLAG_TSO_BUG,
+	TG3_FLAG_IS_5788,
+	TG3_FLAG_MAX_RXPEND_64,
+	TG3_FLAG_TSO_CAPABLE,
+	TG3_FLAG_PCI_EXPRESS,
+	TG3_FLAG_ASF_NEW_HANDSHAKE,
+	TG3_FLAG_HW_AUTONEG,
+	TG3_FLAG_IS_NIC,
+	TG3_FLAG_FLASH,
+	TG3_FLAG_HW_TSO_1,
+	TG3_FLAG_5705_PLUS,
+	TG3_FLAG_5750_PLUS,
+	TG3_FLAG_HW_TSO_3,
+	TG3_FLAG_USING_MSI,
+	TG3_FLAG_USING_MSIX,
+	TG3_FLAG_ICH_WORKAROUND,
+	TG3_FLAG_5780_CLASS,
+	TG3_FLAG_HW_TSO_2,
+	TG3_FLAG_1SHOT_MSI,
+	TG3_FLAG_NO_FWARE_REPORTED,
+	TG3_FLAG_NO_NVRAM_ADDR_TRANS,
+	TG3_FLAG_ENABLE_APE,
+	TG3_FLAG_PROTECTED_NVRAM,
+	TG3_FLAG_MDIOBUS_INITED,
+	TG3_FLAG_LRG_PROD_RING_CAP,
+	TG3_FLAG_RGMII_INBAND_DISABLE,
+	TG3_FLAG_RGMII_EXT_IBND_RX_EN,
+	TG3_FLAG_RGMII_EXT_IBND_TX_EN,
+	TG3_FLAG_CLKREQ_BUG,
+	TG3_FLAG_5755_PLUS,
+	TG3_FLAG_NO_NVRAM,
+	TG3_FLAG_ENABLE_RSS,
+	TG3_FLAG_ENABLE_TSS,
+	TG3_FLAG_4G_DMA_BNDRY_BUG,
+	TG3_FLAG_USE_JUMBO_BDFLAG,
+	TG3_FLAG_L1PLLPD_EN,
+	TG3_FLAG_57765_PLUS,
+	TG3_FLAG_APE_HAS_NCSI,
+	TG3_FLAG_5717_PLUS,
+
+	/* Add new flags before this comment and TG3_FLAG_NUMBER_OF_FLAGS */
+	TG3_FLAG_NUMBER_OF_FLAGS,	/* Last entry in enum TG3_FLAGS */
+};
+
+/* Following definition is copied from linux-3.0rc1/include/linux/kernel.h */
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+/* bitops.h */
+#define BITS_PER_BYTE           8
+#define BITS_TO_LONGS(nr)       DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
+/* types.h: */
+#define DECLARE_BITMAP(name,bits) \
+	unsigned long name[BITS_TO_LONGS(bits)]
+
+struct tg3 {
+	/* begin "general, frequently-used members" cacheline section */
+
+	/* If the IRQ handler (which runs lockless) needs to be
+	 * quiesced, the following bitmask state is used.  The
+	 * SYNC flag is set by non-IRQ context code to initiate
+	 * the quiescence.
+	 *
+	 * When the IRQ handler notices that SYNC is set, it
+	 * disables interrupts and returns.
+	 *
+	 * When all outstanding IRQ handlers have returned after
+	 * the SYNC flag has been set, the setter can be assured
+	 * that interrupts will no longer get run.
+	 *
+	 * In this way all SMP driver locks are never acquired
+	 * in hw IRQ context, only sw IRQ context or lower.
+	 */
+	unsigned int			irq_sync;
+
+	/* SMP locking strategy:
+	 *
+	 * lock: Held during reset, PHY access, timer, and when
+	 *       updating tg3_flags.
+	 *
+	 * netif_tx_lock: Held during tg3_start_xmit. tg3_tx holds
+	 *                netif_tx_lock when it needs to call
+	 *                netif_wake_queue.
+	 *
+	 * Both of these locks are to be held with BH safety.
+	 *
+	 * Because the IRQ handler, tg3_poll, and tg3_start_xmit
+	 * are running lockless, it is necessary to completely
+	 * quiesce the chip with tg3_netif_stop and tg3_full_lock
+	 * before reconfiguring the device.
+	 *
+	 * indirect_lock: Held when accessing registers indirectly
+	 *                with IRQ disabling.
+	 */
+
+	u32				(*read32_mbox) (struct tg3 *, u32);
+	void				(*write32_mbox) (struct tg3 *, u32,
+							 u32);
+	void				*regs;
+	struct net_device		*dev;
+	struct pci_device		*pdev;
+
+	u32				msg_enable;
+
+	/* begin "tx thread" cacheline section */
+	void				(*write32_tx_mbox) (struct tg3 *, u32,
+							    u32);
+
+	/* begin "rx thread" cacheline section */
+	void				(*write32_rx_mbox) (struct tg3 *, u32,
+							    u32);
+	u32				rx_std_max_post;
+	u32				rx_pkt_map_sz;
+
+	/* was struct tg3_napi: */
+	struct tg3_hw_status		*hw_status;
+
+	u32				last_tag;
+	u32				last_irq_tag;
+	u32				int_mbox;
+	/* NOTE: there was a coal_now in struct tg3_napi and struct tg3. We
+	 * didn't use coal_now in struct tg3, so it was removed */
+	u32				coal_now;
+
+	u32				consmbox;
+	u32				rx_rcb_ptr;
+	u16				*rx_rcb_prod_idx;
+	struct tg3_rx_prodring_set	prodring;
+	struct tg3_rx_buffer_desc	*rx_rcb;
+
+	u32				tx_prod;
+	u32				tx_cons;
+	u32				prodmbox;
+	struct tg3_tx_buffer_desc	*tx_ring;
+	struct ring_info		*tx_buffers;
+
+	dma_addr_t			status_mapping;
+	dma_addr_t			rx_rcb_mapping;
+	dma_addr_t			tx_desc_mapping;
+	/* end tg3_napi */
+
+	/* begin "everything else" cacheline(s) section */
+	unsigned long			rx_dropped;
+
+	DECLARE_BITMAP(tg3_flags, TG3_FLAG_NUMBER_OF_FLAGS);
+
+	union {
+	unsigned long			phy_crc_errors;
+	};
+
+	u16				timer_counter;
+	u16				timer_multiplier;
+	u32				timer_offset;
+	u16				asf_counter;
+	u16				asf_multiplier;
+
+	/* 1 second counter for transient serdes link events */
+	u32				serdes_counter;
+#define SERDES_AN_TIMEOUT_5704S		2
+#define SERDES_PARALLEL_DET_TIMEOUT	1
+#define SERDES_AN_TIMEOUT_5714S		1
+
+	struct tg3_link_config		link_config;
+	struct tg3_bufmgr_config	bufmgr_config;
+
+	/* cache h/w values, often passed straight to h/w */
+	u32				rx_mode;
+	u32				tx_mode;
+	u32				mac_mode;
+	u32				mi_mode;
+	u32				misc_host_ctrl;
+	u32				grc_mode;
+	u32				grc_local_ctrl;
+	u32				dma_rwctrl;
+	u32				coalesce_mode;
+
+	/* PCI block */
+	u32				pci_chip_rev_id;
+	u16				pci_cmd;
+	u8				pci_cacheline_sz;
+	u8				pci_lat_timer;
+
+	int				pm_cap;
+	union {
+	int				pcix_cap;
+	int				pcie_cap;
+	};
+	int				pcie_readrq;
+
+	u8				phy_addr;
+
+	/* PHY info */
+	u32				phy_id;
+#define TG3_PHY_ID_MASK			0xfffffff0
+#define TG3_PHY_ID_BCM5400		0x60008040
+#define TG3_PHY_ID_BCM5401		0x60008050
+#define TG3_PHY_ID_BCM5411		0x60008070
+#define TG3_PHY_ID_BCM5701		0x60008110
+#define TG3_PHY_ID_BCM5703		0x60008160
+#define TG3_PHY_ID_BCM5704		0x60008190
+#define TG3_PHY_ID_BCM5705		0x600081a0
+#define TG3_PHY_ID_BCM5750		0x60008180
+#define TG3_PHY_ID_BCM5752		0x60008100
+#define TG3_PHY_ID_BCM5714		0x60008340
+#define TG3_PHY_ID_BCM5780		0x60008350
+#define TG3_PHY_ID_BCM5755		0xbc050cc0
+#define TG3_PHY_ID_BCM5787		0xbc050ce0
+#define TG3_PHY_ID_BCM5756		0xbc050ed0
+#define TG3_PHY_ID_BCM5784		0xbc050fa0
+#define TG3_PHY_ID_BCM5761		0xbc050fd0
+#define TG3_PHY_ID_BCM5718C		0x5c0d8a00
+#define TG3_PHY_ID_BCM5718S		0xbc050ff0
+#define TG3_PHY_ID_BCM57765		0x5c0d8a40
+#define TG3_PHY_ID_BCM5719C		0x5c0d8a20
+#define TG3_PHY_ID_BCM5720C		0x5c0d8b60
+#define TG3_PHY_ID_BCM5906		0xdc00ac40
+#define TG3_PHY_ID_BCM8002		0x60010140
+#define TG3_PHY_ID_INVALID		0xffffffff
+
+#define PHY_ID_RTL8211C			0x001cc910
+#define PHY_ID_RTL8201E			0x00008200
+
+#define TG3_PHY_ID_REV_MASK		0x0000000f
+#define TG3_PHY_REV_BCM5401_B0		0x1
+
+	/* This macro assumes the passed PHY ID is
+	 * already masked with TG3_PHY_ID_MASK.
+	 */
+#define TG3_KNOWN_PHY_ID(X)		\
+	((X) == TG3_PHY_ID_BCM5400 || (X) == TG3_PHY_ID_BCM5401 || \
+	 (X) == TG3_PHY_ID_BCM5411 || (X) == TG3_PHY_ID_BCM5701 || \
+	 (X) == TG3_PHY_ID_BCM5703 || (X) == TG3_PHY_ID_BCM5704 || \
+	 (X) == TG3_PHY_ID_BCM5705 || (X) == TG3_PHY_ID_BCM5750 || \
+	 (X) == TG3_PHY_ID_BCM5752 || (X) == TG3_PHY_ID_BCM5714 || \
+	 (X) == TG3_PHY_ID_BCM5780 || (X) == TG3_PHY_ID_BCM5787 || \
+	 (X) == TG3_PHY_ID_BCM5755 || (X) == TG3_PHY_ID_BCM5756 || \
+	 (X) == TG3_PHY_ID_BCM5906 || (X) == TG3_PHY_ID_BCM5761 || \
+	 (X) == TG3_PHY_ID_BCM5718C || (X) == TG3_PHY_ID_BCM5718S || \
+	 (X) == TG3_PHY_ID_BCM57765 || (X) == TG3_PHY_ID_BCM5719C || \
+	 (X) == TG3_PHY_ID_BCM8002)
+
+	u32				phy_flags;
+#define TG3_PHYFLG_IS_LOW_POWER		0x00000001
+#define TG3_PHYFLG_IS_CONNECTED		0x00000002
+#define TG3_PHYFLG_USE_MI_INTERRUPT	0x00000004
+#define TG3_PHYFLG_PHY_SERDES		0x00000010
+#define TG3_PHYFLG_MII_SERDES		0x00000020
+#define TG3_PHYFLG_ANY_SERDES		(TG3_PHYFLG_PHY_SERDES |	\
+					TG3_PHYFLG_MII_SERDES)
+#define TG3_PHYFLG_IS_FET		0x00000040
+#define TG3_PHYFLG_10_100_ONLY		0x00000080
+#define TG3_PHYFLG_ENABLE_APD		0x00000100
+#define TG3_PHYFLG_CAPACITIVE_COUPLING	0x00000200
+#define TG3_PHYFLG_NO_ETH_WIRE_SPEED	0x00000400
+#define TG3_PHYFLG_JITTER_BUG		0x00000800
+#define TG3_PHYFLG_ADJUST_TRIM		0x00001000
+#define TG3_PHYFLG_ADC_BUG		0x00002000
+#define TG3_PHYFLG_5704_A0_BUG		0x00004000
+#define TG3_PHYFLG_BER_BUG		0x00008000
+#define TG3_PHYFLG_SERDES_PREEMPHASIS	0x00010000
+#define TG3_PHYFLG_PARALLEL_DETECT	0x00020000
+#define TG3_PHYFLG_EEE_CAP		0x00040000
+
+	u32				led_ctrl;
+	u32				phy_otp;
+	u32				setlpicnt;
+
+#define TG3_BPN_SIZE			24
+	char				board_part_number[TG3_BPN_SIZE];
+#define TG3_VER_SIZE			32
+	char				fw_ver[TG3_VER_SIZE];
+	u32				nic_sram_data_cfg;
+	u32				pci_clock_ctrl;
+	struct pci_device			*pdev_peer;
+
+	int				nvram_lock_cnt;
+	u32				nvram_size;
+#define TG3_NVRAM_SIZE_2KB		0x00000800
+#define TG3_NVRAM_SIZE_64KB		0x00010000
+#define TG3_NVRAM_SIZE_128KB		0x00020000
+#define TG3_NVRAM_SIZE_256KB		0x00040000
+#define TG3_NVRAM_SIZE_512KB		0x00080000
+#define TG3_NVRAM_SIZE_1MB		0x00100000
+#define TG3_NVRAM_SIZE_2MB		0x00200000
+
+	u32				nvram_pagesize;
+	u32				nvram_jedecnum;
+
+#define JEDEC_ATMEL			0x1f
+#define JEDEC_ST			0x20
+#define JEDEC_SAIFUN			0x4f
+#define JEDEC_SST			0xbf
+
+#define ATMEL_AT24C02_CHIP_SIZE		TG3_NVRAM_SIZE_2KB
+#define ATMEL_AT24C02_PAGE_SIZE		(8)
+
+#define ATMEL_AT24C64_CHIP_SIZE		TG3_NVRAM_SIZE_64KB
+#define ATMEL_AT24C64_PAGE_SIZE		(32)
+
+#define ATMEL_AT24C512_CHIP_SIZE	TG3_NVRAM_SIZE_512KB
+#define ATMEL_AT24C512_PAGE_SIZE	(128)
+
+#define ATMEL_AT45DB0X1B_PAGE_POS	9
+#define ATMEL_AT45DB0X1B_PAGE_SIZE	264
+
+#define ATMEL_AT25F512_PAGE_SIZE	256
+
+#define ST_M45PEX0_PAGE_SIZE		256
+
+#define SAIFUN_SA25F0XX_PAGE_SIZE	256
+
+#define SST_25VF0X0_PAGE_SIZE		4098
+
+	u16				subsystem_vendor;
+	u16				subsystem_device;
+};
+
+#define ARRAY_SIZE(x) ( sizeof(x) / sizeof((x)[0]) )
+
+#define TG3_TX_RING_SIZE		512
+#define TG3_DEF_TX_RING_PENDING		(TG3_TX_RING_SIZE - 1)
+
+#define	TG3_DMA_ALIGNMENT	16
+
+#define TG3_RX_STD_DMA_SZ		(1536 + 64 + 2)
+
+static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val)
+{
+	tp->write32_mbox(tp, off, val);
+///	if (!tg3_flag(tp, MBOX_WRITE_REORDER) && !tg3_flag(tp, ICH_WORKAROUND))
+///		tp->read32_mbox(tp, off);
+}
+
+u32 tg3_read_indirect_reg32(struct tg3 *tp, u32 off);
+void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val);
+u32 tg3_read_indirect_mbox(struct tg3 *tp, u32 off);
+void tg3_write_indirect_mbox(struct tg3 *tp, u32 off, u32 val);
+
+#define tw32(reg, val)			tg3_write_indirect_reg32(tp, reg, val)
+///#define tw32_mailbox(reg, val)		tg3_write_indirect_mbox(((val) & 0xffffffff), tp->regs + (reg))
+#define tw32_mailbox(reg, val)		tg3_write_indirect_mbox(tp, (reg), (val))
+#define tw32_mailbox_f(reg, val)	tw32_mailbox_flush(tp, (reg), (val))
+#define tw32_f(reg, val)		_tw32_flush(tp, (reg), (val), 0)
+#define tw32_wait_f(reg, val, us)	_tw32_flush(tp, (reg), (val), (us))
+
+#define tw32_tx_mbox(reg, val)		tp->write32_tx_mbox(tp, reg, val)
+#define tw32_rx_mbox(reg, val)		tp->write32_rx_mbox(tp, reg, val)
+
+#define tr32(reg)			tg3_read_indirect_reg32(tp, reg)
+#define tr32_mailbox(reg)		tp->read32_mbox(tp, reg)
+
+/* Functions & macros to verify TG3_FLAGS types */
+
+static inline int variable_test_bit(int nr, volatile const unsigned long *addr)
+{
+	int oldbit;
+
+	asm volatile("bt %2,%1\n\t"
+	             "sbb %0,%0"
+	             : "=r" (oldbit)
+	             : "m" (*(unsigned long *)addr), "Ir" (nr));
+
+	return oldbit;
+}
+
+static inline int _tg3_flag(enum TG3_FLAGS flag, unsigned long *bits)
+{
+	return variable_test_bit(flag, bits);
+}
+
+#define BITOP_ADDR(x) "+m" (*(volatile long *) (x))
+
+static inline void __set_bit(int nr, volatile unsigned long *addr)
+{
+	asm volatile("bts %1,%0" : BITOP_ADDR(addr) : "Ir" (nr) : "memory");
+}
+
+static inline void _tg3_flag_set(enum TG3_FLAGS flag, unsigned long *bits)
+{
+	__set_bit(flag, bits);
+}
+
+static inline void __clear_bit(int nr, volatile unsigned long *addr)
+{
+	asm volatile("btr %1,%0" : BITOP_ADDR(addr) : "Ir" (nr));
+}
+
+static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
+{
+	__clear_bit(flag, bits);
+}
+
+#define tg3_flag(tp, flag)				\
+	_tg3_flag(TG3_FLAG_##flag, (tp)->tg3_flags)
+#define tg3_flag_set(tp, flag)				\
+	_tg3_flag_set(TG3_FLAG_##flag, (tp)->tg3_flags)
+#define tg3_flag_clear(tp, flag)			\
+	_tg3_flag_clear(TG3_FLAG_##flag, (tp)->tg3_flags)
+
+/* tg3_main.c forward declarations */
+int tg3_init_rings(struct tg3 *tp);
+void tg3_rx_prodring_fini(struct tg3_rx_prodring_set *tpr);
+///int tg3_rx_prodring_init(struct tg3 *tp, struct tg3_rx_prodring_set *tpr);
+
+/* tg3_phy.c forward declarations */
+u32 tg3_read_otp_phycfg(struct tg3 *tp);
+void tg3_mdio_init(struct tg3 *tp);
+int tg3_phy_probe(struct tg3 *tp);
+int tg3_phy_reset(struct tg3 *tp);
+int tg3_setup_phy(struct tg3 *tp, int force_reset);
+int tg3_readphy(struct tg3 *tp, int reg, u32 *val);
+int tg3_writephy(struct tg3 *tp, int reg, u32 val);
+
+/* tg3_hw.c forward declarations */
+void _tw32_flush(struct tg3 *tp, u32 off, u32 val, u32 usec_wait);
+void tg3_write_mem(struct tg3 *tp, u32 off, u32 val);
+int tg3_get_invariants(struct tg3 *tp);
+void tg3_init_bufmgr_config(struct tg3 *tp);
+int tg3_get_device_address(struct tg3 *tp);
+int tg3_halt(struct tg3 *tp);
+void tg3_set_txd(struct tg3 *tp, int entry, dma_addr_t mapping, int len, u32 flags);
+void tg3_set_power_state_0(struct tg3 *tp);
+int tg3_alloc_consistent(struct tg3 *tp);
+int tg3_init_hw(struct tg3 *tp, int reset_phy);
+void tg3_poll_link(struct tg3 *tp);
+void tg3_wait_for_event_ack(struct tg3 *tp);
+void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1);
+void tg3_disable_ints(struct tg3 *tp);
+void tg3_enable_ints(struct tg3 *tp);
+
+static inline void tg3_generate_fw_event(struct tg3 *tp)
+{
+	u32 val;
+
+	val = tr32(GRC_RX_CPU_EVENT);
+	val |= GRC_RX_CPU_DRIVER_EVENT;
+	tw32_f(GRC_RX_CPU_EVENT, val);
+}
+
+/* linux-2.6.39, include/linux/mii.h: */
+/**
+ * mii_resolve_flowctrl_fdx
+ * @lcladv: value of MII ADVERTISE register
+ * @rmtadv: value of MII LPA register
+ *
+ * Resolve full duplex flow control as per IEEE 802.3-2005 table 28B-3
+ */
+static inline u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv)
+{
+	u8 cap = 0;
+
+	if (lcladv & rmtadv & ADVERTISE_PAUSE_CAP) {
+		cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
+	} else if (lcladv & rmtadv & ADVERTISE_PAUSE_ASYM) {
+		if (lcladv & ADVERTISE_PAUSE_CAP)
+			cap = FLOW_CTRL_RX;
+		else if (rmtadv & ADVERTISE_PAUSE_CAP)
+			cap = FLOW_CTRL_TX;
+	}
+
+	return cap;
+}
+
+#define ETH_FCS_LEN 4
+
+#endif /* !(_T3_H) */
diff --git a/roms/ipxe/src/drivers/net/tg3/tg3_hw.c b/roms/ipxe/src/drivers/net/tg3/tg3_hw.c
new file mode 100644
index 0000000000000000000000000000000000000000..3a481aba3265cf7f983f6dca780e7d146a224d30
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/tg3/tg3_hw.c
@@ -0,0 +1,2661 @@
+/*
+ * tg3.c: Broadcom Tigon3 ethernet driver.
+ *
+ * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
+ * Copyright (C) 2004 Sun Microsystems Inc.
+ * Copyright (C) 2005-2011 Broadcom Corporation.
+ *
+ * Firmware is:
+ *	Derived from proprietary unpublished source code,
+ *	Copyright (C) 2000-2003 Broadcom Corporation.
+ *
+ *	Permission is hereby granted for the distribution of this firmware
+ *	data in hexadecimal or equivalent format, provided this copyright
+ *	notice is accompanying it.
+ */
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include <mii.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <ipxe/pci.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/timer.h>
+#include <ipxe/malloc.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/netdevice.h>
+
+#include "tg3.h"
+
+#define RESET_KIND_SHUTDOWN	0
+#define RESET_KIND_INIT		1
+#define RESET_KIND_SUSPEND	2
+
+#define TG3_DEF_MAC_MODE	0
+
+void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
+{	DBGP("%s\n", __func__);
+
+	pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);
+	pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);
+}
+
+u32 tg3_read_indirect_reg32(struct tg3 *tp, u32 off)
+{	DBGP("%s\n", __func__);
+
+	u32 val;
+
+	pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);
+	pci_read_config_dword(tp->pdev, TG3PCI_REG_DATA, &val);
+	return val;
+}
+
+static u32 tg3_read32_mbox_5906(struct tg3 *tp, u32 off)
+{	DBGP("%s\n", __func__);
+
+	return readl(tp->regs + off + GRCMBOX_BASE);
+}
+
+static void tg3_write32_mbox_5906(struct tg3 *tp, u32 off, u32 val)
+{	DBGP("%s\n", __func__);
+
+	writel(val, tp->regs + off + GRCMBOX_BASE);
+}
+
+void tg3_write_indirect_mbox(struct tg3 *tp, u32 off, u32 val)
+{	DBGP("%s\n", __func__);
+
+	if (off == (MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW)) {
+		pci_write_config_dword(tp->pdev, TG3PCI_RCV_RET_RING_CON_IDX +
+				       TG3_64BIT_REG_LOW, val);
+		return;
+	}
+	if (off == TG3_RX_STD_PROD_IDX_REG) {
+		pci_write_config_dword(tp->pdev, TG3PCI_STD_RING_PROD_IDX +
+				       TG3_64BIT_REG_LOW, val);
+		return;
+	}
+
+	pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off + 0x5600);
+	pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);
+
+	/* In indirect mode when disabling interrupts, we also need
+	 * to clear the interrupt bit in the GRC local ctrl register.
+	 */
+	if ((off == (MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW)) &&
+	    (val == 0x1)) {
+		pci_write_config_dword(tp->pdev, TG3PCI_MISC_LOCAL_CTRL,
+				       tp->grc_local_ctrl|GRC_LCLCTRL_CLEARINT);
+	}
+}
+
+u32 tg3_read_indirect_mbox(struct tg3 *tp, u32 off)
+{	DBGP("%s\n", __func__);
+
+	u32 val;
+
+	pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off + 0x5600);
+	pci_read_config_dword(tp->pdev, TG3PCI_REG_DATA, &val);
+
+	return val;
+}
+
+/* usec_wait specifies the wait time in usec when writing to certain registers
+ * where it is unsafe to read back the register without some delay.
+ * GRC_LOCAL_CTRL is one example if the GPIOs are toggled to switch power.
+ * TG3PCI_CLOCK_CTRL is another example if the clock frequencies are changed.
+ */
+void _tw32_flush(struct tg3 *tp, u32 off, u32 val, u32 usec_wait)
+{	DBGP("%s\n", __func__);
+
+	tw32(off, val);
+	if (usec_wait)
+		udelay(usec_wait);
+	tr32(off);
+
+	/* Wait again after the read for the posted method to guarantee that
+	 * the wait time is met.
+	 */
+	if (usec_wait)
+		udelay(usec_wait);
+}
+
+/* stolen from legacy etherboot tg3 driver */
+void tg3_set_power_state_0(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	uint16_t power_control;
+	int pm = tp->pm_cap;
+
+	/* Make sure register accesses (indirect or otherwise)
+	 * will function correctly.
+	 */
+	pci_write_config_dword(tp->pdev,  TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl);
+
+	pci_read_config_word(tp->pdev, pm + PCI_PM_CTRL, &power_control);
+
+	power_control |= PCI_PM_CTRL_PME_STATUS;
+	power_control &= ~(PCI_PM_CTRL_STATE_MASK);
+	power_control |= 0;
+	pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
+
+	tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl, 100);
+
+	return;
+}
+
+void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
+{	DBGP("%s\n", __func__);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 &&
+	    (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) {
+		*val = 0;
+		return;
+	}
+
+	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+	pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
+
+	/* Always leave this as zero. */
+	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+}
+
+#define PCI_VENDOR_ID_ARIMA                0x161f
+
+static void tg3_get_eeprom_hw_cfg(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	u32 val;
+	u16 pmcsr;
+
+	/* On some early chips the SRAM cannot be accessed in D3hot state,
+	 * so need make sure we're in D0.
+	 */
+	pci_read_config_word(tp->pdev, tp->pm_cap + PCI_PM_CTRL, &pmcsr);
+	pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+	pci_write_config_word(tp->pdev, tp->pm_cap + PCI_PM_CTRL, pmcsr);
+	mdelay(1);
+
+	/* Make sure register accesses (indirect or otherwise)
+	 * will function correctly.
+	 */
+	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+			       tp->misc_host_ctrl);
+
+	/* The memory arbiter has to be enabled in order for SRAM accesses
+	 * to succeed.  Normally on powerup the tg3 chip firmware will make
+	 * sure it is enabled, but other entities such as system netboot
+	 * code might disable it.
+	 */
+	val = tr32(MEMARB_MODE);
+	tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
+
+	tp->phy_id = TG3_PHY_ID_INVALID;
+	tp->led_ctrl = LED_CTRL_MODE_PHY_1;
+
+	/* Assume an onboard device by default.  */
+	tg3_flag_set(tp, EEPROM_WRITE_PROT);
+
+	tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
+	if (val == NIC_SRAM_DATA_SIG_MAGIC) {
+		u32 nic_cfg, led_cfg;
+		u32 nic_phy_id, ver, cfg2 = 0, cfg4 = 0, eeprom_phy_id;
+		int eeprom_phy_serdes = 0;
+
+		tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg);
+		tp->nic_sram_data_cfg = nic_cfg;
+
+		tg3_read_mem(tp, NIC_SRAM_DATA_VER, &ver);
+		ver >>= NIC_SRAM_DATA_VER_SHIFT;
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
+		    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 &&
+		    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5703 &&
+		    (ver > 0) && (ver < 0x100))
+			tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2);
+
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+			tg3_read_mem(tp, NIC_SRAM_DATA_CFG_4, &cfg4);
+
+		if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) ==
+		    NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER)
+			eeprom_phy_serdes = 1;
+
+		tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &nic_phy_id);
+		if (nic_phy_id != 0) {
+			u32 id1 = nic_phy_id & NIC_SRAM_DATA_PHY_ID1_MASK;
+			u32 id2 = nic_phy_id & NIC_SRAM_DATA_PHY_ID2_MASK;
+
+			eeprom_phy_id  = (id1 >> 16) << 10;
+			eeprom_phy_id |= (id2 & 0xfc00) << 16;
+			eeprom_phy_id |= (id2 & 0x03ff) <<  0;
+		} else
+			eeprom_phy_id = 0;
+
+		tp->phy_id = eeprom_phy_id;
+		if (eeprom_phy_serdes) {
+			if (!tg3_flag(tp, 5705_PLUS))
+				tp->phy_flags |= TG3_PHYFLG_PHY_SERDES;
+			else
+				tp->phy_flags |= TG3_PHYFLG_MII_SERDES;
+		}
+
+		if (tg3_flag(tp, 5750_PLUS))
+			led_cfg = cfg2 & (NIC_SRAM_DATA_CFG_LED_MODE_MASK |
+				    SHASTA_EXT_LED_MODE_MASK);
+		else
+			led_cfg = nic_cfg & NIC_SRAM_DATA_CFG_LED_MODE_MASK;
+
+		switch (led_cfg) {
+		default:
+		case NIC_SRAM_DATA_CFG_LED_MODE_PHY_1:
+			tp->led_ctrl = LED_CTRL_MODE_PHY_1;
+			break;
+
+		case NIC_SRAM_DATA_CFG_LED_MODE_PHY_2:
+			tp->led_ctrl = LED_CTRL_MODE_PHY_2;
+			break;
+
+		case NIC_SRAM_DATA_CFG_LED_MODE_MAC:
+			tp->led_ctrl = LED_CTRL_MODE_MAC;
+
+			/* Default to PHY_1_MODE if 0 (MAC_MODE) is
+			 * read on some older 5700/5701 bootcode.
+			 */
+			if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
+			    ASIC_REV_5700 ||
+			    GET_ASIC_REV(tp->pci_chip_rev_id) ==
+			    ASIC_REV_5701)
+				tp->led_ctrl = LED_CTRL_MODE_PHY_1;
+
+			break;
+
+		case SHASTA_EXT_LED_SHARED:
+			tp->led_ctrl = LED_CTRL_MODE_SHARED;
+			if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 &&
+			    tp->pci_chip_rev_id != CHIPREV_ID_5750_A1)
+				tp->led_ctrl |= (LED_CTRL_MODE_PHY_1 |
+						 LED_CTRL_MODE_PHY_2);
+			break;
+
+		case SHASTA_EXT_LED_MAC:
+			tp->led_ctrl = LED_CTRL_MODE_SHASTA_MAC;
+			break;
+
+		case SHASTA_EXT_LED_COMBO:
+			tp->led_ctrl = LED_CTRL_MODE_COMBO;
+			if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0)
+				tp->led_ctrl |= (LED_CTRL_MODE_PHY_1 |
+						 LED_CTRL_MODE_PHY_2);
+			break;
+
+		}
+
+		if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+		     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) &&
+		    tp->subsystem_vendor == PCI_VENDOR_ID_DELL)
+			tp->led_ctrl = LED_CTRL_MODE_PHY_2;
+
+		if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX)
+			tp->led_ctrl = LED_CTRL_MODE_PHY_1;
+
+		if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP) {
+			tg3_flag_set(tp, EEPROM_WRITE_PROT);
+			if ((tp->subsystem_vendor ==
+			     PCI_VENDOR_ID_ARIMA) &&
+			    (tp->subsystem_device == 0x205a ||
+			     tp->subsystem_device == 0x2063))
+				tg3_flag_clear(tp, EEPROM_WRITE_PROT);
+		} else {
+			tg3_flag_clear(tp, EEPROM_WRITE_PROT);
+			tg3_flag_set(tp, IS_NIC);
+		}
+
+		if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) {
+			tg3_flag_set(tp, ENABLE_ASF);
+			if (tg3_flag(tp, 5750_PLUS))
+				tg3_flag_set(tp, ASF_NEW_HANDSHAKE);
+		}
+
+		if ((nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE) &&
+		    tg3_flag(tp, ENABLE_ASF))
+			tg3_flag_set(tp, ENABLE_APE);
+
+		if (cfg2 & (1 << 17))
+			tp->phy_flags |= TG3_PHYFLG_CAPACITIVE_COUPLING;
+
+		/* serdes signal pre-emphasis in register 0x590 set by */
+		/* bootcode if bit 18 is set */
+		if (cfg2 & (1 << 18))
+			tp->phy_flags |= TG3_PHYFLG_SERDES_PREEMPHASIS;
+
+		if ((tg3_flag(tp, 57765_PLUS) ||
+		     (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
+		      GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX)) &&
+		    (cfg2 & NIC_SRAM_DATA_CFG_2_APD_EN))
+			tp->phy_flags |= TG3_PHYFLG_ENABLE_APD;
+
+		if (tg3_flag(tp, PCI_EXPRESS) &&
+		    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
+		    !tg3_flag(tp, 57765_PLUS)) {
+			u32 cfg3;
+
+			tg3_read_mem(tp, NIC_SRAM_DATA_CFG_3, &cfg3);
+		}
+
+		if (cfg4 & NIC_SRAM_RGMII_INBAND_DISABLE)
+			tg3_flag_set(tp, RGMII_INBAND_DISABLE);
+		if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_RX_EN)
+			tg3_flag_set(tp, RGMII_EXT_IBND_RX_EN);
+		if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_TX_EN)
+			tg3_flag_set(tp, RGMII_EXT_IBND_TX_EN);
+	}
+}
+
+static void tg3_switch_clocks(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	u32 clock_ctrl;
+	u32 orig_clock_ctrl;
+
+	if (tg3_flag(tp, CPMU_PRESENT) || tg3_flag(tp, 5780_CLASS))
+		return;
+
+	clock_ctrl = tr32(TG3PCI_CLOCK_CTRL);
+
+	orig_clock_ctrl = clock_ctrl;
+	clock_ctrl &= (CLOCK_CTRL_FORCE_CLKRUN |
+		       CLOCK_CTRL_CLKRUN_OENABLE |
+		       0x1f);
+	tp->pci_clock_ctrl = clock_ctrl;
+
+	if (tg3_flag(tp, 5705_PLUS)) {
+		if (orig_clock_ctrl & CLOCK_CTRL_625_CORE) {
+			tw32_wait_f(TG3PCI_CLOCK_CTRL,
+				    clock_ctrl | CLOCK_CTRL_625_CORE, 40);
+		}
+	} else if ((orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE) != 0) {
+		tw32_wait_f(TG3PCI_CLOCK_CTRL,
+			    clock_ctrl |
+			    (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK),
+			    40);
+		tw32_wait_f(TG3PCI_CLOCK_CTRL,
+			    clock_ctrl | (CLOCK_CTRL_ALTCLK),
+			    40);
+	}
+	tw32_wait_f(TG3PCI_CLOCK_CTRL, clock_ctrl, 40);
+}
+
+int tg3_get_invariants(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	u32 misc_ctrl_reg;
+	u32 pci_state_reg, grc_misc_cfg;
+	u32 val;
+	u16 pci_cmd;
+	int err;
+
+	/* Force memory write invalidate off.  If we leave it on,
+	 * then on 5700_BX chips we have to enable a workaround.
+	 * The workaround is to set the TG3PCI_DMA_RW_CTRL boundary
+	 * to match the cacheline size.  The Broadcom driver have this
+	 * workaround but turns MWI off all the times so never uses
+	 * it.  This seems to suggest that the workaround is insufficient.
+	 */
+	pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd);
+	pci_cmd &= ~PCI_COMMAND_INVALIDATE;
+	pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
+
+	/* It is absolutely critical that TG3PCI_MISC_HOST_CTRL
+	 * has the register indirect write enable bit set before
+	 * we try to access any of the MMIO registers.  It is also
+	 * critical that the PCI-X hw workaround situation is decided
+	 * before that as well.
+	 */
+	pci_read_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+			      &misc_ctrl_reg);
+
+	tp->pci_chip_rev_id = (misc_ctrl_reg >>
+			       MISC_HOST_CTRL_CHIPREV_SHIFT);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_USE_PROD_ID_REG) {
+		u32 prod_id_asic_rev;
+
+		if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 ||
+		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
+		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 ||
+		    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720)
+			pci_read_config_dword(tp->pdev,
+					      TG3PCI_GEN2_PRODID_ASICREV,
+					      &prod_id_asic_rev);
+		else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57781 ||
+			 tp->pdev->device == TG3PCI_DEVICE_TIGON3_57785 ||
+			 tp->pdev->device == TG3PCI_DEVICE_TIGON3_57761 ||
+			 tp->pdev->device == TG3PCI_DEVICE_TIGON3_57762 ||
+			 tp->pdev->device == TG3PCI_DEVICE_TIGON3_57765 ||
+			 tp->pdev->device == TG3PCI_DEVICE_TIGON3_57791 ||
+			 tp->pdev->device == TG3PCI_DEVICE_TIGON3_57795)
+			pci_read_config_dword(tp->pdev,
+					      TG3PCI_GEN15_PRODID_ASICREV,
+					      &prod_id_asic_rev);
+		else
+			pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV,
+					      &prod_id_asic_rev);
+
+		tp->pci_chip_rev_id = prod_id_asic_rev;
+	}
+
+	/* Wrong chip ID in 5752 A0. This code can be removed later
+	 * as A0 is not in production.
+	 */
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5752_A0_HW)
+		tp->pci_chip_rev_id = CHIPREV_ID_5752_A0;
+
+	/* Initialize misc host control in PCI block. */
+	tp->misc_host_ctrl |= (misc_ctrl_reg &
+			       MISC_HOST_CTRL_CHIPREV);
+	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+			       tp->misc_host_ctrl);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+		tg3_flag_set(tp, 5717_PLUS);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57766 ||
+	    tg3_flag(tp, 5717_PLUS))
+		tg3_flag_set(tp, 57765_PLUS);
+
+	/* Intentionally exclude ASIC_REV_5906 */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
+	    tg3_flag(tp, 57765_PLUS))
+		tg3_flag_set(tp, 5755_PLUS);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
+	    tg3_flag(tp, 5755_PLUS) ||
+	    tg3_flag(tp, 5780_CLASS))
+		tg3_flag_set(tp, 5750_PLUS);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
+	    tg3_flag(tp, 5750_PLUS))
+		tg3_flag_set(tp, 5705_PLUS);
+
+	if (tg3_flag(tp, 5717_PLUS))
+		tg3_flag_set(tp, LRG_PROD_RING_CAP);
+
+	pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
+			      &pci_state_reg);
+
+	tp->pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP);
+	if (tp->pcie_cap != 0) {
+		u16 lnkctl;
+
+		tg3_flag_set(tp, PCI_EXPRESS);
+
+		pci_read_config_word(tp->pdev,
+				     tp->pcie_cap + PCI_EXP_LNKCTL,
+				     &lnkctl);
+		if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) {
+			if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+			    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+			    tp->pci_chip_rev_id == CHIPREV_ID_57780_A0 ||
+			    tp->pci_chip_rev_id == CHIPREV_ID_57780_A1)
+				tg3_flag_set(tp, CLKREQ_BUG);
+		} else if (tp->pci_chip_rev_id == CHIPREV_ID_5717_A0) {
+			tg3_flag_set(tp, L1PLLPD_EN);
+		}
+	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
+		tg3_flag_set(tp, PCI_EXPRESS);
+	} else if (!tg3_flag(tp, 5705_PLUS) ||
+		   tg3_flag(tp, 5780_CLASS)) {
+		tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX);
+		if (!tp->pcix_cap) {
+			DBGC(&tp->pdev->dev,
+				"Cannot find PCI-X capability, aborting\n");
+			return -EIO;
+		}
+
+		if (!(pci_state_reg & PCISTATE_CONV_PCI_MODE))
+			tg3_flag_set(tp, PCIX_MODE);
+	}
+
+	/* If we have an AMD 762 or VIA K8T800 chipset, write
+	 * reordering to the mailbox registers done by the host
+	 * controller can cause major troubles.  We read back from
+	 * every mailbox register write to force the writes to be
+	 * posted to the chip in order.
+	 */
+
+	pci_read_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE,
+			     &tp->pci_cacheline_sz);
+	pci_read_config_byte(tp->pdev, PCI_LATENCY_TIMER,
+			     &tp->pci_lat_timer);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
+	    tp->pci_lat_timer < 64) {
+		tp->pci_lat_timer = 64;
+		pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER,
+				      tp->pci_lat_timer);
+	}
+
+	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) {
+		/* 5700 BX chips need to have their TX producer index
+		 * mailboxes written twice to workaround a bug.
+		 */
+		tg3_flag_set(tp, TXD_MBOX_HWBUG);
+
+		/* If we are in PCI-X mode, enable register write workaround.
+		 *
+		 * The workaround is to use indirect register accesses
+		 * for all chip writes not to mailbox registers.
+		 */
+		if (tg3_flag(tp, PCIX_MODE)) {
+			u32 pm_reg;
+
+			tg3_flag_set(tp, PCIX_TARGET_HWBUG);
+
+			/* The chip can have it's power management PCI config
+			 * space registers clobbered due to this bug.
+			 * So explicitly force the chip into D0 here.
+			 */
+			pci_read_config_dword(tp->pdev,
+					      tp->pm_cap + PCI_PM_CTRL,
+					      &pm_reg);
+			pm_reg &= ~PCI_PM_CTRL_STATE_MASK;
+			pm_reg |= PCI_PM_CTRL_PME_ENABLE | 0 /* D0 */;
+			pci_write_config_dword(tp->pdev,
+					       tp->pm_cap + PCI_PM_CTRL,
+					       pm_reg);
+
+			/* Also, force SERR#/PERR# in PCI command. */
+			pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd);
+			pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+			pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
+		}
+	}
+
+	if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0)
+		tg3_flag_set(tp, PCI_HIGH_SPEED);
+	if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0)
+		tg3_flag_set(tp, PCI_32BIT);
+
+	/* Chip-specific fixup from Broadcom driver */
+	if ((tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) &&
+	    (!(pci_state_reg & PCISTATE_RETRY_SAME_DMA))) {
+		pci_state_reg |= PCISTATE_RETRY_SAME_DMA;
+		pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, pci_state_reg);
+	}
+
+	tp->write32_mbox = tg3_write_indirect_reg32;
+	tp->write32_rx_mbox = tg3_write_indirect_mbox;
+	tp->write32_tx_mbox = tg3_write_indirect_mbox;
+	tp->read32_mbox = tg3_read_indirect_mbox;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+		tp->read32_mbox = tg3_read32_mbox_5906;
+		tp->write32_mbox = tg3_write32_mbox_5906;
+		tp->write32_tx_mbox = tg3_write32_mbox_5906;
+		tp->write32_rx_mbox = tg3_write32_mbox_5906;
+	}
+
+	/* Get eeprom hw config before calling tg3_set_power_state().
+	 * In particular, the TG3_FLAG_IS_NIC flag must be
+	 * determined before calling tg3_set_power_state() so that
+	 * we know whether or not to switch out of Vaux power.
+	 * When the flag is set, it means that GPIO1 is used for eeprom
+	 * write protect and also implies that it is a LOM where GPIOs
+	 * are not used to switch power.
+	 */
+	tg3_get_eeprom_hw_cfg(tp);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
+	    tg3_flag(tp, 57765_PLUS))
+		tg3_flag_set(tp, CPMU_PRESENT);
+
+	/* Set up tp->grc_local_ctrl before calling tg3_power_up().
+	 * GPIO1 driven high will bring 5700's external PHY out of reset.
+	 * It is also used as eeprom write protect on LOMs.
+	 */
+	tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+	    tg3_flag(tp, EEPROM_WRITE_PROT))
+		tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 |
+				       GRC_LCLCTRL_GPIO_OUTPUT1);
+	/* Unused GPIO3 must be driven as output on 5752 because there
+	 * are no pull-up resistors on unused GPIO pins.
+	 */
+	else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
+		tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+		tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL;
+
+	if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761 ||
+	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_5761S) {
+		/* Turn off the debug UART. */
+		tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL;
+		if (tg3_flag(tp, IS_NIC))
+			/* Keep VMain power. */
+			tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE0 |
+					      GRC_LCLCTRL_GPIO_OUTPUT0;
+	}
+
+	/* Force the chip into D0. */
+	tg3_set_power_state_0(tp);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+		tp->phy_flags |= TG3_PHYFLG_IS_FET;
+
+	/* A few boards don't want Ethernet@WireSpeed phy feature */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
+	     (tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) &&
+	     (tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)) ||
+	    (tp->phy_flags & TG3_PHYFLG_IS_FET) ||
+	    (tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
+		tp->phy_flags |= TG3_PHYFLG_NO_ETH_WIRE_SPEED;
+
+	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5703_AX ||
+	    GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_AX)
+		tp->phy_flags |= TG3_PHYFLG_ADC_BUG;
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
+		tp->phy_flags |= TG3_PHYFLG_5704_A0_BUG;
+
+	if (tg3_flag(tp, 5705_PLUS) &&
+	    !(tp->phy_flags & TG3_PHYFLG_IS_FET) &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780 &&
+	    !tg3_flag(tp, 57765_PLUS)) {
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+			if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 &&
+			    tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722)
+				tp->phy_flags |= TG3_PHYFLG_JITTER_BUG;
+			if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5755M)
+				tp->phy_flags |= TG3_PHYFLG_ADJUST_TRIM;
+		} else
+			tp->phy_flags |= TG3_PHYFLG_BER_BUG;
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
+	    GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) {
+		tp->phy_otp = tg3_read_otp_phycfg(tp);
+		if (tp->phy_otp == 0)
+			tp->phy_otp = TG3_OTP_DEFAULT;
+	}
+
+	if (tg3_flag(tp, CPMU_PRESENT))
+		tp->mi_mode = MAC_MI_MODE_500KHZ_CONST;
+	else
+		tp->mi_mode = MAC_MI_MODE_BASE;
+
+	tp->coalesce_mode = 0;
+	if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX &&
+	    GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
+		tp->coalesce_mode |= HOSTCC_MODE_32BYTE;
+
+	/* Set these bits to enable statistics workaround. */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+	    tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 ||
+	    tp->pci_chip_rev_id == CHIPREV_ID_5720_A0) {
+		tp->coalesce_mode |= HOSTCC_MODE_ATTN;
+		tp->grc_mode |= GRC_MODE_IRQ_ON_FLOW_ATTN;
+	}
+
+	tg3_mdio_init(tp);
+
+	/* Initialize data/descriptor byte/word swapping. */
+	val = tr32(GRC_MODE);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+		val &= (GRC_MODE_BYTE_SWAP_B2HRX_DATA |
+			GRC_MODE_WORD_SWAP_B2HRX_DATA |
+			GRC_MODE_B2HRX_ENABLE |
+			GRC_MODE_HTX2B_ENABLE |
+			GRC_MODE_HOST_STACKUP);
+	else
+		val &= GRC_MODE_HOST_STACKUP;
+
+	tw32(GRC_MODE, val | tp->grc_mode);
+
+	tg3_switch_clocks(tp);
+
+	/* Clear this out for sanity. */
+	tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
+
+	pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
+			      &pci_state_reg);
+	if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0 &&
+	    !tg3_flag(tp, PCIX_TARGET_HWBUG)) {
+		u32 chiprevid = GET_CHIP_REV_ID(tp->misc_host_ctrl);
+
+		if (chiprevid == CHIPREV_ID_5701_A0 ||
+		    chiprevid == CHIPREV_ID_5701_B0 ||
+		    chiprevid == CHIPREV_ID_5701_B2 ||
+		    chiprevid == CHIPREV_ID_5701_B5) {
+			void *sram_base;
+
+			/* Write some dummy words into the SRAM status block
+			 * area, see if it reads back correctly.  If the return
+			 * value is bad, force enable the PCIX workaround.
+			 */
+			sram_base = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_STATS_BLK;
+
+			writel(0x00000000, sram_base);
+			writel(0x00000000, sram_base + 4);
+			writel(0xffffffff, sram_base + 4);
+			if (readl(sram_base) != 0x00000000)
+				tg3_flag_set(tp, PCIX_TARGET_HWBUG);
+		}
+	}
+
+	udelay(50);
+	/* FIXME: do we need nvram access? */
+///	tg3_nvram_init(tp);
+
+	grc_misc_cfg = tr32(GRC_MISC_CFG);
+	grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
+	    (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 ||
+	     grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M))
+		tg3_flag_set(tp, IS_5788);
+
+	if (!tg3_flag(tp, IS_5788) &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700)
+		tg3_flag_set(tp, TAGGED_STATUS);
+	if (tg3_flag(tp, TAGGED_STATUS)) {
+		tp->coalesce_mode |= (HOSTCC_MODE_CLRTICK_RXBD |
+				      HOSTCC_MODE_CLRTICK_TXBD);
+
+		tp->misc_host_ctrl |= MISC_HOST_CTRL_TAGGED_STATUS;
+		pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+				       tp->misc_host_ctrl);
+	}
+
+	/* Preserve the APE MAC_MODE bits */
+	if (tg3_flag(tp, ENABLE_APE))
+		tp->mac_mode = MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
+	else
+		tp->mac_mode = TG3_DEF_MAC_MODE;
+
+	/* these are limited to 10/100 only */
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
+	     (grc_misc_cfg == 0x8000 || grc_misc_cfg == 0x4000)) ||
+	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
+	     tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM &&
+	     (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901 ||
+	      tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901_2 ||
+	      tp->pdev->device == PCI_DEVICE_ID_TIGON3_5705F)) ||
+	    (tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM &&
+	     (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F ||
+	      tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F ||
+	      tp->pdev->device == PCI_DEVICE_ID_TIGON3_5787F)) ||
+	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790 ||
+	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_57791 ||
+	    tp->pdev->device == TG3PCI_DEVICE_TIGON3_57795 ||
+	    (tp->phy_flags & TG3_PHYFLG_IS_FET))
+		tp->phy_flags |= TG3_PHYFLG_10_100_ONLY;
+
+	err = tg3_phy_probe(tp);
+	if (err) {
+		DBGC(&tp->pdev->dev, "phy probe failed, err: %s\n", strerror(err));
+		/* ... but do not return immediately ... */
+	}
+
+	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
+		tp->phy_flags &= ~TG3_PHYFLG_USE_MI_INTERRUPT;
+	} else {
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
+			tp->phy_flags |= TG3_PHYFLG_USE_MI_INTERRUPT;
+		else
+			tp->phy_flags &= ~TG3_PHYFLG_USE_MI_INTERRUPT;
+	}
+
+	/* For all SERDES we poll the MAC status register. */
+	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
+		tg3_flag_set(tp, POLL_SERDES);
+	else
+		tg3_flag_clear(tp, POLL_SERDES);
+
+	/* Increment the rx prod index on the rx std ring by at most
+	 * 8 for these chips to workaround hw errata.
+	 */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
+		tp->rx_std_max_post = 8;
+
+	return err;
+}
+
+void tg3_init_bufmgr_config(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	if (tg3_flag(tp, 57765_PLUS)) {
+		tp->bufmgr_config.mbuf_read_dma_low_water =
+			DEFAULT_MB_RDMA_LOW_WATER_5705;
+		tp->bufmgr_config.mbuf_mac_rx_low_water =
+			DEFAULT_MB_MACRX_LOW_WATER_57765;
+		tp->bufmgr_config.mbuf_high_water =
+			DEFAULT_MB_HIGH_WATER_57765;
+
+		tp->bufmgr_config.mbuf_read_dma_low_water_jumbo =
+			DEFAULT_MB_RDMA_LOW_WATER_5705;
+		tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo =
+			DEFAULT_MB_MACRX_LOW_WATER_JUMBO_57765;
+		tp->bufmgr_config.mbuf_high_water_jumbo =
+			DEFAULT_MB_HIGH_WATER_JUMBO_57765;
+	} else if (tg3_flag(tp, 5705_PLUS)) {
+		tp->bufmgr_config.mbuf_read_dma_low_water =
+			DEFAULT_MB_RDMA_LOW_WATER_5705;
+		tp->bufmgr_config.mbuf_mac_rx_low_water =
+			DEFAULT_MB_MACRX_LOW_WATER_5705;
+		tp->bufmgr_config.mbuf_high_water =
+			DEFAULT_MB_HIGH_WATER_5705;
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+			tp->bufmgr_config.mbuf_mac_rx_low_water =
+				DEFAULT_MB_MACRX_LOW_WATER_5906;
+			tp->bufmgr_config.mbuf_high_water =
+				DEFAULT_MB_HIGH_WATER_5906;
+		}
+
+		tp->bufmgr_config.mbuf_read_dma_low_water_jumbo =
+			DEFAULT_MB_RDMA_LOW_WATER_JUMBO_5780;
+		tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo =
+			DEFAULT_MB_MACRX_LOW_WATER_JUMBO_5780;
+		tp->bufmgr_config.mbuf_high_water_jumbo =
+			DEFAULT_MB_HIGH_WATER_JUMBO_5780;
+	} else {
+		tp->bufmgr_config.mbuf_read_dma_low_water =
+			DEFAULT_MB_RDMA_LOW_WATER;
+		tp->bufmgr_config.mbuf_mac_rx_low_water =
+			DEFAULT_MB_MACRX_LOW_WATER;
+		tp->bufmgr_config.mbuf_high_water =
+			DEFAULT_MB_HIGH_WATER;
+
+		tp->bufmgr_config.mbuf_read_dma_low_water_jumbo =
+			DEFAULT_MB_RDMA_LOW_WATER_JUMBO;
+		tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo =
+			DEFAULT_MB_MACRX_LOW_WATER_JUMBO;
+		tp->bufmgr_config.mbuf_high_water_jumbo =
+			DEFAULT_MB_HIGH_WATER_JUMBO;
+	}
+
+	tp->bufmgr_config.dma_low_water = DEFAULT_DMA_LOW_WATER;
+	tp->bufmgr_config.dma_high_water = DEFAULT_DMA_HIGH_WATER;
+}
+
+#define TG3_FW_EVENT_TIMEOUT_USEC 2500
+
+void tg3_wait_for_event_ack(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	int i;
+
+	for (i = 0; i < TG3_FW_EVENT_TIMEOUT_USEC / 10; i++) {
+		if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT))
+			break;
+
+		udelay(10);
+	}
+}
+
+void tg3_write_mem(struct tg3 *tp, u32 off, u32 val)
+{	DBGP("%s\n", __func__);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 &&
+	    (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC))
+		return;
+
+	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
+
+	/* Always leave this as zero. */
+	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+}
+
+static void tg3_stop_fw(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	if (tg3_flag(tp, ENABLE_ASF) && !tg3_flag(tp, ENABLE_APE)) {
+		/* Wait for RX cpu to ACK the previous event. */
+		tg3_wait_for_event_ack(tp);
+
+		tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_PAUSE_FW);
+
+		tg3_generate_fw_event(tp);
+
+		/* Wait for RX cpu to ACK this event. */
+		tg3_wait_for_event_ack(tp);
+	}
+}
+
+static void tg3_write_sig_pre_reset(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX,
+		      NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
+}
+
+void tg3_disable_ints(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	tw32(TG3PCI_MISC_HOST_CTRL,
+	     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
+
+	tw32_mailbox_f(tp->int_mbox, 0x00000001);
+}
+
+void tg3_enable_ints(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	tw32(TG3PCI_MISC_HOST_CTRL,
+	     (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
+
+	tp->coal_now = tp->coalesce_mode | HOSTCC_MODE_ENABLE;
+
+	tw32_mailbox_f(tp->int_mbox, tp->last_tag << 24);
+
+	/* Force an initial interrupt */
+	if (!tg3_flag(tp, TAGGED_STATUS) &&
+	    (tp->hw_status->status & SD_STATUS_UPDATED))
+		tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
+	else
+		tw32(HOSTCC_MODE, tp->coal_now);
+}
+
+#define MAX_WAIT_CNT 1000
+
+/* To stop a block, clear the enable bit and poll till it clears. */
+static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit)
+{	DBGP("%s\n", __func__);
+
+	unsigned int i;
+	u32 val;
+
+	if (tg3_flag(tp, 5705_PLUS)) {
+		switch (ofs) {
+		case RCVLSC_MODE:
+		case DMAC_MODE:
+		case MBFREE_MODE:
+		case BUFMGR_MODE:
+		case MEMARB_MODE:
+			/* We can't enable/disable these bits of the
+			 * 5705/5750, just say success.
+			 */
+			return 0;
+
+		default:
+			break;
+		}
+	}
+
+	val = tr32(ofs);
+	val &= ~enable_bit;
+	tw32_f(ofs, val);
+
+	for (i = 0; i < MAX_WAIT_CNT; i++) {
+		udelay(100);
+		val = tr32(ofs);
+		if ((val & enable_bit) == 0)
+			break;
+	}
+
+	if (i == MAX_WAIT_CNT) {
+		DBGC(&tp->pdev->dev,
+			"tg3_stop_block timed out, ofs=%lx enable_bit=%x\n",
+			ofs, enable_bit);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int tg3_abort_hw(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	int i, err;
+
+	tg3_disable_ints(tp);
+
+	tp->rx_mode &= ~RX_MODE_ENABLE;
+	tw32_f(MAC_RX_MODE, tp->rx_mode);
+	udelay(10);
+
+	err  = tg3_stop_block(tp, RCVBDI_MODE, RCVBDI_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RCVLPC_MODE, RCVLPC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RCVLSC_MODE, RCVLSC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RCVDBDI_MODE, RCVDBDI_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RCVDCC_MODE, RCVDCC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RCVCC_MODE, RCVCC_MODE_ENABLE);
+
+	err |= tg3_stop_block(tp, SNDBDS_MODE, SNDBDS_MODE_ENABLE);
+	err |= tg3_stop_block(tp, SNDBDI_MODE, SNDBDI_MODE_ENABLE);
+	err |= tg3_stop_block(tp, SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RDMAC_MODE, RDMAC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, DMAC_MODE, DMAC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, SNDBDC_MODE, SNDBDC_MODE_ENABLE);
+
+	tp->mac_mode &= ~MAC_MODE_TDE_ENABLE;
+	tw32_f(MAC_MODE, tp->mac_mode);
+	udelay(40);
+
+	tp->tx_mode &= ~TX_MODE_ENABLE;
+	tw32_f(MAC_TX_MODE, tp->tx_mode);
+
+	for (i = 0; i < MAX_WAIT_CNT; i++) {
+		udelay(100);
+		if (!(tr32(MAC_TX_MODE) & TX_MODE_ENABLE))
+			break;
+	}
+	if (i >= MAX_WAIT_CNT) {
+		DBGC(&tp->pdev->dev,
+			"%s timed out, TX_MODE_ENABLE will not clear "
+			"MAC_TX_MODE=%08x\n", __func__, tr32(MAC_TX_MODE));
+		err |= -ENODEV;
+	}
+
+	err |= tg3_stop_block(tp, HOSTCC_MODE, HOSTCC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, WDMAC_MODE, WDMAC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, MBFREE_MODE, MBFREE_MODE_ENABLE);
+
+	tw32(FTQ_RESET, 0xffffffff);
+	tw32(FTQ_RESET, 0x00000000);
+
+	err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE);
+	err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE);
+
+	if (tp->hw_status)
+		memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
+
+	return err;
+}
+
+void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1)
+{	DBGP("%s\n", __func__);
+
+	u32 addr_high, addr_low;
+	int i;
+
+	addr_high = ((tp->dev->ll_addr[0] << 8) |
+		     tp->dev->ll_addr[1]);
+	addr_low = ((tp->dev->ll_addr[2] << 24) |
+		    (tp->dev->ll_addr[3] << 16) |
+		    (tp->dev->ll_addr[4] <<  8) |
+		    (tp->dev->ll_addr[5] <<  0));
+	for (i = 0; i < 4; i++) {
+		if (i == 1 && skip_mac_1)
+			continue;
+		tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high);
+		tw32(MAC_ADDR_0_LOW + (i * 8), addr_low);
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+		for (i = 0; i < 12; i++) {
+			tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high);
+			tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low);
+		}
+	}
+
+	addr_high = (tp->dev->ll_addr[0] +
+		     tp->dev->ll_addr[1] +
+		     tp->dev->ll_addr[2] +
+		     tp->dev->ll_addr[3] +
+		     tp->dev->ll_addr[4] +
+		     tp->dev->ll_addr[5]) &
+		TX_BACKOFF_SEED_MASK;
+	tw32(MAC_TX_BACKOFF_SEED, addr_high);
+}
+
+/* Save PCI command register before chip reset */
+static void tg3_save_pci_state(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	pci_read_config_word(tp->pdev, PCI_COMMAND, &tp->pci_cmd);
+}
+
+/* Restore PCI state after chip reset */
+static void tg3_restore_pci_state(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	u32 val;
+
+	/* Re-enable indirect register accesses. */
+	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+			       tp->misc_host_ctrl);
+
+	/* Set MAX PCI retry to zero. */
+	val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+	    tg3_flag(tp, PCIX_MODE))
+		val |= PCISTATE_RETRY_SAME_DMA;
+
+	pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
+
+	pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) {
+			pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE,
+					      tp->pci_cacheline_sz);
+			pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER,
+					      tp->pci_lat_timer);
+	}
+
+
+	/* Make sure PCI-X relaxed ordering bit is clear. */
+	if (tg3_flag(tp, PCIX_MODE)) {
+		u16 pcix_cmd;
+
+		pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+				     &pcix_cmd);
+		pcix_cmd &= ~PCI_X_CMD_ERO;
+		pci_write_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+				      pcix_cmd);
+	}
+}
+
+static int tg3_poll_fw(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	int i;
+	u32 val;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+		/* Wait up to 20ms for init done. */
+		for (i = 0; i < 200; i++) {
+			if (tr32(VCPU_STATUS) & VCPU_STATUS_INIT_DONE)
+				return 0;
+			udelay(100);
+		}
+		return -ENODEV;
+	}
+
+	/* Wait for firmware initialization to complete. */
+	for (i = 0; i < 100000; i++) {
+		tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
+		if (val == (u32)~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
+			break;
+		udelay(10);
+	}
+
+	/* Chip might not be fitted with firmware.  Some Sun onboard
+	 * parts are configured like that.  So don't signal the timeout
+	 * of the above loop as an error, but do report the lack of
+	 * running firmware once.
+	 */
+	if (i >= 100000 && !tg3_flag(tp, NO_FWARE_REPORTED)) {
+		tg3_flag_set(tp, NO_FWARE_REPORTED);
+
+		DBGC(tp->dev, "No firmware running\n");
+	}
+
+	if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) {
+		/* The 57765 A0 needs a little more
+		 * time to do some important work.
+		 */
+		mdelay(10);
+	}
+
+	return 0;
+}
+
+static int tg3_nvram_lock(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	if (tg3_flag(tp, NVRAM)) {
+		int i;
+
+		if (tp->nvram_lock_cnt == 0) {
+			tw32(NVRAM_SWARB, SWARB_REQ_SET1);
+			for (i = 0; i < 8000; i++) {
+				if (tr32(NVRAM_SWARB) & SWARB_GNT1)
+					break;
+				udelay(20);
+			}
+			if (i == 8000) {
+				tw32(NVRAM_SWARB, SWARB_REQ_CLR1);
+				return -ENODEV;
+			}
+		}
+		tp->nvram_lock_cnt++;
+	}
+	return 0;
+}
+
+static void tg3_nvram_unlock(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	if (tg3_flag(tp, NVRAM)) {
+		if (tp->nvram_lock_cnt > 0)
+			tp->nvram_lock_cnt--;
+		if (tp->nvram_lock_cnt == 0)
+			tw32_f(NVRAM_SWARB, SWARB_REQ_CLR1);
+	}
+}
+
+static int tg3_chip_reset(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	u32 val;
+	int err;
+
+	tg3_nvram_lock(tp);
+
+
+	/* No matching tg3_nvram_unlock() after this because
+	 * chip reset below will undo the nvram lock.
+	 */
+	tp->nvram_lock_cnt = 0;
+
+	/* GRC_MISC_CFG core clock reset will clear the memory
+	 * enable bit in PCI register 4 and the MSI enable bit
+	 * on some chips, so we save relevant registers here.
+	 */
+	tg3_save_pci_state(tp);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
+	    tg3_flag(tp, 5755_PLUS))
+		tw32(GRC_FASTBOOT_PC, 0);
+
+#if 0
+	/*
+	 * We must avoid the readl() that normally takes place.
+	 * It locks machines, causes machine checks, and other
+	 * fun things.  So, temporarily disable the 5701
+	 * hardware workaround, while we do the reset.
+	 */
+	write_op = tp->write32;
+	if (write_op == tg3_write_flush_reg32)
+		tp->write32 = tg3_write32;
+#endif
+
+	/* Prevent the irq handler from reading or writing PCI registers
+	 * during chip reset when the memory enable bit in the PCI command
+	 * register may be cleared.  The chip does not generate interrupt
+	 * at this time, but the irq handler may still be called due to irq
+	 * sharing or irqpoll.
+	 */
+	tg3_flag_set(tp, CHIP_RESETTING);
+
+	if (tp->hw_status) {
+		tp->hw_status->status = 0;
+		tp->hw_status->status_tag = 0;
+	}
+	tp->last_tag = 0;
+	tp->last_irq_tag = 0;
+
+	mb();
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
+		val = tr32(TG3_PCIE_LNKCTL) & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN;
+		tw32(TG3_PCIE_LNKCTL, val | TG3_PCIE_LNKCTL_L1_PLL_PD_DIS);
+	}
+
+	/* do the reset */
+	val = GRC_MISC_CFG_CORECLK_RESET;
+
+	if (tg3_flag(tp, PCI_EXPRESS)) {
+		/* Force PCIe 1.0a mode */
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
+		    !tg3_flag(tp, 57765_PLUS) &&
+		    tr32(TG3_PCIE_PHY_TSTCTL) ==
+		    (TG3_PCIE_PHY_TSTCTL_PCIE10 | TG3_PCIE_PHY_TSTCTL_PSCRAM))
+			tw32(TG3_PCIE_PHY_TSTCTL, TG3_PCIE_PHY_TSTCTL_PSCRAM);
+
+		if (tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) {
+			tw32(GRC_MISC_CFG, (1 << 29));
+			val |= (1 << 29);
+		}
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+		tw32(VCPU_STATUS, tr32(VCPU_STATUS) | VCPU_STATUS_DRV_RESET);
+		tw32(GRC_VCPU_EXT_CTRL,
+		     tr32(GRC_VCPU_EXT_CTRL) & ~GRC_VCPU_EXT_CTRL_HALT_CPU);
+	}
+
+	/* Manage gphy power for all CPMU absent PCIe devices. */
+	if (tg3_flag(tp, 5705_PLUS) && !tg3_flag(tp, CPMU_PRESENT))
+		val |= GRC_MISC_CFG_KEEP_GPHY_POWER;
+
+	tw32(GRC_MISC_CFG, val);
+
+	/* Unfortunately, we have to delay before the PCI read back.
+	 * Some 575X chips even will not respond to a PCI cfg access
+	 * when the reset command is given to the chip.
+	 *
+	 * How do these hardware designers expect things to work
+	 * properly if the PCI write is posted for a long period
+	 * of time?  It is always necessary to have some method by
+	 * which a register read back can occur to push the write
+	 * out which does the reset.
+	 *
+	 * For most tg3 variants the trick below was working.
+	 * Ho hum...
+	 */
+	udelay(120);
+
+	/* Flush PCI posted writes.  The normal MMIO registers
+	 * are inaccessible at this time so this is the only
+	 * way to make this reliably (actually, this is no longer
+	 * the case, see above).  I tried to use indirect
+	 * register read/write but this upset some 5701 variants.
+	 */
+	pci_read_config_dword(tp->pdev, PCI_COMMAND, &val);
+
+	udelay(120);
+
+	if (tg3_flag(tp, PCI_EXPRESS) && tp->pcie_cap) {
+		u16 val16;
+
+		if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A0) {
+			int i;
+			u32 cfg_val;
+
+			/* Wait for link training to complete.  */
+			for (i = 0; i < 5000; i++)
+				udelay(100);
+
+			pci_read_config_dword(tp->pdev, 0xc4, &cfg_val);
+			pci_write_config_dword(tp->pdev, 0xc4,
+					       cfg_val | (1 << 15));
+		}
+
+		/* Clear the "no snoop" and "relaxed ordering" bits. */
+		pci_read_config_word(tp->pdev,
+				     tp->pcie_cap + PCI_EXP_DEVCTL,
+				     &val16);
+		val16 &= ~(PCI_EXP_DEVCTL_RELAX_EN |
+			   PCI_EXP_DEVCTL_NOSNOOP_EN);
+		/*
+		 * Older PCIe devices only support the 128 byte
+		 * MPS setting.  Enforce the restriction.
+		 */
+		if (!tg3_flag(tp, CPMU_PRESENT))
+			val16 &= ~PCI_EXP_DEVCTL_PAYLOAD;
+		pci_write_config_word(tp->pdev,
+				      tp->pcie_cap + PCI_EXP_DEVCTL,
+				      val16);
+
+		/* Clear error status */
+		pci_write_config_word(tp->pdev,
+				      tp->pcie_cap + PCI_EXP_DEVSTA,
+				      PCI_EXP_DEVSTA_CED |
+				      PCI_EXP_DEVSTA_NFED |
+				      PCI_EXP_DEVSTA_FED |
+				      PCI_EXP_DEVSTA_URD);
+	}
+
+	tg3_restore_pci_state(tp);
+
+	tg3_flag_clear(tp, CHIP_RESETTING);
+	tg3_flag_clear(tp, ERROR_PROCESSED);
+
+	val = 0;
+	if (tg3_flag(tp, 5780_CLASS))
+		val = tr32(MEMARB_MODE);
+	tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
+
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A3) {
+		tg3_stop_fw(tp);
+		tw32(0x5000, 0x400);
+	}
+
+	tw32(GRC_MODE, tp->grc_mode);
+
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) {
+		val = tr32(0xc4);
+
+		tw32(0xc4, val | (1 << 15));
+	}
+
+	if ((tp->nic_sram_data_cfg & NIC_SRAM_DATA_CFG_MINI_PCI) != 0 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+		tp->pci_clock_ctrl |= CLOCK_CTRL_CLKRUN_OENABLE;
+		if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0)
+			tp->pci_clock_ctrl |= CLOCK_CTRL_FORCE_CLKRUN;
+		tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
+	}
+
+	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
+		tp->mac_mode |= MAC_MODE_PORT_MODE_TBI;
+		val = tp->mac_mode;
+	} else if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) {
+		tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+		val = tp->mac_mode;
+	} else
+		val = 0;
+
+	tw32_f(MAC_MODE, val);
+	udelay(40);
+
+	err = tg3_poll_fw(tp);
+	if (err)
+		return err;
+
+	if (tg3_flag(tp, PCI_EXPRESS) &&
+	    tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
+	    !tg3_flag(tp, 57765_PLUS)) {
+		val = tr32(0x7c00);
+
+		tw32(0x7c00, val | (1 << 25));
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
+		val = tr32(TG3_CPMU_CLCK_ORIDE);
+		tw32(TG3_CPMU_CLCK_ORIDE, val & ~CPMU_CLCK_ORIDE_MAC_ORIDE_EN);
+	}
+
+	if (tg3_flag(tp, CPMU_PRESENT)) {
+		tw32(TG3_CPMU_D0_CLCK_POLICY, 0);
+		val = tr32(TG3_CPMU_CLCK_ORIDE_EN);
+		tw32(TG3_CPMU_CLCK_ORIDE_EN,
+		     val | CPMU_CLCK_ORIDE_MAC_CLCK_ORIDE_EN);
+	}
+
+	return 0;
+}
+
+int tg3_halt(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	int err;
+
+	tg3_stop_fw(tp);
+
+	tg3_write_sig_pre_reset(tp);
+
+	tg3_abort_hw(tp);
+	err = tg3_chip_reset(tp);
+
+	__tg3_set_mac_addr(tp, 0);
+
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int tg3_nvram_read_using_eeprom(struct tg3 *tp,
+					u32 offset, u32 *val)
+{	DBGP("%s\n", __func__);
+
+	u32 tmp;
+	int i;
+
+	if (offset > EEPROM_ADDR_ADDR_MASK || (offset % 4) != 0)
+		return -EINVAL;
+
+	tmp = tr32(GRC_EEPROM_ADDR) & ~(EEPROM_ADDR_ADDR_MASK |
+					EEPROM_ADDR_DEVID_MASK |
+					EEPROM_ADDR_READ);
+	tw32(GRC_EEPROM_ADDR,
+	     tmp |
+	     (0 << EEPROM_ADDR_DEVID_SHIFT) |
+	     ((offset << EEPROM_ADDR_ADDR_SHIFT) &
+	      EEPROM_ADDR_ADDR_MASK) |
+	     EEPROM_ADDR_READ | EEPROM_ADDR_START);
+
+	for (i = 0; i < 1000; i++) {
+		tmp = tr32(GRC_EEPROM_ADDR);
+
+		if (tmp & EEPROM_ADDR_COMPLETE)
+			break;
+		mdelay(1);
+	}
+	if (!(tmp & EEPROM_ADDR_COMPLETE))
+		return -EBUSY;
+
+	tmp = tr32(GRC_EEPROM_DATA);
+
+	/*
+	 * The data will always be opposite the native endian
+	 * format.  Perform a blind byteswap to compensate.
+	 */
+	*val = bswap_32(tmp);
+
+	return 0;
+}
+
+static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr)
+{	DBGP("%s\n", __func__);
+
+	if (tg3_flag(tp, NVRAM) &&
+	    tg3_flag(tp, NVRAM_BUFFERED) &&
+	    tg3_flag(tp, FLASH) &&
+	    !tg3_flag(tp, NO_NVRAM_ADDR_TRANS) &&
+	    (tp->nvram_jedecnum == JEDEC_ATMEL))
+
+		addr = ((addr / tp->nvram_pagesize) <<
+			ATMEL_AT45DB0X1B_PAGE_POS) +
+		       (addr % tp->nvram_pagesize);
+
+	return addr;
+}
+
+static void tg3_enable_nvram_access(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	if (tg3_flag(tp, 5750_PLUS) && !tg3_flag(tp, PROTECTED_NVRAM)) {
+		u32 nvaccess = tr32(NVRAM_ACCESS);
+
+		tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
+	}
+}
+
+static void tg3_disable_nvram_access(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	if (tg3_flag(tp, 5750_PLUS) && !tg3_flag(tp, PROTECTED_NVRAM)) {
+		u32 nvaccess = tr32(NVRAM_ACCESS);
+
+		tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
+	}
+}
+
+#define NVRAM_CMD_TIMEOUT 10000
+
+static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd)
+{	DBGP("%s\n", __func__);
+
+	int i;
+
+	tw32(NVRAM_CMD, nvram_cmd);
+	for (i = 0; i < NVRAM_CMD_TIMEOUT; i++) {
+		udelay(10);
+		if (tr32(NVRAM_CMD) & NVRAM_CMD_DONE) {
+			udelay(10);
+			break;
+		}
+	}
+
+	if (i == NVRAM_CMD_TIMEOUT)
+		return -EBUSY;
+
+	return 0;
+}
+
+/* NOTE: Data read in from NVRAM is byteswapped according to
+ * the byteswapping settings for all other register accesses.
+ * tg3 devices are BE devices, so on a BE machine, the data
+ * returned will be exactly as it is seen in NVRAM.  On a LE
+ * machine, the 32-bit value will be byteswapped.
+ */
+static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
+{	DBGP("%s\n", __func__);
+
+	int ret;
+
+	if (!tg3_flag(tp, NVRAM))
+		return tg3_nvram_read_using_eeprom(tp, offset, val);
+
+	offset = tg3_nvram_phys_addr(tp, offset);
+
+	if (offset > NVRAM_ADDR_MSK)
+		return -EINVAL;
+
+	ret = tg3_nvram_lock(tp);
+	if (ret)
+		return ret;
+
+	tg3_enable_nvram_access(tp);
+
+	tw32(NVRAM_ADDR, offset);
+	ret = tg3_nvram_exec_cmd(tp, NVRAM_CMD_RD | NVRAM_CMD_GO |
+		NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
+
+	if (ret == 0)
+		*val = tr32(NVRAM_RDDATA);
+
+	tg3_disable_nvram_access(tp);
+
+	tg3_nvram_unlock(tp);
+
+	return ret;
+}
+
+/* Ensures NVRAM data is in bytestream format. */
+static int tg3_nvram_read_be32(struct tg3 *tp, u32 offset, u32 *val)
+{	DBGP("%s\n", __func__);
+
+	u32 v = 0;
+	int res = tg3_nvram_read(tp, offset, &v);
+	if (!res)
+		*val = cpu_to_be32(v);
+	return res;
+}
+
+int tg3_get_device_address(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	struct net_device *dev = tp->dev;
+	u32 hi, lo, mac_offset;
+	int addr_ok = 0;
+
+	mac_offset = 0x7c;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
+	    tg3_flag(tp, 5780_CLASS)) {
+		if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID)
+			mac_offset = 0xcc;
+		if (tg3_nvram_lock(tp))
+			tw32_f(NVRAM_CMD, NVRAM_CMD_RESET);
+		else
+			tg3_nvram_unlock(tp);
+	} else if (tg3_flag(tp, 5717_PLUS)) {
+		if (PCI_FUNC(tp->pdev->busdevfn) & 1)
+			mac_offset = 0xcc;
+		if (PCI_FUNC(tp->pdev->busdevfn) > 1)
+			mac_offset += 0x18c;
+	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+		mac_offset = 0x10;
+
+	/* First try to get it from MAC address mailbox. */
+	tg3_read_mem(tp, NIC_SRAM_MAC_ADDR_HIGH_MBOX, &hi);
+	if ((hi >> 16) == 0x484b) {
+		dev->hw_addr[0] = (hi >>  8) & 0xff;
+		dev->hw_addr[1] = (hi >>  0) & 0xff;
+
+		tg3_read_mem(tp, NIC_SRAM_MAC_ADDR_LOW_MBOX, &lo);
+		dev->hw_addr[2] = (lo >> 24) & 0xff;
+		dev->hw_addr[3] = (lo >> 16) & 0xff;
+		dev->hw_addr[4] = (lo >>  8) & 0xff;
+		dev->hw_addr[5] = (lo >>  0) & 0xff;
+
+		/* Some old bootcode may report a 0 MAC address in SRAM */
+		addr_ok = is_valid_ether_addr(&dev->hw_addr[0]);
+	}
+	if (!addr_ok) {
+		/* Next, try NVRAM. */
+		if (!tg3_flag(tp, NO_NVRAM) &&
+		    !tg3_nvram_read_be32(tp, mac_offset + 0, &hi) &&
+		    !tg3_nvram_read_be32(tp, mac_offset + 4, &lo)) {
+			memcpy(&dev->hw_addr[0], ((char *)&hi) + 2, 2);
+			memcpy(&dev->hw_addr[2], (char *)&lo, sizeof(lo));
+		}
+		/* Finally just fetch it out of the MAC control regs. */
+		else {
+			hi = tr32(MAC_ADDR_0_HIGH);
+			lo = tr32(MAC_ADDR_0_LOW);
+
+			dev->hw_addr[5] = lo & 0xff;
+			dev->hw_addr[4] = (lo >> 8) & 0xff;
+			dev->hw_addr[3] = (lo >> 16) & 0xff;
+			dev->hw_addr[2] = (lo >> 24) & 0xff;
+			dev->hw_addr[1] = hi & 0xff;
+			dev->hw_addr[0] = (hi >> 8) & 0xff;
+		}
+	}
+
+	if (!is_valid_ether_addr(&dev->hw_addr[0])) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void __tg3_set_rx_mode(struct net_device *dev)
+{	DBGP("%s\n", __func__);
+
+	struct tg3 *tp = netdev_priv(dev);
+	u32 rx_mode;
+
+	rx_mode = tp->rx_mode & ~(RX_MODE_PROMISC |
+				  RX_MODE_KEEP_VLAN_TAG);
+
+	rx_mode |= RX_MODE_KEEP_VLAN_TAG;
+
+	/* Accept all multicast. */
+	tw32(MAC_HASH_REG_0, 0xffffffff);
+	tw32(MAC_HASH_REG_1, 0xffffffff);
+	tw32(MAC_HASH_REG_2, 0xffffffff);
+	tw32(MAC_HASH_REG_3, 0xffffffff);
+
+	if (rx_mode != tp->rx_mode) {
+		tp->rx_mode = rx_mode;
+		tw32_f(MAC_RX_MODE, rx_mode);
+		udelay(10);
+	}
+}
+
+static void __tg3_set_coalesce(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+
+	tw32(HOSTCC_RXCOL_TICKS, 0);
+	tw32(HOSTCC_TXCOL_TICKS, LOW_TXCOL_TICKS);
+	tw32(HOSTCC_RXMAX_FRAMES, 1);
+	/* FIXME: mix between TXMAX and RXMAX taken from legacy driver */
+	tw32(HOSTCC_TXMAX_FRAMES, LOW_RXMAX_FRAMES);
+	tw32(HOSTCC_RXCOAL_MAXF_INT, 1);
+	tw32(HOSTCC_TXCOAL_MAXF_INT, 0);
+
+	if (!tg3_flag(tp, 5705_PLUS)) {
+		u32 val = DEFAULT_STAT_COAL_TICKS;
+
+		tw32(HOSTCC_RXCOAL_TICK_INT, DEFAULT_RXCOAL_TICK_INT);
+		tw32(HOSTCC_TXCOAL_TICK_INT, DEFAULT_TXCOAL_TICK_INT);
+
+		if (!netdev_link_ok(tp->dev))
+			val = 0;
+
+		tw32(HOSTCC_STAT_COAL_TICKS, val);
+	}
+}
+
+static void tg3_set_bdinfo(struct tg3 *tp, u32 bdinfo_addr,
+			   dma_addr_t mapping, u32 maxlen_flags,
+			   u32 nic_addr)
+{	DBGP("%s\n", __func__);
+
+	tg3_write_mem(tp,
+		      (bdinfo_addr + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH),
+		      ((u64) mapping >> 32));
+	tg3_write_mem(tp,
+		      (bdinfo_addr + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW),
+		      ((u64) mapping & 0xffffffff));
+	tg3_write_mem(tp,
+		      (bdinfo_addr + TG3_BDINFO_MAXLEN_FLAGS),
+		       maxlen_flags);
+
+	if (!tg3_flag(tp, 5705_PLUS))
+		tg3_write_mem(tp,
+			      (bdinfo_addr + TG3_BDINFO_NIC_ADDR),
+			      nic_addr);
+}
+
+static void tg3_rings_reset(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	int i;
+	u32 txrcb, rxrcb, limit;
+
+	/* Disable all transmit rings but the first. */
+	if (!tg3_flag(tp, 5705_PLUS))
+		limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 16;
+	else if (tg3_flag(tp, 5717_PLUS))
+		limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 4;
+	else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+		limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 2;
+	else
+		limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE;
+
+	for (txrcb = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE;
+	     txrcb < limit; txrcb += TG3_BDINFO_SIZE)
+		tg3_write_mem(tp, txrcb + TG3_BDINFO_MAXLEN_FLAGS,
+			      BDINFO_FLAGS_DISABLED);
+
+
+	/* Disable all receive return rings but the first. */
+	if (tg3_flag(tp, 5717_PLUS))
+		limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 17;
+	else if (!tg3_flag(tp, 5705_PLUS))
+		limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16;
+	else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+		 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+		limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 4;
+	else
+		limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE;
+
+	for (rxrcb = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE;
+	     rxrcb < limit; rxrcb += TG3_BDINFO_SIZE)
+		tg3_write_mem(tp, rxrcb + TG3_BDINFO_MAXLEN_FLAGS,
+			      BDINFO_FLAGS_DISABLED);
+
+	/* Disable interrupts */
+	tw32_mailbox_f(tp->int_mbox, 1);
+
+	tp->tx_prod = 0;
+	tp->tx_cons = 0;
+	tw32_mailbox(tp->prodmbox, 0);
+	tw32_rx_mbox(tp->consmbox, 0);
+
+	/* Make sure the NIC-based send BD rings are disabled. */
+	if (!tg3_flag(tp, 5705_PLUS)) {
+		u32 mbox = MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW;
+		for (i = 0; i < 16; i++)
+			tw32_tx_mbox(mbox + i * 8, 0);
+	}
+
+	txrcb = NIC_SRAM_SEND_RCB;
+	rxrcb = NIC_SRAM_RCV_RET_RCB;
+
+	/* Clear status block in ram. */
+	memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
+
+	/* Set status block DMA address */
+	tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH,
+	     ((u64) tp->status_mapping >> 32));
+	tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
+	     ((u64) tp->status_mapping & 0xffffffff));
+
+	if (tp->tx_ring) {
+		tg3_set_bdinfo(tp, txrcb, tp->tx_desc_mapping,
+			       (TG3_TX_RING_SIZE <<
+				BDINFO_FLAGS_MAXLEN_SHIFT),
+			       NIC_SRAM_TX_BUFFER_DESC);
+		txrcb += TG3_BDINFO_SIZE;
+	}
+
+	/* FIXME: will TG3_RX_RET_MAX_SIZE_5705 work on all cards? */
+	if (tp->rx_rcb) {
+		tg3_set_bdinfo(tp, rxrcb, tp->rx_rcb_mapping,
+			        TG3_RX_RET_MAX_SIZE_5705 <<
+				BDINFO_FLAGS_MAXLEN_SHIFT, 0);
+		rxrcb += TG3_BDINFO_SIZE;
+	}
+}
+
+static void tg3_setup_rxbd_thresholds(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	u32 val, bdcache_maxcnt;
+
+	if (!tg3_flag(tp, 5750_PLUS) ||
+	    tg3_flag(tp, 5780_CLASS) ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
+		bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5700;
+	else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+		 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+		bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5755;
+	else
+		bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5906;
+
+
+	/* NOTE: legacy driver uses RX_PENDING / 8, we only use 4 descriptors
+	 * for now, use / 4 so the result is > 0
+	 */
+	val = TG3_DEF_RX_RING_PENDING / 4;
+	tw32(RCVBDI_STD_THRESH, val);
+
+	if (tg3_flag(tp, 57765_PLUS))
+		tw32(STD_REPLENISH_LWM, bdcache_maxcnt);
+}
+
+static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
+{	DBGP("%s\n", __func__);
+
+	u32 val, rdmac_mode;
+	int i, err, limit;
+	struct tg3_rx_prodring_set *tpr = &tp->prodring;
+
+	tg3_stop_fw(tp);
+
+	tg3_write_sig_pre_reset(tp);
+
+	if (tg3_flag(tp, INIT_COMPLETE))
+		tg3_abort_hw(tp);
+
+	if (reset_phy)
+		tg3_phy_reset(tp);
+
+	err = tg3_chip_reset(tp);
+	if (err)
+		return err;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) {
+		val = tr32(PCIE_PWR_MGMT_THRESH) & ~PCIE_PWR_MGMT_L1_THRESH_MSK;
+		val |= PCIE_PWR_MGMT_EXT_ASPM_TMR_EN |
+		       PCIE_PWR_MGMT_L1_THRESH_4MS;
+		tw32(PCIE_PWR_MGMT_THRESH, val);
+
+		val = tr32(TG3_PCIE_EIDLE_DELAY) & ~TG3_PCIE_EIDLE_DELAY_MASK;
+		tw32(TG3_PCIE_EIDLE_DELAY, val | TG3_PCIE_EIDLE_DELAY_13_CLKS);
+
+		tw32(TG3_CORR_ERR_STAT, TG3_CORR_ERR_STAT_CLEAR);
+
+		val = tr32(TG3_PCIE_LNKCTL) & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN;
+		tw32(TG3_PCIE_LNKCTL, val | TG3_PCIE_LNKCTL_L1_PLL_PD_DIS);
+	}
+
+	if (tg3_flag(tp, L1PLLPD_EN)) {
+		u32 grc_mode = tr32(GRC_MODE);
+
+		/* Access the lower 1K of PL PCIE block registers. */
+		val = grc_mode & ~GRC_MODE_PCIE_PORT_MASK;
+		tw32(GRC_MODE, val | GRC_MODE_PCIE_PL_SEL);
+
+		val = tr32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_PL_LO_PHYCTL1);
+		tw32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_PL_LO_PHYCTL1,
+		     val | TG3_PCIE_PL_LO_PHYCTL1_L1PLLPD_EN);
+
+		tw32(GRC_MODE, grc_mode);
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
+		if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) {
+			u32 grc_mode = tr32(GRC_MODE);
+
+			/* Access the lower 1K of PL PCIE block registers. */
+			val = grc_mode & ~GRC_MODE_PCIE_PORT_MASK;
+			tw32(GRC_MODE, val | GRC_MODE_PCIE_PL_SEL);
+
+			val = tr32(TG3_PCIE_TLDLPL_PORT +
+				   TG3_PCIE_PL_LO_PHYCTL5);
+			tw32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_PL_LO_PHYCTL5,
+			     val | TG3_PCIE_PL_LO_PHYCTL5_DIS_L2CLKREQ);
+
+			tw32(GRC_MODE, grc_mode);
+		}
+
+		if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_57765_AX) {
+			u32 grc_mode = tr32(GRC_MODE);
+
+			/* Access the lower 1K of DL PCIE block registers. */
+			val = grc_mode & ~GRC_MODE_PCIE_PORT_MASK;
+			tw32(GRC_MODE, val | GRC_MODE_PCIE_DL_SEL);
+
+			val = tr32(TG3_PCIE_TLDLPL_PORT +
+				   TG3_PCIE_DL_LO_FTSMAX);
+			val &= ~TG3_PCIE_DL_LO_FTSMAX_MSK;
+			tw32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_DL_LO_FTSMAX,
+			     val | TG3_PCIE_DL_LO_FTSMAX_VAL);
+
+			tw32(GRC_MODE, grc_mode);
+		}
+
+		val = tr32(TG3_CPMU_LSPD_10MB_CLK);
+		val &= ~CPMU_LSPD_10MB_MACCLK_MASK;
+		val |= CPMU_LSPD_10MB_MACCLK_6_25;
+		tw32(TG3_CPMU_LSPD_10MB_CLK, val);
+	}
+
+	/* This works around an issue with Athlon chipsets on
+	 * B3 tigon3 silicon.  This bit has no effect on any
+	 * other revision.  But do not set this on PCI Express
+	 * chips and don't even touch the clocks if the CPMU is present.
+	 */
+	if (!tg3_flag(tp, CPMU_PRESENT)) {
+		if (!tg3_flag(tp, PCI_EXPRESS))
+			tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT;
+		tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
+	}
+
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+	    tg3_flag(tp, PCIX_MODE)) {
+		val = tr32(TG3PCI_PCISTATE);
+		val |= PCISTATE_RETRY_SAME_DMA;
+		tw32(TG3PCI_PCISTATE, val);
+	}
+
+	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_BX) {
+		/* Enable some hw fixes.  */
+		val = tr32(TG3PCI_MSI_DATA);
+		val |= (1 << 26) | (1 << 28) | (1 << 29);
+		tw32(TG3PCI_MSI_DATA, val);
+	}
+
+	/* Descriptor ring init may make accesses to the
+	 * NIC SRAM area to setup the TX descriptors, so we
+	 * can only do this after the hardware has been
+	 * successfully reset.
+	 */
+	err = tg3_init_rings(tp);
+	if (err)
+		return err;
+
+	if (tg3_flag(tp, 57765_PLUS)) {
+		val = tr32(TG3PCI_DMA_RW_CTRL) &
+		      ~DMA_RWCTRL_DIS_CACHE_ALIGNMENT;
+		if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0)
+			val &= ~DMA_RWCTRL_CRDRDR_RDMA_MRRS_MSK;
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765 &&
+		    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
+			val |= DMA_RWCTRL_TAGGED_STAT_WA;
+		tw32(TG3PCI_DMA_RW_CTRL, val | tp->dma_rwctrl);
+	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
+		   GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) {
+		/* This value is determined during the probe time DMA
+		 * engine test, tg3_test_dma.
+		 */
+		tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+	}
+
+	tp->grc_mode &= ~(GRC_MODE_HOST_SENDBDS |
+			  GRC_MODE_4X_NIC_SEND_RINGS |
+			  GRC_MODE_NO_TX_PHDR_CSUM |
+			  GRC_MODE_NO_RX_PHDR_CSUM);
+	tp->grc_mode |= GRC_MODE_HOST_SENDBDS;
+	tp->grc_mode |= GRC_MODE_NO_RX_PHDR_CSUM;
+
+	/* Pseudo-header checksum is done by hardware logic and not
+	 * the offload processers, so make the chip do the pseudo-
+	 * header checksums on receive.  For transmit it is more
+	 * convenient to do the pseudo-header checksum in software
+	 * as Linux does that on transmit for us in all cases.
+	 */
+	tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM;
+
+	tw32(GRC_MODE,
+	     tp->grc_mode |
+	     (GRC_MODE_IRQ_ON_MAC_ATTN | GRC_MODE_HOST_STACKUP));
+
+	/* Setup the timer prescalar register.  Clock is always 66Mhz. */
+	val = tr32(GRC_MISC_CFG);
+	val &= ~0xff;
+	val |= (65 << GRC_MISC_CFG_PRESCALAR_SHIFT);
+	tw32(GRC_MISC_CFG, val);
+
+	/* Initialize MBUF/DESC pool. */
+	if (tg3_flag(tp, 5750_PLUS)) {
+		/* Do nothing.  */
+	} else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+		tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE);
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+			tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE64);
+		else
+			tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE96);
+		tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
+		tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
+	}
+
+	tw32(BUFMGR_MB_RDMA_LOW_WATER,
+	     tp->bufmgr_config.mbuf_read_dma_low_water);
+	tw32(BUFMGR_MB_MACRX_LOW_WATER,
+	     tp->bufmgr_config.mbuf_mac_rx_low_water);
+	tw32(BUFMGR_MB_HIGH_WATER,
+	     tp->bufmgr_config.mbuf_high_water);
+
+	tw32(BUFMGR_DMA_LOW_WATER,
+	     tp->bufmgr_config.dma_low_water);
+	tw32(BUFMGR_DMA_HIGH_WATER,
+	     tp->bufmgr_config.dma_high_water);
+
+	val = BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+		val |= BUFMGR_MODE_NO_TX_UNDERRUN;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+	    tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 ||
+	    tp->pci_chip_rev_id == CHIPREV_ID_5720_A0)
+		val |= BUFMGR_MODE_MBLOW_ATTN_ENAB;
+	tw32(BUFMGR_MODE, val);
+	for (i = 0; i < 2000; i++) {
+		if (tr32(BUFMGR_MODE) & BUFMGR_MODE_ENABLE)
+			break;
+		udelay(10);
+	}
+	if (i >= 2000) {
+		DBGC(tp->dev, "%s cannot enable BUFMGR\n", __func__);
+		return -ENODEV;
+	}
+
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5906_A1)
+		tw32(ISO_PKT_TX, (tr32(ISO_PKT_TX) & ~0x3) | 0x2);
+
+	tg3_setup_rxbd_thresholds(tp);
+
+	/* Initialize TG3_BDINFO's at:
+	 *  RCVDBDI_STD_BD:	standard eth size rx ring
+	 *  RCVDBDI_JUMBO_BD:	jumbo frame rx ring
+	 *  RCVDBDI_MINI_BD:	small frame rx ring (??? does not work)
+	 *
+	 * like so:
+	 *  TG3_BDINFO_HOST_ADDR:	high/low parts of DMA address of ring
+	 *  TG3_BDINFO_MAXLEN_FLAGS:	(rx max buffer size << 16) |
+	 *                              ring attribute flags
+	 *  TG3_BDINFO_NIC_ADDR:	location of descriptors in nic SRAM
+	 *
+	 * Standard receive ring @ NIC_SRAM_RX_BUFFER_DESC, 512 entries.
+	 * Jumbo receive ring @ NIC_SRAM_RX_JUMBO_BUFFER_DESC, 256 entries.
+	 *
+	 * The size of each ring is fixed in the firmware, but the location is
+	 * configurable.
+	 */
+	tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH,
+	     ((u64) tpr->rx_std_mapping >> 32));
+	tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW,
+	     ((u64) tpr->rx_std_mapping & 0xffffffff));
+	if (!tg3_flag(tp, 5717_PLUS))
+		tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR,
+		     NIC_SRAM_RX_BUFFER_DESC);
+
+	/* Disable the mini ring */
+	if (!tg3_flag(tp, 5705_PLUS))
+		tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS,
+		     BDINFO_FLAGS_DISABLED);
+
+	val = TG3_RX_STD_MAX_SIZE_5700 << BDINFO_FLAGS_MAXLEN_SHIFT;
+
+	if (tg3_flag(tp, 57765_PLUS))
+		val |= (RX_STD_MAX_SIZE << 2);
+
+	tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, val);
+
+	tpr->rx_std_prod_idx = 0;
+
+	/* std prod index is updated by tg3_refill_prod_ring() */
+	tw32_rx_mbox(TG3_RX_STD_PROD_IDX_REG, 0);
+	tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG, 0);
+
+	tg3_rings_reset(tp);
+
+	__tg3_set_mac_addr(tp,0);
+
+#define	TG3_MAX_MTU	1522
+	/* MTU + ethernet header + FCS + optional VLAN tag */
+	tw32(MAC_RX_MTU_SIZE, TG3_MAX_MTU);
+
+	/* The slot time is changed by tg3_setup_phy if we
+	 * run at gigabit with half duplex.
+	 */
+	val = (2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+	      (6 << TX_LENGTHS_IPG_SHIFT) |
+	      (32 << TX_LENGTHS_SLOT_TIME_SHIFT);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+		val |= tr32(MAC_TX_LENGTHS) &
+		       (TX_LENGTHS_JMB_FRM_LEN_MSK |
+			TX_LENGTHS_CNT_DWN_VAL_MSK);
+
+	tw32(MAC_TX_LENGTHS, val);
+
+	/* Receive rules. */
+	tw32(MAC_RCV_RULE_CFG, RCV_RULE_CFG_DEFAULT_CLASS);
+	tw32(RCVLPC_CONFIG, 0x0181);
+
+	/* Calculate RDMAC_MODE setting early, we need it to determine
+	 * the RCVLPC_STATE_ENABLE mask.
+	 */
+	rdmac_mode = (RDMAC_MODE_ENABLE | RDMAC_MODE_TGTABORT_ENAB |
+		      RDMAC_MODE_MSTABORT_ENAB | RDMAC_MODE_PARITYERR_ENAB |
+		      RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB |
+		      RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
+		      RDMAC_MODE_LNGREAD_ENAB);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+		rdmac_mode |= RDMAC_MODE_MULT_DMA_RD_DIS;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
+		rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB |
+			      RDMAC_MODE_MBUF_RBD_CRPT_ENAB |
+			      RDMAC_MODE_MBUF_SBD_CRPT_ENAB;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
+	    tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) {
+		if (tg3_flag(tp, TSO_CAPABLE) &&
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+			rdmac_mode |= RDMAC_MODE_FIFO_SIZE_128;
+		} else if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) &&
+			   !tg3_flag(tp, IS_5788)) {
+			rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
+		}
+	}
+
+	if (tg3_flag(tp, PCI_EXPRESS))
+		rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+		rdmac_mode |= tr32(RDMAC_MODE) & RDMAC_MODE_H2BNC_VLAN_DET;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
+	    tg3_flag(tp, 57765_PLUS)) {
+		val = tr32(TG3_RDMA_RSRVCTRL_REG);
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
+			val &= ~(TG3_RDMA_RSRVCTRL_TXMRGN_MASK |
+				 TG3_RDMA_RSRVCTRL_FIFO_LWM_MASK |
+				 TG3_RDMA_RSRVCTRL_FIFO_HWM_MASK);
+			val |= TG3_RDMA_RSRVCTRL_TXMRGN_320B |
+			       TG3_RDMA_RSRVCTRL_FIFO_LWM_1_5K |
+			       TG3_RDMA_RSRVCTRL_FIFO_HWM_1_5K;
+		}
+		tw32(TG3_RDMA_RSRVCTRL_REG,
+		     val | TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX);
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
+		val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL);
+		tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val |
+		     TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K |
+		     TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_LSO_4K);
+	}
+
+	/* Receive/send statistics. */
+	if (tg3_flag(tp, 5750_PLUS)) {
+		val = tr32(RCVLPC_STATS_ENABLE);
+		val &= ~RCVLPC_STATSENAB_DACK_FIX;
+		tw32(RCVLPC_STATS_ENABLE, val);
+	} else if ((rdmac_mode & RDMAC_MODE_FIFO_SIZE_128) &&
+		   tg3_flag(tp, TSO_CAPABLE)) {
+		val = tr32(RCVLPC_STATS_ENABLE);
+		val &= ~RCVLPC_STATSENAB_LNGBRST_RFIX;
+		tw32(RCVLPC_STATS_ENABLE, val);
+	} else {
+		tw32(RCVLPC_STATS_ENABLE, 0xffffff);
+	}
+	tw32(RCVLPC_STATSCTRL, RCVLPC_STATSCTRL_ENABLE);
+	tw32(SNDDATAI_STATSENAB, 0xffffff);
+	tw32(SNDDATAI_STATSCTRL,
+	     (SNDDATAI_SCTRL_ENABLE |
+	      SNDDATAI_SCTRL_FASTUPD));
+
+	/* Setup host coalescing engine. */
+	tw32(HOSTCC_MODE, 0);
+	for (i = 0; i < 2000; i++) {
+		if (!(tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE))
+			break;
+		udelay(10);
+	}
+
+	__tg3_set_coalesce(tp);
+
+	if (!tg3_flag(tp, 5705_PLUS)) {
+		/* Status/statistics block address.  See tg3_timer,
+		 * the tg3_periodic_fetch_stats call there, and
+		 * tg3_get_stats to see how this works for 5705/5750 chips.
+		 * NOTE: stats block removed for iPXE
+		 */
+		tw32(HOSTCC_STATUS_BLK_NIC_ADDR, NIC_SRAM_STATUS_BLK);
+
+		/* Clear statistics and status block memory areas */
+		for (i = NIC_SRAM_STATS_BLK;
+		     i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE;
+		     i += sizeof(u32)) {
+			tg3_write_mem(tp, i, 0);
+			udelay(40);
+		}
+	}
+
+	tw32(HOSTCC_MODE, HOSTCC_MODE_ENABLE | tp->coalesce_mode);
+
+	tw32(RCVCC_MODE, RCVCC_MODE_ENABLE | RCVCC_MODE_ATTN_ENABLE);
+	tw32(RCVLPC_MODE, RCVLPC_MODE_ENABLE);
+	if (!tg3_flag(tp, 5705_PLUS))
+		tw32(RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE);
+
+	if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) {
+		tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
+		/* reset to prevent losing 1st rx packet intermittently */
+		tw32_f(MAC_RX_MODE, RX_MODE_RESET);
+		udelay(10);
+	}
+
+	if (tg3_flag(tp, ENABLE_APE))
+		tp->mac_mode = MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
+	else
+		tp->mac_mode = 0;
+	tp->mac_mode |= MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
+		MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE;
+	if (!tg3_flag(tp, 5705_PLUS) &&
+	    !(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700)
+		tp->mac_mode |= MAC_MODE_LINK_POLARITY;
+	tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR);
+	udelay(40);
+
+	/* tp->grc_local_ctrl is partially set up during tg3_get_invariants().
+	 * If TG3_FLAG_IS_NIC is zero, we should read the
+	 * register to preserve the GPIO settings for LOMs. The GPIOs,
+	 * whether used as inputs or outputs, are set by boot code after
+	 * reset.
+	 */
+	if (!tg3_flag(tp, IS_NIC)) {
+		u32 gpio_mask;
+
+		gpio_mask = GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 |
+			    GRC_LCLCTRL_GPIO_OE2 | GRC_LCLCTRL_GPIO_OUTPUT0 |
+			    GRC_LCLCTRL_GPIO_OUTPUT1 | GRC_LCLCTRL_GPIO_OUTPUT2;
+
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
+			gpio_mask |= GRC_LCLCTRL_GPIO_OE3 |
+				     GRC_LCLCTRL_GPIO_OUTPUT3;
+
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
+			gpio_mask |= GRC_LCLCTRL_GPIO_UART_SEL;
+
+		tp->grc_local_ctrl &= ~gpio_mask;
+		tp->grc_local_ctrl |= tr32(GRC_LOCAL_CTRL) & gpio_mask;
+
+		/* GPIO1 must be driven high for eeprom write protect */
+		if (tg3_flag(tp, EEPROM_WRITE_PROT))
+			tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 |
+					       GRC_LCLCTRL_GPIO_OUTPUT1);
+	}
+	tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
+	udelay(100);
+
+	if (!tg3_flag(tp, 5705_PLUS)) {
+		tw32_f(DMAC_MODE, DMAC_MODE_ENABLE);
+		udelay(40);
+	}
+
+	val = (WDMAC_MODE_ENABLE | WDMAC_MODE_TGTABORT_ENAB |
+	       WDMAC_MODE_MSTABORT_ENAB | WDMAC_MODE_PARITYERR_ENAB |
+	       WDMAC_MODE_ADDROFLOW_ENAB | WDMAC_MODE_FIFOOFLOW_ENAB |
+	       WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB |
+	       WDMAC_MODE_LNGREAD_ENAB);
+
+	/* Enable host coalescing bug fix */
+	if (tg3_flag(tp, 5755_PLUS))
+		val |= WDMAC_MODE_STATUS_TAG_FIX;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+		val |= WDMAC_MODE_BURST_ALL_DATA;
+
+	tw32_f(WDMAC_MODE, val);
+	udelay(40);
+
+	if (tg3_flag(tp, PCIX_MODE)) {
+		u16 pcix_cmd;
+
+		pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+				     &pcix_cmd);
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
+			pcix_cmd &= ~PCI_X_CMD_MAX_READ;
+			pcix_cmd |= PCI_X_CMD_READ_2K;
+		} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+			pcix_cmd &= ~(PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ);
+			pcix_cmd |= PCI_X_CMD_READ_2K;
+		}
+		pci_write_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+				      pcix_cmd);
+	}
+
+	tw32_f(RDMAC_MODE, rdmac_mode);
+	udelay(40);
+
+	tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE);
+	if (!tg3_flag(tp, 5705_PLUS))
+		tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+		tw32(SNDDATAC_MODE,
+		     SNDDATAC_MODE_ENABLE | SNDDATAC_MODE_CDELAY);
+	else
+		tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
+
+	tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE);
+	tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB);
+	val = RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ;
+	if (tg3_flag(tp, LRG_PROD_RING_CAP))
+		val |= RCVDBDI_MODE_LRG_RING_SZ;
+	tw32(RCVDBDI_MODE, val);
+	tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
+
+	val = SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE;
+	if (tg3_flag(tp, ENABLE_TSS))
+		val |= SNDBDI_MODE_MULTI_TXQ_EN;
+	tw32(SNDBDI_MODE, val);
+	tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE);
+
+
+	/* FIXME: 5701 firmware fix? */
+#if 0
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) {
+		err = tg3_load_5701_a0_firmware_fix(tp);
+		if (err)
+			return err;
+	}
+#endif
+
+	tp->tx_mode = TX_MODE_ENABLE;
+
+	if (tg3_flag(tp, 5755_PLUS) ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+		tp->tx_mode |= TX_MODE_MBUF_LOCKUP_FIX;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
+		val = TX_MODE_JMB_FRM_LEN | TX_MODE_CNT_DN_MODE;
+		tp->tx_mode &= ~val;
+		tp->tx_mode |= tr32(MAC_TX_MODE) & val;
+	}
+
+	tw32_f(MAC_TX_MODE, tp->tx_mode);
+	udelay(100);
+
+	tp->rx_mode = RX_MODE_ENABLE;
+
+	tw32_f(MAC_RX_MODE, tp->rx_mode);
+	udelay(10);
+
+	tw32(MAC_LED_CTRL, tp->led_ctrl);
+
+	tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
+	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
+		tw32_f(MAC_RX_MODE, RX_MODE_RESET);
+		udelay(10);
+	}
+	tw32_f(MAC_RX_MODE, tp->rx_mode);
+	udelay(10);
+
+	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
+		if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) &&
+			!(tp->phy_flags & TG3_PHYFLG_SERDES_PREEMPHASIS)) {
+			/* Set drive transmission level to 1.2V  */
+			/* only if the signal pre-emphasis bit is not set  */
+			val = tr32(MAC_SERDES_CFG);
+			val &= 0xfffff000;
+			val |= 0x880;
+			tw32(MAC_SERDES_CFG, val);
+		}
+		if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1)
+			tw32(MAC_SERDES_CFG, 0x616000);
+	}
+
+	/* Prevent chip from dropping frames when flow control
+	 * is enabled.
+	 */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
+		val = 1;
+	else
+		val = 2;
+	tw32_f(MAC_LOW_WMARK_MAX_RX_FRAME, val);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
+	    (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) {
+		/* Use hardware link auto-negotiation */
+		tg3_flag_set(tp, HW_AUTONEG);
+	}
+
+	if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
+		u32 tmp;
+
+		tmp = tr32(SERDES_RX_CTRL);
+		tw32(SERDES_RX_CTRL, tmp | SERDES_RX_SIG_DETECT);
+		tp->grc_local_ctrl &= ~GRC_LCLCTRL_USE_EXT_SIG_DETECT;
+		tp->grc_local_ctrl |= GRC_LCLCTRL_USE_SIG_DETECT;
+		tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
+	}
+
+	err = tg3_setup_phy(tp, 0);
+	if (err)
+		return err;
+
+	if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
+	    !(tp->phy_flags & TG3_PHYFLG_IS_FET)) {
+		u32 tmp;
+
+		/* Clear CRC stats. */
+		if (!tg3_readphy(tp, MII_TG3_TEST1, &tmp)) {
+			tg3_writephy(tp, MII_TG3_TEST1,
+				     tmp | MII_TG3_TEST1_CRC_EN);
+			tg3_readphy(tp, MII_TG3_RXR_COUNTERS, &tmp);
+		}
+	}
+
+	__tg3_set_rx_mode(tp->dev);
+
+	/* Initialize receive rules. */
+	tw32(MAC_RCV_RULE_0,  0xc2000000 & RCV_RULE_DISABLE_MASK);
+	tw32(MAC_RCV_VALUE_0, 0xffffffff & RCV_RULE_DISABLE_MASK);
+	tw32(MAC_RCV_RULE_1,  0x86000004 & RCV_RULE_DISABLE_MASK);
+	tw32(MAC_RCV_VALUE_1, 0xffffffff & RCV_RULE_DISABLE_MASK);
+
+	if (tg3_flag(tp, 5705_PLUS) && !tg3_flag(tp, 5780_CLASS))
+		limit = 8;
+	else
+		limit = 16;
+	if (tg3_flag(tp, ENABLE_ASF))
+		limit -= 4;
+	switch (limit) {
+	case 16:
+		tw32(MAC_RCV_RULE_15,  0); tw32(MAC_RCV_VALUE_15,  0);
+	case 15:
+		tw32(MAC_RCV_RULE_14,  0); tw32(MAC_RCV_VALUE_14,  0);
+	case 14:
+		tw32(MAC_RCV_RULE_13,  0); tw32(MAC_RCV_VALUE_13,  0);
+	case 13:
+		tw32(MAC_RCV_RULE_12,  0); tw32(MAC_RCV_VALUE_12,  0);
+	case 12:
+		tw32(MAC_RCV_RULE_11,  0); tw32(MAC_RCV_VALUE_11,  0);
+	case 11:
+		tw32(MAC_RCV_RULE_10,  0); tw32(MAC_RCV_VALUE_10,  0);
+	case 10:
+		tw32(MAC_RCV_RULE_9,  0); tw32(MAC_RCV_VALUE_9,  0);
+	case 9:
+		tw32(MAC_RCV_RULE_8,  0); tw32(MAC_RCV_VALUE_8,  0);
+	case 8:
+		tw32(MAC_RCV_RULE_7,  0); tw32(MAC_RCV_VALUE_7,  0);
+	case 7:
+		tw32(MAC_RCV_RULE_6,  0); tw32(MAC_RCV_VALUE_6,  0);
+	case 6:
+		tw32(MAC_RCV_RULE_5,  0); tw32(MAC_RCV_VALUE_5,  0);
+	case 5:
+		tw32(MAC_RCV_RULE_4,  0); tw32(MAC_RCV_VALUE_4,  0);
+	case 4:
+		/* tw32(MAC_RCV_RULE_3,  0); tw32(MAC_RCV_VALUE_3,  0); */
+	case 3:
+		/* tw32(MAC_RCV_RULE_2,  0); tw32(MAC_RCV_VALUE_2,  0); */
+	case 2:
+	case 1:
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/* Called at device open time to get the chip ready for
+ * packet processing.  Invoked with tp->lock held.
+ */
+int tg3_init_hw(struct tg3 *tp, int reset_phy)
+{	DBGP("%s\n", __func__);
+
+	tg3_switch_clocks(tp);
+
+	tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
+
+	return tg3_reset_hw(tp, reset_phy);
+}
+
+void tg3_set_txd(struct tg3 *tp, int entry,
+			dma_addr_t mapping, int len, u32 flags)
+{	DBGP("%s\n", __func__);
+
+	struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry];
+
+	txd->addr_hi = ((u64) mapping >> 32);
+	txd->addr_lo = ((u64) mapping & 0xffffffff);
+	txd->len_flags = (len << TXD_LEN_SHIFT) | flags;
+	txd->vlan_tag = 0;
+}
+
+int tg3_do_test_dma(struct tg3 *tp, u32 __unused *buf, dma_addr_t buf_dma, int size, int to_device)
+{	DBGP("%s\n", __func__);
+
+	struct tg3_internal_buffer_desc test_desc;
+	u32 sram_dma_descs;
+	int ret;
+	unsigned int i;
+
+	sram_dma_descs = NIC_SRAM_DMA_DESC_POOL_BASE;
+
+	tw32(FTQ_RCVBD_COMP_FIFO_ENQDEQ, 0);
+	tw32(FTQ_RCVDATA_COMP_FIFO_ENQDEQ, 0);
+	tw32(RDMAC_STATUS, 0);
+	tw32(WDMAC_STATUS, 0);
+
+	tw32(BUFMGR_MODE, 0);
+	tw32(FTQ_RESET, 0);
+
+	test_desc.addr_hi = ((u64) buf_dma) >> 32;
+	test_desc.addr_lo = buf_dma & 0xffffffff;
+	test_desc.nic_mbuf = 0x00002100;
+	test_desc.len = size;
+
+	/*
+	 * HP ZX1 was seeing test failures for 5701 cards running at 33Mhz
+	 * the *second* time the tg3 driver was getting loaded after an
+	 * initial scan.
+	 *
+	 * Broadcom tells me:
+	 *   ...the DMA engine is connected to the GRC block and a DMA
+	 *   reset may affect the GRC block in some unpredictable way...
+	 *   The behavior of resets to individual blocks has not been tested.
+	 *
+	 * Broadcom noted the GRC reset will also reset all sub-components.
+	 */
+	if (to_device) {
+		test_desc.cqid_sqid = (13 << 8) | 2;
+
+		tw32_f(RDMAC_MODE, RDMAC_MODE_ENABLE);
+		udelay(40);
+	} else {
+		test_desc.cqid_sqid = (16 << 8) | 7;
+
+		tw32_f(WDMAC_MODE, WDMAC_MODE_ENABLE);
+		udelay(40);
+	}
+	test_desc.flags = 0x00000005;
+
+	for (i = 0; i < (sizeof(test_desc) / sizeof(u32)); i++) {
+		u32 val;
+
+		val = *(((u32 *)&test_desc) + i);
+		pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR,
+				       sram_dma_descs + (i * sizeof(u32)));
+		pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
+	}
+	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+
+	if (to_device)
+		tw32(FTQ_DMA_HIGH_READ_FIFO_ENQDEQ, sram_dma_descs);
+	else
+		tw32(FTQ_DMA_HIGH_WRITE_FIFO_ENQDEQ, sram_dma_descs);
+
+	ret = -ENODEV;
+	for (i = 0; i < 40; i++) {
+		u32 val;
+
+		if (to_device)
+			val = tr32(FTQ_RCVBD_COMP_FIFO_ENQDEQ);
+		else
+			val = tr32(FTQ_RCVDATA_COMP_FIFO_ENQDEQ);
+		if ((val & 0xffff) == sram_dma_descs) {
+			ret = 0;
+			break;
+		}
+
+		udelay(100);
+	}
+
+	return ret;
+}
diff --git a/roms/ipxe/src/drivers/net/tg3/tg3_phy.c b/roms/ipxe/src/drivers/net/tg3/tg3_phy.c
new file mode 100644
index 0000000000000000000000000000000000000000..65dea7e662cc4e224f7cb1cb360a0f5944cfc4de
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/tg3/tg3_phy.c
@@ -0,0 +1,1603 @@
+
+#include <mii.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <ipxe/pci.h>
+
+#include "tg3.h"
+
+static void tg3_link_report(struct tg3 *tp);
+
+void tg3_mdio_init(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	if (tg3_flag(tp, 5717_PLUS)) {
+		u32 is_serdes;
+
+		tp->phy_addr = PCI_FUNC(tp->pdev->busdevfn) + 1;
+
+		if (tp->pci_chip_rev_id != CHIPREV_ID_5717_A0)
+			is_serdes = tr32(SG_DIG_STATUS) & SG_DIG_IS_SERDES;
+		else
+			is_serdes = tr32(TG3_CPMU_PHY_STRAP) &
+				    TG3_CPMU_PHY_STRAP_IS_SERDES;
+		if (is_serdes)
+			tp->phy_addr += 7;
+	} else
+		tp->phy_addr = TG3_PHY_MII_ADDR;
+}
+
+static int tg3_issue_otp_command(struct tg3 *tp, u32 cmd)
+{	DBGP("%s\n", __func__);
+
+	int i;
+	u32 val;
+
+	tw32(OTP_CTRL, cmd | OTP_CTRL_OTP_CMD_START);
+	tw32(OTP_CTRL, cmd);
+
+	/* Wait for up to 1 ms for command to execute. */
+	for (i = 0; i < 100; i++) {
+		val = tr32(OTP_STATUS);
+		if (val & OTP_STATUS_CMD_DONE)
+			break;
+		udelay(10);
+	}
+
+	return (val & OTP_STATUS_CMD_DONE) ? 0 : -EBUSY;
+}
+
+/* Read the gphy configuration from the OTP region of the chip.  The gphy
+ * configuration is a 32-bit value that straddles the alignment boundary.
+ * We do two 32-bit reads and then shift and merge the results.
+ */
+u32 tg3_read_otp_phycfg(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	u32 bhalf_otp, thalf_otp;
+
+	tw32(OTP_MODE, OTP_MODE_OTP_THRU_GRC);
+
+	if (tg3_issue_otp_command(tp, OTP_CTRL_OTP_CMD_INIT))
+		return 0;
+
+	tw32(OTP_ADDRESS, OTP_ADDRESS_MAGIC1);
+
+	if (tg3_issue_otp_command(tp, OTP_CTRL_OTP_CMD_READ))
+		return 0;
+
+	thalf_otp = tr32(OTP_READ_DATA);
+
+	tw32(OTP_ADDRESS, OTP_ADDRESS_MAGIC2);
+
+	if (tg3_issue_otp_command(tp, OTP_CTRL_OTP_CMD_READ))
+		return 0;
+
+	bhalf_otp = tr32(OTP_READ_DATA);
+
+	return ((thalf_otp & 0x0000ffff) << 16) | (bhalf_otp >> 16);
+}
+
+#define PHY_BUSY_LOOPS	5000
+
+int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
+{	DBGP("%s\n", __func__);
+
+	u32 frame_val;
+	unsigned int loops;
+	int ret;
+
+	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
+		tw32_f(MAC_MI_MODE,
+		     (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));
+		udelay(80);
+	}
+
+	*val = 0x0;
+
+	frame_val  = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) &
+		      MI_COM_PHY_ADDR_MASK);
+	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
+		      MI_COM_REG_ADDR_MASK);
+	frame_val |= (MI_COM_CMD_READ | MI_COM_START);
+
+	tw32_f(MAC_MI_COM, frame_val);
+
+	loops = PHY_BUSY_LOOPS;
+	while (loops != 0) {
+		udelay(10);
+		frame_val = tr32(MAC_MI_COM);
+
+		if ((frame_val & MI_COM_BUSY) == 0) {
+			udelay(5);
+			frame_val = tr32(MAC_MI_COM);
+			break;
+		}
+		loops -= 1;
+	}
+
+	ret = -EBUSY;
+	if (loops != 0) {
+		*val = frame_val & MI_COM_DATA_MASK;
+		ret = 0;
+	}
+
+	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
+		tw32_f(MAC_MI_MODE, tp->mi_mode);
+		udelay(80);
+	}
+
+	return ret;
+}
+
+struct subsys_tbl_ent {
+	u16 subsys_vendor, subsys_devid;
+	u32 phy_id;
+};
+
+static struct subsys_tbl_ent subsys_id_to_phy_id[] = {
+	/* Broadcom boards. */
+	{ TG3PCI_SUBVENDOR_ID_BROADCOM,
+	  TG3PCI_SUBDEVICE_ID_BROADCOM_95700A6, TG3_PHY_ID_BCM5401 },
+	{ TG3PCI_SUBVENDOR_ID_BROADCOM,
+	  TG3PCI_SUBDEVICE_ID_BROADCOM_95701A5, TG3_PHY_ID_BCM5701 },
+	{ TG3PCI_SUBVENDOR_ID_BROADCOM,
+	  TG3PCI_SUBDEVICE_ID_BROADCOM_95700T6, TG3_PHY_ID_BCM8002 },
+	{ TG3PCI_SUBVENDOR_ID_BROADCOM,
+	  TG3PCI_SUBDEVICE_ID_BROADCOM_95700A9, 0 },
+	{ TG3PCI_SUBVENDOR_ID_BROADCOM,
+	  TG3PCI_SUBDEVICE_ID_BROADCOM_95701T1, TG3_PHY_ID_BCM5701 },
+	{ TG3PCI_SUBVENDOR_ID_BROADCOM,
+	  TG3PCI_SUBDEVICE_ID_BROADCOM_95701T8, TG3_PHY_ID_BCM5701 },
+	{ TG3PCI_SUBVENDOR_ID_BROADCOM,
+	  TG3PCI_SUBDEVICE_ID_BROADCOM_95701A7, 0 },
+	{ TG3PCI_SUBVENDOR_ID_BROADCOM,
+	  TG3PCI_SUBDEVICE_ID_BROADCOM_95701A10, TG3_PHY_ID_BCM5701 },
+	{ TG3PCI_SUBVENDOR_ID_BROADCOM,
+	  TG3PCI_SUBDEVICE_ID_BROADCOM_95701A12, TG3_PHY_ID_BCM5701 },
+	{ TG3PCI_SUBVENDOR_ID_BROADCOM,
+	  TG3PCI_SUBDEVICE_ID_BROADCOM_95703AX1, TG3_PHY_ID_BCM5703 },
+	{ TG3PCI_SUBVENDOR_ID_BROADCOM,
+	  TG3PCI_SUBDEVICE_ID_BROADCOM_95703AX2, TG3_PHY_ID_BCM5703 },
+
+	/* 3com boards. */
+	{ TG3PCI_SUBVENDOR_ID_3COM,
+	  TG3PCI_SUBDEVICE_ID_3COM_3C996T, TG3_PHY_ID_BCM5401 },
+	{ TG3PCI_SUBVENDOR_ID_3COM,
+	  TG3PCI_SUBDEVICE_ID_3COM_3C996BT, TG3_PHY_ID_BCM5701 },
+	{ TG3PCI_SUBVENDOR_ID_3COM,
+	  TG3PCI_SUBDEVICE_ID_3COM_3C996SX, 0 },
+	{ TG3PCI_SUBVENDOR_ID_3COM,
+	  TG3PCI_SUBDEVICE_ID_3COM_3C1000T, TG3_PHY_ID_BCM5701 },
+	{ TG3PCI_SUBVENDOR_ID_3COM,
+	  TG3PCI_SUBDEVICE_ID_3COM_3C940BR01, TG3_PHY_ID_BCM5701 },
+
+	/* DELL boards. */
+	{ TG3PCI_SUBVENDOR_ID_DELL,
+	  TG3PCI_SUBDEVICE_ID_DELL_VIPER, TG3_PHY_ID_BCM5401 },
+	{ TG3PCI_SUBVENDOR_ID_DELL,
+	  TG3PCI_SUBDEVICE_ID_DELL_JAGUAR, TG3_PHY_ID_BCM5401 },
+	{ TG3PCI_SUBVENDOR_ID_DELL,
+	  TG3PCI_SUBDEVICE_ID_DELL_MERLOT, TG3_PHY_ID_BCM5411 },
+	{ TG3PCI_SUBVENDOR_ID_DELL,
+	  TG3PCI_SUBDEVICE_ID_DELL_SLIM_MERLOT, TG3_PHY_ID_BCM5411 },
+
+	/* Compaq boards. */
+	{ TG3PCI_SUBVENDOR_ID_COMPAQ,
+	  TG3PCI_SUBDEVICE_ID_COMPAQ_BANSHEE, TG3_PHY_ID_BCM5701 },
+	{ TG3PCI_SUBVENDOR_ID_COMPAQ,
+	  TG3PCI_SUBDEVICE_ID_COMPAQ_BANSHEE_2, TG3_PHY_ID_BCM5701 },
+	{ TG3PCI_SUBVENDOR_ID_COMPAQ,
+	  TG3PCI_SUBDEVICE_ID_COMPAQ_CHANGELING, 0 },
+	{ TG3PCI_SUBVENDOR_ID_COMPAQ,
+	  TG3PCI_SUBDEVICE_ID_COMPAQ_NC7780, TG3_PHY_ID_BCM5701 },
+	{ TG3PCI_SUBVENDOR_ID_COMPAQ,
+	  TG3PCI_SUBDEVICE_ID_COMPAQ_NC7780_2, TG3_PHY_ID_BCM5701 },
+
+	/* IBM boards. */
+	{ TG3PCI_SUBVENDOR_ID_IBM,
+	  TG3PCI_SUBDEVICE_ID_IBM_5703SAX2, 0 }
+};
+
+static struct subsys_tbl_ent *tg3_lookup_by_subsys(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	int i;
+
+	DBGC(tp->dev, "Matching with: %x:%x\n", tp->subsystem_vendor, tp->subsystem_device);
+
+	for (i = 0; i < (int) ARRAY_SIZE(subsys_id_to_phy_id); i++) {
+		if ((subsys_id_to_phy_id[i].subsys_vendor ==
+		     tp->subsystem_vendor) &&
+		    (subsys_id_to_phy_id[i].subsys_devid ==
+		     tp->subsystem_device))
+			return &subsys_id_to_phy_id[i];
+	}
+	return NULL;
+}
+
+int tg3_writephy(struct tg3 *tp, int reg, u32 val)
+{	DBGP("%s\n", __func__);
+
+	u32 frame_val;
+	unsigned int loops;
+	int ret;
+
+	if ((tp->phy_flags & TG3_PHYFLG_IS_FET) &&
+	    (reg == MII_TG3_CTRL || reg == MII_TG3_AUX_CTRL))
+		return 0;
+
+	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
+		tw32_f(MAC_MI_MODE,
+		     (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));
+		udelay(80);
+	}
+
+	frame_val  = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) &
+		      MI_COM_PHY_ADDR_MASK);
+	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
+		      MI_COM_REG_ADDR_MASK);
+	frame_val |= (val & MI_COM_DATA_MASK);
+	frame_val |= (MI_COM_CMD_WRITE | MI_COM_START);
+
+	tw32_f(MAC_MI_COM, frame_val);
+
+	loops = PHY_BUSY_LOOPS;
+	while (loops != 0) {
+		udelay(10);
+		frame_val = tr32(MAC_MI_COM);
+		if ((frame_val & MI_COM_BUSY) == 0) {
+			udelay(5);
+			frame_val = tr32(MAC_MI_COM);
+			break;
+		}
+		loops -= 1;
+	}
+
+	ret = -EBUSY;
+	if (loops != 0)
+		ret = 0;
+
+	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
+		tw32_f(MAC_MI_MODE, tp->mi_mode);
+		udelay(80);
+	}
+
+	return ret;
+}
+
+static int tg3_bmcr_reset(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	u32 phy_control;
+	int limit, err;
+
+	/* OK, reset it, and poll the BMCR_RESET bit until it
+	 * clears or we time out.
+	 */
+	phy_control = BMCR_RESET;
+	err = tg3_writephy(tp, MII_BMCR, phy_control);
+	if (err != 0)
+		return -EBUSY;
+
+	limit = 5000;
+	while (limit--) {
+		err = tg3_readphy(tp, MII_BMCR, &phy_control);
+		if (err != 0)
+			return -EBUSY;
+
+		if ((phy_control & BMCR_RESET) == 0) {
+			udelay(40);
+			break;
+		}
+		udelay(10);
+	}
+	if (limit < 0)
+		return -EBUSY;
+
+	return 0;
+}
+
+static int tg3_wait_macro_done(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	int limit = 100;
+
+	while (limit--) {
+		u32 tmp32;
+
+		if (!tg3_readphy(tp, MII_TG3_DSP_CONTROL, &tmp32)) {
+			if ((tmp32 & 0x1000) == 0)
+				break;
+		}
+	}
+	if (limit < 0)
+		return -EBUSY;
+
+	return 0;
+}
+
+static int tg3_phy_write_and_check_testpat(struct tg3 *tp, int *resetp)
+{	DBGP("%s\n", __func__);
+
+	static const u32 test_pat[4][6] = {
+	{ 0x00005555, 0x00000005, 0x00002aaa, 0x0000000a, 0x00003456, 0x00000003 },
+	{ 0x00002aaa, 0x0000000a, 0x00003333, 0x00000003, 0x0000789a, 0x00000005 },
+	{ 0x00005a5a, 0x00000005, 0x00002a6a, 0x0000000a, 0x00001bcd, 0x00000003 },
+	{ 0x00002a5a, 0x0000000a, 0x000033c3, 0x00000003, 0x00002ef1, 0x00000005 }
+	};
+	int chan;
+
+	for (chan = 0; chan < 4; chan++) {
+		int i;
+
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
+			     (chan * 0x2000) | 0x0200);
+		tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0002);
+
+		for (i = 0; i < 6; i++)
+			tg3_writephy(tp, MII_TG3_DSP_RW_PORT,
+				     test_pat[chan][i]);
+
+		tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0202);
+		if (tg3_wait_macro_done(tp)) {
+			*resetp = 1;
+			return -EBUSY;
+		}
+
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
+			     (chan * 0x2000) | 0x0200);
+		tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0082);
+		if (tg3_wait_macro_done(tp)) {
+			*resetp = 1;
+			return -EBUSY;
+		}
+
+		tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0802);
+		if (tg3_wait_macro_done(tp)) {
+			*resetp = 1;
+			return -EBUSY;
+		}
+
+		for (i = 0; i < 6; i += 2) {
+			u32 low, high;
+
+			if (tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &low) ||
+			    tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &high) ||
+			    tg3_wait_macro_done(tp)) {
+				*resetp = 1;
+				return -EBUSY;
+			}
+			low &= 0x7fff;
+			high &= 0x000f;
+			if (low != test_pat[chan][i] ||
+			    high != test_pat[chan][i+1]) {
+				tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000b);
+				tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4001);
+				tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4005);
+
+				return -EBUSY;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int tg3_phy_reset_chanpat(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	int chan;
+
+	for (chan = 0; chan < 4; chan++) {
+		int i;
+
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS,
+			     (chan * 0x2000) | 0x0200);
+		tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0002);
+		for (i = 0; i < 6; i++)
+			tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x000);
+		tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0202);
+		if (tg3_wait_macro_done(tp))
+			return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val)
+{	DBGP("%s\n", __func__);
+
+	int err;
+
+	err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg);
+	if (!err)
+		err = tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val);
+
+	return err;
+}
+
+static int tg3_phy_auxctl_write(struct tg3 *tp, int reg, u32 set)
+{	DBGP("%s\n", __func__);
+
+	if (reg == MII_TG3_AUXCTL_SHDWSEL_MISC)
+		set |= MII_TG3_AUXCTL_MISC_WREN;
+
+	return tg3_writephy(tp, MII_TG3_AUX_CTRL, set | reg);
+}
+
+#define TG3_PHY_AUXCTL_SMDSP_ENABLE(tp) \
+	tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, \
+			     MII_TG3_AUXCTL_ACTL_SMDSP_ENA | \
+			     MII_TG3_AUXCTL_ACTL_TX_6DB)
+
+#define TG3_PHY_AUXCTL_SMDSP_DISABLE(tp) \
+	tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, \
+			     MII_TG3_AUXCTL_ACTL_TX_6DB);
+
+static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	u32 reg32, phy9_orig;
+	int retries, do_phy_reset, err;
+
+	retries = 10;
+	do_phy_reset = 1;
+	do {
+		if (do_phy_reset) {
+			err = tg3_bmcr_reset(tp);
+			if (err)
+				return err;
+			do_phy_reset = 0;
+		}
+
+		/* Disable transmitter and interrupt.  */
+		if (tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32))
+			continue;
+
+		reg32 |= 0x3000;
+		tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
+
+		/* Set full-duplex, 1000 mbps.  */
+		tg3_writephy(tp, MII_BMCR,
+			     BMCR_FULLDPLX | TG3_BMCR_SPEED1000);
+
+		/* Set to master mode.  */
+		if (tg3_readphy(tp, MII_TG3_CTRL, &phy9_orig))
+			continue;
+
+		tg3_writephy(tp, MII_TG3_CTRL,
+			     (MII_TG3_CTRL_AS_MASTER |
+			      MII_TG3_CTRL_ENABLE_AS_MASTER));
+
+		err = TG3_PHY_AUXCTL_SMDSP_ENABLE(tp);
+		if (err)
+			return err;
+
+		/* Block the PHY control access.  */
+		tg3_phydsp_write(tp, 0x8005, 0x0800);
+
+		err = tg3_phy_write_and_check_testpat(tp, &do_phy_reset);
+		if (!err)
+			break;
+	} while (--retries);
+
+	err = tg3_phy_reset_chanpat(tp);
+	if (err)
+		return err;
+
+	tg3_phydsp_write(tp, 0x8005, 0x0000);
+
+	tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200);
+	tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0000);
+
+	TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+
+	tg3_writephy(tp, MII_TG3_CTRL, phy9_orig);
+
+	if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32)) {
+		reg32 &= ~0x3000;
+		tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
+	} else if (!err)
+		err = -EBUSY;
+
+	return err;
+}
+
+static void tg3_phy_apply_otp(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	u32 otp, phy;
+
+	if (!tp->phy_otp)
+		return;
+
+	otp = tp->phy_otp;
+
+	if (TG3_PHY_AUXCTL_SMDSP_ENABLE(tp))
+		return;
+
+	phy = ((otp & TG3_OTP_AGCTGT_MASK) >> TG3_OTP_AGCTGT_SHIFT);
+	phy |= MII_TG3_DSP_TAP1_AGCTGT_DFLT;
+	tg3_phydsp_write(tp, MII_TG3_DSP_TAP1, phy);
+
+	phy = ((otp & TG3_OTP_HPFFLTR_MASK) >> TG3_OTP_HPFFLTR_SHIFT) |
+	      ((otp & TG3_OTP_HPFOVER_MASK) >> TG3_OTP_HPFOVER_SHIFT);
+	tg3_phydsp_write(tp, MII_TG3_DSP_AADJ1CH0, phy);
+
+	phy = ((otp & TG3_OTP_LPFDIS_MASK) >> TG3_OTP_LPFDIS_SHIFT);
+	phy |= MII_TG3_DSP_AADJ1CH3_ADCCKADJ;
+	tg3_phydsp_write(tp, MII_TG3_DSP_AADJ1CH3, phy);
+
+	phy = ((otp & TG3_OTP_VDAC_MASK) >> TG3_OTP_VDAC_SHIFT);
+	tg3_phydsp_write(tp, MII_TG3_DSP_EXP75, phy);
+
+	phy = ((otp & TG3_OTP_10BTAMP_MASK) >> TG3_OTP_10BTAMP_SHIFT);
+	tg3_phydsp_write(tp, MII_TG3_DSP_EXP96, phy);
+
+	phy = ((otp & TG3_OTP_ROFF_MASK) >> TG3_OTP_ROFF_SHIFT) |
+	      ((otp & TG3_OTP_RCOFF_MASK) >> TG3_OTP_RCOFF_SHIFT);
+	tg3_phydsp_write(tp, MII_TG3_DSP_EXP97, phy);
+
+	TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+}
+
+static int tg3_phy_auxctl_read(struct tg3 *tp, int reg, u32 *val)
+{	DBGP("%s\n", __func__);
+
+	int err;
+
+	err = tg3_writephy(tp, MII_TG3_AUX_CTRL,
+			   (reg << MII_TG3_AUXCTL_MISC_RDSEL_SHIFT) |
+			   MII_TG3_AUXCTL_SHDWSEL_MISC);
+	if (!err)
+		err = tg3_readphy(tp, MII_TG3_AUX_CTRL, val);
+
+	return err;
+}
+
+static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable)
+{	DBGP("%s\n", __func__);
+
+	u32 phy;
+
+	if (!tg3_flag(tp, 5705_PLUS) ||
+	    (tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
+		return;
+
+	if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
+		u32 ephy;
+
+		if (!tg3_readphy(tp, MII_TG3_FET_TEST, &ephy)) {
+			u32 reg = MII_TG3_FET_SHDW_MISCCTRL;
+
+			tg3_writephy(tp, MII_TG3_FET_TEST,
+				     ephy | MII_TG3_FET_SHADOW_EN);
+			if (!tg3_readphy(tp, reg, &phy)) {
+				if (enable)
+					phy |= MII_TG3_FET_SHDW_MISCCTRL_MDIX;
+				else
+					phy &= ~MII_TG3_FET_SHDW_MISCCTRL_MDIX;
+				tg3_writephy(tp, reg, phy);
+			}
+			tg3_writephy(tp, MII_TG3_FET_TEST, ephy);
+		}
+	} else {
+		int ret;
+
+		ret = tg3_phy_auxctl_read(tp,
+					  MII_TG3_AUXCTL_SHDWSEL_MISC, &phy);
+		if (!ret) {
+			if (enable)
+				phy |= MII_TG3_AUXCTL_MISC_FORCE_AMDIX;
+			else
+				phy &= ~MII_TG3_AUXCTL_MISC_FORCE_AMDIX;
+			tg3_phy_auxctl_write(tp,
+					     MII_TG3_AUXCTL_SHDWSEL_MISC, phy);
+		}
+	}
+}
+
+static void tg3_phy_set_wirespeed(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	int ret;
+	u32 val;
+
+	if (tp->phy_flags & TG3_PHYFLG_NO_ETH_WIRE_SPEED)
+		return;
+
+	ret = tg3_phy_auxctl_read(tp, MII_TG3_AUXCTL_SHDWSEL_MISC, &val);
+	if (!ret)
+		tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_MISC,
+				     val | MII_TG3_AUXCTL_MISC_WIRESPD_EN);
+}
+
+/* This will reset the tigon3 PHY if there is no valid
+ * link unless the FORCE argument is non-zero.
+ */
+int tg3_phy_reset(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	u32 val, cpmuctrl;
+	int err;
+
+	DBGCP(&tp->pdev->dev, "%s\n", __func__);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+		val = tr32(GRC_MISC_CFG);
+		tw32_f(GRC_MISC_CFG, val & ~GRC_MISC_CFG_EPHY_IDDQ);
+		udelay(40);
+	}
+	err  = tg3_readphy(tp, MII_BMSR, &val);
+	err |= tg3_readphy(tp, MII_BMSR, &val);
+	if (err != 0)
+		return -EBUSY;
+
+	netdev_link_down(tp->dev);
+	tg3_link_report(tp);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+		err = tg3_phy_reset_5703_4_5(tp);
+		if (err)
+			return err;
+		goto out;
+	}
+
+	cpmuctrl = 0;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
+	    GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) {
+		cpmuctrl = tr32(TG3_CPMU_CTRL);
+		if (cpmuctrl & CPMU_CTRL_GPHY_10MB_RXONLY)
+			tw32(TG3_CPMU_CTRL,
+			     cpmuctrl & ~CPMU_CTRL_GPHY_10MB_RXONLY);
+	}
+
+	err = tg3_bmcr_reset(tp);
+	if (err)
+		return err;
+
+	if (cpmuctrl & CPMU_CTRL_GPHY_10MB_RXONLY) {
+		val = MII_TG3_DSP_EXP8_AEDW | MII_TG3_DSP_EXP8_REJ2MHz;
+		tg3_phydsp_write(tp, MII_TG3_DSP_EXP8, val);
+
+		tw32(TG3_CPMU_CTRL, cpmuctrl);
+	}
+
+	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX ||
+	    GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5761_AX) {
+		val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
+		if ((val & CPMU_LSPD_1000MB_MACCLK_MASK) ==
+		    CPMU_LSPD_1000MB_MACCLK_12_5) {
+			val &= ~CPMU_LSPD_1000MB_MACCLK_MASK;
+			udelay(40);
+			tw32_f(TG3_CPMU_LSPD_1000MB_CLK, val);
+		}
+	}
+
+	if (tg3_flag(tp, 5717_PLUS) &&
+	    (tp->phy_flags & TG3_PHYFLG_MII_SERDES))
+		return 0;
+
+	tg3_phy_apply_otp(tp);
+
+out:
+	if ((tp->phy_flags & TG3_PHYFLG_ADC_BUG) &&
+	    !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) {
+		tg3_phydsp_write(tp, 0x201f, 0x2aaa);
+		tg3_phydsp_write(tp, 0x000a, 0x0323);
+		TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+	}
+
+	if (tp->phy_flags & TG3_PHYFLG_5704_A0_BUG) {
+		tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8d68);
+		tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8d68);
+	}
+
+	if (tp->phy_flags & TG3_PHYFLG_BER_BUG) {
+		if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) {
+			tg3_phydsp_write(tp, 0x000a, 0x310b);
+			tg3_phydsp_write(tp, 0x201f, 0x9506);
+			tg3_phydsp_write(tp, 0x401f, 0x14e2);
+			TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+		}
+	} else if (tp->phy_flags & TG3_PHYFLG_JITTER_BUG) {
+		if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) {
+			tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
+			if (tp->phy_flags & TG3_PHYFLG_ADJUST_TRIM) {
+				tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x110b);
+				tg3_writephy(tp, MII_TG3_TEST1,
+					     MII_TG3_TEST1_TRIM_EN | 0x4);
+			} else
+				tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b);
+
+			TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+		}
+	}
+
+	if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) {
+		/* Cannot do read-modify-write on 5401 */
+		tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, 0x4c20);
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+		/* adjust output voltage */
+		tg3_writephy(tp, MII_TG3_FET_PTEST, 0x12);
+	}
+
+	tg3_phy_toggle_automdix(tp, 1);
+	tg3_phy_set_wirespeed(tp);
+	return 0;
+}
+
+static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)
+{	DBGP("%s\n", __func__);
+
+	u32 adv_reg, all_mask = 0;
+
+	if (mask & ADVERTISED_10baseT_Half)
+		all_mask |= ADVERTISE_10HALF;
+	if (mask & ADVERTISED_10baseT_Full)
+		all_mask |= ADVERTISE_10FULL;
+	if (mask & ADVERTISED_100baseT_Half)
+		all_mask |= ADVERTISE_100HALF;
+	if (mask & ADVERTISED_100baseT_Full)
+		all_mask |= ADVERTISE_100FULL;
+
+	if (tg3_readphy(tp, MII_ADVERTISE, &adv_reg))
+		return 0;
+
+	if ((adv_reg & all_mask) != all_mask)
+		return 0;
+	if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
+		u32 tg3_ctrl;
+
+		all_mask = 0;
+		if (mask & ADVERTISED_1000baseT_Half)
+			all_mask |= ADVERTISE_1000HALF;
+		if (mask & ADVERTISED_1000baseT_Full)
+			all_mask |= ADVERTISE_1000FULL;
+
+		if (tg3_readphy(tp, MII_TG3_CTRL, &tg3_ctrl))
+			return 0;
+
+		if ((tg3_ctrl & all_mask) != all_mask)
+			return 0;
+	}
+	return 1;
+}
+
+static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl)
+{	DBGP("%s\n", __func__);
+
+	u16 miireg;
+
+	if ((flow_ctrl & FLOW_CTRL_TX) && (flow_ctrl & FLOW_CTRL_RX))
+		miireg = ADVERTISE_PAUSE_CAP;
+	else if (flow_ctrl & FLOW_CTRL_TX)
+		miireg = ADVERTISE_PAUSE_ASYM;
+	else if (flow_ctrl & FLOW_CTRL_RX)
+		miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+	else
+		miireg = 0;
+
+	return miireg;
+}
+
+static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
+{	DBGP("%s\n", __func__);
+
+	int err = 0;
+	u32 val __unused, new_adv;
+
+	new_adv = ADVERTISE_CSMA;
+	if (advertise & ADVERTISED_10baseT_Half)
+		new_adv |= ADVERTISE_10HALF;
+	if (advertise & ADVERTISED_10baseT_Full)
+		new_adv |= ADVERTISE_10FULL;
+	if (advertise & ADVERTISED_100baseT_Half)
+		new_adv |= ADVERTISE_100HALF;
+	if (advertise & ADVERTISED_100baseT_Full)
+		new_adv |= ADVERTISE_100FULL;
+
+	new_adv |= tg3_advert_flowctrl_1000T(flowctrl);
+
+	err = tg3_writephy(tp, MII_ADVERTISE, new_adv);
+	if (err)
+		goto done;
+
+	if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
+		goto done;
+
+	new_adv = 0;
+	if (advertise & ADVERTISED_1000baseT_Half)
+		new_adv |= MII_TG3_CTRL_ADV_1000_HALF;
+	if (advertise & ADVERTISED_1000baseT_Full)
+		new_adv |= MII_TG3_CTRL_ADV_1000_FULL;
+
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
+	    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
+		new_adv |= (MII_TG3_CTRL_AS_MASTER |
+			    MII_TG3_CTRL_ENABLE_AS_MASTER);
+
+	err = tg3_writephy(tp, MII_TG3_CTRL, new_adv);
+	if (err)
+		goto done;
+
+	if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP))
+		goto done;
+
+done:
+	return err;
+}
+
+static int tg3_init_5401phy_dsp(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	int err;
+
+	/* Turn off tap power management. */
+	/* Set Extended packet length bit */
+	err = tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, 0x4c20);
+
+	err |= tg3_phydsp_write(tp, 0x0012, 0x1804);
+	err |= tg3_phydsp_write(tp, 0x0013, 0x1204);
+	err |= tg3_phydsp_write(tp, 0x8006, 0x0132);
+	err |= tg3_phydsp_write(tp, 0x8006, 0x0232);
+	err |= tg3_phydsp_write(tp, 0x201f, 0x0a20);
+
+	udelay(40);
+
+	return err;
+}
+
+#define ADVERTISED_Autoneg              (1 << 6)
+#define ADVERTISED_Pause                (1 << 13)
+#define ADVERTISED_TP                   (1 << 7)
+#define ADVERTISED_FIBRE                (1 << 10)
+
+#define AUTONEG_ENABLE          0x01
+
+static void tg3_phy_init_link_config(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	u32 adv = ADVERTISED_Autoneg |
+		  ADVERTISED_Pause;
+
+
+	if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY))
+		adv |= ADVERTISED_1000baseT_Half |
+		       ADVERTISED_1000baseT_Full;
+	if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
+		adv |= ADVERTISED_100baseT_Half |
+		       ADVERTISED_100baseT_Full |
+		       ADVERTISED_10baseT_Half |
+		       ADVERTISED_10baseT_Full |
+		       ADVERTISED_TP;
+	else
+		adv |= ADVERTISED_FIBRE;
+
+	tp->link_config.advertising = adv;
+	tp->link_config.speed = SPEED_INVALID;
+	tp->link_config.duplex = DUPLEX_INVALID;
+	tp->link_config.autoneg = AUTONEG_ENABLE;
+	tp->link_config.active_speed = SPEED_INVALID;
+	tp->link_config.active_duplex = DUPLEX_INVALID;
+	tp->link_config.orig_speed = SPEED_INVALID;
+	tp->link_config.orig_duplex = DUPLEX_INVALID;
+	tp->link_config.orig_autoneg = AUTONEG_INVALID;
+}
+
+int tg3_phy_probe(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	u32 hw_phy_id_1, hw_phy_id_2;
+	u32 hw_phy_id, hw_phy_id_masked;
+	int err;
+
+	/* flow control autonegotiation is default behavior */
+	tg3_flag_set(tp, PAUSE_AUTONEG);
+	tp->link_config.flowctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
+
+	/* Reading the PHY ID register can conflict with ASF
+	 * firmware access to the PHY hardware.
+	 */
+	err = 0;
+	if (tg3_flag(tp, ENABLE_ASF) || tg3_flag(tp, ENABLE_APE)) {
+		hw_phy_id = hw_phy_id_masked = TG3_PHY_ID_INVALID;
+	} else {
+		/* Now read the physical PHY_ID from the chip and verify
+		 * that it is sane.  If it doesn't look good, we fall back
+		 * to either the hard-coded table based PHY_ID and failing
+		 * that the value found in the eeprom area.
+		 */
+		err |= tg3_readphy(tp, MII_PHYSID1, &hw_phy_id_1);
+		err |= tg3_readphy(tp, MII_PHYSID2, &hw_phy_id_2);
+
+		hw_phy_id  = (hw_phy_id_1 & 0xffff) << 10;
+		hw_phy_id |= (hw_phy_id_2 & 0xfc00) << 16;
+		hw_phy_id |= (hw_phy_id_2 & 0x03ff) <<  0;
+
+		hw_phy_id_masked = hw_phy_id & TG3_PHY_ID_MASK;
+	}
+
+	if (!err && TG3_KNOWN_PHY_ID(hw_phy_id_masked)) {
+		tp->phy_id = hw_phy_id;
+		if (hw_phy_id_masked == TG3_PHY_ID_BCM8002)
+			tp->phy_flags |= TG3_PHYFLG_PHY_SERDES;
+		else
+			tp->phy_flags &= ~TG3_PHYFLG_PHY_SERDES;
+	} else {
+		if (tp->phy_id != TG3_PHY_ID_INVALID) {
+			/* Do nothing, phy ID already set up in
+			 * tg3_get_eeprom_hw_cfg().
+			 */
+		} else {
+			struct subsys_tbl_ent *p;
+
+			/* No eeprom signature?  Try the hardcoded
+			 * subsys device table.
+			 */
+			p = tg3_lookup_by_subsys(tp);
+			if (!p) {
+				DBGC(&tp->pdev->dev, "lookup by subsys failed\n");
+				return -ENODEV;
+			}
+
+			tp->phy_id = p->phy_id;
+			if (!tp->phy_id ||
+			    tp->phy_id == TG3_PHY_ID_BCM8002)
+				tp->phy_flags |= TG3_PHYFLG_PHY_SERDES;
+		}
+	}
+
+	if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
+	    ((tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 &&
+	      tp->pci_chip_rev_id != CHIPREV_ID_5717_A0) ||
+	     (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
+	      tp->pci_chip_rev_id != CHIPREV_ID_57765_A0)))
+		tp->phy_flags |= TG3_PHYFLG_EEE_CAP;
+
+	tg3_phy_init_link_config(tp);
+
+	if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
+	    !tg3_flag(tp, ENABLE_APE) &&
+	    !tg3_flag(tp, ENABLE_ASF)) {
+		u32 bmsr;
+		u32 mask;
+
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+		if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
+		    (bmsr & BMSR_LSTATUS))
+			goto skip_phy_reset;
+
+		err = tg3_phy_reset(tp);
+		if (err)
+			return err;
+
+		tg3_phy_set_wirespeed(tp);
+
+		mask = (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+			ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
+			ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full);
+		if (!tg3_copper_is_advertising_all(tp, mask)) {
+			tg3_phy_autoneg_cfg(tp, tp->link_config.advertising,
+			                    tp->link_config.flowctrl);
+
+			tg3_writephy(tp, MII_BMCR,
+				     BMCR_ANENABLE | BMCR_ANRESTART);
+		}
+	}
+
+skip_phy_reset:
+	if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) {
+		err = tg3_init_5401phy_dsp(tp);
+		if (err)
+			return err;
+
+		err = tg3_init_5401phy_dsp(tp);
+	}
+
+	return err;
+}
+
+void tg3_poll_link(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	if (tp->hw_status->status & SD_STATUS_LINK_CHG) {
+		DBGC(tp->dev,"link_changed\n");
+		tp->hw_status->status &= ~SD_STATUS_LINK_CHG;
+		tg3_setup_phy(tp, 0);
+	}
+}
+
+static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 *duplex)
+{	DBGP("%s\n", __func__);
+
+	switch (val & MII_TG3_AUX_STAT_SPDMASK) {
+	case MII_TG3_AUX_STAT_10HALF:
+		*speed = SPEED_10;
+		*duplex = DUPLEX_HALF;
+		break;
+
+	case MII_TG3_AUX_STAT_10FULL:
+		*speed = SPEED_10;
+		*duplex = DUPLEX_FULL;
+		break;
+
+	case MII_TG3_AUX_STAT_100HALF:
+		*speed = SPEED_100;
+		*duplex = DUPLEX_HALF;
+		break;
+
+	case MII_TG3_AUX_STAT_100FULL:
+		*speed = SPEED_100;
+		*duplex = DUPLEX_FULL;
+		break;
+
+	case MII_TG3_AUX_STAT_1000HALF:
+		*speed = SPEED_1000;
+		*duplex = DUPLEX_HALF;
+		break;
+
+	case MII_TG3_AUX_STAT_1000FULL:
+		*speed = SPEED_1000;
+		*duplex = DUPLEX_FULL;
+		break;
+
+	default:
+		if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
+			*speed = (val & MII_TG3_AUX_STAT_100) ? SPEED_100 :
+				 SPEED_10;
+			*duplex = (val & MII_TG3_AUX_STAT_FULL) ? DUPLEX_FULL :
+				  DUPLEX_HALF;
+			break;
+		}
+		*speed = SPEED_INVALID;
+		*duplex = DUPLEX_INVALID;
+		break;
+	}
+}
+
+static int tg3_adv_1000T_flowctrl_ok(struct tg3 *tp, u32 *lcladv, u32 *rmtadv)
+{	DBGP("%s\n", __func__);
+
+	u32 curadv, reqadv;
+
+	if (tg3_readphy(tp, MII_ADVERTISE, lcladv))
+		return 1;
+
+	curadv = *lcladv & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+	reqadv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
+
+	if (tp->link_config.active_duplex == DUPLEX_FULL) {
+		if (curadv != reqadv)
+			return 0;
+
+		if (tg3_flag(tp, PAUSE_AUTONEG))
+			tg3_readphy(tp, MII_LPA, rmtadv);
+	} else {
+		/* Reprogram the advertisement register, even if it
+		 * does not affect the current link.  If the link
+		 * gets renegotiated in the future, we can save an
+		 * additional renegotiation cycle by advertising
+		 * it correctly in the first place.
+		 */
+		if (curadv != reqadv) {
+			*lcladv &= ~(ADVERTISE_PAUSE_CAP |
+				     ADVERTISE_PAUSE_ASYM);
+			tg3_writephy(tp, MII_ADVERTISE, *lcladv | reqadv);
+		}
+	}
+
+	return 1;
+}
+
+static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
+{	DBGP("%s\n", __func__);
+
+	u8 cap = 0;
+
+	if (lcladv & ADVERTISE_1000XPAUSE) {
+		if (lcladv & ADVERTISE_1000XPSE_ASYM) {
+			if (rmtadv & LPA_1000XPAUSE)
+				cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
+			else if (rmtadv & LPA_1000XPAUSE_ASYM)
+				cap = FLOW_CTRL_RX;
+		} else {
+			if (rmtadv & LPA_1000XPAUSE)
+				cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
+		}
+	} else if (lcladv & ADVERTISE_1000XPSE_ASYM) {
+		if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM))
+			cap = FLOW_CTRL_TX;
+	}
+
+	return cap;
+}
+
+static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv)
+{	DBGP("%s\n", __func__);
+
+	u8 flowctrl = 0;
+	u32 old_rx_mode = tp->rx_mode;
+	u32 old_tx_mode = tp->tx_mode;
+
+	if (tg3_flag(tp, PAUSE_AUTONEG)) {
+		if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)
+			flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv);
+		else
+			flowctrl = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
+	} else
+		flowctrl = tp->link_config.flowctrl;
+
+	tp->link_config.active_flowctrl = flowctrl;
+
+	if (flowctrl & FLOW_CTRL_RX)
+		tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
+	else
+		tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
+
+	if (old_rx_mode != tp->rx_mode)
+		tw32_f(MAC_RX_MODE, tp->rx_mode);
+
+	if (flowctrl & FLOW_CTRL_TX)
+		tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
+	else
+		tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
+
+	if (old_tx_mode != tp->tx_mode)
+		tw32_f(MAC_TX_MODE, tp->tx_mode);
+}
+
+static void tg3_phy_copper_begin(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	u32 new_adv;
+
+	if (tp->link_config.speed == SPEED_INVALID) {
+		if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
+			tp->link_config.advertising &=
+				~(ADVERTISED_1000baseT_Half |
+				  ADVERTISED_1000baseT_Full);
+
+		tg3_phy_autoneg_cfg(tp, tp->link_config.advertising,
+				    tp->link_config.flowctrl);
+	} else {
+		/* Asking for a specific link mode. */
+		if (tp->link_config.speed == SPEED_1000) {
+			if (tp->link_config.duplex == DUPLEX_FULL)
+				new_adv = ADVERTISED_1000baseT_Full;
+			else
+				new_adv = ADVERTISED_1000baseT_Half;
+		} else if (tp->link_config.speed == SPEED_100) {
+			if (tp->link_config.duplex == DUPLEX_FULL)
+				new_adv = ADVERTISED_100baseT_Full;
+			else
+				new_adv = ADVERTISED_100baseT_Half;
+		} else {
+			if (tp->link_config.duplex == DUPLEX_FULL)
+				new_adv = ADVERTISED_10baseT_Full;
+			else
+				new_adv = ADVERTISED_10baseT_Half;
+		}
+
+		tg3_phy_autoneg_cfg(tp, new_adv,
+				    tp->link_config.flowctrl);
+	}
+
+	tg3_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
+}
+
+static int tg3_5700_link_polarity(struct tg3 *tp, u32 speed)
+{	DBGP("%s\n", __func__);
+
+	if (tp->led_ctrl == LED_CTRL_MODE_PHY_2)
+		return 1;
+	else if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5411) {
+		if (speed != SPEED_10)
+			return 1;
+	} else if (speed == SPEED_10)
+		return 1;
+
+	return 0;
+}
+
+#if 1
+
+static void tg3_ump_link_report(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	u32 reg;
+	u32 val;
+
+	if (!tg3_flag(tp, 5780_CLASS) || !tg3_flag(tp, ENABLE_ASF))
+		return;
+
+	tg3_wait_for_event_ack(tp);
+
+	tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE);
+
+	tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14);
+
+	val = 0;
+	if (!tg3_readphy(tp, MII_BMCR, &reg))
+		val = reg << 16;
+	if (!tg3_readphy(tp, MII_BMSR, &reg))
+		val |= (reg & 0xffff);
+	tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val);
+
+	val = 0;
+	if (!tg3_readphy(tp, MII_ADVERTISE, &reg))
+		val = reg << 16;
+	if (!tg3_readphy(tp, MII_LPA, &reg))
+		val |= (reg & 0xffff);
+	tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val);
+
+	val = 0;
+	if (!(tp->phy_flags & TG3_PHYFLG_MII_SERDES)) {
+		if (!tg3_readphy(tp, MII_CTRL1000, &reg))
+			val = reg << 16;
+		if (!tg3_readphy(tp, MII_STAT1000, &reg))
+			val |= (reg & 0xffff);
+	}
+	tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val);
+
+	if (!tg3_readphy(tp, MII_PHYADDR, &reg))
+		val = reg << 16;
+	else
+		val = 0;
+	tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val);
+
+	tg3_generate_fw_event(tp);
+}
+
+/* NOTE: Debugging only code */
+static void tg3_link_report(struct tg3 *tp)
+{	DBGP("%s\n", __func__);
+
+	if (!netdev_link_ok(tp->dev)) {
+		DBGC(tp->dev, "Link is down\n");
+		tg3_ump_link_report(tp);
+	} else {
+		DBGC(tp->dev, "Link is up at %d Mbps, %s duplex\n",
+			    (tp->link_config.active_speed == SPEED_1000 ?
+			     1000 :
+			     (tp->link_config.active_speed == SPEED_100 ?
+			      100 : 10)),
+			    (tp->link_config.active_duplex == DUPLEX_FULL ?
+			     "full" : "half"));
+
+		DBGC(tp->dev, "Flow control is %s for TX and %s for RX\n",
+			    (tp->link_config.active_flowctrl & FLOW_CTRL_TX) ?
+			    "on" : "off",
+			    (tp->link_config.active_flowctrl & FLOW_CTRL_RX) ?
+			    "on" : "off");
+
+		if (tp->phy_flags & TG3_PHYFLG_EEE_CAP)
+			DBGC(tp->dev, "EEE is %s\n",
+				    tp->setlpicnt ? "enabled" : "disabled");
+
+		tg3_ump_link_report(tp);
+	}
+}
+#endif
+
+static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
+{	DBGP("%s\n", __func__);
+
+	int current_link_up;
+	u32 bmsr, val;
+	u32 lcl_adv, rmt_adv;
+	u16 current_speed;
+	u8 current_duplex;
+	int i, err;
+
+	tw32(MAC_EVENT, 0);
+
+	tw32_f(MAC_STATUS,
+	     (MAC_STATUS_SYNC_CHANGED |
+	      MAC_STATUS_CFG_CHANGED |
+	      MAC_STATUS_MI_COMPLETION |
+	      MAC_STATUS_LNKSTATE_CHANGED));
+	udelay(40);
+
+	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
+		tw32_f(MAC_MI_MODE,
+		     (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));
+		udelay(80);
+	}
+
+	tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_PWRCTL, 0);
+
+	/* Some third-party PHYs need to be reset on link going
+	 * down.
+	 */
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
+	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
+	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
+	    netdev_link_ok(tp->dev)) {
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+		if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
+		    !(bmsr & BMSR_LSTATUS))
+			force_reset = 1;
+	}
+	if (force_reset)
+		tg3_phy_reset(tp);
+
+	if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) {
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+		if (tg3_readphy(tp, MII_BMSR, &bmsr) ||
+		    !tg3_flag(tp, INIT_COMPLETE))
+			bmsr = 0;
+
+		if (!(bmsr & BMSR_LSTATUS)) {
+			err = tg3_init_5401phy_dsp(tp);
+			if (err)
+				return err;
+
+			tg3_readphy(tp, MII_BMSR, &bmsr);
+			for (i = 0; i < 1000; i++) {
+				udelay(10);
+				if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
+				    (bmsr & BMSR_LSTATUS)) {
+					udelay(40);
+					break;
+				}
+			}
+
+			if ((tp->phy_id & TG3_PHY_ID_REV_MASK) ==
+			    TG3_PHY_REV_BCM5401_B0 &&
+			    !(bmsr & BMSR_LSTATUS) &&
+			    tp->link_config.active_speed == SPEED_1000) {
+				err = tg3_phy_reset(tp);
+				if (!err)
+					err = tg3_init_5401phy_dsp(tp);
+				if (err)
+					return err;
+			}
+		}
+	} else if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
+		   tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
+		/* 5701 {A0,B0} CRC bug workaround */
+		tg3_writephy(tp, 0x15, 0x0a75);
+		tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8c68);
+		tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8d68);
+		tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8c68);
+	}
+
+	/* Clear pending interrupts... */
+	tg3_readphy(tp, MII_TG3_ISTAT, &val);
+	tg3_readphy(tp, MII_TG3_ISTAT, &val);
+
+	if (tp->phy_flags & TG3_PHYFLG_USE_MI_INTERRUPT)
+		tg3_writephy(tp, MII_TG3_IMASK, ~MII_TG3_INT_LINKCHG);
+	else if (!(tp->phy_flags & TG3_PHYFLG_IS_FET))
+		tg3_writephy(tp, MII_TG3_IMASK, ~0);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+		if (tp->led_ctrl == LED_CTRL_MODE_PHY_1)
+			tg3_writephy(tp, MII_TG3_EXT_CTRL,
+				     MII_TG3_EXT_CTRL_LNK3_LED_MODE);
+		else
+			tg3_writephy(tp, MII_TG3_EXT_CTRL, 0);
+	}
+
+	current_link_up = 0;
+	current_speed = SPEED_INVALID;
+	current_duplex = DUPLEX_INVALID;
+
+	if (tp->phy_flags & TG3_PHYFLG_CAPACITIVE_COUPLING) {
+		err = tg3_phy_auxctl_read(tp,
+					  MII_TG3_AUXCTL_SHDWSEL_MISCTEST,
+					  &val);
+		if (!err && !(val & (1 << 10))) {
+			tg3_phy_auxctl_write(tp,
+					     MII_TG3_AUXCTL_SHDWSEL_MISCTEST,
+					     val | (1 << 10));
+			goto relink;
+		}
+	}
+
+	bmsr = 0;
+	for (i = 0; i < 100; i++) {
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+		if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
+		    (bmsr & BMSR_LSTATUS))
+			break;
+		udelay(40);
+	}
+
+	if (bmsr & BMSR_LSTATUS) {
+		u32 aux_stat, bmcr;
+
+		tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
+		for (i = 0; i < 2000; i++) {
+			udelay(10);
+			if (!tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat) &&
+			    aux_stat)
+				break;
+		}
+
+		tg3_aux_stat_to_speed_duplex(tp, aux_stat,
+					     &current_speed,
+					     &current_duplex);
+
+		bmcr = 0;
+		for (i = 0; i < 200; i++) {
+			tg3_readphy(tp, MII_BMCR, &bmcr);
+			if (tg3_readphy(tp, MII_BMCR, &bmcr))
+				continue;
+			if (bmcr && bmcr != 0x7fff)
+				break;
+			udelay(10);
+		}
+
+		lcl_adv = 0;
+		rmt_adv = 0;
+
+		tp->link_config.active_speed = current_speed;
+		tp->link_config.active_duplex = current_duplex;
+
+		if ((bmcr & BMCR_ANENABLE) &&
+		    tg3_copper_is_advertising_all(tp,
+					tp->link_config.advertising)) {
+			if (tg3_adv_1000T_flowctrl_ok(tp, &lcl_adv,
+							  &rmt_adv)) {
+				current_link_up = 1;
+			}
+		}
+
+		if (current_link_up == 1 &&
+		    tp->link_config.active_duplex == DUPLEX_FULL)
+			tg3_setup_flow_control(tp, lcl_adv, rmt_adv);
+	}
+
+relink:
+	if (current_link_up == 0) {
+		tg3_phy_copper_begin(tp);
+
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+		if ((!tg3_readphy(tp, MII_BMSR, &bmsr) && (bmsr & BMSR_LSTATUS)) ||
+		    (tp->mac_mode & MAC_MODE_PORT_INT_LPBACK))
+			current_link_up = 1;
+	}
+
+	tp->mac_mode &= ~MAC_MODE_PORT_MODE_MASK;
+	if (current_link_up == 1) {
+		if (tp->link_config.active_speed == SPEED_100 ||
+		    tp->link_config.active_speed == SPEED_10)
+			tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
+		else
+			tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+	} else if (tp->phy_flags & TG3_PHYFLG_IS_FET)
+		tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
+	else
+		tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+
+	tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
+	if (tp->link_config.active_duplex == DUPLEX_HALF)
+		tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
+		if (current_link_up == 1 &&
+		    tg3_5700_link_polarity(tp, tp->link_config.active_speed))
+			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
+		else
+			tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
+	}
+
+	/* ??? Without this setting Netgear GA302T PHY does not
+	 * ??? send/receive packets...
+	 */
+	if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5411 &&
+	    tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) {
+		tp->mi_mode |= MAC_MI_MODE_AUTO_POLL;
+		tw32_f(MAC_MI_MODE, tp->mi_mode);
+		udelay(80);
+	}
+
+	tw32_f(MAC_MODE, tp->mac_mode);
+	udelay(40);
+
+	/* Enabled attention when the link has changed state. */
+	tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
+	udelay(40);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 &&
+	    current_link_up == 1 &&
+	    tp->link_config.active_speed == SPEED_1000 &&
+	    (tg3_flag(tp, PCIX_MODE) || tg3_flag(tp, PCI_HIGH_SPEED))) {
+		udelay(120);
+		/* NOTE: this freezes for mdc? */
+		tw32_f(MAC_STATUS,
+		     (MAC_STATUS_SYNC_CHANGED |
+		      MAC_STATUS_CFG_CHANGED));
+		udelay(40);
+		tg3_write_mem(tp,
+			      NIC_SRAM_FIRMWARE_MBOX,
+			      NIC_SRAM_FIRMWARE_MBOX_MAGIC2);
+	}
+
+	/* Prevent send BD corruption. */
+	if (tg3_flag(tp, CLKREQ_BUG)) {
+		u16 oldlnkctl, newlnkctl;
+
+		pci_read_config_word(tp->pdev,
+				     tp->pcie_cap + PCI_EXP_LNKCTL,
+				     &oldlnkctl);
+		if (tp->link_config.active_speed == SPEED_100 ||
+		    tp->link_config.active_speed == SPEED_10)
+			newlnkctl = oldlnkctl & ~PCI_EXP_LNKCTL_CLKREQ_EN;
+		else
+			newlnkctl = oldlnkctl | PCI_EXP_LNKCTL_CLKREQ_EN;
+		if (newlnkctl != oldlnkctl)
+			pci_write_config_word(tp->pdev,
+					      tp->pcie_cap + PCI_EXP_LNKCTL,
+					      newlnkctl);
+	}
+
+	if (current_link_up != netdev_link_ok(tp->dev)) {
+		if (current_link_up)
+			netdev_link_up(tp->dev);
+		else
+			netdev_link_down(tp->dev);
+		tg3_link_report(tp);
+	}
+
+	return 0;
+}
+
+int tg3_setup_phy(struct tg3 *tp, int force_reset)
+{	DBGP("%s\n", __func__);
+
+	u32 val;
+	int err;
+
+#if 0
+	if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
+		err = tg3_setup_fiber_phy(tp, force_reset);
+	else if (tp->phy_flags & TG3_PHYFLG_MII_SERDES)
+		err = tg3_setup_fiber_mii_phy(tp, force_reset);
+	else
+#endif
+	/* FIXME: add only copper phy variants for now */
+	err = tg3_setup_copper_phy(tp, force_reset);
+
+	val = (2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+	      (6 << TX_LENGTHS_IPG_SHIFT);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+		val |= tr32(MAC_TX_LENGTHS) &
+		       (TX_LENGTHS_JMB_FRM_LEN_MSK |
+			TX_LENGTHS_CNT_DWN_VAL_MSK);
+
+	if (tp->link_config.active_speed == SPEED_1000 &&
+	    tp->link_config.active_duplex == DUPLEX_HALF)
+		tw32(MAC_TX_LENGTHS, val |
+		     (0xff << TX_LENGTHS_SLOT_TIME_SHIFT));
+	else
+		tw32(MAC_TX_LENGTHS, val |
+		     (32 << TX_LENGTHS_SLOT_TIME_SHIFT));
+
+	if (!tg3_flag(tp, 5705_PLUS)) {
+		if (netdev_link_ok(tp->dev)) {
+			tw32(HOSTCC_STAT_COAL_TICKS, DEFAULT_STAT_COAL_TICKS);
+		} else {
+			tw32(HOSTCC_STAT_COAL_TICKS, 0);
+		}
+	}
+
+	val = tr32(PCIE_PWR_MGMT_THRESH);
+	if (!netdev_link_ok(tp->dev))
+		val = (val & ~PCIE_PWR_MGMT_L1_THRESH_MSK);
+	else
+		val |= PCIE_PWR_MGMT_L1_THRESH_MSK;
+	tw32(PCIE_PWR_MGMT_THRESH, val);
+
+	return err;
+}
diff --git a/roms/ipxe/src/drivers/net/tlan.c b/roms/ipxe/src/drivers/net/tlan.c
index b1a09d187f34b44c218ace7fd6b0..74398df42dcae15d835939535037 100644
--- a/roms/ipxe/src/drivers/net/tlan.c
+++ b/roms/ipxe/src/drivers/net/tlan.c
@@ -15,7 +15,8 @@
 *
 *    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.
+*    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+*    02110-1301, USA.
 *
 *    Portions of this code based on:
 *	lan.c: Linux ThunderLan Driver:
@@ -201,7 +202,7 @@ static struct tlan_private {
 	unsigned short vendor_id;	/* PCI Vendor code */
 	unsigned short dev_id;	/* PCI Device code */
 	const char *nic_name;
-	unsigned int cur_rx, dirty_rx;	/* Producer/consumer ring indicies */
+	unsigned int cur_rx, dirty_rx;	/* Producer/consumer ring indices */
 	unsigned rx_buf_sz;	/* Based on mtu + Slack */
 	struct TLanList *txList;
 	u32 txHead;
@@ -1084,11 +1085,11 @@ These routines are based on the information in Chap. 2 of the
 *				for this device.
 *		phy		The address of the PHY to be queried.
 *		reg		The register whose contents are to be
-*				retreived.
+*				retrieved.
 *		val		A pointer to a variable to store the
 *				retrieved value.
 *
-*	This function uses the TLAN's MII bus to retreive the contents
+*	This function uses the TLAN's MII bus to retrieve the contents
 *	of a given register on a PHY.  It sends the appropriate info
 *	and then reads the 16-bit register value from the MII bus via
 *	the TLAN SIO register.
diff --git a/roms/ipxe/src/drivers/net/tlan.h b/roms/ipxe/src/drivers/net/tlan.h
index 31b3c8f467a2fc449521410a7264..b787532be20d25218b21846669ad 100644
--- a/roms/ipxe/src/drivers/net/tlan.h
+++ b/roms/ipxe/src/drivers/net/tlan.h
@@ -15,7 +15,8 @@
 *
 *    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.
+*    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+*    02110-1301, USA.
 *
 *    Portions of this code (almost all) based on:
 *               tlan.c: Linux ThunderLan Driver:
diff --git a/roms/ipxe/src/drivers/net/via-rhine.c b/roms/ipxe/src/drivers/net/via-rhine.c
index 439a4a5dfac0f73cd310db2f573e..f3bb4e014340be73028ab03e5454 100644
--- a/roms/ipxe/src/drivers/net/via-rhine.c
+++ b/roms/ipxe/src/drivers/net/via-rhine.c
@@ -288,7 +288,7 @@ static const char *version = "rhine.c v1.0.2 2004-10-29\n";
  */
 
 #define EECSR_EEPR		0x80	/* eeprom programed status, 73h means programed */
-#define EECSR_EMBP		0x40	/* eeprom embeded programming */
+#define EECSR_EMBP		0x40	/* eeprom embedded programming */
 #define EECSR_AUTOLD		0x20	/* eeprom content reload */
 #define EECSR_DPM		0x10	/* eeprom direct programming */
 #define EECSR_CS		0x08	/* eeprom CS pin */
@@ -322,7 +322,7 @@ static const char *version = "rhine.c v1.0.2 2004-10-29\n";
  * Bits in the CFGA register
  */
 
-#define CFGA_EELOAD		0x80	/* enable eeprom embeded and direct programming */
+#define CFGA_EELOAD		0x80	/* enable eeprom embedded and direct programming */
 #define CFGA_JUMPER		0x40
 #define CFGA_MTGPIO		0x08
 #define CFGA_T10EN		0x02
@@ -693,7 +693,7 @@ static void MIIDelay (void);
 static void rhine_init_ring (struct nic *dev);
 static void rhine_disable (struct nic *nic);
 static void rhine_reset (struct nic *nic);
-static int rhine_poll (struct nic *nic, int retreive);
+static int rhine_poll (struct nic *nic, int retrieve);
 static void rhine_transmit (struct nic *nic, const char *d, unsigned int t,
 			    unsigned int s, const char *p);
 static void reload_eeprom(int ioaddr);
@@ -1286,7 +1286,7 @@ rhine_reset (struct nic *nic)
 #define IOSYNC  do { inb(nic->ioaddr + StationAddr); } while (0)
 
 static int
-rhine_poll (struct nic *nic, int retreive)
+rhine_poll (struct nic *nic, int retrieve)
 {
     struct rhine_private *tp = (struct rhine_private *) nic->priv_data;
     int rxstatus, good = 0;;
@@ -1295,7 +1295,7 @@ rhine_poll (struct nic *nic, int retreive)
     {
         unsigned int intr_status;
         /* There is a packet ready */
-        if(!retreive)
+        if(!retrieve)
             return 1;
 
         intr_status = inw(nic->ioaddr + IntrStatus);
diff --git a/roms/ipxe/src/drivers/net/via-velocity.c b/roms/ipxe/src/drivers/net/via-velocity.c
index fa90f9b3f2aae8abc5b1ffd5155e..9ba0b093d2f40fd087e6937518c7 100644
--- a/roms/ipxe/src/drivers/net/via-velocity.c
+++ b/roms/ipxe/src/drivers/net/via-velocity.c
@@ -15,7 +15,8 @@
 *
 *    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.
+*    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+*    02110-1301, USA.
 *
 *    This driver is based on:
 *         via-velocity.c: VIA Velocity VT6120, VT6122 Ethernet driver 
@@ -124,7 +125,7 @@ VELOCITY_PARAM(enable_tagging, "Enable 802.1Q tagging");
 /* IP_byte_align[] is used for IP header DWORD byte aligned
    0: indicate the IP header won't be DWORD byte aligned.(Default) .
    1: indicate the IP header will be DWORD byte aligned.
-      In some enviroment, the IP header should be DWORD byte aligned,
+      In some environment, the IP header should be DWORD byte aligned,
       or the packet will be droped when we receive it. (eg: IPVS)
 */
 VELOCITY_PARAM(IP_byte_align, "Enable IP header dword aligned");
diff --git a/roms/ipxe/src/drivers/net/via-velocity.h b/roms/ipxe/src/drivers/net/via-velocity.h
index b657224d2248e95362ab1b57c7eb..753fe445f6a887a65c4da35c83dc 100644
--- a/roms/ipxe/src/drivers/net/via-velocity.h
+++ b/roms/ipxe/src/drivers/net/via-velocity.h
@@ -878,7 +878,7 @@ enum {
  *	Bits in the EECSR register
  */
 
-#define EECSR_EMBP          0x40	/* eeprom embeded programming */
+#define EECSR_EMBP          0x40	/* eeprom embedded programming */
 #define EECSR_RELOAD        0x20	/* eeprom content reload */
 #define EECSR_DPM           0x10	/* eeprom direct programming */
 #define EECSR_ECS           0x08	/* eeprom CS pin */
diff --git a/roms/ipxe/src/drivers/net/virtio-net.c b/roms/ipxe/src/drivers/net/virtio-net.c
index 54e962d1f838dc5af3e19114d685..d5fd8197975da869a6b401413f21 100644
--- a/roms/ipxe/src/drivers/net/virtio-net.c
+++ b/roms/ipxe/src/drivers/net/virtio-net.c
@@ -69,7 +69,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
  * Linux source.
  */
 
-/* Virtqueue indicies */
+/* Virtqueue indices */
 enum {
 	RX_INDEX = 0,
 	TX_INDEX,
diff --git a/roms/ipxe/src/drivers/net/vmxnet3.c b/roms/ipxe/src/drivers/net/vmxnet3.c
new file mode 100644
index 0000000000000000000000000000000000000000..9401c110e7075482bebc20270c41ed00ca0d7f78
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/vmxnet3.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright (C) 2011 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/pci.h>
+#include <ipxe/io.h>
+#include <ipxe/malloc.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/ethernet.h>
+#include "vmxnet3.h"
+
+/**
+ * @file
+ *
+ * VMware vmxnet3 virtual NIC driver
+ *
+ */
+
+/**
+ * Issue command
+ *
+ * @v vmxnet		vmxnet3 NIC
+ * @v command		Command to issue
+ * @ret result		Command result
+ */
+static inline uint32_t vmxnet3_command ( struct vmxnet3_nic *vmxnet,
+					 uint32_t command ) {
+
+	/* Issue command */
+	writel ( command, ( vmxnet->vd + VMXNET3_VD_CMD ) );
+	return readl ( vmxnet->vd + VMXNET3_VD_CMD );
+}
+
+/**
+ * Transmit packet
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @ret rc		Return status code
+ */
+static int vmxnet3_transmit ( struct net_device *netdev,
+			      struct io_buffer *iobuf ) {
+	struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
+	struct vmxnet3_tx_desc *tx_desc;
+	unsigned int desc_idx;
+	unsigned int generation;
+
+	/* Check that we have a free transmit descriptor */
+	desc_idx = ( vmxnet->count.tx_prod % VMXNET3_NUM_TX_DESC );
+	generation = ( ( vmxnet->count.tx_prod & VMXNET3_NUM_TX_DESC ) ?
+		       0 : cpu_to_le32 ( VMXNET3_TXF_GEN ) );
+	if ( vmxnet->tx_iobuf[desc_idx] ) {
+		DBGC ( vmxnet, "VMXNET3 %p out of transmit descriptors\n",
+		       vmxnet );
+		return -ENOBUFS;
+	}
+
+	/* Increment producer counter */
+	vmxnet->count.tx_prod++;
+
+	/* Store I/O buffer for later completion */
+	vmxnet->tx_iobuf[desc_idx] = iobuf;
+
+	/* Populate transmit descriptor */
+	tx_desc = &vmxnet->dma->tx_desc[desc_idx];
+	tx_desc->address = cpu_to_le64 ( virt_to_bus ( iobuf->data ) );
+	tx_desc->flags[0] = ( generation | cpu_to_le32 ( iob_len ( iobuf ) ) );
+	tx_desc->flags[1] = cpu_to_le32 ( VMXNET3_TXF_CQ | VMXNET3_TXF_EOP );
+
+	/* Hand over descriptor to NIC */
+	wmb();
+	writel ( ( vmxnet->count.tx_prod % VMXNET3_NUM_TX_DESC ),
+		 ( vmxnet->pt + VMXNET3_PT_TXPROD ) );
+
+	return 0;
+}
+
+/**
+ * Poll for completed transmissions
+ *
+ * @v netdev		Network device
+ */
+static void vmxnet3_poll_tx ( struct net_device *netdev ) {
+	struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
+	struct vmxnet3_tx_comp *tx_comp;
+	struct io_buffer *iobuf;
+	unsigned int comp_idx;
+	unsigned int desc_idx;
+	unsigned int generation;
+
+	while ( 1 ) {
+
+		/* Look for completed descriptors */
+		comp_idx = ( vmxnet->count.tx_cons % VMXNET3_NUM_TX_COMP );
+		generation = ( ( vmxnet->count.tx_cons & VMXNET3_NUM_TX_COMP ) ?
+			       0 : cpu_to_le32 ( VMXNET3_TXCF_GEN ) );
+		tx_comp = &vmxnet->dma->tx_comp[comp_idx];
+		if ( generation != ( tx_comp->flags &
+				     cpu_to_le32 ( VMXNET3_TXCF_GEN ) ) ) {
+			break;
+		}
+
+		/* Increment consumer counter */
+		vmxnet->count.tx_cons++;
+
+		/* Locate corresponding transmit descriptor */
+		desc_idx = ( le32_to_cpu ( tx_comp->index ) %
+			     VMXNET3_NUM_TX_DESC );
+		iobuf = vmxnet->tx_iobuf[desc_idx];
+		if ( ! iobuf ) {
+			DBGC ( vmxnet, "VMXNET3 %p completed on empty transmit "
+			       "buffer %#x/%#x\n", vmxnet, comp_idx, desc_idx );
+			netdev_tx_err ( netdev, NULL, -ENOTTY );
+			continue;
+		}
+
+		/* Remove I/O buffer from transmit queue */
+		vmxnet->tx_iobuf[desc_idx] = NULL;
+
+		/* Report transmission completion to network layer */
+		DBGC2 ( vmxnet, "VMXNET3 %p completed TX %#x/%#x (len %#zx)\n",
+			vmxnet, comp_idx, desc_idx, iob_len ( iobuf ) );
+		netdev_tx_complete ( netdev, iobuf );
+	}
+}
+
+/**
+ * Flush any uncompleted transmit buffers
+ *
+ * @v netdev		Network device
+ */
+static void vmxnet3_flush_tx ( struct net_device *netdev ) {
+	struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
+	unsigned int i;
+
+	for ( i = 0 ; i < VMXNET3_NUM_TX_DESC ; i++ ) {
+		if ( vmxnet->tx_iobuf[i] ) {
+			netdev_tx_complete_err ( netdev, vmxnet->tx_iobuf[i],
+						 -ECANCELED );
+			vmxnet->tx_iobuf[i] = NULL;
+		}
+	}
+}
+
+/**
+ * Refill receive ring
+ *
+ * @v netdev		Network device
+ */
+static void vmxnet3_refill_rx ( struct net_device *netdev ) {
+	struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
+	struct vmxnet3_rx_desc *rx_desc;
+	struct io_buffer *iobuf;
+	unsigned int orig_rx_prod = vmxnet->count.rx_prod;
+	unsigned int desc_idx;
+	unsigned int generation;
+
+	/* Fill receive ring to specified fill level */
+	while ( vmxnet->count.rx_fill < VMXNET3_RX_FILL ) {
+
+		/* Locate receive descriptor */
+		desc_idx = ( vmxnet->count.rx_prod % VMXNET3_NUM_RX_DESC );
+		generation = ( ( vmxnet->count.rx_prod & VMXNET3_NUM_RX_DESC ) ?
+			       0 : cpu_to_le32 ( VMXNET3_RXF_GEN ) );
+		assert ( vmxnet->rx_iobuf[desc_idx] == NULL );
+
+		/* Allocate I/O buffer */
+		iobuf = alloc_iob ( VMXNET3_MTU + NET_IP_ALIGN );
+		if ( ! iobuf ) {
+			/* Non-fatal low memory condition */
+			break;
+		}
+		iob_reserve ( iobuf, NET_IP_ALIGN );
+
+		/* Increment producer counter and fill level */
+		vmxnet->count.rx_prod++;
+		vmxnet->count.rx_fill++;
+
+		/* Store I/O buffer for later completion */
+		vmxnet->rx_iobuf[desc_idx] = iobuf;
+
+		/* Populate receive descriptor */
+		rx_desc = &vmxnet->dma->rx_desc[desc_idx];
+		rx_desc->address = cpu_to_le64 ( virt_to_bus ( iobuf->data ) );
+		rx_desc->flags = ( generation | cpu_to_le32 ( VMXNET3_MTU ) );
+
+	}
+
+	/* Hand over any new descriptors to NIC */
+	if ( vmxnet->count.rx_prod != orig_rx_prod ) {
+		wmb();
+		writel ( ( vmxnet->count.rx_prod % VMXNET3_NUM_RX_DESC ),
+			 ( vmxnet->pt + VMXNET3_PT_RXPROD ) );
+	}
+}
+
+/**
+ * Poll for received packets
+ *
+ * @v netdev		Network device
+ */
+static void vmxnet3_poll_rx ( struct net_device *netdev ) {
+	struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
+	struct vmxnet3_rx_comp *rx_comp;
+	struct io_buffer *iobuf;
+	unsigned int comp_idx;
+	unsigned int desc_idx;
+	unsigned int generation;
+	size_t len;
+
+	while ( 1 ) {
+
+		/* Look for completed descriptors */
+		comp_idx = ( vmxnet->count.rx_cons % VMXNET3_NUM_RX_COMP );
+		generation = ( ( vmxnet->count.rx_cons & VMXNET3_NUM_RX_COMP ) ?
+			       0 : cpu_to_le32 ( VMXNET3_RXCF_GEN ) );
+		rx_comp = &vmxnet->dma->rx_comp[comp_idx];
+		if ( generation != ( rx_comp->flags &
+				     cpu_to_le32 ( VMXNET3_RXCF_GEN ) ) ) {
+			break;
+		}
+
+		/* Increment consumer counter */
+		vmxnet->count.rx_cons++;
+
+		/* Locate corresponding receive descriptor */
+		desc_idx = ( le32_to_cpu ( rx_comp->index ) %
+			     VMXNET3_NUM_RX_DESC );
+		iobuf = vmxnet->rx_iobuf[desc_idx];
+		if ( ! iobuf ) {
+			DBGC ( vmxnet, "VMXNET3 %p completed on empty receive "
+			       "buffer %#x/%#x\n", vmxnet, comp_idx, desc_idx );
+			netdev_rx_err ( netdev, NULL, -ENOTTY );
+			continue;
+		}
+
+		/* Remove I/O buffer from receive queue */
+		vmxnet->rx_iobuf[desc_idx] = NULL;
+		vmxnet->count.rx_fill--;
+
+		/* Deliver packet to network layer */
+		len = ( le32_to_cpu ( rx_comp->len ) &
+			( VMXNET3_MAX_PACKET_LEN - 1 ) );
+		DBGC2 ( vmxnet, "VMXNET3 %p completed RX %#x/%#x (len %#zx)\n",
+			vmxnet, comp_idx, desc_idx, len );
+		iob_put ( iobuf, len );
+		netdev_rx ( netdev, iobuf );
+	}
+}
+
+/**
+ * Flush any uncompleted receive buffers
+ *
+ * @v netdev		Network device
+ */
+static void vmxnet3_flush_rx ( struct net_device *netdev ) {
+	struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
+	struct io_buffer *iobuf;
+	unsigned int i;
+
+	for ( i = 0 ; i < VMXNET3_NUM_RX_DESC ; i++ ) {
+		if ( ( iobuf = vmxnet->rx_iobuf[i] ) != NULL ) {
+			netdev_rx_err ( netdev, iobuf, -ECANCELED );
+			vmxnet->rx_iobuf[i] = NULL;
+		}
+	}
+}
+
+/**
+ * Check link state
+ *
+ * @v netdev		Network device
+ */
+static void vmxnet3_check_link ( struct net_device *netdev ) {
+	struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
+	uint32_t state;
+	int link_up;
+	unsigned int link_speed;
+
+	/* Get link state */
+	state = vmxnet3_command ( vmxnet, VMXNET3_CMD_GET_LINK );
+	link_up = ( state & 1 );
+	link_speed = ( state >> 16 );
+
+	/* Report link state to network device */
+	if ( link_up ) {
+		DBGC ( vmxnet, "VMXNET3 %p link is up at %d Mbps\n",
+		       vmxnet, link_speed );
+		netdev_link_up ( netdev );
+	} else {
+		DBGC ( vmxnet, "VMXNET3 %p link is down\n", vmxnet );
+		netdev_link_down ( netdev );
+	}
+}
+
+/**
+ * Poll for events
+ *
+ * @v netdev		Network device
+ */
+static void vmxnet3_poll_events ( struct net_device *netdev ) {
+	struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
+	uint32_t events;
+
+	/* Do nothing unless there are events to process */
+	if ( ! vmxnet->dma->shared.ecr )
+		return;
+	events = le32_to_cpu ( vmxnet->dma->shared.ecr );
+
+	/* Acknowledge these events */
+	writel ( events, ( vmxnet->vd + VMXNET3_VD_ECR ) );
+
+	/* Check for link state change */
+	if ( events & VMXNET3_ECR_LINK ) {
+		vmxnet3_check_link ( netdev );
+		events &= ~VMXNET3_ECR_LINK;
+	}
+
+	/* Check for queue errors */
+	if ( events & ( VMXNET3_ECR_TQERR | VMXNET3_ECR_RQERR ) ) {
+		vmxnet3_command ( vmxnet, VMXNET3_CMD_GET_QUEUE_STATUS );
+		DBGC ( vmxnet, "VMXNET3 %p queue error status (TX %08x, RX "
+		       "%08x)\n", vmxnet,
+		       le32_to_cpu ( vmxnet->dma->queues.tx.status.error ),
+		       le32_to_cpu ( vmxnet->dma->queues.rx.status.error ) );
+		/* Report errors to allow for visibility via "ifstat" */
+		if ( events & VMXNET3_ECR_TQERR )
+			netdev_tx_err ( netdev, NULL, -EPIPE );
+		if ( events & VMXNET3_ECR_RQERR )
+			netdev_rx_err ( netdev, NULL, -EPIPE );
+		events &= ~( VMXNET3_ECR_TQERR | VMXNET3_ECR_RQERR );
+	}
+
+	/* Check for unknown events */
+	if ( events ) {
+		DBGC ( vmxnet, "VMXNET3 %p unknown events %08x\n",
+		       vmxnet, events );
+		/* Report error to allow for visibility via "ifstat" */
+		netdev_rx_err ( netdev, NULL, -ENODEV );
+	}
+}
+
+/**
+ * Poll network device
+ *
+ * @v netdev		Network device
+ */
+static void vmxnet3_poll ( struct net_device *netdev ) {
+
+	vmxnet3_poll_events ( netdev );
+	vmxnet3_poll_tx ( netdev );
+	vmxnet3_poll_rx ( netdev );
+	vmxnet3_refill_rx ( netdev );
+}
+
+/**
+ * Enable/disable interrupts
+ *
+ * @v netdev		Network device
+ * @v enable		Interrupts should be enabled
+ */
+static void vmxnet3_irq ( struct net_device *netdev, int enable ) {
+	struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
+
+	DBGC ( vmxnet, "VMXNET3 %p %s IRQ not implemented\n",
+	       vmxnet, ( enable ? "enable" : "disable" ) );
+}
+
+/**
+ * Set MAC address
+ *
+ * @v vmxnet		vmxnet3 NIC
+ * @v ll_addr		Link-layer address to set
+ */
+static void vmxnet3_set_ll_addr ( struct vmxnet3_nic *vmxnet,
+				  const void *ll_addr ) {
+	struct {
+		uint32_t low;
+		uint32_t high;
+	} __attribute__ (( packed )) mac;
+
+	memset ( &mac, 0, sizeof ( mac ) );
+	memcpy ( &mac, ll_addr, ETH_ALEN );
+	writel ( cpu_to_le32 ( mac.low ), ( vmxnet->vd + VMXNET3_VD_MACL ) );
+	writel ( cpu_to_le32 ( mac.high ), ( vmxnet->vd + VMXNET3_VD_MACH ) );
+}
+
+/**
+ * Open NIC
+ *
+ * @v netdev		Network device
+ * @ret rc		Return status code
+ */
+static int vmxnet3_open ( struct net_device *netdev ) {
+	struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
+	struct vmxnet3_shared *shared;
+	struct vmxnet3_queues *queues;
+	uint64_t shared_bus;
+	uint64_t queues_bus;
+	uint32_t status;
+	int rc;
+
+	/* Allocate DMA areas */
+	vmxnet->dma = malloc_dma ( sizeof ( *vmxnet->dma ), VMXNET3_DMA_ALIGN );
+	if ( ! vmxnet->dma ) {
+		DBGC ( vmxnet, "VMXNET3 %p could not allocate DMA area\n",
+		       vmxnet );
+		rc = -ENOMEM;
+		goto err_alloc_dma;
+	}
+	memset ( vmxnet->dma, 0, sizeof ( *vmxnet->dma ) );
+
+	/* Populate queue descriptors */
+	queues = &vmxnet->dma->queues;
+	queues->tx.cfg.desc_address =
+		cpu_to_le64 ( virt_to_bus ( &vmxnet->dma->tx_desc ) );
+	queues->tx.cfg.comp_address =
+		cpu_to_le64 ( virt_to_bus ( &vmxnet->dma->tx_comp ) );
+	queues->tx.cfg.num_desc = cpu_to_le32 ( VMXNET3_NUM_TX_DESC );
+	queues->tx.cfg.num_comp = cpu_to_le32 ( VMXNET3_NUM_TX_COMP );
+	queues->rx.cfg.desc_address[0] =
+		cpu_to_le64 ( virt_to_bus ( &vmxnet->dma->rx_desc ) );
+	queues->rx.cfg.comp_address =
+		cpu_to_le64 ( virt_to_bus ( &vmxnet->dma->rx_comp ) );
+	queues->rx.cfg.num_desc[0] = cpu_to_le32 ( VMXNET3_NUM_RX_DESC );
+	queues->rx.cfg.num_comp = cpu_to_le32 ( VMXNET3_NUM_RX_COMP );
+	queues_bus = virt_to_bus ( queues );
+	DBGC ( vmxnet, "VMXNET3 %p queue descriptors at %08llx+%zx\n",
+	       vmxnet, queues_bus, sizeof ( *queues ) );
+
+	/* Populate shared area */
+	shared = &vmxnet->dma->shared;
+	shared->magic = cpu_to_le32 ( VMXNET3_SHARED_MAGIC );
+	shared->misc.version = cpu_to_le32 ( VMXNET3_VERSION_MAGIC );
+	shared->misc.version_support = cpu_to_le32 ( VMXNET3_VERSION_SELECT );
+	shared->misc.upt_version_support =
+		cpu_to_le32 ( VMXNET3_UPT_VERSION_SELECT );
+	shared->misc.queue_desc_address = cpu_to_le64 ( queues_bus );
+	shared->misc.queue_desc_len = cpu_to_le32 ( sizeof ( *queues ) );
+	shared->misc.mtu = cpu_to_le32 ( VMXNET3_MTU );
+	shared->misc.num_tx_queues = 1;
+	shared->misc.num_rx_queues = 1;
+	shared->interrupt.num_intrs = 1;
+	shared->interrupt.control = cpu_to_le32 ( VMXNET3_IC_DISABLE_ALL );
+	shared->rx_filter.mode = cpu_to_le32 ( VMXNET3_RXM_UCAST |
+					       VMXNET3_RXM_BCAST |
+					       VMXNET3_RXM_ALL_MULTI );
+	shared_bus = virt_to_bus ( shared );
+	DBGC ( vmxnet, "VMXNET3 %p shared area at %08llx+%zx\n",
+	       vmxnet, shared_bus, sizeof ( *shared ) );
+
+	/* Zero counters */
+	memset ( &vmxnet->count, 0, sizeof ( vmxnet->count ) );
+
+	/* Set MAC address */
+	vmxnet3_set_ll_addr ( vmxnet, &netdev->ll_addr );
+
+	/* Pass shared area to device */
+	writel ( ( shared_bus >> 0 ), ( vmxnet->vd + VMXNET3_VD_DSAL ) );
+	writel ( ( shared_bus >> 32 ), ( vmxnet->vd + VMXNET3_VD_DSAH ) );
+
+	/* Activate device */
+	if ( ( status = vmxnet3_command ( vmxnet,
+					  VMXNET3_CMD_ACTIVATE_DEV ) ) != 0 ) {
+		DBGC ( vmxnet, "VMXNET3 %p could not activate (status %#x)\n",
+		       vmxnet, status );
+		rc = -EIO;
+		goto err_activate;
+	}
+
+	/* Fill receive ring */
+	vmxnet3_refill_rx ( netdev );
+
+	return 0;
+
+	vmxnet3_command ( vmxnet, VMXNET3_CMD_QUIESCE_DEV );
+	vmxnet3_command ( vmxnet, VMXNET3_CMD_RESET_DEV );
+ err_activate:
+	vmxnet3_flush_tx ( netdev );
+	vmxnet3_flush_rx ( netdev );
+	free_dma ( vmxnet->dma, sizeof ( *vmxnet->dma ) );
+ err_alloc_dma:
+	return rc;
+}
+
+/**
+ * Close NIC
+ *
+ * @v netdev		Network device
+ */
+static void vmxnet3_close ( struct net_device *netdev ) {
+	struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
+
+	vmxnet3_command ( vmxnet, VMXNET3_CMD_QUIESCE_DEV );
+	vmxnet3_command ( vmxnet, VMXNET3_CMD_RESET_DEV );
+	vmxnet3_flush_tx ( netdev );
+	vmxnet3_flush_rx ( netdev );
+	free_dma ( vmxnet->dma, sizeof ( *vmxnet->dma ) );
+}
+
+/** vmxnet3 net device operations */
+static struct net_device_operations vmxnet3_operations = {
+	.open		= vmxnet3_open,
+	.close		= vmxnet3_close,
+	.transmit	= vmxnet3_transmit,
+	.poll		= vmxnet3_poll,
+	.irq		= vmxnet3_irq,
+};
+
+/**
+ * Check version
+ *
+ * @v vmxnet		vmxnet3 NIC
+ * @ret rc		Return status code
+ */
+static int vmxnet3_check_version ( struct vmxnet3_nic *vmxnet ) {
+	uint32_t version;
+	uint32_t upt_version;
+
+	/* Read version */
+	version = readl ( vmxnet->vd + VMXNET3_VD_VRRS );
+	upt_version = readl ( vmxnet->vd + VMXNET3_VD_UVRS );
+	DBGC ( vmxnet, "VMXNET3 %p is version %d (UPT version %d)\n",
+	       vmxnet, version, upt_version );
+
+	/* Inform NIC of driver version */
+	writel ( VMXNET3_VERSION_SELECT, ( vmxnet->vd + VMXNET3_VD_VRRS ) );
+	writel ( VMXNET3_UPT_VERSION_SELECT, ( vmxnet->vd + VMXNET3_VD_UVRS ) );
+
+	return 0;
+}
+
+/**
+ * Get permanent MAC address
+ *
+ * @v vmxnet		vmxnet3 NIC
+ * @v hw_addr		Hardware address to fill in
+ */
+static void vmxnet3_get_hw_addr ( struct vmxnet3_nic *vmxnet, void *hw_addr ) {
+	struct {
+		uint32_t low;
+		uint32_t high;
+	} __attribute__ (( packed )) mac;
+
+	mac.low = le32_to_cpu ( vmxnet3_command ( vmxnet,
+					       VMXNET3_CMD_GET_PERM_MAC_LO ) );
+	mac.high = le32_to_cpu ( vmxnet3_command ( vmxnet,
+					       VMXNET3_CMD_GET_PERM_MAC_HI ) );
+	memcpy ( hw_addr, &mac, ETH_ALEN );
+}
+
+/**
+ * Probe PCI device
+ *
+ * @v pci		PCI device
+ * @v id		PCI ID
+ * @ret rc		Return status code
+ */
+static int vmxnet3_probe ( struct pci_device *pci ) {
+	struct net_device *netdev;
+	struct vmxnet3_nic *vmxnet;
+	int rc;
+
+	/* Allocate network device */
+	netdev = alloc_etherdev ( sizeof ( *vmxnet ) );
+	if ( ! netdev ) {
+		rc = -ENOMEM;
+		goto err_alloc_etherdev;
+	}
+	netdev_init ( netdev, &vmxnet3_operations );
+	vmxnet = netdev_priv ( netdev );
+	pci_set_drvdata ( pci, netdev );
+	netdev->dev = &pci->dev;
+	memset ( vmxnet, 0, sizeof ( *vmxnet ) );
+
+	/* Fix up PCI device */
+	adjust_pci_device ( pci );
+
+	/* Map PCI BARs */
+	vmxnet->pt = ioremap ( pci_bar_start ( pci, VMXNET3_PT_BAR ),
+			       VMXNET3_PT_LEN );
+	vmxnet->vd = ioremap ( pci_bar_start ( pci, VMXNET3_VD_BAR ),
+			       VMXNET3_VD_LEN );
+
+	/* Version check */
+	if ( ( rc = vmxnet3_check_version ( vmxnet ) ) != 0 )
+		goto err_check_version;
+
+	/* Reset device */
+	if ( ( rc = vmxnet3_command ( vmxnet, VMXNET3_CMD_RESET_DEV ) ) != 0 )
+		goto err_reset;
+
+	/* Read initial MAC address */
+	vmxnet3_get_hw_addr ( vmxnet, &netdev->hw_addr );
+
+	/* Register network device */
+	if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
+		DBGC ( vmxnet, "VMXNET3 %p could not register net device: "
+		       "%s\n", vmxnet, strerror ( rc ) );
+		goto err_register_netdev;
+	}
+
+	/* Get initial link state */
+	vmxnet3_check_link ( netdev );
+
+	return 0;
+
+	unregister_netdev ( netdev );
+ err_register_netdev:
+ err_reset:
+ err_check_version:
+	iounmap ( vmxnet->vd );
+	iounmap ( vmxnet->pt );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+ err_alloc_etherdev:
+	return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci		PCI device
+ */
+static void vmxnet3_remove ( struct pci_device *pci ) {
+	struct net_device *netdev = pci_get_drvdata ( pci );
+	struct vmxnet3_nic *vmxnet = netdev_priv ( netdev );
+
+	unregister_netdev ( netdev );
+	iounmap ( vmxnet->vd );
+	iounmap ( vmxnet->pt );
+	netdev_nullify ( netdev );
+	netdev_put ( netdev );
+}
+
+/** vmxnet3 PCI IDs */
+static struct pci_device_id vmxnet3_nics[] = {
+	PCI_ROM ( 0x15ad, 0x07b0, "vmxnet3", "vmxnet3 virtual NIC", 0 ),
+};
+
+/** vmxnet3 PCI driver */
+struct pci_driver vmxnet3_driver __pci_driver = {
+	.ids = vmxnet3_nics,
+	.id_count = ( sizeof ( vmxnet3_nics ) / sizeof ( vmxnet3_nics[0] ) ),
+	.probe = vmxnet3_probe,
+	.remove = vmxnet3_remove,
+};
diff --git a/roms/ipxe/src/drivers/net/vmxnet3.h b/roms/ipxe/src/drivers/net/vmxnet3.h
new file mode 100644
index 0000000000000000000000000000000000000000..db313d4b83368f7fdfd0c43f3a3e76699c6e9e80
--- /dev/null
+++ b/roms/ipxe/src/drivers/net/vmxnet3.h
@@ -0,0 +1,498 @@
+#ifndef _VMXNET3_H
+#define _VMXNET3_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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * VMware vmxnet3 virtual NIC driver
+ *
+ */
+
+#include <ipxe/pci.h>
+
+/** Maximum number of TX queues */
+#define VMXNET3_MAX_TX_QUEUES 8
+
+/** Maximum number of RX queues */
+#define VMXNET3_MAX_RX_QUEUES 16
+
+/** Maximum number of interrupts */
+#define VMXNET3_MAX_INTRS 25
+
+/** Maximum packet size */
+#define VMXNET3_MAX_PACKET_LEN 0x4000
+
+/** "PT" PCI BAR address */
+#define VMXNET3_PT_BAR PCI_BASE_ADDRESS_0
+
+/** "PT" PCI BAR size */
+#define VMXNET3_PT_LEN 0x1000
+
+/** Interrupt Mask Register */
+#define VMXNET3_PT_IMR 0x0
+
+/** Transmit producer index */
+#define VMXNET3_PT_TXPROD 0x600
+
+/** Rx producer index for ring 1 */
+#define VMXNET3_PT_RXPROD 0x800
+
+/** Rx producer index for ring 2 */
+#define VMXNET3_PT_RXPROD2 0xa00
+
+/** "VD" PCI BAR address */
+#define VMXNET3_VD_BAR PCI_BASE_ADDRESS_1
+
+/** "VD" PCI BAR size */
+#define VMXNET3_VD_LEN 0x1000
+
+/** vmxnet3 Revision Report Selection */
+#define VMXNET3_VD_VRRS	0x0
+
+/** UPT Version Report Selection */
+#define VMXNET3_VD_UVRS 0x8
+
+/** Driver Shared Address Low */
+#define VMXNET3_VD_DSAL 0x10
+
+/** Driver Shared Address High */
+#define VMXNET3_VD_DSAH 0x18
+
+/** Command */
+#define VMXNET3_VD_CMD	0x20
+
+/** MAC Address Low */
+#define VMXNET3_VD_MACL 0x28
+
+/** MAC Address High */
+#define VMXNET3_VD_MACH 0x30
+
+/** Interrupt Cause Register */
+#define VMXNET3_VD_ICR	0x38
+
+/** Event Cause Register */
+#define VMXNET3_VD_ECR	0x40
+
+/** Commands */
+enum vmxnet3_command {
+	VMXNET3_CMD_FIRST_SET = 0xcafe0000,
+	VMXNET3_CMD_ACTIVATE_DEV = VMXNET3_CMD_FIRST_SET,
+	VMXNET3_CMD_QUIESCE_DEV,
+	VMXNET3_CMD_RESET_DEV,
+	VMXNET3_CMD_UPDATE_RX_MODE,
+	VMXNET3_CMD_UPDATE_MAC_FILTERS,
+	VMXNET3_CMD_UPDATE_VLAN_FILTERS,
+	VMXNET3_CMD_UPDATE_RSSIDT,
+	VMXNET3_CMD_UPDATE_IML,
+	VMXNET3_CMD_UPDATE_PMCFG,
+	VMXNET3_CMD_UPDATE_FEATURE,
+	VMXNET3_CMD_LOAD_PLUGIN,
+
+	VMXNET3_CMD_FIRST_GET = 0xf00d0000,
+	VMXNET3_CMD_GET_QUEUE_STATUS = VMXNET3_CMD_FIRST_GET,
+	VMXNET3_CMD_GET_STATS,
+	VMXNET3_CMD_GET_LINK,
+	VMXNET3_CMD_GET_PERM_MAC_LO,
+	VMXNET3_CMD_GET_PERM_MAC_HI,
+	VMXNET3_CMD_GET_DID_LO,
+	VMXNET3_CMD_GET_DID_HI,
+	VMXNET3_CMD_GET_DEV_EXTRA_INFO,
+	VMXNET3_CMD_GET_CONF_INTR
+};
+
+/** Events */
+enum vmxnet3_event {
+	VMXNET3_ECR_RQERR = 0x00000001,
+	VMXNET3_ECR_TQERR = 0x00000002,
+	VMXNET3_ECR_LINK = 0x00000004,
+	VMXNET3_ECR_DIC = 0x00000008,
+	VMXNET3_ECR_DEBUG = 0x00000010,
+};
+
+/** Miscellaneous configuration descriptor */
+struct vmxnet3_misc_config {
+	/** Driver version */
+	uint32_t version;
+	/** Guest information */
+	uint32_t guest_info;
+	/** Version supported */
+	uint32_t version_support;
+	/** UPT version supported */
+	uint32_t upt_version_support;
+	/** UPT features supported */
+	uint64_t upt_features;
+	/** Driver-private data address */
+	uint64_t driver_data_address;
+	/** Queue descriptors data address */
+	uint64_t queue_desc_address;
+	/** Driver-private data length */
+	uint32_t driver_data_len;
+	/** Queue descriptors data length */
+	uint32_t queue_desc_len;
+	/** Maximum transmission unit */
+	uint32_t mtu;
+	/** Maximum number of RX scatter-gather */
+	uint16_t max_num_rx_sg;
+	/** Number of TX queues */
+	uint8_t num_tx_queues;
+	/** Number of RX queues */
+	uint8_t num_rx_queues;
+	/** Reserved */
+	uint32_t reserved0[4];
+} __attribute__ (( packed ));
+
+/** Driver version magic */
+#define VMXNET3_VERSION_MAGIC 0x69505845
+
+/** Interrupt configuration */
+struct vmxnet3_interrupt_config {
+	uint8_t mask_mode;
+	uint8_t num_intrs;
+	uint8_t event_intr_index;
+	uint8_t moderation_level[VMXNET3_MAX_INTRS];
+	uint32_t control;
+	uint32_t reserved0[2];
+} __attribute__ (( packed ));
+
+/** Interrupt control - disable all interrupts */
+#define VMXNET3_IC_DISABLE_ALL 0x1
+
+/** Receive filter configuration */
+struct vmxnet3_rx_filter_config {
+	/** Receive filter mode */
+	uint32_t mode;
+	/** Multicast filter table length */
+	uint16_t multicast_len;
+	/** Reserved */
+	uint16_t reserved0;
+	/** Multicast filter table address */
+	uint64_t multicast_address;
+	/** VLAN filter table (one bit per possible VLAN) */
+	uint8_t vlan_filter[512];
+} __attribute__ (( packed ));
+
+/** Receive filter mode */
+enum vmxnet3_rx_filter_mode {
+	VMXNET3_RXM_UCAST	= 0x01,  /**< Unicast only */
+	VMXNET3_RXM_MCAST	= 0x02,  /**< Multicast passing the filters */
+	VMXNET3_RXM_BCAST	= 0x04,  /**< Broadcast only */
+	VMXNET3_RXM_ALL_MULTI	= 0x08,  /**< All multicast */
+	VMXNET3_RXM_PROMISC	= 0x10,  /**< Promiscuous */
+};
+
+/** Variable-length configuration descriptor */
+struct vmxnet3_variable_config {
+	uint32_t version;
+	uint32_t length;
+	uint64_t address;
+} __attribute__ (( packed ));
+
+/** Driver shared area */
+struct vmxnet3_shared {
+	/** Magic signature */
+	uint32_t magic;
+	/** Reserved */
+	uint32_t reserved0;
+	/** Miscellaneous configuration */
+	struct vmxnet3_misc_config misc;
+	/** Interrupt configuration */
+	struct vmxnet3_interrupt_config interrupt;
+	/** Receive filter configuration */
+	struct vmxnet3_rx_filter_config rx_filter;
+	/** RSS configuration */
+	struct vmxnet3_variable_config rss;
+	/** Pattern-matching configuration */
+	struct vmxnet3_variable_config pattern;
+	/** Plugin configuration */
+	struct vmxnet3_variable_config plugin;
+	/** Event notifications */
+	uint32_t ecr;
+	/** Reserved */
+	uint32_t reserved1[5];
+} __attribute__ (( packed ));
+
+/** Alignment of driver shared area */
+#define VMXNET3_SHARED_ALIGN 8
+
+/** Driver shared area magic */
+#define VMXNET3_SHARED_MAGIC 0xbabefee1
+
+/** Transmit descriptor */
+struct vmxnet3_tx_desc {
+	/** Address */
+	uint64_t address;
+	/** Flags */
+	uint32_t flags[2];
+} __attribute__ (( packed ));
+
+/** Transmit generation flag */
+#define VMXNET3_TXF_GEN 0x00004000UL
+
+/** Transmit end-of-packet flag */
+#define VMXNET3_TXF_EOP 0x000001000UL
+
+/** Transmit completion request flag */
+#define VMXNET3_TXF_CQ 0x000002000UL
+
+/** Transmit completion descriptor */
+struct vmxnet3_tx_comp {
+	/** Index of the end-of-packet descriptor */
+	uint32_t index;
+	/** Reserved */
+	uint32_t reserved0[2];
+	/** Flags */
+	uint32_t flags;
+} __attribute__ (( packed ));
+
+/** Transmit completion generation flag */
+#define VMXNET3_TXCF_GEN 0x80000000UL
+
+/** Transmit queue control */
+struct vmxnet3_tx_queue_control {
+	uint32_t num_deferred;
+	uint32_t threshold;
+	uint64_t reserved0;
+} __attribute__ (( packed ));
+
+/** Transmit queue configuration */
+struct vmxnet3_tx_queue_config {
+	/** Descriptor ring address */
+	uint64_t desc_address;
+	/** Data ring address */
+	uint64_t immediate_address;
+	/** Completion ring address */
+	uint64_t comp_address;
+	/** Driver-private data address */
+	uint64_t driver_data_address;
+	/** Reserved */
+	uint64_t reserved0;
+	/** Number of descriptors */
+	uint32_t num_desc;
+	/** Number of data descriptors */
+	uint32_t num_immediate;
+	/** Number of completion descriptors */
+	uint32_t num_comp;
+	/** Driver-private data length */
+	uint32_t driver_data_len;
+	/** Interrupt index */
+	uint8_t intr_index;
+	/** Reserved */
+	uint8_t reserved[7];
+} __attribute__ (( packed ));
+
+/** Transmit queue statistics */
+struct vmxnet3_tx_stats {
+	/** Reserved */
+	uint64_t reserved[10];
+} __attribute__ (( packed ));
+
+/** Receive descriptor */
+struct vmxnet3_rx_desc {
+	/** Address */
+	uint64_t address;
+	/** Flags */
+	uint32_t flags;
+	/** Reserved */
+	uint32_t reserved0;
+} __attribute__ (( packed ));
+
+/** Receive generation flag */
+#define VMXNET3_RXF_GEN 0x80000000UL
+
+/** Receive completion descriptor */
+struct vmxnet3_rx_comp {
+	/** Descriptor index */
+	uint32_t index;
+	/** RSS hash value */
+	uint32_t rss;
+	/** Length */
+	uint32_t len;
+	/** Flags */
+	uint32_t flags;
+} __attribute__ (( packed ));
+
+/** Receive completion generation flag */
+#define VMXNET3_RXCF_GEN 0x80000000UL
+
+/** Receive queue control */
+struct vmxnet3_rx_queue_control {
+	uint8_t update_prod;
+	uint8_t reserved0[7];
+	uint64_t reserved1;
+} __attribute__ (( packed ));
+
+/** Receive queue configuration */
+struct vmxnet3_rx_queue_config {
+	/** Descriptor ring addresses */
+	uint64_t desc_address[2];
+	/** Completion ring address */
+	uint64_t comp_address;
+	/** Driver-private data address */
+	uint64_t driver_data_address;
+	/** Reserved */
+	uint64_t reserved0;
+	/** Number of descriptors */
+	uint32_t num_desc[2];
+	/** Number of completion descriptors */
+	uint32_t num_comp;
+	/** Driver-private data length */
+	uint32_t driver_data_len;
+	/** Interrupt index */
+	uint8_t intr_index;
+	/** Reserved */
+	uint8_t reserved[7];
+} __attribute__ (( packed ));
+
+/** Receive queue statistics */
+struct vmxnet3_rx_stats {
+	/** Reserved */
+	uint64_t reserved[10];
+} __attribute__ (( packed ));
+
+/** Queue status */
+struct vmxnet3_queue_status {
+	uint8_t stopped;
+	uint8_t reserved0[3];
+	uint32_t error;
+} __attribute__ (( packed ));
+
+/** Transmit queue descriptor */
+struct vmxnet3_tx_queue {
+	struct vmxnet3_tx_queue_control ctrl;
+	struct vmxnet3_tx_queue_config cfg;
+	struct vmxnet3_queue_status status;
+	struct vmxnet3_tx_stats state;
+	uint8_t reserved[88];
+} __attribute__ (( packed ));
+
+/** Receive queue descriptor */
+struct vmxnet3_rx_queue {
+	struct vmxnet3_rx_queue_control ctrl;
+	struct vmxnet3_rx_queue_config cfg;
+	struct vmxnet3_queue_status status;
+	struct vmxnet3_rx_stats stats;
+	uint8_t reserved[88];
+} __attribute__ (( packed ));
+
+/**
+ * Queue descriptor set
+ *
+ * We use only a single TX and RX queue
+ */
+struct vmxnet3_queues {
+	/** Transmit queue descriptor(s) */
+	struct vmxnet3_tx_queue tx;
+	/** Receive queue descriptor(s) */
+	struct vmxnet3_rx_queue rx;
+} __attribute__ (( packed ));
+
+/** Alignment of queue descriptor set */
+#define VMXNET3_QUEUES_ALIGN 128
+
+/** Alignment of rings */
+#define VMXNET3_RING_ALIGN 512
+
+/** Number of TX descriptors */
+#define VMXNET3_NUM_TX_DESC 32
+
+/** Number of TX completion descriptors */
+#define VMXNET3_NUM_TX_COMP 32
+
+/** Number of RX descriptors */
+#define VMXNET3_NUM_RX_DESC 32
+
+/** Number of RX completion descriptors */
+#define VMXNET3_NUM_RX_COMP 32
+
+/**
+ * DMA areas
+ *
+ * These are arranged in order of decreasing alignment, to allow for a
+ * single allocation
+ */
+struct vmxnet3_dma {
+	/** TX descriptor ring */
+	struct vmxnet3_tx_desc tx_desc[VMXNET3_NUM_TX_DESC];
+	/** TX completion ring */
+	struct vmxnet3_tx_comp tx_comp[VMXNET3_NUM_TX_COMP];
+	/** RX descriptor ring */
+	struct vmxnet3_rx_desc rx_desc[VMXNET3_NUM_RX_DESC];
+	/** RX completion ring */
+	struct vmxnet3_rx_comp rx_comp[VMXNET3_NUM_RX_COMP];
+	/** Queue descriptors */
+	struct vmxnet3_queues queues;
+	/** Shared area */
+	struct vmxnet3_shared shared;
+} __attribute__ (( packed ));
+
+/** DMA area alignment */
+#define VMXNET3_DMA_ALIGN 512
+
+/** Producer and consumer counters */
+struct vmxnet3_counters {
+	/** Transmit producer counter */
+	unsigned int tx_prod;
+	/** Transmit completion consumer counter */
+	unsigned int tx_cons;
+	/** Receive producer counter */
+	unsigned int rx_prod;
+	/** Receive fill level */
+	unsigned int rx_fill;
+	/** Receive consumer counter */
+	unsigned int rx_cons;
+};
+
+/** A vmxnet3 NIC */
+struct vmxnet3_nic {
+	/** "PT" register base address */
+	void *pt;
+	/** "VD" register base address */
+	void *vd;
+
+	/** DMA area */
+	struct vmxnet3_dma *dma;
+	/** Producer and consumer counters */
+	struct vmxnet3_counters count;
+	/** Transmit I/O buffers */
+	struct io_buffer *tx_iobuf[VMXNET3_NUM_TX_DESC];
+	/** Receive I/O buffers */
+	struct io_buffer *rx_iobuf[VMXNET3_NUM_RX_DESC];
+};
+
+/** vmxnet3 version that we support */
+#define VMXNET3_VERSION_SELECT 1
+
+/** UPT version that we support */
+#define VMXNET3_UPT_VERSION_SELECT 1
+
+/** MTU size */
+#define VMXNET3_MTU ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* FCS */ )
+
+/** Receive ring maximum fill level */
+#define VMXNET3_RX_FILL 8
+
+/** Received packet alignment padding */
+#define NET_IP_ALIGN 2
+
+#endif /* _VMXNET3_H */
diff --git a/roms/ipxe/src/drivers/net/vxge/vxge_main.c b/roms/ipxe/src/drivers/net/vxge/vxge_main.c
index b8533d311ac7ff7e3b8c93736fb8..130eab61786e236de8dba1304cb4 100644
--- a/roms/ipxe/src/drivers/net/vxge/vxge_main.c
+++ b/roms/ipxe/src/drivers/net/vxge/vxge_main.c
@@ -252,7 +252,7 @@ static void vxge_poll(struct net_device *ndev)
 /*
  * vxge_irq - enable or Disable interrupts
  *
- * @netdev   netdevice sturcture reference
+ * @netdev   netdevice structure reference
  * @action   requested interrupt action
  */
 static void vxge_irq(struct net_device *netdev __unused, int action)
diff --git a/roms/ipxe/src/drivers/net/w89c840.c b/roms/ipxe/src/drivers/net/w89c840.c
index b3149550f4c0954ac9a82980f11e..ce638ab998e25876627ccdab3f8c 100644
--- a/roms/ipxe/src/drivers/net/w89c840.c
+++ b/roms/ipxe/src/drivers/net/w89c840.c
@@ -26,7 +26,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/nvs/nvs.c b/roms/ipxe/src/drivers/nvs/nvs.c
index a4a06ccff547bff4bfbd1488a7c0..ccb2145bdcca89dcb1bb84b36ac7 100644
--- a/roms/ipxe/src/drivers/nvs/nvs.c
+++ b/roms/ipxe/src/drivers/nvs/nvs.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/nvs/nvsvpd.c b/roms/ipxe/src/drivers/nvs/nvsvpd.c
index a22ec825f927b44699df6d0131fe..33148d5b9736091d863cc3d74391 100644
--- a/roms/ipxe/src/drivers/nvs/nvsvpd.c
+++ b/roms/ipxe/src/drivers/nvs/nvsvpd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/nvs/spi.c b/roms/ipxe/src/drivers/nvs/spi.c
index e12aeff66e38116d7e05108bad12..84613b9ddf08105289972c73e4f5 100644
--- a/roms/ipxe/src/drivers/nvs/spi.c
+++ b/roms/ipxe/src/drivers/nvs/spi.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/drivers/nvs/threewire.c b/roms/ipxe/src/drivers/nvs/threewire.c
index 047091fd54c4794283e965e2f920..53f1ad8dee4d4e3a2a7274718df9 100644
--- a/roms/ipxe/src/drivers/nvs/threewire.c
+++ b/roms/ipxe/src/drivers/nvs/threewire.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/hci/commands/autoboot_cmd.c b/roms/ipxe/src/hci/commands/autoboot_cmd.c
index 0917f6fa1a398021f033606c0b0e..f3886b1f6954db1865f91b10db90 100644
--- a/roms/ipxe/src/hci/commands/autoboot_cmd.c
+++ b/roms/ipxe/src/hci/commands/autoboot_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #include <stdio.h>
diff --git a/roms/ipxe/src/hci/commands/config_cmd.c b/roms/ipxe/src/hci/commands/config_cmd.c
index e447d6af3b8a21c656c873e4b56a..f1fb567c2b21e2d98084a6bd84d7 100644
--- a/roms/ipxe/src/hci/commands/config_cmd.c
+++ b/roms/ipxe/src/hci/commands/config_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #include <string.h>
diff --git a/roms/ipxe/src/hci/commands/dhcp_cmd.c b/roms/ipxe/src/hci/commands/dhcp_cmd.c
index acf3cfdaad655426ed0536282c38..279620c32ebae748280da4cee212 100644
--- a/roms/ipxe/src/hci/commands/dhcp_cmd.c
+++ b/roms/ipxe/src/hci/commands/dhcp_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/hci/commands/digest_cmd.c b/roms/ipxe/src/hci/commands/digest_cmd.c
index 6ca12eff16e2908a9306268be5f3..3cf2f10267de1529cce1c48dca84 100644
--- a/roms/ipxe/src/hci/commands/digest_cmd.c
+++ b/roms/ipxe/src/hci/commands/digest_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -28,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/crypto.h>
 #include <ipxe/md5.h>
 #include <ipxe/sha1.h>
+#include <usr/imgmgmt.h>
 
 /** @file
  *
@@ -74,8 +76,8 @@ static int digest_exec ( int argc, char **argv,
 
 	for ( i = optind ; i < argc ; i++ ) {
 
-		/* find image */
-		if ( ( rc = parse_image ( argv[i], &image ) ) != 0 )
+		/* Acquire image */
+		if ( ( rc = imgacquire ( argv[i], &image ) ) != 0 )
 			continue;
 		offset = 0;
 		len = image->len;
diff --git a/roms/ipxe/src/hci/commands/fcmgmt_cmd.c b/roms/ipxe/src/hci/commands/fcmgmt_cmd.c
index a2b818ec336cee490a3aca1904f8..b7e38040cd9d9647d5c4427ea6cb 100644
--- a/roms/ipxe/src/hci/commands/fcmgmt_cmd.c
+++ b/roms/ipxe/src/hci/commands/fcmgmt_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/hci/commands/gdbstub_cmd.c b/roms/ipxe/src/hci/commands/gdbstub_cmd.c
index f35f0140b6252c4d4c9acd7a768a..33890aebc9fb3073badc850cc9b0 100644
--- a/roms/ipxe/src/hci/commands/gdbstub_cmd.c
+++ b/roms/ipxe/src/hci/commands/gdbstub_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/hci/commands/ifmgmt_cmd.c b/roms/ipxe/src/hci/commands/ifmgmt_cmd.c
index 29691d4efa050efb8f5e35330932..3f3f6b51cd220e94ea4cfe7ad5b9 100644
--- a/roms/ipxe/src/hci/commands/ifmgmt_cmd.c
+++ b/roms/ipxe/src/hci/commands/ifmgmt_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/hci/commands/image_cmd.c b/roms/ipxe/src/hci/commands/image_cmd.c
index 1ff3ff49be4c8972b97842c3ee3d..6f51a6ba2a0ade3b380692bf381e 100644
--- a/roms/ipxe/src/hci/commands/image_cmd.c
+++ b/roms/ipxe/src/hci/commands/image_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -26,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/image.h>
 #include <ipxe/command.h>
 #include <ipxe/parseopt.h>
+#include <ipxe/shell.h>
 #include <usr/imgmgmt.h>
 
 /** @file
@@ -34,167 +36,258 @@ FILE_LICENCE ( GPL2_OR_LATER );
  *
  */
 
-/** "imgfetch" options */
-struct imgfetch_options {
+/** "img{single}" options */
+struct imgsingle_options {
 	/** Image name */
 	const char *name;
+	/** Replace image */
+	int replace;
+	/** Free image after execution */
+	int autofree;
 };
 
-/** "imgfetch" option list */
-static struct option_descriptor imgfetch_opts[] = {
+/** "img{single}" option list */
+static struct option_descriptor imgsingle_opts[] = {
 	OPTION_DESC ( "name", 'n', required_argument,
-		      struct imgfetch_options, name, parse_string ),
+		      struct imgsingle_options, name, parse_string ),
+	OPTION_DESC ( "replace", 'r', no_argument,
+		      struct imgsingle_options, replace, parse_flag ),
+	OPTION_DESC ( "autofree", 'a', no_argument,
+		      struct imgsingle_options, autofree, parse_flag ),
 };
 
-/** "imgfetch" command descriptor */
-static struct command_descriptor imgfetch_cmd =
-	COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS,
-		       "[--name <name>] <uri> [<arguments>...]" );
+/** "img{single}" command descriptor */
+static struct command_descriptor imgsingle_cmd =
+	COMMAND_DESC ( struct imgsingle_options, imgsingle_opts,
+		       1, MAX_ARGUMENTS,
+		       "[--name <name>] [--autofree] "
+		       "<uri|image> [<arguments>...]" );
+
+/** An "img{single}" family command descriptor */
+struct imgsingle_descriptor {
+	/** Command descriptor */
+	struct command_descriptor *cmd;
+	/** Function to use to acquire the image */
+	int ( * acquire ) ( const char *name, struct image **image );
+	/** Pre-action to take upon image, or NULL */
+	void ( * preaction ) ( struct image *image );
+	/** Action to take upon image, or NULL */
+	int ( * action ) ( struct image *image,
+			   struct imgsingle_options *opts );
+	/** Verb to describe action */
+	const char *verb;
+};
 
 /**
- * The "imgfetch" and friends command body
+ * The "img{single}" family of commands
  *
  * @v argc		Argument count
  * @v argv		Argument list
- * @v cmd		Command descriptor
+ * @v desc		"img{single}" command descriptor
  * @v action_name	Action name (for error messages)
- * @v action		Action to take upon a successful download
+ * @v action		Action to take upon image
  * @ret rc		Return status code
  */
-static int imgfetch_core_exec ( int argc, char **argv,
-				const char *action_name,
-				int ( * action ) ( struct image *image ) ) {
-	struct imgfetch_options opts;
-	char *uri_string;
+static int imgsingle_exec ( int argc, char **argv,
+			    struct imgsingle_descriptor *desc ) {
+	struct imgsingle_options opts;
+	char *name_uri = NULL;
 	char *cmdline = NULL;
+	struct image *image;
 	int rc;
 
 	/* Parse options */
-	if ( ( rc = parse_options ( argc, argv, &imgfetch_cmd, &opts ) ) != 0 )
+	if ( ( rc = parse_options ( argc, argv, desc->cmd, &opts ) ) != 0 )
 		goto err_parse_options;
 
-	/* Parse URI string */
-	uri_string = argv[optind];
+	/* Parse name/URI string and command line, if present */
+	if ( optind < argc ) {
+		name_uri = argv[optind];
+		if ( argv[ optind + 1 ] != NULL ) {
+			cmdline = concat_args ( &argv[ optind + 1 ] );
+			if ( ! cmdline ) {
+				rc = -ENOMEM;
+				goto err_parse_cmdline;
+			}
+		}
+	}
 
-	/* Parse command line */
-	if ( argv[ optind + 1 ] != NULL ) {
-		cmdline = concat_args ( &argv[ optind + 1 ] );
-		if ( ! cmdline ) {
-			rc = -ENOMEM;
-			goto err_cmdline;
+	/* Acquire the image */
+	if ( name_uri ) {
+		if ( ( rc = desc->acquire ( name_uri, &image ) ) != 0 )
+			goto err_acquire;
+	} else {
+		image = image_find_selected();
+		if ( ! image ) {
+			printf ( "No image selected\n" );
+			goto err_acquire;
 		}
 	}
 
-	/* Fetch the image */
-	if ( ( rc = imgdownload_string ( uri_string, opts.name, cmdline,
-					 action ) ) != 0 ) {
-		printf ( "Could not %s %s: %s\n",
-			 action_name, uri_string, strerror ( rc ) );
-		goto err_imgdownload;
+	/* Carry out command pre-action, if applicable */
+	if ( desc->preaction )
+		desc->preaction ( image );
+
+	/* Set the image name, if applicable */
+	if ( opts.name ) {
+		if ( ( rc = image_set_name ( image, opts.name ) ) != 0 ) {
+			printf ( "Could not name image: %s\n",
+				 strerror ( rc ) );
+			goto err_set_name;
+		}
 	}
 
-	/* Free command line */
-	free ( cmdline );
+	/* Set the command-line arguments, if applicable */
+	if ( cmdline ) {
+		if ( ( rc = image_set_cmdline ( image, cmdline ) ) != 0 ) {
+			printf ( "Could not set arguments: %s\n",
+				 strerror ( rc ) );
+			goto err_set_cmdline;
+		}
+	}
 
-	return 0;
+	/* Set the auto-unregister flag, if applicable */
+	if ( opts.autofree )
+		image->flags |= IMAGE_AUTO_UNREGISTER;
 
- err_imgdownload:
+	/* Carry out command action, if applicable */
+	if ( desc->action ) {
+		if ( ( rc = desc->action ( image, &opts ) ) != 0 ) {
+			printf ( "Could not %s: %s\n",
+				 desc->verb, strerror ( rc ) );
+			goto err_action;
+		}
+	}
+
+	/* Success */
+	rc = 0;
+
+ err_action:
+ err_set_cmdline:
+ err_set_name:
+ err_acquire:
 	free ( cmdline );
- err_cmdline:
+ err_parse_cmdline:
  err_parse_options:
 	return rc;
 }
 
+/** "imgfetch" command descriptor */
+static struct command_descriptor imgfetch_cmd =
+	COMMAND_DESC ( struct imgsingle_options, imgsingle_opts,
+		       1, MAX_ARGUMENTS,
+		       "[--name <name>] [--autofree] <uri> [<arguments>...]" );
+
+/** "imgfetch" family command descriptor */
+struct imgsingle_descriptor imgfetch_desc = {
+	.cmd = &imgfetch_cmd,
+	.acquire = imgdownload_string,
+};
+
 /**
- * The "imgfetch"/"module" command
+ * The "imgfetch" command
  *
  * @v argc		Argument count
  * @v argv		Argument list
  * @ret rc		Return status code
  */
 static int imgfetch_exec ( int argc, char **argv ) {
-
-	return imgfetch_core_exec ( argc, argv, "fetch",
-				    register_and_put_image );
+	return imgsingle_exec ( argc, argv, &imgfetch_desc );
 }
 
 /**
- * The "kernel" command
+ * "imgselect" command action
  *
- * @v argc		Argument count
- * @v argv		Argument list
+ * @v image		Image
+ * @v opts		Options
  * @ret rc		Return status code
  */
-static int kernel_exec ( int argc, char **argv ) {
-
-	return imgfetch_core_exec ( argc, argv, "select",
-				    register_and_select_image );
+static int imgselect ( struct image *image,
+		       struct imgsingle_options *opts __unused ) {
+	return image_select ( image );
 }
 
+/** "imgselect" family command descriptor */
+struct imgsingle_descriptor imgselect_desc = {
+	.cmd = &imgsingle_cmd,
+	.acquire = imgacquire,
+	.action = imgselect,
+	.verb = "select",
+};
+
 /**
- * The "chain" command
+ * The "imgselect" command
  *
  * @v argc		Argument count
  * @v argv		Argument list
  * @ret rc		Return status code
  */
-static int chain_exec ( int argc, char **argv) {
-
-	return imgfetch_core_exec ( argc, argv, "boot",
-				    register_and_boot_image );
+static int imgselect_exec ( int argc, char **argv ) {
+	return imgsingle_exec ( argc, argv, &imgselect_desc );
 }
 
-/** "imgselect" options */
-struct imgselect_options {};
-
-/** "imgselect" option list */
-static struct option_descriptor imgselect_opts[] = {};
-
-/** "imgselect" command descriptor */
-static struct command_descriptor imgselect_cmd =
-	COMMAND_DESC ( struct imgselect_options, imgselect_opts, 1, 1,
-		       "<image>" );
+/** "imgexec" command descriptor */
+static struct command_descriptor imgexec_cmd =
+	COMMAND_DESC ( struct imgsingle_options, imgsingle_opts,
+		       0, MAX_ARGUMENTS,
+		       "[--autofree] [--replace] "
+		       "[<uri|image> [<arguments>...]]" );
 
 /**
- * The "imgselect" command
+ * "imgexec" command action
  *
- * @v argc		Argument count
- * @v argv		Argument list
+ * @v image		Image
+ * @v opts		Options
  * @ret rc		Return status code
  */
-static int imgselect_exec ( int argc, char **argv ) {
-	struct imgselect_options opts;
-	struct image *image;
+static int imgexec ( struct image *image, struct imgsingle_options *opts ) {
 	int rc;
 
-	/* Parse options */
-	if ( ( rc = parse_options ( argc, argv, &imgselect_cmd, &opts ) ) != 0 )
-		return rc;
+	/* Perform replacement or execution as applicable */
+	if ( opts->replace ) {
 
-	/* Parse image name */
-	if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 )
-		return rc;
+		/* Try to replace image */
+		if ( ( rc = image_replace ( image ) ) != 0 )
+			return rc;
 
-	/* Load image */
-	if ( ( rc = imgselect ( image ) ) != 0 ) {
-		printf ( "Could not select %s: %s\n",
-			 image->name, strerror ( rc ) );
-		return rc;
+		/* Stop script and tail-recurse into replacement image */
+		shell_stop ( SHELL_STOP_COMMAND_SEQUENCE );
+
+	} else {
+
+		/* Try to execute image */
+		if ( ( rc = image_exec ( image ) ) != 0 )
+			return rc;
 	}
 
 	return 0;
 }
 
-/** "imgargs" options */
-struct imgargs_options {};
+/** "imgexec" family command descriptor */
+struct imgsingle_descriptor imgexec_desc = {
+	.cmd = &imgexec_cmd,
+	.acquire = imgacquire,
+	.action = imgexec,
+	.verb = "boot",
+};
 
-/** "imgargs" option list */
-static struct option_descriptor imgargs_opts[] = {};
+/**
+ * The "imgexec" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int imgexec_exec ( int argc, char **argv) {
+	return imgsingle_exec ( argc, argv, &imgexec_desc );
+}
 
-/** "imgargs" command descriptor */
-static struct command_descriptor imgargs_cmd =
-	COMMAND_DESC ( struct imgargs_options, imgargs_opts, 1, MAX_ARGUMENTS,
-		       "<image> [<arguments>...]" );
+/** "imgargs" family command descriptor */
+struct imgsingle_descriptor imgargs_desc = {
+	.cmd = &imgsingle_cmd,
+	.acquire = imgacquire,
+	.preaction = image_clear_cmdline,
+};
 
 /**
  * The "imgargs" command body
@@ -204,105 +297,60 @@ static struct command_descriptor imgargs_cmd =
  * @ret rc		Return status code
  */
 static int imgargs_exec ( int argc, char **argv ) {
-	struct imgargs_options opts;
-	struct image *image;
-	char *cmdline = NULL;
-	int rc;
-
-	/* Parse options */
-	if ( ( rc = parse_options ( argc, argv, &imgargs_cmd, &opts ) ) != 0 )
-		goto err_parse_options;
-
-	/* Parse image name */
-	if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 )
-		goto err_parse_image;
-
-	/* Parse command line */
-	if ( argv[ optind + 1 ] != NULL ) {
-		cmdline = concat_args ( &argv[ optind + 1 ] );
-		if ( ! cmdline ) {
-			rc = -ENOMEM;
-			goto err_cmdline;
-		}
-	}
-
-	/* Set command line */
-	if ( ( rc = image_set_cmdline ( image, cmdline ) ) != 0 )
-		goto err_set_cmdline;
-
-	/* Free command line */
-	free ( cmdline );
-
-	return 0;
-
- err_set_cmdline:
-	free ( cmdline );
- err_cmdline:
- err_parse_image:
- err_parse_options:
-	return rc;
+	return imgsingle_exec ( argc, argv, &imgargs_desc );
 }
 
-/** "imgexec" options */
-struct imgexec_options {};
+/** "img{multi}" options */
+struct imgmulti_options {};
 
-/** "imgexec" option list */
-static struct option_descriptor imgexec_opts[] = {};
+/** "img{multi}" option list */
+static struct option_descriptor imgmulti_opts[] = {};
 
-/** "imgexec" command descriptor */
-static struct command_descriptor imgexec_cmd =
-	COMMAND_DESC ( struct imgexec_options, imgexec_opts, 0, 1,
-		       "[<image>]" );
+/** "img{multi}" command descriptor */
+static struct command_descriptor imgmulti_cmd =
+	COMMAND_DESC ( struct imgmulti_options, imgmulti_opts, 0, MAX_ARGUMENTS,
+		       "[<image>...]" );
 
 /**
- * The "imgexec" command
+ * The "img{multi}" family of commands
  *
  * @v argc		Argument count
  * @v argv		Argument list
+ * @v payload		Function to execute on each image
  * @ret rc		Return status code
  */
-static int imgexec_exec ( int argc, char **argv ) {
-	struct imgexec_options opts;
+static int imgmulti_exec ( int argc, char **argv,
+			   void ( * payload ) ( struct image *image ) ) {
+	struct imgmulti_options opts;
 	struct image *image;
+	struct image *tmp;
+	int i;
 	int rc;
 
 	/* Parse options */
-	if ( ( rc = parse_options ( argc, argv, &imgexec_cmd, &opts ) ) != 0 )
+	if ( ( rc = parse_options ( argc, argv, &imgmulti_cmd, &opts ) ) != 0 )
 		return rc;
 
-	/* Parse image name */
-	if ( optind < argc ) {
-		if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 )
-			return rc;
-	} else {
-		image = imgautoselect();
-		if ( ! image ) {
-			rc = -ENOTTY;
-			printf ( "No image selected: %s\n", strerror ( rc ) );
-			return rc;
-		}
+	/* If no images are explicitly specified, process all images */
+	if ( optind == argc ) {
+		for_each_image_safe ( image, tmp )
+			payload ( image );
+		return 0;
 	}
 
-	/* Execute image */
-	if ( ( rc = imgexec ( image ) ) != 0 ) {
-		printf ( "Could not execute %s: %s\n",
-			 image->name, strerror ( rc ) );
-		return rc;
+	/* Otherwise, process specified images */
+	for ( i = optind ; i < argc ; i++ ) {
+		image = find_image ( argv[i] );
+		if ( ! image ) {
+			printf ( "\"%s\": no such image\n", argv[i] );
+			return -ENOENT;
+		}
+		payload ( image );
 	}
 
 	return 0;
 }
 
-/** "imgstat" options */
-struct imgstat_options {};
-
-/** "imgstat" option list */
-static struct option_descriptor imgstat_opts[] = {};
-
-/** "imgstat" command descriptor */
-static struct command_descriptor imgstat_cmd =
-	COMMAND_DESC ( struct imgstat_options, imgstat_opts, 0, 0, "" );
-
 /**
  * The "imgstat" command
  *
@@ -311,33 +359,9 @@ static struct command_descriptor imgstat_cmd =
  * @ret rc		Return status code
  */
 static int imgstat_exec ( int argc, char **argv ) {
-	struct imgstat_options opts;
-	struct image *image;
-	int rc;
-
-	/* Parse options */
-	if ( ( rc = parse_options ( argc, argv, &imgstat_cmd, &opts ) ) != 0 )
-		return rc;
-
-	/* Show status of all images */
-	for_each_image ( image ) {
-		imgstat ( image );
-	}
-
-	return 0;
+	return imgmulti_exec ( argc, argv, imgstat );
 }
 
-/** "imgfree" options */
-struct imgfree_options {};
-
-/** "imgfree" option list */
-static struct option_descriptor imgfree_opts[] = {};
-
-/** "imgfree" command descriptor */
-static struct command_descriptor imgfree_cmd =
-	COMMAND_DESC ( struct imgfree_options, imgfree_opts, 0, 1,
-		       "[<image>]" );
-
 /**
  * The "imgfree" command
  *
@@ -346,28 +370,7 @@ static struct command_descriptor imgfree_cmd =
  * @ret rc		Return status code
  */
 static int imgfree_exec ( int argc, char **argv ) {
-	struct imgfree_options opts;
-	struct image *image;
-	struct image *tmp;
-	int rc;
-
-	/* Parse options */
-	if ( ( rc = parse_options ( argc, argv, &imgfree_cmd, &opts ) ) != 0 )
-		return rc;
-
-	if ( optind < argc ) {
-		/* Free specified image */
-		if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 )
-			return rc;
-		imgfree ( image );
-	} else {
-		/* Free all images */
-		list_for_each_entry_safe ( image, tmp, &images, list ) {
-			imgfree ( image );
-		}
-	}
-
-	return 0;
+	return imgmulti_exec ( argc, argv, unregister_image );
 }
 
 /** Image management commands */
@@ -386,19 +389,19 @@ struct command image_commands[] __command = {
 	},
 	{
 		.name = "kernel",
-		.exec = kernel_exec,
+		.exec = imgselect_exec, /* synonym for "imgselect" */
 	},
 	{
 		.name = "chain",
-		.exec = chain_exec,
+		.exec = imgexec_exec, /* synonym for "imgexec" */
 	},
 	{
 		.name = "imgselect",
 		.exec = imgselect_exec,
 	},
 	{
-		.name = "imgload", /* synonym for "imgselect" */
-		.exec = imgselect_exec,
+		.name = "imgload",
+		.exec = imgselect_exec, /* synonym for "imgselect" */
 	},
 	{
 		.name = "imgargs",
diff --git a/roms/ipxe/src/hci/commands/image_trust_cmd.c b/roms/ipxe/src/hci/commands/image_trust_cmd.c
new file mode 100644
index 0000000000000000000000000000000000000000..e7a2bf122c33ba82f4edf248ec79e23a090c6424
--- /dev/null
+++ b/roms/ipxe/src/hci/commands/image_trust_cmd.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <ipxe/image.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <usr/imgmgmt.h>
+#include <usr/imgtrust.h>
+
+/** @file
+ *
+ * Image trust management commands
+ *
+ */
+
+/** "imgtrust" options */
+struct imgtrust_options {
+	/** Allow trusted images */
+	int allow;
+	/** Make trust requirement permanent */
+	int permanent;
+};
+
+/** "imgtrust" option list */
+static struct option_descriptor imgtrust_opts[] = {
+	OPTION_DESC ( "allow", 'a', no_argument,
+		      struct imgtrust_options, allow, parse_flag ),
+	OPTION_DESC ( "permanent", 'p', no_argument,
+		      struct imgtrust_options, permanent, parse_flag ),
+};
+
+/** "imgtrust" command descriptor */
+static struct command_descriptor imgtrust_cmd =
+	COMMAND_DESC ( struct imgtrust_options, imgtrust_opts, 0, 0,
+		       "[--allow] [--permanent]" );
+
+/**
+ * The "imgtrust" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int imgtrust_exec ( int argc, char **argv ) {
+	struct imgtrust_options opts;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &imgtrust_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Set trust requirement */
+	if ( ( rc = image_set_trust ( ( ! opts.allow ),
+				      opts.permanent ) ) != 0 ) {
+		printf ( "Could not set image trust requirement: %s\n",
+			 strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/** "imgverify" options */
+struct imgverify_options {
+	/** Required signer common name */
+	const char *signer;
+	/** Keep signature after verification */
+	int keep;
+};
+
+/** "imgverify" option list */
+static struct option_descriptor imgverify_opts[] = {
+	OPTION_DESC ( "signer", 's', required_argument,
+		      struct imgverify_options, signer, parse_string ),
+	OPTION_DESC ( "keep", 'k', no_argument,
+		      struct imgverify_options, keep, parse_flag ),
+};
+
+/** "imgverify" command descriptor */
+static struct command_descriptor imgverify_cmd =
+	COMMAND_DESC ( struct imgverify_options, imgverify_opts, 2, 2,
+		       "[--signer <signer>] [--keep] <uri|image> "
+		       "<signature uri|image>" );
+
+/**
+ * The "imgverify" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int imgverify_exec ( int argc, char **argv ) {
+	struct imgverify_options opts;
+	const char *image_name_uri;
+	const char *signature_name_uri;
+	struct image *image;
+	struct image *signature;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &imgverify_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse image name/URI string */
+	image_name_uri = argv[optind];
+
+	/* Parse signature name/URI string */
+	signature_name_uri = argv[ optind + 1 ];
+
+	/* Acquire the image */
+	if ( ( rc = imgacquire ( image_name_uri, &image ) ) != 0 )
+		goto err_acquire_image;
+
+	/* Acquire the signature image */
+	if ( ( rc = imgacquire ( signature_name_uri, &signature ) ) != 0 )
+		goto err_acquire_signature;
+
+	/* Verify image */
+	if ( ( rc = imgverify ( image, signature, opts.signer ) ) != 0 ) {
+		printf ( "Could not verify: %s\n", strerror ( rc ) );
+		goto err_verify;
+	}
+
+	/* Success */
+	rc = 0;
+
+ err_verify:
+	/* Discard signature unless --keep was specified */
+	if ( ! opts.keep )
+		unregister_image ( signature );
+ err_acquire_signature:
+ err_acquire_image:
+	return rc;
+}
+
+/** Image trust management commands */
+struct command image_trust_commands[] __command = {
+	{
+		.name = "imgtrust",
+		.exec = imgtrust_exec,
+	},
+	{
+		.name = "imgverify",
+		.exec = imgverify_exec,
+	},
+};
+
+/* Drag in objects typically required for signature verification */
+REQUIRE_OBJECT ( rsa );
+REQUIRE_OBJECT ( md5 );
+REQUIRE_OBJECT ( sha1 );
+REQUIRE_OBJECT ( sha256 );
diff --git a/roms/ipxe/src/hci/commands/iwmgmt_cmd.c b/roms/ipxe/src/hci/commands/iwmgmt_cmd.c
index 00a8360db9c0a83b3ad119cb8fa6..d91ad1e3435d3363d84ed97d3f78 100644
--- a/roms/ipxe/src/hci/commands/iwmgmt_cmd.c
+++ b/roms/ipxe/src/hci/commands/iwmgmt_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/hci/commands/login_cmd.c b/roms/ipxe/src/hci/commands/login_cmd.c
index 3286932d00e57f9d5d15ea1f9fe8..bc23e6ff52c370f456f55f5f9715 100644
--- a/roms/ipxe/src/hci/commands/login_cmd.c
+++ b/roms/ipxe/src/hci/commands/login_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #include <string.h>
diff --git a/roms/ipxe/src/hci/commands/lotest_cmd.c b/roms/ipxe/src/hci/commands/lotest_cmd.c
index 172be2d8ce77d1906dd76d42c3b6..92f08887aedb06500c23b4fd0c8d 100644
--- a/roms/ipxe/src/hci/commands/lotest_cmd.c
+++ b/roms/ipxe/src/hci/commands/lotest_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/hci/commands/menu_cmd.c b/roms/ipxe/src/hci/commands/menu_cmd.c
new file mode 100644
index 0000000000000000000000000000000000000000..10966db273fd91b44bbe53c71593294cae6685bc
--- /dev/null
+++ b/roms/ipxe/src/hci/commands/menu_cmd.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Menu commands
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ipxe/menu.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/settings.h>
+#include <ipxe/features.h>
+
+FEATURE ( FEATURE_MISC, "Menu", DHCP_EB_FEATURE_MENU, 1 );
+
+/** "menu" options */
+struct menu_options {
+	/** Name */
+	const char *name;
+	/** Delete */
+	int delete;
+};
+
+/** "menu" option list */
+static struct option_descriptor menu_opts[] = {
+	OPTION_DESC ( "name", 'n', required_argument,
+		      struct menu_options, name, parse_string ),
+	OPTION_DESC ( "delete", 'd', no_argument,
+		      struct menu_options, delete, parse_flag ),
+};
+
+/** "menu" command descriptor */
+static struct command_descriptor menu_cmd =
+	COMMAND_DESC ( struct menu_options, menu_opts, 0, MAX_ARGUMENTS,
+		       "[--name <name>] [--delete] [<title>]" );
+
+/**
+ * The "menu" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int menu_exec ( int argc, char **argv ) {
+	struct menu_options opts;
+	struct menu *menu;
+	char *title;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &menu_cmd, &opts ) ) != 0 )
+		goto err_parse_options;
+
+	/* Parse title */
+	title = concat_args ( &argv[optind] );
+	if ( ! title ) {
+		rc = -ENOMEM;
+		goto err_parse_title;
+	}
+
+	/* Create menu */
+	menu = create_menu ( opts.name, title );
+	if ( ! menu ) {
+		rc = -ENOMEM;
+		goto err_create_menu;
+	}
+
+	/* Destroy menu, if applicable */
+	if ( opts.delete )
+		destroy_menu ( menu );
+
+	/* Success */
+	rc = 0;
+
+ err_create_menu:
+	free ( title );
+ err_parse_title:
+ err_parse_options:
+	return rc;
+}
+
+/** "item" options */
+struct item_options {
+	/** Menu name */
+	const char *menu;
+	/** Shortcut key */
+	unsigned int key;
+	/** Use as default */
+	int is_default;
+	/** Use as a separator */
+	int is_gap;
+};
+
+/** "item" option list */
+static struct option_descriptor item_opts[] = {
+	OPTION_DESC ( "menu", 'm', required_argument,
+		      struct item_options, menu, parse_string ),
+	OPTION_DESC ( "key", 'k', required_argument,
+		      struct item_options, key, parse_key ),
+	OPTION_DESC ( "default", 'd', no_argument,
+		      struct item_options, is_default, parse_flag ),
+	OPTION_DESC ( "gap", 'g', no_argument,
+		      struct item_options, is_gap, parse_flag ),
+};
+
+/** "item" command descriptor */
+static struct command_descriptor item_cmd =
+	COMMAND_DESC ( struct item_options, item_opts, 0, MAX_ARGUMENTS,
+		       "[--menu <menu>] [--key <key>] [--default] "
+		       "[<label>|--gap [<text>]]" );
+
+/**
+ * The "item" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int item_exec ( int argc, char **argv ) {
+	struct item_options opts;
+	struct menu *menu;
+	struct menu_item *item;
+	char *label = NULL;
+	char *text = NULL;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &item_cmd, &opts ) ) != 0 )
+		goto err_parse_options;
+
+	/* Parse label, if present */
+	if ( ! opts.is_gap )
+		label = argv[optind++]; /* May be NULL */
+
+	/* Parse text, if present */
+	if ( optind < argc ) {
+		text = concat_args ( &argv[optind] );
+		if ( ! text ) {
+			rc = -ENOMEM;
+			goto err_parse_text;
+		}
+	}
+
+	/* Identify menu */
+	if ( ( rc = parse_menu ( opts.menu, &menu ) ) != 0 )
+		goto err_parse_menu;
+
+	/* Add menu item */
+	item = add_menu_item ( menu, label, ( text ? text : "" ),
+			       opts.key, opts.is_default );
+	if ( ! item ) {
+		rc = -ENOMEM;
+		goto err_add_menu_item;
+	}
+
+	/* Success */
+	rc = 0;
+
+ err_add_menu_item:
+ err_parse_menu:
+	free ( text );
+ err_parse_text:
+ err_parse_options:
+	return rc;
+}
+
+/** "choose" options */
+struct choose_options {
+	/** Menu name */
+	const char *menu;
+	/** Timeout */
+	unsigned int timeout;
+	/** Default selection */
+	const char *select;
+	/** Keep menu */
+	int keep;
+};
+
+/** "choose" option list */
+static struct option_descriptor choose_opts[] = {
+	OPTION_DESC ( "menu", 'm', required_argument,
+		      struct choose_options, menu, parse_string ),
+	OPTION_DESC ( "default", 'd', required_argument,
+		      struct choose_options, select, parse_string ),
+	OPTION_DESC ( "timeout", 't', required_argument,
+		      struct choose_options, timeout, parse_integer ),
+	OPTION_DESC ( "keep", 'k', no_argument,
+		      struct choose_options, keep, parse_flag ),
+};
+
+/** "choose" command descriptor */
+static struct command_descriptor choose_cmd =
+	COMMAND_DESC ( struct choose_options, choose_opts, 1, 1,
+		       "[--menu <menu>] [--default <label>] "
+		       "[--timeout <timeout>] [--keep] <setting>" );
+
+/**
+ * The "choose" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int choose_exec ( int argc, char **argv ) {
+	struct choose_options opts;
+	struct menu *menu;
+	struct menu_item *item;
+	const char *setting;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &choose_cmd, &opts ) ) != 0 )
+		goto err_parse_options;
+
+	/* Parse setting name */
+	setting = argv[optind];
+
+	/* Identify menu */
+	if ( ( rc = parse_menu ( opts.menu, &menu ) ) != 0 )
+		goto err_parse_menu;
+
+	/* Show menu */
+	if ( ( rc = show_menu ( menu, opts.timeout, opts.select, &item ) ) != 0)
+		goto err_show_menu;
+
+	/* Store setting */
+	if ( ( rc = storef_named_setting ( setting, &setting_type_string,
+					   item->label ) ) != 0 ) {
+		printf ( "Could not store \"%s\": %s\n",
+			 setting, strerror ( rc ) );
+		goto err_store;
+	}
+
+	/* Success */
+	rc = 0;
+
+ err_store:
+ err_show_menu:
+	/* Destroy menu, if applicable */
+	if ( ! opts.keep )
+		destroy_menu ( menu );
+ err_parse_menu:
+ err_parse_options:
+	return rc;
+}
+
+/** Menu commands */
+struct command menu_commands[] __command = {
+	{
+		.name = "menu",
+		.exec = menu_exec,
+	},
+	{
+		.name = "item",
+		.exec = item_exec,
+	},
+	{
+		.name = "choose",
+		.exec = choose_exec,
+	},
+};
diff --git a/roms/ipxe/src/hci/commands/nslookup_cmd.c b/roms/ipxe/src/hci/commands/nslookup_cmd.c
new file mode 100644
index 0000000000000000000000000000000000000000..265afdc3d297f707ae0586fc8b6cd20915de323f
--- /dev/null
+++ b/roms/ipxe/src/hci/commands/nslookup_cmd.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2012 Patrick Plenefisch <phplenefisch@wpi.edu>.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <getopt.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <usr/nslookup.h>
+
+/** @file
+ *
+ * nslookup command
+ *
+ */
+
+/** "nslookup" options */
+struct nslookup_options {};
+
+/** "nslookup" option list */
+static struct option_descriptor nslookup_opts[] = {};
+
+/** "nslookup" command descriptor */
+static struct command_descriptor nslookup_cmd =
+	COMMAND_DESC ( struct nslookup_options, nslookup_opts, 2, 2,
+		       "<setting> <name>" );
+
+/**
+ * The "nslookup" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int nslookup_exec ( int argc, char **argv ) {
+	struct nslookup_options opts;
+	const char *name;
+	const char *setting_name;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &nslookup_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Parse setting name */
+	setting_name = argv[optind];
+
+	/* Parse name to be resolved */
+	name = argv[ optind + 1 ];
+
+	/* Look up name */
+	if ( ( rc = nslookup ( name, setting_name ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/** The "nslookup" command */
+struct command nslookup_command __command = {
+	.name = "nslookup",
+	.exec = nslookup_exec,
+};
diff --git a/roms/ipxe/src/hci/commands/nvo_cmd.c b/roms/ipxe/src/hci/commands/nvo_cmd.c
index a7e0f4a039474852501fb8d56bf0..f255bbf5742bfc2d0b23b21b2194 100644
--- a/roms/ipxe/src/hci/commands/nvo_cmd.c
+++ b/roms/ipxe/src/hci/commands/nvo_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #include <stdint.h>
@@ -108,7 +109,8 @@ static struct command_descriptor clear_read_cmd =
  */
 static int set_core_exec ( int argc, char **argv,
 			   struct command_descriptor *cmd,
-			   int ( * get_value ) ( char **args, char **value ) ) {
+			   int ( * get_value ) ( const char *name,
+						 char **args, char **value ) ) {
 	struct set_core_options opts;
 	const char *name;
 	char *value;
@@ -122,11 +124,12 @@ static int set_core_exec ( int argc, char **argv,
 	name = argv[optind];
 
 	/* Parse setting value */
-	if ( ( rc = get_value ( &argv[ optind + 1 ], &value ) ) != 0 )
+	if ( ( rc = get_value ( name, &argv[ optind + 1 ], &value ) ) != 0 )
 		goto err_get_value;
 
 	/* Determine total length of command line */
-	if ( ( rc = storef_named_setting ( name, value ) ) != 0 ) {
+	if ( ( rc = storef_named_setting ( name, &setting_type_string,
+					   value ) ) != 0 ) {
 		printf ( "Could not %s \"%s\": %s\n",
 			 argv[0], name, strerror ( rc ) );
 		goto err_store;
@@ -145,11 +148,12 @@ static int set_core_exec ( int argc, char **argv,
 /**
  * Get setting value for "set" command
  *
+ * @v name		Setting name
  * @v args		Remaining arguments
  * @ret value		Setting value
  * @ret rc		Return status code
  */
-static int set_value ( char **args, char **value ) {
+static int set_value ( const char *name __unused, char **args, char **value ) {
 
 	*value = concat_args ( args );
 	if ( ! *value )
@@ -172,11 +176,13 @@ static int set_exec ( int argc, char **argv ) {
 /**
  * Get setting value for "clear" command
  *
+ * @v name		Setting name
  * @v args		Remaining arguments
  * @ret value		Setting value
  * @ret rc		Return status code
  */
-static int clear_value ( char **args __unused, char **value ) {
+static int clear_value ( const char *name __unused, char **args __unused,
+			 char **value ) {
 
 	*value = NULL;
 	return 0;
@@ -196,16 +202,30 @@ static int clear_exec ( int argc, char **argv ) {
 /**
  * Get setting value for "read" command
  *
+ * @v name		Setting name
+ * @v args		Remaining arguments
  * @ret value		Setting value
  * @ret rc		Return status code
  */
-static int read_value ( char **args __unused, char **value ) {
+static int read_value ( const char *name, char **args __unused, char **value ) {
+	char *existing;
+	int rc;
 
-	*value = readline ( NULL );
-	if ( ! *value )
-		return -ENOMEM;
+	/* Read existing value */
+	if ( ( rc = fetchf_named_setting_copy ( name, &existing ) ) < 0 )
+		goto err_existing;
 
-	return 0;
+	/* Read new value */
+	if ( ( rc = readline_history ( NULL, existing, NULL, value ) ) != 0 )
+		goto err_new;
+
+	/* Success */
+	rc = 0;
+
+ err_new:
+	free ( existing );
+ err_existing:
+	return rc;
 }
 
 /**
diff --git a/roms/ipxe/src/hci/commands/route_cmd.c b/roms/ipxe/src/hci/commands/route_cmd.c
index f839d53f438e566cabf525a5b908..3b51f06b0e3b0e43220bb784e064 100644
--- a/roms/ipxe/src/hci/commands/route_cmd.c
+++ b/roms/ipxe/src/hci/commands/route_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/hci/commands/sanboot_cmd.c b/roms/ipxe/src/hci/commands/sanboot_cmd.c
index 198a7322d78d21c2c83aadbc5597..14055a8c41d00f675935def8b3cb 100644
--- a/roms/ipxe/src/hci/commands/sanboot_cmd.c
+++ b/roms/ipxe/src/hci/commands/sanboot_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #include <stdio.h>
@@ -23,6 +24,7 @@
 #include <ipxe/command.h>
 #include <ipxe/parseopt.h>
 #include <ipxe/uri.h>
+#include <ipxe/sanboot.h>
 #include <usr/autoboot.h>
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -34,47 +36,92 @@ FILE_LICENCE ( GPL2_OR_LATER );
  */
 
 /** "sanboot" options */
-struct sanboot_options {};
+struct sanboot_options {
+	/** Drive number */
+	unsigned int drive;
+	/** Do not describe SAN device */
+	int no_describe;
+	/** Keep SAN device */
+	int keep;
+};
 
 /** "sanboot" option list */
-static struct option_descriptor sanboot_opts[] = {};
+static struct option_descriptor sanboot_opts[] = {
+	OPTION_DESC ( "drive", 'd', required_argument,
+		      struct sanboot_options, drive, parse_integer ),
+	OPTION_DESC ( "no-describe", 'n', no_argument,
+		      struct sanboot_options, no_describe, parse_flag ),
+	OPTION_DESC ( "keep", 'k', no_argument,
+		      struct sanboot_options, keep, parse_flag ),
+};
+
+/** "sanhook" command descriptor */
+static struct command_descriptor sanhook_cmd =
+	COMMAND_DESC ( struct sanboot_options, sanboot_opts, 1, 1,
+		       "[--drive <drive>] [--no-describe] <root-path>" );
 
 /** "sanboot" command descriptor */
 static struct command_descriptor sanboot_cmd =
-	COMMAND_DESC ( struct sanboot_options, sanboot_opts, 1, 1,
-		       "<root-path>" );
+	COMMAND_DESC ( struct sanboot_options, sanboot_opts, 0, 1,
+		       "[--drive <drive>] [--no-describe] [--keep] "
+		       "[<root-path>]" );
+
+/** "sanunhook" command descriptor */
+static struct command_descriptor sanunhook_cmd =
+	COMMAND_DESC ( struct sanboot_options, sanboot_opts, 0, 0,
+		       "[--drive <drive>]" );
 
 /**
- * The "sanboot" command
+ * The "sanboot", "sanhook" and "sanunhook" commands
  *
  * @v argc		Argument count
  * @v argv		Argument list
+ * @v default_flags	Default set of flags for uriboot()
+ * @v no_root_path_flags Additional flags to apply if no root path is present
  * @ret rc		Return status code
  */
-static int sanboot_exec ( int argc, char **argv ) {
+static int sanboot_core_exec ( int argc, char **argv,
+			       struct command_descriptor *cmd,
+			       int default_flags, int no_root_path_flags ) {
 	struct sanboot_options opts;
 	const char *root_path;
 	struct uri *uri;
+	int flags;
 	int rc;
 
+	/* Initialise options */
+	memset ( &opts, 0, sizeof ( opts ) );
+	opts.drive = san_default_drive();
+
 	/* Parse options */
-	if ( ( rc = parse_options ( argc, argv, &sanboot_cmd, &opts ) ) != 0 )
+	if ( ( rc = reparse_options ( argc, argv, cmd, &opts ) ) != 0 )
 		goto err_parse_options;
 
-	/* Parse root path */
-	root_path = argv[optind];
-	uri = parse_uri ( root_path );
-	if ( ! uri ) {
-		rc = -ENOMEM;
-		goto err_parse_uri;
+	/* Parse root path, if present */
+	if ( argc > optind ) {
+		root_path = argv[optind];
+		uri = parse_uri ( root_path );
+		if ( ! uri ) {
+			rc = -ENOMEM;
+			goto err_parse_uri;
+		}
+	} else {
+		root_path = NULL;
+		uri = NULL;
 	}
 
+	/* Construct flags */
+	flags = default_flags;
+	if ( opts.no_describe )
+		flags |= URIBOOT_NO_SAN_DESCRIBE;
+	if ( opts.keep )
+		flags |= URIBOOT_NO_SAN_UNHOOK;
+	if ( ! root_path )
+		flags |= no_root_path_flags;
+
 	/* Boot from root path */
-	if ( ( rc = uriboot ( NULL, uri ) ) != 0 ) {
-		printf ( "Could not boot from %s: %s\n",
-			 root_path, strerror ( rc ) );
+	if ( ( rc = uriboot ( NULL, uri, opts.drive, flags ) ) != 0 )
 		goto err_uriboot;
-	}
 
  err_uriboot:
 	uri_put ( uri );
@@ -83,8 +130,56 @@ static int sanboot_exec ( int argc, char **argv ) {
 	return rc;
 }
 
+/**
+ * The "sanhook" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int sanhook_exec ( int argc, char **argv ) {
+	return sanboot_core_exec ( argc, argv, &sanhook_cmd,
+				   ( URIBOOT_NO_SAN_BOOT |
+				     URIBOOT_NO_SAN_UNHOOK ), 0 );
+}
+
+/**
+ * The "sanboot" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int sanboot_exec ( int argc, char **argv ) {
+	return sanboot_core_exec ( argc, argv, &sanboot_cmd,
+				   0, URIBOOT_NO_SAN_UNHOOK );
+}
+
+/**
+ * The "sanunhook" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int sanunhook_exec ( int argc, char **argv ) {
+	return sanboot_core_exec ( argc, argv, &sanunhook_cmd,
+				   ( URIBOOT_NO_SAN_DESCRIBE |
+				     URIBOOT_NO_SAN_BOOT ), 0 );
+}
+
 /** SAN commands */
-struct command sanboot_command __command = {
-	.name = "sanboot",
-	.exec = sanboot_exec,
+struct command sanboot_commands[] __command = {
+	{
+		.name = "sanhook",
+		.exec = sanhook_exec,
+	},
+	{
+		.name = "sanboot",
+		.exec = sanboot_exec,
+	},
+	{
+		.name = "sanunhook",
+		.exec = sanunhook_exec,
+	},
 };
diff --git a/roms/ipxe/src/hci/commands/sync_cmd.c b/roms/ipxe/src/hci/commands/sync_cmd.c
new file mode 100644
index 0000000000000000000000000000000000000000..221e87395278885fc1ec9acf0fcb1e5665799d1c
--- /dev/null
+++ b/roms/ipxe/src/hci/commands/sync_cmd.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <ipxe/timer.h>
+#include <ipxe/pending.h>
+
+/** @file
+ *
+ * "sync" command
+ *
+ */
+
+/** "sync" options */
+struct sync_options {
+	/** Timeout */
+	unsigned int timeout;
+};
+
+/** "sync" option list */
+static struct option_descriptor sync_opts[] = {
+	OPTION_DESC ( "timeout", 't', required_argument,
+		      struct sync_options, timeout, parse_integer ),
+};
+
+/** "sync" command descriptor */
+static struct command_descriptor sync_cmd =
+	COMMAND_DESC ( struct sync_options, sync_opts, 0, 0,
+		       "[--timeout <timeout>]" );
+
+/**
+ * "sync" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Return status code
+ */
+static int sync_exec ( int argc, char **argv ) {
+	struct sync_options opts;
+	unsigned long timeout;
+	int rc;
+
+	/* Parse options */
+	if ( ( rc = parse_options ( argc, argv, &sync_cmd, &opts ) ) != 0 )
+		return rc;
+
+	/* Wait for pending operations to complete */
+	timeout = ( ( opts.timeout * TICKS_PER_SEC ) / 1000 );
+	if ( ( rc = pending_wait ( timeout ) ) != 0 ) {
+		printf ( "Operations did not complete: %s\n", strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/** Sync commands */
+struct command sync_command __command = {
+	.name = "sync",
+	.exec = sync_exec,
+};
diff --git a/roms/ipxe/src/hci/commands/time_cmd.c b/roms/ipxe/src/hci/commands/time_cmd.c
index 1dd175783c05f52309209c05785f..d1dd49cafe4d9aa84f91f56652c2 100644
--- a/roms/ipxe/src/hci/commands/time_cmd.c
+++ b/roms/ipxe/src/hci/commands/time_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  *
  * March-19-2009 @ 02:44: Added sleep command.
  * Shao Miller <shao.miller@yrdsb.edu.on.ca>.
@@ -27,7 +28,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <unistd.h>
 #include <ipxe/command.h>
 #include <ipxe/parseopt.h>
-#include <ipxe/nap.h>
 #include <ipxe/timer.h>
 
 /** @file
@@ -57,7 +57,8 @@ static struct command_descriptor time_cmd =
 static int time_exec ( int argc, char **argv ) {
 	struct time_options opts;
 	unsigned long start;
-	int secs;
+	unsigned long elapsed;
+	int decisecs;
 	int rc;
 
 	/* Parse options */
@@ -66,9 +67,11 @@ static int time_exec ( int argc, char **argv ) {
 
 	start = currticks();
 	rc = execv ( argv[1], argv + 1 );
-	secs = (currticks() - start) / ticks_per_sec();
+	elapsed = ( currticks() - start );
+	decisecs = ( 10 * elapsed / ticks_per_sec() );
 
-	printf ( "%s: %ds\n", argv[0], secs );
+	printf ( "%s: %d.%ds\n", argv[0],
+		 ( decisecs / 10 ), ( decisecs % 10 ) );
 
 	return rc;
 }
@@ -78,42 +81,3 @@ struct command time_command __command = {
 	.name = "time",
 	.exec = time_exec,
 };
-
-/** "sleep" options */
-struct sleep_options {};
-
-/** "sleep" option list */
-static struct option_descriptor sleep_opts[] = {};
-
-/** "sleep" command descriptor */
-static struct command_descriptor sleep_cmd =
-	COMMAND_DESC ( struct sleep_options, sleep_opts, 1, 1, "<seconds>" );
-
-/**
- * "sleep" command
- *
- * @v argc		Argument count
- * @v argv		Argument list
- * @ret rc		Return status code
- */
-static int sleep_exec ( int argc, char **argv ) {
-	struct sleep_options opts;
-	unsigned long start, delay;
-	int rc;
-
-	/* Parse options */
-	if ( ( rc = parse_options ( argc, argv, &sleep_cmd, &opts ) ) != 0 )
-		return rc;
-
-	start = currticks();
-	delay = strtoul ( argv[1], NULL, 0 ) * ticks_per_sec();
-	while ( ( currticks() - start ) <= delay )
-		cpu_nap();
-	return 0;
-}
-
-/** "sleep" command */
-struct command sleep_command __command = {
-	.name = "sleep",
-	.exec = sleep_exec,
-};
diff --git a/roms/ipxe/src/hci/commands/vlan_cmd.c b/roms/ipxe/src/hci/commands/vlan_cmd.c
index 28638ae6a3b7c747ef7918c6dc74..822e5dcf3cb527dc1968dc350e03 100644
--- a/roms/ipxe/src/hci/commands/vlan_cmd.c
+++ b/roms/ipxe/src/hci/commands/vlan_cmd.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/hci/editstring.c b/roms/ipxe/src/hci/editstring.c
index 996528ff563a07d057c03b66dfbd..8c56d2337b524eb4570405699fee 100644
--- a/roms/ipxe/src/hci/editstring.c
+++ b/roms/ipxe/src/hci/editstring.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -36,6 +37,7 @@ static void insert_character ( struct edit_string *string,
                                unsigned int character ) __nonnull;
 static void delete_character ( struct edit_string *string ) __nonnull;
 static void backspace ( struct edit_string *string ) __nonnull;
+static void kill_sol ( struct edit_string *string ) __nonnull;
 static void kill_eol ( struct edit_string *string ) __nonnull;
 
 /**
@@ -108,6 +110,17 @@ static void backspace ( struct edit_string *string ) {
 	}
 }
 
+/**
+ * Delete to start of line
+ *
+ * @v string           Editable string
+ */
+static void kill_sol ( struct edit_string *string ) {
+	size_t old_cursor = string->cursor;
+	string->cursor = 0;
+	insert_delete ( string, old_cursor, NULL );
+}
+
 /**
  * Delete to end of line
  *
@@ -168,6 +181,10 @@ int edit_string ( struct edit_string *string, int key ) {
 		/* Delete character */
 		delete_character ( string );
 		break;
+	case CTRL_U:
+		/* Delete to start of line */
+		kill_sol ( string );
+		break;
 	case CTRL_K:
 		/* Delete to end of line */
 		kill_eol ( string );
diff --git a/roms/ipxe/src/hci/keymap/keymap_no-latin1.c b/roms/ipxe/src/hci/keymap/keymap_no-latin1.c
new file mode 100644
index 0000000000000000000000000000000000000000..8c3e81b31de84820cad12b603b6d280f1e77554e
--- /dev/null
+++ b/roms/ipxe/src/hci/keymap/keymap_no-latin1.c
@@ -0,0 +1,34 @@
+/** @file
+ *
+ * "no-latin1" keyboard mapping
+ *
+ * This file is automatically generated; do not edit
+ *
+ */
+
+FILE_LICENCE ( PUBLIC_DOMAIN );
+
+#include <ipxe/keymap.h>
+
+/** "no-latin1" keyboard mapping */
+struct key_mapping no_latin1_mapping[] __keymap = {
+	{ 0x26, 0x2f },	/* '&' => '/' */
+	{ 0x28, 0x29 },	/* '(' => ')' */
+	{ 0x29, 0x3d },	/* ')' => '=' */
+	{ 0x2a, 0x28 },	/* '*' => '(' */
+	{ 0x2b, 0x60 },	/* '+' => '`' */
+	{ 0x2d, 0x2b },	/* '-' => '+' */
+	{ 0x2f, 0x2d },	/* '/' => '-' */
+	{ 0x3c, 0x3b },	/* '<' => ';' */
+	{ 0x3d, 0x5c },	/* '=' => '\\' */
+	{ 0x3e, 0x3a },	/* '>' => ':' */
+	{ 0x3f, 0x5f },	/* '?' => '_' */
+	{ 0x40, 0x22 },	/* '@' => '"' */
+	{ 0x5c, 0x27 },	/* '\\' => '\'' */
+	{ 0x5d, 0x7e },	/* ']' => '~' */
+	{ 0x5e, 0x26 },	/* '^' => '&' */
+	{ 0x5f, 0x3f },	/* '_' => '?' */
+	{ 0x60, 0x7c },	/* '`' => '|' */
+	{ 0x7c, 0x2a },	/* '|' => '*' */
+	{ 0x7d, 0x5e },	/* '}' => '^' */
+};
diff --git a/roms/ipxe/src/hci/mucurses/ansi_screen.c b/roms/ipxe/src/hci/mucurses/ansi_screen.c
index cc342f7ca3040a712edd05300297..d952e5f2aa931caf2c03118e31e2 100644
--- a/roms/ipxe/src/hci/mucurses/ansi_screen.c
+++ b/roms/ipxe/src/hci/mucurses/ansi_screen.c
@@ -12,6 +12,8 @@ static void ansiscr_putc(struct _curses_screen *scr, chtype c) __nonnull;
 unsigned short _COLS = 80;
 unsigned short _LINES = 24;
 
+static unsigned int saved_usage;
+
 static void ansiscr_reset ( struct _curses_screen *scr ) {
 	/* Reset terminal attributes and clear screen */
 	scr->attrs = 0;
@@ -20,6 +22,16 @@ static void ansiscr_reset ( struct _curses_screen *scr ) {
 	printf ( "\033[0m" );
 }
 
+static void ansiscr_init ( struct _curses_screen *scr ) {
+	saved_usage = console_set_usage ( CONSOLE_USAGE_TUI );
+	ansiscr_reset ( scr );
+}
+
+static void ansiscr_exit ( struct _curses_screen *scr ) {
+	ansiscr_reset ( scr );
+	console_set_usage ( saved_usage );
+}
+
 static void ansiscr_movetoyx ( struct _curses_screen *scr,
 			       unsigned int y, unsigned int x ) {
 	if ( ( x != scr->curs_x ) || ( y != scr->curs_y ) ) {
@@ -65,8 +77,8 @@ static bool ansiscr_peek ( struct _curses_screen *scr __unused ) {
 }
 
 SCREEN _ansi_screen = {
-	.init		= ansiscr_reset,
-	.exit		= ansiscr_reset,
+	.init		= ansiscr_init,
+	.exit		= ansiscr_exit,
 	.movetoyx	= ansiscr_movetoyx,
 	.putc		= ansiscr_putc,
 	.getc		= ansiscr_getc,
diff --git a/roms/ipxe/src/hci/mucurses/mucurses.c b/roms/ipxe/src/hci/mucurses/mucurses.c
index 7c1620210d0f5a2f8f3ada06de6a..ab9a6535ffad9e4a46bafb63aa97 100644
--- a/roms/ipxe/src/hci/mucurses/mucurses.c
+++ b/roms/ipxe/src/hci/mucurses/mucurses.c
@@ -1,4 +1,3 @@
-#include <ipxe/console.h>
 #include <curses.h>
 #include "mucurses.h"
 
diff --git a/roms/ipxe/src/hci/mucurses/widgets/editbox.c b/roms/ipxe/src/hci/mucurses/widgets/editbox.c
index 5d2ba56cc9cc7ec93ef95b5d5bbf..630a66e0b91c11b58c60c3c982db 100644
--- a/roms/ipxe/src/hci/mucurses/widgets/editbox.c
+++ b/roms/ipxe/src/hci/mucurses/widgets/editbox.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/hci/readline.c b/roms/ipxe/src/hci/readline.c
index 32793abe5635e655f9c403335b33..d67980b2cbef68534cd0858656dd 100644
--- a/roms/ipxe/src/hci/readline.c
+++ b/roms/ipxe/src/hci/readline.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -21,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <errno.h>
 #include <ipxe/console.h>
 #include <ipxe/keys.h>
 #include <ipxe/editstring.h>
@@ -240,20 +242,25 @@ void history_free ( struct readline_history *history ) {
  * Read line from console (with history)
  *
  * @v prompt		Prompt string
+ * @v prefill		Prefill string, or NULL for no prefill
  * @v history		History buffer, or NULL for no history
  * @ret line		Line read from console (excluding terminating newline)
+ * @ret rc		Return status code
  *
  * The returned line is allocated with malloc(); the caller must
  * eventually call free() to release the storage.
  */
-char * readline_history ( const char *prompt,
-			  struct readline_history *history ) {
+int readline_history ( const char *prompt, const char *prefill,
+		       struct readline_history *history, char **line ) {
 	char buf[READLINE_MAX];
 	struct edit_string string;
 	int key;
 	int move_by;
 	const char *new_string;
-	char *line;
+	int rc;
+
+	/* Avoid returning uninitialised data on error */
+	*line = NULL;
 
 	/* Display prompt, if applicable */
 	if ( prompt )
@@ -264,6 +271,12 @@ char * readline_history ( const char *prompt,
 	init_editstring ( &string, buf, sizeof ( buf ) );
 	buf[0] = '\0';
 
+	/* Prefill string, if applicable */
+	if ( prefill ) {
+		replace_string ( &string, prefill );
+		sync_console ( &string );
+	}
+
 	while ( 1 ) {
 		/* Handle keypress */
 		key = edit_string ( &string, getkey ( 0 ) );
@@ -272,12 +285,11 @@ char * readline_history ( const char *prompt,
 		switch ( key ) {
 		case CR:
 		case LF:
-			line = strdup ( buf );
-			if ( ! line )
-				printf ( "\nOut of memory" );
+			*line = strdup ( buf );
+			rc = ( ( *line ) ? 0 : -ENOMEM );
 			goto done;
 		case CTRL_C:
-			line = NULL;
+			rc = -ECANCELED;
 			goto done;
 		case KEY_UP:
 			move_by = 1;
@@ -303,11 +315,12 @@ char * readline_history ( const char *prompt,
  done:
 	putchar ( '\n' );
 	if ( history ) {
-		if ( line && line[0] )
-			history_append ( history, line );
+		if ( *line && (*line)[0] )
+			history_append ( history, *line );
 		history_cleanup ( history );
 	}
-	return line;
+	assert ( ( rc == 0 ) ^ ( *line == NULL ) );
+	return rc;
 }
 
 /**
@@ -320,5 +333,8 @@ char * readline_history ( const char *prompt,
  * eventually call free() to release the storage.
  */
 char * readline ( const char *prompt ) {
-	return readline_history ( prompt, NULL );
+	char *line;
+
+	readline_history ( prompt, NULL, NULL, &line );
+	return line;
 }
diff --git a/roms/ipxe/src/hci/shell.c b/roms/ipxe/src/hci/shell.c
index e426ba946f8ee807c55d75e5522e..b62086769aa6745e4ff4d07db8da 100644
--- a/roms/ipxe/src/hci/shell.c
+++ b/roms/ipxe/src/hci/shell.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -85,7 +86,7 @@ int shell ( void ) {
 
 	/* Read and execute commands */
 	do {
-		line = readline_history ( shell_prompt, &history );
+		readline_history ( shell_prompt, NULL, &history, &line );
 		if ( line ) {
 			rc = system ( line );
 			free ( line );
diff --git a/roms/ipxe/src/hci/tui/login_ui.c b/roms/ipxe/src/hci/tui/login_ui.c
index 04aabfa8c75a6447cabd78f47223..52ab0e3603a94f243c2f11af9e10 100644
--- a/roms/ipxe/src/hci/tui/login_ui.c
+++ b/roms/ipxe/src/hci/tui/login_ui.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -32,11 +33,11 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/editbox.h>
 #include <ipxe/keys.h>
 #include <ipxe/login_ui.h>
+#include <config/colour.h>
 
 /* Colour pairs */
 #define CPAIR_NORMAL		1
-#define CPAIR_LABEL		2
-#define CPAIR_EDITBOX		3
+#define CPAIR_EDIT		2
 
 /* Screen layout */
 #define USERNAME_LABEL_ROW	8
@@ -65,9 +66,8 @@ int login_ui ( void ) {
 	/* Initialise UI */
 	initscr();
 	start_color();
-	init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLACK );
-	init_pair ( CPAIR_LABEL, COLOR_WHITE, COLOR_BLACK );
-	init_pair ( CPAIR_EDITBOX, COLOR_WHITE, COLOR_BLUE );
+	init_pair ( CPAIR_NORMAL, COLOR_NORMAL_FG, COLOR_NORMAL_BG );
+	init_pair ( CPAIR_EDIT, COLOR_EDIT_FG, COLOR_EDIT_BG );
 	init_editbox ( &username_box, username, sizeof ( username ), NULL,
 		       USERNAME_ROW, EDITBOX_COL, EDITBOX_WIDTH, 0 );
 	init_editbox ( &password_box, password, sizeof ( password ), NULL,
@@ -75,11 +75,13 @@ int login_ui ( void ) {
 		       EDITBOX_STARS );
 
 	/* Draw initial UI */
+	color_set ( CPAIR_NORMAL, NULL );
 	erase();
-	color_set ( CPAIR_LABEL, NULL );
+	attron ( A_BOLD );
 	mvprintw ( USERNAME_LABEL_ROW, LABEL_COL, "Username:" );
 	mvprintw ( PASSWORD_LABEL_ROW, LABEL_COL, "Password:" );
-	color_set ( CPAIR_EDITBOX, NULL );
+	attroff ( A_BOLD );
+	color_set ( CPAIR_EDIT, NULL );
 	draw_editbox ( &username_box );
 	draw_editbox ( &password_box );
 
diff --git a/roms/ipxe/src/hci/tui/menu_ui.c b/roms/ipxe/src/hci/tui/menu_ui.c
new file mode 100644
index 0000000000000000000000000000000000000000..d5636f8b018e03101f969dad4820213cf27fdbda
--- /dev/null
+++ b/roms/ipxe/src/hci/tui/menu_ui.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Menu interface
+ *
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <curses.h>
+#include <ipxe/keys.h>
+#include <ipxe/timer.h>
+#include <ipxe/console.h>
+#include <ipxe/menu.h>
+#include <config/colour.h>
+
+/* Colour pairs */
+#define CPAIR_NORMAL	1
+#define CPAIR_SELECT	2
+#define CPAIR_SEPARATOR	3
+
+/* Screen layout */
+#define TITLE_ROW	1
+#define MENU_ROW	3
+#define MENU_COL	1
+#define MENU_ROWS	18
+#define MENU_COLS	78
+#define MENU_PAD	2
+
+/** A menu user interface */
+struct menu_ui {
+	/** Menu */
+	struct menu *menu;
+	/** Number of menu items */
+	int count;
+	/** Currently selected item */
+	int selected;
+	/** First visible item */
+	int first_visible;
+	/** Timeout (0=indefinite) */
+	unsigned long timeout;
+};
+
+/**
+ * Return a numbered menu item
+ *
+ * @v menu		Menu
+ * @v index		Index
+ * @ret item		Menu item, or NULL
+ */
+static struct menu_item * menu_item ( struct menu *menu, unsigned int index ) {
+	struct menu_item *item;
+
+	list_for_each_entry ( item, &menu->items, list ) {
+		if ( index-- == 0 )
+			return item;
+	}
+
+	return NULL;
+}
+
+/**
+ * Draw a numbered menu item
+ *
+ * @v ui		Menu user interface
+ * @v index		Index
+ */
+static void draw_menu_item ( struct menu_ui *ui, int index ) {
+	struct menu_item *item;
+	unsigned int row_offset;
+	char buf[ MENU_COLS + 1 /* NUL */ ];
+	char timeout_buf[6]; /* "(xxx)" + NUL */
+	size_t timeout_len;
+	size_t max_len;
+	size_t len;
+
+	/* Move to start of row */
+	row_offset = ( index - ui->first_visible );
+	move ( ( MENU_ROW + row_offset ), MENU_COL );
+
+	/* Get menu item */
+	item = menu_item ( ui->menu, index );
+	if ( item ) {
+
+		/* Draw separators in a different colour */
+		if ( ! item->label )
+			color_set ( CPAIR_SEPARATOR, NULL );
+
+		/* Highlight if this is the selected item */
+		if ( index == ui->selected ) {
+			color_set ( CPAIR_SELECT, NULL );
+			attron ( A_BOLD );
+		}
+
+		/* Construct row */
+		memset ( buf, ' ', ( sizeof ( buf ) - 1 ) );
+		buf[ sizeof ( buf ) -1 ] = '\0';
+		len = strlen ( item->text );
+		max_len = ( sizeof ( buf ) - 1 /* NUL */ - ( 2 * MENU_PAD ) );
+		if ( len > max_len )
+			len = max_len;
+		memcpy ( ( buf + MENU_PAD ), item->text, len );
+
+		/* Add timeout if applicable */
+		timeout_len =
+			snprintf ( timeout_buf, sizeof ( timeout_buf ), "(%ld)",
+				   ( ( ui->timeout + TICKS_PER_SEC - 1 ) /
+				     TICKS_PER_SEC ) );
+		if ( ( index == ui->selected ) && ( ui->timeout != 0 ) ) {
+			memcpy ( ( buf + MENU_COLS - MENU_PAD - timeout_len ),
+				 timeout_buf, timeout_len );
+		}
+
+		/* Print row */
+		printw ( "%s", buf );
+
+		/* Reset attributes */
+		color_set ( CPAIR_NORMAL, NULL );
+		attroff ( A_BOLD );
+
+	} else {
+		/* Clear row if there is no corresponding menu item */
+		clrtoeol();
+	}
+
+	/* Move cursor back to start of row */
+	move ( ( MENU_ROW + row_offset ), MENU_COL );
+}
+
+/**
+ * Draw the current block of menu items
+ *
+ * @v ui		Menu user interface
+ */
+static void draw_menu_items ( struct menu_ui *ui ) {
+	unsigned int i;
+
+	/* Jump scroll to correct point in list */
+	while ( ui->first_visible < ui->selected )
+		ui->first_visible += MENU_ROWS;
+	while ( ui->first_visible > ui->selected )
+		ui->first_visible -= MENU_ROWS;
+
+	/* Draw ellipses before and/or after the list as necessary */
+	color_set ( CPAIR_SEPARATOR, NULL );
+	mvaddstr ( ( MENU_ROW - 1 ), ( MENU_COL + MENU_PAD ),
+		   ( ( ui->first_visible > 0 ) ? "..." : "   " ) );
+	mvaddstr ( ( MENU_ROW + MENU_ROWS ), ( MENU_COL + MENU_PAD ),
+		   ( ( ( ui->first_visible + MENU_ROWS ) < ui->count ) ?
+		     "..." : "   " ) );
+	color_set ( CPAIR_NORMAL, NULL );
+
+	/* Draw visible items */
+	for ( i = 0 ; i < MENU_ROWS ; i++ )
+		draw_menu_item ( ui, ( ui->first_visible + i ) );
+}
+
+/**
+ * Menu main loop
+ *
+ * @v ui		Menu user interface
+ * @ret selected	Selected item
+ * @ret rc		Return status code
+ */
+static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) {
+	struct menu_item *item;
+	unsigned long timeout;
+	unsigned int delta;
+	int current;
+	int key;
+	int i;
+	int move;
+	int chosen = 0;
+	int rc = 0;
+
+	do {
+		/* Record current selection */
+		current = ui->selected;
+
+		/* Calculate timeout as remainder of current second */
+		timeout = ( ui->timeout % TICKS_PER_SEC );
+		if ( ( timeout == 0 ) && ( ui->timeout != 0 ) )
+			timeout = TICKS_PER_SEC;
+		ui->timeout -= timeout;
+
+		/* Get key */
+		move = 0;
+		key = getkey ( timeout );
+		if ( key < 0 ) {
+			/* Choose default if we finally time out */
+			if ( ui->timeout == 0 )
+				chosen = 1;
+		} else {
+			/* Cancel any timeout */
+			ui->timeout = 0;
+
+			/* Handle key */
+			switch ( key ) {
+			case KEY_UP:
+				move = -1;
+				break;
+			case KEY_DOWN:
+				move = +1;
+				break;
+			case KEY_PPAGE:
+				move = ( ui->first_visible - ui->selected - 1 );
+				break;
+			case KEY_NPAGE:
+				move = ( ui->first_visible - ui->selected
+					 + MENU_ROWS );
+				break;
+			case KEY_HOME:
+				move = -ui->count;
+				break;
+			case KEY_END:
+				move = +ui->count;
+				break;
+			case ESC:
+			case CTRL_C:
+				rc = -ECANCELED;
+				break;
+			case CR:
+			case LF:
+				chosen = 1;
+				break;
+			default:
+				i = 0;
+				list_for_each_entry ( item, &ui->menu->items,
+						      list ) {
+					if ( ! ( item->shortcut &&
+						 ( item->shortcut == key ) ) ) {
+						i++;
+						continue;
+					}
+					ui->selected = i;
+					if ( item->label ) {
+						chosen = 1;
+					} else {
+						move = +1;
+					}
+				}
+				break;
+			}
+		}
+
+		/* Move selection, if applicable */
+		while ( move ) {
+			ui->selected += move;
+			if ( ui->selected < 0 ) {
+				ui->selected = 0;
+				move = +1;
+			} else if ( ui->selected >= ui->count ) {
+				ui->selected = ( ui->count - 1 );
+				move = -1;
+			}
+			item = menu_item ( ui->menu, ui->selected );
+			if ( item->label )
+				break;
+			move = ( ( move > 0 ) ? +1 : -1 );
+		}
+
+		/* Redraw selection if necessary */
+		if ( ( ui->selected != current ) || ( timeout != 0 ) ) {
+			draw_menu_item ( ui, current );
+			delta = ( ui->selected - ui->first_visible );
+			if ( delta >= MENU_ROWS )
+				draw_menu_items ( ui );
+			draw_menu_item ( ui, ui->selected );
+		}
+
+		/* Record selection */
+		item = menu_item ( ui->menu, ui->selected );
+		assert ( item != NULL );
+		assert ( item->label != NULL );
+		*selected = item;
+
+	} while ( ( rc == 0 ) && ! chosen );
+
+	return rc;
+}
+
+/**
+ * Show menu
+ *
+ * @v menu		Menu
+ * @v wait_ms		Time to wait, in milliseconds (0=indefinite)
+ * @ret selected	Selected item
+ * @ret rc		Return status code
+ */
+int show_menu ( struct menu *menu, unsigned int timeout_ms,
+		const char *select, struct menu_item **selected ) {
+	struct menu_item *item;
+	struct menu_ui ui;
+	char buf[ MENU_COLS + 1 /* NUL */ ];
+	int labelled_count = 0;
+	int rc;
+
+	/* Initialise UI */
+	memset ( &ui, 0, sizeof ( ui ) );
+	ui.menu = menu;
+	ui.timeout = ( ( timeout_ms * TICKS_PER_SEC ) / 1000 );
+	list_for_each_entry ( item, &menu->items, list ) {
+		if ( item->label ) {
+			if ( ! labelled_count )
+				ui.selected = ui.count;
+			labelled_count++;
+			if ( select ) {
+				if ( strcmp ( select, item->label ) == 0 )
+					ui.selected = ui.count;
+			} else {
+				if ( item->is_default )
+					ui.selected = ui.count;
+			}
+		}
+		ui.count++;
+	}
+	if ( ! labelled_count ) {
+		/* Menus with no labelled items cannot be selected
+		 * from, and will seriously confuse the navigation
+		 * logic.  Refuse to display any such menus.
+		 */
+		return -ENOENT;
+	}
+
+	/* Initialise screen */
+	initscr();
+	start_color();
+	init_pair ( CPAIR_NORMAL, COLOR_NORMAL_FG, COLOR_NORMAL_BG );
+	init_pair ( CPAIR_SELECT, COLOR_SELECT_FG, COLOR_SELECT_BG );
+	init_pair ( CPAIR_SEPARATOR, COLOR_SEPARATOR_FG, COLOR_SEPARATOR_BG );
+	color_set ( CPAIR_NORMAL, NULL );
+	erase();
+
+	/* Draw initial content */
+	attron ( A_BOLD );
+	snprintf ( buf, sizeof ( buf ), "%s", ui.menu->title );
+	mvprintw ( TITLE_ROW, ( ( COLS - strlen ( buf ) ) / 2 ), "%s", buf );
+	attroff ( A_BOLD );
+	draw_menu_items ( &ui );
+	draw_menu_item ( &ui, ui.selected );
+
+	/* Enter main loop */
+	rc = menu_loop ( &ui, selected );
+	assert ( *selected );
+
+	/* Clear screen */
+	endwin();
+
+	return rc;
+}
diff --git a/roms/ipxe/src/hci/tui/settings_ui.c b/roms/ipxe/src/hci/tui/settings_ui.c
index ed076101fe019d79e219c034c878..403d12453e32ac818519fd6e0c80 100644
--- a/roms/ipxe/src/hci/tui/settings_ui.c
+++ b/roms/ipxe/src/hci/tui/settings_ui.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -28,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/editbox.h>
 #include <ipxe/keys.h>
 #include <ipxe/settings_ui.h>
+#include <config/colour.h>
 
 /** @file
  *
@@ -557,11 +559,11 @@ int settings_ui ( struct settings *settings ) {
 
 	initscr();
 	start_color();
-	init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLUE );
-	init_pair ( CPAIR_SELECT, COLOR_WHITE, COLOR_RED );
-	init_pair ( CPAIR_EDIT, COLOR_BLACK, COLOR_CYAN );
-	init_pair ( CPAIR_ALERT, COLOR_WHITE, COLOR_RED );
-	init_pair ( CPAIR_URL, COLOR_CYAN, COLOR_BLUE );
+	init_pair ( CPAIR_NORMAL, COLOR_NORMAL_FG, COLOR_NORMAL_BG );
+	init_pair ( CPAIR_SELECT, COLOR_SELECT_FG, COLOR_SELECT_BG );
+	init_pair ( CPAIR_EDIT, COLOR_EDIT_FG, COLOR_EDIT_BG );
+	init_pair ( CPAIR_ALERT, COLOR_ALERT_FG, COLOR_ALERT_BG );
+	init_pair ( CPAIR_URL, COLOR_URL_FG, COLOR_URL_BG );
 	color_set ( CPAIR_NORMAL, NULL );
 	erase();
 	
diff --git a/roms/ipxe/src/hci/wireless_errors.c b/roms/ipxe/src/hci/wireless_errors.c
index 63c6251c6388c1405cd4f4966cb9..7154df55656a41ffb2a60fc6b0ad 100644
--- a/roms/ipxe/src/hci/wireless_errors.c
+++ b/roms/ipxe/src/hci/wireless_errors.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/image/efi_image.c b/roms/ipxe/src/image/efi_image.c
index 0575496cbcf7c0feaceaad367adb..0368b82c4eb589ae4463a9906a12 100644
--- a/roms/ipxe/src/image/efi_image.c
+++ b/roms/ipxe/src/image/efi_image.c
@@ -13,19 +13,104 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <errno.h>
+#include <stdlib.h>
+#include <wchar.h>
 #include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_snp.h>
+#include <ipxe/efi/efi_download.h>
+#include <ipxe/efi/efi_file.h>
+#include <ipxe/efi/efi_driver.h>
+#include <ipxe/efi/efi_strings.h>
 #include <ipxe/image.h>
 #include <ipxe/init.h>
 #include <ipxe/features.h>
+#include <ipxe/uri.h>
 
 FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
 
+/** EFI loaded image protocol GUID */
+static EFI_GUID efi_loaded_image_protocol_guid =
+	EFI_LOADED_IMAGE_PROTOCOL_GUID;
+
+/**
+ * Create device path for image
+ *
+ * @v image		EFI image
+ * @v parent		Parent device path
+ * @ret path		Device path, or NULL on failure
+ *
+ * The caller must eventually free() the device path.
+ */
+static EFI_DEVICE_PATH_PROTOCOL *
+efi_image_path ( struct image *image, EFI_DEVICE_PATH_PROTOCOL *parent ) {
+	EFI_DEVICE_PATH_PROTOCOL *path;
+	FILEPATH_DEVICE_PATH *filepath;
+	EFI_DEVICE_PATH_PROTOCOL *end;
+	size_t name_len;
+	size_t prefix_len;
+	size_t filepath_len;
+	size_t len;
+
+	/* Calculate device path lengths */
+	end = efi_devpath_end ( parent );
+	prefix_len = ( ( void * ) end - ( void * ) parent );
+	name_len = strlen ( image->name );
+	filepath_len = ( SIZE_OF_FILEPATH_DEVICE_PATH +
+			 ( name_len + 1 /* NUL */ ) * sizeof ( wchar_t ) );
+	len = ( prefix_len + filepath_len + sizeof ( *end ) );
+
+	/* Allocate device path */
+	path = zalloc ( len );
+	if ( ! path )
+		return NULL;
+
+	/* Construct device path */
+	memcpy ( path, parent, prefix_len );
+	filepath = ( ( ( void * ) path ) + prefix_len );
+	filepath->Header.Type = MEDIA_DEVICE_PATH;
+	filepath->Header.SubType = MEDIA_FILEPATH_DP;
+	filepath->Header.Length[0] = ( filepath_len & 0xff );
+	filepath->Header.Length[1] = ( filepath_len >> 8 );
+	efi_snprintf ( filepath->PathName, ( name_len + 1 /* NUL */ ),
+		       "%s", image->name );
+	end = ( ( ( void * ) filepath ) + filepath_len );
+	end->Type = END_DEVICE_PATH_TYPE;
+	end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
+	end->Length[0] = sizeof ( *end );
+
+	return path;
+}
+
+/**
+ * Create command line for image
+ *
+ * @v image             EFI image
+ * @ret cmdline		Command line, or NULL on failure
+ */
+static wchar_t * efi_image_cmdline ( struct image *image ) {
+	wchar_t *cmdline;
+	size_t len;
+
+	len = ( strlen ( image->name ) +
+		( image->cmdline ?
+		  ( 1 /* " " */ + strlen ( image->cmdline ) ) : 0 ) );
+	cmdline = zalloc ( ( len + 1 /* NUL */ ) * sizeof ( wchar_t ) );
+	if ( ! cmdline )
+		return NULL;
+	efi_snprintf ( cmdline, ( len + 1 /* NUL */ ), "%s%s%s",
+		       image->name,
+		       ( image->cmdline ? " " : "" ),
+		       ( image->cmdline ? image->cmdline : "" ) );
+	return cmdline;
+}
+
 /**
  * Execute EFI image
  *
@@ -34,35 +119,120 @@ FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
  */
 static int efi_image_exec ( struct image *image ) {
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	struct efi_snp_device *snpdev;
+	EFI_DEVICE_PATH_PROTOCOL *path;
+	union {
+		EFI_LOADED_IMAGE_PROTOCOL *image;
+		void *interface;
+	} loaded;
 	EFI_HANDLE handle;
-	UINTN exit_data_size;
-	CHAR16 *exit_data;
+	wchar_t *cmdline;
 	EFI_STATUS efirc;
 	int rc;
 
+	/* Find an appropriate device handle to use */
+	snpdev = last_opened_snpdev();
+	if ( ! snpdev ) {
+		DBGC ( image, "EFIIMAGE %p could not identify SNP device\n",
+		       image );
+		rc = -ENODEV;
+		goto err_no_snpdev;
+	}
+
+	/* Install file I/O protocols */
+	if ( ( rc = efi_file_install ( &snpdev->handle ) ) != 0 ) {
+		DBGC ( image, "EFIIMAGE %p could not install file protocol: "
+		       "%s\n", image, strerror ( rc ) );
+		goto err_file_install;
+	}
+
+	/* Install iPXE download protocol */
+	if ( ( rc = efi_download_install ( &snpdev->handle ) ) != 0 ) {
+		DBGC ( image, "EFIIMAGE %p could not install iPXE download "
+		       "protocol: %s\n", image, strerror ( rc ) );
+		goto err_download_install;
+	}
+
+	/* Create device path for image */
+	path = efi_image_path ( image, &snpdev->path );
+	if ( ! path ) {
+		DBGC ( image, "EFIIMAGE %p could not create device path\n",
+		       image );
+		rc = -ENOMEM;
+		goto err_image_path;
+	}
+
+	/* Create command line for image */
+	cmdline = efi_image_cmdline ( image );
+	if ( ! cmdline ) {
+		DBGC ( image, "EFIIMAGE %p could not create command line\n",
+		       image );
+		rc = -ENOMEM;
+		goto err_cmdline;
+	}
+
 	/* Attempt loading image */
-	if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
+	if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, path,
 				       user_to_virt ( image->data, 0 ),
 				       image->len, &handle ) ) != 0 ) {
 		/* Not an EFI image */
 		DBGC ( image, "EFIIMAGE %p could not load: %s\n",
 		       image, efi_strerror ( efirc ) );
-		return -ENOEXEC;
+		rc = -ENOEXEC;
+		goto err_load_image;
 	}
 
+	/* Get the loaded image protocol for the newly loaded image */
+	efirc = bs->OpenProtocol ( handle, &efi_loaded_image_protocol_guid,
+				   &loaded.interface, efi_image_handle,
+				   NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL );
+	if ( efirc ) {
+		/* Should never happen */
+		rc = EFIRC_TO_RC ( efirc );
+		goto err_open_protocol;
+	}
+
+	/* Sanity checks */
+	assert ( loaded.image->ParentHandle == efi_image_handle );
+	assert ( loaded.image->DeviceHandle == snpdev->handle );
+	assert ( loaded.image->LoadOptionsSize == 0 );
+	assert ( loaded.image->LoadOptions == NULL );
+
+	/* Set command line */
+	loaded.image->LoadOptions = cmdline;
+	loaded.image->LoadOptionsSize =
+		( ( wcslen ( cmdline ) + 1 /* NUL */ ) * sizeof ( wchar_t ) );
+
 	/* Start the image */
-	if ( ( efirc = bs->StartImage ( handle, &exit_data_size,
-					&exit_data ) ) != 0 ) {
+	if ( ( efirc = bs->StartImage ( handle, NULL, NULL ) ) != 0 ) {
 		DBGC ( image, "EFIIMAGE %p returned with status %s\n",
 		       image, efi_strerror ( efirc ) );
+		rc = EFIRC_TO_RC ( efirc );
+		goto err_start_image;
 	}
-	rc = EFIRC_TO_RC ( efirc );
 
+	/* Success */
+	rc = 0;
+
+ err_start_image:
+ err_open_protocol:
 	/* Unload the image.  We can't leave it loaded, because we
 	 * have no "unload" operation.
 	 */
-	bs->UnloadImage ( handle );
-
+	if ( ( efirc = bs->UnloadImage ( handle ) ) != 0 ) {
+		DBGC ( image, "EFIIMAGE %p could not unload: %s\n",
+		       image, efi_strerror ( efirc ) );
+	}
+ err_load_image:
+	free ( cmdline );
+ err_cmdline:
+	free ( path );
+ err_image_path:
+	efi_download_uninstall ( snpdev->handle );
+ err_download_install:
+	efi_file_uninstall ( snpdev->handle );
+ err_file_install:
+ err_no_snpdev:
 	return rc;
 }
 
diff --git a/roms/ipxe/src/image/elf.c b/roms/ipxe/src/image/elf.c
index 406a8d477c2b345c5dd7e336415a..51636a8e9437776ec8af9a0238c7 100644
--- a/roms/ipxe/src/image/elf.c
+++ b/roms/ipxe/src/image/elf.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -38,6 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 typedef Elf32_Ehdr	Elf_Ehdr;
 typedef Elf32_Phdr	Elf_Phdr;
 typedef Elf32_Off	Elf_Off;
+#define ELFCLASS	ELFCLASS32
 
 /**
  * Load ELF segment into memory
@@ -46,11 +48,14 @@ typedef Elf32_Off	Elf_Off;
  * @v phdr		ELF program header
  * @v ehdr		ELF executable header
  * @ret entry		Entry point, if found
+ * @ret max		Maximum used address
  * @ret rc		Return status code
  */
 static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
-			      Elf_Ehdr *ehdr, physaddr_t *entry ) {
+			      Elf_Ehdr *ehdr, physaddr_t *entry,
+			      physaddr_t *max ) {
 	physaddr_t dest;
+	physaddr_t end;
 	userptr_t buffer;
 	unsigned long e_offset;
 	int rc;
@@ -78,6 +83,7 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
 		return -ENOEXEC;
 	}
 	buffer = phys_to_user ( dest );
+	end = ( dest + phdr->p_memsz );
 
 	DBGC ( image, "ELF %p loading segment [%x,%x) to [%x,%x,%x)\n", image,
 	       phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
@@ -92,6 +98,10 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
 		return rc;
 	}
 
+	/* Update maximum used address, if applicable */
+	if ( end > *max )
+		*max = end;
+
 	/* Copy image to segment */
 	memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz );
 
@@ -118,9 +128,17 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
  *
  * @v image		ELF file
  * @ret entry		Entry point
+ * @ret max		Maximum used address
  * @ret rc		Return status code
  */
-int elf_load ( struct image *image, physaddr_t *entry ) {
+int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ) {
+	static const uint8_t e_ident[] = {
+		[EI_MAG0]	= ELFMAG0,
+		[EI_MAG1]	= ELFMAG1,
+		[EI_MAG2]	= ELFMAG2,
+		[EI_MAG3]	= ELFMAG3,
+		[EI_CLASS]	= ELFCLASS,
+	};
 	Elf_Ehdr ehdr;
 	Elf_Phdr phdr;
 	Elf_Off phoff;
@@ -129,11 +147,15 @@ int elf_load ( struct image *image, physaddr_t *entry ) {
 
 	/* Read ELF header */
 	copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
-	if ( memcmp ( &ehdr.e_ident[EI_MAG0], ELFMAG, SELFMAG ) != 0 ) {
+	if ( memcmp ( &ehdr.e_ident[EI_MAG0], e_ident,
+		      sizeof ( e_ident ) ) != 0 ) {
 		DBGC ( image, "ELF %p has invalid signature\n", image );
 		return -ENOEXEC;
 	}
 
+	/* Initialise maximum used address */
+	*max = 0;
+
 	/* Invalidate entry point */
 	*entry = 0;
 
@@ -147,7 +169,7 @@ int elf_load ( struct image *image, physaddr_t *entry ) {
 		}
 		copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) );
 		if ( ( rc = elf_load_segment ( image, &phdr, &ehdr,
-					       entry ) ) != 0 ) {
+					       entry, max ) ) != 0 ) {
 			return rc;
 		}
 	}
diff --git a/roms/ipxe/src/image/script.c b/roms/ipxe/src/image/script.c
index 161ac682e7cc650cabd80261910d..e83180ab55f55ec9f830c4125334 100644
--- a/roms/ipxe/src/image/script.c
+++ b/roms/ipxe/src/image/script.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -58,6 +59,7 @@ static int process_script ( struct image *image,
 			    int ( * terminate ) ( int rc ) ) {
 	off_t eol;
 	size_t len;
+	char *line;
 	int rc;
 
 	script_offset = 0;
@@ -71,23 +73,23 @@ static int process_script ( struct image *image,
 			eol = image->len;
 		len = ( eol - script_offset );
 
-		/* Copy line, terminate with NUL, and execute command */
-		{
-			char cmdbuf[ len + 1 ];
+		/* Allocate buffer for line */
+		line = zalloc ( len + 1 /* NUL */ );
+		if ( ! line )
+			return -ENOMEM;
 
-			copy_from_user ( cmdbuf, image->data,
-					 script_offset, len );
-			cmdbuf[len] = '\0';
-			DBG ( "$ %s\n", cmdbuf );
+		/* Copy line */
+		copy_from_user ( line, image->data, script_offset, len );
+		DBG ( "$ %s\n", line );
 
-			/* Move to next line */
-			script_offset += ( len + 1 );
+		/* Move to next line */
+		script_offset += ( len + 1 );
 
-			/* Process line */
-			rc = process_line ( cmdbuf );
-			if ( terminate ( rc ) )
-				return rc;
-		}
+		/* Process and free line */
+		rc = process_line ( line );
+		free ( line );
+		if ( terminate ( rc ) )
+			return rc;
 
 	} while ( script_offset < image->len );
 
@@ -221,11 +223,17 @@ static const char *goto_label;
  * @ret rc		Return status code
  */
 static int goto_find_label ( const char *line ) {
+	size_t len = strlen ( goto_label );
 
 	if ( line[0] != ':' )
 		return -ENOENT;
-	if ( strcmp ( goto_label, &line[1] ) != 0 )
+
+	if ( strncmp ( goto_label, &line[1], len ) != 0 )
+		return -ENOENT;
+
+	if ( line[ 1 + len ] && ! isspace ( line[ 1 + len ] ) )
 		return -ENOENT;
+
 	return 0;
 }
 
@@ -296,7 +304,7 @@ struct prompt_options {
 /** "prompt" option list */
 static struct option_descriptor prompt_opts[] = {
 	OPTION_DESC ( "key", 'k', required_argument,
-		      struct prompt_options, key, parse_integer ),
+		      struct prompt_options, key, parse_key ),
 	OPTION_DESC ( "timeout", 't', required_argument,
 		      struct prompt_options, timeout, parse_integer ),
 };
diff --git a/roms/ipxe/src/image/segment.c b/roms/ipxe/src/image/segment.c
index 97f6a9959454eccd81de7e795c81..86fe426628919f81837f90c2990c 100644
--- a/roms/ipxe/src/image/segment.c
+++ b/roms/ipxe/src/image/segment.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/include/assert.h b/roms/ipxe/src/include/assert.h
index 40a00a2b1008c1d88b7bf38a099a..655cbdc03e14aa7eee12a41f2041 100644
--- a/roms/ipxe/src/include/assert.h
+++ b/roms/ipxe/src/include/assert.h
@@ -18,6 +18,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ASSERTING 1
 #endif
 
+extern unsigned int assertion_failures;
+
 /** printf() for assertions
  *
  * This function exists so that the assert() macro can expand to
@@ -43,6 +45,7 @@ assert_printf ( const char *fmt, ... ) asm ( "printf" );
 #define assert( condition ) 						     \
 	do { 								     \
 		if ( ASSERTING && ! (condition) ) { 			     \
+			assertion_failures++;				     \
 			assert_printf ( "assert(%s) failed at %s line %d\n", \
 					#condition, __FILE__, __LINE__ );    \
 		} 							     \
diff --git a/roms/ipxe/src/include/btext.h b/roms/ipxe/src/include/btext.h
deleted file mode 100644
index 1d3f9e59b36498b4b8c161bbf6e8307360e1bbaf..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/include/btext.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * This file describes the structure passed from the BootX application
- * (for MacOS) when it is used to boot Linux.
- *
- * Written by Benjamin Herrenschmidt.
- *  
- * Move to LinuxBIOS by LYH  yhlu@tyan.com
- *
- */
-
-
-#ifndef _BTEXT_H__
-#define _BTEXT_H__
-
-#if 1
-#define u32 unsigned int
-#define u16 unsigned short
-#define u8 unsigned char
-#endif
-
-/* Here are the boot informations that are passed to the bootstrap
- * Note that the kernel arguments and the device tree are appended
- * at the end of this structure. */
-typedef struct boot_infos
-{
-
-    /* NEW (vers. 2) this holds the current _logical_ base addr of
-       the frame buffer (for use by early boot message) */
-    u8*       logicalDisplayBase;
-
-
-    /* Some infos about the current MacOS display */
-    u32       dispDeviceRect[4];       /* left,top,right,bottom */
-    u32       dispDeviceDepth;         /* (8, 16 or 32) */
-    u32       dispDeviceBase;          /* base address (physical) */
-    u32       dispDeviceRowBytes;      /* rowbytes (in bytes) */
-    u32       dispDeviceColorsOffset;  /* Colormap (8 bits only) or 0 (*) */
-
-
-    /* The framebuffer size (optional, currently 0) */
-    u32       frameBufferSize;         /* Represents a max size, can be 0. */
-
-
-} boot_infos_t;
-
-/* (*) The format of the colormap is 256 * 3 * 2 bytes. Each color index is represented
- * by 3 short words containing a 16 bits (unsigned) color component.
- * Later versions may contain the gamma table for direct-color devices here.
- */
-#define BOOTX_COLORTABLE_SIZE    (256UL*3UL*2UL)
-
-
-/*
- * Definitions for using the procedures in btext.c.
- *
- * Benjamin Herrenschmidt <benh@kernel.crashing.org>
- */
-
-extern boot_infos_t disp_bi;
-extern u32 boot_text_mapped;
-
-#endif /* _BTEXT_H */
diff --git a/roms/ipxe/src/include/compiler.h b/roms/ipxe/src/include/compiler.h
index feea5167ec04113e76ba0cd38282..ed9af237d01adac8f351a545d34c 100644
--- a/roms/ipxe/src/include/compiler.h
+++ b/roms/ipxe/src/include/compiler.h
@@ -260,19 +260,9 @@ REQUEST_EXPANDED ( CONFIG_SYMBOL );
 
 #ifndef ASSEMBLY
 
-/** printf() for debugging
- *
- * This function exists so that the DBG() macros can expand to
- * printf() calls without dragging the printf() prototype into scope.
- *
- * As far as the compiler is concerned, dbg_printf() and printf() are
- * completely unrelated calls; it's only at the assembly stage that
- * references to the dbg_printf symbol are collapsed into references
- * to the printf symbol.
- */
-extern int __attribute__ (( format ( printf, 1, 2 ) )) 
-dbg_printf ( const char *fmt, ... ) asm ( "printf" );
-
+/** printf() for debugging */
+extern void __attribute__ (( format ( printf, 1, 2 ) ))
+dbg_printf ( const char *fmt, ... );
 extern void dbg_autocolourise ( unsigned long id );
 extern void dbg_decolourise ( void );
 extern void dbg_hex_dump_da ( unsigned long dispaddr,
@@ -339,6 +329,7 @@ int __debug_disable;
 				unsigned long ul;		\
 				typeof ( dispaddr ) raw;	\
 			} da;					\
+			da.ul = 0;				\
 			da.raw = dispaddr;			\
 			dbg_hex_dump_da ( da.ul, data, len );	\
 		}						\
@@ -370,6 +361,7 @@ int __debug_disable;
 				unsigned long ul;		\
 				typeof ( dispaddr ) raw;	\
 			} da;					\
+			da.ul = 0;				\
 			da.raw = dispaddr;			\
 			dbg_md5_da ( da.ul, data, len );	\
 		}						\
@@ -421,6 +413,7 @@ int __debug_disable;
 				unsigned long ul;		\
 				typeof ( id ) raw;		\
 			} dbg_stream;				\
+			dbg_stream.ul = 0;			\
 			dbg_stream.raw = id;			\
 			dbg_autocolourise ( dbg_stream.ul );	\
 		}						\
diff --git a/roms/ipxe/src/include/errno.h b/roms/ipxe/src/include/errno.h
index a86573fc9f9aaf4f4a99fc4568d5..bd4ddaf41be6becc0564f08e460a 100644
--- a/roms/ipxe/src/include/errno.h
+++ b/roms/ipxe/src/include/errno.h
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #ifndef ERRNO_H
diff --git a/roms/ipxe/src/include/etherboot.h b/roms/ipxe/src/include/etherboot.h
index b2fbe4f67639880a28f79a2acb34..ba79cb16ac60474b96489a097dc0 100644
--- a/roms/ipxe/src/include/etherboot.h
+++ b/roms/ipxe/src/include/etherboot.h
@@ -14,7 +14,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <stdio.h>
 #include <unistd.h>
 #include <strings.h>
-#include <ipxe/console.h>
 #include <ipxe/timer.h>
 #include <ipxe/if_arp.h>
 #include <ipxe/if_ether.h>
diff --git a/roms/ipxe/src/include/hci/ifmgmt_cmd.h b/roms/ipxe/src/include/hci/ifmgmt_cmd.h
index a7751cb287c03b83aff54004d2cc..abdb27f43a0a55f36b8d5358e8ad 100644
--- a/roms/ipxe/src/include/hci/ifmgmt_cmd.h
+++ b/roms/ipxe/src/include/hci/ifmgmt_cmd.h
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #ifndef _IFMGMT_CMD_H
diff --git a/roms/ipxe/src/include/ipxe/aes.h b/roms/ipxe/src/include/ipxe/aes.h
index 5d645b207f706aef0de670aa838f..4e44f9853671d87a72197a21a471 100644
--- a/roms/ipxe/src/include/ipxe/aes.h
+++ b/roms/ipxe/src/include/ipxe/aes.h
@@ -21,6 +21,10 @@ struct aes_context {
 /** AES context size */
 #define AES_CTX_SIZE sizeof ( struct aes_context )
 
+/* AXTLS functions */
+extern void axtls_aes_encrypt ( const AES_CTX *ctx, uint32_t *data );
+extern void axtls_aes_decrypt ( const AES_CTX *ctx, uint32_t *data );
+
 extern struct cipher_algorithm aes_algorithm;
 extern struct cipher_algorithm aes_cbc_algorithm;
 
diff --git a/roms/ipxe/src/include/ipxe/ansiesc.h b/roms/ipxe/src/include/ipxe/ansiesc.h
index 35438e43a593b768d9975b958e0d..c00af258a8aa69cc5bf768de1277 100644
--- a/roms/ipxe/src/include/ipxe/ansiesc.h
+++ b/roms/ipxe/src/include/ipxe/ansiesc.h
@@ -113,6 +113,13 @@ struct ansiesc_context {
 /** Select graphic rendition */
 #define ANSIESC_SGR 'm'
 
+/** Explicit log message priority
+ *
+ * This is an iPXE private sequence identifier.  (The range 'p' to '~'
+ * is reserved for private sequences.)
+ */
+#define ANSIESC_LOG_PRIORITY 'p'
+
 /** @} */
 
 extern int ansiesc_process ( struct ansiesc_context *ctx, int c );
diff --git a/roms/ipxe/src/include/ipxe/arp.h b/roms/ipxe/src/include/ipxe/arp.h
index f7b99c68da04a003fa5b6e3a932f..00396d8214dfa4395adc3785f8f8 100644
--- a/roms/ipxe/src/include/ipxe/arp.h
+++ b/roms/ipxe/src/include/ipxe/arp.h
@@ -35,10 +35,8 @@ struct arp_net_protocol {
 
 extern struct net_protocol arp_protocol __net_protocol;
 
-extern int arp_resolve ( struct net_device *netdev,
-			 struct net_protocol *net_protocol,
-			 const void *dest_net_addr,
-			 const void *source_net_addr,
-			 void *dest_ll_addr );
+extern int arp_tx ( struct io_buffer *iobuf, struct net_device *netdev,
+		    struct net_protocol *net_protocol, const void *net_dest,
+		    const void *net_source, const void *ll_source );
 
 #endif /* _IPXE_ARP_H */
diff --git a/roms/ipxe/src/include/ipxe/asn1.h b/roms/ipxe/src/include/ipxe/asn1.h
index 85e480e87c692cc049f386dbe037..3e73b59c7817fbeeeb90a07252d4 100644
--- a/roms/ipxe/src/include/ipxe/asn1.h
+++ b/roms/ipxe/src/include/ipxe/asn1.h
@@ -9,26 +9,295 @@
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
+#include <stdint.h>
+#include <time.h>
+#include <ipxe/tables.h>
+
+/** An ASN.1 object cursor */
+struct asn1_cursor {
+	/** Start of data */
+	const void *data;
+	/** Length of data */
+	size_t len;
+};
+
+/** An ASN.1 object builder */
+struct asn1_builder {
+	/** Data
+	 *
+	 * This is always dynamically allocated.  If @c data is NULL
+	 * while @len is non-zero, this indicates that a memory
+	 * allocation error has occurred during the building process.
+	 */
+	void *data;
+	/** Length of data */
+	size_t len;
+};
+
+/** Maximum (viable) length of ASN.1 length
+ *
+ * While in theory unlimited, this length is sufficient to contain a
+ * size_t.
+ */
+#define ASN1_MAX_LEN_LEN ( 1 + sizeof ( size_t ) )
+
+/** An ASN.1 header */
+struct asn1_builder_header {
+	/** Type */
+	uint8_t type;
+	/** Length (encoded) */
+	uint8_t length[ASN1_MAX_LEN_LEN];
+} __attribute__ (( packed ));
+
+/** ASN.1 end */
+#define ASN1_END 0x00
+
+/** ASN.1 boolean */
+#define ASN1_BOOLEAN 0x01
+
+/** ASN.1 integer */
 #define ASN1_INTEGER 0x02
+
+/** ASN.1 bit string */
 #define ASN1_BIT_STRING 0x03
+
+/** ASN.1 octet string */
 #define ASN1_OCTET_STRING 0x04
+
+/** ASN.1 null */
 #define ASN1_NULL 0x05
+
+/** ASN.1 object identifier */
 #define ASN1_OID 0x06
+
+/** ASN.1 enumeration */
+#define ASN1_ENUMERATED 0x0a
+
+/** ASN.1 UTC time */
+#define ASN1_UTC_TIME 0x17
+
+/** ASN.1 generalized time */
+#define ASN1_GENERALIZED_TIME 0x18
+
+/** ASN.1 sequence */
 #define ASN1_SEQUENCE 0x30
-#define ASN1_IP_ADDRESS 0x40
-#define ASN1_EXPLICIT_TAG 0xa0
 
-/**
- * A DER-encoded ASN.1 object cursor
+/** ASN.1 set */
+#define ASN1_SET 0x31
+
+/** ASN.1 implicit tag */
+#define ASN1_IMPLICIT_TAG( number) ( 0x80 | (number) )
+
+/** ASN.1 explicit tag */
+#define ASN1_EXPLICIT_TAG( number) ( 0xa0 | (number) )
+
+/** ASN.1 "any tag" magic value */
+#define ASN1_ANY -1U
+
+/** Initial OID byte */
+#define ASN1_OID_INITIAL( first, second ) ( ( (first) * 40 ) + (second) )
+
+/** Single-byte OID value
+ *
+ * Valid for values up to 127
  */
-struct asn1_cursor {
-	/** Start of data */
-	void *data;
-	/** Length of data */
-	size_t len;
+#define ASN1_OID_SINGLE( value ) ( (value) & 0x7f )
+
+/** Double-byte OID value
+ *
+ * Valid for values up to 16383
+ */
+#define ASN1_OID_DOUBLE( value ) \
+	( 0x80 | ( ( (value) >> 7 ) & 0x7f ) ), ASN1_OID_SINGLE ( (value) )
+
+/** Double-byte OID value
+ *
+ * Valid for values up to 2097151
+ */
+#define ASN1_OID_TRIPLE( value ) \
+	( 0x80 | ( ( (value) >> 14 ) & 0x7f ) ), ASN1_OID_DOUBLE ( (value) )
+
+/** ASN.1 OID for rsaEncryption (1.2.840.113549.1.1.1) */
+#define ASN1_OID_RSAENCRYPTION					\
+	ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ),	\
+	ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ),	\
+	ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 1 )
+
+/** ASN.1 OID for md5WithRSAEncryption (1.2.840.113549.1.1.4) */
+#define ASN1_OID_MD5WITHRSAENCRYPTION				\
+	ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ),	\
+	ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ),	\
+	ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 4 )
+
+/** ASN.1 OID for sha1WithRSAEncryption (1.2.840.113549.1.1.5) */
+#define ASN1_OID_SHA1WITHRSAENCRYPTION				\
+	ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ),	\
+	ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ),	\
+	ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 5 )
+
+/** ASN.1 OID for sha256WithRSAEncryption (1.2.840.113549.1.1.11) */
+#define ASN1_OID_SHA256WITHRSAENCRYPTION			\
+	ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ),	\
+	ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ),	\
+	ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 11 )
+
+/** ASN.1 OID for id-md5 (1.2.840.113549.2.5) */
+#define ASN1_OID_MD5						\
+	ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ),	\
+	ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 2 ),	\
+	ASN1_OID_SINGLE ( 5 )
+
+/** ASN.1 OID for id-sha1 (1.3.14.3.2.26) */
+#define ASN1_OID_SHA1						\
+	ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 14 ),	\
+	ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 2 ),		\
+	ASN1_OID_SINGLE ( 26 )
+
+/** ASN.1 OID for id-sha256 (2.16.840.1.101.3.4.2.1) */
+#define ASN1_OID_SHA256						\
+	ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ),	\
+	ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 101 ),		\
+	ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 4 ),		\
+	ASN1_OID_SINGLE ( 2 ), ASN1_OID_SINGLE ( 1 )
+
+/** ASN.1 OID for commonName (2.5.4.3) */
+#define ASN1_OID_COMMON_NAME					\
+	ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 4 ),	\
+	ASN1_OID_SINGLE ( 3 )
+
+/** ASN.1 OID for id-ce-keyUsage (2.5.29.15) */
+#define ASN1_OID_KEYUSAGE					\
+	ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 29 ),	\
+	ASN1_OID_SINGLE ( 15 )
+
+/** ASN.1 OID for id-ce-basicConstraints (2.5.29.19) */
+#define ASN1_OID_BASICCONSTRAINTS				\
+	ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 29 ),	\
+	ASN1_OID_SINGLE ( 19 )
+
+/** ASN.1 OID for id-ce-extKeyUsage (2.5.29.37) */
+#define ASN1_OID_EXTKEYUSAGE					\
+	ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 29 ),	\
+	ASN1_OID_SINGLE ( 37 )
+
+/** ASN.1 OID for id-kp-codeSigning (1.3.6.1.5.5.7.3.3) */
+#define ASN1_OID_CODESIGNING					\
+	ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 6 ),	\
+	ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 5 ),		\
+	ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ),		\
+	ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 3 )
+
+/** ASN.1 OID for pkcs-signedData (1.2.840.113549.1.7.2) */
+#define ASN1_OID_SIGNEDDATA					\
+	ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ),	\
+	ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ),	\
+	ASN1_OID_SINGLE ( 7 ), ASN1_OID_SINGLE ( 2 )
+
+/** ASN.1 OID for id-pe-authorityInfoAccess (1.3.6.1.5.5.7.1.1) */
+#define ASN1_OID_AUTHORITYINFOACCESS				\
+	ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 6 ),	\
+	ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 5 ),		\
+	ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ),		\
+	ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 1 )
+
+/** ASN.1 OID for id-ad-ocsp (1.3.6.1.5.5.7.48.1) */
+#define ASN1_OID_OCSP						\
+	ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 6 ),	\
+	ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 5 ),		\
+	ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ),		\
+	ASN1_OID_SINGLE ( 48 ), ASN1_OID_SINGLE ( 1 )
+
+/** ASN.1 OID for id-pkix-ocsp-basic ( 1.3.6.1.5.5.7.48.1.1) */
+#define ASN1_OID_OCSP_BASIC					\
+	ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 6 ),	\
+	ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 5 ),		\
+	ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ),		\
+	ASN1_OID_SINGLE ( 48 ), ASN1_OID_SINGLE ( 1 ),		\
+	ASN1_OID_SINGLE ( 1 )
+
+/** ASN.1 OID for id-kp-OCSPSigning (1.3.6.1.5.5.7.3.9) */
+#define ASN1_OID_OCSPSIGNING					\
+	ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 6 ),	\
+	ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 5 ),		\
+	ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ),		\
+	ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 9 )
+
+/** Define an ASN.1 cursor containing an OID */
+#define ASN1_OID_CURSOR( oid_value ) {				\
+		.data = oid_value,				\
+		.len = sizeof ( oid_value ),			\
+	}
+
+/** An ASN.1 OID-identified algorithm */
+struct asn1_algorithm {
+	/** Name */
+	const char *name;
+	/** Object identifier */
+	struct asn1_cursor oid;
+	/** Public-key algorithm (if applicable) */
+	struct pubkey_algorithm *pubkey;
+	/** Digest algorithm (if applicable) */
+	struct digest_algorithm *digest;
 };
 
+/** ASN.1 OID-identified algorithms */
+#define ASN1_ALGORITHMS __table ( struct asn1_algorithm, "asn1_algorithms" )
+
+/** Declare an ASN.1 OID-identified algorithm */
+#define __asn1_algorithm __table_entry ( ASN1_ALGORITHMS, 01 )
+
+/** An ASN.1 bit string */
+struct asn1_bit_string {
+	/** Data */
+	const void *data;
+	/** Length */
+	size_t len;
+	/** Unused bits at end of data */
+	unsigned int unused;
+} __attribute__ (( packed ));
+
+/**
+ * Extract ASN.1 type
+ *
+ * @v cursor		ASN.1 object cursor
+ * @ret type		Type
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+asn1_type ( const struct asn1_cursor *cursor ) {
+	return ( *( ( const uint8_t * ) cursor->data ) );
+}
+
+extern void asn1_invalidate_cursor ( struct asn1_cursor *cursor );
 extern int asn1_enter ( struct asn1_cursor *cursor, unsigned int type );
+extern int asn1_skip_if_exists ( struct asn1_cursor *cursor,
+				 unsigned int type );
 extern int asn1_skip ( struct asn1_cursor *cursor, unsigned int type );
+extern int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type );
+extern int asn1_enter_any ( struct asn1_cursor *cursor );
+extern int asn1_skip_any ( struct asn1_cursor *cursor );
+extern int asn1_shrink_any ( struct asn1_cursor *cursor );
+extern int asn1_boolean ( const struct asn1_cursor *cursor );
+extern int asn1_integer ( const struct asn1_cursor *cursor, int *value );
+extern int asn1_bit_string ( const struct asn1_cursor *cursor,
+			     struct asn1_bit_string *bits );
+extern int asn1_integral_bit_string ( const struct asn1_cursor *cursor,
+				      struct asn1_bit_string *bits );
+extern int asn1_compare ( const struct asn1_cursor *cursor1,
+			  const struct asn1_cursor *cursor2 );
+extern int asn1_algorithm ( const struct asn1_cursor *cursor,
+			    struct asn1_algorithm **algorithm );
+extern int asn1_pubkey_algorithm ( const struct asn1_cursor *cursor,
+				   struct asn1_algorithm **algorithm );
+extern int asn1_digest_algorithm ( const struct asn1_cursor *cursor,
+				   struct asn1_algorithm **algorithm );
+extern int asn1_signature_algorithm ( const struct asn1_cursor *cursor,
+				      struct asn1_algorithm **algorithm );
+extern int asn1_generalized_time ( const struct asn1_cursor *cursor,
+				   time_t *time );
+extern int asn1_prepend_raw ( struct asn1_builder *builder, const void *data,
+			      size_t len );
+extern int asn1_prepend ( struct asn1_builder *builder, unsigned int type,
+			  const void *data, size_t len );
+extern int asn1_wrap ( struct asn1_builder *builder, unsigned int type );
 
 #endif /* _IPXE_ASN1_H */
diff --git a/roms/ipxe/src/include/ipxe/bigint.h b/roms/ipxe/src/include/ipxe/bigint.h
new file mode 100644
index 0000000000000000000000000000000000000000..97fbce2456f097145a558e64164a9efd1cab6208
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/bigint.h
@@ -0,0 +1,301 @@
+#ifndef _IPXE_BIGINT_H
+#define _IPXE_BIGINT_H
+
+/** @file
+ *
+ * Big integer support
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * Define a big-integer type
+ *
+ * @v size		Number of elements
+ * @ret bigint_t	Big integer type
+ */
+#define bigint_t( size )						\
+	struct {							\
+		bigint_element_t element[ (size) ];			\
+	}
+
+/**
+ * Determine number of elements required for a big-integer type
+ *
+ * @v len		Maximum length of big integer, in bytes
+ * @ret size		Number of elements
+ */
+#define bigint_required_size( len )					\
+	( ( (len) + sizeof ( bigint_element_t ) - 1 ) /			\
+	  sizeof ( bigint_element_t ) )
+
+/**
+ * Determine number of elements in big-integer type
+ *
+ * @v bigint		Big integer
+ * @ret size		Number of elements
+ */
+#define bigint_size( bigint )						\
+	( sizeof ( *(bigint) ) / sizeof ( (bigint)->element[0] ) )
+
+/**
+ * Initialise big integer
+ *
+ * @v value		Big integer to initialise
+ * @v data		Raw data
+ * @v len		Length of raw data
+ */
+#define bigint_init( value, data, len ) do {				\
+	unsigned int size = bigint_size (value);			\
+	assert ( (len) <= ( size * sizeof ( (value)->element[0] ) ) );	\
+	bigint_init_raw ( (value)->element, size, (data), (len) );	\
+	} while ( 0 )
+
+/**
+ * Finalise big integer
+ *
+ * @v value		Big integer to finalise
+ * @v out		Output buffer
+ * @v len		Length of output buffer
+ */
+#define bigint_done( value, out, len ) do {				\
+	unsigned int size = bigint_size (value);			\
+	bigint_done_raw ( (value)->element, size, (out), (len) );	\
+	} while ( 0 )
+
+/**
+ * Add big integers
+ *
+ * @v addend		Big integer to add
+ * @v value		Big integer to be added to
+ */
+#define bigint_add( addend, value ) do {				\
+	unsigned int size = bigint_size (addend);			\
+	bigint_add_raw ( (addend)->element, (value)->element, size );	\
+	} while ( 0 )
+
+/**
+ * Subtract big integers
+ *
+ * @v subtrahend	Big integer to subtract
+ * @v value		Big integer to be subtracted from
+ */
+#define bigint_subtract( subtrahend, value ) do {			\
+	unsigned int size = bigint_size (subtrahend);			\
+	bigint_subtract_raw ( (subtrahend)->element, (value)->element,	\
+			      size );					\
+	} while ( 0 )
+
+/**
+ * Rotate big integer left
+ *
+ * @v value		Big integer
+ */
+#define bigint_rol( value ) do {					\
+	unsigned int size = bigint_size (value);			\
+	bigint_rol_raw ( (value)->element, size );			\
+	} while ( 0 )
+
+/**
+ * Rotate big integer right
+ *
+ * @v value		Big integer
+ */
+#define bigint_ror( value ) do {					\
+	unsigned int size = bigint_size (value);			\
+	bigint_ror_raw ( (value)->element, size );			\
+	} while ( 0 )
+
+/**
+ * Test if big integer is equal to zero
+ *
+ * @v value		Big integer
+ * @v size		Number of elements
+ * @ret is_zero		Big integer is equal to zero
+ */
+#define bigint_is_zero( value ) ( {					\
+	unsigned int size = bigint_size (value);			\
+	bigint_is_zero_raw ( (value)->element, size ); } )
+
+/**
+ * Compare big integers
+ *
+ * @v value		Big integer
+ * @v reference		Reference big integer
+ * @ret geq		Big integer is greater than or equal to the reference
+ */
+#define bigint_is_geq( value, reference ) ( {				\
+	unsigned int size = bigint_size (value);			\
+	bigint_is_geq_raw ( (value)->element, (reference)->element,	\
+			    size ); } )
+
+/**
+ * Test if bit is set in big integer
+ *
+ * @v value		Big integer
+ * @v bit		Bit to test
+ * @ret is_set		Bit is set
+ */
+#define bigint_bit_is_set( value, bit ) ( {				\
+	unsigned int size = bigint_size (value);			\
+	bigint_bit_is_set_raw ( (value)->element, size, bit ); } )
+
+/**
+ * Find highest bit set in big integer
+ *
+ * @v value		Big integer
+ * @ret max_bit		Highest bit set + 1 (or 0 if no bits set)
+ */
+#define bigint_max_set_bit( value ) ( {					\
+	unsigned int size = bigint_size (value);			\
+	bigint_max_set_bit_raw ( (value)->element, size ); } )
+
+/**
+ * Grow big integer
+ *
+ * @v source		Source big integer
+ * @v dest		Destination big integer
+ */
+#define bigint_grow( source, dest ) do {				\
+	unsigned int source_size = bigint_size (source);		\
+	unsigned int dest_size = bigint_size (dest);			\
+	bigint_grow_raw ( (source)->element, source_size,		\
+			  (dest)->element, dest_size );			\
+	} while ( 0 )
+
+/**
+ * Shrink big integer
+ *
+ * @v source		Source big integer
+ * @v dest		Destination big integer
+ */
+#define bigint_shrink( source, dest ) do {				\
+	unsigned int source_size = bigint_size (source);		\
+	unsigned int dest_size = bigint_size (dest);			\
+	bigint_shrink_raw ( (source)->element, source_size,		\
+			    (dest)->element, dest_size );		\
+	} while ( 0 )
+
+/**
+ * Multiply big integers
+ *
+ * @v multiplicand	Big integer to be multiplied
+ * @v multiplier	Big integer to be multiplied
+ * @v result		Big integer to hold result
+ */
+#define bigint_multiply( multiplicand, multiplier, result ) do {	\
+	unsigned int size = bigint_size (multiplicand);			\
+	bigint_multiply_raw ( (multiplicand)->element,			\
+			      (multiplier)->element, (result)->element,	\
+			      size );					\
+	} while ( 0 )
+
+/**
+ * Perform modular multiplication of big integers
+ *
+ * @v multiplicand	Big integer to be multiplied
+ * @v multiplier	Big integer to be multiplied
+ * @v modulus		Big integer modulus
+ * @v result		Big integer to hold result
+ * @v tmp		Temporary working space
+ */
+#define bigint_mod_multiply( multiplicand, multiplier, modulus,		\
+			     result, tmp ) do {				\
+	unsigned int size = bigint_size (multiplicand);			\
+	bigint_mod_multiply_raw ( (multiplicand)->element,		\
+				  (multiplier)->element,		\
+				  (modulus)->element,			\
+				  (result)->element, size, tmp );	\
+	} while ( 0 )
+
+/**
+ * Calculate temporary working space required for moduluar multiplication
+ *
+ * @v modulus		Big integer modulus
+ * @ret len		Length of temporary working space
+ */
+#define bigint_mod_multiply_tmp_len( modulus ) ( {			\
+	unsigned int size = bigint_size (modulus);			\
+	sizeof ( struct {						\
+		bigint_t ( size * 2 ) temp_result;			\
+		bigint_t ( size * 2 ) temp_modulus;			\
+	} ); } )
+
+/**
+ * Perform modular exponentiation of big integers
+ *
+ * @v base		Big integer base
+ * @v modulus		Big integer modulus
+ * @v exponent		Big integer exponent
+ * @v result		Big integer to hold result
+ * @v tmp		Temporary working space
+ */
+#define bigint_mod_exp( base, modulus, exponent, result, tmp ) do {	\
+	unsigned int size = bigint_size (base);				\
+	unsigned int exponent_size = bigint_size (exponent);		\
+	bigint_mod_exp_raw ( (base)->element, (modulus)->element,	\
+			     (exponent)->element, (result)->element,	\
+			     size, exponent_size, tmp );		\
+	} while ( 0 )
+
+/**
+ * Calculate temporary working space required for moduluar exponentiation
+ *
+ * @v modulus		Big integer modulus
+ * @v exponent		Big integer exponent
+ * @ret len		Length of temporary working space
+ */
+#define bigint_mod_exp_tmp_len( modulus, exponent ) ( {			\
+	unsigned int size = bigint_size (modulus);			\
+	unsigned int exponent_size = bigint_size (exponent);		\
+	size_t mod_multiply_len =					\
+		bigint_mod_multiply_tmp_len (modulus);			\
+	sizeof ( struct {						\
+		bigint_t ( size ) temp_base;				\
+		bigint_t ( exponent_size ) temp_exponent;		\
+		uint8_t mod_multiply[mod_multiply_len];			\
+	} ); } )
+
+#include <bits/bigint.h>
+
+void bigint_init_raw ( bigint_element_t *value0, unsigned int size,
+		       const void *data, size_t len );
+void bigint_done_raw ( const bigint_element_t *value0, unsigned int size,
+		       void *out, size_t len );
+void bigint_add_raw ( const bigint_element_t *addend0,
+		      bigint_element_t *value0, unsigned int size );
+void bigint_subtract_raw ( const bigint_element_t *subtrahend0,
+			   bigint_element_t *value0, unsigned int size );
+void bigint_rol_raw ( bigint_element_t *value0, unsigned int size );
+void bigint_ror_raw ( bigint_element_t *value0, unsigned int size );
+int bigint_is_zero_raw ( const bigint_element_t *value0, unsigned int size );
+int bigint_is_geq_raw ( const bigint_element_t *value0,
+			const bigint_element_t *reference0,
+			unsigned int size );
+int bigint_bit_is_set_raw ( const bigint_element_t *value0, unsigned int size,
+			    unsigned int bit );
+int bigint_max_set_bit_raw ( const bigint_element_t *value0,
+			     unsigned int size );
+void bigint_grow_raw ( const bigint_element_t *source0,
+		       unsigned int source_size, bigint_element_t *dest0,
+		       unsigned int dest_size );
+void bigint_shrink_raw ( const bigint_element_t *source0,
+			 unsigned int source_size, bigint_element_t *dest0,
+			 unsigned int dest_size );
+void bigint_multiply_raw ( const bigint_element_t *multiplicand0,
+			   const bigint_element_t *multiplier0,
+			   bigint_element_t *result0,
+			   unsigned int size );
+void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0,
+			       const bigint_element_t *multiplier0,
+			       const bigint_element_t *modulus0,
+			       bigint_element_t *result0,
+			       unsigned int size, void *tmp );
+void bigint_mod_exp_raw ( const bigint_element_t *base0,
+			  const bigint_element_t *modulus0,
+			  const bigint_element_t *exponent0,
+			  bigint_element_t *result0,
+			  unsigned int size, unsigned int exponent_size,
+			  void *tmp );
+
+#endif /* _IPXE_BIGINT_H */
diff --git a/roms/ipxe/src/include/ipxe/bitbash.h b/roms/ipxe/src/include/ipxe/bitbash.h
index 62b54b10f9ca9288ffb6e1c90216..69d5d9e3ecbe9822bda1b4097b1b 100644
--- a/roms/ipxe/src/include/ipxe/bitbash.h
+++ b/roms/ipxe/src/include/ipxe/bitbash.h
@@ -13,6 +13,18 @@ struct bit_basher;
 
 /** Bit-bashing operations */
 struct bit_basher_operations {
+	/**
+	 * Open bit-bashing interface (optional)
+	 *
+	 * @v basher		Bit-bashing interface
+	 */
+	void ( * open ) ( struct bit_basher *basher );
+	/**
+	 * Close bit-bashing interface (optional)
+	 *
+	 * @v basher		Bit-bashing interface
+	 */
+	void ( * close ) ( struct bit_basher *basher );
 	/**
 	 * Set/clear output bit
 	 *
@@ -45,6 +57,26 @@ struct bit_basher {
 	struct bit_basher_operations *op;
 };
 
+/**
+ * Open bit-bashing interface
+ *
+ * @v basher		Bit-bashing interface
+ */
+static inline void open_bit ( struct bit_basher *basher ) {
+	if ( basher->op->open )
+		basher->op->open ( basher );
+}
+
+/**
+ * Close bit-bashing interface
+ *
+ * @v basher		Bit-bashing interface
+ */
+static inline void close_bit ( struct bit_basher *basher ) {
+	if ( basher->op->close )
+		basher->op->close ( basher );
+}
+
 extern void write_bit ( struct bit_basher *basher, unsigned int bit_id,
 			unsigned long data );
 extern int read_bit ( struct bit_basher *basher, unsigned int bit_id );
diff --git a/roms/ipxe/src/include/ipxe/bitops.h b/roms/ipxe/src/include/ipxe/bitops.h
index 4118ef81964338cf096e5ebfadca..73e859f41fa7bffa2a7c3be305c9 100644
--- a/roms/ipxe/src/include/ipxe/bitops.h
+++ b/roms/ipxe/src/include/ipxe/bitops.h
@@ -16,7 +16,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/include/ipxe/clientcert.h b/roms/ipxe/src/include/ipxe/clientcert.h
new file mode 100644
index 0000000000000000000000000000000000000000..08f62eb733aa80cbcc295fff996b250bc790e04b
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/clientcert.h
@@ -0,0 +1,43 @@
+#ifndef _IPXE_CLIENTCERT_H
+#define _IPXE_CLIENTCERT_H
+
+/** @file
+ *
+ * Client certificate store
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/** A client certificate */
+struct client_certificate {
+	/** Data */
+	const void *data;
+	/** Length */
+	size_t len;
+};
+
+/** A client private key */
+struct client_private_key {
+	/** Data */
+	const void *data;
+	/** Length */
+	size_t len;
+};
+
+extern struct client_certificate client_certificate;
+extern struct client_private_key client_private_key;
+
+/**
+ * Check for presence of a client certificate
+ *
+ * @ret have_cert	We have a client certificate and private key
+ */
+static inline int have_client_certificate ( void ) {
+	return ( ( client_certificate.len > 0 ) &&
+		 ( client_private_key.len > 0 ) );
+}
+
+#endif /* _IPXE_CLIENTCERT_H */
diff --git a/roms/ipxe/src/include/ipxe/cms.h b/roms/ipxe/src/include/ipxe/cms.h
new file mode 100644
index 0000000000000000000000000000000000000000..eadeca4b80f09cf71340fd49856fd522b9b9ff68
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/cms.h
@@ -0,0 +1,75 @@
+#ifndef _IPXE_CMS_H
+#define _IPXE_CMS_H
+
+/** @file
+ *
+ * Cryptographic Message Syntax (PKCS #7)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <time.h>
+#include <ipxe/asn1.h>
+#include <ipxe/crypto.h>
+#include <ipxe/x509.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/uaccess.h>
+
+/** CMS signer information */
+struct cms_signer_info {
+	/** List of signer information blocks */
+	struct list_head list;
+
+	/** Certificate chain */
+	struct x509_chain *chain;
+
+	/** Digest algorithm */
+	struct digest_algorithm *digest;
+	/** Public-key algorithm */
+	struct pubkey_algorithm *pubkey;
+
+	/** Signature */
+	void *signature;
+	/** Length of signature */
+	size_t signature_len;
+};
+
+/** A CMS signature */
+struct cms_signature {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** List of all certificates */
+	struct x509_chain *certificates;
+	/** List of signer information blocks */
+	struct list_head info;
+};
+
+/**
+ * Get reference to CMS signature
+ *
+ * @v sig		CMS signature
+ * @ret sig		CMS signature
+ */
+static inline __attribute__ (( always_inline )) struct cms_signature *
+cms_get ( struct cms_signature *sig ) {
+	ref_get ( &sig->refcnt );
+	return sig;
+}
+
+/**
+ * Drop reference to CMS signature
+ *
+ * @v sig		CMS signature
+ */
+static inline __attribute__ (( always_inline )) void
+cms_put ( struct cms_signature *sig ) {
+	ref_put ( &sig->refcnt );
+}
+
+extern int cms_signature ( const void *data, size_t len,
+			   struct cms_signature **sig );
+extern int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
+			const char *name, time_t time, struct x509_root *root );
+
+#endif /* _IPXE_CMS_H */
diff --git a/roms/ipxe/src/include/ipxe/console.h b/roms/ipxe/src/include/ipxe/console.h
index 3bfa5033fe7e75998ec410ec8f66..e2bf4be973a608056a94cc7d366c 100644
--- a/roms/ipxe/src/include/ipxe/console.h
+++ b/roms/ipxe/src/include/ipxe/console.h
@@ -1,6 +1,7 @@
 #ifndef _IPXE_CONSOLE_H
 #define _IPXE_CONSOLE_H
 
+#include <stdio.h>
 #include <ipxe/tables.h>
 
 /** @file
@@ -74,6 +75,13 @@ struct console_driver {
 	 *
 	 */
 	int ( *iskey ) ( void );
+
+	/** Console usage bitmask
+	 *
+	 * This is the bitwise OR of zero or more @c CONSOLE_USAGE_XXX
+	 * values.
+	 */
+	int usage;
 };
 
 /** Console driver table */
@@ -98,10 +106,57 @@ struct console_driver {
  */
 #define __console_driver __table_entry ( CONSOLES, 01 )
 
-/* Function prototypes */
+/**
+ * @defgroup consoleusage Console usages
+ * @{
+ */
+
+/** Standard output */
+#define CONSOLE_USAGE_STDOUT 0x0001
+
+/** Debug messages */
+#define CONSOLE_USAGE_DEBUG 0x0002
+
+/** Text-based user interface */
+#define CONSOLE_USAGE_TUI 0x0004
+
+/** Log messages */
+#define CONSOLE_USAGE_LOG 0x0008
+
+/** All console usages */
+#define CONSOLE_USAGE_ALL ( CONSOLE_USAGE_STDOUT | CONSOLE_USAGE_DEBUG | \
+			    CONSOLE_USAGE_TUI | CONSOLE_USAGE_LOG )
+
+/** @} */
+
+/**
+ * Test to see if console has an explicit usage
+ *
+ * @v console		Console definition (e.g. CONSOLE_PCBIOS)
+ * @ret explicit	Console has an explicit usage
+ *
+ * This relies upon the trick that the expression ( 2 * N + 1 ) will
+ * be valid even if N is defined to be empty, since it will then
+ * evaluate to give ( 2 * + 1 ) == ( 2 * +1 ) == 2.
+ */
+#define CONSOLE_EXPLICIT( console ) ( ( 2 * console + 1 ) != 2 )
+
+extern int console_usage;
+
+/**
+ * Set console usage
+ *
+ * @v usage		New console usage
+ * @ret old_usage	Previous console usage
+ */
+static inline __attribute__ (( always_inline )) int
+console_set_usage ( int usage ) {
+	int old_usage = console_usage;
+
+	console_usage = usage;
+	return old_usage;
+}
 
-extern void putchar ( int character );
-extern int getchar ( void );
 extern int iskey ( void );
 extern int getkey ( unsigned long timeout );
 
diff --git a/roms/ipxe/src/include/ipxe/crypto.h b/roms/ipxe/src/include/ipxe/crypto.h
index 9383c076c42283d3ff153b3486ce..d7d42b66c3278cae0e0528290754 100644
--- a/roms/ipxe/src/include/ipxe/crypto.h
+++ b/roms/ipxe/src/include/ipxe/crypto.h
@@ -96,6 +96,67 @@ struct pubkey_algorithm {
 	const char *name;
 	/** Context size */
 	size_t ctxsize;
+	/** Initialise algorithm
+	 *
+	 * @v ctx		Context
+	 * @v key		Key
+	 * @v key_len		Length of key
+	 * @ret rc		Return status code
+	 */
+	int ( * init ) ( void *ctx, const void *key, size_t key_len );
+	/** Calculate maximum output length
+	 *
+	 * @v ctx		Context
+	 * @ret max_len		Maximum output length
+	 */
+	size_t ( * max_len ) ( void *ctx );
+	/** Encrypt
+	 *
+	 * @v ctx		Context
+	 * @v plaintext		Plaintext
+	 * @v plaintext_len	Length of plaintext
+	 * @v ciphertext	Ciphertext
+	 * @ret ciphertext_len	Length of ciphertext, or negative error
+	 */
+	int ( * encrypt ) ( void *ctx, const void *data, size_t len,
+			    void *out );
+	/** Decrypt
+	 *
+	 * @v ctx		Context
+	 * @v ciphertext	Ciphertext
+	 * @v ciphertext_len	Ciphertext length
+	 * @v plaintext		Plaintext
+	 * @ret plaintext_len	Plaintext length, or negative error
+	 */
+	int ( * decrypt ) ( void *ctx, const void *data, size_t len,
+			    void *out );
+	/** Sign digest value
+	 *
+	 * @v ctx		Context
+	 * @v digest		Digest algorithm
+	 * @v value		Digest value
+	 * @v signature		Signature
+	 * @ret signature_len	Signature length, or negative error
+	 */
+	int ( * sign ) ( void *ctx, struct digest_algorithm *digest,
+			 const void *value, void *signature );
+	/** Verify signed digest value
+	 *
+	 * @v ctx		Context
+	 * @v digest		Digest algorithm
+	 * @v value		Digest value
+	 * @v signature		Signature
+	 * @v signature_len	Signature length
+	 * @ret rc		Return status code
+	 */
+	int ( * verify ) ( void *ctx, struct digest_algorithm *digest,
+			   const void *value, const void *signature,
+			   size_t signature_len );
+	/** Finalise algorithm
+	 *
+	 * @v ctx		Context
+	 */
+	void ( * final ) ( void *ctx );
 };
 
 static inline void digest_init ( struct digest_algorithm *digest,
@@ -147,10 +208,45 @@ static inline int is_stream_cipher ( struct cipher_algorithm *cipher ) {
 	return ( cipher->blocksize == 1 );
 }
 
+static inline int pubkey_init ( struct pubkey_algorithm *pubkey, void *ctx,
+				const void *key, size_t key_len ) {
+	return pubkey->init ( ctx, key, key_len );
+}
+
+static inline size_t pubkey_max_len ( struct pubkey_algorithm *pubkey,
+				      void *ctx ) {
+	return pubkey->max_len ( ctx );
+}
+
+static inline int pubkey_encrypt ( struct pubkey_algorithm *pubkey, void *ctx,
+				   const void *data, size_t len, void *out ) {
+	return pubkey->encrypt ( ctx, data, len, out );
+}
+
+static inline int pubkey_decrypt ( struct pubkey_algorithm *pubkey, void *ctx,
+				   const void *data, size_t len, void *out ) {
+	return pubkey->decrypt ( ctx, data, len, out );
+}
+
+static inline int pubkey_sign ( struct pubkey_algorithm *pubkey, void *ctx,
+				struct digest_algorithm *digest,
+				const void *value, void *signature ) {
+	return pubkey->sign ( ctx, digest, value, signature );
+}
+
+static inline int pubkey_verify ( struct pubkey_algorithm *pubkey, void *ctx,
+				  struct digest_algorithm *digest,
+				  const void *value, const void *signature,
+				  size_t signature_len ) {
+	return pubkey->verify ( ctx, digest, value, signature, signature_len );
+}
+
+static inline void pubkey_final ( struct pubkey_algorithm *pubkey, void *ctx ) {
+	pubkey->final ( ctx );
+}
+
 extern struct digest_algorithm digest_null;
 extern struct cipher_algorithm cipher_null;
 extern struct pubkey_algorithm pubkey_null;
 
-void get_random_bytes ( void *buf, size_t len );
-
 #endif /* _IPXE_CRYPTO_H */
diff --git a/roms/ipxe/src/include/ipxe/dhcp.h b/roms/ipxe/src/include/ipxe/dhcp.h
index 148e3d66f6beec2ee230133d4e13..b97dfe32cc392f364393d6dbcf22 100644
--- a/roms/ipxe/src/include/ipxe/dhcp.h
+++ b/roms/ipxe/src/include/ipxe/dhcp.h
@@ -10,6 +10,7 @@
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
+#include <stdarg.h>
 #include <ipxe/in.h>
 #include <ipxe/list.h>
 #include <ipxe/refcnt.h>
@@ -240,6 +241,39 @@ struct dhcp_client_id {
 /** Client system architecture */
 #define DHCP_CLIENT_ARCHITECTURE 93
 
+/** DHCP client architecture */
+struct dhcp_client_architecture {
+	uint16_t arch;
+} __attribute__ (( packed ));
+
+/** DHCP client architecture values
+ *
+ * These are defined by the PXE specification and redefined by
+ * RFC4578.
+ */
+enum dhcp_client_architecture_values {
+	/** Intel x86 PC */
+	DHCP_CLIENT_ARCHITECTURE_X86 = 0x0000,
+	/** NEC/PC98 */
+	DHCP_CLIENT_ARCHITECTURE_PC98 = 0x0001,
+	/** EFI Itanium */
+	DHCP_CLIENT_ARCHITECTURE_IA64 = 0x0002,
+	/** DEC Alpha */
+	DHCP_CLIENT_ARCHITECTURE_ALPHA = 0x0003,
+	/** Arc x86 */
+	DHCP_CLIENT_ARCHITECTURE_ARCX86 = 0x0004,
+	/** Intel Lean Client */
+	DHCP_CLIENT_ARCHITECTURE_LC = 0x0005,
+	/** EFI IA32 */
+	DHCP_CLIENT_ARCHITECTURE_IA32 = 0x0006,
+	/** EFI BC */
+	DHCP_CLIENT_ARCHITECTURE_EFI = 0x0007,
+	/** EFI Xscale */
+	DHCP_CLIENT_ARCHITECTURE_XSCALE = 0x0008,
+	/** EFI x86-64 */
+	DHCP_CLIENT_ARCHITECTURE_X86_64 = 0x0009,
+};
+
 /** Client network device interface */
 #define DHCP_CLIENT_NDI 94
 
@@ -318,6 +352,21 @@ struct dhcp_client_uuid {
  */
 #define DHCP_EB_SCRIPTLET DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x51 )
 
+/** Encrypted syslog server */
+#define DHCP_EB_SYSLOGS_SERVER DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x55 )
+
+/** Trusted root certficate fingerprints */
+#define DHCP_EB_TRUST DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x5a )
+
+/** Client certficate */
+#define DHCP_EB_CERT DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x5b )
+
+/** Client private key */
+#define DHCP_EB_KEY DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x5c )
+
+/** Cross-signed certificate source */
+#define DHCP_EB_CROSS_CERT DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x5d )
+
 /** Skip PXE DHCP protocol extensions such as ProxyDHCP
  *
  * If set to a non-zero value, iPXE will not wait for ProxyDHCP offers
@@ -425,32 +474,6 @@ struct dhcp_netdev_desc {
 
 /** @} */
 
-/**
- * Count number of arguments to a variadic macro
- *
- * This rather neat, non-iterative solution is courtesy of Laurent
- * Deniau.
- *
- */
-#define _VA_ARG_COUNT(  _1,  _2,  _3,  _4,  _5,  _6,  _7,  _8,		\
-		        _9, _10, _11, _12, _13, _14, _15, _16,		\
-		       _17, _18, _19, _20, _21, _22, _23, _24,		\
-		       _25, _26, _27, _28, _29, _30, _31, _32,		\
-		       _33, _34, _35, _36, _37, _38, _39, _40,		\
-		       _41, _42, _43, _44, _45, _46, _47, _48,		\
-		       _49, _50, _51, _52, _53, _54, _55, _56,		\
-		       _57, _58, _59, _60, _61, _62, _63,   N, ... ) N
-#define VA_ARG_COUNT( ... )						\
-	_VA_ARG_COUNT ( __VA_ARGS__, 					\
-			63, 62, 61, 60, 59, 58, 57, 56,			\
-			55, 54, 53, 52, 51, 50, 49, 48,			\
-			47, 46, 45, 44, 43, 42, 41, 40,			\
-			39, 38, 37, 36, 35, 34, 33, 32,			\
-			31, 30, 29, 28, 27, 26, 25, 24,			\
-			23, 22, 21, 20, 19, 18, 17, 16,			\
-			15, 14, 13, 12, 11, 10,  9,  8,			\
-			 7,  6,  5,  4,  3,  2,  1,  0 )
-
 /** Construct a DHCP option from a list of bytes */
 #define DHCP_OPTION( ... ) VA_ARG_COUNT ( __VA_ARGS__ ), __VA_ARGS__
 
@@ -627,15 +650,16 @@ struct dhcphdr {
 /** Setting block name used for BootServerDHCP responses */
 #define PXEBS_SETTINGS_NAME "pxebs"
 
-extern unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
-				  uint16_t *flags );
+extern uint32_t dhcp_last_xid;
 extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
 				struct net_device *netdev, uint8_t msgtype,
-				const void *options, size_t options_len,
-				void *data, size_t max_len );
+				uint32_t xid, const void *options,
+				size_t options_len, void *data,
+				size_t max_len );
 extern int dhcp_create_request ( struct dhcp_packet *dhcppkt,
 				 struct net_device *netdev,
-				 unsigned int msgtype, struct in_addr ciaddr,
+				 unsigned int msgtype, uint32_t xid,
+				 struct in_addr ciaddr,
 				 void *data, size_t max_len );
 extern int start_dhcp ( struct interface *job, struct net_device *netdev );
 extern int start_pxebs ( struct interface *job, struct net_device *netdev,
diff --git a/roms/ipxe/src/include/ipxe/drbg.h b/roms/ipxe/src/include/ipxe/drbg.h
new file mode 100644
index 0000000000000000000000000000000000000000..6374e7787128d373375dfa8ff67f32218ccb3355
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/drbg.h
@@ -0,0 +1,135 @@
+#ifndef _IPXE_DRBG_H
+#define _IPXE_DRBG_H
+
+/** @file
+ *
+ * DRBG mechanism
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/sha256.h>
+#include <ipxe/hmac_drbg.h>
+
+/** Choose HMAC_DRBG using SHA-256
+ *
+ * HMAC_DRBG using SHA-256 is an Approved algorithm in ANS X9.82.
+ */
+#define HMAC_DRBG_ALGORITHM HMAC_DRBG_SHA256
+
+/** Maximum security strength */
+#define DRBG_MAX_SECURITY_STRENGTH \
+	HMAC_DRBG_MAX_SECURITY_STRENGTH ( HMAC_DRBG_ALGORITHM )
+
+/** Security strength
+ *
+ * We choose to operate at a strength of 128 bits.
+ */
+#define DRBG_SECURITY_STRENGTH 128
+
+/** Minimum entropy input length */
+#define DRBG_MIN_ENTROPY_LEN_BYTES \
+	HMAC_DRBG_MIN_ENTROPY_LEN_BYTES ( DRBG_SECURITY_STRENGTH )
+
+/** Maximum entropy input length */
+#define DRBG_MAX_ENTROPY_LEN_BYTES HMAC_DRBG_MAX_ENTROPY_LEN_BYTES
+
+/** Maximum personalisation string length */
+#define DRBG_MAX_PERSONAL_LEN_BYTES HMAC_DRBG_MAX_PERSONAL_LEN_BYTES
+
+/** Maximum additional input length */
+#define DRBG_MAX_ADDITIONAL_LEN_BYTES HMAC_DRBG_MAX_ADDITIONAL_LEN_BYTES
+
+/** Maximum length of generated pseudorandom data per request */
+#define DRBG_MAX_GENERATED_LEN_BYTES HMAC_DRBG_MAX_GENERATED_LEN_BYTES
+
+/** A Deterministic Random Bit Generator */
+struct drbg_state {
+	/** Algorithm internal state */
+	struct hmac_drbg_state internal;
+	/** Reseed required flag */
+	int reseed_required;
+	/** State is valid */
+	int valid;
+};
+
+/**
+ * Instantiate DRBG algorithm
+ *
+ * @v state		Algorithm state
+ * @v entropy		Entropy input
+ * @v entropy_len	Length of entropy input
+ * @v personal		Personalisation string
+ * @v personal_len	Length of personalisation string
+ *
+ * This is the Instantiate_algorithm function defined in ANS X9.82
+ * Part 3-2007 Section 9.2 (NIST SP 800-90 Section 9.1).
+ */
+static inline void drbg_instantiate_algorithm ( struct drbg_state *state,
+						const void *entropy,
+						size_t entropy_len,
+						const void *personal,
+						size_t personal_len ) {
+	hmac_drbg_instantiate ( HMAC_DRBG_HASH ( HMAC_DRBG_ALGORITHM ),
+				&state->internal, entropy, entropy_len,
+				personal, personal_len );
+}
+
+/**
+ * Reseed DRBG algorithm
+ *
+ * @v state		Algorithm state
+ * @v entropy		Entropy input
+ * @v entropy_len	Length of entropy input
+ * @v additional	Additional input
+ * @v additional_len	Length of additional input
+ *
+ * This is the Reseed_algorithm function defined in ANS X9.82
+ * Part 3-2007 Section 9.3 (NIST SP 800-90 Section 9.2).
+ */
+static inline void drbg_reseed_algorithm ( struct drbg_state *state,
+					   const void *entropy,
+					   size_t entropy_len,
+					   const void *additional,
+					   size_t additional_len ) {
+	hmac_drbg_reseed ( HMAC_DRBG_HASH ( HMAC_DRBG_ALGORITHM ),
+			   &state->internal, entropy, entropy_len,
+			   additional, additional_len );
+}
+
+/**
+ * Generate pseudorandom bits using DRBG algorithm
+ *
+ * @v state		Algorithm state
+ * @v additional	Additional input
+ * @v additional_len	Length of additional input
+ * @v data		Output buffer
+ * @v len		Length of output buffer
+ * @ret rc		Return status code
+ *
+ * This is the Generate_algorithm function defined in ANS X9.82
+ * Part 3-2007 Section 9.4 (NIST SP 800-90 Section 9.3).
+ *
+ * Note that the only permitted error is "reseed required".
+ */
+static inline int drbg_generate_algorithm ( struct drbg_state *state,
+					    const void *additional,
+					    size_t additional_len,
+					    void *data, size_t len ) {
+	return hmac_drbg_generate ( HMAC_DRBG_HASH ( HMAC_DRBG_ALGORITHM ),
+				    &state->internal, additional,
+				    additional_len, data, len );
+}
+
+extern int drbg_instantiate ( struct drbg_state *state, const void *personal,
+			      size_t personal_len );
+extern int drbg_reseed ( struct drbg_state *state, const void *additional,
+			 size_t additional_len );
+extern int drbg_generate ( struct drbg_state *state, const void *additional,
+			   size_t additional_len, int prediction_resist,
+			   void *data, size_t len );
+extern void drbg_uninstantiate ( struct drbg_state *state );
+
+#endif /* _IPXE_DRBG_H */
diff --git a/roms/ipxe/src/include/ipxe/eapol.h b/roms/ipxe/src/include/ipxe/eapol.h
index 3fad4428428d994b17262027692e..5ca9c2815044c6b1eaca7f6a6e23 100644
--- a/roms/ipxe/src/include/ipxe/eapol.h
+++ b/roms/ipxe/src/include/ipxe/eapol.h
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #ifndef _IPXE_EAPOL_H
diff --git a/roms/ipxe/src/include/ipxe/efi/Base.h b/roms/ipxe/src/include/ipxe/efi/Base.h
index 999b414716961d73345740904fe5..2fb4ec6f600da26c055553e7f2e8 100644
--- a/roms/ipxe/src/include/ipxe/efi/Base.h
+++ b/roms/ipxe/src/include/ipxe/efi/Base.h
@@ -6,7 +6,7 @@
   environment. There are a set of base libraries in the Mde Package that can
   be used to implement base modules.
 
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
 This program and the accompanying materials
 are licensed and made available under the terms and conditions of the BSD License
@@ -395,6 +395,7 @@ struct _LIST_ENTRY {
 //  VA_END (VA_LIST Marker) - Clear Marker
 //  VA_ARG (VA_LIST Marker, var arg size) - Use Marker to get an argument from
 //    the ... list. You must know the size and pass it in this macro.
+//  VA_COPY (VA_LIST Dest, VA_LIST Start) - Initialize Dest as a copy of Start.
 //
 //  example:
 //
@@ -456,6 +457,13 @@ struct _LIST_ENTRY {
 
 #define VA_END(Marker)                ((void)0)
 
+// For some ARM RVCT compilers, __va_copy is not defined
+#ifndef __va_copy
+  #define __va_copy(dest, src) ((void)((dest) = (src)))
+#endif
+
+#define VA_COPY(Dest, Start)          __va_copy (Dest, Start)
+
 #elif defined(__GNUC__) && !defined(NO_BUILTIN_VA_FUNCS)
 //
 // Use GCC built-in macros for variable argument lists.
@@ -473,6 +481,8 @@ typedef __builtin_va_list VA_LIST;
 
 #define VA_END(Marker)               __builtin_va_end (Marker)
 
+#define VA_COPY(Dest, Start)         __builtin_va_copy (Dest, Start)
+
 #else
 ///
 /// Variable used to traverse the list of arguments. This type can vary by
@@ -528,6 +538,19 @@ typedef CHAR8 *VA_LIST;
 **/
 #define VA_END(Marker)      (Marker = (VA_LIST) 0)
 
+/**
+  Initializes a VA_LIST as a copy of an existing VA_LIST.
+
+  This macro initializes Dest as a copy of Start, as if the VA_START macro had been applied to Dest
+  followed by the same sequence of uses of the VA_ARG macro as had previously been used to reach
+  the present state of Start.
+
+  @param   Dest   VA_LIST used to traverse the list of arguments.
+  @param   Start  VA_LIST used to traverse the list of arguments.
+
+**/
+#define VA_COPY(Dest, Start)  ((void)((Dest) = (Start)))
+
 #endif
 
 ///
@@ -678,10 +701,22 @@ typedef UINTN  *BASE_LIST;
   @return  Minimum of two operands.
 
 **/
-
 #define MIN(a, b)                       \
   (((a) < (b)) ? (a) : (b))
 
+/**
+  Return the absolute value of a signed operand.
+
+  This macro returns the absolute value of the signed operand specified by a.
+
+  @param   a        The signed operand.
+
+  @return  The absolute value of the signed operand.
+
+**/
+#define ABS(a)                          \
+  (((a) < 0) ? (-(a)) : (a))
+
 //
 // Status codes common to all execution phases
 //
@@ -884,6 +919,12 @@ typedef UINTN RETURN_STATUS;
 ///
 #define RETURN_INVALID_LANGUAGE      ENCODE_ERROR (32)
 
+///
+/// The security status of the data is unknown or compromised
+/// and the data must be updated or replaced to restore a valid
+/// security status.
+///
+#define RETURN_COMPROMISED_DATA      ENCODE_ERROR (33)
 
 ///
 /// The string contained one or more characters that
@@ -908,6 +949,12 @@ typedef UINTN RETURN_STATUS;
 ///
 #define RETURN_WARN_BUFFER_TOO_SMALL ENCODE_WARNING (4)
 
+///
+/// The data has not been updated within the timeframe set by
+/// local policy for this type of data.
+///
+#define RETURN_WARN_STALE_DATA       ENCODE_WARNING (5)
+
 /**
   Returns a 16-bit signature built from 2 ASCII characters.
 
diff --git a/roms/ipxe/src/include/ipxe/efi/Guid/FileInfo.h b/roms/ipxe/src/include/ipxe/efi/Guid/FileInfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..21fd38904020f31559f3be7746e067791ec09fe5
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/efi/Guid/FileInfo.h
@@ -0,0 +1,73 @@
+/** @file
+  Provides a GUID and a data structure that can be used with EFI_FILE_PROTOCOL.SetInfo()
+  and EFI_FILE_PROTOCOL.GetInfo() to set or get generic file information.
+  This GUID is defined in UEFI specification.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that 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 __FILE_INFO_H__
+#define __FILE_INFO_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_FILE_INFO_ID \
+  { \
+    0x9576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+  }
+
+typedef struct {
+  ///
+  /// The size of the EFI_FILE_INFO structure, including the Null-terminated FileName string.
+  ///
+  UINT64    Size;
+  ///
+  /// The size of the file in bytes.
+  ///
+  UINT64    FileSize;
+  ///
+  /// PhysicalSize The amount of physical space the file consumes on the file system volume.
+  ///
+  UINT64    PhysicalSize;
+  ///
+  /// The time the file was created.
+  ///
+  EFI_TIME  CreateTime;
+  ///
+  /// The time when the file was last accessed.
+  ///
+  EFI_TIME  LastAccessTime;
+  ///
+  /// The time when the file's contents were last modified.
+  ///
+  EFI_TIME  ModificationTime;
+  ///
+  /// The attribute bits for the file.
+  ///
+  UINT64    Attribute;
+  ///
+  /// The Null-terminated name of the file.
+  ///
+  CHAR16    FileName[1];
+} EFI_FILE_INFO;
+
+///
+/// The FileName field of the EFI_FILE_INFO data structure is variable length.
+/// Whenever code needs to know the size of the EFI_FILE_INFO data structure, it needs to
+/// be the size of the data structure without the FileName field.  The following macro
+/// computes this size correctly no matter how big the FileName array is declared.
+/// This is required to make the EFI_FILE_INFO data structure ANSI compilant.
+///
+#define SIZE_OF_EFI_FILE_INFO OFFSET_OF (EFI_FILE_INFO, FileName)
+
+extern EFI_GUID gEfiFileInfoGuid;
+
+#endif
diff --git a/roms/ipxe/src/include/ipxe/efi/Guid/FileSystemInfo.h b/roms/ipxe/src/include/ipxe/efi/Guid/FileSystemInfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..504b7938f69a02c12d4d75539cdb643e834417c0
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/efi/Guid/FileSystemInfo.h
@@ -0,0 +1,65 @@
+/** @file
+  Provides a GUID and a data structure that can be used with EFI_FILE_PROTOCOL.GetInfo()
+  or EFI_FILE_PROTOCOL.SetInfo() to get or set information about the system's volume.
+  This GUID is defined in UEFI specification.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that 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 __FILE_SYSTEM_INFO_H__
+#define __FILE_SYSTEM_INFO_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_FILE_SYSTEM_INFO_ID \
+  { \
+    0x9576e93, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+  }
+
+typedef struct {
+  ///
+  /// The size of the EFI_FILE_SYSTEM_INFO structure, including the Null-terminated VolumeLabel string.
+  ///
+  UINT64  Size;
+  ///
+  /// TRUE if the volume only supports read access.
+  ///
+  BOOLEAN ReadOnly;
+  ///
+  /// The number of bytes managed by the file system.
+  ///
+  UINT64  VolumeSize;
+  ///
+  /// The number of available bytes for use by the file system.
+  ///
+  UINT64  FreeSpace;
+  ///
+  /// The nominal block size by which files are typically grown.
+  ///
+  UINT32  BlockSize;
+  ///
+  /// The Null-terminated string that is the volume's label.
+  ///
+  CHAR16  VolumeLabel[1];
+} EFI_FILE_SYSTEM_INFO;
+
+///
+/// The VolumeLabel field of the EFI_FILE_SYSTEM_INFO data structure is variable length.
+/// Whenever code needs to know the size of the EFI_FILE_SYSTEM_INFO data structure, it needs
+/// to be the size of the data structure without the VolumeLable field.  The following macro
+/// computes this size correctly no matter how big the VolumeLable array is declared.
+/// This is required to make the EFI_FILE_SYSTEM_INFO data structure ANSI compilant.
+///
+#define SIZE_OF_EFI_FILE_SYSTEM_INFO  OFFSET_OF (EFI_FILE_SYSTEM_INFO, VolumeLabel)
+
+extern EFI_GUID gEfiFileSystemInfoGuid;
+
+#endif
diff --git a/roms/ipxe/src/include/ipxe/efi/Guid/WinCertificate.h b/roms/ipxe/src/include/ipxe/efi/Guid/WinCertificate.h
index 75fc642f09e633a08668280f721e..cf0a7c25e90693bdbba3b15234ca 100644
--- a/roms/ipxe/src/include/ipxe/efi/Guid/WinCertificate.h
+++ b/roms/ipxe/src/include/ipxe/efi/Guid/WinCertificate.h
@@ -1,7 +1,7 @@
 /** @file
   GUID for UEFI WIN_CERTIFICATE structure.
 
-  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
   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
@@ -76,7 +76,7 @@ typedef struct {
 typedef struct {
   ///
   /// This is the standard WIN_CERTIFICATE header, where
-  /// wCertificateType is set to WIN_CERT_TYPE_UEFI_GUID.
+  /// wCertificateType is set to WIN_CERT_TYPE_EFI_GUID.
   ///
   WIN_CERTIFICATE   Hdr;
   ///
diff --git a/roms/ipxe/src/include/ipxe/efi/Ia32/ProcessorBind.h b/roms/ipxe/src/include/ipxe/efi/Ia32/ProcessorBind.h
index 20cf407b6a5f8f84d47488d8ed95..89bce6ff96328f0635621469ed37 100644
--- a/roms/ipxe/src/include/ipxe/efi/Ia32/ProcessorBind.h
+++ b/roms/ipxe/src/include/ipxe/efi/Ia32/ProcessorBind.h
@@ -1,7 +1,7 @@
 /** @file
   Processor or Compiler specific defines and types for IA-32 architecture.
 
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials are licensed and made available under
 the terms and conditions of the BSD License that accompanies this distribution.
 The full text of the license may be found at
@@ -149,7 +149,7 @@ FILE_LICENCE ( BSD3 );
   ///
   /// 1-byte signed value.
   ///
-  typedef char                INT8;
+  typedef signed char         INT8;
 #else
   ///
   /// 8-byte unsigned value.
@@ -196,7 +196,7 @@ FILE_LICENCE ( BSD3 );
   ///
   /// 1-byte signed value
   ///
-  typedef char                INT8;
+  typedef signed char         INT8;
 #endif
 
 ///
@@ -247,13 +247,17 @@ typedef INT32   INTN;
   /// Microsoft* compiler specific method for EFIAPI calling convention.
   ///
   #define EFIAPI __cdecl
+#elif defined(__GNUC__)
+  ///
+  /// GCC specific method for EFIAPI calling convention.
+  ///
+  #define EFIAPI __attribute__((cdecl))
 #else
-  #if defined(__GNUC__)
-    ///
-    /// GCC specific method for EFIAPI calling convention.
-    ///
-    #define EFIAPI __attribute__((cdecl))
-  #endif
+  ///
+  /// The default for a non Microsoft* or GCC compiler is to assume the EFI ABI
+  /// is the standard.
+  ///
+  #define EFIAPI
 #endif
 
 #if defined(__GNUC__)
diff --git a/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Pci22.h b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Pci22.h
index b57059a945e3b004ea1714e4e46b..53654ee42573c6d2931138b12c69 100644
--- a/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Pci22.h
+++ b/roms/ipxe/src/include/ipxe/efi/IndustryStandard/Pci22.h
@@ -6,7 +6,7 @@
     PCI-to-PCI Bridge Architecture Specification, Revision 1.2
     PC Card Standard, 8.0
 
-  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
   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
@@ -221,7 +221,7 @@ typedef struct {
 #define     PCI_IF_16550_MODEM            0x02
 #define     PCI_IF_16650_MODEM            0x03
 #define     PCI_IF_16750_MODEM            0x04
-#define   PCI_SUBCLASS_SCC_OTHER          0x80
+#define   PCI_SUBCLASS_SCC_OTHER        0x80
 
 #define PCI_CLASS_SYSTEM_PERIPHERAL   0x08
 #define   PCI_SUBCLASS_PIC              0x00
@@ -240,7 +240,7 @@ typedef struct {
 #define     PCI_IF_EISA_TIMER             0x02
 #define   PCI_SUBCLASS_RTC              0x03
 #define     PCI_IF_GENERIC_RTC            0x00
-#define     PCI_IF_ISA_RTC                0x00
+#define     PCI_IF_ISA_RTC                0x01
 #define   PCI_SUBCLASS_PNP_CONTROLLER   0x04    ///< HotPlug Controller
 #define   PCI_SUBCLASS_PERIPHERAL_OTHER 0x80
 
@@ -251,10 +251,12 @@ typedef struct {
 #define   PCI_SUBCLASS_SCAN_CONTROLLER  0x03
 #define   PCI_SUBCLASS_GAMEPORT         0x04
 #define     PCI_IF_GAMEPORT               0x00
-#define     PCI_IF_GAMEPORT1              0x01
+#define     PCI_IF_GAMEPORT1              0x10
 #define   PCI_SUBCLASS_INPUT_OTHER      0x80
 
 #define PCI_CLASS_DOCKING_STATION     0x0A
+#define   PCI_SUBCLASS_DOCKING_GENERIC  0x00
+#define   PCI_SUBCLASS_DOCKING_OTHER    0x80
 
 #define PCI_CLASS_PROCESSOR           0x0B
 #define   PCI_SUBCLASS_PROC_386         0x00
@@ -282,7 +284,7 @@ typedef struct {
 #define PCI_CLASS_WIRELESS            0x0D
 #define   PCI_SUBCLASS_IRDA             0x00
 #define   PCI_SUBCLASS_IR               0x01
-#define   PCI_SUBCLASS_RF               0x02
+#define   PCI_SUBCLASS_RF               0x10
 #define   PCI_SUBCLASS_WIRELESS_OTHER   0x80
 
 #define PCI_CLASS_INTELLIGENT_IO      0x0E
diff --git a/roms/ipxe/src/include/ipxe/efi/Library/BaseLib.h b/roms/ipxe/src/include/ipxe/efi/Library/BaseLib.h
new file mode 100644
index 0000000000000000000000000000000000000000..be521f96949e81b12b69075e51d12bc37ad4111a
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/efi/Library/BaseLib.h
@@ -0,0 +1,7250 @@
+/** @file
+  Provides string functions, linked list functions, math functions, synchronization
+  functions, and CPU architecture-specific functions.
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+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_LIB__
+#define __BASE_LIB__
+
+FILE_LICENCE ( BSD3 );
+
+//
+// Definitions for architecture-specific types
+//
+#if   defined (MDE_CPU_IA32)
+///
+/// The IA-32 architecture context buffer used by SetJump() and LongJump().
+///
+typedef struct {
+  UINT32                            Ebx;
+  UINT32                            Esi;
+  UINT32                            Edi;
+  UINT32                            Ebp;
+  UINT32                            Esp;
+  UINT32                            Eip;
+} BASE_LIBRARY_JUMP_BUFFER;
+
+#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 4
+
+#endif // defined (MDE_CPU_IA32)
+
+#if defined (MDE_CPU_IPF)
+
+///
+/// The Itanium architecture context buffer used by SetJump() and LongJump().
+///
+typedef struct {
+  UINT64                            F2[2];
+  UINT64                            F3[2];
+  UINT64                            F4[2];
+  UINT64                            F5[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                            R4;
+  UINT64                            R5;
+  UINT64                            R6;
+  UINT64                            R7;
+  UINT64                            SP;
+  UINT64                            BR0;
+  UINT64                            BR1;
+  UINT64                            BR2;
+  UINT64                            BR3;
+  UINT64                            BR4;
+  UINT64                            BR5;
+  UINT64                            InitialUNAT;
+  UINT64                            AfterSpillUNAT;
+  UINT64                            PFS;
+  UINT64                            BSP;
+  UINT64                            Predicates;
+  UINT64                            LoopCount;
+  UINT64                            FPSR;
+} BASE_LIBRARY_JUMP_BUFFER;
+
+#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 0x10
+
+#endif // defined (MDE_CPU_IPF)
+
+#if defined (MDE_CPU_X64)
+///
+/// The x64 architecture context buffer used by SetJump() and LongJump().
+///
+typedef struct {
+  UINT64                            Rbx;
+  UINT64                            Rsp;
+  UINT64                            Rbp;
+  UINT64                            Rdi;
+  UINT64                            Rsi;
+  UINT64                            R12;
+  UINT64                            R13;
+  UINT64                            R14;
+  UINT64                            R15;
+  UINT64                            Rip;
+  UINT64                            MxCsr;
+  UINT8                             XmmBuffer[160]; ///< XMM6-XMM15.
+} BASE_LIBRARY_JUMP_BUFFER;
+
+#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 8
+
+#endif // defined (MDE_CPU_X64)
+
+#if defined (MDE_CPU_EBC)
+///
+/// The EBC context buffer used by SetJump() and LongJump().
+///
+typedef struct {
+  UINT64                            R0;
+  UINT64                            R1;
+  UINT64                            R2;
+  UINT64                            R3;
+  UINT64                            IP;
+} BASE_LIBRARY_JUMP_BUFFER;
+
+#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 8
+
+#endif // defined (MDE_CPU_EBC)
+
+#if defined (MDE_CPU_ARM)
+
+typedef struct {
+  UINT32    R3;  ///< A copy of R13.
+  UINT32    R4;
+  UINT32    R5;
+  UINT32    R6;
+  UINT32    R7;
+  UINT32    R8;
+  UINT32    R9;
+  UINT32    R10;
+  UINT32    R11;
+  UINT32    R12;
+  UINT32    R14;
+} BASE_LIBRARY_JUMP_BUFFER;
+
+#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 4
+
+#endif  // defined (MDE_CPU_ARM)
+
+//
+// String Services
+//
+
+/**
+  Copies one Null-terminated Unicode string to another Null-terminated Unicode
+  string and returns the new Unicode string.
+
+  This function copies the contents of the Unicode string Source to the Unicode
+  string Destination, and returns Destination. If Source and Destination
+  overlap, then the results are undefined.
+
+  If Destination is NULL, then ASSERT().
+  If Destination is not aligned on a 16-bit boundary, then ASSERT().
+  If Source is NULL, then ASSERT().
+  If Source is not aligned on a 16-bit boundary, then ASSERT().
+  If Source and Destination overlap, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
+  PcdMaximumUnicodeStringLength Unicode characters not including the
+  Null-terminator, then ASSERT().
+
+  @param  Destination The pointer to a Null-terminated Unicode string.
+  @param  Source      The pointer to a Null-terminated Unicode string.
+
+  @return Destination.
+
+**/
+CHAR16 *
+EFIAPI
+StrCpy (
+  OUT     CHAR16                    *Destination,
+  IN      CONST CHAR16              *Source
+  );
+
+
+/**
+  Copies up to a specified length from one Null-terminated Unicode string to
+  another Null-terminated Unicode string and returns the new Unicode string.
+
+  This function copies the contents of the Unicode string Source to the Unicode
+  string Destination, and returns Destination. At most, Length Unicode
+  characters are copied from Source to Destination. If Length is 0, then
+  Destination is returned unmodified. If Length is greater that the number of
+  Unicode characters in Source, then Destination is padded with Null Unicode
+  characters. If Source and Destination overlap, then the results are
+  undefined.
+
+  If Length > 0 and Destination is NULL, then ASSERT().
+  If Length > 0 and Destination is not aligned on a 16-bit boundary, then ASSERT().
+  If Length > 0 and Source is NULL, then ASSERT().
+  If Length > 0 and Source is not aligned on a 16-bit boundary, then ASSERT().
+  If Source and Destination overlap, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and Length is greater than
+  PcdMaximumUnicodeStringLength, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
+  PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
+  then ASSERT().
+
+  @param  Destination The pointer to a Null-terminated Unicode string.
+  @param  Source      The pointer to a Null-terminated Unicode string.
+  @param  Length      The maximum number of Unicode characters to copy.
+
+  @return Destination.
+
+**/
+CHAR16 *
+EFIAPI
+StrnCpy (
+  OUT     CHAR16                    *Destination,
+  IN      CONST CHAR16              *Source,
+  IN      UINTN                     Length
+  );
+
+
+/**
+  Returns the length of a Null-terminated Unicode string.
+
+  This function returns the number of Unicode characters in the Null-terminated
+  Unicode string specified by String.
+
+  If String is NULL, then ASSERT().
+  If String is not aligned on a 16-bit boundary, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+  PcdMaximumUnicodeStringLength Unicode characters not including the
+  Null-terminator, then ASSERT().
+
+  @param  String  Pointer to a Null-terminated Unicode string.
+
+  @return The length of String.
+
+**/
+UINTN
+EFIAPI
+StrLen (
+  IN      CONST CHAR16              *String
+  );
+
+
+/**
+  Returns the size of a Null-terminated Unicode string in bytes, including the
+  Null terminator.
+
+  This function returns the size, in bytes, of the Null-terminated Unicode string
+  specified by String.
+
+  If String is NULL, then ASSERT().
+  If String is not aligned on a 16-bit boundary, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+  PcdMaximumUnicodeStringLength Unicode characters not including the
+  Null-terminator, then ASSERT().
+
+  @param  String  The pointer to a Null-terminated Unicode string.
+
+  @return The size of String.
+
+**/
+UINTN
+EFIAPI
+StrSize (
+  IN      CONST CHAR16              *String
+  );
+
+
+/**
+  Compares two Null-terminated Unicode strings, and returns the difference
+  between the first mismatched Unicode characters.
+
+  This function compares the Null-terminated Unicode string FirstString to the
+  Null-terminated Unicode string SecondString. If FirstString is identical to
+  SecondString, then 0 is returned. Otherwise, the value returned is the first
+  mismatched Unicode character in SecondString subtracted from the first
+  mismatched Unicode character in FirstString.
+
+  If FirstString is NULL, then ASSERT().
+  If FirstString is not aligned on a 16-bit boundary, then ASSERT().
+  If SecondString is NULL, then ASSERT().
+  If SecondString is not aligned on a 16-bit boundary, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and FirstString contains more
+  than PcdMaximumUnicodeStringLength Unicode characters not including the
+  Null-terminator, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and SecondString contains more
+  than PcdMaximumUnicodeStringLength Unicode characters, not including the
+  Null-terminator, then ASSERT().
+
+  @param  FirstString   The pointer to a Null-terminated Unicode string.
+  @param  SecondString  The pointer to a Null-terminated Unicode string.
+
+  @retval 0      FirstString is identical to SecondString.
+  @return others FirstString is not identical to SecondString.
+
+**/
+INTN
+EFIAPI
+StrCmp (
+  IN      CONST CHAR16              *FirstString,
+  IN      CONST CHAR16              *SecondString
+  );
+
+
+/**
+  Compares up to a specified length the contents of two Null-terminated Unicode strings,
+  and returns the difference between the first mismatched Unicode characters.
+
+  This function compares the Null-terminated Unicode string FirstString to the
+  Null-terminated Unicode string SecondString. At most, Length Unicode
+  characters will be compared. If Length is 0, then 0 is returned. If
+  FirstString is identical to SecondString, then 0 is returned. Otherwise, the
+  value returned is the first mismatched Unicode character in SecondString
+  subtracted from the first mismatched Unicode character in FirstString.
+
+  If Length > 0 and FirstString is NULL, then ASSERT().
+  If Length > 0 and FirstString is not aligned on a 16-bit boundary, then ASSERT().
+  If Length > 0 and SecondString is NULL, then ASSERT().
+  If Length > 0 and SecondString is not aligned on a 16-bit boundary, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and Length is greater than
+  PcdMaximumUnicodeStringLength, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and FirstString contains more than
+  PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
+  then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and SecondString contains more than
+  PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
+  then ASSERT().
+
+  @param  FirstString   The pointer to a Null-terminated Unicode string.
+  @param  SecondString  The pointer to a Null-terminated Unicode string.
+  @param  Length        The maximum number of Unicode characters to compare.
+
+  @retval 0      FirstString is identical to SecondString.
+  @return others FirstString is not identical to SecondString.
+
+**/
+INTN
+EFIAPI
+StrnCmp (
+  IN      CONST CHAR16              *FirstString,
+  IN      CONST CHAR16              *SecondString,
+  IN      UINTN                     Length
+  );
+
+
+/**
+  Concatenates one Null-terminated Unicode string to another Null-terminated
+  Unicode string, and returns the concatenated Unicode string.
+
+  This function concatenates two Null-terminated Unicode strings. The contents
+  of Null-terminated Unicode string Source are concatenated to the end of
+  Null-terminated Unicode string Destination. The Null-terminated concatenated
+  Unicode String is returned. If Source and Destination overlap, then the
+  results are undefined.
+
+  If Destination is NULL, then ASSERT().
+  If Destination is not aligned on a 16-bit boundary, then ASSERT().
+  If Source is NULL, then ASSERT().
+  If Source is not aligned on a 16-bit boundary, then ASSERT().
+  If Source and Destination overlap, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and Destination contains more
+  than PcdMaximumUnicodeStringLength Unicode characters, not including the
+  Null-terminator, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
+  PcdMaximumUnicodeStringLength Unicode characters, not including the
+  Null-terminator, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and concatenating Destination
+  and Source results in a Unicode string with more than
+  PcdMaximumUnicodeStringLength Unicode characters, not including the
+  Null-terminator, then ASSERT().
+
+  @param  Destination The pointer to a Null-terminated Unicode string.
+  @param  Source      The pointer to a Null-terminated Unicode string.
+
+  @return Destination.
+
+**/
+CHAR16 *
+EFIAPI
+StrCat (
+  IN OUT  CHAR16                    *Destination,
+  IN      CONST CHAR16              *Source
+  );
+
+
+/**
+  Concatenates up to a specified length one Null-terminated Unicode to the end
+  of another Null-terminated Unicode string, and returns the concatenated
+  Unicode string.
+
+  This function concatenates two Null-terminated Unicode strings. The contents
+  of Null-terminated Unicode string Source are concatenated to the end of
+  Null-terminated Unicode string Destination, and Destination is returned. At
+  most, Length Unicode characters are concatenated from Source to the end of
+  Destination, and Destination is always Null-terminated. If Length is 0, then
+  Destination is returned unmodified. If Source and Destination overlap, then
+  the results are undefined.
+
+  If Destination is NULL, then ASSERT().
+  If Length > 0 and Destination is not aligned on a 16-bit boundary, then ASSERT().
+  If Length > 0 and Source is NULL, then ASSERT().
+  If Length > 0 and Source is not aligned on a 16-bit boundary, then ASSERT().
+  If Source and Destination overlap, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and Length is greater than
+  PcdMaximumUnicodeStringLength, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and Destination contains more
+  than PcdMaximumUnicodeStringLength Unicode characters, not including the
+  Null-terminator, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
+  PcdMaximumUnicodeStringLength Unicode characters, not including the
+  Null-terminator, then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and concatenating Destination
+  and Source results in a Unicode string with more than PcdMaximumUnicodeStringLength
+  Unicode characters, not including the Null-terminator, then ASSERT().
+
+  @param  Destination The pointer to a Null-terminated Unicode string.
+  @param  Source      The pointer to a Null-terminated Unicode string.
+  @param  Length      The maximum number of Unicode characters to concatenate from
+                      Source.
+
+  @return Destination.
+
+**/
+CHAR16 *
+EFIAPI
+StrnCat (
+  IN OUT  CHAR16                    *Destination,
+  IN      CONST CHAR16              *Source,
+  IN      UINTN                     Length
+  );
+
+/**
+  Returns the first occurrence of a Null-terminated Unicode sub-string
+  in a Null-terminated Unicode string.
+
+  This function scans the contents of the Null-terminated Unicode string
+  specified by String and returns the first occurrence of SearchString.
+  If SearchString is not found in String, then NULL is returned.  If
+  the length of SearchString is zero, then String is returned.
+
+  If String is NULL, then ASSERT().
+  If String is not aligned on a 16-bit boundary, then ASSERT().
+  If SearchString is NULL, then ASSERT().
+  If SearchString is not aligned on a 16-bit boundary, then ASSERT().
+
+  If PcdMaximumUnicodeStringLength is not zero, and SearchString
+  or String contains more than PcdMaximumUnicodeStringLength Unicode
+  characters, not including the Null-terminator, then ASSERT().
+
+  @param  String          The pointer to a Null-terminated Unicode string.
+  @param  SearchString    The pointer to a Null-terminated Unicode string to search for.
+
+  @retval NULL            If the SearchString does not appear in String.
+  @return others          If there is a match.
+
+**/
+CHAR16 *
+EFIAPI
+StrStr (
+  IN      CONST CHAR16              *String,
+  IN      CONST CHAR16              *SearchString
+  );
+
+/**
+  Convert a Null-terminated Unicode decimal string to a value of
+  type UINTN.
+
+  This function returns a value of type UINTN by interpreting the contents
+  of the Unicode string specified by String as a decimal number. The format
+  of the input Unicode string String is:
+
+                  [spaces] [decimal digits].
+
+  The valid decimal digit character is in the range [0-9]. The
+  function will ignore the pad space, which includes spaces or
+  tab characters, before [decimal digits]. The running zero in the
+  beginning of [decimal digits] will be ignored. Then, the function
+  stops at the first character that is a not a valid decimal character
+  or a Null-terminator, whichever one comes first.
+
+  If String is NULL, then ASSERT().
+  If String is not aligned in a 16-bit boundary, then ASSERT().
+  If String has only pad spaces, then 0 is returned.
+  If String has no pad spaces or valid decimal digits,
+  then 0 is returned.
+  If the number represented by String overflows according
+  to the range defined by UINTN, then ASSERT().
+
+  If PcdMaximumUnicodeStringLength is not zero, and String contains
+  more than PcdMaximumUnicodeStringLength Unicode characters not including
+  the Null-terminator, then ASSERT().
+
+  @param  String      The pointer to a Null-terminated Unicode string.
+
+  @retval Value translated from String.
+
+**/
+UINTN
+EFIAPI
+StrDecimalToUintn (
+  IN      CONST CHAR16              *String
+  );
+
+/**
+  Convert a Null-terminated Unicode decimal string to a value of
+  type UINT64.
+
+  This function returns a value of type UINT64 by interpreting the contents
+  of the Unicode string specified by String as a decimal number. The format
+  of the input Unicode string String is:
+
+                  [spaces] [decimal digits].
+
+  The valid decimal digit character is in the range [0-9]. The
+  function will ignore the pad space, which includes spaces or
+  tab characters, before [decimal digits]. The running zero in the
+  beginning of [decimal digits] will be ignored. Then, the function
+  stops at the first character that is a not a valid decimal character
+  or a Null-terminator, whichever one comes first.
+
+  If String is NULL, then ASSERT().
+  If String is not aligned in a 16-bit boundary, then ASSERT().
+  If String has only pad spaces, then 0 is returned.
+  If String has no pad spaces or valid decimal digits,
+  then 0 is returned.
+  If the number represented by String overflows according
+  to the range defined by UINT64, then ASSERT().
+
+  If PcdMaximumUnicodeStringLength is not zero, and String contains
+  more than PcdMaximumUnicodeStringLength Unicode characters not including
+  the Null-terminator, then ASSERT().
+
+  @param  String          The pointer to a Null-terminated Unicode string.
+
+  @retval Value translated from String.
+
+**/
+UINT64
+EFIAPI
+StrDecimalToUint64 (
+  IN      CONST CHAR16              *String
+  );
+
+
+/**
+  Convert a Null-terminated Unicode hexadecimal string to a value of type UINTN.
+
+  This function returns a value of type UINTN by interpreting the contents
+  of the Unicode string specified by String as a hexadecimal number.
+  The format of the input Unicode string String is:
+
+                  [spaces][zeros][x][hexadecimal digits].
+
+  The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
+  The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
+  If "x" appears in the input string, it must be prefixed with at least one 0.
+  The function will ignore the pad space, which includes spaces or tab characters,
+  before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
+  [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
+  first valid hexadecimal digit. Then, the function stops at the first character
+  that is a not a valid hexadecimal character or NULL, whichever one comes first.
+
+  If String is NULL, then ASSERT().
+  If String is not aligned in a 16-bit boundary, then ASSERT().
+  If String has only pad spaces, then zero is returned.
+  If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
+  then zero is returned.
+  If the number represented by String overflows according to the range defined by
+  UINTN, then ASSERT().
+
+  If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+  PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator,
+  then ASSERT().
+
+  @param  String          The pointer to a Null-terminated Unicode string.
+
+  @retval Value translated from String.
+
+**/
+UINTN
+EFIAPI
+StrHexToUintn (
+  IN      CONST CHAR16              *String
+  );
+
+
+/**
+  Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
+
+  This function returns a value of type UINT64 by interpreting the contents
+  of the Unicode string specified by String as a hexadecimal number.
+  The format of the input Unicode string String is
+
+                  [spaces][zeros][x][hexadecimal digits].
+
+  The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
+  The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
+  If "x" appears in the input string, it must be prefixed with at least one 0.
+  The function will ignore the pad space, which includes spaces or tab characters,
+  before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
+  [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
+  first valid hexadecimal digit. Then, the function stops at the first character that is
+  a not a valid hexadecimal character or NULL, whichever one comes first.
+
+  If String is NULL, then ASSERT().
+  If String is not aligned in a 16-bit boundary, then ASSERT().
+  If String has only pad spaces, then zero is returned.
+  If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
+  then zero is returned.
+  If the number represented by String overflows according to the range defined by
+  UINT64, then ASSERT().
+
+  If PcdMaximumUnicodeStringLength is not zero, and String contains more than
+  PcdMaximumUnicodeStringLength Unicode characters not including the Null-terminator,
+  then ASSERT().
+
+  @param  String          The pointer to a Null-terminated Unicode string.
+
+  @retval Value translated from String.
+
+**/
+UINT64
+EFIAPI
+StrHexToUint64 (
+  IN      CONST CHAR16             *String
+  );
+
+/**
+  Convert a Null-terminated Unicode string to a Null-terminated
+  ASCII string and returns the ASCII string.
+
+  This function converts the content of the Unicode string Source
+  to the ASCII string Destination by copying the lower 8 bits of
+  each Unicode character. It returns Destination.
+
+  The caller is responsible to make sure Destination points to a buffer with size
+  equal or greater than ((StrLen (Source) + 1) * sizeof (CHAR8)) in bytes.
+
+  If any Unicode characters in Source contain non-zero value in
+  the upper 8 bits, then ASSERT().
+
+  If Destination is NULL, then ASSERT().
+  If Source is NULL, then ASSERT().
+  If Source is not aligned on a 16-bit boundary, then ASSERT().
+  If Source and Destination overlap, then ASSERT().
+
+  If PcdMaximumUnicodeStringLength is not zero, and Source contains
+  more than PcdMaximumUnicodeStringLength Unicode characters not including
+  the Null-terminator, then ASSERT().
+
+  If PcdMaximumAsciiStringLength is not zero, and Source contains more
+  than PcdMaximumAsciiStringLength Unicode characters not including the
+  Null-terminator, then ASSERT().
+
+  @param  Source        The pointer to a Null-terminated Unicode string.
+  @param  Destination   The pointer to a Null-terminated ASCII string.
+
+  @return Destination.
+
+**/
+CHAR8 *
+EFIAPI
+UnicodeStrToAsciiStr (
+  IN      CONST CHAR16              *Source,
+  OUT     CHAR8                     *Destination
+  );
+
+
+/**
+  Copies one Null-terminated ASCII string to another Null-terminated ASCII
+  string and returns the new ASCII string.
+
+  This function copies the contents of the ASCII string Source to the ASCII
+  string Destination, and returns Destination. If Source and Destination
+  overlap, then the results are undefined.
+
+  If Destination is NULL, then ASSERT().
+  If Source is NULL, then ASSERT().
+  If Source and Destination overlap, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero and Source contains more than
+  PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator,
+  then ASSERT().
+
+  @param  Destination The pointer to a Null-terminated ASCII string.
+  @param  Source      The pointer to a Null-terminated ASCII string.
+
+  @return Destination
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrCpy (
+  OUT     CHAR8                     *Destination,
+  IN      CONST CHAR8               *Source
+  );
+
+
+/**
+  Copies up to a specified length one Null-terminated ASCII string to another
+  Null-terminated ASCII string and returns the new ASCII string.
+
+  This function copies the contents of the ASCII string Source to the ASCII
+  string Destination, and returns Destination. At most, Length ASCII characters
+  are copied from Source to Destination. If Length is 0, then Destination is
+  returned unmodified. If Length is greater that the number of ASCII characters
+  in Source, then Destination is padded with Null ASCII characters. If Source
+  and Destination overlap, then the results are undefined.
+
+  If Destination is NULL, then ASSERT().
+  If Source is NULL, then ASSERT().
+  If Source and Destination overlap, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero, and Length is greater than
+  PcdMaximumAsciiStringLength, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero, and Source contains more than
+  PcdMaximumAsciiStringLength ASCII characters, not including the Null-terminator,
+  then ASSERT().
+
+  @param  Destination The pointer to a Null-terminated ASCII string.
+  @param  Source      The pointer to a Null-terminated ASCII string.
+  @param  Length      The maximum number of ASCII characters to copy.
+
+  @return Destination
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrnCpy (
+  OUT     CHAR8                     *Destination,
+  IN      CONST CHAR8               *Source,
+  IN      UINTN                     Length
+  );
+
+
+/**
+  Returns the length of a Null-terminated ASCII string.
+
+  This function returns the number of ASCII characters in the Null-terminated
+  ASCII string specified by String.
+
+  If Length > 0 and Destination is NULL, then ASSERT().
+  If Length > 0 and Source is NULL, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero and String contains more than
+  PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator,
+  then ASSERT().
+
+  @param  String  The pointer to a Null-terminated ASCII string.
+
+  @return The length of String.
+
+**/
+UINTN
+EFIAPI
+AsciiStrLen (
+  IN      CONST CHAR8               *String
+  );
+
+
+/**
+  Returns the size of a Null-terminated ASCII string in bytes, including the
+  Null terminator.
+
+  This function returns the size, in bytes, of the Null-terminated ASCII string
+  specified by String.
+
+  If String is NULL, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero and String contains more than
+  PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator,
+  then ASSERT().
+
+  @param  String  The pointer to a Null-terminated ASCII string.
+
+  @return The size of String.
+
+**/
+UINTN
+EFIAPI
+AsciiStrSize (
+  IN      CONST CHAR8               *String
+  );
+
+
+/**
+  Compares two Null-terminated ASCII strings, and returns the difference
+  between the first mismatched ASCII characters.
+
+  This function compares the Null-terminated ASCII string FirstString to the
+  Null-terminated ASCII string SecondString. If FirstString is identical to
+  SecondString, then 0 is returned. Otherwise, the value returned is the first
+  mismatched ASCII character in SecondString subtracted from the first
+  mismatched ASCII character in FirstString.
+
+  If FirstString is NULL, then ASSERT().
+  If SecondString is NULL, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero and FirstString contains more than
+  PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator,
+  then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero and SecondString contains more
+  than PcdMaximumAsciiStringLength ASCII characters not including the
+  Null-terminator, then ASSERT().
+
+  @param  FirstString   The pointer to a Null-terminated ASCII string.
+  @param  SecondString  The pointer to a Null-terminated ASCII string.
+
+  @retval ==0      FirstString is identical to SecondString.
+  @retval !=0      FirstString is not identical to SecondString.
+
+**/
+INTN
+EFIAPI
+AsciiStrCmp (
+  IN      CONST CHAR8               *FirstString,
+  IN      CONST CHAR8               *SecondString
+  );
+
+
+/**
+  Performs a case insensitive comparison of two Null-terminated ASCII strings,
+  and returns the difference between the first mismatched ASCII characters.
+
+  This function performs a case insensitive comparison of the Null-terminated
+  ASCII string FirstString to the Null-terminated ASCII string SecondString. If
+  FirstString is identical to SecondString, then 0 is returned. Otherwise, the
+  value returned is the first mismatched lower case ASCII character in
+  SecondString subtracted from the first mismatched lower case ASCII character
+  in FirstString.
+
+  If FirstString is NULL, then ASSERT().
+  If SecondString is NULL, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero and FirstString contains more than
+  PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator,
+  then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero and SecondString contains more
+  than PcdMaximumAsciiStringLength ASCII characters not including the
+  Null-terminator, then ASSERT().
+
+  @param  FirstString   The pointer to a Null-terminated ASCII string.
+  @param  SecondString  The pointer to a Null-terminated ASCII string.
+
+  @retval ==0    FirstString is identical to SecondString using case insensitive
+                 comparisons.
+  @retval !=0    FirstString is not identical to SecondString using case
+                 insensitive comparisons.
+
+**/
+INTN
+EFIAPI
+AsciiStriCmp (
+  IN      CONST CHAR8               *FirstString,
+  IN      CONST CHAR8               *SecondString
+  );
+
+
+/**
+  Compares two Null-terminated ASCII strings with maximum lengths, and returns
+  the difference between the first mismatched ASCII characters.
+
+  This function compares the Null-terminated ASCII string FirstString to the
+  Null-terminated ASCII  string SecondString. At most, Length ASCII characters
+  will be compared. If Length is 0, then 0 is returned. If FirstString is
+  identical to SecondString, then 0 is returned. Otherwise, the value returned
+  is the first mismatched ASCII character in SecondString subtracted from the
+  first mismatched ASCII character in FirstString.
+
+  If Length > 0 and FirstString is NULL, then ASSERT().
+  If Length > 0 and SecondString is NULL, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero, and Length is greater than
+  PcdMaximumAsciiStringLength, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero, and FirstString contains more than
+  PcdMaximumAsciiStringLength ASCII characters, not including the Null-terminator,
+  then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero, and SecondString contains more than
+  PcdMaximumAsciiStringLength ASCII characters, not including the Null-terminator,
+  then ASSERT().
+
+  @param  FirstString   The pointer to a Null-terminated ASCII string.
+  @param  SecondString  The pointer to a Null-terminated ASCII string.
+  @param  Length        The maximum number of ASCII characters for compare.
+
+  @retval ==0       FirstString is identical to SecondString.
+  @retval !=0       FirstString is not identical to SecondString.
+
+**/
+INTN
+EFIAPI
+AsciiStrnCmp (
+  IN      CONST CHAR8               *FirstString,
+  IN      CONST CHAR8               *SecondString,
+  IN      UINTN                     Length
+  );
+
+
+/**
+  Concatenates one Null-terminated ASCII string to another Null-terminated
+  ASCII string, and returns the concatenated ASCII string.
+
+  This function concatenates two Null-terminated ASCII strings. The contents of
+  Null-terminated ASCII string Source are concatenated to the end of Null-
+  terminated ASCII string Destination. The Null-terminated concatenated ASCII
+  String is returned.
+
+  If Destination is NULL, then ASSERT().
+  If Source is NULL, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero and Destination contains more than
+  PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator,
+  then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero and Source contains more than
+  PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator,
+  then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero and concatenating Destination and
+  Source results in a ASCII string with more than PcdMaximumAsciiStringLength
+  ASCII characters, then ASSERT().
+
+  @param  Destination The pointer to a Null-terminated ASCII string.
+  @param  Source      The pointer to a Null-terminated ASCII string.
+
+  @return Destination
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrCat (
+  IN OUT CHAR8    *Destination,
+  IN CONST CHAR8  *Source
+  );
+
+
+/**
+  Concatenates up to a specified length one Null-terminated ASCII string to
+  the end of another Null-terminated ASCII string, and returns the
+  concatenated ASCII string.
+
+  This function concatenates two Null-terminated ASCII strings. The contents
+  of Null-terminated ASCII string Source are concatenated to the end of Null-
+  terminated ASCII string Destination, and Destination is returned. At most,
+  Length ASCII characters are concatenated from Source to the end of
+  Destination, and Destination is always Null-terminated. If Length is 0, then
+  Destination is returned unmodified. If Source and Destination overlap, then
+  the results are undefined.
+
+  If Length > 0 and Destination is NULL, then ASSERT().
+  If Length > 0 and Source is NULL, then ASSERT().
+  If Source and Destination overlap, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero, and Length is greater than
+  PcdMaximumAsciiStringLength, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero, and Destination contains more than
+  PcdMaximumAsciiStringLength ASCII characters, not including the Null-terminator,
+  then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero, and Source contains more than
+  PcdMaximumAsciiStringLength ASCII characters, not including the Null-terminator,
+  then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero, and concatenating Destination and
+  Source results in a ASCII string with more than PcdMaximumAsciiStringLength
+  ASCII characters, not including the Null-terminator, then ASSERT().
+
+  @param  Destination The pointer to a Null-terminated ASCII string.
+  @param  Source      The pointer to a Null-terminated ASCII string.
+  @param  Length      The maximum number of ASCII characters to concatenate from
+                      Source.
+
+  @return Destination
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrnCat (
+  IN OUT  CHAR8                     *Destination,
+  IN      CONST CHAR8               *Source,
+  IN      UINTN                     Length
+  );
+
+
+/**
+  Returns the first occurrence of a Null-terminated ASCII sub-string
+  in a Null-terminated ASCII string.
+
+  This function scans the contents of the ASCII string specified by String
+  and returns the first occurrence of SearchString. If SearchString is not
+  found in String, then NULL is returned. If the length of SearchString is zero,
+  then String is returned.
+
+  If String is NULL, then ASSERT().
+  If SearchString is NULL, then ASSERT().
+
+  If PcdMaximumAsciiStringLength is not zero, and SearchString or
+  String contains more than PcdMaximumAsciiStringLength Unicode characters
+  not including the Null-terminator, then ASSERT().
+
+  @param  String          The pointer to a Null-terminated ASCII string.
+  @param  SearchString    The pointer to a Null-terminated ASCII string to search for.
+
+  @retval NULL            If the SearchString does not appear in String.
+  @retval others          If there is a match return the first occurrence of SearchingString.
+                          If the length of SearchString is zero,return String.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrStr (
+  IN      CONST CHAR8               *String,
+  IN      CONST CHAR8               *SearchString
+  );
+
+
+/**
+  Convert a Null-terminated ASCII decimal string to a value of type
+  UINTN.
+
+  This function returns a value of type UINTN by interpreting the contents
+  of the ASCII string String as a decimal number. The format of the input
+  ASCII string String is:
+
+                    [spaces] [decimal digits].
+
+  The valid decimal digit character is in the range [0-9]. The function will
+  ignore the pad space, which includes spaces or tab characters, before the digits.
+  The running zero in the beginning of [decimal digits] will be ignored. Then, the
+  function stops at the first character that is a not a valid decimal character or
+  Null-terminator, whichever on comes first.
+
+  If String has only pad spaces, then 0 is returned.
+  If String has no pad spaces or valid decimal digits, then 0 is returned.
+  If the number represented by String overflows according to the range defined by
+  UINTN, then ASSERT().
+  If String is NULL, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero, and String contains more than
+  PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator,
+  then ASSERT().
+
+  @param  String          The pointer to a Null-terminated ASCII string.
+
+  @retval The value translated from String.
+
+**/
+UINTN
+EFIAPI
+AsciiStrDecimalToUintn (
+  IN      CONST CHAR8               *String
+  );
+
+
+/**
+  Convert a Null-terminated ASCII decimal string to a value of type
+  UINT64.
+
+  This function returns a value of type UINT64 by interpreting the contents
+  of the ASCII string String as a decimal number. The format of the input
+  ASCII string String is:
+
+                    [spaces] [decimal digits].
+
+  The valid decimal digit character is in the range [0-9]. The function will
+  ignore the pad space, which includes spaces or tab characters, before the digits.
+  The running zero in the beginning of [decimal digits] will be ignored. Then, the
+  function stops at the first character that is a not a valid decimal character or
+  Null-terminator, whichever on comes first.
+
+  If String has only pad spaces, then 0 is returned.
+  If String has no pad spaces or valid decimal digits, then 0 is returned.
+  If the number represented by String overflows according to the range defined by
+  UINT64, then ASSERT().
+  If String is NULL, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero, and String contains more than
+  PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator,
+  then ASSERT().
+
+  @param  String          The pointer to a Null-terminated ASCII string.
+
+  @retval Value translated from String.
+
+**/
+UINT64
+EFIAPI
+AsciiStrDecimalToUint64 (
+  IN      CONST CHAR8               *String
+  );
+
+
+/**
+  Convert a Null-terminated ASCII hexadecimal string to a value of type UINTN.
+
+  This function returns a value of type UINTN by interpreting the contents of
+  the ASCII string String as a hexadecimal number. The format of the input ASCII
+  string String is:
+
+                  [spaces][zeros][x][hexadecimal digits].
+
+  The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
+  The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix. If "x"
+  appears in the input string, it must be prefixed with at least one 0. The function
+  will ignore the pad space, which includes spaces or tab characters, before [zeros],
+  [x] or [hexadecimal digits]. The running zero before [x] or [hexadecimal digits]
+  will be ignored. Then, the decoding starts after [x] or the first valid hexadecimal
+  digit. Then, the function stops at the first character that is a not a valid
+  hexadecimal character or Null-terminator, whichever on comes first.
+
+  If String has only pad spaces, then 0 is returned.
+  If String has no leading pad spaces, leading zeros or valid hexadecimal digits, then
+  0 is returned.
+
+  If the number represented by String overflows according to the range defined by UINTN,
+  then ASSERT().
+  If String is NULL, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero,
+  and String contains more than PcdMaximumAsciiStringLength ASCII characters not including
+  the Null-terminator, then ASSERT().
+
+  @param  String          The pointer to a Null-terminated ASCII string.
+
+  @retval Value translated from String.
+
+**/
+UINTN
+EFIAPI
+AsciiStrHexToUintn (
+  IN      CONST CHAR8               *String
+  );
+
+
+/**
+  Convert a Null-terminated ASCII hexadecimal string to a value of type UINT64.
+
+  This function returns a value of type UINT64 by interpreting the contents of
+  the ASCII string String as a hexadecimal number. The format of the input ASCII
+  string String is:
+
+                  [spaces][zeros][x][hexadecimal digits].
+
+  The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
+  The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix. If "x"
+  appears in the input string, it must be prefixed with at least one 0. The function
+  will ignore the pad space, which includes spaces or tab characters, before [zeros],
+  [x] or [hexadecimal digits]. The running zero before [x] or [hexadecimal digits]
+  will be ignored. Then, the decoding starts after [x] or the first valid hexadecimal
+  digit. Then, the function stops at the first character that is a not a valid
+  hexadecimal character or Null-terminator, whichever on comes first.
+
+  If String has only pad spaces, then 0 is returned.
+  If String has no leading pad spaces, leading zeros or valid hexadecimal digits, then
+  0 is returned.
+
+  If the number represented by String overflows according to the range defined by UINT64,
+  then ASSERT().
+  If String is NULL, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero,
+  and String contains more than PcdMaximumAsciiStringLength ASCII characters not including
+  the Null-terminator, then ASSERT().
+
+  @param  String          The pointer to a Null-terminated ASCII string.
+
+  @retval Value translated from String.
+
+**/
+UINT64
+EFIAPI
+AsciiStrHexToUint64 (
+  IN      CONST CHAR8                *String
+  );
+
+
+/**
+  Convert one Null-terminated ASCII string to a Null-terminated
+  Unicode string and returns the Unicode string.
+
+  This function converts the contents of the ASCII string Source to the Unicode
+  string Destination, and returns Destination.  The function terminates the
+  Unicode string Destination by appending a Null-terminator character at the end.
+  The caller is responsible to make sure Destination points to a buffer with size
+  equal or greater than ((AsciiStrLen (Source) + 1) * sizeof (CHAR16)) in bytes.
+
+  If Destination is NULL, then ASSERT().
+  If Destination is not aligned on a 16-bit boundary, then ASSERT().
+  If Source is NULL, then ASSERT().
+  If Source and Destination overlap, then ASSERT().
+  If PcdMaximumAsciiStringLength is not zero, and Source contains more than
+  PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator,
+  then ASSERT().
+  If PcdMaximumUnicodeStringLength is not zero, and Source contains more than
+  PcdMaximumUnicodeStringLength ASCII characters not including the
+  Null-terminator, then ASSERT().
+
+  @param  Source        The pointer to a Null-terminated ASCII string.
+  @param  Destination   The pointer to a Null-terminated Unicode string.
+
+  @return Destination.
+
+**/
+CHAR16 *
+EFIAPI
+AsciiStrToUnicodeStr (
+  IN      CONST CHAR8               *Source,
+  OUT     CHAR16                    *Destination
+  );
+
+
+/**
+  Converts an 8-bit value to an 8-bit BCD value.
+
+  Converts the 8-bit value specified by Value to BCD. The BCD value is
+  returned.
+
+  If Value >= 100, then ASSERT().
+
+  @param  Value The 8-bit value to convert to BCD. Range 0..99.
+
+  @return The BCD value.
+
+**/
+UINT8
+EFIAPI
+DecimalToBcd8 (
+  IN      UINT8                     Value
+  );
+
+
+/**
+  Converts an 8-bit BCD value to an 8-bit value.
+
+  Converts the 8-bit BCD value specified by Value to an 8-bit value. The 8-bit
+  value is returned.
+
+  If Value >= 0xA0, then ASSERT().
+  If (Value & 0x0F) >= 0x0A, then ASSERT().
+
+  @param  Value The 8-bit BCD value to convert to an 8-bit value.
+
+  @return The 8-bit value is returned.
+
+**/
+UINT8
+EFIAPI
+BcdToDecimal8 (
+  IN      UINT8                     Value
+  );
+
+
+//
+// Linked List Functions and Macros
+//
+
+/**
+  Initializes the head node of a doubly linked list that is declared as a
+  global variable in a module.
+
+  Initializes the forward and backward links of a new linked list. After
+  initializing a linked list with this macro, the other linked list functions
+  may be used to add and remove nodes from the linked list. This macro results
+  in smaller executables by initializing the linked list in the data section,
+  instead if calling the InitializeListHead() function to perform the
+  equivalent operation.
+
+  @param  ListHead  The head note of a list to initialize.
+
+**/
+#define INITIALIZE_LIST_HEAD_VARIABLE(ListHead)  {&(ListHead), &(ListHead)}
+
+
+/**
+  Initializes the head node of a doubly linked list, and returns the pointer to
+  the head node of the doubly linked list.
+
+  Initializes the forward and backward links of a new linked list. After
+  initializing a linked list with this function, the other linked list
+  functions may be used to add and remove nodes from the linked list. It is up
+  to the caller of this function to allocate the memory for ListHead.
+
+  If ListHead is NULL, then ASSERT().
+
+  @param  ListHead  A pointer to the head node of a new doubly linked list.
+
+  @return ListHead
+
+**/
+LIST_ENTRY *
+EFIAPI
+InitializeListHead (
+  IN OUT  LIST_ENTRY                *ListHead
+  );
+
+
+/**
+  Adds a node to the beginning of a doubly linked list, and returns the pointer
+  to the head node of the doubly linked list.
+
+  Adds the node Entry at the beginning of the doubly linked list denoted by
+  ListHead, and returns ListHead.
+
+  If ListHead is NULL, then ASSERT().
+  If Entry is NULL, then ASSERT().
+  If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLength is not zero, and prior to insertion the number
+  of nodes in ListHead, including the ListHead node, is greater than or
+  equal to PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  ListHead  A pointer to the head node of a doubly linked list.
+  @param  Entry     A pointer to a node that is to be inserted at the beginning
+                    of a doubly linked list.
+
+  @return ListHead
+
+**/
+LIST_ENTRY *
+EFIAPI
+InsertHeadList (
+  IN OUT  LIST_ENTRY                *ListHead,
+  IN OUT  LIST_ENTRY                *Entry
+  );
+
+
+/**
+  Adds a node to the end of a doubly linked list, and returns the pointer to
+  the head node of the doubly linked list.
+
+  Adds the node Entry to the end of the doubly linked list denoted by ListHead,
+  and returns ListHead.
+
+  If ListHead is NULL, then ASSERT().
+  If Entry is NULL, then ASSERT().
+  If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLength is not zero, and prior to insertion the number
+  of nodes in ListHead, including the ListHead node, is greater than or
+  equal to PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  ListHead  A pointer to the head node of a doubly linked list.
+  @param  Entry     A pointer to a node that is to be added at the end of the
+                    doubly linked list.
+
+  @return ListHead
+
+**/
+LIST_ENTRY *
+EFIAPI
+InsertTailList (
+  IN OUT  LIST_ENTRY                *ListHead,
+  IN OUT  LIST_ENTRY                *Entry
+  );
+
+
+/**
+  Retrieves the first node of a doubly linked list.
+
+  Returns the first node of a doubly linked list.  List must have been
+  initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+  If List is empty, then List is returned.
+
+  If List is NULL, then ASSERT().
+  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLength is not zero, and the number of nodes
+  in List, including the List node, is greater than or equal to
+  PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  List  A pointer to the head node of a doubly linked list.
+
+  @return The first node of a doubly linked list.
+  @retval NULL  The list is empty.
+
+**/
+LIST_ENTRY *
+EFIAPI
+GetFirstNode (
+  IN      CONST LIST_ENTRY          *List
+  );
+
+
+/**
+  Retrieves the next node of a doubly linked list.
+
+  Returns the node of a doubly linked list that follows Node.
+  List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()
+  or InitializeListHead().  If List is empty, then List is returned.
+
+  If List is NULL, then ASSERT().
+  If Node is NULL, then ASSERT().
+  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLength is not zero, and List contains more than
+  PcdMaximumLinkedListLength nodes, then ASSERT().
+  If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+  @param  List  A pointer to the head node of a doubly linked list.
+  @param  Node  A pointer to a node in the doubly linked list.
+
+  @return The pointer to the next node if one exists. Otherwise List is returned.
+
+**/
+LIST_ENTRY *
+EFIAPI
+GetNextNode (
+  IN      CONST LIST_ENTRY          *List,
+  IN      CONST LIST_ENTRY          *Node
+  );
+
+
+/**
+  Retrieves the previous node of a doubly linked list.
+
+  Returns the node of a doubly linked list that precedes Node.
+  List must have been initialized with INTIALIZE_LIST_HEAD_VARIABLE()
+  or InitializeListHead().  If List is empty, then List is returned.
+
+  If List is NULL, then ASSERT().
+  If Node is NULL, then ASSERT().
+  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLength is not zero, and List contains more than
+  PcdMaximumLinkedListLength nodes, then ASSERT().
+  If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+  @param  List  A pointer to the head node of a doubly linked list.
+  @param  Node  A pointer to a node in the doubly linked list.
+
+  @return The pointer to the previous node if one exists. Otherwise List is returned.
+
+**/
+LIST_ENTRY *
+EFIAPI
+GetPreviousNode (
+  IN      CONST LIST_ENTRY          *List,
+  IN      CONST LIST_ENTRY          *Node
+  );
+
+
+/**
+  Checks to see if a doubly linked list is empty or not.
+
+  Checks to see if the doubly linked list is empty. If the linked list contains
+  zero nodes, this function returns TRUE. Otherwise, it returns FALSE.
+
+  If ListHead is NULL, then ASSERT().
+  If ListHead was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLength is not zero, and the number of nodes
+  in List, including the List node, is greater than or equal to
+  PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  ListHead  A pointer to the head node of a doubly linked list.
+
+  @retval TRUE  The linked list is empty.
+  @retval FALSE The linked list is not empty.
+
+**/
+BOOLEAN
+EFIAPI
+IsListEmpty (
+  IN      CONST LIST_ENTRY          *ListHead
+  );
+
+
+/**
+  Determines if a node in a doubly linked list is the head node of a the same
+  doubly linked list.  This function is typically used to terminate a loop that
+  traverses all the nodes in a doubly linked list starting with the head node.
+
+  Returns TRUE if Node is equal to List.  Returns FALSE if Node is one of the
+  nodes in the doubly linked list specified by List.  List must have been
+  initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+
+  If List is NULL, then ASSERT().
+  If Node is NULL, then ASSERT().
+  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead(),
+  then ASSERT().
+  If PcdMaximumLinkedListLength is not zero, and the number of nodes
+  in List, including the List node, is greater than or equal to
+  PcdMaximumLinkedListLength, then ASSERT().
+  If PcdVerifyNodeInList is TRUE and Node is not a node in List the and Node is not equal
+  to List, then ASSERT().
+
+  @param  List  A pointer to the head node of a doubly linked list.
+  @param  Node  A pointer to a node in the doubly linked list.
+
+  @retval TRUE  Node is the head of the doubly-linked list pointed by List.
+  @retval FALSE Node is not the head of the doubly-linked list pointed by List.
+
+**/
+BOOLEAN
+EFIAPI
+IsNull (
+  IN      CONST LIST_ENTRY          *List,
+  IN      CONST LIST_ENTRY          *Node
+  );
+
+
+/**
+  Determines if a node the last node in a doubly linked list.
+
+  Returns TRUE if Node is the last node in the doubly linked list specified by
+  List. Otherwise, FALSE is returned. List must have been initialized with
+  INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+
+  If List is NULL, then ASSERT().
+  If Node is NULL, then ASSERT().
+  If List was not initialized with INTIALIZE_LIST_HEAD_VARIABLE() or
+  InitializeListHead(), then ASSERT().
+  If PcdMaximumLinkedListLength is not zero, and the number of nodes
+  in List, including the List node, is greater than or equal to
+  PcdMaximumLinkedListLength, then ASSERT().
+  If PcdVerifyNodeInList is TRUE and Node is not a node in List, then ASSERT().
+
+  @param  List  A pointer to the head node of a doubly linked list.
+  @param  Node  A pointer to a node in the doubly linked list.
+
+  @retval TRUE  Node is the last node in the linked list.
+  @retval FALSE Node is not the last node in the linked list.
+
+**/
+BOOLEAN
+EFIAPI
+IsNodeAtEnd (
+  IN      CONST LIST_ENTRY          *List,
+  IN      CONST LIST_ENTRY          *Node
+  );
+
+
+/**
+  Swaps the location of two nodes in a doubly linked list, and returns the
+  first node after the swap.
+
+  If FirstEntry is identical to SecondEntry, then SecondEntry is returned.
+  Otherwise, the location of the FirstEntry node is swapped with the location
+  of the SecondEntry node in a doubly linked list. SecondEntry must be in the
+  same double linked list as FirstEntry and that double linked list must have
+  been initialized with INTIALIZE_LIST_HEAD_VARIABLE() or InitializeListHead().
+  SecondEntry is returned after the nodes are swapped.
+
+  If FirstEntry is NULL, then ASSERT().
+  If SecondEntry is NULL, then ASSERT().
+  If PcdVerifyNodeInList is TRUE and SecondEntry and FirstEntry are not in the
+  same linked list, then ASSERT().
+  If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
+  linked list containing the FirstEntry and SecondEntry nodes, including
+  the FirstEntry and SecondEntry nodes, is greater than or equal to
+  PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  FirstEntry  A pointer to a node in a linked list.
+  @param  SecondEntry A pointer to another node in the same linked list.
+
+  @return SecondEntry.
+
+**/
+LIST_ENTRY *
+EFIAPI
+SwapListEntries (
+  IN OUT  LIST_ENTRY                *FirstEntry,
+  IN OUT  LIST_ENTRY                *SecondEntry
+  );
+
+
+/**
+  Removes a node from a doubly linked list, and returns the node that follows
+  the removed node.
+
+  Removes the node Entry from a doubly linked list. It is up to the caller of
+  this function to release the memory used by this node if that is required. On
+  exit, the node following Entry in the doubly linked list is returned. If
+  Entry is the only node in the linked list, then the head node of the linked
+  list is returned.
+
+  If Entry is NULL, then ASSERT().
+  If Entry is the head node of an empty list, then ASSERT().
+  If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
+  linked list containing Entry, including the Entry node, is greater than
+  or equal to PcdMaximumLinkedListLength, then ASSERT().
+
+  @param  Entry A pointer to a node in a linked list.
+
+  @return Entry.
+
+**/
+LIST_ENTRY *
+EFIAPI
+RemoveEntryList (
+  IN      CONST LIST_ENTRY          *Entry
+  );
+
+//
+// Math Services
+//
+
+/**
+  Shifts a 64-bit integer left between 0 and 63 bits. The low bits are filled
+  with zeros. The shifted value is returned.
+
+  This function shifts the 64-bit value Operand to the left by Count bits. The
+  low Count bits are set to zero. The shifted value is returned.
+
+  If Count is greater than 63, then ASSERT().
+
+  @param  Operand The 64-bit operand to shift left.
+  @param  Count   The number of bits to shift left.
+
+  @return Operand << Count.
+
+**/
+UINT64
+EFIAPI
+LShiftU64 (
+  IN      UINT64                    Operand,
+  IN      UINTN                     Count
+  );
+
+
+/**
+  Shifts a 64-bit integer right between 0 and 63 bits. This high bits are
+  filled with zeros. The shifted value is returned.
+
+  This function shifts the 64-bit value Operand to the right by Count bits. The
+  high Count bits are set to zero. The shifted value is returned.
+
+  If Count is greater than 63, then ASSERT().
+
+  @param  Operand The 64-bit operand to shift right.
+  @param  Count   The number of bits to shift right.
+
+  @return Operand >> Count
+
+**/
+UINT64
+EFIAPI
+RShiftU64 (
+  IN      UINT64                    Operand,
+  IN      UINTN                     Count
+  );
+
+
+/**
+  Shifts a 64-bit integer right between 0 and 63 bits. The high bits are filled
+  with original integer's bit 63. The shifted value is returned.
+
+  This function shifts the 64-bit value Operand to the right by Count bits. The
+  high Count bits are set to bit 63 of Operand.  The shifted value is returned.
+
+  If Count is greater than 63, then ASSERT().
+
+  @param  Operand The 64-bit operand to shift right.
+  @param  Count   The number of bits to shift right.
+
+  @return Operand >> Count
+
+**/
+UINT64
+EFIAPI
+ARShiftU64 (
+  IN      UINT64                    Operand,
+  IN      UINTN                     Count
+  );
+
+
+/**
+  Rotates a 32-bit integer left between 0 and 31 bits, filling the low bits
+  with the high bits that were rotated.
+
+  This function rotates the 32-bit value Operand to the left by Count bits. The
+  low Count bits are fill with the high Count bits of Operand. The rotated
+  value is returned.
+
+  If Count is greater than 31, then ASSERT().
+
+  @param  Operand The 32-bit operand to rotate left.
+  @param  Count   The number of bits to rotate left.
+
+  @return Operand << Count
+
+**/
+UINT32
+EFIAPI
+LRotU32 (
+  IN      UINT32                    Operand,
+  IN      UINTN                     Count
+  );
+
+
+/**
+  Rotates a 32-bit integer right between 0 and 31 bits, filling the high bits
+  with the low bits that were rotated.
+
+  This function rotates the 32-bit value Operand to the right by Count bits.
+  The high Count bits are fill with the low Count bits of Operand. The rotated
+  value is returned.
+
+  If Count is greater than 31, then ASSERT().
+
+  @param  Operand The 32-bit operand to rotate right.
+  @param  Count   The number of bits to rotate right.
+
+  @return Operand >> Count
+
+**/
+UINT32
+EFIAPI
+RRotU32 (
+  IN      UINT32                    Operand,
+  IN      UINTN                     Count
+  );
+
+
+/**
+  Rotates a 64-bit integer left between 0 and 63 bits, filling the low bits
+  with the high bits that were rotated.
+
+  This function rotates the 64-bit value Operand to the left by Count bits. The
+  low Count bits are fill with the high Count bits of Operand. The rotated
+  value is returned.
+
+  If Count is greater than 63, then ASSERT().
+
+  @param  Operand The 64-bit operand to rotate left.
+  @param  Count   The number of bits to rotate left.
+
+  @return Operand << Count
+
+**/
+UINT64
+EFIAPI
+LRotU64 (
+  IN      UINT64                    Operand,
+  IN      UINTN                     Count
+  );
+
+
+/**
+  Rotates a 64-bit integer right between 0 and 63 bits, filling the high bits
+  with the high low bits that were rotated.
+
+  This function rotates the 64-bit value Operand to the right by Count bits.
+  The high Count bits are fill with the low Count bits of Operand. The rotated
+  value is returned.
+
+  If Count is greater than 63, then ASSERT().
+
+  @param  Operand The 64-bit operand to rotate right.
+  @param  Count   The number of bits to rotate right.
+
+  @return Operand >> Count
+
+**/
+UINT64
+EFIAPI
+RRotU64 (
+  IN      UINT64                    Operand,
+  IN      UINTN                     Count
+  );
+
+
+/**
+  Returns the bit position of the lowest bit set in a 32-bit value.
+
+  This function computes the bit position of the lowest bit set in the 32-bit
+  value specified by Operand. If Operand is zero, then -1 is returned.
+  Otherwise, a value between 0 and 31 is returned.
+
+  @param  Operand The 32-bit operand to evaluate.
+
+  @retval 0..31  The lowest bit set in Operand was found.
+  @retval -1    Operand is zero.
+
+**/
+INTN
+EFIAPI
+LowBitSet32 (
+  IN      UINT32                    Operand
+  );
+
+
+/**
+  Returns the bit position of the lowest bit set in a 64-bit value.
+
+  This function computes the bit position of the lowest bit set in the 64-bit
+  value specified by Operand. If Operand is zero, then -1 is returned.
+  Otherwise, a value between 0 and 63 is returned.
+
+  @param  Operand The 64-bit operand to evaluate.
+
+  @retval 0..63  The lowest bit set in Operand was found.
+  @retval -1    Operand is zero.
+
+
+**/
+INTN
+EFIAPI
+LowBitSet64 (
+  IN      UINT64                    Operand
+  );
+
+
+/**
+  Returns the bit position of the highest bit set in a 32-bit value. Equivalent
+  to log2(x).
+
+  This function computes the bit position of the highest bit set in the 32-bit
+  value specified by Operand. If Operand is zero, then -1 is returned.
+  Otherwise, a value between 0 and 31 is returned.
+
+  @param  Operand The 32-bit operand to evaluate.
+
+  @retval 0..31  Position of the highest bit set in Operand if found.
+  @retval -1    Operand is zero.
+
+**/
+INTN
+EFIAPI
+HighBitSet32 (
+  IN      UINT32                    Operand
+  );
+
+
+/**
+  Returns the bit position of the highest bit set in a 64-bit value. Equivalent
+  to log2(x).
+
+  This function computes the bit position of the highest bit set in the 64-bit
+  value specified by Operand. If Operand is zero, then -1 is returned.
+  Otherwise, a value between 0 and 63 is returned.
+
+  @param  Operand The 64-bit operand to evaluate.
+
+  @retval 0..63   Position of the highest bit set in Operand if found.
+  @retval -1     Operand is zero.
+
+**/
+INTN
+EFIAPI
+HighBitSet64 (
+  IN      UINT64                    Operand
+  );
+
+
+/**
+  Returns the value of the highest bit set in a 32-bit value. Equivalent to
+  1 << log2(x).
+
+  This function computes the value of the highest bit set in the 32-bit value
+  specified by Operand. If Operand is zero, then zero is returned.
+
+  @param  Operand The 32-bit operand to evaluate.
+
+  @return 1 << HighBitSet32(Operand)
+  @retval 0 Operand is zero.
+
+**/
+UINT32
+EFIAPI
+GetPowerOfTwo32 (
+  IN      UINT32                    Operand
+  );
+
+
+/**
+  Returns the value of the highest bit set in a 64-bit value. Equivalent to
+  1 << log2(x).
+
+  This function computes the value of the highest bit set in the 64-bit value
+  specified by Operand. If Operand is zero, then zero is returned.
+
+  @param  Operand The 64-bit operand to evaluate.
+
+  @return 1 << HighBitSet64(Operand)
+  @retval 0 Operand is zero.
+
+**/
+UINT64
+EFIAPI
+GetPowerOfTwo64 (
+  IN      UINT64                    Operand
+  );
+
+
+/**
+  Switches the endianness of a 16-bit integer.
+
+  This function swaps the bytes in a 16-bit unsigned value to switch the value
+  from little endian to big endian or vice versa. The byte swapped value is
+  returned.
+
+  @param  Value A 16-bit unsigned value.
+
+  @return The byte swapped Value.
+
+**/
+UINT16
+EFIAPI
+SwapBytes16 (
+  IN      UINT16                    Value
+  );
+
+
+/**
+  Switches the endianness of a 32-bit integer.
+
+  This function swaps the bytes in a 32-bit unsigned value to switch the value
+  from little endian to big endian or vice versa. The byte swapped value is
+  returned.
+
+  @param  Value A 32-bit unsigned value.
+
+  @return The byte swapped Value.
+
+**/
+UINT32
+EFIAPI
+SwapBytes32 (
+  IN      UINT32                    Value
+  );
+
+
+/**
+  Switches the endianness of a 64-bit integer.
+
+  This function swaps the bytes in a 64-bit unsigned value to switch the value
+  from little endian to big endian or vice versa. The byte swapped value is
+  returned.
+
+  @param  Value A 64-bit unsigned value.
+
+  @return The byte swapped Value.
+
+**/
+UINT64
+EFIAPI
+SwapBytes64 (
+  IN      UINT64                    Value
+  );
+
+
+/**
+  Multiples a 64-bit unsigned integer by a 32-bit unsigned integer and
+  generates a 64-bit unsigned result.
+
+  This function multiples the 64-bit unsigned value Multiplicand by the 32-bit
+  unsigned value Multiplier and generates a 64-bit unsigned result. This 64-
+  bit unsigned result is returned.
+
+  @param  Multiplicand  A 64-bit unsigned value.
+  @param  Multiplier    A 32-bit unsigned value.
+
+  @return Multiplicand * Multiplier
+
+**/
+UINT64
+EFIAPI
+MultU64x32 (
+  IN      UINT64                    Multiplicand,
+  IN      UINT32                    Multiplier
+  );
+
+
+/**
+  Multiples a 64-bit unsigned integer by a 64-bit unsigned integer and
+  generates a 64-bit unsigned result.
+
+  This function multiples the 64-bit unsigned value Multiplicand by the 64-bit
+  unsigned value Multiplier and generates a 64-bit unsigned result. This 64-
+  bit unsigned result is returned.
+
+  @param  Multiplicand  A 64-bit unsigned value.
+  @param  Multiplier    A 64-bit unsigned value.
+
+  @return Multiplicand * Multiplier.
+
+**/
+UINT64
+EFIAPI
+MultU64x64 (
+  IN      UINT64                    Multiplicand,
+  IN      UINT64                    Multiplier
+  );
+
+
+/**
+  Multiples a 64-bit signed integer by a 64-bit signed integer and generates a
+  64-bit signed result.
+
+  This function multiples the 64-bit signed value Multiplicand by the 64-bit
+  signed value Multiplier and generates a 64-bit signed result. This 64-bit
+  signed result is returned.
+
+  @param  Multiplicand  A 64-bit signed value.
+  @param  Multiplier    A 64-bit signed value.
+
+  @return Multiplicand * Multiplier
+
+**/
+INT64
+EFIAPI
+MultS64x64 (
+  IN      INT64                     Multiplicand,
+  IN      INT64                     Multiplier
+  );
+
+
+/**
+  Divides a 64-bit unsigned integer by a 32-bit unsigned integer and generates
+  a 64-bit unsigned result.
+
+  This function divides the 64-bit unsigned value Dividend by the 32-bit
+  unsigned value Divisor and generates a 64-bit unsigned quotient. This
+  function returns the 64-bit unsigned quotient.
+
+  If Divisor is 0, then ASSERT().
+
+  @param  Dividend  A 64-bit unsigned value.
+  @param  Divisor   A 32-bit unsigned value.
+
+  @return Dividend / Divisor.
+
+**/
+UINT64
+EFIAPI
+DivU64x32 (
+  IN      UINT64                    Dividend,
+  IN      UINT32                    Divisor
+  );
+
+
+/**
+  Divides a 64-bit unsigned integer by a 32-bit unsigned integer and generates
+  a 32-bit unsigned remainder.
+
+  This function divides the 64-bit unsigned value Dividend by the 32-bit
+  unsigned value Divisor and generates a 32-bit remainder. This function
+  returns the 32-bit unsigned remainder.
+
+  If Divisor is 0, then ASSERT().
+
+  @param  Dividend  A 64-bit unsigned value.
+  @param  Divisor   A 32-bit unsigned value.
+
+  @return Dividend % Divisor.
+
+**/
+UINT32
+EFIAPI
+ModU64x32 (
+  IN      UINT64                    Dividend,
+  IN      UINT32                    Divisor
+  );
+
+
+/**
+  Divides a 64-bit unsigned integer by a 32-bit unsigned integer and generates
+  a 64-bit unsigned result and an optional 32-bit unsigned remainder.
+
+  This function divides the 64-bit unsigned value Dividend by the 32-bit
+  unsigned value Divisor and generates a 64-bit unsigned quotient. If Remainder
+  is not NULL, then the 32-bit unsigned remainder is returned in Remainder.
+  This function returns the 64-bit unsigned quotient.
+
+  If Divisor is 0, then ASSERT().
+
+  @param  Dividend  A 64-bit unsigned value.
+  @param  Divisor   A 32-bit unsigned value.
+  @param  Remainder A pointer to a 32-bit unsigned value. This parameter is
+                    optional and may be NULL.
+
+  @return Dividend / Divisor.
+
+**/
+UINT64
+EFIAPI
+DivU64x32Remainder (
+  IN      UINT64                    Dividend,
+  IN      UINT32                    Divisor,
+  OUT     UINT32                    *Remainder  OPTIONAL
+  );
+
+
+/**
+  Divides a 64-bit unsigned integer by a 64-bit unsigned integer and generates
+  a 64-bit unsigned result and an optional 64-bit unsigned remainder.
+
+  This function divides the 64-bit unsigned value Dividend by the 64-bit
+  unsigned value Divisor and generates a 64-bit unsigned quotient. If Remainder
+  is not NULL, then the 64-bit unsigned remainder is returned in Remainder.
+  This function returns the 64-bit unsigned quotient.
+
+  If Divisor is 0, then ASSERT().
+
+  @param  Dividend  A 64-bit unsigned value.
+  @param  Divisor   A 64-bit unsigned value.
+  @param  Remainder A pointer to a 64-bit unsigned value. This parameter is
+                    optional and may be NULL.
+
+  @return Dividend / Divisor.
+
+**/
+UINT64
+EFIAPI
+DivU64x64Remainder (
+  IN      UINT64                    Dividend,
+  IN      UINT64                    Divisor,
+  OUT     UINT64                    *Remainder  OPTIONAL
+  );
+
+
+/**
+  Divides a 64-bit signed integer by a 64-bit signed integer and generates a
+  64-bit signed result and a optional 64-bit signed remainder.
+
+  This function divides the 64-bit signed value Dividend by the 64-bit signed
+  value Divisor and generates a 64-bit signed quotient. If Remainder is not
+  NULL, then the 64-bit signed remainder is returned in Remainder. This
+  function returns the 64-bit signed quotient.
+
+  It is the caller's responsibility to not call this function with a Divisor of 0.
+  If Divisor is 0, then the quotient and remainder should be assumed to be
+  the largest negative integer.
+
+  If Divisor is 0, then ASSERT().
+
+  @param  Dividend  A 64-bit signed value.
+  @param  Divisor   A 64-bit signed value.
+  @param  Remainder A pointer to a 64-bit signed value. This parameter is
+                    optional and may be NULL.
+
+  @return Dividend / Divisor.
+
+**/
+INT64
+EFIAPI
+DivS64x64Remainder (
+  IN      INT64                     Dividend,
+  IN      INT64                     Divisor,
+  OUT     INT64                     *Remainder  OPTIONAL
+  );
+
+
+/**
+  Reads a 16-bit value from memory that may be unaligned.
+
+  This function returns the 16-bit value pointed to by Buffer. The function
+  guarantees that the read operation does not produce an alignment fault.
+
+  If the Buffer is NULL, then ASSERT().
+
+  @param  Buffer  The pointer to a 16-bit value that may be unaligned.
+
+  @return The 16-bit value read from Buffer.
+
+**/
+UINT16
+EFIAPI
+ReadUnaligned16 (
+  IN CONST UINT16              *Buffer
+  );
+
+
+/**
+  Writes a 16-bit value to memory that may be unaligned.
+
+  This function writes the 16-bit value specified by Value to Buffer. Value is
+  returned. The function guarantees that the write operation does not produce
+  an alignment fault.
+
+  If the Buffer is NULL, then ASSERT().
+
+  @param  Buffer  The pointer to a 16-bit value that may be unaligned.
+  @param  Value   16-bit value to write to Buffer.
+
+  @return The 16-bit value to write to Buffer.
+
+**/
+UINT16
+EFIAPI
+WriteUnaligned16 (
+  OUT UINT16                    *Buffer,
+  IN  UINT16                    Value
+  );
+
+
+/**
+  Reads a 24-bit value from memory that may be unaligned.
+
+  This function returns the 24-bit value pointed to by Buffer. The function
+  guarantees that the read operation does not produce an alignment fault.
+
+  If the Buffer is NULL, then ASSERT().
+
+  @param  Buffer  The pointer to a 24-bit value that may be unaligned.
+
+  @return The 24-bit value read from Buffer.
+
+**/
+UINT32
+EFIAPI
+ReadUnaligned24 (
+  IN CONST UINT32              *Buffer
+  );
+
+
+/**
+  Writes a 24-bit value to memory that may be unaligned.
+
+  This function writes the 24-bit value specified by Value to Buffer. Value is
+  returned. The function guarantees that the write operation does not produce
+  an alignment fault.
+
+  If the Buffer is NULL, then ASSERT().
+
+  @param  Buffer  The pointer to a 24-bit value that may be unaligned.
+  @param  Value   24-bit value to write to Buffer.
+
+  @return The 24-bit value to write to Buffer.
+
+**/
+UINT32
+EFIAPI
+WriteUnaligned24 (
+  OUT UINT32                    *Buffer,
+  IN  UINT32                    Value
+  );
+
+
+/**
+  Reads a 32-bit value from memory that may be unaligned.
+
+  This function returns the 32-bit value pointed to by Buffer. The function
+  guarantees that the read operation does not produce an alignment fault.
+
+  If the Buffer is NULL, then ASSERT().
+
+  @param  Buffer  The pointer to a 32-bit value that may be unaligned.
+
+  @return The 32-bit value read from Buffer.
+
+**/
+UINT32
+EFIAPI
+ReadUnaligned32 (
+  IN CONST UINT32              *Buffer
+  );
+
+
+/**
+  Writes a 32-bit value to memory that may be unaligned.
+
+  This function writes the 32-bit value specified by Value to Buffer. Value is
+  returned. The function guarantees that the write operation does not produce
+  an alignment fault.
+
+  If the Buffer is NULL, then ASSERT().
+
+  @param  Buffer  The pointer to a 32-bit value that may be unaligned.
+  @param  Value   32-bit value to write to Buffer.
+
+  @return The 32-bit value to write to Buffer.
+
+**/
+UINT32
+EFIAPI
+WriteUnaligned32 (
+  OUT UINT32                    *Buffer,
+  IN  UINT32                    Value
+  );
+
+
+/**
+  Reads a 64-bit value from memory that may be unaligned.
+
+  This function returns the 64-bit value pointed to by Buffer. The function
+  guarantees that the read operation does not produce an alignment fault.
+
+  If the Buffer is NULL, then ASSERT().
+
+  @param  Buffer  The pointer to a 64-bit value that may be unaligned.
+
+  @return The 64-bit value read from Buffer.
+
+**/
+UINT64
+EFIAPI
+ReadUnaligned64 (
+  IN CONST UINT64              *Buffer
+  );
+
+
+/**
+  Writes a 64-bit value to memory that may be unaligned.
+
+  This function writes the 64-bit value specified by Value to Buffer. Value is
+  returned. The function guarantees that the write operation does not produce
+  an alignment fault.
+
+  If the Buffer is NULL, then ASSERT().
+
+  @param  Buffer  The pointer to a 64-bit value that may be unaligned.
+  @param  Value   64-bit value to write to Buffer.
+
+  @return The 64-bit value to write to Buffer.
+
+**/
+UINT64
+EFIAPI
+WriteUnaligned64 (
+  OUT UINT64                    *Buffer,
+  IN  UINT64                    Value
+  );
+
+
+//
+// Bit Field Functions
+//
+
+/**
+  Returns a bit field from an 8-bit value.
+
+  Returns the bitfield specified by the StartBit and the EndBit from Operand.
+
+  If 8-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+
+  @return The bit field read.
+
+**/
+UINT8
+EFIAPI
+BitFieldRead8 (
+  IN      UINT8                     Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit
+  );
+
+
+/**
+  Writes a bit field to an 8-bit value, and returns the result.
+
+  Writes Value to the bit field specified by the StartBit and the EndBit in
+  Operand. All other bits in Operand are preserved. The new 8-bit value is
+  returned.
+
+  If 8-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  Value     New value of the bit field.
+
+  @return The new 8-bit value.
+
+**/
+UINT8
+EFIAPI
+BitFieldWrite8 (
+  IN      UINT8                     Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT8                     Value
+  );
+
+
+/**
+  Reads a bit field from an 8-bit value, performs a bitwise OR, and returns the
+  result.
+
+  Performs a bitwise OR between the bit field specified by StartBit
+  and EndBit in Operand and the value specified by OrData. All other bits in
+  Operand are preserved. The new 8-bit value is returned.
+
+  If 8-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  OrData    The value to OR with the read value from the value
+
+  @return The new 8-bit value.
+
+**/
+UINT8
+EFIAPI
+BitFieldOr8 (
+  IN      UINT8                     Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT8                     OrData
+  );
+
+
+/**
+  Reads a bit field from an 8-bit value, performs a bitwise AND, and returns
+  the result.
+
+  Performs a bitwise AND between the bit field specified by StartBit and EndBit
+  in Operand and the value specified by AndData. All other bits in Operand are
+  preserved. The new 8-bit value is returned.
+
+  If 8-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  AndData   The value to AND with the read value from the value.
+
+  @return The new 8-bit value.
+
+**/
+UINT8
+EFIAPI
+BitFieldAnd8 (
+  IN      UINT8                     Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT8                     AndData
+  );
+
+
+/**
+  Reads a bit field from an 8-bit value, performs a bitwise AND followed by a
+  bitwise OR, and returns the result.
+
+  Performs a bitwise AND between the bit field specified by StartBit and EndBit
+  in Operand and the value specified by AndData, followed by a bitwise
+  OR with value specified by OrData. All other bits in Operand are
+  preserved. The new 8-bit value is returned.
+
+  If 8-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 7, then ASSERT().
+  If EndBit is greater than 7, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..7.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..7.
+  @param  AndData   The value to AND with the read value from the value.
+  @param  OrData    The value to OR with the result of the AND operation.
+
+  @return The new 8-bit value.
+
+**/
+UINT8
+EFIAPI
+BitFieldAndThenOr8 (
+  IN      UINT8                     Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT8                     AndData,
+  IN      UINT8                     OrData
+  );
+
+
+/**
+  Returns a bit field from a 16-bit value.
+
+  Returns the bitfield specified by the StartBit and the EndBit from Operand.
+
+  If 16-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+
+  @return The bit field read.
+
+**/
+UINT16
+EFIAPI
+BitFieldRead16 (
+  IN      UINT16                    Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit
+  );
+
+
+/**
+  Writes a bit field to a 16-bit value, and returns the result.
+
+  Writes Value to the bit field specified by the StartBit and the EndBit in
+  Operand. All other bits in Operand are preserved. The new 16-bit value is
+  returned.
+
+  If 16-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+  @param  Value     New value of the bit field.
+
+  @return The new 16-bit value.
+
+**/
+UINT16
+EFIAPI
+BitFieldWrite16 (
+  IN      UINT16                    Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT16                    Value
+  );
+
+
+/**
+  Reads a bit field from a 16-bit value, performs a bitwise OR, and returns the
+  result.
+
+  Performs a bitwise OR between the bit field specified by StartBit
+  and EndBit in Operand and the value specified by OrData. All other bits in
+  Operand are preserved. The new 16-bit value is returned.
+
+  If 16-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+  @param  OrData    The value to OR with the read value from the value
+
+  @return The new 16-bit value.
+
+**/
+UINT16
+EFIAPI
+BitFieldOr16 (
+  IN      UINT16                    Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT16                    OrData
+  );
+
+
+/**
+  Reads a bit field from a 16-bit value, performs a bitwise AND, and returns
+  the result.
+
+  Performs a bitwise AND between the bit field specified by StartBit and EndBit
+  in Operand and the value specified by AndData. All other bits in Operand are
+  preserved. The new 16-bit value is returned.
+
+  If 16-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+  @param  AndData   The value to AND with the read value from the value
+
+  @return The new 16-bit value.
+
+**/
+UINT16
+EFIAPI
+BitFieldAnd16 (
+  IN      UINT16                    Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT16                    AndData
+  );
+
+
+/**
+  Reads a bit field from a 16-bit value, performs a bitwise AND followed by a
+  bitwise OR, and returns the result.
+
+  Performs a bitwise AND between the bit field specified by StartBit and EndBit
+  in Operand and the value specified by AndData, followed by a bitwise
+  OR with value specified by OrData. All other bits in Operand are
+  preserved. The new 16-bit value is returned.
+
+  If 16-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 15, then ASSERT().
+  If EndBit is greater than 15, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..15.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..15.
+  @param  AndData   The value to AND with the read value from the value.
+  @param  OrData    The value to OR with the result of the AND operation.
+
+  @return The new 16-bit value.
+
+**/
+UINT16
+EFIAPI
+BitFieldAndThenOr16 (
+  IN      UINT16                    Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT16                    AndData,
+  IN      UINT16                    OrData
+  );
+
+
+/**
+  Returns a bit field from a 32-bit value.
+
+  Returns the bitfield specified by the StartBit and the EndBit from Operand.
+
+  If 32-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+
+  @return The bit field read.
+
+**/
+UINT32
+EFIAPI
+BitFieldRead32 (
+  IN      UINT32                    Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit
+  );
+
+
+/**
+  Writes a bit field to a 32-bit value, and returns the result.
+
+  Writes Value to the bit field specified by the StartBit and the EndBit in
+  Operand. All other bits in Operand are preserved. The new 32-bit value is
+  returned.
+
+  If 32-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  Value     New value of the bit field.
+
+  @return The new 32-bit value.
+
+**/
+UINT32
+EFIAPI
+BitFieldWrite32 (
+  IN      UINT32                    Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT32                    Value
+  );
+
+
+/**
+  Reads a bit field from a 32-bit value, performs a bitwise OR, and returns the
+  result.
+
+  Performs a bitwise OR between the bit field specified by StartBit
+  and EndBit in Operand and the value specified by OrData. All other bits in
+  Operand are preserved. The new 32-bit value is returned.
+
+  If 32-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  OrData    The value to OR with the read value from the value.
+
+  @return The new 32-bit value.
+
+**/
+UINT32
+EFIAPI
+BitFieldOr32 (
+  IN      UINT32                    Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT32                    OrData
+  );
+
+
+/**
+  Reads a bit field from a 32-bit value, performs a bitwise AND, and returns
+  the result.
+
+  Performs a bitwise AND between the bit field specified by StartBit and EndBit
+  in Operand and the value specified by AndData. All other bits in Operand are
+  preserved. The new 32-bit value is returned.
+
+  If 32-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  AndData   The value to AND with the read value from the value
+
+  @return The new 32-bit value.
+
+**/
+UINT32
+EFIAPI
+BitFieldAnd32 (
+  IN      UINT32                    Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT32                    AndData
+  );
+
+
+/**
+  Reads a bit field from a 32-bit value, performs a bitwise AND followed by a
+  bitwise OR, and returns the result.
+
+  Performs a bitwise AND between the bit field specified by StartBit and EndBit
+  in Operand and the value specified by AndData, followed by a bitwise
+  OR with value specified by OrData. All other bits in Operand are
+  preserved. The new 32-bit value is returned.
+
+  If 32-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  AndData   The value to AND with the read value from the value.
+  @param  OrData    The value to OR with the result of the AND operation.
+
+  @return The new 32-bit value.
+
+**/
+UINT32
+EFIAPI
+BitFieldAndThenOr32 (
+  IN      UINT32                    Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT32                    AndData,
+  IN      UINT32                    OrData
+  );
+
+
+/**
+  Returns a bit field from a 64-bit value.
+
+  Returns the bitfield specified by the StartBit and the EndBit from Operand.
+
+  If 64-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 63, then ASSERT().
+  If EndBit is greater than 63, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..63.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..63.
+
+  @return The bit field read.
+
+**/
+UINT64
+EFIAPI
+BitFieldRead64 (
+  IN      UINT64                    Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit
+  );
+
+
+/**
+  Writes a bit field to a 64-bit value, and returns the result.
+
+  Writes Value to the bit field specified by the StartBit and the EndBit in
+  Operand. All other bits in Operand are preserved. The new 64-bit value is
+  returned.
+
+  If 64-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 63, then ASSERT().
+  If EndBit is greater than 63, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..63.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..63.
+  @param  Value     New value of the bit field.
+
+  @return The new 64-bit value.
+
+**/
+UINT64
+EFIAPI
+BitFieldWrite64 (
+  IN      UINT64                    Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT64                    Value
+  );
+
+
+/**
+  Reads a bit field from a 64-bit value, performs a bitwise OR, and returns the
+  result.
+
+  Performs a bitwise OR between the bit field specified by StartBit
+  and EndBit in Operand and the value specified by OrData. All other bits in
+  Operand are preserved. The new 64-bit value is returned.
+
+  If 64-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 63, then ASSERT().
+  If EndBit is greater than 63, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..63.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..63.
+  @param  OrData    The value to OR with the read value from the value
+
+  @return The new 64-bit value.
+
+**/
+UINT64
+EFIAPI
+BitFieldOr64 (
+  IN      UINT64                    Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT64                    OrData
+  );
+
+
+/**
+  Reads a bit field from a 64-bit value, performs a bitwise AND, and returns
+  the result.
+
+  Performs a bitwise AND between the bit field specified by StartBit and EndBit
+  in Operand and the value specified by AndData. All other bits in Operand are
+  preserved. The new 64-bit value is returned.
+
+  If 64-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 63, then ASSERT().
+  If EndBit is greater than 63, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..63.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..63.
+  @param  AndData   The value to AND with the read value from the value
+
+  @return The new 64-bit value.
+
+**/
+UINT64
+EFIAPI
+BitFieldAnd64 (
+  IN      UINT64                    Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT64                    AndData
+  );
+
+
+/**
+  Reads a bit field from a 64-bit value, performs a bitwise AND followed by a
+  bitwise OR, and returns the result.
+
+  Performs a bitwise AND between the bit field specified by StartBit and EndBit
+  in Operand and the value specified by AndData, followed by a bitwise
+  OR with value specified by OrData. All other bits in Operand are
+  preserved. The new 64-bit value is returned.
+
+  If 64-bit operations are not supported, then ASSERT().
+  If StartBit is greater than 63, then ASSERT().
+  If EndBit is greater than 63, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Operand   Operand on which to perform the bitfield operation.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..63.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..63.
+  @param  AndData   The value to AND with the read value from the value.
+  @param  OrData    The value to OR with the result of the AND operation.
+
+  @return The new 64-bit value.
+
+**/
+UINT64
+EFIAPI
+BitFieldAndThenOr64 (
+  IN      UINT64                    Operand,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT64                    AndData,
+  IN      UINT64                    OrData
+  );
+
+//
+// Base Library Checksum Functions
+//
+
+/**
+  Returns the sum of all elements in a buffer in unit of UINT8.
+  During calculation, the carry bits are dropped.
+
+  This function calculates the sum of all elements in a buffer
+  in unit of UINT8. The carry bits in result of addition are dropped.
+  The result is returned as UINT8. If Length is Zero, then Zero is
+  returned.
+
+  If Buffer is NULL, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer      The pointer to the buffer to carry out the sum operation.
+  @param  Length      The size, in bytes, of Buffer.
+
+  @return Sum         The sum of Buffer with carry bits dropped during additions.
+
+**/
+UINT8
+EFIAPI
+CalculateSum8 (
+  IN      CONST UINT8              *Buffer,
+  IN      UINTN                     Length
+  );
+
+
+/**
+  Returns the two's complement checksum of all elements in a buffer
+  of 8-bit values.
+
+  This function first calculates the sum of the 8-bit values in the
+  buffer specified by Buffer and Length.  The carry bits in the result
+  of addition are dropped. Then, the two's complement of the sum is
+  returned.  If Length is 0, then 0 is returned.
+
+  If Buffer is NULL, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer      The pointer to the buffer to carry out the checksum operation.
+  @param  Length      The size, in bytes, of Buffer.
+
+  @return Checksum    The two's complement checksum of Buffer.
+
+**/
+UINT8
+EFIAPI
+CalculateCheckSum8 (
+  IN      CONST UINT8              *Buffer,
+  IN      UINTN                     Length
+  );
+
+
+/**
+  Returns the sum of all elements in a buffer of 16-bit values.  During
+  calculation, the carry bits are dropped.
+
+  This function calculates the sum of the 16-bit values in the buffer
+  specified by Buffer and Length. The carry bits in result of addition are dropped.
+  The 16-bit result is returned.  If Length is 0, then 0 is returned.
+
+  If Buffer is NULL, then ASSERT().
+  If Buffer is not aligned on a 16-bit boundary, then ASSERT().
+  If Length is not aligned on a 16-bit boundary, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer      The pointer to the buffer to carry out the sum operation.
+  @param  Length      The size, in bytes, of Buffer.
+
+  @return Sum         The sum of Buffer with carry bits dropped during additions.
+
+**/
+UINT16
+EFIAPI
+CalculateSum16 (
+  IN      CONST UINT16             *Buffer,
+  IN      UINTN                     Length
+  );
+
+
+/**
+  Returns the two's complement checksum of all elements in a buffer of
+  16-bit values.
+
+  This function first calculates the sum of the 16-bit values in the buffer
+  specified by Buffer and Length.  The carry bits in the result of addition
+  are dropped. Then, the two's complement of the sum is returned.  If Length
+  is 0, then 0 is returned.
+
+  If Buffer is NULL, then ASSERT().
+  If Buffer is not aligned on a 16-bit boundary, then ASSERT().
+  If Length is not aligned on a 16-bit boundary, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer      The pointer to the buffer to carry out the checksum operation.
+  @param  Length      The size, in bytes, of Buffer.
+
+  @return Checksum    The two's complement checksum of Buffer.
+
+**/
+UINT16
+EFIAPI
+CalculateCheckSum16 (
+  IN      CONST UINT16             *Buffer,
+  IN      UINTN                     Length
+  );
+
+
+/**
+  Returns the sum of all elements in a buffer of 32-bit values. During
+  calculation, the carry bits are dropped.
+
+  This function calculates the sum of the 32-bit values in the buffer
+  specified by Buffer and Length. The carry bits in result of addition are dropped.
+  The 32-bit result is returned. If Length is 0, then 0 is returned.
+
+  If Buffer is NULL, then ASSERT().
+  If Buffer is not aligned on a 32-bit boundary, then ASSERT().
+  If Length is not aligned on a 32-bit boundary, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer      The pointer to the buffer to carry out the sum operation.
+  @param  Length      The size, in bytes, of Buffer.
+
+  @return Sum         The sum of Buffer with carry bits dropped during additions.
+
+**/
+UINT32
+EFIAPI
+CalculateSum32 (
+  IN      CONST UINT32             *Buffer,
+  IN      UINTN                     Length
+  );
+
+
+/**
+  Returns the two's complement checksum of all elements in a buffer of
+  32-bit values.
+
+  This function first calculates the sum of the 32-bit values in the buffer
+  specified by Buffer and Length.  The carry bits in the result of addition
+  are dropped. Then, the two's complement of the sum is returned.  If Length
+  is 0, then 0 is returned.
+
+  If Buffer is NULL, then ASSERT().
+  If Buffer is not aligned on a 32-bit boundary, then ASSERT().
+  If Length is not aligned on a 32-bit boundary, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer      The pointer to the buffer to carry out the checksum operation.
+  @param  Length      The size, in bytes, of Buffer.
+
+  @return Checksum    The two's complement checksum of Buffer.
+
+**/
+UINT32
+EFIAPI
+CalculateCheckSum32 (
+  IN      CONST UINT32             *Buffer,
+  IN      UINTN                     Length
+  );
+
+
+/**
+  Returns the sum of all elements in a buffer of 64-bit values.  During
+  calculation, the carry bits are dropped.
+
+  This function calculates the sum of the 64-bit values in the buffer
+  specified by Buffer and Length. The carry bits in result of addition are dropped.
+  The 64-bit result is returned.  If Length is 0, then 0 is returned.
+
+  If Buffer is NULL, then ASSERT().
+  If Buffer is not aligned on a 64-bit boundary, then ASSERT().
+  If Length is not aligned on a 64-bit boundary, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer      The pointer to the buffer to carry out the sum operation.
+  @param  Length      The size, in bytes, of Buffer.
+
+  @return Sum         The sum of Buffer with carry bits dropped during additions.
+
+**/
+UINT64
+EFIAPI
+CalculateSum64 (
+  IN      CONST UINT64             *Buffer,
+  IN      UINTN                     Length
+  );
+
+
+/**
+  Returns the two's complement checksum of all elements in a buffer of
+  64-bit values.
+
+  This function first calculates the sum of the 64-bit values in the buffer
+  specified by Buffer and Length.  The carry bits in the result of addition
+  are dropped. Then, the two's complement of the sum is returned.  If Length
+  is 0, then 0 is returned.
+
+  If Buffer is NULL, then ASSERT().
+  If Buffer is not aligned on a 64-bit boundary, then ASSERT().
+  If Length is not aligned on a 64-bit boundary, then ASSERT().
+  If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+  @param  Buffer      The pointer to the buffer to carry out the checksum operation.
+  @param  Length      The size, in bytes, of Buffer.
+
+  @return Checksum    The two's complement checksum of Buffer.
+
+**/
+UINT64
+EFIAPI
+CalculateCheckSum64 (
+  IN      CONST UINT64             *Buffer,
+  IN      UINTN                     Length
+  );
+
+
+//
+// Base Library CPU Functions
+//
+
+/**
+  Function entry point used when a stack switch is requested with SwitchStack()
+
+  @param  Context1        Context1 parameter passed into SwitchStack().
+  @param  Context2        Context2 parameter passed into SwitchStack().
+
+**/
+typedef
+VOID
+(EFIAPI *SWITCH_STACK_ENTRY_POINT)(
+  IN      VOID                      *Context1,  OPTIONAL
+  IN      VOID                      *Context2   OPTIONAL
+  );
+
+
+/**
+  Used to serialize load and store operations.
+
+  All loads and stores that proceed calls to this function are guaranteed to be
+  globally visible when this function returns.
+
+**/
+VOID
+EFIAPI
+MemoryFence (
+  VOID
+  );
+
+
+/**
+  Saves the current CPU context that can be restored with a call to LongJump()
+  and returns 0.
+
+  Saves the current CPU context in the buffer specified by JumpBuffer and
+  returns 0. The initial call to SetJump() must always return 0. Subsequent
+  calls to LongJump() cause a non-zero value to be returned by SetJump().
+
+  If JumpBuffer is NULL, then ASSERT().
+  For Itanium processors, if JumpBuffer is not aligned on a 16-byte boundary, then ASSERT().
+
+  NOTE: The structure BASE_LIBRARY_JUMP_BUFFER is CPU architecture specific.
+  The same structure must never be used for more than one CPU architecture context.
+  For example, a BASE_LIBRARY_JUMP_BUFFER allocated by an IA-32 module must never be used from an x64 module.
+  SetJump()/LongJump() is not currently supported for the EBC processor type.
+
+  @param  JumpBuffer  A pointer to CPU context buffer.
+
+  @retval 0 Indicates a return from SetJump().
+
+**/
+UINTN
+EFIAPI
+SetJump (
+  OUT     BASE_LIBRARY_JUMP_BUFFER  *JumpBuffer
+  );
+
+
+/**
+  Restores the CPU context that was saved with SetJump().
+
+  Restores the CPU context from the buffer specified by JumpBuffer. This
+  function never returns to the caller. Instead is resumes execution based on
+  the state of JumpBuffer.
+
+  If JumpBuffer is NULL, then ASSERT().
+  For Itanium processors, if JumpBuffer is not aligned on a 16-byte boundary, then ASSERT().
+  If Value is 0, then ASSERT().
+
+  @param  JumpBuffer  A pointer to CPU context buffer.
+  @param  Value       The value to return when the SetJump() context is
+                      restored and must be non-zero.
+
+**/
+VOID
+EFIAPI
+LongJump (
+  IN      BASE_LIBRARY_JUMP_BUFFER  *JumpBuffer,
+  IN      UINTN                     Value
+  );
+
+
+/**
+  Enables CPU interrupts.
+
+**/
+VOID
+EFIAPI
+EnableInterrupts (
+  VOID
+  );
+
+
+/**
+  Disables CPU interrupts.
+
+**/
+VOID
+EFIAPI
+DisableInterrupts (
+  VOID
+  );
+
+
+/**
+  Disables CPU interrupts and returns the interrupt state prior to the disable
+  operation.
+
+  @retval TRUE  CPU interrupts were enabled on entry to this call.
+  @retval FALSE CPU interrupts were disabled on entry to this call.
+
+**/
+BOOLEAN
+EFIAPI
+SaveAndDisableInterrupts (
+  VOID
+  );
+
+
+/**
+  Enables CPU interrupts for the smallest window required to capture any
+  pending interrupts.
+
+**/
+VOID
+EFIAPI
+EnableDisableInterrupts (
+  VOID
+  );
+
+
+/**
+  Retrieves the current CPU interrupt state.
+
+  Returns TRUE if interrupts are currently enabled. Otherwise
+  returns FALSE.
+
+  @retval TRUE  CPU interrupts are enabled.
+  @retval FALSE CPU interrupts are disabled.
+
+**/
+BOOLEAN
+EFIAPI
+GetInterruptState (
+  VOID
+  );
+
+
+/**
+  Set the current CPU interrupt state.
+
+  Sets the current CPU interrupt state to the state specified by
+  InterruptState. If InterruptState is TRUE, then interrupts are enabled. If
+  InterruptState is FALSE, then interrupts are disabled. InterruptState is
+  returned.
+
+  @param  InterruptState  TRUE if interrupts should enabled. FALSE if
+                          interrupts should be disabled.
+
+  @return InterruptState
+
+**/
+BOOLEAN
+EFIAPI
+SetInterruptState (
+  IN      BOOLEAN                   InterruptState
+  );
+
+
+/**
+  Requests CPU to pause for a short period of time.
+
+  Requests CPU to pause for a short period of time. Typically used in MP
+  systems to prevent memory starvation while waiting for a spin lock.
+
+**/
+VOID
+EFIAPI
+CpuPause (
+  VOID
+  );
+
+
+/**
+  Transfers control to a function starting with a new stack.
+
+  Transfers control to the function specified by EntryPoint using the
+  new stack specified by NewStack and passing in the parameters specified
+  by Context1 and Context2.  Context1 and Context2 are optional and may
+  be NULL.  The function EntryPoint must never return.  This function
+  supports a variable number of arguments following the NewStack parameter.
+  These additional arguments are ignored on IA-32, x64, and EBC architectures.
+  Itanium processors expect one additional parameter of type VOID * that specifies
+  the new backing store pointer.
+
+  If EntryPoint is NULL, then ASSERT().
+  If NewStack is NULL, then ASSERT().
+
+  @param  EntryPoint  A pointer to function to call with the new stack.
+  @param  Context1    A pointer to the context to pass into the EntryPoint
+                      function.
+  @param  Context2    A pointer to the context to pass into the EntryPoint
+                      function.
+  @param  NewStack    A pointer to the new stack to use for the EntryPoint
+                      function.
+  @param  ...         This variable argument list is ignored for IA-32, x64, and
+                      EBC architectures.  For Itanium processors, this variable
+                      argument list is expected to contain a single parameter of
+                      type VOID * that specifies the new backing store pointer.
+
+
+**/
+VOID
+EFIAPI
+SwitchStack (
+  IN      SWITCH_STACK_ENTRY_POINT  EntryPoint,
+  IN      VOID                      *Context1,  OPTIONAL
+  IN      VOID                      *Context2,  OPTIONAL
+  IN      VOID                      *NewStack,
+  ...
+  );
+
+
+/**
+  Generates a breakpoint on the CPU.
+
+  Generates a breakpoint on the CPU. The breakpoint must be implemented such
+  that code can resume normal execution after the breakpoint.
+
+**/
+VOID
+EFIAPI
+CpuBreakpoint (
+  VOID
+  );
+
+
+/**
+  Executes an infinite loop.
+
+  Forces the CPU to execute an infinite loop. A debugger may be used to skip
+  past the loop and the code that follows the loop must execute properly. This
+  implies that the infinite loop must not cause the code that follow it to be
+  optimized away.
+
+**/
+VOID
+EFIAPI
+CpuDeadLoop (
+  VOID
+  );
+
+#if defined (MDE_CPU_IPF)
+
+/**
+  Flush a range of  cache lines in the cache coherency domain of the calling
+  CPU.
+
+  Flushes the cache lines specified by Address and Length.  If Address is not aligned
+  on a cache line boundary, then entire cache line containing Address is flushed.
+  If Address + Length is not aligned on a cache line boundary, then the entire cache
+  line containing Address + Length - 1 is flushed.  This function may choose to flush
+  the entire cache if that is more efficient than flushing the specified range.  If
+  Length is 0, the no cache lines are flushed.  Address is returned.
+  This function is only available on Itanium processors.
+
+  If Length is greater than (MAX_ADDRESS - Address + 1), then ASSERT().
+
+  @param  Address The base address of the instruction lines to invalidate. If
+                  the CPU is in a physical addressing mode, then Address is a
+                  physical address. If the CPU is in a virtual addressing mode,
+                  then Address is a virtual address.
+
+  @param  Length  The number of bytes to invalidate from the instruction cache.
+
+  @return Address.
+
+**/
+VOID *
+EFIAPI
+AsmFlushCacheRange (
+  IN      VOID                      *Address,
+  IN      UINTN                     Length
+  );
+
+
+/**
+  Executes an FC instruction.
+  Executes an FC instruction on the cache line specified by Address.
+  The cache line size affected is at least 32-bytes (aligned on a 32-byte boundary).
+  An implementation may flush a larger region.  This function is only available on Itanium processors.
+
+  @param Address    The Address of cache line to be flushed.
+
+  @return The address of FC instruction executed.
+
+**/
+UINT64
+EFIAPI
+AsmFc (
+  IN  UINT64  Address
+  );
+
+
+/**
+  Executes an FC.I instruction.
+  Executes an FC.I instruction on the cache line specified by Address.
+  The cache line size affected is at least 32-bytes (aligned on a 32-byte boundary).
+  An implementation may flush a larger region.  This function is only available on Itanium processors.
+
+  @param Address    The Address of cache line to be flushed.
+
+  @return The address of the FC.I instruction executed.
+
+**/
+UINT64
+EFIAPI
+AsmFci (
+  IN  UINT64  Address
+  );
+
+
+/**
+  Reads the current value of a Processor Identifier Register (CPUID).
+
+  Reads and returns the current value of Processor Identifier Register specified by Index.
+  The Index of largest implemented CPUID (One less than the number of implemented CPUID
+  registers) is determined by CPUID [3] bits {7:0}.
+  No parameter checking is performed on Index.  If the Index value is beyond the
+  implemented CPUID register range, a Reserved Register/Field fault may occur.  The caller
+  must either guarantee that Index is valid, or the caller must set up fault handlers to
+  catch the faults.  This function is only available on Itanium processors.
+
+  @param Index    The 8-bit Processor Identifier Register index to read.
+
+  @return The current value of Processor Identifier Register specified by Index.
+
+**/
+UINT64
+EFIAPI
+AsmReadCpuid (
+  IN  UINT8   Index
+  );
+
+
+/**
+  Reads the current value of 64-bit Processor Status Register (PSR).
+  This function is only available on Itanium processors.
+
+  @return The current value of PSR.
+
+**/
+UINT64
+EFIAPI
+AsmReadPsr (
+  VOID
+  );
+
+
+/**
+  Writes the current value of 64-bit Processor Status Register (PSR).
+
+  No parameter checking is performed on Value.  All bits of Value corresponding to
+  reserved fields of PSR must be 0 or a Reserved Register/Field fault may occur.
+  The caller must either guarantee that Value is valid, or the caller must set up
+  fault handlers to catch the faults. This function is only available on Itanium processors.
+
+  @param Value    The 64-bit value to write to PSR.
+
+  @return The 64-bit value written to the PSR.
+
+**/
+UINT64
+EFIAPI
+AsmWritePsr (
+  IN UINT64  Value
+  );
+
+
+/**
+  Reads the current value of 64-bit Kernel Register #0 (KR0).
+
+  Reads and returns the current value of KR0.
+  This function is only available on Itanium processors.
+
+  @return The current value of KR0.
+
+**/
+UINT64
+EFIAPI
+AsmReadKr0 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of 64-bit Kernel Register #1 (KR1).
+
+  Reads and returns the current value of KR1.
+  This function is only available on Itanium processors.
+
+  @return The current value of KR1.
+
+**/
+UINT64
+EFIAPI
+AsmReadKr1 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of 64-bit Kernel Register #2 (KR2).
+
+  Reads and returns the current value of KR2.
+  This function is only available on Itanium processors.
+
+  @return The current value of KR2.
+
+**/
+UINT64
+EFIAPI
+AsmReadKr2 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of 64-bit Kernel Register #3 (KR3).
+
+  Reads and returns the current value of KR3.
+  This function is only available on Itanium processors.
+
+  @return The current value of KR3.
+
+**/
+UINT64
+EFIAPI
+AsmReadKr3 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of 64-bit Kernel Register #4 (KR4).
+
+  Reads and returns the current value of KR4.
+  This function is only available on Itanium processors.
+
+  @return The current value of KR4.
+
+**/
+UINT64
+EFIAPI
+AsmReadKr4 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of 64-bit Kernel Register #5 (KR5).
+
+  Reads and returns the current value of KR5.
+  This function is only available on Itanium processors.
+
+  @return The current value of KR5.
+
+**/
+UINT64
+EFIAPI
+AsmReadKr5 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of 64-bit Kernel Register #6 (KR6).
+
+  Reads and returns the current value of KR6.
+  This function is only available on Itanium processors.
+
+  @return The current value of KR6.
+
+**/
+UINT64
+EFIAPI
+AsmReadKr6 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of 64-bit Kernel Register #7 (KR7).
+
+  Reads and returns the current value of KR7.
+  This function is only available on Itanium processors.
+
+  @return The current value of KR7.
+
+**/
+UINT64
+EFIAPI
+AsmReadKr7 (
+  VOID
+  );
+
+
+/**
+  Write the current value of 64-bit Kernel Register #0 (KR0).
+
+  Writes the current value of KR0.  The 64-bit value written to
+  the KR0 is returned. This function is only available on Itanium processors.
+
+  @param  Value   The 64-bit value to write to KR0.
+
+  @return The 64-bit value written to the KR0.
+
+**/
+UINT64
+EFIAPI
+AsmWriteKr0 (
+  IN UINT64  Value
+  );
+
+
+/**
+  Write the current value of 64-bit Kernel Register #1 (KR1).
+
+  Writes the current value of KR1.  The 64-bit value written to
+  the KR1 is returned. This function is only available on Itanium processors.
+
+  @param  Value   The 64-bit value to write to KR1.
+
+  @return The 64-bit value written to the KR1.
+
+**/
+UINT64
+EFIAPI
+AsmWriteKr1 (
+  IN UINT64  Value
+  );
+
+
+/**
+  Write the current value of 64-bit Kernel Register #2 (KR2).
+
+  Writes the current value of KR2.  The 64-bit value written to
+  the KR2 is returned. This function is only available on Itanium processors.
+
+  @param  Value   The 64-bit value to write to KR2.
+
+  @return The 64-bit value written to the KR2.
+
+**/
+UINT64
+EFIAPI
+AsmWriteKr2 (
+  IN UINT64  Value
+  );
+
+
+/**
+  Write the current value of 64-bit Kernel Register #3 (KR3).
+
+  Writes the current value of KR3.  The 64-bit value written to
+  the KR3 is returned. This function is only available on Itanium processors.
+
+  @param  Value   The 64-bit value to write to KR3.
+
+  @return The 64-bit value written to the KR3.
+
+**/
+UINT64
+EFIAPI
+AsmWriteKr3 (
+  IN UINT64  Value
+  );
+
+
+/**
+  Write the current value of 64-bit Kernel Register #4 (KR4).
+
+  Writes the current value of KR4.  The 64-bit value written to
+  the KR4 is returned. This function is only available on Itanium processors.
+
+  @param  Value   The 64-bit value to write to KR4.
+
+  @return The 64-bit value written to the KR4.
+
+**/
+UINT64
+EFIAPI
+AsmWriteKr4 (
+  IN UINT64  Value
+  );
+
+
+/**
+  Write the current value of 64-bit Kernel Register #5 (KR5).
+
+  Writes the current value of KR5.  The 64-bit value written to
+  the KR5 is returned. This function is only available on Itanium processors.
+
+  @param  Value   The 64-bit value to write to KR5.
+
+  @return The 64-bit value written to the KR5.
+
+**/
+UINT64
+EFIAPI
+AsmWriteKr5 (
+  IN UINT64  Value
+  );
+
+
+/**
+  Write the current value of 64-bit Kernel Register #6 (KR6).
+
+  Writes the current value of KR6.  The 64-bit value written to
+  the KR6 is returned. This function is only available on Itanium processors.
+
+  @param  Value   The 64-bit value to write to KR6.
+
+  @return The 64-bit value written to the KR6.
+
+**/
+UINT64
+EFIAPI
+AsmWriteKr6 (
+  IN UINT64  Value
+  );
+
+
+/**
+  Write the current value of 64-bit Kernel Register #7 (KR7).
+
+  Writes the current value of KR7.  The 64-bit value written to
+  the KR7 is returned. This function is only available on Itanium processors.
+
+  @param  Value   The 64-bit value to write to KR7.
+
+  @return The 64-bit value written to the KR7.
+
+**/
+UINT64
+EFIAPI
+AsmWriteKr7 (
+  IN UINT64  Value
+  );
+
+
+/**
+  Reads the current value of Interval Timer Counter Register (ITC).
+
+  Reads and returns the current value of ITC.
+  This function is only available on Itanium processors.
+
+  @return The current value of ITC.
+
+**/
+UINT64
+EFIAPI
+AsmReadItc (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Interval Timer Vector Register (ITV).
+
+  Reads and returns the current value of ITV.
+  This function is only available on Itanium processors.
+
+  @return The current value of ITV.
+
+**/
+UINT64
+EFIAPI
+AsmReadItv (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Interval Timer Match Register (ITM).
+
+  Reads and returns the current value of ITM.
+  This function is only available on Itanium processors.
+
+  @return The current value of ITM.
+**/
+UINT64
+EFIAPI
+AsmReadItm (
+  VOID
+  );
+
+
+/**
+  Writes the current value of 64-bit Interval Timer Counter Register (ITC).
+
+  Writes the current value of ITC.  The 64-bit value written to the ITC is returned.
+  This function is only available on Itanium processors.
+
+  @param Value    The 64-bit value to write to ITC.
+
+  @return The 64-bit value written to the ITC.
+
+**/
+UINT64
+EFIAPI
+AsmWriteItc (
+  IN UINT64  Value
+  );
+
+
+/**
+  Writes the current value of 64-bit Interval Timer Match Register (ITM).
+
+  Writes the current value of ITM.  The 64-bit value written to the ITM is returned.
+  This function is only available on Itanium processors.
+
+  @param Value    The 64-bit value to write to ITM.
+
+  @return The 64-bit value written to the ITM.
+
+**/
+UINT64
+EFIAPI
+AsmWriteItm (
+  IN UINT64  Value
+  );
+
+
+/**
+  Writes the current value of 64-bit Interval Timer Vector Register (ITV).
+
+  Writes the current value of ITV.  The 64-bit value written to the ITV is returned.
+  No parameter checking is performed on Value.  All bits of Value corresponding to
+  reserved fields of ITV must be 0 or a Reserved Register/Field fault may occur.
+  The caller must either guarantee that Value is valid, or the caller must set up
+  fault handlers to catch the faults.
+  This function is only available on Itanium processors.
+
+  @param Value    The 64-bit value to write to ITV.
+
+  @return The 64-bit value written to the ITV.
+
+**/
+UINT64
+EFIAPI
+AsmWriteItv (
+  IN UINT64  Value
+  );
+
+
+/**
+  Reads the current value of Default Control Register (DCR).
+
+  Reads and returns the current value of DCR.  This function is only available on Itanium processors.
+
+  @return The current value of DCR.
+
+**/
+UINT64
+EFIAPI
+AsmReadDcr (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Interruption Vector Address Register (IVA).
+
+  Reads and returns the current value of IVA.  This function is only available on Itanium processors.
+
+  @return The current value of IVA.
+**/
+UINT64
+EFIAPI
+AsmReadIva (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Page Table Address Register (PTA).
+
+  Reads and returns the current value of PTA.  This function is only available on Itanium processors.
+
+  @return The current value of PTA.
+
+**/
+UINT64
+EFIAPI
+AsmReadPta (
+  VOID
+  );
+
+
+/**
+  Writes the current value of 64-bit Default Control Register (DCR).
+
+  Writes the current value of DCR.  The 64-bit value written to the DCR is returned.
+  No parameter checking is performed on Value.  All bits of Value corresponding to
+  reserved fields of DCR must be 0 or a Reserved Register/Field fault may occur.
+  The caller must either guarantee that Value is valid, or the caller must set up
+  fault handlers to catch the faults.
+  This function is only available on Itanium processors.
+
+  @param Value    The 64-bit value to write to DCR.
+
+  @return The 64-bit value written to the DCR.
+
+**/
+UINT64
+EFIAPI
+AsmWriteDcr (
+  IN UINT64  Value
+  );
+
+
+/**
+  Writes the current value of 64-bit Interruption Vector Address Register (IVA).
+
+  Writes the current value of IVA.  The 64-bit value written to the IVA is returned.
+  The size of vector table is 32 K bytes and is 32 K bytes aligned
+  the low 15 bits of Value is ignored when written.
+  This function is only available on Itanium processors.
+
+  @param Value    The 64-bit value to write to IVA.
+
+  @return The 64-bit value written to the IVA.
+
+**/
+UINT64
+EFIAPI
+AsmWriteIva (
+  IN UINT64  Value
+  );
+
+
+/**
+  Writes the current value of 64-bit Page Table Address Register (PTA).
+
+  Writes the current value of PTA.  The 64-bit value written to the PTA is returned.
+  No parameter checking is performed on Value.  All bits of Value corresponding to
+  reserved fields of DCR must be 0 or a Reserved Register/Field fault may occur.
+  The caller must either guarantee that Value is valid, or the caller must set up
+  fault handlers to catch the faults.
+  This function is only available on Itanium processors.
+
+  @param Value    The 64-bit value to write to PTA.
+
+  @return The 64-bit value written to the PTA.
+**/
+UINT64
+EFIAPI
+AsmWritePta (
+  IN UINT64  Value
+  );
+
+
+/**
+  Reads the current value of Local Interrupt ID Register (LID).
+
+  Reads and returns the current value of LID.  This function is only available on Itanium processors.
+
+  @return The current value of LID.
+
+**/
+UINT64
+EFIAPI
+AsmReadLid (
+  VOID
+  );
+
+
+/**
+  Reads the current value of External Interrupt Vector Register (IVR).
+
+  Reads and returns the current value of IVR.  This function is only available on Itanium processors.
+
+  @return The current value of IVR.
+
+**/
+UINT64
+EFIAPI
+AsmReadIvr (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Task Priority Register (TPR).
+
+  Reads and returns the current value of TPR.  This function is only available on Itanium processors.
+
+  @return The current value of TPR.
+
+**/
+UINT64
+EFIAPI
+AsmReadTpr (
+  VOID
+  );
+
+
+/**
+  Reads the current value of External Interrupt Request Register #0 (IRR0).
+
+  Reads and returns the current value of IRR0.  This function is only available on Itanium processors.
+
+  @return The current value of IRR0.
+
+**/
+UINT64
+EFIAPI
+AsmReadIrr0 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of External Interrupt Request Register #1 (IRR1).
+
+  Reads and returns the current value of IRR1.  This function is only available on Itanium processors.
+
+  @return The current value of IRR1.
+
+**/
+UINT64
+EFIAPI
+AsmReadIrr1 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of External Interrupt Request Register #2 (IRR2).
+
+  Reads and returns the current value of IRR2.  This function is only available on Itanium processors.
+
+  @return The current value of IRR2.
+
+**/
+UINT64
+EFIAPI
+AsmReadIrr2 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of External Interrupt Request Register #3 (IRR3).
+
+  Reads and returns the current value of IRR3.  This function is only available on Itanium processors.
+
+  @return The current value of IRR3.
+
+**/
+UINT64
+EFIAPI
+AsmReadIrr3 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Performance Monitor Vector Register (PMV).
+
+  Reads and returns the current value of PMV.  This function is only available on Itanium processors.
+
+  @return The current value of PMV.
+
+**/
+UINT64
+EFIAPI
+AsmReadPmv (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Corrected Machine Check Vector Register (CMCV).
+
+  Reads and returns the current value of CMCV.  This function is only available on Itanium processors.
+
+  @return The current value of CMCV.
+
+**/
+UINT64
+EFIAPI
+AsmReadCmcv (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Local Redirection Register #0 (LRR0).
+
+  Reads and returns the current value of LRR0.  This function is only available on Itanium processors.
+
+  @return The current value of LRR0.
+
+**/
+UINT64
+EFIAPI
+AsmReadLrr0 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Local Redirection Register #1 (LRR1).
+
+  Reads and returns the current value of LRR1.  This function is only available on Itanium processors.
+
+  @return The current value of LRR1.
+
+**/
+UINT64
+EFIAPI
+AsmReadLrr1 (
+  VOID
+  );
+
+
+/**
+  Writes the current value of 64-bit Page Local Interrupt ID Register (LID).
+
+  Writes the current value of LID.  The 64-bit value written to the LID is returned.
+  No parameter checking is performed on Value.  All bits of Value corresponding to
+  reserved fields of LID must be 0 or a Reserved Register/Field fault may occur.
+  The caller must either guarantee that Value is valid, or the caller must set up
+  fault handlers to catch the faults.
+  This function is only available on Itanium processors.
+
+  @param Value    The 64-bit value to write to LID.
+
+  @return The 64-bit value written to the LID.
+
+**/
+UINT64
+EFIAPI
+AsmWriteLid (
+  IN UINT64  Value
+  );
+
+
+/**
+  Writes the current value of 64-bit Task Priority Register (TPR).
+
+  Writes the current value of TPR.  The 64-bit value written to the TPR is returned.
+  No parameter checking is performed on Value.  All bits of Value corresponding to
+  reserved fields of TPR must be 0 or a Reserved Register/Field fault may occur.
+  The caller must either guarantee that Value is valid, or the caller must set up
+  fault handlers to catch the faults.
+  This function is only available on Itanium processors.
+
+  @param Value    The 64-bit value to write to TPR.
+
+  @return The 64-bit value written to the TPR.
+
+**/
+UINT64
+EFIAPI
+AsmWriteTpr (
+  IN UINT64  Value
+  );
+
+
+/**
+  Performs a write operation on End OF External Interrupt Register (EOI).
+
+  Writes a value of 0 to the EOI Register.  This function is only available on Itanium processors.
+
+**/
+VOID
+EFIAPI
+AsmWriteEoi (
+  VOID
+  );
+
+
+/**
+  Writes the current value of 64-bit Performance Monitor Vector Register (PMV).
+
+  Writes the current value of PMV.  The 64-bit value written to the PMV is returned.
+  No parameter checking is performed on Value.  All bits of Value corresponding
+  to reserved fields of PMV must be 0 or a Reserved Register/Field fault may occur.
+  The caller must either guarantee that Value is valid, or the caller must set up
+  fault handlers to catch the faults.
+  This function is only available on Itanium processors.
+
+  @param Value    The 64-bit value to write to PMV.
+
+  @return The 64-bit value written to the PMV.
+
+**/
+UINT64
+EFIAPI
+AsmWritePmv (
+  IN UINT64  Value
+  );
+
+
+/**
+  Writes the current value of 64-bit Corrected Machine Check Vector Register (CMCV).
+
+  Writes the current value of CMCV.  The 64-bit value written to the CMCV is returned.
+  No parameter checking is performed on Value.  All bits of Value corresponding
+  to reserved fields of CMCV must be 0 or a Reserved Register/Field fault may occur.
+  The caller must either guarantee that Value is valid, or the caller must set up
+  fault handlers to catch the faults.
+  This function is only available on Itanium processors.
+
+  @param Value    The 64-bit value to write to CMCV.
+
+  @return The 64-bit value written to the CMCV.
+
+**/
+UINT64
+EFIAPI
+AsmWriteCmcv (
+  IN UINT64  Value
+  );
+
+
+/**
+  Writes the current value of 64-bit Local Redirection Register #0 (LRR0).
+
+  Writes the current value of LRR0.  The 64-bit value written to the LRR0 is returned.
+  No parameter checking is performed on Value.  All bits of Value corresponding
+  to reserved fields of LRR0 must be 0 or a Reserved Register/Field fault may occur.
+  The caller must either guarantee that Value is valid, or the caller must set up
+  fault handlers to catch the faults.
+  This function is only available on Itanium processors.
+
+  @param Value    The 64-bit value to write to LRR0.
+
+  @return The 64-bit value written to the LRR0.
+
+**/
+UINT64
+EFIAPI
+AsmWriteLrr0 (
+  IN UINT64  Value
+  );
+
+
+/**
+  Writes the current value of 64-bit Local Redirection Register #1 (LRR1).
+
+  Writes the current value of LRR1.  The 64-bit value written to the LRR1 is returned.
+  No parameter checking is performed on Value.  All bits of Value corresponding
+  to reserved fields of LRR1 must be 0 or a Reserved Register/Field fault may occur.
+  The caller must either guarantee that Value is valid, or the caller must
+  set up fault handlers to catch the faults.
+  This function is only available on Itanium processors.
+
+  @param Value    The 64-bit value to write to LRR1.
+
+  @return The 64-bit value written to the LRR1.
+
+**/
+UINT64
+EFIAPI
+AsmWriteLrr1 (
+  IN UINT64  Value
+  );
+
+
+/**
+  Reads the current value of Instruction Breakpoint Register (IBR).
+
+  The Instruction Breakpoint Registers are used in pairs.  The even numbered
+  registers contain breakpoint addresses, and the odd numbered registers contain
+  breakpoint mask conditions.  At least four instruction registers pairs are implemented
+  on all processor models.   Implemented registers are contiguous starting with
+  register 0.  No parameter checking is performed on Index, and if the Index value
+  is beyond the implemented IBR register range, a Reserved Register/Field fault may
+  occur.  The caller must either guarantee that Index is valid, or the caller must
+  set up fault handlers to catch the faults.
+  This function is only available on Itanium processors.
+
+  @param Index    The 8-bit Instruction Breakpoint Register index to read.
+
+  @return The current value of Instruction Breakpoint Register specified by Index.
+
+**/
+UINT64
+EFIAPI
+AsmReadIbr (
+  IN  UINT8   Index
+  );
+
+
+/**
+  Reads the current value of Data Breakpoint Register (DBR).
+
+  The Data Breakpoint Registers are used in pairs.  The even numbered registers
+  contain breakpoint addresses, and odd numbered registers contain breakpoint
+  mask conditions.  At least four data registers pairs are implemented on all processor
+  models.  Implemented registers are contiguous starting with register 0.
+  No parameter checking is performed on Index.  If the Index value is beyond
+  the implemented DBR register range, a Reserved Register/Field fault may occur.
+  The caller must either guarantee that Index is valid, or the caller must set up
+  fault handlers to catch the faults.
+  This function is only available on Itanium processors.
+
+  @param Index    The 8-bit Data Breakpoint Register index to read.
+
+  @return The current value of Data Breakpoint Register specified by Index.
+
+**/
+UINT64
+EFIAPI
+AsmReadDbr (
+  IN  UINT8   Index
+  );
+
+
+/**
+  Reads the current value of Performance Monitor Configuration Register (PMC).
+
+  All processor implementations provide at least four performance counters
+  (PMC/PMD [4]...PMC/PMD [7] pairs), and four performance monitor counter overflow
+  status registers (PMC [0]... PMC [3]).  Processor implementations may provide
+  additional implementation-dependent PMC and PMD to increase the number of
+  'generic' performance counters (PMC/PMD pairs).  The remainder of PMC and PMD
+  register set is implementation dependent.  No parameter checking is performed
+  on Index.  If the Index value is beyond the implemented PMC register range,
+  zero value will be returned.
+  This function is only available on Itanium processors.
+
+  @param Index    The 8-bit Performance Monitor Configuration Register index to read.
+
+  @return   The current value of Performance Monitor Configuration Register
+            specified by Index.
+
+**/
+UINT64
+EFIAPI
+AsmReadPmc (
+  IN  UINT8   Index
+  );
+
+
+/**
+  Reads the current value of Performance Monitor Data Register (PMD).
+
+  All processor implementations provide at least 4 performance counters
+  (PMC/PMD [4]...PMC/PMD [7] pairs), and 4 performance monitor counter
+  overflow status registers (PMC [0]... PMC [3]).  Processor implementations may
+  provide additional implementation-dependent PMC and PMD to increase the number
+  of 'generic' performance counters (PMC/PMD pairs).  The remainder of PMC and PMD
+  register set is implementation dependent.  No parameter checking is performed
+  on Index.  If the Index value is beyond the implemented PMD register range,
+  zero value will be returned.
+  This function is only available on Itanium processors.
+
+  @param Index    The 8-bit Performance Monitor Data Register index to read.
+
+  @return The current value of Performance Monitor Data Register specified by Index.
+
+**/
+UINT64
+EFIAPI
+AsmReadPmd (
+  IN  UINT8   Index
+  );
+
+
+/**
+  Writes the current value of 64-bit Instruction Breakpoint Register (IBR).
+
+  Writes current value of Instruction Breakpoint Register specified by Index.
+  The Instruction Breakpoint Registers are used in pairs.  The even numbered
+  registers contain breakpoint addresses, and odd numbered registers contain
+  breakpoint mask conditions.  At least four instruction registers pairs are implemented
+  on all processor models.  Implemented registers are contiguous starting with
+  register 0.  No parameter checking is performed on Index.  If the Index value
+  is beyond the implemented IBR register range, a Reserved Register/Field fault may
+  occur.  The caller must either guarantee that Index is valid, or the caller must
+  set up fault handlers to catch the faults.
+  This function is only available on Itanium processors.
+
+  @param Index    The 8-bit Instruction Breakpoint Register index to write.
+  @param Value    The 64-bit value to write to IBR.
+
+  @return The 64-bit value written to the IBR.
+
+**/
+UINT64
+EFIAPI
+AsmWriteIbr (
+  IN UINT8   Index,
+  IN UINT64  Value
+  );
+
+
+/**
+  Writes the current value of 64-bit Data Breakpoint Register (DBR).
+
+  Writes current value of Data Breakpoint Register specified by Index.
+  The Data Breakpoint Registers are used in pairs.  The even numbered registers
+  contain breakpoint addresses, and odd numbered registers contain breakpoint
+  mask conditions.  At least four data registers pairs are implemented on all processor
+  models.  Implemented registers are contiguous starting with register 0.  No parameter
+  checking is performed on Index.  If the Index value is beyond the implemented
+  DBR register range, a Reserved Register/Field fault may occur.  The caller must
+  either guarantee that Index is valid, or the caller must set up fault handlers to
+  catch the faults.
+  This function is only available on Itanium processors.
+
+  @param Index    The 8-bit Data Breakpoint Register index to write.
+  @param Value    The 64-bit value to write to DBR.
+
+  @return The 64-bit value written to the DBR.
+
+**/
+UINT64
+EFIAPI
+AsmWriteDbr (
+  IN UINT8   Index,
+  IN UINT64  Value
+  );
+
+
+/**
+  Writes the current value of 64-bit Performance Monitor Configuration Register (PMC).
+
+  Writes current value of Performance Monitor Configuration Register specified by Index.
+  All processor implementations provide at least four performance counters
+  (PMC/PMD [4]...PMC/PMD [7] pairs), and four performance monitor counter overflow status
+  registers (PMC [0]... PMC [3]).  Processor implementations may provide additional
+  implementation-dependent PMC and PMD to increase the number of 'generic' performance
+  counters (PMC/PMD pairs).  The remainder of PMC and PMD register set is implementation
+  dependent.  No parameter checking is performed on Index.  If the Index value is
+  beyond the implemented PMC register range, the write is ignored.
+  This function is only available on Itanium processors.
+
+  @param Index    The 8-bit Performance Monitor Configuration Register index to write.
+  @param Value    The 64-bit value to write to PMC.
+
+  @return The 64-bit value written to the PMC.
+
+**/
+UINT64
+EFIAPI
+AsmWritePmc (
+  IN UINT8   Index,
+  IN UINT64  Value
+  );
+
+
+/**
+  Writes the current value of 64-bit Performance Monitor Data Register (PMD).
+
+  Writes current value of Performance Monitor Data Register specified by Index.
+  All processor implementations provide at least four performance counters
+  (PMC/PMD [4]...PMC/PMD [7] pairs), and four performance monitor counter overflow
+  status registers (PMC [0]... PMC [3]).  Processor implementations may provide
+  additional implementation-dependent PMC and PMD to increase the number of 'generic'
+  performance counters (PMC/PMD pairs).  The remainder of PMC and PMD register set
+  is implementation dependent.  No parameter checking is performed on Index.  If the
+  Index value is beyond the implemented PMD register range, the write is ignored.
+  This function is only available on Itanium processors.
+
+  @param Index    The 8-bit Performance Monitor Data Register index to write.
+  @param Value    The 64-bit value to write to PMD.
+
+  @return The 64-bit value written to the PMD.
+
+**/
+UINT64
+EFIAPI
+AsmWritePmd (
+  IN UINT8   Index,
+  IN UINT64  Value
+  );
+
+
+/**
+  Reads the current value of 64-bit Global Pointer (GP).
+
+  Reads and returns the current value of GP.
+  This function is only available on Itanium processors.
+
+  @return The current value of GP.
+
+**/
+UINT64
+EFIAPI
+AsmReadGp (
+  VOID
+  );
+
+
+/**
+  Write the current value of 64-bit Global Pointer (GP).
+
+  Writes the current value of GP. The 64-bit value written to the GP is returned.
+  No parameter checking is performed on Value.
+  This function is only available on Itanium processors.
+
+  @param Value  The 64-bit value to write to GP.
+
+  @return The 64-bit value written to the GP.
+
+**/
+UINT64
+EFIAPI
+AsmWriteGp (
+  IN UINT64  Value
+  );
+
+
+/**
+  Reads the current value of 64-bit Stack Pointer (SP).
+
+  Reads and returns the current value of SP.
+  This function is only available on Itanium processors.
+
+  @return The current value of SP.
+
+**/
+UINT64
+EFIAPI
+AsmReadSp (
+  VOID
+  );
+
+
+///
+/// Valid Index value for AsmReadControlRegister().
+///
+#define IPF_CONTROL_REGISTER_DCR   0
+#define IPF_CONTROL_REGISTER_ITM   1
+#define IPF_CONTROL_REGISTER_IVA   2
+#define IPF_CONTROL_REGISTER_PTA   8
+#define IPF_CONTROL_REGISTER_IPSR  16
+#define IPF_CONTROL_REGISTER_ISR   17
+#define IPF_CONTROL_REGISTER_IIP   19
+#define IPF_CONTROL_REGISTER_IFA   20
+#define IPF_CONTROL_REGISTER_ITIR  21
+#define IPF_CONTROL_REGISTER_IIPA  22
+#define IPF_CONTROL_REGISTER_IFS   23
+#define IPF_CONTROL_REGISTER_IIM   24
+#define IPF_CONTROL_REGISTER_IHA   25
+#define IPF_CONTROL_REGISTER_LID   64
+#define IPF_CONTROL_REGISTER_IVR   65
+#define IPF_CONTROL_REGISTER_TPR   66
+#define IPF_CONTROL_REGISTER_EOI   67
+#define IPF_CONTROL_REGISTER_IRR0  68
+#define IPF_CONTROL_REGISTER_IRR1  69
+#define IPF_CONTROL_REGISTER_IRR2  70
+#define IPF_CONTROL_REGISTER_IRR3  71
+#define IPF_CONTROL_REGISTER_ITV   72
+#define IPF_CONTROL_REGISTER_PMV   73
+#define IPF_CONTROL_REGISTER_CMCV  74
+#define IPF_CONTROL_REGISTER_LRR0  80
+#define IPF_CONTROL_REGISTER_LRR1  81
+
+/**
+  Reads a 64-bit control register.
+
+  Reads and returns the control register specified by Index. The valid Index valued
+  are defined above in "Related Definitions".
+  If Index is invalid then 0xFFFFFFFFFFFFFFFF is returned.  This function is only
+  available on Itanium processors.
+
+  @param  Index                     The index of the control register to read.
+
+  @return The control register specified by Index.
+
+**/
+UINT64
+EFIAPI
+AsmReadControlRegister (
+  IN UINT64  Index
+  );
+
+
+///
+/// Valid Index value for AsmReadApplicationRegister().
+///
+#define IPF_APPLICATION_REGISTER_K0        0
+#define IPF_APPLICATION_REGISTER_K1        1
+#define IPF_APPLICATION_REGISTER_K2        2
+#define IPF_APPLICATION_REGISTER_K3        3
+#define IPF_APPLICATION_REGISTER_K4        4
+#define IPF_APPLICATION_REGISTER_K5        5
+#define IPF_APPLICATION_REGISTER_K6        6
+#define IPF_APPLICATION_REGISTER_K7        7
+#define IPF_APPLICATION_REGISTER_RSC       16
+#define IPF_APPLICATION_REGISTER_BSP       17
+#define IPF_APPLICATION_REGISTER_BSPSTORE  18
+#define IPF_APPLICATION_REGISTER_RNAT      19
+#define IPF_APPLICATION_REGISTER_FCR       21
+#define IPF_APPLICATION_REGISTER_EFLAG     24
+#define IPF_APPLICATION_REGISTER_CSD       25
+#define IPF_APPLICATION_REGISTER_SSD       26
+#define IPF_APPLICATION_REGISTER_CFLG      27
+#define IPF_APPLICATION_REGISTER_FSR       28
+#define IPF_APPLICATION_REGISTER_FIR       29
+#define IPF_APPLICATION_REGISTER_FDR       30
+#define IPF_APPLICATION_REGISTER_CCV       32
+#define IPF_APPLICATION_REGISTER_UNAT      36
+#define IPF_APPLICATION_REGISTER_FPSR      40
+#define IPF_APPLICATION_REGISTER_ITC       44
+#define IPF_APPLICATION_REGISTER_PFS       64
+#define IPF_APPLICATION_REGISTER_LC        65
+#define IPF_APPLICATION_REGISTER_EC        66
+
+/**
+  Reads a 64-bit application register.
+
+  Reads and returns the application register specified by Index. The valid Index
+  valued are defined above in "Related Definitions".
+  If Index is invalid then 0xFFFFFFFFFFFFFFFF is returned.  This function is only
+  available on Itanium processors.
+
+  @param  Index                     The index of the application register to read.
+
+  @return The application register specified by Index.
+
+**/
+UINT64
+EFIAPI
+AsmReadApplicationRegister (
+  IN UINT64  Index
+  );
+
+
+/**
+  Reads the current value of a Machine Specific Register (MSR).
+
+  Reads and returns the current value of the Machine Specific Register specified by Index.  No
+  parameter checking is performed on Index, and if the Index value is beyond the implemented MSR
+  register range, a Reserved Register/Field fault may occur.  The caller must either guarantee that
+  Index is valid, or the caller must set up fault handlers to catch the faults.  This function is
+  only available on Itanium processors.
+
+  @param  Index                     The 8-bit Machine Specific Register index to read.
+
+  @return The current value of the Machine Specific Register specified by Index.
+
+**/
+UINT64
+EFIAPI
+AsmReadMsr (
+  IN UINT8   Index
+  );
+
+
+/**
+  Writes the current value of a Machine Specific Register (MSR).
+
+  Writes Value to the Machine Specific Register specified by Index.  Value is returned.  No
+  parameter checking is performed on Index, and if the Index value is beyond the implemented MSR
+  register range, a Reserved Register/Field fault may occur.  The caller must either guarantee that
+  Index is valid, or the caller must set up fault handlers to catch the faults.  This function is
+  only available on Itanium processors.
+
+  @param  Index                     The 8-bit Machine Specific Register index to write.
+  @param  Value                     The 64-bit value to write to the Machine Specific Register.
+
+  @return The 64-bit value to write to the Machine Specific Register.
+
+**/
+UINT64
+EFIAPI
+AsmWriteMsr (
+  IN UINT8   Index,
+  IN UINT64  Value
+  );
+
+
+/**
+  Determines if the CPU is currently executing in virtual, physical, or mixed mode.
+
+  Determines the current execution mode of the CPU.
+  If the CPU is in virtual mode(PSR.RT=1, PSR.DT=1, PSR.IT=1), then 1 is returned.
+  If the CPU is in physical mode(PSR.RT=0, PSR.DT=0, PSR.IT=0), then 0 is returned.
+  If the CPU is not in physical mode or virtual mode, then it is in mixed mode,
+  and -1 is returned.
+  This function is only available on Itanium processors.
+
+  @retval  1  The CPU is in virtual mode.
+  @retval  0  The CPU is in physical mode.
+  @retval -1  The CPU is in mixed mode.
+
+**/
+INT64
+EFIAPI
+AsmCpuVirtual (
+  VOID
+  );
+
+
+/**
+  Makes a PAL procedure call.
+
+  This is a wrapper function to make a PAL procedure call.  Based on the Index
+  value this API will make static or stacked PAL call.  The following table
+  describes the usage of PAL Procedure Index Assignment. Architected procedures
+  may be designated as required or optional.  If a PAL procedure is specified
+  as optional, a unique return code of 0xFFFFFFFFFFFFFFFF is returned in the
+  Status field of the PAL_CALL_RETURN structure.
+  This indicates that the procedure is not present in this PAL implementation.
+  It is the caller's responsibility to check for this return code after calling
+  any optional PAL procedure.
+  No parameter checking is performed on the 5 input parameters, but there are
+  some common rules that the caller should follow when making a PAL call.  Any
+  address passed to PAL as buffers for return parameters must be 8-byte aligned.
+  Unaligned addresses may cause undefined results.  For those parameters defined
+  as reserved or some fields defined as reserved must be zero filled or the invalid
+  argument return value may be returned or undefined result may occur during the
+  execution of the procedure.  If the PalEntryPoint  does not point to a valid
+  PAL entry point then the system behavior is undefined.  This function is only
+  available on Itanium processors.
+
+  @param PalEntryPoint  The PAL procedure calls entry point.
+  @param Index          The PAL procedure Index number.
+  @param Arg2           The 2nd parameter for PAL procedure calls.
+  @param Arg3           The 3rd parameter for PAL procedure calls.
+  @param Arg4           The 4th parameter for PAL procedure calls.
+
+  @return structure returned from the PAL Call procedure, including the status and return value.
+
+**/
+PAL_CALL_RETURN
+EFIAPI
+AsmPalCall (
+  IN UINT64  PalEntryPoint,
+  IN UINT64  Index,
+  IN UINT64  Arg2,
+  IN UINT64  Arg3,
+  IN UINT64  Arg4
+  );
+#endif
+
+#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)
+///
+/// IA32 and x64 Specific Functions.
+/// Byte packed structure for 16-bit Real Mode EFLAGS.
+///
+typedef union {
+  struct {
+    UINT32  CF:1;           ///< Carry Flag.
+    UINT32  Reserved_0:1;   ///< Reserved.
+    UINT32  PF:1;           ///< Parity Flag.
+    UINT32  Reserved_1:1;   ///< Reserved.
+    UINT32  AF:1;           ///< Auxiliary Carry Flag.
+    UINT32  Reserved_2:1;   ///< Reserved.
+    UINT32  ZF:1;           ///< Zero Flag.
+    UINT32  SF:1;           ///< Sign Flag.
+    UINT32  TF:1;           ///< Trap Flag.
+    UINT32  IF:1;           ///< Interrupt Enable Flag.
+    UINT32  DF:1;           ///< Direction Flag.
+    UINT32  OF:1;           ///< Overflow Flag.
+    UINT32  IOPL:2;         ///< I/O Privilege Level.
+    UINT32  NT:1;           ///< Nested Task.
+    UINT32  Reserved_3:1;   ///< Reserved.
+  } Bits;
+  UINT16    Uint16;
+} IA32_FLAGS16;
+
+///
+/// Byte packed structure for EFLAGS/RFLAGS.
+/// 32-bits on IA-32.
+/// 64-bits on x64.  The upper 32-bits on x64 are reserved.
+///
+typedef union {
+  struct {
+    UINT32  CF:1;           ///< Carry Flag.
+    UINT32  Reserved_0:1;   ///< Reserved.
+    UINT32  PF:1;           ///< Parity Flag.
+    UINT32  Reserved_1:1;   ///< Reserved.
+    UINT32  AF:1;           ///< Auxiliary Carry Flag.
+    UINT32  Reserved_2:1;   ///< Reserved.
+    UINT32  ZF:1;           ///< Zero Flag.
+    UINT32  SF:1;           ///< Sign Flag.
+    UINT32  TF:1;           ///< Trap Flag.
+    UINT32  IF:1;           ///< Interrupt Enable Flag.
+    UINT32  DF:1;           ///< Direction Flag.
+    UINT32  OF:1;           ///< Overflow Flag.
+    UINT32  IOPL:2;         ///< I/O Privilege Level.
+    UINT32  NT:1;           ///< Nested Task.
+    UINT32  Reserved_3:1;   ///< Reserved.
+    UINT32  RF:1;           ///< Resume Flag.
+    UINT32  VM:1;           ///< Virtual 8086 Mode.
+    UINT32  AC:1;           ///< Alignment Check.
+    UINT32  VIF:1;          ///< Virtual Interrupt Flag.
+    UINT32  VIP:1;          ///< Virtual Interrupt Pending.
+    UINT32  ID:1;           ///< ID Flag.
+    UINT32  Reserved_4:10;  ///< Reserved.
+  } Bits;
+  UINTN     UintN;
+} IA32_EFLAGS32;
+
+///
+/// Byte packed structure for Control Register 0 (CR0).
+/// 32-bits on IA-32.
+/// 64-bits on x64.  The upper 32-bits on x64 are reserved.
+///
+typedef union {
+  struct {
+    UINT32  PE:1;           ///< Protection Enable.
+    UINT32  MP:1;           ///< Monitor Coprocessor.
+    UINT32  EM:1;           ///< Emulation.
+    UINT32  TS:1;           ///< Task Switched.
+    UINT32  ET:1;           ///< Extension Type.
+    UINT32  NE:1;           ///< Numeric Error.
+    UINT32  Reserved_0:10;  ///< Reserved.
+    UINT32  WP:1;           ///< Write Protect.
+    UINT32  Reserved_1:1;   ///< Reserved.
+    UINT32  AM:1;           ///< Alignment Mask.
+    UINT32  Reserved_2:10;  ///< Reserved.
+    UINT32  NW:1;           ///< Mot Write-through.
+    UINT32  CD:1;           ///< Cache Disable.
+    UINT32  PG:1;           ///< Paging.
+  } Bits;
+  UINTN     UintN;
+} IA32_CR0;
+
+///
+/// Byte packed structure for Control Register 4 (CR4).
+/// 32-bits on IA-32.
+/// 64-bits on x64.  The upper 32-bits on x64 are reserved.
+///
+typedef union {
+  struct {
+    UINT32  VME:1;          ///< Virtual-8086 Mode Extensions.
+    UINT32  PVI:1;          ///< Protected-Mode Virtual Interrupts.
+    UINT32  TSD:1;          ///< Time Stamp Disable.
+    UINT32  DE:1;           ///< Debugging Extensions.
+    UINT32  PSE:1;          ///< Page Size Extensions.
+    UINT32  PAE:1;          ///< Physical Address Extension.
+    UINT32  MCE:1;          ///< Machine Check Enable.
+    UINT32  PGE:1;          ///< Page Global Enable.
+    UINT32  PCE:1;          ///< Performance Monitoring Counter
+                            ///< Enable.
+    UINT32  OSFXSR:1;       ///< Operating System Support for
+                            ///< FXSAVE and FXRSTOR instructions
+    UINT32  OSXMMEXCPT:1;   ///< Operating System Support for
+                            ///< Unmasked SIMD Floating Point
+                            ///< Exceptions.
+    UINT32  Reserved_0:2;   ///< Reserved.
+    UINT32  VMXE:1;         ///< VMX Enable
+    UINT32  Reserved_1:18;  ///< Reserved.
+  } Bits;
+  UINTN     UintN;
+} IA32_CR4;
+
+///
+/// Byte packed structure for a segment descriptor in a GDT/LDT.
+///
+typedef union {
+  struct {
+    UINT32  LimitLow:16;
+    UINT32  BaseLow:16;
+    UINT32  BaseMid:8;
+    UINT32  Type:4;
+    UINT32  S:1;
+    UINT32  DPL:2;
+    UINT32  P:1;
+    UINT32  LimitHigh:4;
+    UINT32  AVL:1;
+    UINT32  L:1;
+    UINT32  DB:1;
+    UINT32  G:1;
+    UINT32  BaseHigh:8;
+  } Bits;
+  UINT64  Uint64;
+} IA32_SEGMENT_DESCRIPTOR;
+
+///
+/// Byte packed structure for an IDTR, GDTR, LDTR descriptor.
+///
+#pragma pack (1)
+typedef struct {
+  UINT16  Limit;
+  UINTN   Base;
+} IA32_DESCRIPTOR;
+#pragma pack ()
+
+#define IA32_IDT_GATE_TYPE_TASK          0x85
+#define IA32_IDT_GATE_TYPE_INTERRUPT_16  0x86
+#define IA32_IDT_GATE_TYPE_TRAP_16       0x87
+#define IA32_IDT_GATE_TYPE_INTERRUPT_32  0x8E
+#define IA32_IDT_GATE_TYPE_TRAP_32       0x8F
+
+
+#if defined (MDE_CPU_IA32)
+///
+/// Byte packed structure for an IA-32 Interrupt Gate Descriptor.
+///
+typedef union {
+  struct {
+    UINT32  OffsetLow:16;   ///< Offset bits 15..0.
+    UINT32  Selector:16;    ///< Selector.
+    UINT32  Reserved_0:8;   ///< Reserved.
+    UINT32  GateType:8;     ///< Gate Type.  See #defines above.
+    UINT32  OffsetHigh:16;  ///< Offset bits 31..16.
+  } Bits;
+  UINT64  Uint64;
+} IA32_IDT_GATE_DESCRIPTOR;
+
+#endif
+
+#if defined (MDE_CPU_X64)
+///
+/// Byte packed structure for an x64 Interrupt Gate Descriptor.
+///
+typedef union {
+  struct {
+    UINT32  OffsetLow:16;   ///< Offset bits 15..0.
+    UINT32  Selector:16;    ///< Selector.
+    UINT32  Reserved_0:8;   ///< Reserved.
+    UINT32  GateType:8;     ///< Gate Type.  See #defines above.
+    UINT32  OffsetHigh:16;  ///< Offset bits 31..16.
+    UINT32  OffsetUpper:32; ///< Offset bits 63..32.
+    UINT32  Reserved_1:32;  ///< Reserved.
+  } Bits;
+  struct {
+    UINT64  Uint64;
+    UINT64  Uint64_1;
+  } Uint128;
+} IA32_IDT_GATE_DESCRIPTOR;
+
+#endif
+
+///
+/// Byte packed structure for an FP/SSE/SSE2 context.
+///
+typedef struct {
+  UINT8  Buffer[512];
+} IA32_FX_BUFFER;
+
+///
+/// Structures for the 16-bit real mode thunks.
+///
+typedef struct {
+  UINT32                            Reserved1;
+  UINT32                            Reserved2;
+  UINT32                            Reserved3;
+  UINT32                            Reserved4;
+  UINT8                             BL;
+  UINT8                             BH;
+  UINT16                            Reserved5;
+  UINT8                             DL;
+  UINT8                             DH;
+  UINT16                            Reserved6;
+  UINT8                             CL;
+  UINT8                             CH;
+  UINT16                            Reserved7;
+  UINT8                             AL;
+  UINT8                             AH;
+  UINT16                            Reserved8;
+} IA32_BYTE_REGS;
+
+typedef struct {
+  UINT16                            DI;
+  UINT16                            Reserved1;
+  UINT16                            SI;
+  UINT16                            Reserved2;
+  UINT16                            BP;
+  UINT16                            Reserved3;
+  UINT16                            SP;
+  UINT16                            Reserved4;
+  UINT16                            BX;
+  UINT16                            Reserved5;
+  UINT16                            DX;
+  UINT16                            Reserved6;
+  UINT16                            CX;
+  UINT16                            Reserved7;
+  UINT16                            AX;
+  UINT16                            Reserved8;
+} IA32_WORD_REGS;
+
+typedef struct {
+  UINT32                            EDI;
+  UINT32                            ESI;
+  UINT32                            EBP;
+  UINT32                            ESP;
+  UINT32                            EBX;
+  UINT32                            EDX;
+  UINT32                            ECX;
+  UINT32                            EAX;
+  UINT16                            DS;
+  UINT16                            ES;
+  UINT16                            FS;
+  UINT16                            GS;
+  IA32_EFLAGS32                     EFLAGS;
+  UINT32                            Eip;
+  UINT16                            CS;
+  UINT16                            SS;
+} IA32_DWORD_REGS;
+
+typedef union {
+  IA32_DWORD_REGS                   E;
+  IA32_WORD_REGS                    X;
+  IA32_BYTE_REGS                    H;
+} IA32_REGISTER_SET;
+
+///
+/// Byte packed structure for an 16-bit real mode thunks.
+///
+typedef struct {
+  IA32_REGISTER_SET                 *RealModeState;
+  VOID                              *RealModeBuffer;
+  UINT32                            RealModeBufferSize;
+  UINT32                            ThunkAttributes;
+} THUNK_CONTEXT;
+
+#define THUNK_ATTRIBUTE_BIG_REAL_MODE             0x00000001
+#define THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15   0x00000002
+#define THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL 0x00000004
+
+/**
+  Retrieves CPUID information.
+
+  Executes the CPUID instruction with EAX set to the value specified by Index.
+  This function always returns Index.
+  If Eax is not NULL, then the value of EAX after CPUID is returned in Eax.
+  If Ebx is not NULL, then the value of EBX after CPUID is returned in Ebx.
+  If Ecx is not NULL, then the value of ECX after CPUID is returned in Ecx.
+  If Edx is not NULL, then the value of EDX after CPUID is returned in Edx.
+  This function is only available on IA-32 and x64.
+
+  @param  Index The 32-bit value to load into EAX prior to invoking the CPUID
+                instruction.
+  @param  Eax   The pointer to the 32-bit EAX value returned by the CPUID
+                instruction. This is an optional parameter that may be NULL.
+  @param  Ebx   The pointer to the 32-bit EBX value returned by the CPUID
+                instruction. This is an optional parameter that may be NULL.
+  @param  Ecx   The pointer to the 32-bit ECX value returned by the CPUID
+                instruction. This is an optional parameter that may be NULL.
+  @param  Edx   The pointer to the 32-bit EDX value returned by the CPUID
+                instruction. This is an optional parameter that may be NULL.
+
+  @return Index.
+
+**/
+UINT32
+EFIAPI
+AsmCpuid (
+  IN      UINT32                    Index,
+  OUT     UINT32                    *Eax,  OPTIONAL
+  OUT     UINT32                    *Ebx,  OPTIONAL
+  OUT     UINT32                    *Ecx,  OPTIONAL
+  OUT     UINT32                    *Edx   OPTIONAL
+  );
+
+
+/**
+  Retrieves CPUID information using an extended leaf identifier.
+
+  Executes the CPUID instruction with EAX set to the value specified by Index
+  and ECX set to the value specified by SubIndex. This function always returns
+  Index. This function is only available on IA-32 and x64.
+
+  If Eax is not NULL, then the value of EAX after CPUID is returned in Eax.
+  If Ebx is not NULL, then the value of EBX after CPUID is returned in Ebx.
+  If Ecx is not NULL, then the value of ECX after CPUID is returned in Ecx.
+  If Edx is not NULL, then the value of EDX after CPUID is returned in Edx.
+
+  @param  Index     The 32-bit value to load into EAX prior to invoking the
+                    CPUID instruction.
+  @param  SubIndex  The 32-bit value to load into ECX prior to invoking the
+                    CPUID instruction.
+  @param  Eax       The pointer to the 32-bit EAX value returned by the CPUID
+                    instruction. This is an optional parameter that may be
+                    NULL.
+  @param  Ebx       The pointer to the 32-bit EBX value returned by the CPUID
+                    instruction. This is an optional parameter that may be
+                    NULL.
+  @param  Ecx       The pointer to the 32-bit ECX value returned by the CPUID
+                    instruction. This is an optional parameter that may be
+                    NULL.
+  @param  Edx       The pointer to the 32-bit EDX value returned by the CPUID
+                    instruction. This is an optional parameter that may be
+                    NULL.
+
+  @return Index.
+
+**/
+UINT32
+EFIAPI
+AsmCpuidEx (
+  IN      UINT32                    Index,
+  IN      UINT32                    SubIndex,
+  OUT     UINT32                    *Eax,  OPTIONAL
+  OUT     UINT32                    *Ebx,  OPTIONAL
+  OUT     UINT32                    *Ecx,  OPTIONAL
+  OUT     UINT32                    *Edx   OPTIONAL
+  );
+
+
+/**
+  Set CD bit and clear NW bit of CR0 followed by a WBINVD.
+
+  Disables the caches by setting the CD bit of CR0 to 1, clearing the NW bit of CR0 to 0,
+  and executing a WBINVD instruction.  This function is only available on IA-32 and x64.
+
+**/
+VOID
+EFIAPI
+AsmDisableCache (
+  VOID
+  );
+
+
+/**
+  Perform a WBINVD and clear both the CD and NW bits of CR0.
+
+  Enables the caches by executing a WBINVD instruction and then clear both the CD and NW
+  bits of CR0 to 0.  This function is only available on IA-32 and x64.
+
+**/
+VOID
+EFIAPI
+AsmEnableCache (
+  VOID
+  );
+
+
+/**
+  Returns the lower 32-bits of a Machine Specific Register(MSR).
+
+  Reads and returns the lower 32-bits of the MSR specified by Index.
+  No parameter checking is performed on Index, and some Index values may cause
+  CPU exceptions. The caller must either guarantee that Index is valid, or the
+  caller must set up exception handlers to catch the exceptions. This function
+  is only available on IA-32 and x64.
+
+  @param  Index The 32-bit MSR index to read.
+
+  @return The lower 32 bits of the MSR identified by Index.
+
+**/
+UINT32
+EFIAPI
+AsmReadMsr32 (
+  IN      UINT32                    Index
+  );
+
+
+/**
+  Writes a 32-bit value to a Machine Specific Register(MSR), and returns the value.
+  The upper 32-bits of the MSR are set to zero.
+
+  Writes the 32-bit value specified by Value to the MSR specified by Index. The
+  upper 32-bits of the MSR write are set to zero. The 32-bit value written to
+  the MSR is returned. No parameter checking is performed on Index or Value,
+  and some of these may cause CPU exceptions. The caller must either guarantee
+  that Index and Value are valid, or the caller must establish proper exception
+  handlers. This function is only available on IA-32 and x64.
+
+  @param  Index The 32-bit MSR index to write.
+  @param  Value The 32-bit value to write to the MSR.
+
+  @return Value
+
+**/
+UINT32
+EFIAPI
+AsmWriteMsr32 (
+  IN      UINT32                    Index,
+  IN      UINT32                    Value
+  );
+
+
+/**
+  Reads a 64-bit MSR, performs a bitwise OR on the lower 32-bits, and
+  writes the result back to the 64-bit MSR.
+
+  Reads the 64-bit MSR specified by Index, performs a bitwise OR
+  between the lower 32-bits of the read result and the value specified by
+  OrData, and writes the result to the 64-bit MSR specified by Index. The lower
+  32-bits of the value written to the MSR is returned. No parameter checking is
+  performed on Index or OrData, and some of these may cause CPU exceptions. The
+  caller must either guarantee that Index and OrData are valid, or the caller
+  must establish proper exception handlers. This function is only available on
+  IA-32 and x64.
+
+  @param  Index   The 32-bit MSR index to write.
+  @param  OrData  The value to OR with the read value from the MSR.
+
+  @return The lower 32-bit value written to the MSR.
+
+**/
+UINT32
+EFIAPI
+AsmMsrOr32 (
+  IN      UINT32                    Index,
+  IN      UINT32                    OrData
+  );
+
+
+/**
+  Reads a 64-bit MSR, performs a bitwise AND on the lower 32-bits, and writes
+  the result back to the 64-bit MSR.
+
+  Reads the 64-bit MSR specified by Index, performs a bitwise AND between the
+  lower 32-bits of the read result and the value specified by AndData, and
+  writes the result to the 64-bit MSR specified by Index. The lower 32-bits of
+  the value written to the MSR is returned. No parameter checking is performed
+  on Index or AndData, and some of these may cause CPU exceptions. The caller
+  must either guarantee that Index and AndData are valid, or the caller must
+  establish proper exception handlers. This function is only available on IA-32
+  and x64.
+
+  @param  Index   The 32-bit MSR index to write.
+  @param  AndData The value to AND with the read value from the MSR.
+
+  @return The lower 32-bit value written to the MSR.
+
+**/
+UINT32
+EFIAPI
+AsmMsrAnd32 (
+  IN      UINT32                    Index,
+  IN      UINT32                    AndData
+  );
+
+
+/**
+  Reads a 64-bit MSR, performs a bitwise AND followed by a bitwise OR
+  on the lower 32-bits, and writes the result back to the 64-bit MSR.
+
+  Reads the 64-bit MSR specified by Index, performs a bitwise AND between the
+  lower 32-bits of the read result and the value specified by AndData
+  preserving the upper 32-bits, performs a bitwise OR between the
+  result of the AND operation and the value specified by OrData, and writes the
+  result to the 64-bit MSR specified by Address. The lower 32-bits of the value
+  written to the MSR is returned. No parameter checking is performed on Index,
+  AndData, or OrData, and some of these may cause CPU exceptions. The caller
+  must either guarantee that Index, AndData, and OrData are valid, or the
+  caller must establish proper exception handlers. This function is only
+  available on IA-32 and x64.
+
+  @param  Index   The 32-bit MSR index to write.
+  @param  AndData The value to AND with the read value from the MSR.
+  @param  OrData  The value to OR with the result of the AND operation.
+
+  @return The lower 32-bit value written to the MSR.
+
+**/
+UINT32
+EFIAPI
+AsmMsrAndThenOr32 (
+  IN      UINT32                    Index,
+  IN      UINT32                    AndData,
+  IN      UINT32                    OrData
+  );
+
+
+/**
+  Reads a bit field of an MSR.
+
+  Reads the bit field in the lower 32-bits of a 64-bit MSR. The bit field is
+  specified by the StartBit and the EndBit. The value of the bit field is
+  returned. The caller must either guarantee that Index is valid, or the caller
+  must set up exception handlers to catch the exceptions. This function is only
+  available on IA-32 and x64.
+
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+
+  @param  Index     The 32-bit MSR index to read.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+
+  @return The bit field read from the MSR.
+
+**/
+UINT32
+EFIAPI
+AsmMsrBitFieldRead32 (
+  IN      UINT32                    Index,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit
+  );
+
+
+/**
+  Writes a bit field to an MSR.
+
+  Writes Value to a bit field in the lower 32-bits of a 64-bit MSR. The bit
+  field is specified by the StartBit and the EndBit. All other bits in the
+  destination MSR are preserved. The lower 32-bits of the MSR written is
+  returned. The caller must either guarantee that Index and the data written
+  is valid, or the caller must set up exception handlers to catch the exceptions.
+  This function is only available on IA-32 and x64.
+
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Index     The 32-bit MSR index to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  Value     New value of the bit field.
+
+  @return The lower 32-bit of the value written to the MSR.
+
+**/
+UINT32
+EFIAPI
+AsmMsrBitFieldWrite32 (
+  IN      UINT32                    Index,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT32                    Value
+  );
+
+
+/**
+  Reads a bit field in a 64-bit MSR, performs a bitwise OR, and writes the
+  result back to the bit field in the 64-bit MSR.
+
+  Reads the 64-bit MSR specified by Index, performs a bitwise OR
+  between the read result and the value specified by OrData, and writes the
+  result to the 64-bit MSR specified by Index. The lower 32-bits of the value
+  written to the MSR are returned. Extra left bits in OrData are stripped. The
+  caller must either guarantee that Index and the data written is valid, or
+  the caller must set up exception handlers to catch the exceptions. This
+  function is only available on IA-32 and x64.
+
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Index     The 32-bit MSR index to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  OrData    The value to OR with the read value from the MSR.
+
+  @return The lower 32-bit of the value written to the MSR.
+
+**/
+UINT32
+EFIAPI
+AsmMsrBitFieldOr32 (
+  IN      UINT32                    Index,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT32                    OrData
+  );
+
+
+/**
+  Reads a bit field in a 64-bit MSR, performs a bitwise AND, and writes the
+  result back to the bit field in the 64-bit MSR.
+
+  Reads the 64-bit MSR specified by Index, performs a bitwise AND between the
+  read result and the value specified by AndData, and writes the result to the
+  64-bit MSR specified by Index. The lower 32-bits of the value written to the
+  MSR are returned. Extra left bits in AndData are stripped. The caller must
+  either guarantee that Index and the data written is valid, or the caller must
+  set up exception handlers to catch the exceptions. This function is only
+  available on IA-32 and x64.
+
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Index     The 32-bit MSR index to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  AndData   The value to AND with the read value from the MSR.
+
+  @return The lower 32-bit of the value written to the MSR.
+
+**/
+UINT32
+EFIAPI
+AsmMsrBitFieldAnd32 (
+  IN      UINT32                    Index,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT32                    AndData
+  );
+
+
+/**
+  Reads a bit field in a 64-bit MSR, performs a bitwise AND followed by a
+  bitwise OR, and writes the result back to the bit field in the
+  64-bit MSR.
+
+  Reads the 64-bit MSR specified by Index, performs a bitwise AND followed by a
+  bitwise OR between the read result and the value specified by
+  AndData, and writes the result to the 64-bit MSR specified by Index. The
+  lower 32-bits of the value written to the MSR are returned. Extra left bits
+  in both AndData and OrData are stripped. The caller must either guarantee
+  that Index and the data written is valid, or the caller must set up exception
+  handlers to catch the exceptions. This function is only available on IA-32
+  and x64.
+
+  If StartBit is greater than 31, then ASSERT().
+  If EndBit is greater than 31, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Index     The 32-bit MSR index to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..31.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..31.
+  @param  AndData   The value to AND with the read value from the MSR.
+  @param  OrData    The value to OR with the result of the AND operation.
+
+  @return The lower 32-bit of the value written to the MSR.
+
+**/
+UINT32
+EFIAPI
+AsmMsrBitFieldAndThenOr32 (
+  IN      UINT32                    Index,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT32                    AndData,
+  IN      UINT32                    OrData
+  );
+
+
+/**
+  Returns a 64-bit Machine Specific Register(MSR).
+
+  Reads and returns the 64-bit MSR specified by Index. No parameter checking is
+  performed on Index, and some Index values may cause CPU exceptions. The
+  caller must either guarantee that Index is valid, or the caller must set up
+  exception handlers to catch the exceptions. This function is only available
+  on IA-32 and x64.
+
+  @param  Index The 32-bit MSR index to read.
+
+  @return The value of the MSR identified by Index.
+
+**/
+UINT64
+EFIAPI
+AsmReadMsr64 (
+  IN      UINT32                    Index
+  );
+
+
+/**
+  Writes a 64-bit value to a Machine Specific Register(MSR), and returns the
+  value.
+
+  Writes the 64-bit value specified by Value to the MSR specified by Index. The
+  64-bit value written to the MSR is returned. No parameter checking is
+  performed on Index or Value, and some of these may cause CPU exceptions. The
+  caller must either guarantee that Index and Value are valid, or the caller
+  must establish proper exception handlers. This function is only available on
+  IA-32 and x64.
+
+  @param  Index The 32-bit MSR index to write.
+  @param  Value The 64-bit value to write to the MSR.
+
+  @return Value
+
+**/
+UINT64
+EFIAPI
+AsmWriteMsr64 (
+  IN      UINT32                    Index,
+  IN      UINT64                    Value
+  );
+
+
+/**
+  Reads a 64-bit MSR, performs a bitwise OR, and writes the result
+  back to the 64-bit MSR.
+
+  Reads the 64-bit MSR specified by Index, performs a bitwise OR
+  between the read result and the value specified by OrData, and writes the
+  result to the 64-bit MSR specified by Index. The value written to the MSR is
+  returned. No parameter checking is performed on Index or OrData, and some of
+  these may cause CPU exceptions. The caller must either guarantee that Index
+  and OrData are valid, or the caller must establish proper exception handlers.
+  This function is only available on IA-32 and x64.
+
+  @param  Index   The 32-bit MSR index to write.
+  @param  OrData  The value to OR with the read value from the MSR.
+
+  @return The value written back to the MSR.
+
+**/
+UINT64
+EFIAPI
+AsmMsrOr64 (
+  IN      UINT32                    Index,
+  IN      UINT64                    OrData
+  );
+
+
+/**
+  Reads a 64-bit MSR, performs a bitwise AND, and writes the result back to the
+  64-bit MSR.
+
+  Reads the 64-bit MSR specified by Index, performs a bitwise AND between the
+  read result and the value specified by OrData, and writes the result to the
+  64-bit MSR specified by Index. The value written to the MSR is returned. No
+  parameter checking is performed on Index or OrData, and some of these may
+  cause CPU exceptions. The caller must either guarantee that Index and OrData
+  are valid, or the caller must establish proper exception handlers. This
+  function is only available on IA-32 and x64.
+
+  @param  Index   The 32-bit MSR index to write.
+  @param  AndData The value to AND with the read value from the MSR.
+
+  @return The value written back to the MSR.
+
+**/
+UINT64
+EFIAPI
+AsmMsrAnd64 (
+  IN      UINT32                    Index,
+  IN      UINT64                    AndData
+  );
+
+
+/**
+  Reads a 64-bit MSR, performs a bitwise AND followed by a bitwise
+  OR, and writes the result back to the 64-bit MSR.
+
+  Reads the 64-bit MSR specified by Index, performs a bitwise AND between read
+  result and the value specified by AndData, performs a bitwise OR
+  between the result of the AND operation and the value specified by OrData,
+  and writes the result to the 64-bit MSR specified by Index. The value written
+  to the MSR is returned. No parameter checking is performed on Index, AndData,
+  or OrData, and some of these may cause CPU exceptions. The caller must either
+  guarantee that Index, AndData, and OrData are valid, or the caller must
+  establish proper exception handlers. This function is only available on IA-32
+  and x64.
+
+  @param  Index   The 32-bit MSR index to write.
+  @param  AndData The value to AND with the read value from the MSR.
+  @param  OrData  The value to OR with the result of the AND operation.
+
+  @return The value written back to the MSR.
+
+**/
+UINT64
+EFIAPI
+AsmMsrAndThenOr64 (
+  IN      UINT32                    Index,
+  IN      UINT64                    AndData,
+  IN      UINT64                    OrData
+  );
+
+
+/**
+  Reads a bit field of an MSR.
+
+  Reads the bit field in the 64-bit MSR. The bit field is specified by the
+  StartBit and the EndBit. The value of the bit field is returned. The caller
+  must either guarantee that Index is valid, or the caller must set up
+  exception handlers to catch the exceptions. This function is only available
+  on IA-32 and x64.
+
+  If StartBit is greater than 63, then ASSERT().
+  If EndBit is greater than 63, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+
+  @param  Index     The 32-bit MSR index to read.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..63.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..63.
+
+  @return The value read from the MSR.
+
+**/
+UINT64
+EFIAPI
+AsmMsrBitFieldRead64 (
+  IN      UINT32                    Index,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit
+  );
+
+
+/**
+  Writes a bit field to an MSR.
+
+  Writes Value to a bit field in a 64-bit MSR. The bit field is specified by
+  the StartBit and the EndBit. All other bits in the destination MSR are
+  preserved. The MSR written is returned. The caller must either guarantee
+  that Index and the data written is valid, or the caller must set up exception
+  handlers to catch the exceptions. This function is only available on IA-32 and x64.
+
+  If StartBit is greater than 63, then ASSERT().
+  If EndBit is greater than 63, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Index     The 32-bit MSR index to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..63.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..63.
+  @param  Value     New value of the bit field.
+
+  @return The value written back to the MSR.
+
+**/
+UINT64
+EFIAPI
+AsmMsrBitFieldWrite64 (
+  IN      UINT32                    Index,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT64                    Value
+  );
+
+
+/**
+  Reads a bit field in a 64-bit MSR, performs a bitwise OR, and
+  writes the result back to the bit field in the 64-bit MSR.
+
+  Reads the 64-bit MSR specified by Index, performs a bitwise OR
+  between the read result and the value specified by OrData, and writes the
+  result to the 64-bit MSR specified by Index. The value written to the MSR is
+  returned. Extra left bits in OrData are stripped. The caller must either
+  guarantee that Index and the data written is valid, or the caller must set up
+  exception handlers to catch the exceptions. This function is only available
+  on IA-32 and x64.
+
+  If StartBit is greater than 63, then ASSERT().
+  If EndBit is greater than 63, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Index     The 32-bit MSR index to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..63.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..63.
+  @param  OrData    The value to OR with the read value from the bit field.
+
+  @return The value written back to the MSR.
+
+**/
+UINT64
+EFIAPI
+AsmMsrBitFieldOr64 (
+  IN      UINT32                    Index,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT64                    OrData
+  );
+
+
+/**
+  Reads a bit field in a 64-bit MSR, performs a bitwise AND, and writes the
+  result back to the bit field in the 64-bit MSR.
+
+  Reads the 64-bit MSR specified by Index, performs a bitwise AND between the
+  read result and the value specified by AndData, and writes the result to the
+  64-bit MSR specified by Index. The value written to the MSR is returned.
+  Extra left bits in AndData are stripped. The caller must either guarantee
+  that Index and the data written is valid, or the caller must set up exception
+  handlers to catch the exceptions. This function is only available on IA-32
+  and x64.
+
+  If StartBit is greater than 63, then ASSERT().
+  If EndBit is greater than 63, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Index     The 32-bit MSR index to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..63.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..63.
+  @param  AndData   The value to AND with the read value from the bit field.
+
+  @return The value written back to the MSR.
+
+**/
+UINT64
+EFIAPI
+AsmMsrBitFieldAnd64 (
+  IN      UINT32                    Index,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT64                    AndData
+  );
+
+
+/**
+  Reads a bit field in a 64-bit MSR, performs a bitwise AND followed by a
+  bitwise OR, and writes the result back to the bit field in the
+  64-bit MSR.
+
+  Reads the 64-bit MSR specified by Index, performs a bitwise AND followed by
+  a bitwise OR between the read result and the value specified by
+  AndData, and writes the result to the 64-bit MSR specified by Index. The
+  value written to the MSR is returned. Extra left bits in both AndData and
+  OrData are stripped. The caller must either guarantee that Index and the data
+  written is valid, or the caller must set up exception handlers to catch the
+  exceptions. This function is only available on IA-32 and x64.
+
+  If StartBit is greater than 63, then ASSERT().
+  If EndBit is greater than 63, then ASSERT().
+  If EndBit is less than StartBit, then ASSERT().
+  If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+  If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
+
+  @param  Index     The 32-bit MSR index to write.
+  @param  StartBit  The ordinal of the least significant bit in the bit field.
+                    Range 0..63.
+  @param  EndBit    The ordinal of the most significant bit in the bit field.
+                    Range 0..63.
+  @param  AndData   The value to AND with the read value from the bit field.
+  @param  OrData    The value to OR with the result of the AND operation.
+
+  @return The value written back to the MSR.
+
+**/
+UINT64
+EFIAPI
+AsmMsrBitFieldAndThenOr64 (
+  IN      UINT32                    Index,
+  IN      UINTN                     StartBit,
+  IN      UINTN                     EndBit,
+  IN      UINT64                    AndData,
+  IN      UINT64                    OrData
+  );
+
+
+/**
+  Reads the current value of the EFLAGS register.
+
+  Reads and returns the current value of the EFLAGS register. This function is
+  only available on IA-32 and x64. This returns a 32-bit value on IA-32 and a
+  64-bit value on x64.
+
+  @return EFLAGS on IA-32 or RFLAGS on x64.
+
+**/
+UINTN
+EFIAPI
+AsmReadEflags (
+  VOID
+  );
+
+
+/**
+  Reads the current value of the Control Register 0 (CR0).
+
+  Reads and returns the current value of CR0. This function is only available
+  on IA-32 and x64. This returns a 32-bit value on IA-32 and a 64-bit value on
+  x64.
+
+  @return The value of the Control Register 0 (CR0).
+
+**/
+UINTN
+EFIAPI
+AsmReadCr0 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of the Control Register 2 (CR2).
+
+  Reads and returns the current value of CR2. This function is only available
+  on IA-32 and x64. This returns a 32-bit value on IA-32 and a 64-bit value on
+  x64.
+
+  @return The value of the Control Register 2 (CR2).
+
+**/
+UINTN
+EFIAPI
+AsmReadCr2 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of the Control Register 3 (CR3).
+
+  Reads and returns the current value of CR3. This function is only available
+  on IA-32 and x64. This returns a 32-bit value on IA-32 and a 64-bit value on
+  x64.
+
+  @return The value of the Control Register 3 (CR3).
+
+**/
+UINTN
+EFIAPI
+AsmReadCr3 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of the Control Register 4 (CR4).
+
+  Reads and returns the current value of CR4. This function is only available
+  on IA-32 and x64. This returns a 32-bit value on IA-32 and a 64-bit value on
+  x64.
+
+  @return The value of the Control Register 4 (CR4).
+
+**/
+UINTN
+EFIAPI
+AsmReadCr4 (
+  VOID
+  );
+
+
+/**
+  Writes a value to Control Register 0 (CR0).
+
+  Writes and returns a new value to CR0. This function is only available on
+  IA-32 and x64. This writes a 32-bit value on IA-32 and a 64-bit value on x64.
+
+  @param  Cr0 The value to write to CR0.
+
+  @return The value written to CR0.
+
+**/
+UINTN
+EFIAPI
+AsmWriteCr0 (
+  UINTN  Cr0
+  );
+
+
+/**
+  Writes a value to Control Register 2 (CR2).
+
+  Writes and returns a new value to CR2. This function is only available on
+  IA-32 and x64. This writes a 32-bit value on IA-32 and a 64-bit value on x64.
+
+  @param  Cr2 The value to write to CR2.
+
+  @return The value written to CR2.
+
+**/
+UINTN
+EFIAPI
+AsmWriteCr2 (
+  UINTN  Cr2
+  );
+
+
+/**
+  Writes a value to Control Register 3 (CR3).
+
+  Writes and returns a new value to CR3. This function is only available on
+  IA-32 and x64. This writes a 32-bit value on IA-32 and a 64-bit value on x64.
+
+  @param  Cr3 The value to write to CR3.
+
+  @return The value written to CR3.
+
+**/
+UINTN
+EFIAPI
+AsmWriteCr3 (
+  UINTN  Cr3
+  );
+
+
+/**
+  Writes a value to Control Register 4 (CR4).
+
+  Writes and returns a new value to CR4. This function is only available on
+  IA-32 and x64. This writes a 32-bit value on IA-32 and a 64-bit value on x64.
+
+  @param  Cr4 The value to write to CR4.
+
+  @return The value written to CR4.
+
+**/
+UINTN
+EFIAPI
+AsmWriteCr4 (
+  UINTN  Cr4
+  );
+
+
+/**
+  Reads the current value of Debug Register 0 (DR0).
+
+  Reads and returns the current value of DR0. This function is only available
+  on IA-32 and x64. This returns a 32-bit value on IA-32 and a 64-bit value on
+  x64.
+
+  @return The value of Debug Register 0 (DR0).
+
+**/
+UINTN
+EFIAPI
+AsmReadDr0 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Debug Register 1 (DR1).
+
+  Reads and returns the current value of DR1. This function is only available
+  on IA-32 and x64. This returns a 32-bit value on IA-32 and a 64-bit value on
+  x64.
+
+  @return The value of Debug Register 1 (DR1).
+
+**/
+UINTN
+EFIAPI
+AsmReadDr1 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Debug Register 2 (DR2).
+
+  Reads and returns the current value of DR2. This function is only available
+  on IA-32 and x64. This returns a 32-bit value on IA-32 and a 64-bit value on
+  x64.
+
+  @return The value of Debug Register 2 (DR2).
+
+**/
+UINTN
+EFIAPI
+AsmReadDr2 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Debug Register 3 (DR3).
+
+  Reads and returns the current value of DR3. This function is only available
+  on IA-32 and x64. This returns a 32-bit value on IA-32 and a 64-bit value on
+  x64.
+
+  @return The value of Debug Register 3 (DR3).
+
+**/
+UINTN
+EFIAPI
+AsmReadDr3 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Debug Register 4 (DR4).
+
+  Reads and returns the current value of DR4. This function is only available
+  on IA-32 and x64. This returns a 32-bit value on IA-32 and a 64-bit value on
+  x64.
+
+  @return The value of Debug Register 4 (DR4).
+
+**/
+UINTN
+EFIAPI
+AsmReadDr4 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Debug Register 5 (DR5).
+
+  Reads and returns the current value of DR5. This function is only available
+  on IA-32 and x64. This returns a 32-bit value on IA-32 and a 64-bit value on
+  x64.
+
+  @return The value of Debug Register 5 (DR5).
+
+**/
+UINTN
+EFIAPI
+AsmReadDr5 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Debug Register 6 (DR6).
+
+  Reads and returns the current value of DR6. This function is only available
+  on IA-32 and x64. This returns a 32-bit value on IA-32 and a 64-bit value on
+  x64.
+
+  @return The value of Debug Register 6 (DR6).
+
+**/
+UINTN
+EFIAPI
+AsmReadDr6 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Debug Register 7 (DR7).
+
+  Reads and returns the current value of DR7. This function is only available
+  on IA-32 and x64. This returns a 32-bit value on IA-32 and a 64-bit value on
+  x64.
+
+  @return The value of Debug Register 7 (DR7).
+
+**/
+UINTN
+EFIAPI
+AsmReadDr7 (
+  VOID
+  );
+
+
+/**
+  Writes a value to Debug Register 0 (DR0).
+
+  Writes and returns a new value to DR0. This function is only available on
+  IA-32 and x64. This writes a 32-bit value on IA-32 and a 64-bit value on x64.
+
+  @param  Dr0 The value to write to Dr0.
+
+  @return The value written to Debug Register 0 (DR0).
+
+**/
+UINTN
+EFIAPI
+AsmWriteDr0 (
+  UINTN  Dr0
+  );
+
+
+/**
+  Writes a value to Debug Register 1 (DR1).
+
+  Writes and returns a new value to DR1. This function is only available on
+  IA-32 and x64. This writes a 32-bit value on IA-32 and a 64-bit value on x64.
+
+  @param  Dr1 The value to write to Dr1.
+
+  @return The value written to Debug Register 1 (DR1).
+
+**/
+UINTN
+EFIAPI
+AsmWriteDr1 (
+  UINTN  Dr1
+  );
+
+
+/**
+  Writes a value to Debug Register 2 (DR2).
+
+  Writes and returns a new value to DR2. This function is only available on
+  IA-32 and x64. This writes a 32-bit value on IA-32 and a 64-bit value on x64.
+
+  @param  Dr2 The value to write to Dr2.
+
+  @return The value written to Debug Register 2 (DR2).
+
+**/
+UINTN
+EFIAPI
+AsmWriteDr2 (
+  UINTN  Dr2
+  );
+
+
+/**
+  Writes a value to Debug Register 3 (DR3).
+
+  Writes and returns a new value to DR3. This function is only available on
+  IA-32 and x64. This writes a 32-bit value on IA-32 and a 64-bit value on x64.
+
+  @param  Dr3 The value to write to Dr3.
+
+  @return The value written to Debug Register 3 (DR3).
+
+**/
+UINTN
+EFIAPI
+AsmWriteDr3 (
+  UINTN  Dr3
+  );
+
+
+/**
+  Writes a value to Debug Register 4 (DR4).
+
+  Writes and returns a new value to DR4. This function is only available on
+  IA-32 and x64. This writes a 32-bit value on IA-32 and a 64-bit value on x64.
+
+  @param  Dr4 The value to write to Dr4.
+
+  @return The value written to Debug Register 4 (DR4).
+
+**/
+UINTN
+EFIAPI
+AsmWriteDr4 (
+  UINTN  Dr4
+  );
+
+
+/**
+  Writes a value to Debug Register 5 (DR5).
+
+  Writes and returns a new value to DR5. This function is only available on
+  IA-32 and x64. This writes a 32-bit value on IA-32 and a 64-bit value on x64.
+
+  @param  Dr5 The value to write to Dr5.
+
+  @return The value written to Debug Register 5 (DR5).
+
+**/
+UINTN
+EFIAPI
+AsmWriteDr5 (
+  UINTN  Dr5
+  );
+
+
+/**
+  Writes a value to Debug Register 6 (DR6).
+
+  Writes and returns a new value to DR6. This function is only available on
+  IA-32 and x64. This writes a 32-bit value on IA-32 and a 64-bit value on x64.
+
+  @param  Dr6 The value to write to Dr6.
+
+  @return The value written to Debug Register 6 (DR6).
+
+**/
+UINTN
+EFIAPI
+AsmWriteDr6 (
+  UINTN  Dr6
+  );
+
+
+/**
+  Writes a value to Debug Register 7 (DR7).
+
+  Writes and returns a new value to DR7. This function is only available on
+  IA-32 and x64. This writes a 32-bit value on IA-32 and a 64-bit value on x64.
+
+  @param  Dr7 The value to write to Dr7.
+
+  @return The value written to Debug Register 7 (DR7).
+
+**/
+UINTN
+EFIAPI
+AsmWriteDr7 (
+  UINTN  Dr7
+  );
+
+
+/**
+  Reads the current value of Code Segment Register (CS).
+
+  Reads and returns the current value of CS. This function is only available on
+  IA-32 and x64.
+
+  @return The current value of CS.
+
+**/
+UINT16
+EFIAPI
+AsmReadCs (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Data Segment Register (DS).
+
+  Reads and returns the current value of DS. This function is only available on
+  IA-32 and x64.
+
+  @return The current value of DS.
+
+**/
+UINT16
+EFIAPI
+AsmReadDs (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Extra Segment Register (ES).
+
+  Reads and returns the current value of ES. This function is only available on
+  IA-32 and x64.
+
+  @return The current value of ES.
+
+**/
+UINT16
+EFIAPI
+AsmReadEs (
+  VOID
+  );
+
+
+/**
+  Reads the current value of FS Data Segment Register (FS).
+
+  Reads and returns the current value of FS. This function is only available on
+  IA-32 and x64.
+
+  @return The current value of FS.
+
+**/
+UINT16
+EFIAPI
+AsmReadFs (
+  VOID
+  );
+
+
+/**
+  Reads the current value of GS Data Segment Register (GS).
+
+  Reads and returns the current value of GS. This function is only available on
+  IA-32 and x64.
+
+  @return The current value of GS.
+
+**/
+UINT16
+EFIAPI
+AsmReadGs (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Stack Segment Register (SS).
+
+  Reads and returns the current value of SS. This function is only available on
+  IA-32 and x64.
+
+  @return The current value of SS.
+
+**/
+UINT16
+EFIAPI
+AsmReadSs (
+  VOID
+  );
+
+
+/**
+  Reads the current value of Task Register (TR).
+
+  Reads and returns the current value of TR. This function is only available on
+  IA-32 and x64.
+
+  @return The current value of TR.
+
+**/
+UINT16
+EFIAPI
+AsmReadTr (
+  VOID
+  );
+
+
+/**
+  Reads the current Global Descriptor Table Register(GDTR) descriptor.
+
+  Reads and returns the current GDTR descriptor and returns it in Gdtr. This
+  function is only available on IA-32 and x64.
+
+  If Gdtr is NULL, then ASSERT().
+
+  @param  Gdtr  The pointer to a GDTR descriptor.
+
+**/
+VOID
+EFIAPI
+AsmReadGdtr (
+  OUT     IA32_DESCRIPTOR           *Gdtr
+  );
+
+
+/**
+  Writes the current Global Descriptor Table Register (GDTR) descriptor.
+
+  Writes and the current GDTR descriptor specified by Gdtr. This function is
+  only available on IA-32 and x64.
+
+  If Gdtr is NULL, then ASSERT().
+
+  @param  Gdtr  The pointer to a GDTR descriptor.
+
+**/
+VOID
+EFIAPI
+AsmWriteGdtr (
+  IN      CONST IA32_DESCRIPTOR     *Gdtr
+  );
+
+
+/**
+  Reads the current Interrupt Descriptor Table Register(IDTR) descriptor.
+
+  Reads and returns the current IDTR descriptor and returns it in Idtr. This
+  function is only available on IA-32 and x64.
+
+  If Idtr is NULL, then ASSERT().
+
+  @param  Idtr  The pointer to a IDTR descriptor.
+
+**/
+VOID
+EFIAPI
+AsmReadIdtr (
+  OUT     IA32_DESCRIPTOR           *Idtr
+  );
+
+
+/**
+  Writes the current Interrupt Descriptor Table Register(IDTR) descriptor.
+
+  Writes the current IDTR descriptor and returns it in Idtr. This function is
+  only available on IA-32 and x64.
+
+  If Idtr is NULL, then ASSERT().
+
+  @param  Idtr  The pointer to a IDTR descriptor.
+
+**/
+VOID
+EFIAPI
+AsmWriteIdtr (
+  IN      CONST IA32_DESCRIPTOR     *Idtr
+  );
+
+
+/**
+  Reads the current Local Descriptor Table Register(LDTR) selector.
+
+  Reads and returns the current 16-bit LDTR descriptor value. This function is
+  only available on IA-32 and x64.
+
+  @return The current selector of LDT.
+
+**/
+UINT16
+EFIAPI
+AsmReadLdtr (
+  VOID
+  );
+
+
+/**
+  Writes the current Local Descriptor Table Register (LDTR) selector.
+
+  Writes and the current LDTR descriptor specified by Ldtr. This function is
+  only available on IA-32 and x64.
+
+  @param  Ldtr  16-bit LDTR selector value.
+
+**/
+VOID
+EFIAPI
+AsmWriteLdtr (
+  IN      UINT16                    Ldtr
+  );
+
+
+/**
+  Save the current floating point/SSE/SSE2 context to a buffer.
+
+  Saves the current floating point/SSE/SSE2 state to the buffer specified by
+  Buffer. Buffer must be aligned on a 16-byte boundary. This function is only
+  available on IA-32 and x64.
+
+  If Buffer is NULL, then ASSERT().
+  If Buffer is not aligned on a 16-byte boundary, then ASSERT().
+
+  @param  Buffer  The pointer to a buffer to save the floating point/SSE/SSE2 context.
+
+**/
+VOID
+EFIAPI
+AsmFxSave (
+  OUT     IA32_FX_BUFFER            *Buffer
+  );
+
+
+/**
+  Restores the current floating point/SSE/SSE2 context from a buffer.
+
+  Restores the current floating point/SSE/SSE2 state from the buffer specified
+  by Buffer. Buffer must be aligned on a 16-byte boundary. This function is
+  only available on IA-32 and x64.
+
+  If Buffer is NULL, then ASSERT().
+  If Buffer is not aligned on a 16-byte boundary, then ASSERT().
+  If Buffer was not saved with AsmFxSave(), then ASSERT().
+
+  @param  Buffer  The pointer to a buffer to save the floating point/SSE/SSE2 context.
+
+**/
+VOID
+EFIAPI
+AsmFxRestore (
+  IN      CONST IA32_FX_BUFFER      *Buffer
+  );
+
+
+/**
+  Reads the current value of 64-bit MMX Register #0 (MM0).
+
+  Reads and returns the current value of MM0. This function is only available
+  on IA-32 and x64.
+
+  @return The current value of MM0.
+
+**/
+UINT64
+EFIAPI
+AsmReadMm0 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of 64-bit MMX Register #1 (MM1).
+
+  Reads and returns the current value of MM1. This function is only available
+  on IA-32 and x64.
+
+  @return The current value of MM1.
+
+**/
+UINT64
+EFIAPI
+AsmReadMm1 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of 64-bit MMX Register #2 (MM2).
+
+  Reads and returns the current value of MM2. This function is only available
+  on IA-32 and x64.
+
+  @return The current value of MM2.
+
+**/
+UINT64
+EFIAPI
+AsmReadMm2 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of 64-bit MMX Register #3 (MM3).
+
+  Reads and returns the current value of MM3. This function is only available
+  on IA-32 and x64.
+
+  @return The current value of MM3.
+
+**/
+UINT64
+EFIAPI
+AsmReadMm3 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of 64-bit MMX Register #4 (MM4).
+
+  Reads and returns the current value of MM4. This function is only available
+  on IA-32 and x64.
+
+  @return The current value of MM4.
+
+**/
+UINT64
+EFIAPI
+AsmReadMm4 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of 64-bit MMX Register #5 (MM5).
+
+  Reads and returns the current value of MM5. This function is only available
+  on IA-32 and x64.
+
+  @return The current value of MM5.
+
+**/
+UINT64
+EFIAPI
+AsmReadMm5 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of 64-bit MMX Register #6 (MM6).
+
+  Reads and returns the current value of MM6. This function is only available
+  on IA-32 and x64.
+
+  @return The current value of MM6.
+
+**/
+UINT64
+EFIAPI
+AsmReadMm6 (
+  VOID
+  );
+
+
+/**
+  Reads the current value of 64-bit MMX Register #7 (MM7).
+
+  Reads and returns the current value of MM7. This function is only available
+  on IA-32 and x64.
+
+  @return The current value of MM7.
+
+**/
+UINT64
+EFIAPI
+AsmReadMm7 (
+  VOID
+  );
+
+
+/**
+  Writes the current value of 64-bit MMX Register #0 (MM0).
+
+  Writes the current value of MM0. This function is only available on IA32 and
+  x64.
+
+  @param  Value The 64-bit value to write to MM0.
+
+**/
+VOID
+EFIAPI
+AsmWriteMm0 (
+  IN      UINT64                    Value
+  );
+
+
+/**
+  Writes the current value of 64-bit MMX Register #1 (MM1).
+
+  Writes the current value of MM1. This function is only available on IA32 and
+  x64.
+
+  @param  Value The 64-bit value to write to MM1.
+
+**/
+VOID
+EFIAPI
+AsmWriteMm1 (
+  IN      UINT64                    Value
+  );
+
+
+/**
+  Writes the current value of 64-bit MMX Register #2 (MM2).
+
+  Writes the current value of MM2. This function is only available on IA32 and
+  x64.
+
+  @param  Value The 64-bit value to write to MM2.
+
+**/
+VOID
+EFIAPI
+AsmWriteMm2 (
+  IN      UINT64                    Value
+  );
+
+
+/**
+  Writes the current value of 64-bit MMX Register #3 (MM3).
+
+  Writes the current value of MM3. This function is only available on IA32 and
+  x64.
+
+  @param  Value The 64-bit value to write to MM3.
+
+**/
+VOID
+EFIAPI
+AsmWriteMm3 (
+  IN      UINT64                    Value
+  );
+
+
+/**
+  Writes the current value of 64-bit MMX Register #4 (MM4).
+
+  Writes the current value of MM4. This function is only available on IA32 and
+  x64.
+
+  @param  Value The 64-bit value to write to MM4.
+
+**/
+VOID
+EFIAPI
+AsmWriteMm4 (
+  IN      UINT64                    Value
+  );
+
+
+/**
+  Writes the current value of 64-bit MMX Register #5 (MM5).
+
+  Writes the current value of MM5. This function is only available on IA32 and
+  x64.
+
+  @param  Value The 64-bit value to write to MM5.
+
+**/
+VOID
+EFIAPI
+AsmWriteMm5 (
+  IN      UINT64                    Value
+  );
+
+
+/**
+  Writes the current value of 64-bit MMX Register #6 (MM6).
+
+  Writes the current value of MM6. This function is only available on IA32 and
+  x64.
+
+  @param  Value The 64-bit value to write to MM6.
+
+**/
+VOID
+EFIAPI
+AsmWriteMm6 (
+  IN      UINT64                    Value
+  );
+
+
+/**
+  Writes the current value of 64-bit MMX Register #7 (MM7).
+
+  Writes the current value of MM7. This function is only available on IA32 and
+  x64.
+
+  @param  Value The 64-bit value to write to MM7.
+
+**/
+VOID
+EFIAPI
+AsmWriteMm7 (
+  IN      UINT64                    Value
+  );
+
+
+/**
+  Reads the current value of Time Stamp Counter (TSC).
+
+  Reads and returns the current value of TSC. This function is only available
+  on IA-32 and x64.
+
+  @return The current value of TSC
+
+**/
+UINT64
+EFIAPI
+AsmReadTsc (
+  VOID
+  );
+
+
+/**
+  Reads the current value of a Performance Counter (PMC).
+
+  Reads and returns the current value of performance counter specified by
+  Index. This function is only available on IA-32 and x64.
+
+  @param  Index The 32-bit Performance Counter index to read.
+
+  @return The value of the PMC specified by Index.
+
+**/
+UINT64
+EFIAPI
+AsmReadPmc (
+  IN      UINT32                    Index
+  );
+
+
+/**
+  Sets up a monitor buffer that is used by AsmMwait().
+
+  Executes a MONITOR instruction with the register state specified by Eax, Ecx
+  and Edx. Returns Eax. This function is only available on IA-32 and x64.
+
+  @param  Eax The value to load into EAX or RAX before executing the MONITOR
+              instruction.
+  @param  Ecx The value to load into ECX or RCX before executing the MONITOR
+              instruction.
+  @param  Edx The value to load into EDX or RDX before executing the MONITOR
+              instruction.
+
+  @return Eax
+
+**/
+UINTN
+EFIAPI
+AsmMonitor (
+  IN      UINTN                     Eax,
+  IN      UINTN                     Ecx,
+  IN      UINTN                     Edx
+  );
+
+
+/**
+  Executes an MWAIT instruction.
+
+  Executes an MWAIT instruction with the register state specified by Eax and
+  Ecx. Returns Eax. This function is only available on IA-32 and x64.
+
+  @param  Eax The value to load into EAX or RAX before executing the MONITOR
+              instruction.
+  @param  Ecx The value to load into ECX or RCX before executing the MONITOR
+              instruction.
+
+  @return Eax
+
+**/
+UINTN
+EFIAPI
+AsmMwait (
+  IN      UINTN                     Eax,
+  IN      UINTN                     Ecx
+  );
+
+
+/**
+  Executes a WBINVD instruction.
+
+  Executes a WBINVD instruction. This function is only available on IA-32 and
+  x64.
+
+**/
+VOID
+EFIAPI
+AsmWbinvd (
+  VOID
+  );
+
+
+/**
+  Executes a INVD instruction.
+
+  Executes a INVD instruction. This function is only available on IA-32 and
+  x64.
+
+**/
+VOID
+EFIAPI
+AsmInvd (
+  VOID
+  );
+
+
+/**
+  Flushes a cache line from all the instruction and data caches within the
+  coherency domain of the CPU.
+
+  Flushed the cache line specified by LinearAddress, and returns LinearAddress.
+  This function is only available on IA-32 and x64.
+
+  @param  LinearAddress The address of the cache line to flush. If the CPU is
+                        in a physical addressing mode, then LinearAddress is a
+                        physical address. If the CPU is in a virtual
+                        addressing mode, then LinearAddress is a virtual
+                        address.
+
+  @return LinearAddress.
+**/
+VOID *
+EFIAPI
+AsmFlushCacheLine (
+  IN      VOID                      *LinearAddress
+  );
+
+
+/**
+  Enables the 32-bit paging mode on the CPU.
+
+  Enables the 32-bit paging mode on the CPU. CR0, CR3, CR4, and the page tables
+  must be properly initialized prior to calling this service. This function
+  assumes the current execution mode is 32-bit protected mode. This function is
+  only available on IA-32. After the 32-bit paging mode is enabled, control is
+  transferred to the function specified by EntryPoint using the new stack
+  specified by NewStack and passing in the parameters specified by Context1 and
+  Context2. Context1 and Context2 are optional and may be NULL. The function
+  EntryPoint must never return.
+
+  If the current execution mode is not 32-bit protected mode, then ASSERT().
+  If EntryPoint is NULL, then ASSERT().
+  If NewStack is NULL, then ASSERT().
+
+  There are a number of constraints that must be followed before calling this
+  function:
+  1)  Interrupts must be disabled.
+  2)  The caller must be in 32-bit protected mode with flat descriptors. This
+      means all descriptors must have a base of 0 and a limit of 4GB.
+  3)  CR0 and CR4 must be compatible with 32-bit protected mode with flat
+      descriptors.
+  4)  CR3 must point to valid page tables that will be used once the transition
+      is complete, and those page tables must guarantee that the pages for this
+      function and the stack are identity mapped.
+
+  @param  EntryPoint  A pointer to function to call with the new stack after
+                      paging is enabled.
+  @param  Context1    A pointer to the context to pass into the EntryPoint
+                      function as the first parameter after paging is enabled.
+  @param  Context2    A pointer to the context to pass into the EntryPoint
+                      function as the second parameter after paging is enabled.
+  @param  NewStack    A pointer to the new stack to use for the EntryPoint
+                      function after paging is enabled.
+
+**/
+VOID
+EFIAPI
+AsmEnablePaging32 (
+  IN      SWITCH_STACK_ENTRY_POINT  EntryPoint,
+  IN      VOID                      *Context1,  OPTIONAL
+  IN      VOID                      *Context2,  OPTIONAL
+  IN      VOID                      *NewStack
+  );
+
+
+/**
+  Disables the 32-bit paging mode on the CPU.
+
+  Disables the 32-bit paging mode on the CPU and returns to 32-bit protected
+  mode. This function assumes the current execution mode is 32-paged protected
+  mode. This function is only available on IA-32. After the 32-bit paging mode
+  is disabled, control is transferred to the function specified by EntryPoint
+  using the new stack specified by NewStack and passing in the parameters
+  specified by Context1 and Context2. Context1 and Context2 are optional and
+  may be NULL. The function EntryPoint must never return.
+
+  If the current execution mode is not 32-bit paged mode, then ASSERT().
+  If EntryPoint is NULL, then ASSERT().
+  If NewStack is NULL, then ASSERT().
+
+  There are a number of constraints that must be followed before calling this
+  function:
+  1)  Interrupts must be disabled.
+  2)  The caller must be in 32-bit paged mode.
+  3)  CR0, CR3, and CR4 must be compatible with 32-bit paged mode.
+  4)  CR3 must point to valid page tables that guarantee that the pages for
+      this function and the stack are identity mapped.
+
+  @param  EntryPoint  A pointer to function to call with the new stack after
+                      paging is disabled.
+  @param  Context1    A pointer to the context to pass into the EntryPoint
+                      function as the first parameter after paging is disabled.
+  @param  Context2    A pointer to the context to pass into the EntryPoint
+                      function as the second parameter after paging is
+                      disabled.
+  @param  NewStack    A pointer to the new stack to use for the EntryPoint
+                      function after paging is disabled.
+
+**/
+VOID
+EFIAPI
+AsmDisablePaging32 (
+  IN      SWITCH_STACK_ENTRY_POINT  EntryPoint,
+  IN      VOID                      *Context1,  OPTIONAL
+  IN      VOID                      *Context2,  OPTIONAL
+  IN      VOID                      *NewStack
+  );
+
+
+/**
+  Enables the 64-bit paging mode on the CPU.
+
+  Enables the 64-bit paging mode on the CPU. CR0, CR3, CR4, and the page tables
+  must be properly initialized prior to calling this service. This function
+  assumes the current execution mode is 32-bit protected mode with flat
+  descriptors. This function is only available on IA-32. After the 64-bit
+  paging mode is enabled, control is transferred to the function specified by
+  EntryPoint using the new stack specified by NewStack and passing in the
+  parameters specified by Context1 and Context2. Context1 and Context2 are
+  optional and may be 0. The function EntryPoint must never return.
+
+  If the current execution mode is not 32-bit protected mode with flat
+  descriptors, then ASSERT().
+  If EntryPoint is 0, then ASSERT().
+  If NewStack is 0, then ASSERT().
+
+  @param  Cs          The 16-bit selector to load in the CS before EntryPoint
+                      is called. The descriptor in the GDT that this selector
+                      references must be setup for long mode.
+  @param  EntryPoint  The 64-bit virtual address of the function to call with
+                      the new stack after paging is enabled.
+  @param  Context1    The 64-bit virtual address of the context to pass into
+                      the EntryPoint function as the first parameter after
+                      paging is enabled.
+  @param  Context2    The 64-bit virtual address of the context to pass into
+                      the EntryPoint function as the second parameter after
+                      paging is enabled.
+  @param  NewStack    The 64-bit virtual address of the new stack to use for
+                      the EntryPoint function after paging is enabled.
+
+**/
+VOID
+EFIAPI
+AsmEnablePaging64 (
+  IN      UINT16                    Cs,
+  IN      UINT64                    EntryPoint,
+  IN      UINT64                    Context1,  OPTIONAL
+  IN      UINT64                    Context2,  OPTIONAL
+  IN      UINT64                    NewStack
+  );
+
+
+/**
+  Disables the 64-bit paging mode on the CPU.
+
+  Disables the 64-bit paging mode on the CPU and returns to 32-bit protected
+  mode. This function assumes the current execution mode is 64-paging mode.
+  This function is only available on x64. After the 64-bit paging mode is
+  disabled, control is transferred to the function specified by EntryPoint
+  using the new stack specified by NewStack and passing in the parameters
+  specified by Context1 and Context2. Context1 and Context2 are optional and
+  may be 0. The function EntryPoint must never return.
+
+  If the current execution mode is not 64-bit paged mode, then ASSERT().
+  If EntryPoint is 0, then ASSERT().
+  If NewStack is 0, then ASSERT().
+
+  @param  Cs          The 16-bit selector to load in the CS before EntryPoint
+                      is called. The descriptor in the GDT that this selector
+                      references must be setup for 32-bit protected mode.
+  @param  EntryPoint  The 64-bit virtual address of the function to call with
+                      the new stack after paging is disabled.
+  @param  Context1    The 64-bit virtual address of the context to pass into
+                      the EntryPoint function as the first parameter after
+                      paging is disabled.
+  @param  Context2    The 64-bit virtual address of the context to pass into
+                      the EntryPoint function as the second parameter after
+                      paging is disabled.
+  @param  NewStack    The 64-bit virtual address of the new stack to use for
+                      the EntryPoint function after paging is disabled.
+
+**/
+VOID
+EFIAPI
+AsmDisablePaging64 (
+  IN      UINT16                    Cs,
+  IN      UINT32                    EntryPoint,
+  IN      UINT32                    Context1,  OPTIONAL
+  IN      UINT32                    Context2,  OPTIONAL
+  IN      UINT32                    NewStack
+  );
+
+
+//
+// 16-bit thunking services
+//
+
+/**
+  Retrieves the properties for 16-bit thunk functions.
+
+  Computes the size of the buffer and stack below 1MB required to use the
+  AsmPrepareThunk16(), AsmThunk16() and AsmPrepareAndThunk16() functions. This
+  buffer size is returned in RealModeBufferSize, and the stack size is returned
+  in ExtraStackSize. If parameters are passed to the 16-bit real mode code,
+  then the actual minimum stack size is ExtraStackSize plus the maximum number
+  of bytes that need to be passed to the 16-bit real mode code.
+
+  If RealModeBufferSize is NULL, then ASSERT().
+  If ExtraStackSize is NULL, then ASSERT().
+
+  @param  RealModeBufferSize  A pointer to the size of the buffer below 1MB
+                              required to use the 16-bit thunk functions.
+  @param  ExtraStackSize      A pointer to the extra size of stack below 1MB
+                              that the 16-bit thunk functions require for
+                              temporary storage in the transition to and from
+                              16-bit real mode.
+
+**/
+VOID
+EFIAPI
+AsmGetThunk16Properties (
+  OUT     UINT32                    *RealModeBufferSize,
+  OUT     UINT32                    *ExtraStackSize
+  );
+
+
+/**
+  Prepares all structures a code required to use AsmThunk16().
+
+  Prepares all structures and code required to use AsmThunk16().
+
+  This interface is limited to be used in either physical mode or virtual modes with paging enabled where the
+  virtual to physical mappings for ThunkContext.RealModeBuffer is mapped 1:1.
+
+  If ThunkContext is NULL, then ASSERT().
+
+  @param  ThunkContext  A pointer to the context structure that describes the
+                        16-bit real mode code to call.
+
+**/
+VOID
+EFIAPI
+AsmPrepareThunk16 (
+  IN OUT  THUNK_CONTEXT             *ThunkContext
+  );
+
+
+/**
+  Transfers control to a 16-bit real mode entry point and returns the results.
+
+  Transfers control to a 16-bit real mode entry point and returns the results.
+  AsmPrepareThunk16() must be called with ThunkContext before this function is used.
+  This function must be called with interrupts disabled.
+
+  The register state from the RealModeState field of ThunkContext is restored just prior
+  to calling the 16-bit real mode entry point.  This includes the EFLAGS field of RealModeState,
+  which is used to set the interrupt state when a 16-bit real mode entry point is called.
+  Control is transferred to the 16-bit real mode entry point specified by the CS and Eip fields of RealModeState.
+  The stack is initialized to the SS and ESP fields of RealModeState.  Any parameters passed to
+  the 16-bit real mode code must be populated by the caller at SS:ESP prior to calling this function.
+  The 16-bit real mode entry point is invoked with a 16-bit CALL FAR instruction,
+  so when accessing stack contents, the 16-bit real mode code must account for the 16-bit segment
+  and 16-bit offset of the return address that were pushed onto the stack. The 16-bit real mode entry
+  point must exit with a RETF instruction. The register state is captured into RealModeState immediately
+  after the RETF instruction is executed.
+
+  If EFLAGS specifies interrupts enabled, or any of the 16-bit real mode code enables interrupts,
+  or any of the 16-bit real mode code makes a SW interrupt, then the caller is responsible for making sure
+  the IDT at address 0 is initialized to handle any HW or SW interrupts that may occur while in 16-bit real mode.
+
+  If EFLAGS specifies interrupts enabled, or any of the 16-bit real mode code enables interrupts,
+  then the caller is responsible for making sure the 8259 PIC is in a state compatible with 16-bit real mode.
+  This includes the base vectors, the interrupt masks, and the edge/level trigger mode.
+
+  If THUNK_ATTRIBUTE_BIG_REAL_MODE is set in the ThunkAttributes field of ThunkContext, then the user code
+  is invoked in big real mode.  Otherwise, the user code is invoked in 16-bit real mode with 64KB segment limits.
+
+  If neither THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 nor THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL are set in
+  ThunkAttributes, then it is assumed that the user code did not enable the A20 mask, and no attempt is made to
+  disable the A20 mask.
+
+  If THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 is set and THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL is clear in
+  ThunkAttributes, then attempt to use the INT 15 service to disable the A20 mask.  If this INT 15 call fails,
+  then attempt to disable the A20 mask by directly accessing the 8042 keyboard controller I/O ports.
+
+  If THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 is clear and THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL is set in
+  ThunkAttributes, then attempt to disable the A20 mask by directly accessing the 8042 keyboard controller I/O ports.
+
+  If ThunkContext is NULL, then ASSERT().
+  If AsmPrepareThunk16() was not previously called with ThunkContext, then ASSERT().
+  If both THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 and THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL are set in
+  ThunkAttributes, then ASSERT().
+
+  This interface is limited to be used in either physical mode or virtual modes with paging enabled where the
+  virtual to physical mappings for ThunkContext.RealModeBuffer are mapped 1:1.
+
+  @param  ThunkContext  A pointer to the context structure that describes the
+                        16-bit real mode code to call.
+
+**/
+VOID
+EFIAPI
+AsmThunk16 (
+  IN OUT  THUNK_CONTEXT             *ThunkContext
+  );
+
+
+/**
+  Prepares all structures and code for a 16-bit real mode thunk, transfers
+  control to a 16-bit real mode entry point, and returns the results.
+
+  Prepares all structures and code for a 16-bit real mode thunk, transfers
+  control to a 16-bit real mode entry point, and returns the results. If the
+  caller only need to perform a single 16-bit real mode thunk, then this
+  service should be used. If the caller intends to make more than one 16-bit
+  real mode thunk, then it is more efficient if AsmPrepareThunk16() is called
+  once and AsmThunk16() can be called for each 16-bit real mode thunk.
+
+  This interface is limited to be used in either physical mode or virtual modes with paging enabled where the
+  virtual to physical mappings for ThunkContext.RealModeBuffer is mapped 1:1.
+
+  See AsmPrepareThunk16() and AsmThunk16() for the detailed description and ASSERT() conditions.
+
+  @param  ThunkContext  A pointer to the context structure that describes the
+                        16-bit real mode code to call.
+
+**/
+VOID
+EFIAPI
+AsmPrepareAndThunk16 (
+  IN OUT  THUNK_CONTEXT             *ThunkContext
+  );
+
+#endif
+#endif
+
+
diff --git a/roms/ipxe/src/include/ipxe/efi/Pi/PiBootMode.h b/roms/ipxe/src/include/ipxe/efi/Pi/PiBootMode.h
index 30fd4437782b89ef9a9ce1e62137..f462f7aadfa437431ca249ff302f 100644
--- a/roms/ipxe/src/include/ipxe/efi/Pi/PiBootMode.h
+++ b/roms/ipxe/src/include/ipxe/efi/Pi/PiBootMode.h
@@ -1,7 +1,7 @@
 /** @file
   Present the boot mode values in PI.
 
-  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
   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
@@ -11,7 +11,7 @@
   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 
   @par Revision Reference:
-  PI Version 1.0
+  PI Version 1.2.1A
 
 **/
 
@@ -35,6 +35,7 @@ typedef UINT32  EFI_BOOT_MODE;
 #define BOOT_WITH_DEFAULT_SETTINGS                    0x04
 #define BOOT_ON_S4_RESUME                             0x05
 #define BOOT_ON_S5_RESUME                             0x06
+#define BOOT_WITH_MFG_MODE_SETTINGS                   0x07
 #define BOOT_ON_S2_RESUME                             0x10
 #define BOOT_ON_S3_RESUME                             0x11
 #define BOOT_ON_FLASH_UPDATE                          0x12
diff --git a/roms/ipxe/src/include/ipxe/efi/Pi/PiDxeCis.h b/roms/ipxe/src/include/ipxe/efi/Pi/PiDxeCis.h
index 6c4f44b900ce842fa3ddd2e3f589..e007cab83cf1be649f8a5c8455a0 100644
--- a/roms/ipxe/src/include/ipxe/efi/Pi/PiDxeCis.h
+++ b/roms/ipxe/src/include/ipxe/efi/Pi/PiDxeCis.h
@@ -1,7 +1,7 @@
 /** @file
   Include file matches things in PI.
 
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials are licensed and made available under
 the terms and conditions of the BSD License that accompanies this distribution.
 The full text of the license may be found at
@@ -11,7 +11,7 @@ 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:
-  PI Version 1.0
+  PI Version 1.2
 
 **/
 
@@ -371,7 +371,8 @@ EFI_STATUS
                                 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.
-
+  @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is
+                                not available yet.
 **/
 typedef
 EFI_STATUS
@@ -656,8 +657,10 @@ EFI_STATUS
 //
 // DXE Services Table
 //
-#define DXE_SERVICES_SIGNATURE  0x565245535f455844ULL
-#define DXE_SERVICES_REVISION   ((1<<16) | (00))
+#define DXE_SERVICES_SIGNATURE            0x565245535f455844ULL
+#define DXE_SPECIFICATION_MAJOR_REVISION  1
+#define DXE_SPECIFICATION_MINOR_REVISION  20
+#define DXE_SERVICES_REVISION             ((DXE_SPECIFICATION_MAJOR_REVISION<<16) | (DXE_SPECIFICATION_MINOR_REVISION))
 
 typedef struct {
   ///
diff --git a/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareFile.h b/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareFile.h
index 6909018bce50ce147f8cf4f03c6c..f6cf9574d544834ceb3dfcdab8f0 100644
--- a/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareFile.h
+++ b/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareFile.h
@@ -1,7 +1,7 @@
 /** @file
   The firmware file related definitions in PI.
 
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials are licensed and made available under
 the terms and conditions of the BSD License that accompanies this distribution.
 The full text of the license may be found at
@@ -36,8 +36,7 @@ typedef union {
     ///
     /// If the FFS_ATTRIB_CHECKSUM (see definition below) bit of the Attributes
     /// field is set to one, the IntegrityCheck.Checksum.File field is an 8-bit
-    /// checksum of the entire file The State field and the file tail are assumed to be zero
-    /// and the checksum is calculated such that the entire file sums to zero.
+    /// checksum of the file data.
     /// If the FFS_ATTRIB_CHECKSUM bit of the Attributes field is cleared to zero,
     /// the IntegrityCheck.Checksum.File field must be initialized with a value of
     /// 0xAA. The IntegrityCheck.Checksum.File field is valid any time the
@@ -176,9 +175,18 @@ typedef struct {
   /// If FFS_ATTRIB_LARGE_FILE is set in Attributes, then ExtendedSize exists and Size must be set to zero.
   /// If FFS_ATTRIB_LARGE_FILE is not set then EFI_FFS_FILE_HEADER is used.
   ///
-  EFI_FFS_FILE_STATE        ExtendedSize;
+  UINT32                    ExtendedSize;
 } EFI_FFS_FILE_HEADER2;
 
+#define IS_FFS_FILE2(FfsFileHeaderPtr) \
+    (((((EFI_FFS_FILE_HEADER *) (UINTN) FfsFileHeaderPtr)->Attributes) & FFS_ATTRIB_LARGE_FILE) == FFS_ATTRIB_LARGE_FILE)
+
+#define FFS_FILE_SIZE(FfsFileHeaderPtr) \
+    ((UINT32) (*((UINT32 *) ((EFI_FFS_FILE_HEADER *) (UINTN) FfsFileHeaderPtr)->Size) & 0x00ffffff))
+
+#define FFS_FILE2_SIZE(FfsFileHeaderPtr) \
+    (((EFI_FFS_FILE_HEADER2 *) (UINTN) FfsFileHeaderPtr)->ExtendedSize)
+
 typedef UINT8 EFI_SECTION_TYPE;
 
 ///
@@ -473,8 +481,14 @@ typedef struct {
   CHAR16                        VersionString[1];
 } EFI_VERSION_SECTION2;
 
+#define IS_SECTION2(SectionHeaderPtr) \
+    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff) == 0x00ffffff)
+
 #define SECTION_SIZE(SectionHeaderPtr) \
-    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) SectionHeaderPtr)->Size) & 0x00ffffff))
+    ((UINT32) (*((UINT32 *) ((EFI_COMMON_SECTION_HEADER *) (UINTN) SectionHeaderPtr)->Size) & 0x00ffffff))
+
+#define SECTION2_SIZE(SectionHeaderPtr) \
+    (((EFI_COMMON_SECTION_HEADER2 *) (UINTN) SectionHeaderPtr)->ExtendedSize)
 
 #pragma pack()
 
diff --git a/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareVolume.h b/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareVolume.h
index 813fab228e1c0ba370c1771b8610..4863e146d08a21cea99d7da7ef2f 100644
--- a/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareVolume.h
+++ b/roms/ipxe/src/include/ipxe/efi/Pi/PiFirmwareVolume.h
@@ -11,7 +11,7 @@
   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 
   @par Revision Reference:
-  PI Version 1.2B
+  PI Version 1.2C
 
 **/
 
@@ -75,7 +75,7 @@ typedef UINT32  EFI_FVB_ATTRIBUTES_2;
 #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_512K     0x00130000
 #define EFI_FVB2_ALIGNMENT_1M       0x00140000
 #define EFI_FVB2_ALIGNMENT_2M       0x00150000
 #define EFI_FVB2_ALIGNMENT_4M       0x00160000
@@ -207,13 +207,15 @@ typedef struct {
   ///
   /// An array of GUIDs, each GUID representing an OEM file type.
   ///
-  EFI_GUID  Types[1];
+  /// EFI_GUID  Types[1];
+  ///
 } EFI_FIRMWARE_VOLUME_EXT_ENTRY_OEM_TYPE;
 
 #define EFI_FV_EXT_TYPE_GUID_TYPE 0x0002
 
 ///
-/// This extension header provides a mapping between a GUID and an OEM file type.
+/// This extension header EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE provides a vendor specific
+/// GUID FormatType type which includes a length and a successive series of data bytes.
 ///
 typedef struct {
   ///
@@ -227,7 +229,8 @@ typedef struct {
   ///
   /// An arry of bytes of length Length.
   ///
-  UINT8                             Data[1];
+  /// UINT8                             Data[1];
+  ///
 } EFI_FIRMWARE_VOLUME_EXT_ENTRY_GUID_TYPE;
 
 #endif
diff --git a/roms/ipxe/src/include/ipxe/efi/Pi/PiHob.h b/roms/ipxe/src/include/ipxe/efi/Pi/PiHob.h
index cd196cb3018f0c21baf21f010157..c68ea3002c7be4c2d7a8334f27ae 100644
--- a/roms/ipxe/src/include/ipxe/efi/Pi/PiHob.h
+++ b/roms/ipxe/src/include/ipxe/efi/Pi/PiHob.h
@@ -1,7 +1,7 @@
 /** @file
   HOB related definitions in PI.
 
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials are licensed and made available under
 the terms and conditions of the BSD License that accompanies this distribution.
 The full text of the license may be found at
@@ -251,21 +251,21 @@ typedef UINT32 EFI_RESOURCE_ATTRIBUTE_TYPE;
 //
 // These types can be ORed together as needed.
 //
-// The first three enumerations describe settings
+// The following attributes are used to describe settings
 //
-#define EFI_RESOURCE_ATTRIBUTE_PRESENT              0x00000001
-#define EFI_RESOURCE_ATTRIBUTE_INITIALIZED          0x00000002
-#define EFI_RESOURCE_ATTRIBUTE_TESTED               0x00000004
+#define EFI_RESOURCE_ATTRIBUTE_PRESENT                  0x00000001
+#define EFI_RESOURCE_ATTRIBUTE_INITIALIZED              0x00000002
+#define EFI_RESOURCE_ATTRIBUTE_TESTED                   0x00000004
+#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED           0x00000080
+#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED          0x00000100
+#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED      0x00000200
 //
-// The rest of the settings describe capabilities
+// The rest of the attributes are used to 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
@@ -274,6 +274,9 @@ typedef UINT32 EFI_RESOURCE_ATTRIBUTE_TYPE;
 #define EFI_RESOURCE_ATTRIBUTE_32_BIT_IO                0x00008000
 #define EFI_RESOURCE_ATTRIBUTE_64_BIT_IO                0x00010000
 #define EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED        0x00020000
+#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE         0x00100000
+#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE        0x00200000
+#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE    0x00400000
 
 ///
 /// Describes the resource properties of all fixed,
diff --git a/roms/ipxe/src/include/ipxe/efi/Pi/PiStatusCode.h b/roms/ipxe/src/include/ipxe/efi/Pi/PiStatusCode.h
index 6133f00c4107a69c7210a5ee4139..4c720529ff1e9e19ee975e20e918 100644
--- a/roms/ipxe/src/include/ipxe/efi/Pi/PiStatusCode.h
+++ b/roms/ipxe/src/include/ipxe/efi/Pi/PiStatusCode.h
@@ -22,7 +22,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 FILE_LICENCE ( BSD3 );
 
 //
-// Required for IA32 and IPF defines for CPU exception types
+// Required for IA32, X64, IPF, ARM and EBC defines for CPU exception types
 //
 #include <ipxe/efi/Protocol/DebugSupport.h>
 
@@ -713,6 +713,9 @@ typedef struct {
 #define EFI_SOFTWARE_EFI_BOOT_SERVICE     (EFI_SOFTWARE | 0x00100000)
 #define EFI_SOFTWARE_EFI_RUNTIME_SERVICE  (EFI_SOFTWARE | 0x00110000)
 #define EFI_SOFTWARE_EFI_DXE_SERVICE      (EFI_SOFTWARE | 0x00120000)
+#define EFI_SOFTWARE_X64_EXCEPTION        (EFI_SOFTWARE | 0x00130000)
+#define EFI_SOFTWARE_ARM_EXCEPTION        (EFI_SOFTWARE | 0x00140000)
+
 ///@}
 
 ///
@@ -753,7 +756,6 @@ typedef struct {
 
 ///
 /// Software Class PEI Module Subclass Progress Code definitions.
-/// Note: EFI_SW_PEI_PC_RECOVERY_BEGIN is different from PI 1.2 Specification.
 ///
 ///@{
 #define EFI_SW_PEI_PC_RECOVERY_BEGIN  (EFI_SUBCLASS_SPECIFIC | 0x00000000)
@@ -808,6 +810,14 @@ typedef struct {
 #define EFI_SW_RT_PC_RETURN_TO_LAST   (EFI_SUBCLASS_SPECIFIC | 0x00000002)
 ///@}
 
+//
+// Software Class X64 Exception Subclass Progress Code definitions.
+//
+
+//
+// Software Class ARM Exception Subclass Progress Code definitions.
+//
+
 //
 // Software Class EBC Exception Subclass Progress Code definitions.
 //
@@ -987,7 +997,6 @@ typedef struct {
 
 ///
 /// Software Class PEI Module Subclass Error Code definitions.
-/// Note: EFI_SW_PEI_EC_INVALID_CAPSULE_DESCRIPTOR is different from PI 1.2 Specification.
 ///
 ///@{
 #define EFI_SW_PEI_EC_NO_RECOVERY_CAPSULE          (EFI_SUBCLASS_SPECIFIC | 0x00000000)
@@ -1123,8 +1132,65 @@ typedef struct {
 // Software Class EFI Runtime Service Subclass Error Code definitions.
 //
 
-//
-// Software Class EFI DXE Service Subclass Error Code definitions.
-//
+///
+/// Software Class EFI DXE Service Subclass Error Code definitions.
+///
+///@{
+#define EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS   (EFI_SUBCLASS_SPECIFIC | 0x00000005)
+#define EFI_SW_DXE_BS_PC_VERIFYING_PASSWORD         (EFI_SUBCLASS_SPECIFIC | 0x00000006)
+///@}
+
+///
+/// Software Class DXE RT Driver Subclass Progress Code definitions.
+///
+///@{
+#define EFI_SW_DXE_RT_PC_S0                         (EFI_SUBCLASS_SPECIFIC | 0x00000000)
+#define EFI_SW_DXE_RT_PC_S1                         (EFI_SUBCLASS_SPECIFIC | 0x00000001)
+#define EFI_SW_DXE_RT_PC_S2                         (EFI_SUBCLASS_SPECIFIC | 0x00000002)
+#define EFI_SW_DXE_RT_PC_S3                         (EFI_SUBCLASS_SPECIFIC | 0x00000003)
+#define EFI_SW_DXE_RT_PC_S4                         (EFI_SUBCLASS_SPECIFIC | 0x00000004)
+#define EFI_SW_DXE_RT_PC_S5                         (EFI_SUBCLASS_SPECIFIC | 0x00000005)
+///@}
+
+///
+/// Software Class X64 Exception Subclass Error Code definitions.
+/// These exceptions are derived from the debug protocol
+/// definitions in the EFI specification.
+///
+///@{
+#define EFI_SW_EC_X64_DIVIDE_ERROR                   EXCEPT_X64_DIVIDE_ERROR
+#define EFI_SW_EC_X64_DEBUG                          EXCEPT_X64_DEBUG
+#define EFI_SW_EC_X64_NMI                            EXCEPT_X64_NMI
+#define EFI_SW_EC_X64_BREAKPOINT                     EXCEPT_X64_BREAKPOINT
+#define EFI_SW_EC_X64_OVERFLOW                       EXCEPT_X64_OVERFLOW
+#define EFI_SW_EC_X64_BOUND                          EXCEPT_X64_BOUND
+#define EFI_SW_EC_X64_INVALID_OPCODE                 EXCEPT_X64_INVALID_OPCODE
+#define EFI_SW_EC_X64_DOUBLE_FAULT                   EXCEPT_X64_DOUBLE_FAULT
+#define EFI_SW_EC_X64_INVALID_TSS                    EXCEPT_X64_INVALID_TSS
+#define EFI_SW_EC_X64_SEG_NOT_PRESENT                EXCEPT_X64_SEG_NOT_PRESENT
+#define EFI_SW_EC_X64_STACK_FAULT                    EXCEPT_X64_STACK_FAULT
+#define EFI_SW_EC_X64_GP_FAULT                       EXCEPT_X64_GP_FAULT
+#define EFI_SW_EC_X64_PAGE_FAULT                     EXCEPT_X64_PAGE_FAULT
+#define EFI_SW_EC_X64_FP_ERROR                       EXCEPT_X64_FP_ERROR
+#define EFI_SW_EC_X64_ALIGNMENT_CHECK                EXCEPT_X64_ALIGNMENT_CHECK
+#define EFI_SW_EC_X64_MACHINE_CHECK                  EXCEPT_X64_MACHINE_CHECK
+#define EFI_SW_EC_X64_SIMD                           EXCEPT_X64_SIMD
+///@}
+
+///
+/// Software Class ARM Exception Subclass Error Code definitions.
+/// These exceptions are derived from the debug protocol
+/// definitions in the EFI specification.
+///
+///@{
+#define EFI_SW_EC_ARM_RESET                          EXCEPT_ARM_RESET
+#define EFI_SW_EC_ARM_UNDEFINED_INSTRUCTION          EXCEPT_ARM_UNDEFINED_INSTRUCTION
+#define EFI_SW_EC_ARM_SOFTWARE_INTERRUPT             EXCEPT_ARM_SOFTWARE_INTERRUPT
+#define EFI_SW_EC_ARM_PREFETCH_ABORT                 EXCEPT_ARM_PREFETCH_ABORT
+#define EFI_SW_EC_ARM_DATA_ABORT                     EXCEPT_ARM_DATA_ABORT
+#define EFI_SW_EC_ARM_RESERVED                       EXCEPT_ARM_RESERVED
+#define EFI_SW_EC_ARM_IRQ                            EXCEPT_ARM_IRQ
+#define EFI_SW_EC_ARM_FIQ                            EXCEPT_ARM_FIQ
+///@}
 
 #endif
diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/BlockIo.h b/roms/ipxe/src/include/ipxe/efi/Protocol/BlockIo.h
new file mode 100644
index 0000000000000000000000000000000000000000..f45154bb1032292b2c822e7e1fce700f22ce2dd2
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/efi/Protocol/BlockIo.h
@@ -0,0 +1,243 @@
+/** @file
+  Block IO protocol as defined in the UEFI 2.0 specification.
+
+  The Block IO protocol is used to abstract block devices like hard drives,
+  DVD-ROMs and floppy drives.
+
+  Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+  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 __BLOCK_IO_H__
+#define __BLOCK_IO_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_BLOCK_IO_PROTOCOL_GUID \
+  { \
+    0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+  }
+
+typedef struct _EFI_BLOCK_IO_PROTOCOL  EFI_BLOCK_IO_PROTOCOL;
+
+///
+/// Protocol GUID name defined in EFI1.1.
+///
+#define BLOCK_IO_PROTOCOL       EFI_BLOCK_IO_PROTOCOL_GUID
+
+///
+/// Protocol defined in EFI1.1.
+///
+typedef EFI_BLOCK_IO_PROTOCOL   EFI_BLOCK_IO;
+
+/**
+  Reset the Block Device.
+
+  @param  This                 Indicates a pointer to the calling context.
+  @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_BLOCK_RESET)(
+  IN EFI_BLOCK_IO_PROTOCOL          *This,
+  IN BOOLEAN                        ExtendedVerification
+  );
+
+/**
+  Read BufferSize bytes from Lba into Buffer.
+
+  @param  This       Indicates a pointer to the calling context.
+  @param  MediaId    Id of the media, changes every time the media is replaced.
+  @param  Lba        The starting Logical Block Address to read from
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.
+  @param  Buffer     A pointer to the destination buffer for the data. The caller is
+                     responsible for either having implicit or explicit ownership of the buffer.
+
+  @retval EFI_SUCCESS           The data was read correctly from the device.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
+  @retval EFI_NO_MEDIA          There is no media in the device.
+  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+                                or the buffer is not on proper alignment.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_BLOCK_READ)(
+  IN EFI_BLOCK_IO_PROTOCOL          *This,
+  IN UINT32                         MediaId,
+  IN EFI_LBA                        Lba,
+  IN UINTN                          BufferSize,
+  OUT VOID                          *Buffer
+  );
+
+/**
+  Write BufferSize bytes from Lba into Buffer.
+
+  @param  This       Indicates a pointer to the calling context.
+  @param  MediaId    The media ID that the write request is for.
+  @param  Lba        The starting logical block address to be written. The caller is
+                     responsible for writing to only legitimate locations.
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.
+  @param  Buffer     A pointer to the source buffer for the data.
+
+  @retval EFI_SUCCESS           The data was written correctly to the device.
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
+  @retval EFI_NO_MEDIA          There is no media in the device.
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+                                or the buffer is not on proper alignment.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_BLOCK_WRITE)(
+  IN EFI_BLOCK_IO_PROTOCOL          *This,
+  IN UINT32                         MediaId,
+  IN EFI_LBA                        Lba,
+  IN UINTN                          BufferSize,
+  IN VOID                           *Buffer
+  );
+
+/**
+  Flush the Block Device.
+
+  @param  This              Indicates a pointer to the calling context.
+
+  @retval EFI_SUCCESS       All outstanding data was written to the device
+  @retval EFI_DEVICE_ERROR  The device reported an error while writting back the data
+  @retval EFI_NO_MEDIA      There is no media in the device.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_BLOCK_FLUSH)(
+  IN EFI_BLOCK_IO_PROTOCOL  *This
+  );
+
+/**
+  Block IO read only mode data and updated only via members of BlockIO
+**/
+typedef struct {
+  ///
+  /// The curent media Id. If the media changes, this value is changed.
+  ///
+  UINT32  MediaId;
+
+  ///
+  /// TRUE if the media is removable; otherwise, FALSE.
+  ///
+  BOOLEAN RemovableMedia;
+
+  ///
+  /// TRUE if there is a media currently present in the device;
+  /// othersise, FALSE. THis field shows the media present status
+  /// as of the most recent ReadBlocks() or WriteBlocks() call.
+  ///
+  BOOLEAN MediaPresent;
+
+  ///
+  /// TRUE if LBA 0 is the first block of a partition; otherwise
+  /// FALSE. For media with only one partition this would be TRUE.
+  ///
+  BOOLEAN LogicalPartition;
+
+  ///
+  /// TRUE if the media is marked read-only otherwise, FALSE.
+  /// This field shows the read-only status as of the most recent WriteBlocks () call.
+  ///
+  BOOLEAN ReadOnly;
+
+  ///
+  /// TRUE if the WriteBlock () function caches write data.
+  ///
+  BOOLEAN WriteCaching;
+
+  ///
+  /// The intrinsic block size of the device. If the media changes, then
+  /// this field is updated.
+  ///
+  UINT32  BlockSize;
+
+  ///
+  /// Supplies the alignment requirement for any buffer to read or write block(s).
+  ///
+  UINT32  IoAlign;
+
+  ///
+  /// The last logical block address on the device.
+  /// If the media changes, then this field is updated.
+  ///
+  EFI_LBA LastBlock;
+
+  ///
+  /// Only present if EFI_BLOCK_IO_PROTOCOL.Revision is greater than or equal to
+  /// EFI_BLOCK_IO_PROTOCOL_REVISION2. Returns the first LBA is aligned to
+  /// a physical block boundary.
+  ///
+  EFI_LBA LowestAlignedLba;
+
+  ///
+  /// Only present if EFI_BLOCK_IO_PROTOCOL.Revision is greater than or equal to
+  /// EFI_BLOCK_IO_PROTOCOL_REVISION2. Returns the number of logical blocks
+  /// per physical block.
+  ///
+  UINT32 LogicalBlocksPerPhysicalBlock;
+
+  ///
+  /// Only present if EFI_BLOCK_IO_PROTOCOL.Revision is greater than or equal to
+  /// EFI_BLOCK_IO_PROTOCOL_REVISION3. Returns the optimal transfer length
+  /// granularity as a number of logical blocks.
+  ///
+  UINT32 OptimalTransferLengthGranularity;
+} EFI_BLOCK_IO_MEDIA;
+
+#define EFI_BLOCK_IO_PROTOCOL_REVISION  0x00010000
+#define EFI_BLOCK_IO_PROTOCOL_REVISION2 0x00020001
+#define EFI_BLOCK_IO_PROTOCOL_REVISION3 0x00020031
+
+///
+/// Revision defined in EFI1.1.
+///
+#define EFI_BLOCK_IO_INTERFACE_REVISION   EFI_BLOCK_IO_PROTOCOL_REVISION
+
+///
+///  This protocol provides control over block devices.
+///
+struct _EFI_BLOCK_IO_PROTOCOL {
+  ///
+  /// The revision to which the block IO interface adheres. All future
+  /// revisions must be backwards compatible. If a future version is not
+  /// back wards compatible, it is not the same GUID.
+  ///
+  UINT64              Revision;
+  ///
+  /// Pointer to the EFI_BLOCK_IO_MEDIA data for this device.
+  ///
+  EFI_BLOCK_IO_MEDIA  *Media;
+
+  EFI_BLOCK_RESET     Reset;
+  EFI_BLOCK_READ      ReadBlocks;
+  EFI_BLOCK_WRITE     WriteBlocks;
+  EFI_BLOCK_FLUSH     FlushBlocks;
+
+};
+
+extern EFI_GUID gEfiBlockIoProtocolGuid;
+
+#endif
diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/ComponentName2.h b/roms/ipxe/src/include/ipxe/efi/Protocol/ComponentName2.h
index 978ede5ab67067431bcca8c168dd..82d8b2561c002c5136295c049709 100644
--- a/roms/ipxe/src/include/ipxe/efi/Protocol/ComponentName2.h
+++ b/roms/ipxe/src/include/ipxe/efi/Protocol/ComponentName2.h
@@ -3,7 +3,7 @@
   This protocol is used to retrieve user readable names of drivers
   and controllers managed by UEFI Drivers.
 
-  Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
   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
@@ -121,8 +121,7 @@ EFI_STATUS
                                 driver specified by This was
                                 returned in DriverName.
 
-  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid
-                                EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
 
   @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it
                                 is not a valid EFI_HANDLE.
diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/Cpu.h b/roms/ipxe/src/include/ipxe/efi/Protocol/Cpu.h
index ebcaf5f10d3cd0ef898deaea8388..665924e88088791e49ded76db7a0 100644
--- a/roms/ipxe/src/include/ipxe/efi/Protocol/Cpu.h
+++ b/roms/ipxe/src/include/ipxe/efi/Protocol/Cpu.h
@@ -3,7 +3,7 @@
 
   This code abstracts the DXE core from processor implementation details.
 
-  Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
   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
@@ -246,6 +246,8 @@ EFI_STATUS
   @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.
+                                Attributes specified an illegal combination of attributes that
+                                cannot be set together.
   @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
diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePath.h b/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePath.h
index 5c6787080787b9c5cb2b3fcedf92..cc4c927df79c10cca676e39bf869 100644
--- a/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePath.h
+++ b/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePath.h
@@ -5,7 +5,7 @@
   from a software point of view. The path 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 - 2010, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials are licensed and made available under
 the terms and conditions of the BSD License that accompanies this distribution.
 The full text of the license may be found at
@@ -348,6 +348,26 @@ typedef struct {
   UINT64                          Lun;
 } FIBRECHANNEL_DEVICE_PATH;
 
+///
+/// Fibre Channel Ex SubType.
+///
+#define MSG_FIBRECHANNELEX_DP     0x15
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// Reserved for the future.
+  ///
+  UINT32                          Reserved;
+  ///
+  /// 8 byte array containing Fibre Channel End Device Port Name.
+  ///
+  UINT8                           WWN[8];
+  ///
+  /// 8 byte array containing Fibre Channel Logical Unit Number.
+  ///
+  UINT8                           Lun[8];
+} FIBRECHANNELEX_DEVICE_PATH;
+
 ///
 /// 1394 Device Path SubType
 ///
@@ -543,6 +563,14 @@ typedef struct {
   /// 0x01 - The Source IP Address is statically bound.
   ///
   BOOLEAN                         StaticIpAddress;
+  ///
+  /// The gateway IP address
+  ///
+  EFI_IPv4_ADDRESS                GatewayIpAddress;
+  ///
+  /// The subnet mask
+  ///
+  EFI_IPv4_ADDRESS                SubnetMask;
 } IPv4_DEVICE_PATH;
 
 ///
@@ -572,10 +600,21 @@ typedef struct {
   ///
   UINT16                          Protocol;
   ///
-  /// 0x00 - The Source IP Address was assigned though DHCP.
-  /// 0x01 - The Source IP Address is statically bound.
+  /// 0x00 - The Local IP Address was manually configured.
+  /// 0x01 - The Local IP Address is assigned through IPv6
+  /// stateless auto-configuration.
+  /// 0x02 - The Local IP Address is assigned through IPv6
+  /// stateful configuration.
   ///
-  BOOLEAN                         StaticIpAddress;
+  UINT8                           IpAddressOrigin;
+  ///
+  /// The prefix length
+  ///
+  UINT8                           PrefixLength;
+  ///
+  /// The gateway IP address
+  ///
+  EFI_IPv6_ADDRESS                GatewayIpAddress;
 } IPv6_DEVICE_PATH;
 
 ///
@@ -692,9 +731,9 @@ typedef struct {
 #define UART_FLOW_CONTROL_HARDWARE         0x00000001
 #define UART_FLOW_CONTROL_XON_XOFF         0x00000010
 
-#define DEVICE_PATH_MESSAGING_SAS                 EFI_SAS_DEVICE_PATH_GUID
+#define DEVICE_PATH_MESSAGING_SAS          EFI_SAS_DEVICE_PATH_GUID
 ///
-/// Serial Attached SCSI (SAS) devices.
+/// Serial Attached SCSI (SAS) Device Path.
 ///
 typedef struct {
   EFI_DEVICE_PATH_PROTOCOL        Header;
@@ -724,6 +763,30 @@ typedef struct {
   UINT16                          RelativeTargetPort;
 } SAS_DEVICE_PATH;
 
+///
+/// Serial Attached SCSI (SAS) Ex Device Path SubType
+///
+#define MSG_SASEX_DP              0x16
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL        Header;
+  ///
+  /// 8-byte array of the SAS Address for Serial Attached SCSI Target Port.
+  ///
+  UINT8                           SasAddress[8];
+  ///
+  /// 8-byte array of the SAS Logical Unit Number.
+  ///
+  UINT8                           Lun[8];
+  ///
+  /// More Information about the device and its interconnect.
+  ///
+  UINT16                          DeviceTopology;
+  ///
+  /// Relative Target Port (RTP).
+  ///
+  UINT16                          RelativeTargetPort;
+} SASEX_DEVICE_PATH;
+
 ///
 /// iSCSI Device Path SubType
 ///
@@ -897,7 +960,7 @@ typedef struct {
 } MEDIA_PROTOCOL_DEVICE_PATH;
 
 ///
-/// PIWG Firmware Volume Device Path SubType.
+/// PIWG Firmware File SubType.
 ///
 #define MEDIA_PIWG_FW_FILE_DP     0x06
 
@@ -967,7 +1030,7 @@ typedef struct {
   ///
   UINT16                          StatusFlag;
   ///
-  /// ASCIIZ string that describes the boot device to a user.
+  /// Null-terminated ASCII string that describes the boot device to a user.
   ///
   CHAR8                           String[1];
 } BBS_BBS_DEVICE_PATH;
@@ -989,78 +1052,100 @@ typedef struct {
 /// 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;
-  MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH Offset;
-
-  BBS_BBS_DEVICE_PATH                  Bbs;
+  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;
+  ACPI_ADR_DEVICE_PATH                       AcpiAdr;
+
+  ATAPI_DEVICE_PATH                          Atapi;
+  SCSI_DEVICE_PATH                           Scsi;
+  ISCSI_DEVICE_PATH                          Iscsi;
+  FIBRECHANNEL_DEVICE_PATH                   FibreChannel;
+  FIBRECHANNELEX_DEVICE_PATH                 FibreChannelEx;
+
+  F1394_DEVICE_PATH                          F1394;
+  USB_DEVICE_PATH                            Usb;
+  SATA_DEVICE_PATH                           Sata;
+  USB_CLASS_DEVICE_PATH                      UsbClass;
+  USB_WWID_DEVICE_PATH                       UsbWwid;
+  DEVICE_LOGICAL_UNIT_DEVICE_PATH            LogicUnit;
+  I2O_DEVICE_PATH                            I2O;
+  MAC_ADDR_DEVICE_PATH                       MacAddr;
+  IPv4_DEVICE_PATH                           Ipv4;
+  IPv6_DEVICE_PATH                           Ipv6;
+  VLAN_DEVICE_PATH                           Vlan;
+  INFINIBAND_DEVICE_PATH                     InfiniBand;
+  UART_DEVICE_PATH                           Uart;
+  UART_FLOW_CONTROL_DEVICE_PATH              UartFlowControl;
+  SAS_DEVICE_PATH                            Sas;
+  SASEX_DEVICE_PATH                          SasEx;
+  HARDDRIVE_DEVICE_PATH                      HardDrive;
+  CDROM_DEVICE_PATH                          CD;
+
+  FILEPATH_DEVICE_PATH                       FilePath;
+  MEDIA_PROTOCOL_DEVICE_PATH                 MediaProtocol;
+
+  MEDIA_FW_VOL_DEVICE_PATH                   FirmwareVolume;
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH          FirmwareFile;
+  MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH    Offset;
+
+  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;
-  MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *Offset;
-
-  BBS_BBS_DEVICE_PATH                  *Bbs;
-  UINT8                                *Raw;
+  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;
+  ACPI_ADR_DEVICE_PATH                       *AcpiAdr;
+
+  ATAPI_DEVICE_PATH                          *Atapi;
+  SCSI_DEVICE_PATH                           *Scsi;
+  ISCSI_DEVICE_PATH                          *Iscsi;
+  FIBRECHANNEL_DEVICE_PATH                   *FibreChannel;
+  FIBRECHANNELEX_DEVICE_PATH                 *FibreChannelEx;
+
+  F1394_DEVICE_PATH                          *F1394;
+  USB_DEVICE_PATH                            *Usb;
+  SATA_DEVICE_PATH                           *Sata;
+  USB_CLASS_DEVICE_PATH                      *UsbClass;
+  USB_WWID_DEVICE_PATH                       *UsbWwid;
+  DEVICE_LOGICAL_UNIT_DEVICE_PATH            *LogicUnit;
+  I2O_DEVICE_PATH                            *I2O;
+  MAC_ADDR_DEVICE_PATH                       *MacAddr;
+  IPv4_DEVICE_PATH                           *Ipv4;
+  IPv6_DEVICE_PATH                           *Ipv6;
+  VLAN_DEVICE_PATH                           *Vlan;
+  INFINIBAND_DEVICE_PATH                     *InfiniBand;
+  UART_DEVICE_PATH                           *Uart;
+  UART_FLOW_CONTROL_DEVICE_PATH              *UartFlowControl;
+  SAS_DEVICE_PATH                            *Sas;
+  SASEX_DEVICE_PATH                          *SasEx;
+  HARDDRIVE_DEVICE_PATH                      *HardDrive;
+  CDROM_DEVICE_PATH                          *CD;
+
+  FILEPATH_DEVICE_PATH                       *FilePath;
+  MEDIA_PROTOCOL_DEVICE_PATH                 *MediaProtocol;
+
+  MEDIA_FW_VOL_DEVICE_PATH                   *FirmwareVolume;
+  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH          *FirmwareFile;
+  MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH    *Offset;
+
+  BBS_BBS_DEVICE_PATH                        *Bbs;
+  UINT8                                      *Raw;
 } EFI_DEV_PATH_PTR;
 
 #pragma pack()
diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePathToText.h b/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePathToText.h
new file mode 100644
index 0000000000000000000000000000000000000000..edca965bca46fa1630ee993408d99052472d36b9
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/efi/Protocol/DevicePathToText.h
@@ -0,0 +1,87 @@
+/** @file
+  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL as defined in UEFI 2.0.
+  This protocol provides service to convert device nodes and paths to text.
+
+  Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+  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 __DEVICE_PATH_TO_TEXT_PROTOCOL_H__
+#define __DEVICE_PATH_TO_TEXT_PROTOCOL_H__
+
+FILE_LICENCE ( BSD3 );
+
+///
+/// Device Path To Text protocol
+///
+#define EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \
+  { \
+    0x8b843e20, 0x8132, 0x4852, {0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c } \
+  }
+
+/**
+  Convert a device node to its text representation.
+
+  @param  DeviceNode     Points to the device node to be converted.
+  @param  DisplayOnly    If DisplayOnly is TRUE, then the shorter text representation
+                         of the display node is used, where applicable. If DisplayOnly
+                         is FALSE, then the longer text representation of the display node
+                         is used.
+  @param  AllowShortcuts If AllowShortcuts is TRUE, then the shortcut forms of text
+                         representation for a device node can be used, where applicable.
+
+  @retval a_pointer      a pointer to the allocated text representation of the device node data
+  @retval NULL           if DeviceNode is NULL or there was insufficient memory.
+
+**/
+typedef
+CHAR16*
+(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_NODE)(
+  IN CONST EFI_DEVICE_PATH_PROTOCOL   *DeviceNode,
+  IN BOOLEAN                          DisplayOnly,
+  IN BOOLEAN                          AllowShortcuts
+  );
+
+/**
+  Convert a device path to its text representation.
+
+  @param  DevicePath     Points to the device path to be converted.
+  @param  DisplayOnly    If DisplayOnly is TRUE, then the shorter text representation
+                         of the display node is used, where applicable. If DisplayOnly
+                         is FALSE, then the longer text representation of the display node
+                         is used.
+  @param  AllowShortcuts The AllowShortcuts is FALSE, then the shortcut forms of
+                         text representation for a device node cannot be used.
+
+  @retval a_pointer      a pointer to the allocated text representation of the device node.
+  @retval NULL           if DevicePath is NULL or there was insufficient memory.
+
+**/
+typedef
+CHAR16*
+(EFIAPI *EFI_DEVICE_PATH_TO_TEXT_PATH)(
+  IN CONST EFI_DEVICE_PATH_PROTOCOL   *DevicePath,
+  IN BOOLEAN                          DisplayOnly,
+  IN BOOLEAN                          AllowShortcuts
+  );
+
+///
+/// This protocol converts device paths and device nodes to text.
+///
+typedef struct {
+  EFI_DEVICE_PATH_TO_TEXT_NODE        ConvertDeviceNodeToText;
+  EFI_DEVICE_PATH_TO_TEXT_PATH        ConvertDevicePathToText;
+} EFI_DEVICE_PATH_TO_TEXT_PROTOCOL;
+
+extern EFI_GUID gEfiDevicePathToTextProtocolGuid;
+
+#endif
+
+
diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/FormBrowser2.h b/roms/ipxe/src/include/ipxe/efi/Protocol/FormBrowser2.h
index 6befec63a10b620cae24e921b6d0..12873c31fddf7fb52f068aed69ba 100644
--- a/roms/ipxe/src/include/ipxe/efi/Protocol/FormBrowser2.h
+++ b/roms/ipxe/src/include/ipxe/efi/Protocol/FormBrowser2.h
@@ -61,6 +61,10 @@ typedef UINTN EFI_BROWSER_ACTION_REQUEST;
 #define EFI_BROWSER_ACTION_REQUEST_RESET  1
 #define EFI_BROWSER_ACTION_REQUEST_SUBMIT 2
 #define EFI_BROWSER_ACTION_REQUEST_EXIT   3
+#define EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT  4
+#define EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT 5
+#define EFI_BROWSER_ACTION_REQUEST_FORM_APPLY        6
+#define EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD      7
 
 
 /**
diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/HiiConfigAccess.h b/roms/ipxe/src/include/ipxe/efi/Protocol/HiiConfigAccess.h
index 2bef5cbc856c0d82ecac8876ed5e..929d9cd28a2a467fe613145453e4 100644
--- a/roms/ipxe/src/include/ipxe/efi/Protocol/HiiConfigAccess.h
+++ b/roms/ipxe/src/include/ipxe/efi/Protocol/HiiConfigAccess.h
@@ -36,6 +36,12 @@ typedef UINTN EFI_BROWSER_ACTION;
 #define EFI_BROWSER_ACTION_RETRIEVE   2
 #define EFI_BROWSER_ACTION_FORM_OPEN  3
 #define EFI_BROWSER_ACTION_FORM_CLOSE 4
+#define EFI_BROWSER_ACTION_DEFAULT_STANDARD      0x1000
+#define EFI_BROWSER_ACTION_DEFAULT_MANUFACTURING 0x1001
+#define EFI_BROWSER_ACTION_DEFAULT_SAFE          0x1002
+#define EFI_BROWSER_ACTION_DEFAULT_PLATFORM      0x2000
+#define EFI_BROWSER_ACTION_DEFAULT_HARDWARE      0x3000
+#define EFI_BROWSER_ACTION_DEFAULT_FIRMWARE      0x4000
 
 /**
 
diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/LoadFile.h b/roms/ipxe/src/include/ipxe/efi/Protocol/LoadFile.h
new file mode 100644
index 0000000000000000000000000000000000000000..99387e89fdd2d9993caf01b06bd57195b835ecc1
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/efi/Protocol/LoadFile.h
@@ -0,0 +1,90 @@
+/** @file
+  Load File protocol as defined in the UEFI 2.0 specification.
+
+  The load file protocol exists to supports the addition of new boot devices,
+  and to support booting from devices that do not map well to file system.
+  Network boot is done via a LoadFile protocol.
+
+  UEFI 2.0 can boot from any device that produces a LoadFile protocol.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that 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_LOAD_FILE_PROTOCOL_H__
+#define __EFI_LOAD_FILE_PROTOCOL_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_LOAD_FILE_PROTOCOL_GUID \
+  { \
+    0x56EC3091, 0x954C, 0x11d2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B } \
+  }
+
+///
+/// Protocol Guid defined by EFI1.1.
+///
+#define LOAD_FILE_PROTOCOL EFI_LOAD_FILE_PROTOCOL_GUID
+
+typedef struct _EFI_LOAD_FILE_PROTOCOL EFI_LOAD_FILE_PROTOCOL;
+
+///
+/// Backward-compatible with EFI1.1
+///
+typedef EFI_LOAD_FILE_PROTOCOL  EFI_LOAD_FILE_INTERFACE;
+
+/**
+  Causes the driver to load a specified file.
+
+  @param  This       Protocol instance pointer.
+  @param  FilePath   The device specific path of the file to load.
+  @param  BootPolicy If TRUE, indicates that the request originates from the
+                     boot manager is attempting to load FilePath as a boot
+                     selection. If FALSE, then FilePath must match as exact file
+                     to be loaded.
+  @param  BufferSize On input the size of Buffer in bytes. On output with a return
+                     code of EFI_SUCCESS, the amount of data transferred to
+                     Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
+                     the size of Buffer required to retrieve the requested file.
+  @param  Buffer     The memory buffer to transfer the file to. IF Buffer is NULL,
+                     then the size of the requested file is returned in
+                     BufferSize.
+
+  @retval EFI_SUCCESS           The file was loaded.
+  @retval EFI_UNSUPPORTED       The device does not support the provided BootPolicy
+  @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or
+                                BufferSize is NULL.
+  @retval EFI_NO_MEDIA          No medium was present to load the file.
+  @retval EFI_DEVICE_ERROR      The file was not loaded due to a device error.
+  @retval EFI_NO_RESPONSE       The remote system did not respond.
+  @retval EFI_NOT_FOUND         The file was not found.
+  @retval EFI_ABORTED           The file load process was manually cancelled.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_LOAD_FILE)(
+  IN EFI_LOAD_FILE_PROTOCOL           *This,
+  IN EFI_DEVICE_PATH_PROTOCOL         *FilePath,
+  IN BOOLEAN                          BootPolicy,
+  IN OUT UINTN                        *BufferSize,
+  IN VOID                             *Buffer OPTIONAL
+  );
+
+///
+/// The EFI_LOAD_FILE_PROTOCOL is a simple protocol used to obtain files from arbitrary devices.
+///
+struct _EFI_LOAD_FILE_PROTOCOL {
+  EFI_LOAD_FILE LoadFile;
+};
+
+extern EFI_GUID gEfiLoadFileProtocolGuid;
+
+#endif
diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/NetworkInterfaceIdentifier.h b/roms/ipxe/src/include/ipxe/efi/Protocol/NetworkInterfaceIdentifier.h
index ac86e972ee61f3c2181d7dc83fa5..29319069f409c3d4c5fcdfa92969 100644
--- a/roms/ipxe/src/include/ipxe/efi/Protocol/NetworkInterfaceIdentifier.h
+++ b/roms/ipxe/src/include/ipxe/efi/Protocol/NetworkInterfaceIdentifier.h
@@ -1,7 +1,7 @@
 /** @file
   EFI Network Interface Identifier Protocol.
 
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials are licensed and made available under
 the terms and conditions of the BSD License that accompanies this distribution.
 The full text of the license may be found at
@@ -87,6 +87,29 @@ typedef enum {
   EfiNetworkInterfaceUndi = 1
 } EFI_NETWORK_INTERFACE_TYPE;
 
+///
+/// Forward reference for pure ANSI compatability.
+///
+typedef struct undiconfig_table  UNDI_CONFIG_TABLE;
+
+///
+/// The format of the configuration table for UNDI
+///
+struct undiconfig_table {
+  UINT32             NumberOfInterfaces;    ///< The number of NIC devices
+                                            ///< that this UNDI controls.
+  UINT32             reserved;
+  UNDI_CONFIG_TABLE  *nextlink;             ///< A pointer to the next UNDI
+                                            ///< configuration table.
+  ///
+  /// The length of this array is given in the NumberOfInterfaces field.
+  ///
+  struct {
+    VOID             *NII_InterfacePointer; ///< Pointer to the NII interface structure.
+    VOID             *DevicePathPointer;    ///< Pointer to the device path for this NIC.
+  } NII_entry[1];
+};
+
 extern EFI_GUID gEfiNetworkInterfaceIdentifierProtocolGuid;
 extern EFI_GUID gEfiNetworkInterfaceIdentifierProtocolGuid_31;
 
diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/PciRootBridgeIo.h b/roms/ipxe/src/include/ipxe/efi/Protocol/PciRootBridgeIo.h
index e8feea0c44b6b76c922c51047760..b9c80f589a6a2e72edd1885d7c3d 100644
--- a/roms/ipxe/src/include/ipxe/efi/Protocol/PciRootBridgeIo.h
+++ b/roms/ipxe/src/include/ipxe/efi/Protocol/PciRootBridgeIo.h
@@ -5,7 +5,7 @@
   and PCI Configuration cycles on a PCI Root Bridge. It also provides services to perform
   defferent types of bus mastering DMA.
 
-  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
   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
@@ -21,6 +21,8 @@
 
 FILE_LICENCE ( BSD3 );
 
+#include <ipxe/efi/Library/BaseLib.h>
+
 #define EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID \
   { \
     0x2f707ebb, 0x4a1a, 0x11d4, {0x9a, 0x38, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
@@ -108,7 +110,11 @@ typedef enum {
 #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)))
+  (UINT64) ( \
+  (((UINTN) bus) << 24) | \
+  (((UINTN) dev) << 16) | \
+  (((UINTN) func) << 8) | \
+  (((UINTN) (reg)) < 256 ? ((UINTN) (reg)) : (UINT64) (LShiftU64 ((UINT64) (reg), 32))))
 
 typedef struct {
   UINT8   Register;
diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleFileSystem.h b/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleFileSystem.h
new file mode 100644
index 0000000000000000000000000000000000000000..1981808646d9afa868ed1c56047eb243f51dfdc2
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleFileSystem.h
@@ -0,0 +1,403 @@
+/** @file
+  SimpleFileSystem protocol as defined in the UEFI 2.0 specification.
+
+  The SimpleFileSystem protocol is the programmatic access to the FAT (12,16,32)
+  file system specified in UEFI 2.0. It can also be used to abstract a file
+  system other than FAT.
+
+  UEFI 2.0 can boot from any valid EFI image contained in a SimpleFileSystem.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that 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_FILE_SYSTEM_H__
+#define __SIMPLE_FILE_SYSTEM_H__
+
+FILE_LICENCE ( BSD3 );
+
+#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \
+  { \
+    0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
+  }
+
+typedef struct _EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL;
+
+typedef struct _EFI_FILE_PROTOCOL         EFI_FILE_PROTOCOL;
+typedef struct _EFI_FILE_PROTOCOL         *EFI_FILE_HANDLE;
+
+///
+/// Protocol GUID name defined in EFI1.1.
+///
+#define SIMPLE_FILE_SYSTEM_PROTOCOL       EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID
+
+///
+/// Protocol name defined in EFI1.1.
+///
+typedef EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   EFI_FILE_IO_INTERFACE;
+typedef EFI_FILE_PROTOCOL                 EFI_FILE;
+
+/**
+  Open the root directory on a volume.
+
+  @param  This A pointer to the volume to open the root directory.
+  @param  Root A pointer to the location to return the opened file handle for the
+               root directory.
+
+  @retval EFI_SUCCESS          The device was opened.
+  @retval EFI_UNSUPPORTED      This volume does not support the requested file system type.
+  @retval EFI_NO_MEDIA         The device has no medium.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_ACCESS_DENIED    The service denied access to the file.
+  @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
+  @retval EFI_MEDIA_CHANGED    The device has a different medium in it or the medium is no
+                               longer supported. Any existing file handles for this volume are
+                               no longer valid. To access the files on the new medium, the
+                               volume must be reopened with OpenVolume().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME)(
+  IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL    *This,
+  OUT EFI_FILE_PROTOCOL                 **Root
+  );
+
+#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION  0x00010000
+
+///
+/// Revision defined in EFI1.1
+///
+#define EFI_FILE_IO_INTERFACE_REVISION  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
+
+struct _EFI_SIMPLE_FILE_SYSTEM_PROTOCOL {
+  ///
+  /// The version of the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL. The version
+  /// specified by this specification is 0x00010000. All future revisions
+  /// must be backwards compatible.
+  ///
+  UINT64                                      Revision;
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME OpenVolume;
+};
+
+/**
+  Opens a new file relative to the source file's location.
+
+  @param  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
+                     handle to the source location. This would typically be an open
+                     handle to a directory.
+  @param  NewHandle  A pointer to the location to return the opened handle for the new
+                     file.
+  @param  FileName   The Null-terminated string of the name of the file to be opened.
+                     The file name may contain the following path modifiers: "\", ".",
+                     and "..".
+  @param  OpenMode   The mode to open the file. The only valid combinations that the
+                     file may be opened with are: Read, Read/Write, or Create/Read/Write.
+  @param  Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these are the
+                     attribute bits for the newly created file.
+
+  @retval EFI_SUCCESS          The file was opened.
+  @retval EFI_NOT_FOUND        The specified file could not be found on the device.
+  @retval EFI_NO_MEDIA         The device has no medium.
+  @retval EFI_MEDIA_CHANGED    The device has a different medium in it or the medium is no
+                               longer supported.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_WRITE_PROTECTED  An attempt was made to create a file, or open a file for write
+                               when the media is write-protected.
+  @retval EFI_ACCESS_DENIED    The service denied access to the file.
+  @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
+  @retval EFI_VOLUME_FULL      The volume is full.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FILE_OPEN)(
+  IN EFI_FILE_PROTOCOL        *This,
+  OUT EFI_FILE_PROTOCOL       **NewHandle,
+  IN CHAR16                   *FileName,
+  IN UINT64                   OpenMode,
+  IN UINT64                   Attributes
+  );
+
+//
+// Open modes
+//
+#define EFI_FILE_MODE_READ    0x0000000000000001ULL
+#define EFI_FILE_MODE_WRITE   0x0000000000000002ULL
+#define EFI_FILE_MODE_CREATE  0x8000000000000000ULL
+
+//
+// File attributes
+//
+#define EFI_FILE_READ_ONLY  0x0000000000000001ULL
+#define EFI_FILE_HIDDEN     0x0000000000000002ULL
+#define EFI_FILE_SYSTEM     0x0000000000000004ULL
+#define EFI_FILE_RESERVED   0x0000000000000008ULL
+#define EFI_FILE_DIRECTORY  0x0000000000000010ULL
+#define EFI_FILE_ARCHIVE    0x0000000000000020ULL
+#define EFI_FILE_VALID_ATTR 0x0000000000000037ULL
+
+/**
+  Closes a specified file handle.
+
+  @param  This          A pointer to the EFI_FILE_PROTOCOL instance that is the file
+                        handle to close.
+
+  @retval EFI_SUCCESS   The file was closed.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FILE_CLOSE)(
+  IN EFI_FILE_PROTOCOL  *This
+  );
+
+/**
+  Close and delete the file handle.
+
+  @param  This                     A pointer to the EFI_FILE_PROTOCOL instance that is the
+                                   handle to the file to delete.
+
+  @retval EFI_SUCCESS              The file was closed and deleted, and the handle was closed.
+  @retval EFI_WARN_DELETE_FAILURE  The handle was closed, but the file was not deleted.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FILE_DELETE)(
+  IN EFI_FILE_PROTOCOL  *This
+  );
+
+/**
+  Reads data from a file.
+
+  @param  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
+                     handle to read data from.
+  @param  BufferSize On input, the size of the Buffer. On output, the amount of data
+                     returned in Buffer. In both cases, the size is measured in bytes.
+  @param  Buffer     The buffer into which the data is read.
+
+  @retval EFI_SUCCESS          Data was read.
+  @retval EFI_NO_MEDIA         The device has no medium.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_DEVICE_ERROR     An attempt was made to read from a deleted file.
+  @retval EFI_DEVICE_ERROR     On entry, the current file position is beyond the end of the file.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_BUFFER_TO_SMALL  The BufferSize is too small to read the current directory
+                               entry. BufferSize has been updated with the size
+                               needed to complete the request.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FILE_READ)(
+  IN EFI_FILE_PROTOCOL        *This,
+  IN OUT UINTN                *BufferSize,
+  OUT VOID                    *Buffer
+  );
+
+/**
+  Writes data to a file.
+
+  @param  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
+                     handle to write data to.
+  @param  BufferSize On input, the size of the Buffer. On output, the amount of data
+                     actually written. In both cases, the size is measured in bytes.
+  @param  Buffer     The buffer of data to write.
+
+  @retval EFI_SUCCESS          Data was written.
+  @retval EFI_UNSUPPORTED      Writes to open directory files are not supported.
+  @retval EFI_NO_MEDIA         The device has no medium.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_DEVICE_ERROR     An attempt was made to write to a deleted file.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_WRITE_PROTECTED  The file or medium is write-protected.
+  @retval EFI_ACCESS_DENIED    The file was opened read only.
+  @retval EFI_VOLUME_FULL      The volume is full.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FILE_WRITE)(
+  IN EFI_FILE_PROTOCOL        *This,
+  IN OUT UINTN                *BufferSize,
+  IN VOID                     *Buffer
+  );
+
+/**
+  Sets a file's current position.
+
+  @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the
+                          file handle to set the requested position on.
+  @param  Position        The byte position from the start of the file to set.
+
+  @retval EFI_SUCCESS      The position was set.
+  @retval EFI_UNSUPPORTED  The seek request for nonzero is not valid on open
+                           directories.
+  @retval EFI_DEVICE_ERROR An attempt was made to set the position of a deleted file.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FILE_SET_POSITION)(
+  IN EFI_FILE_PROTOCOL        *This,
+  IN UINT64                   Position
+  );
+
+/**
+  Returns a file's current position.
+
+  @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the file
+                          handle to get the current position on.
+  @param  Position        The address to return the file's current position value.
+
+  @retval EFI_SUCCESS      The position was returned.
+  @retval EFI_UNSUPPORTED  The request is not valid on open directories.
+  @retval EFI_DEVICE_ERROR An attempt was made to get the position from a deleted file.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FILE_GET_POSITION)(
+  IN EFI_FILE_PROTOCOL        *This,
+  OUT UINT64                  *Position
+  );
+
+/**
+  Returns information about a file.
+
+  @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the file
+                          handle the requested information is for.
+  @param  InformationType The type identifier for the information being requested.
+  @param  BufferSize      On input, the size of Buffer. On output, the amount of data
+                          returned in Buffer. In both cases, the size is measured in bytes.
+  @param  Buffer          A pointer to the data buffer to return. The buffer's type is
+                          indicated by InformationType.
+
+  @retval EFI_SUCCESS          The information was returned.
+  @retval EFI_UNSUPPORTED      The InformationType is not known.
+  @retval EFI_NO_MEDIA         The device has no medium.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
+                               BufferSize has been updated with the size needed to complete
+                               the request.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FILE_GET_INFO)(
+  IN EFI_FILE_PROTOCOL        *This,
+  IN EFI_GUID                 *InformationType,
+  IN OUT UINTN                *BufferSize,
+  OUT VOID                    *Buffer
+  );
+
+/**
+  Sets information about a file.
+
+  @param  File            A pointer to the EFI_FILE_PROTOCOL instance that is the file
+                          handle the information is for.
+  @param  InformationType The type identifier for the information being set.
+  @param  BufferSize      The size, in bytes, of Buffer.
+  @param  Buffer          A pointer to the data buffer to write. The buffer's type is
+                          indicated by InformationType.
+
+  @retval EFI_SUCCESS          The information was set.
+  @retval EFI_UNSUPPORTED      The InformationType is not known.
+  @retval EFI_NO_MEDIA         The device has no medium.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_WRITE_PROTECTED  InformationType is EFI_FILE_INFO_ID and the media is
+                               read-only.
+  @retval EFI_WRITE_PROTECTED  InformationType is EFI_FILE_PROTOCOL_SYSTEM_INFO_ID
+                               and the media is read only.
+  @retval EFI_WRITE_PROTECTED  InformationType is EFI_FILE_SYSTEM_VOLUME_LABEL_ID
+                               and the media is read-only.
+  @retval EFI_ACCESS_DENIED    An attempt is made to change the name of a file to a
+                               file that is already present.
+  @retval EFI_ACCESS_DENIED    An attempt is being made to change the EFI_FILE_DIRECTORY
+                               Attribute.
+  @retval EFI_ACCESS_DENIED    An attempt is being made to change the size of a directory.
+  @retval EFI_ACCESS_DENIED    InformationType is EFI_FILE_INFO_ID and the file was opened
+                               read-only and an attempt is being made to modify a field
+                               other than Attribute.
+  @retval EFI_VOLUME_FULL      The volume is full.
+  @retval EFI_BAD_BUFFER_SIZE  BufferSize is smaller than the size of the type indicated
+                               by InformationType.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FILE_SET_INFO)(
+  IN EFI_FILE_PROTOCOL        *This,
+  IN EFI_GUID                 *InformationType,
+  IN UINTN                    BufferSize,
+  IN VOID                     *Buffer
+  );
+
+/**
+  Flushes all modified data associated with a file to a device.
+
+  @param  This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+               handle to flush.
+
+  @retval EFI_SUCCESS          The data was flushed.
+  @retval EFI_NO_MEDIA         The device has no medium.
+  @retval EFI_DEVICE_ERROR     The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+  @retval EFI_WRITE_PROTECTED  The file or medium is write-protected.
+  @retval EFI_ACCESS_DENIED    The file was opened read-only.
+  @retval EFI_VOLUME_FULL      The volume is full.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FILE_FLUSH)(
+  IN EFI_FILE_PROTOCOL  *This
+  );
+
+#define EFI_FILE_PROTOCOL_REVISION   0x00010000
+//
+// Revision defined in EFI1.1.
+//
+#define EFI_FILE_REVISION   EFI_FILE_PROTOCOL_REVISION
+
+///
+/// The EFI_FILE_PROTOCOL provides file IO access to supported file systems.
+/// An EFI_FILE_PROTOCOL provides access to a file's or directory's contents,
+/// and is also a reference to a location in the directory tree of the file system
+/// in which the file resides. With any given file handle, other files may be opened
+/// relative to this file's location, yielding new file handles.
+///
+struct _EFI_FILE_PROTOCOL {
+  ///
+  /// The version of the EFI_FILE_PROTOCOL interface. The version specified
+  /// by this specification is 0x00010000. Future versions are required
+  /// to be backward compatible to version 1.0.
+  ///
+  UINT64                Revision;
+  EFI_FILE_OPEN         Open;
+  EFI_FILE_CLOSE        Close;
+  EFI_FILE_DELETE       Delete;
+  EFI_FILE_READ         Read;
+  EFI_FILE_WRITE        Write;
+  EFI_FILE_GET_POSITION GetPosition;
+  EFI_FILE_SET_POSITION SetPosition;
+  EFI_FILE_GET_INFO     GetInfo;
+  EFI_FILE_SET_INFO     SetInfo;
+  EFI_FILE_FLUSH        Flush;
+};
+
+
+extern EFI_GUID gEfiSimpleFileSystemProtocolGuid;
+
+#endif
diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextIn.h b/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextIn.h
index a89a9b4fa5394ed74adab553036c..571ecaf30bf51c15f5cd9c5d8436 100644
--- a/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextIn.h
+++ b/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextIn.h
@@ -4,7 +4,7 @@
   Abstraction of a very simple input device like a keyboard or serial
   terminal.
 
-  Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
   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
@@ -78,8 +78,6 @@ typedef struct {
 #define SCAN_F8         0x0012
 #define SCAN_F9         0x0013
 #define SCAN_F10        0x0014
-#define SCAN_F11        0x0015
-#define SCAN_F12        0x0016
 #define SCAN_ESC        0x0017
 
 /**
diff --git a/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextInEx.h b/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextInEx.h
new file mode 100644
index 0000000000000000000000000000000000000000..9a9f5ab595402349534bdb2ad0768bd88fa98d25
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/efi/Protocol/SimpleTextInEx.h
@@ -0,0 +1,327 @@
+/** @file
+  Simple Text Input Ex protocol from the UEFI 2.0 specification.
+
+  This protocol defines an extension to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+  which exposes much more state and modifier information from the input device,
+  also allows one to register a notification for a particular keystroke.
+
+  Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+  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_EX_H__
+#define __SIMPLE_TEXT_IN_EX_H__
+
+FILE_LICENCE ( BSD3 );
+
+#include <ipxe/efi/Protocol/SimpleTextIn.h>
+
+#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \
+  {0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } }
+
+
+typedef struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL;
+
+/**
+  The Reset() function resets the input device hardware. As part
+  of initialization process, the firmware/device will make a quick
+  but reasonable attempt to verify that the device is functioning.
+  If the ExtendedVerification flag is TRUE the firmware may take
+  an extended amount of time to verify the device is operating on
+  reset. Otherwise the reset operation is to occur as quickly as
+  possible. The hardware verification process is not defined by
+  this specification and is left up to the platform firmware or
+  driver to implement.
+
+  @param This                 A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
+
+  @param ExtendedVerification Indicates that the driver may
+                              perform a more exhaustive
+                              verification operation of the
+                              device during reset.
+
+
+  @retval EFI_SUCCESS       The device was reset.
+
+  @retval EFI_DEVICE_ERROR  The device is not functioning
+                            correctly and could not be reset.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INPUT_RESET_EX)(
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+  IN BOOLEAN                           ExtendedVerification
+);
+
+
+///
+/// EFI_KEY_TOGGLE_STATE. The toggle states are defined.
+/// They are: EFI_TOGGLE_STATE_VALID, EFI_SCROLL_LOCK_ACTIVE
+/// EFI_NUM_LOCK_ACTIVE, EFI_CAPS_LOCK_ACTIVE
+///
+typedef UINT8 EFI_KEY_TOGGLE_STATE;
+
+typedef struct _EFI_KEY_STATE {
+  ///
+  /// Reflects the currently pressed shift
+  /// modifiers for the input device. The
+  /// returned value is valid only if the high
+  /// order bit has been set.
+  ///
+  UINT32                KeyShiftState;
+  ///
+  /// Reflects the current internal state of
+  /// various toggled attributes. The returned
+  /// value is valid only if the high order
+  /// bit has been set.
+  ///
+  EFI_KEY_TOGGLE_STATE  KeyToggleState;
+} EFI_KEY_STATE;
+
+typedef struct {
+  ///
+  /// The EFI scan code and Unicode value returned from the input device.
+  ///
+  EFI_INPUT_KEY   Key;
+  ///
+  /// The current state of various toggled attributes as well as input modifier values.
+  ///
+  EFI_KEY_STATE   KeyState;
+} EFI_KEY_DATA;
+
+//
+// Any Shift or Toggle State that is valid should have
+// high order bit set.
+//
+// Shift state
+//
+#define EFI_SHIFT_STATE_VALID     0x80000000
+#define EFI_RIGHT_SHIFT_PRESSED   0x00000001
+#define EFI_LEFT_SHIFT_PRESSED    0x00000002
+#define EFI_RIGHT_CONTROL_PRESSED 0x00000004
+#define EFI_LEFT_CONTROL_PRESSED  0x00000008
+#define EFI_RIGHT_ALT_PRESSED     0x00000010
+#define EFI_LEFT_ALT_PRESSED      0x00000020
+#define EFI_RIGHT_LOGO_PRESSED    0x00000040
+#define EFI_LEFT_LOGO_PRESSED     0x00000080
+#define EFI_MENU_KEY_PRESSED      0x00000100
+#define EFI_SYS_REQ_PRESSED       0x00000200
+
+//
+// Toggle state
+//
+#define EFI_TOGGLE_STATE_VALID    0x80
+#define EFI_KEY_STATE_EXPOSED     0x40
+#define EFI_SCROLL_LOCK_ACTIVE    0x01
+#define EFI_NUM_LOCK_ACTIVE       0x02
+#define EFI_CAPS_LOCK_ACTIVE      0x04
+
+//
+// EFI Scan codes
+//
+#define SCAN_F11                  0x0015
+#define SCAN_F12                  0x0016
+#define SCAN_PAUSE                0x0048
+#define SCAN_F13                  0x0068
+#define SCAN_F14                  0x0069
+#define SCAN_F15                  0x006A
+#define SCAN_F16                  0x006B
+#define SCAN_F17                  0x006C
+#define SCAN_F18                  0x006D
+#define SCAN_F19                  0x006E
+#define SCAN_F20                  0x006F
+#define SCAN_F21                  0x0070
+#define SCAN_F22                  0x0071
+#define SCAN_F23                  0x0072
+#define SCAN_F24                  0x0073
+#define SCAN_MUTE                 0x007F
+#define SCAN_VOLUME_UP            0x0080
+#define SCAN_VOLUME_DOWN          0x0081
+#define SCAN_BRIGHTNESS_UP        0x0100
+#define SCAN_BRIGHTNESS_DOWN      0x0101
+#define SCAN_SUSPEND              0x0102
+#define SCAN_HIBERNATE            0x0103
+#define SCAN_TOGGLE_DISPLAY       0x0104
+#define SCAN_RECOVERY             0x0105
+#define SCAN_EJECT                0x0106
+
+/**
+  The function reads the next keystroke from the input device. If
+  there is no pending keystroke the function returns
+  EFI_NOT_READY. If there is a pending keystroke, then
+  KeyData.Key.ScanCode is the EFI scan code defined in Error!
+  Reference source not found. The KeyData.Key.UnicodeChar is the
+  actual printable character or is zero if the key does not
+  represent a printable character (control key, function key,
+  etc.). The KeyData.KeyState is shift state for the character
+  reflected in KeyData.Key.UnicodeChar or KeyData.Key.ScanCode .
+  When interpreting the data from this function, it should be
+  noted that if a class of printable characters that are
+  normally adjusted by shift modifiers (e.g. Shift Key + "f"
+  key) would be presented solely as a KeyData.Key.UnicodeChar
+  without the associated shift state. So in the previous example
+  of a Shift Key + "f" key being pressed, the only pertinent
+  data returned would be KeyData.Key.UnicodeChar with the value
+  of "F". This of course would not typically be the case for
+  non-printable characters such as the pressing of the Right
+  Shift Key + F10 key since the corresponding returned data
+  would be reflected both in the KeyData.KeyState.KeyShiftState
+  and KeyData.Key.ScanCode values. UEFI drivers which implement
+  the EFI_SIMPLE_TEXT_INPUT_EX protocol are required to return
+  KeyData.Key and KeyData.KeyState values. These drivers must
+  always return the most current state of
+  KeyData.KeyState.KeyShiftState and
+  KeyData.KeyState.KeyToggleState. It should also be noted that
+  certain input devices may not be able to produce shift or toggle
+  state information, and in those cases the high order bit in the
+  respective Toggle and Shift state fields should not be active.
+
+
+  @param This     A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
+
+  @param KeyData  A pointer to a buffer that is filled in with
+                  the keystroke state data for the key that was
+                  pressed.
+
+
+  @retval EFI_SUCCESS     The keystroke information was
+                          returned.
+
+  @retval EFI_NOT_READY   There was no keystroke data available.
+                          EFI_DEVICE_ERROR The keystroke
+                          information was not returned due to
+                          hardware errors.
+
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INPUT_READ_KEY_EX)(
+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+  OUT EFI_KEY_DATA                      *KeyData
+);
+
+/**
+  The SetState() function allows the input device hardware to
+  have state settings adjusted.
+
+  @param This           A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
+
+  @param KeyToggleState Pointer to the EFI_KEY_TOGGLE_STATE to
+                        set the state for the input device.
+
+
+  @retval EFI_SUCCESS       The device state was set appropriately.
+
+  @retval EFI_DEVICE_ERROR  The device is not functioning
+                            correctly and could not have the
+                            setting adjusted.
+
+  @retval EFI_UNSUPPORTED   The device does not support the
+                            ability to have its state set.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SET_STATE)(
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+  IN EFI_KEY_TOGGLE_STATE              *KeyToggleState
+);
+
+///
+/// The function will be called when the key sequence is typed specified by KeyData.
+///
+typedef
+EFI_STATUS
+(EFIAPI *EFI_KEY_NOTIFY_FUNCTION)(
+  IN EFI_KEY_DATA *KeyData
+);
+
+/**
+  The RegisterKeystrokeNotify() function registers a function
+  which will be called when a specified keystroke will occur.
+
+  @param This                     A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
+
+  @param KeyData                  A pointer to a buffer that is filled in with
+                                  the keystroke information for the key that was
+                                  pressed.
+
+  @param KeyNotificationFunction  Points to the function to be
+                                  called when the key sequence
+                                  is typed specified by KeyData.
+
+
+  @param NotifyHandle             Points to the unique handle assigned to
+                                  the registered notification.
+
+  @retval EFI_SUCCESS           The device state was set
+                                appropriately.
+
+  @retval EFI_OUT_OF_RESOURCES  Unable to allocate necessary
+                                data structures.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_REGISTER_KEYSTROKE_NOTIFY)(
+  IN  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+  IN  EFI_KEY_DATA                      *KeyData,
+  IN  EFI_KEY_NOTIFY_FUNCTION           KeyNotificationFunction,
+  OUT VOID                              **NotifyHandle
+);
+
+/**
+  The UnregisterKeystrokeNotify() function removes the
+  notification which was previously registered.
+
+  @param This               A pointer to the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL instance.
+
+  @param NotificationHandle The handle of the notification
+                            function being unregistered.
+
+  @retval EFI_SUCCESS The device state was set appropriately.
+
+  @retval EFI_INVALID_PARAMETER The NotificationHandle is
+                                invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_UNREGISTER_KEYSTROKE_NOTIFY)(
+  IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *This,
+  IN VOID                               *NotificationHandle
+);
+
+
+///
+/// The EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL is used on the ConsoleIn
+/// device. It is an extension to the Simple Text Input protocol
+/// which allows a variety of extended shift state information to be
+/// returned.
+///
+struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL{
+  EFI_INPUT_RESET_EX              Reset;
+  EFI_INPUT_READ_KEY_EX           ReadKeyStrokeEx;
+  ///
+  /// Event to use with WaitForEvent() to wait for a key to be available.
+  ///
+  EFI_EVENT                       WaitForKeyEx;
+  EFI_SET_STATE                   SetState;
+  EFI_REGISTER_KEYSTROKE_NOTIFY   RegisterKeyNotify;
+  EFI_UNREGISTER_KEYSTROKE_NOTIFY UnregisterKeyNotify;
+};
+
+
+extern EFI_GUID gEfiSimpleTextInputExProtocolGuid;
+
+#endif
+
diff --git a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiBaseType.h b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiBaseType.h
index 2c63aa6ff2af1e76a769806063eb..c56f3757b9a87102b8db31d001d1 100644
--- a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiBaseType.h
+++ b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiBaseType.h
@@ -1,7 +1,7 @@
 /** @file
   Defines data types and constants introduced in UEFI.
 
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials are licensed and made available under
 the terms and conditions of the BSD License that accompanies this distribution.
 The full text of the license may be found at
@@ -150,11 +150,13 @@ typedef union {
 #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_COMPROMISED_DATA      RETURN_COMPROMISED_DATA
 
 #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 EFI_WARN_STALE_DATA       RETURN_WARN_STALE_DATA
 ///@}
 
 ///
diff --git a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiGpt.h b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiGpt.h
index 26af39f5d46446cb1715efb77ec0..19acf55d42dfa02b33c3f9d3f8de 100644
--- a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiGpt.h
+++ b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiGpt.h
@@ -71,7 +71,8 @@ typedef struct {
   ///
   /// The size, in bytes, of each the GUID Partition
   /// Entry structures in the GUID Partition Entry
-  /// array. Must be a multiple of 8.
+  /// array. This field shall be set to a value of 128 x 2^n where n is
+  /// an integer greater than or equal to zero (e.g., 128, 256, 512, etc.).
   ///
   UINT32            SizeOfPartitionEntry;
   ///
diff --git a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiInternalFormRepresentation.h b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiInternalFormRepresentation.h
index 6b6d1e066dc4a309c85d05f68e6a..e792473c1f979c1542259a8e79db 100644
--- a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiInternalFormRepresentation.h
+++ b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiInternalFormRepresentation.h
@@ -3,7 +3,7 @@
   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 - 2010, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials are licensed and made available under
 the terms and conditions of the BSD License that accompanies this distribution.
 The full text of the license may be found at
@@ -660,6 +660,13 @@ typedef struct {
   UINT8  Day;
 } EFI_HII_DATE;
 
+typedef struct {
+  EFI_QUESTION_ID QuestionId;
+  EFI_FORM_ID     FormId;
+  EFI_GUID        FormSetGuid;
+  EFI_STRING_ID   DevicePath;
+} EFI_HII_REF;
+
 typedef union {
   UINT8           u8;
   UINT16          u16;
@@ -669,7 +676,8 @@ typedef union {
   EFI_HII_TIME    time;
   EFI_HII_DATE    date;
   EFI_STRING_ID   string; ///< EFI_IFR_TYPE_STRING, EFI_IFR_TYPE_ACTION
-  // UINT8 buffer[];      ///< EFI_IFR_TYPE_ORDERED_LIST
+  EFI_HII_REF     ref;    ///< EFI_IFR_TYPE_REF
+  // UINT8 buffer[];      ///< EFI_IFR_TYPE_BUFFER
 } EFI_IFR_TYPE_VALUE;
 
 //
@@ -694,7 +702,7 @@ typedef union {
 #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_EQ_ID_VAL_LIST_OP      0x14
 #define EFI_IFR_AND_OP                 0x15
 #define EFI_IFR_OR_OP                  0x16
 #define EFI_IFR_NOT_OP                 0x17
@@ -771,6 +779,8 @@ typedef union {
 #define EFI_IFR_CATENATE_OP            0x5E
 #define EFI_IFR_GUID_OP                0x5F
 #define EFI_IFR_SECURITY_OP            0x60
+#define EFI_IFR_MODAL_TAG_OP           0x61
+#define EFI_IFR_REFRESH_ID_OP          0x62
 
 //
 // Definitions of IFR Standard Headers
@@ -843,6 +853,8 @@ typedef struct _EFI_IFR_VARSTORE_EFI {
   EFI_VARSTORE_ID          VarStoreId;
   EFI_GUID                 Guid;
   UINT32                   Attributes;
+  UINT16                   Size;
+  UINT8                    Name[1];
 } EFI_IFR_VARSTORE_EFI;
 
 typedef struct _EFI_IFR_VARSTORE_NAME_VALUE {
@@ -875,6 +887,10 @@ typedef struct _EFI_IFR_IMAGE {
   EFI_IMAGE_ID             Id;
 } EFI_IFR_IMAGE;
 
+typedef struct _EFI_IFR_MODAL_TAG {
+  EFI_IFR_OP_HEADER        Header;
+} EFI_IFR_MODAL_TAG;
+
 typedef struct _EFI_IFR_LOCKED {
   EFI_IFR_OP_HEADER        Header;
 } EFI_IFR_LOCKED;
@@ -891,6 +907,12 @@ typedef struct _EFI_IFR_DEFAULT {
   EFI_IFR_TYPE_VALUE       Value;
 } EFI_IFR_DEFAULT;
 
+typedef struct _EFI_IFR_DEFAULT_2 {
+  EFI_IFR_OP_HEADER        Header;
+  UINT16                   DefaultId;
+  UINT8                    Type;
+} EFI_IFR_DEFAULT_2;
+
 typedef struct _EFI_IFR_VALUE {
   EFI_IFR_OP_HEADER        Header;
 } EFI_IFR_VALUE;
@@ -948,6 +970,11 @@ typedef struct _EFI_IFR_REF4 {
   EFI_STRING_ID            DevicePath;
 } EFI_IFR_REF4;
 
+typedef struct _EFI_IFR_REF5 {
+  EFI_IFR_OP_HEADER Header;
+  EFI_IFR_QUESTION_HEADER Question;
+} EFI_IFR_REF5;
+
 typedef struct _EFI_IFR_RESET_BUTTON {
   EFI_IFR_OP_HEADER        Header;
   EFI_IFR_STATEMENT_HEADER Statement;
@@ -1134,6 +1161,7 @@ typedef struct _EFI_IFR_ONE_OF_OPTION {
 #define EFI_IFR_TYPE_UNDEFINED         0x09
 #define EFI_IFR_TYPE_ACTION            0x0A
 #define EFI_IFR_TYPE_BUFFER            0x0B
+#define EFI_IFR_TYPE_REF               0x0C
 
 #define EFI_IFR_OPTION_DEFAULT         0x10
 #define EFI_IFR_OPTION_DEFAULT_MFG     0x20
@@ -1144,6 +1172,11 @@ typedef struct _EFI_IFR_GUID {
   //Optional Data Follows
 } EFI_IFR_GUID;
 
+typedef struct _EFI_IFR_REFRESH_ID {
+  EFI_IFR_OP_HEADER Header;
+  EFI_GUID          RefreshEventGroupId;
+} EFI_IFR_REFRESH_ID;
+
 typedef struct _EFI_IFR_DUP {
   EFI_IFR_OP_HEADER        Header;
 } EFI_IFR_DUP;
diff --git a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiMultiPhase.h b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiMultiPhase.h
index 6ecbcf118f2ec2836276dc9057fc..678f3ebd6e1ccbb0d73d579a23cf 100644
--- a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiMultiPhase.h
+++ b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiMultiPhase.h
@@ -1,7 +1,7 @@
 /** @file
   This includes some definitions introduced in UEFI that will be used in both PEI and DXE phases.
 
-Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials are licensed and made available under
 the terms and conditions of the BSD License that accompanies this distribution.
 The full text of the license may be found at
@@ -122,21 +122,26 @@ typedef struct {
 ///
 /// 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
-
+#define EFI_VARIABLE_NON_VOLATILE                            0x00000001
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS                      0x00000002
+#define EFI_VARIABLE_RUNTIME_ACCESS                          0x00000004
 ///
 /// This attribute is identified by the mnemonic 'HR'
 /// elsewhere in this specification.
 ///
-#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS   0x00000010
+#define EFI_VARIABLE_HARDWARE_ERROR_RECORD                   0x00000008
+///
+/// Attributes of Authenticated Variable
+///
+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS              0x00000010
+#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS   0x00000020
+#define EFI_VARIABLE_APPEND_WRITE                            0x00000040
+
 
 ///
 /// AuthInfo is a WIN_CERTIFICATE using the wCertificateType
 /// WIN_CERTIFICATE_UEFI_GUID and the CertType
-/// EFI_CERT_TYPE_RSA2048_SHA256. If the attribute specifies
+/// EFI_CERT_TYPE_RSA2048_SHA256_GUID. 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
@@ -167,5 +172,24 @@ typedef struct {
   WIN_CERTIFICATE_UEFI_GUID   AuthInfo;
 } EFI_VARIABLE_AUTHENTICATION;
 
-#endif
+///
+/// When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
+/// set, then the Data buffer shall begin with an instance of a complete (and serialized)
+/// EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
+/// variable value and DataSize shall reflect the combined size of the descriptor and the new
+/// variable value. The authentication descriptor is not part of the variable data and is not
+/// returned by subsequent calls to GetVariable().
+///
+typedef struct {
+  ///
+  /// For the TimeStamp value, components Pad1, Nanosecond, TimeZone, Daylight and
+  /// Pad2 shall be set to 0. This means that the time shall always be expressed in GMT.
+  ///
+  EFI_TIME                    TimeStamp;
+  ///
+  /// Only a CertType of  EFI_CERT_TYPE_PKCS7_GUID is accepted.
+  ///
+  WIN_CERTIFICATE_UEFI_GUID   AuthInfo;
+ } EFI_VARIABLE_AUTHENTICATION_2;
 
+#endif
diff --git a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h
index 1f125d4f31219321699f6df6690e..141bccd751ac87e7d83ed733c668 100644
--- a/roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h
+++ b/roms/ipxe/src/include/ipxe/efi/Uefi/UefiSpec.h
@@ -5,7 +5,7 @@
   If a code construct is defined in the UEFI 2.3 specification it must be included
   by this include file.
 
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
 This program and the accompanying materials are licensed and made available under
 the terms and conditions of the BSD License that accompanies this distribution.
 The full text of the license may be found at
@@ -25,6 +25,7 @@ FILE_LICENCE ( BSD3 );
 
 #include <ipxe/efi/Protocol/DevicePath.h>
 #include <ipxe/efi/Protocol/SimpleTextIn.h>
+#include <ipxe/efi/Protocol/SimpleTextInEx.h>
 #include <ipxe/efi/Protocol/SimpleTextOut.h>
 
 ///
@@ -128,6 +129,7 @@ typedef struct {
   @retval EFI_INVALID_PARAMETER 1) Type is not AllocateAnyPages or
                                 AllocateMaxAddress or AllocateAddress.
                                 2) MemoryType is in the range
+                                3) Memory is NULL.
                                 EfiMaxMemoryType..0x7FFFFFFF.
   @retval EFI_OUT_OF_RESOURCES  The pages could not be allocated.
   @retval EFI_NOT_FOUND         The requested pages could not be found.
@@ -206,7 +208,7 @@ EFI_STATUS
 
   @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.
+  @retval EFI_INVALID_PARAMETER PoolType was invalid or Buffer is NULL.
 
 **/
 typedef
@@ -277,11 +279,13 @@ EFI_STATUS
                                 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_INVALID_PARAMETER ControllerHandle is NULL.
   @retval EFI_NOT_FOUND         1) There are no EFI_DRIVER_BINDING_PROTOCOL instances
                                 present in the system.
                                 2) No drivers were connected to ControllerHandle.
-
+  @retval EFI_SECURITY_VIOLATION
+                                The user has no permission to start UEFI device drivers on the device path
+                                associated with the ControllerHandle or specified by the RemainingDevicePath.
 **/
 typedef
 EFI_STATUS
@@ -307,7 +311,7 @@ EFI_STATUS
                                 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 1) ControllerHandle is not a valid EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER 1) ControllerHandle is NULL.
                                 2) DriverImageHandle is not NULL, and it is not a valid EFI_HANDLE.
                                 3) ChildHandle is not NULL, and it is not a valid EFI_HANDLE.
                                 4) DriverImageHandle does not support the EFI_DRIVER_BINDING_PROTOCOL.
@@ -848,8 +852,9 @@ EFI_STATUS
   @param  ExitData              The pointer to a pointer to a data buffer that includes a Null-terminated
                                 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 EFI_INVALID_PARAMETER  ImageHandle is either an invalid image handle or the image
+                                 has already been initialized with StartImage.
+  @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the image should not be started.
   @return Exit code from image
 
 **/
@@ -1136,8 +1141,8 @@ EFI_STATUS
 /**
   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  Handle                The pointer to a handle to install the new protocol interfaces on,
+                                or a pointer to NULL if a new handle is to be allocated.
   @param  ...                   A variable argument list containing pairs of protocol GUIDs and protocol
                                 interfaces.
 
@@ -1168,7 +1173,7 @@ EFI_STATUS
   @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 Handle is not a valid EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER Handle is NULL.
   @retval EFI_INVALID_PARAMETER Protocol is NULL.
 
 **/
@@ -1194,7 +1199,7 @@ EFI_STATUS
   @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 Handle is not a valid EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER Handle is NULL.
   @retval EFI_INVALID_PARAMETER Protocol is NULL.
 
 **/
@@ -1234,7 +1239,7 @@ EFI_STATUS
 
   @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 Handle is not a valid EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER Handle is NULL.
   @retval EFI_INVALID_PARAMETER Protocol is NULL.
   @retval EFI_INVALID_PARAMETER Interface is NULL.
 
@@ -1305,8 +1310,8 @@ EFI_STATUS
                                 that required the protocol interface.
 
   @retval EFI_SUCCESS           The protocol instance was closed.
-  @retval EFI_INVALID_PARAMETER 1) Handle is not a valid EFI_HANDLE.
-                                2) AgentHandle is not a valid EFI_HANDLE.
+  @retval EFI_INVALID_PARAMETER 1) Handle is NULL.
+                                2) AgentHandle is NULL.
                                 3) ControllerHandle is not NULL and ControllerHandle is not a valid EFI_HANDLE.
                                 4) Protocol is NULL.
   @retval EFI_NOT_FOUND         1) Handle does not support the protocol specified by Protocol.
@@ -1493,7 +1498,7 @@ EFI_STATUS
 
   @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_INVALID_PARAMETER Guid is NULL.
   @retval EFI_OUT_OF_RESOURCES  There is not enough memory available to complete the operation.
 
 **/
@@ -1720,21 +1725,26 @@ EFI_STATUS
   OUT UINT64            *MaximumVariableSize
   );
 
+//
+// Firmware should stop at a firmware user interface on next boot
+//
+#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI    0x0000000000000001
 
 //
 // EFI Runtime Services Table
 //
 #define EFI_SYSTEM_TABLE_SIGNATURE      SIGNATURE_64 ('I','B','I',' ','S','Y','S','T')
+#define EFI_2_31_SYSTEM_TABLE_REVISION  ((2 << 16) | (31))
 #define EFI_2_30_SYSTEM_TABLE_REVISION  ((2 << 16) | (30))
 #define EFI_2_20_SYSTEM_TABLE_REVISION  ((2 << 16) | (20))
 #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_SYSTEM_TABLE_REVISION       EFI_2_30_SYSTEM_TABLE_REVISION
+#define EFI_SYSTEM_TABLE_REVISION       EFI_2_31_SYSTEM_TABLE_REVISION
 
 #define EFI_RUNTIME_SERVICES_SIGNATURE  SIGNATURE_64 ('R','U','N','T','S','E','R','V')
-#define EFI_RUNTIME_SERVICES_REVISION   EFI_2_30_SYSTEM_TABLE_REVISION
+#define EFI_RUNTIME_SERVICES_REVISION   EFI_2_31_SYSTEM_TABLE_REVISION
 
 ///
 /// EFI Runtime Services Table.
@@ -1786,7 +1796,7 @@ typedef struct {
 
 
 #define EFI_BOOT_SERVICES_SIGNATURE   SIGNATURE_64 ('B','O','O','T','S','E','R','V')
-#define EFI_BOOT_SERVICES_REVISION    EFI_2_30_SYSTEM_TABLE_REVISION
+#define EFI_BOOT_SERVICES_REVISION    EFI_2_31_SYSTEM_TABLE_REVISION
 
 ///
 /// EFI Boot Services Table.
@@ -2003,50 +2013,46 @@ EFI_STATUS
 ///
 /// EFI Boot Key Data
 ///
-typedef union {
-  struct {
-    ///
-    /// Indicates the revision of the EFI_KEY_OPTION structure. This revision level should be 0.
-    ///
-    UINT32  Revision        : 8;
-    ///
-    /// Either the left or right Shift keys must be pressed (1) or must not be pressed (0).
-    ///
-    UINT32  ShiftPressed    : 1;
-    ///
-    /// Either the left or right Control keys must be pressed (1) or must not be pressed (0).
-    ///
-    UINT32  ControlPressed  : 1;
-    ///
-    /// Either the left or right Alt keys must be pressed (1) or must not be pressed (0).
-    ///
-    UINT32  AltPressed      : 1;
-    ///
-    /// Either the left or right Logo keys must be pressed (1) or must not be pressed (0).
-    ///
-    UINT32  LogoPressed     : 1;
-    ///
-    /// The Menu key must be pressed (1) or must not be pressed (0).
-    ///
-    UINT32  MenuPressed     : 1;
-    ///
-    /// The SysReq key must be pressed (1) or must not be pressed (0).
-    ///
-    UINT32  SysReqPressed    : 1;
-    UINT32  Reserved        : 16;
-    ///
-    /// Specifies the actual number of entries in EFI_KEY_OPTION.Keys, from 0-3. If
-    /// zero, then only the shift state is considered. If more than one, then the boot option will
-    /// only be launched if all of the specified keys are pressed with the same shift state.
-    ///
-    UINT32  InputKeyCount   : 2;
-  } Options;
-  UINT32  PackedValue;
-} EFI_BOOT_KEY_DATA;
+typedef UINT32 EFI_BOOT_KEY_DATA;
+///
+/// Indicates the revision of the EFI_KEY_OPTION structure. This revision level should be 0.
+///
+#define EFI_KEY_OPTION_REVISION_MASK        0x000000FF
+///
+/// Either the left or right Shift keys must be pressed (1) or must not be pressed (0).
+///
+#define EFI_KEY_OPTION_SHIFT_PRESSED_MASK   BIT8
+///
+/// Either the left or right Control keys must be pressed (1) or must not be pressed (0).
+///
+#define EFI_KEY_OPTION_CONTROL_PRESSED_MASK BIT9
+///
+/// Either the left or right Alt keys must be pressed (1) or must not be pressed (0).
+///
+#define EFI_KEY_OPTION_ALT_PRESSED_MASK     BIT10
+///
+/// Either the left or right Logo keys must be pressed (1) or must not be pressed (0).
+///
+#define EFI_KEY_OPTION_LOGO_PRESSED_MASK    BIT11
+///
+/// The Menu key must be pressed (1) or must not be pressed (0).
+///
+#define EFI_KEY_OPTION_MENU_PRESSED_MASK    BIT12
+///
+/// The SysReq key must be pressed (1) or must not be pressed (0).
+///
+#define EFI_KEY_OPTION_SYS_REQ_PRESSED_MASK BIT13
+///
+/// Specifies the actual number of entries in EFI_KEY_OPTION.Keys, from 0-3. If
+/// zero, then only the shift state is considered. If more than one, then the boot option will
+/// only be launched if all of the specified keys are pressed with the same shift state.
+///
+#define EFI_KEY_OPTION_INPUT_KEY_COUNT_MASK (BIT30 | BIT31)
 
 ///
 /// EFI Key Option.
 ///
+#pragma pack(1)
 typedef struct {
   ///
   /// Specifies options about how the key will be processed.
@@ -2070,6 +2076,7 @@ typedef struct {
   ///
   //EFI_INPUT_KEY      Keys[];
 } EFI_KEY_OPTION;
+#pragma pack()
 
 //
 // EFI File location to boot from on removable media devices
diff --git a/roms/ipxe/src/include/ipxe/efi/X64/ProcessorBind.h b/roms/ipxe/src/include/ipxe/efi/X64/ProcessorBind.h
index 0b1a3e11e51c4673fb4b4e283c5b..e10e3b549ab6edd271f06cda83e3 100644
--- a/roms/ipxe/src/include/ipxe/efi/X64/ProcessorBind.h
+++ b/roms/ipxe/src/include/ipxe/efi/X64/ProcessorBind.h
@@ -1,7 +1,7 @@
 /** @file
   Processor or Compiler specific defines and types x64 (Intel 64, AMD64).
 
-  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
   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
@@ -149,7 +149,7 @@ FILE_LICENCE ( BSD3 );
   ///
   /// 1-byte signed value
   ///
-  typedef char                INT8;
+  typedef signed char         INT8;
 #else
   ///
   /// 8-byte unsigned value
@@ -196,7 +196,7 @@ FILE_LICENCE ( BSD3 );
   ///
   /// 1-byte signed value
   ///
-  typedef char                INT8;
+  typedef signed char         INT8;
 #endif
 
 ///
diff --git a/roms/ipxe/src/include/ipxe/efi/efi.h b/roms/ipxe/src/include/ipxe/efi/efi.h
index 8a216b5373f6afe9cfafc0dfb87b..46b66690dc607216385efa0aab52 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi.h
@@ -54,12 +54,7 @@
 /** An EFI protocol used by iPXE */
 struct efi_protocol {
 	/** GUID */
-	union {
-		/** EFI protocol GUID */
-		EFI_GUID guid;
-		/** UUID structure understood by iPXE */
-		union uuid uuid;
-	} u;
+	EFI_GUID guid;
 	/** Variable containing pointer to protocol structure */
 	void **protocol;
 };
@@ -77,7 +72,7 @@ struct efi_protocol {
  */
 #define EFI_REQUIRE_PROTOCOL( _protocol, _ptr )				     \
 	struct efi_protocol __ ## _protocol __efi_protocol = {		     \
-		.u.guid = _protocol ## _GUID,				     \
+		.guid = _protocol ## _GUID,				     \
 		.protocol = ( ( void ** ) ( void * )			     \
 			      ( ( (_ptr) == ( ( _protocol ** ) (_ptr) ) ) ?  \
 				(_ptr) : (_ptr) ) ),			     \
@@ -86,12 +81,7 @@ struct efi_protocol {
 /** An EFI configuration table used by iPXE */
 struct efi_config_table {
 	/** GUID */
-	union {
-		/** EFI configuration table GUID */
-		EFI_GUID guid;
-		/** UUID structure understood by iPXE */
-		union uuid uuid;
-	} u;
+	EFI_GUID guid;
 	/** Variable containing pointer to configuration table */
 	void **table;
 	/** Table is required for operation */
@@ -113,7 +103,7 @@ struct efi_config_table {
  */
 #define EFI_USE_TABLE( _table, _ptr, _required )			     \
 	struct efi_config_table __ ## _table __efi_config_table = {	     \
-		.u.guid = _table ## _GUID,				     \
+		.guid = _table ## _GUID,				     \
 		.table = ( ( void ** ) ( void * ) (_ptr) ),		     \
 		.required = (_required),				     \
 	}
@@ -140,6 +130,41 @@ extern EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image;
 extern EFI_SYSTEM_TABLE *efi_systab;
 
 extern const char * efi_strerror ( EFI_STATUS efirc );
+extern const char * efi_guid_ntoa ( EFI_GUID *guid );
+
+extern void dbg_efi_protocols ( EFI_HANDLE handle );
+extern void dbg_efi_devpath ( EFI_DEVICE_PATH_PROTOCOL *path );
+
+#define DBG_EFI_PROTOCOLS_IF( level, handle ) do {		\
+		if ( DBG_ ## level ) {				\
+			dbg_efi_protocols ( handle );		\
+		}						\
+	} while ( 0 )
+
+#define DBG_EFI_DEVPATH_IF( level, path ) do {			\
+		if ( DBG_ ## level ) {				\
+			dbg_efi_devpath ( path );		\
+		}						\
+	} while ( 0 )
+
+#define DBGC_EFI_PROTOCOLS_IF( level, id, ... ) do {		\
+		DBG_AC_IF ( level, id );			\
+		DBG_EFI_PROTOCOLS_IF ( level, __VA_ARGS__ );	\
+		DBG_DC_IF ( level );				\
+	} while ( 0 )
+
+#define DBGC_EFI_DEVPATH_IF( level, id, ... ) do {		\
+		DBG_AC_IF ( level, id );			\
+		DBG_EFI_DEVPATH_IF ( level, __VA_ARGS__ );	\
+		DBG_DC_IF ( level );				\
+	} while ( 0 )
+
+#define DBGC_EFI_PROTOCOLS( ... )				\
+	DBGC_EFI_PROTOCOLS_IF( LOG, ##__VA_ARGS__ )
+
+#define DBGC_EFI_DEVPATH( ... )					\
+	DBGC_EFI_DEVPATH_IF( LOG, ##__VA_ARGS__ )
+
 extern EFI_STATUS efi_init ( EFI_HANDLE image_handle,
 			     EFI_SYSTEM_TABLE *systab );
 
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_download.h b/roms/ipxe/src/include/ipxe/efi/efi_download.h
new file mode 100644
index 0000000000000000000000000000000000000000..3ce4972219b92f66bc7c931bafedee6c3f023406
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/efi/efi_download.h
@@ -0,0 +1,157 @@
+#ifndef _IPXE_DOWNLOAD_H
+#define _IPXE_DOWNLOAD_H
+
+/*
+ * Copyright (C) 2010 VMware, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * iPXE Download Protocol
+ *
+ * EFI applications started by iPXE may use this interface to download files.
+ */
+
+typedef struct _IPXE_DOWNLOAD_PROTOCOL IPXE_DOWNLOAD_PROTOCOL;
+
+/** Token to represent a currently downloading file */
+typedef VOID *IPXE_DOWNLOAD_FILE;
+
+/**
+ * Callback function that is invoked when data arrives for a particular file.
+ *
+ * Not all protocols will deliver data in order. Clients should not rely on the
+ * order of data delivery matching the order in the file.
+ *
+ * Some protocols are capable of determining the file size near the beginning
+ * of data transfer. To allow the client to allocate memory more efficiently,
+ * iPXE may give a hint about the file size by calling the Data callback with
+ * a zero BufferLength and the file size in FileOffset. Clients should be
+ * prepared to deal with more or less data than the hint actually arriving.
+ *
+ * @v Context		Context provided to the Start function
+ * @v Buffer		New data
+ * @v BufferLength	Length of new data in bytes
+ * @v FileOffset	Offset of new data in the file
+ * @ret Status		EFI_SUCCESS to continue the download,
+ *			or any error code to abort.
+ */
+typedef
+EFI_STATUS
+(EFIAPI *IPXE_DOWNLOAD_DATA_CALLBACK)(
+  IN VOID *Context,
+  IN VOID *Buffer,
+  IN UINTN BufferLength,
+  IN UINTN FileOffset
+  );
+
+/**
+ * Callback function that is invoked when the file is finished downloading, or
+ * when a connection unexpectedly closes or times out.
+ *
+ * The finish callback is also called when a download is aborted by the Abort
+ * function (below).
+ *
+ * @v Context		Context provided to the Start function
+ * @v Status		Reason for termination: EFI_SUCCESS when the entire
+ * 			file was transferred successfully, or an error
+ * 			otherwise
+ */
+typedef
+void
+(EFIAPI *IPXE_DOWNLOAD_FINISH_CALLBACK)(
+  IN VOID *Context,
+  IN EFI_STATUS Status
+  );
+
+/**
+ * Start downloading a file, and register callback functions to handle the
+ * download.
+ *
+ * @v This		iPXE Download Protocol instance
+ * @v Url		URL to download from
+ * @v DataCallback	Callback that will be invoked when data arrives
+ * @v FinishCallback	Callback that will be invoked when the download ends
+ * @v Context		Context passed to the Data and Finish callbacks
+ * @v File		Token that can be used to abort the download
+ * @ret Status		EFI status code
+ */
+typedef
+EFI_STATUS
+(EFIAPI *IPXE_DOWNLOAD_START)(
+  IN IPXE_DOWNLOAD_PROTOCOL *This,
+  IN CHAR8 *Url,
+  IN IPXE_DOWNLOAD_DATA_CALLBACK DataCallback,
+  IN IPXE_DOWNLOAD_FINISH_CALLBACK FinishCallback,
+  IN VOID *Context,
+  OUT IPXE_DOWNLOAD_FILE *File
+  );
+
+/**
+ * Forcibly abort downloading a file that is currently in progress.
+ *
+ * It is not safe to call this function after the Finish callback has executed.
+ *
+ * @v This		iPXE Download Protocol instance
+ * @v File		Token obtained from Start
+ * @v Status		Reason for aborting the download
+ * @ret Status		EFI status code
+ */
+typedef
+EFI_STATUS
+(EFIAPI *IPXE_DOWNLOAD_ABORT)(
+  IN IPXE_DOWNLOAD_PROTOCOL *This,
+  IN IPXE_DOWNLOAD_FILE File,
+  IN EFI_STATUS Status
+  );
+
+/**
+ * Poll for more data from iPXE. This function will invoke the registered
+ * callbacks if data is available or if downloads complete.
+ *
+ * @v This		iPXE Download Protocol instance
+ * @ret Status		EFI status code
+ */
+typedef
+EFI_STATUS
+(EFIAPI *IPXE_DOWNLOAD_POLL)(
+  IN IPXE_DOWNLOAD_PROTOCOL *This
+  );
+
+/**
+ * The iPXE Download Protocol.
+ *
+ * iPXE will attach a iPXE Download Protocol to the DeviceHandle in the Loaded
+ * Image Protocol of all child EFI applications.
+ */
+struct _IPXE_DOWNLOAD_PROTOCOL {
+   IPXE_DOWNLOAD_START Start;
+   IPXE_DOWNLOAD_ABORT Abort;
+   IPXE_DOWNLOAD_POLL Poll;
+};
+
+#define IPXE_DOWNLOAD_PROTOCOL_GUID \
+  { \
+    0x3eaeaebd, 0xdecf, 0x493b, { 0x9b, 0xd1, 0xcd, 0xb2, 0xde, 0xca, 0xe7, 0x19 } \
+  }
+
+extern int efi_download_install ( EFI_HANDLE *device );
+extern void efi_download_uninstall ( EFI_HANDLE device );
+
+#endif /* _IPXE_DOWNLOAD_H */
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_file.h b/roms/ipxe/src/include/ipxe/efi/efi_file.h
new file mode 100644
index 0000000000000000000000000000000000000000..0d75cf5b004817164a04ecc8306002d4188a3ace
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/efi/efi_file.h
@@ -0,0 +1,13 @@
+#ifndef _IPXE_EFI_FILE_H
+#define _IPXE_EFI_FILE_H
+
+/** @file
+ *
+ * EFI file protocols
+ *
+ */
+
+extern int efi_file_install ( EFI_HANDLE *handle );
+extern void efi_file_uninstall ( EFI_HANDLE handle );
+
+#endif /* _IPXE_EFI_FILE_H */
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_hii.h b/roms/ipxe/src/include/ipxe/efi/efi_hii.h
index 1a98750f2cf317d0be0bcc83e5cb..8e94bbe7e3341aeee7838b12893c 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_hii.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_hii.h
@@ -8,133 +8,89 @@
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
+#include <string.h>
 #include <ipxe/efi/Uefi/UefiInternalFormRepresentation.h>
 #include <ipxe/efi/Guid/MdeModuleHii.h>
 
-/**
- * Define an EFI IFR form set type
- *
- * @v num_class_guids	Number of class GUIDs
- * @ret type		Form set type
- */
-#define EFI_IFR_FORM_SET_TYPE( num_class_guids )			   \
-	struct {							   \
-		EFI_IFR_FORM_SET FormSet;				   \
-		EFI_GUID ClassGuid[num_class_guids];			   \
-	} __attribute__ (( packed ))
-
-/**
- * Define an EFI IFR form set
- *
- * @v guid		GUID
- * @v title		Title string
- * @v help		Help string
- * @v type		Form set type (as returned by EFI_IFR_FORM_SET_TYPE())
- * @ret ifr		Form set
- *
- * This definition opens a new scope, which must be closed by an
- * EFI_IFR_END().
- */
-#define EFI_IFR_FORM_SET( guid, title, help, type, ... ) {		   \
-	.FormSet = {							   \
-		.Header = {						   \
-			.OpCode = EFI_IFR_FORM_SET_OP,			   \
-			.Length = sizeof ( type ),			   \
-			.Scope = 1,					   \
-		},							   \
-		.Guid = guid,						   \
-		.FormSetTitle = title,					   \
-		.Help = help,						   \
-		.Flags = ( sizeof ( ( ( type * ) NULL )->ClassGuid ) /	   \
-			   sizeof ( ( ( type * ) NULL )->ClassGuid[0] ) ), \
-	},								   \
-	.ClassGuid = {							   \
-		__VA_ARGS__						   \
-	},								   \
-	}
-
-/**
- * Define an EFI IFR GUID class
- *
- * @v class		Class
- * @ret ifr		GUID class
- */
-#define EFI_IFR_GUID_CLASS( class ) {					   \
-	.Header = {							   \
-		.OpCode = EFI_IFR_GUID_OP,				   \
-		.Length = sizeof ( EFI_IFR_GUID_CLASS ),		   \
-	},								   \
-	.Guid = EFI_IFR_TIANO_GUID,					   \
-	.ExtendOpCode = EFI_IFR_EXTEND_OP_CLASS,			   \
-	.Class = class,							   \
-	}
+/** GUID indicating formset compliance for IBM Unified Configuration Manager */
+#define EFI_HII_IBM_UCM_COMPLIANT_FORMSET_GUID				   \
+	{ 0x5c8e9746, 0xa5f7, 0x4593,					   \
+	  { 0xaf, 0x1f, 0x66, 0xa8, 0x2a, 0xa1, 0x9c, 0xb1 } }
 
-/**
- * Define an EFI IFR GUID subclass
- *
- * @v subclass		Subclass
- * @ret ifr		GUID subclass
- */
-#define EFI_IFR_GUID_SUBCLASS( subclass ) {				   \
-	.Header = {							   \
-		.OpCode = EFI_IFR_GUID_OP,				   \
-		.Length = sizeof ( EFI_IFR_GUID_SUBCLASS ),		   \
-	},								   \
-	.Guid = EFI_IFR_TIANO_GUID,					   \
-	.ExtendOpCode = EFI_IFR_EXTEND_OP_SUBCLASS,			   \
-	.SubClass = subclass,						   \
-	}
+/** An EFI IFR builder */
+struct efi_ifr_builder {
+	/** IFR opcodes */
+	EFI_IFR_OP_HEADER *ops;
+	/** Length of IFR opcodes */
+	size_t ops_len;
+	/** Strings */
+	EFI_HII_STRING_BLOCK *strings;
+	/** Length of strings */
+	size_t strings_len;
+	/** Current string identifier */
+	unsigned int string_id;
+	/** Current variable store identifier */
+	unsigned int varstore_id;
+	/** Current form identifier */
+	unsigned int form_id;
+	/** An allocation has failed */
+	int failed;
+};
 
 /**
- * Define an EFI IFR form
+ * Initialise IFR builder
  *
- * @v formid		Form ID
- * @v title		Title string
- * @ret ifr		Form
+ * @v ifr		IFR builder
  *
- * This definition opens a new scope, which must be closed by an
- * EFI_IFR_END().
+ * The caller must eventually call efi_ifr_free() to free the dynamic
+ * storage associated with the IFR builder.
  */
-#define EFI_IFR_FORM( formid, title ) {					   \
-	.Header = {							   \
-		.OpCode = EFI_IFR_FORM_OP,				   \
-		.Length = sizeof ( EFI_IFR_FORM ),			   \
-		.Scope = 1,						   \
-	},								   \
-	.FormId = formid,						   \
-	.FormTitle = title,						   \
-	}
+static inline void efi_ifr_init ( struct efi_ifr_builder *ifr ) {
+	memset ( ifr, 0, sizeof ( *ifr ) );
+}
 
-/**
- * Define an EFI IFR text widget
- *
- * @v prompt		Prompt string
- * @v help		Help string
- * @v text		Text string
- * @ret ifr		Text widget
- */
-#define EFI_IFR_TEXT( prompt, help, text ) {				   \
-	.Header = {							   \
-		.OpCode = EFI_IFR_TEXT_OP,				   \
-		.Length = sizeof ( EFI_IFR_TEXT ),			   \
-	},								   \
-	.Statement = {							   \
-		.Prompt = prompt,					   \
-		.Help = help,						   \
-	},								   \
-	.TextTwo = text,						   \
-	}
-
-/**
- * Define an EFI IFR end marker
- *
- * @ret ifr		End marker
- */
-#define EFI_IFR_END() {							   \
-	.Header = {							   \
-		.OpCode = EFI_IFR_END_OP,				   \
-		.Length = sizeof ( EFI_IFR_END ),			   \
-	},								   \
-	}
+extern unsigned int efi_ifr_string ( struct efi_ifr_builder *ifr,
+				     const char *fmt, ... );
+extern void efi_ifr_end_op ( struct efi_ifr_builder *ifr );
+extern void efi_ifr_false_op ( struct efi_ifr_builder *ifr );
+extern unsigned int efi_ifr_form_op ( struct efi_ifr_builder *ifr,
+				      unsigned int title_id );
+extern void efi_ifr_form_set_op ( struct efi_ifr_builder *ifr,
+				  const EFI_GUID *guid,
+				  unsigned int title_id, unsigned int help_id,
+				  ... );
+void efi_ifr_get_op ( struct efi_ifr_builder *ifr, unsigned int varstore_id,
+		      unsigned int varstore_info, unsigned int varstore_type );
+extern void efi_ifr_guid_class_op ( struct efi_ifr_builder *ifr,
+				    unsigned int class );
+extern void efi_ifr_guid_subclass_op ( struct efi_ifr_builder *ifr,
+				       unsigned int subclass );
+extern void efi_ifr_numeric_op ( struct efi_ifr_builder *ifr,
+				 unsigned int prompt_id,
+				 unsigned int help_id, unsigned int question_id,
+				 unsigned int varstore_id,
+				 unsigned int varstore_info,
+				 unsigned int vflags, unsigned long min_value,
+				 unsigned long max_value, unsigned int step,
+				 unsigned int flags );
+extern void efi_ifr_string_op ( struct efi_ifr_builder *ifr,
+				unsigned int prompt_id, unsigned int help_id,
+				unsigned int question_id,
+				unsigned int varstore_id,
+				unsigned int varstore_info, unsigned int vflags,
+				unsigned int min_size, unsigned int max_size,
+				unsigned int flags );
+extern void efi_ifr_suppress_if_op ( struct efi_ifr_builder *ifr );
+extern void efi_ifr_text_op ( struct efi_ifr_builder *ifr,
+			      unsigned int prompt_id, unsigned int help_id,
+			      unsigned int text_id );
+extern void efi_ifr_true_op ( struct efi_ifr_builder *ifr );
+extern unsigned int
+efi_ifr_varstore_name_value_op ( struct efi_ifr_builder *ifr,
+				 const EFI_GUID *guid );
+extern void efi_ifr_free ( struct efi_ifr_builder *ifr );
+extern EFI_HII_PACKAGE_LIST_HEADER *
+efi_ifr_package ( struct efi_ifr_builder *ifr, const EFI_GUID *guid,
+		  const char *language, unsigned int language_id );
 
 #endif /* _IPXE_EFI_HII_H */
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_pci.h b/roms/ipxe/src/include/ipxe/efi/efi_pci.h
index 24890eb40bb7670b3ee758c9c242..6429f2109122081e91cc668035d1 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_pci.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_pci.h
@@ -12,6 +12,11 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/efi/Protocol/PciIo.h>
 #include <ipxe/efi/Protocol/DevicePath.h>
 
+/* PciRootBridgeIo.h uses LShiftU64(), which isn't defined anywhere else */
+static inline EFIAPI uint64_t LShiftU64 ( UINT64 value, UINTN shift ) {
+	return ( value << shift );
+}
+
 struct efi_driver;
 struct device;
 
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_snp.h b/roms/ipxe/src/include/ipxe/efi/efi_snp.h
new file mode 100644
index 0000000000000000000000000000000000000000..3791645975d3a4e0595ebe8d61df61ce35d91a37
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/efi/efi_snp.h
@@ -0,0 +1,79 @@
+#ifndef _IPXE_EFI_SNP_H
+#define _IPXE_EFI_SNP_H
+
+/** @file
+ *
+ * iPXE EFI SNP interface
+ *
+ */
+
+#include <ipxe/list.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/Protocol/SimpleNetwork.h>
+#include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h>
+#include <ipxe/efi/Protocol/ComponentName2.h>
+#include <ipxe/efi/Protocol/DevicePath.h>
+#include <ipxe/efi/Protocol/HiiConfigAccess.h>
+#include <ipxe/efi/Protocol/HiiDatabase.h>
+#include <ipxe/efi/Protocol/LoadFile.h>
+
+/** An SNP device */
+struct efi_snp_device {
+	/** List of SNP devices */
+	struct list_head list;
+	/** The underlying iPXE network device */
+	struct net_device *netdev;
+	/** The underlying EFI PCI device */
+	struct efi_pci_device *efipci;
+	/** EFI device handle */
+	EFI_HANDLE handle;
+	/** 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;
+	/** The network interface identifier */
+	EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii;
+	/** Component name protocol */
+	EFI_COMPONENT_NAME2_PROTOCOL name2;
+	/** Load file protocol handle */
+	EFI_LOAD_FILE_PROTOCOL load_file;
+	/** HII configuration access protocol */
+	EFI_HII_CONFIG_ACCESS_PROTOCOL hii;
+	/** HII package list */
+	EFI_HII_PACKAGE_LIST_HEADER *package_list;
+	/** HII handle */
+	EFI_HII_HANDLE hii_handle;
+	/** Device name */
+	wchar_t name[ sizeof ( ( ( struct net_device * ) NULL )->name ) ];
+	/** Driver name */
+	wchar_t driver_name[16];
+	/** Controller name */
+	wchar_t controller_name[32];
+	/** The device path
+	 *
+	 * This field is variable in size and must appear at the end
+	 * of the structure.
+	 */
+	EFI_DEVICE_PATH_PROTOCOL path;
+};
+
+extern int efi_snp_hii_install ( struct efi_snp_device *snpdev );
+extern void efi_snp_hii_uninstall ( struct efi_snp_device *snpdev );
+extern struct efi_snp_device * last_opened_snpdev ( void );
+
+#endif /* _IPXE_EFI_SNP_H */
diff --git a/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h b/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h
index dc226a3e5feac42981918afe7117..79c18972e2257ffb1624ef41e541 100644
--- a/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h
+++ b/roms/ipxe/src/include/ipxe/efi/efi_uaccess.h
@@ -56,6 +56,12 @@ UACCESS_INLINE ( efi, userptr_add ) ( userptr_t userptr, off_t offset ) {
 	return trivial_userptr_add ( userptr, offset );
 }
 
+static inline __always_inline off_t
+UACCESS_INLINE ( efi, userptr_sub ) ( userptr_t userptr,
+				      userptr_t subtrahend ) {
+	return trivial_userptr_sub ( userptr, subtrahend );
+}
+
 static inline __always_inline void
 UACCESS_INLINE ( efi, memcpy_user ) ( userptr_t dest, off_t dest_off,
 					userptr_t src, off_t src_off,
diff --git a/roms/ipxe/src/include/ipxe/efi/import.pl b/roms/ipxe/src/include/ipxe/efi/import.pl
index 2b5d3e93968934688074add0ada6..995514681a03db738b7166237bce 100755
--- a/roms/ipxe/src/include/ipxe/efi/import.pl
+++ b/roms/ipxe/src/include/ipxe/efi/import.pl
@@ -59,6 +59,7 @@ sub try_import_file {
       open my $outfh, ">$outfile" or die "Could not open $outfile: $!\n";
       my @dependencies = ();
       my $licence;
+      my $maybe_guard;
       my $guard;
       while ( <$infh> ) {
 	# Strip CR and trailing whitespace
@@ -77,10 +78,16 @@ sub try_import_file {
 	# Write out line
 	print $outfh "$_\n";
 	# Apply FILE_LICENCE() immediately after include guard
-	if ( /^\#define\s+_?_\S+_H_?_$/ ) {
-	  die "Duplicate header guard detected in $infile\n" if $guard;
-	  $guard = 1;
-	  print $outfh "\nFILE_LICENCE ( $licence );\n" if $licence;
+	if ( defined $maybe_guard ) {
+	  if ( /^\#define\s+_?_${maybe_guard}_?_$/ ) {
+	    die "Duplicate header guard detected in $infile\n" if $guard;
+	    $guard = $maybe_guard;
+	    print $outfh "\nFILE_LICENCE ( $licence );\n" if $licence;
+	  }
+	  undef $maybe_guard;
+	}
+	if ( /^#ifndef\s+_?_(\S+)_?_/ ) {
+	  $maybe_guard = $1;
 	}
       }
       close $outfh;
diff --git a/roms/ipxe/src/include/ipxe/elf.h b/roms/ipxe/src/include/ipxe/elf.h
index e5fed2f89d68d9c05a83edf8aff6..ec675c0473d7ce1f26a854345605 100644
--- a/roms/ipxe/src/include/ipxe/elf.h
+++ b/roms/ipxe/src/include/ipxe/elf.h
@@ -12,6 +12,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <elf.h>
 
-extern int elf_load ( struct image *image, physaddr_t *entry );
+extern int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max );
 
 #endif /* _IPXE_ELF_H */
diff --git a/roms/ipxe/src/include/ipxe/eltorito.h b/roms/ipxe/src/include/ipxe/eltorito.h
new file mode 100644
index 0000000000000000000000000000000000000000..3302b38b6fa115ed7ca20e21a54de41b598eda71
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/eltorito.h
@@ -0,0 +1,103 @@
+#ifndef _IPXE_ELTORITO_H
+#define _IPXE_ELTORITO_H
+
+/**
+ * @file
+ *
+ * El Torito bootable CD-ROM specification
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/iso9660.h>
+
+/** An El Torito Boot Record Volume Descriptor (fixed portion) */
+struct eltorito_descriptor_fixed {
+	/** Descriptor type */
+	uint8_t type;
+	/** Identifier ("CD001") */
+	uint8_t id[5];
+	/** Version, must be 1 */
+	uint8_t version;
+	/** Boot system indicator; must be "EL TORITO SPECIFICATION" */
+	uint8_t system_id[32];
+} __attribute__ (( packed ));
+
+/** An El Torito Boot Record Volume Descriptor */
+struct eltorito_descriptor {
+	/** Fixed portion */
+	struct eltorito_descriptor_fixed fixed;
+	/** Unused */
+	uint8_t unused[32];
+	/** Boot catalog sector */
+	uint32_t sector;
+} __attribute__ (( packed ));
+
+/** El Torito Boot Record Volume Descriptor block address */
+#define ELTORITO_LBA 17
+
+/** An El Torito Boot Catalog Validation Entry */
+struct eltorito_validation_entry {
+	/** Header ID; must be 1 */
+	uint8_t header_id;
+	/** Platform ID
+	 *
+	 * 0 = 80x86
+	 * 1 = PowerPC
+	 * 2 = Mac
+	 */
+	uint8_t platform_id;
+	/** Reserved */
+	uint16_t reserved;
+	/** ID string */
+	uint8_t id_string[24];
+	/** Checksum word */
+	uint16_t checksum;
+	/** Signature; must be 0xaa55 */
+	uint16_t signature;
+} __attribute__ (( packed ));
+
+/** El Torito platform IDs */
+enum eltorito_platform_id {
+	ELTORITO_PLATFORM_X86 = 0x00,
+	ELTORITO_PLATFORM_POWERPC = 0x01,
+	ELTORITO_PLATFORM_MAC = 0x02,
+};
+
+/** A bootable entry in the El Torito Boot Catalog */
+struct eltorito_boot_entry {
+	/** Boot indicator
+	 *
+	 * Must be @c ELTORITO_BOOTABLE for a bootable ISO image
+	 */
+	uint8_t indicator;
+	/** Media type
+	 *
+	 */
+	uint8_t media_type;
+	/** Load segment */
+	uint16_t load_segment;
+	/** System type */
+	uint8_t filesystem;
+	/** Unused */
+	uint8_t reserved_a;
+	/** Sector count */
+	uint16_t length;
+	/** Starting sector */
+	uint32_t start;
+	/** Unused */
+	uint8_t reserved_b[20];
+} __attribute__ (( packed ));
+
+/** Boot indicator for a bootable ISO image */
+#define ELTORITO_BOOTABLE 0x88
+
+/** El Torito media types */
+enum eltorito_media_type {
+	/** No emulation */
+	ELTORITO_NO_EMULATION = 0,
+};
+
+#endif /* _IPXE_ELTORITO_H */
diff --git a/roms/ipxe/src/include/ipxe/entropy.h b/roms/ipxe/src/include/ipxe/entropy.h
new file mode 100644
index 0000000000000000000000000000000000000000..adf325e79a4162d5dc3344cb70ee186de2743918
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/entropy.h
@@ -0,0 +1,224 @@
+#ifndef _IPXE_ENTROPY_H
+#define _IPXE_ENTROPY_H
+
+/** @file
+ *
+ * Entropy source
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <ipxe/api.h>
+#include <ipxe/hash_df.h>
+#include <ipxe/sha256.h>
+#include <config/entropy.h>
+
+/**
+ * Calculate static inline entropy API function name
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @ret _subsys_func	Subsystem API function
+ */
+#define ENTROPY_INLINE( _subsys, _api_func ) \
+	SINGLE_API_INLINE ( ENTROPY_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide a entropy API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @v _func		Implementing function
+ */
+#define PROVIDE_ENTROPY( _subsys, _api_func, _func ) \
+	PROVIDE_SINGLE_API ( ENTROPY_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline entropy API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ */
+#define PROVIDE_ENTROPY_INLINE( _subsys, _api_func ) \
+	PROVIDE_SINGLE_API_INLINE ( ENTROPY_PREFIX_ ## _subsys, _api_func )
+
+/** A noise sample */
+typedef uint8_t noise_sample_t;
+
+/** An entropy sample */
+typedef uint8_t entropy_sample_t;
+
+/* Include all architecture-independent entropy API headers */
+#include <ipxe/null_entropy.h>
+#include <ipxe/linux/linux_entropy.h>
+
+/* Include all architecture-dependent entropy API headers */
+#include <bits/entropy.h>
+
+/**
+ * Enable entropy gathering
+ *
+ * @ret rc		Return status code
+ */
+int entropy_enable ( void );
+
+/**
+ * Disable entropy gathering
+ *
+ */
+void entropy_disable ( void );
+
+/**
+ * min-entropy per sample
+ *
+ * @ret min_entropy	min-entropy of each sample
+ *
+ * min-entropy is defined in ANS X9.82 Part 1-2006 Section 8.3 and in
+ * NIST SP 800-90 Appendix C.3 as
+ *
+ *    H_min = -log2 ( p_max )
+ *
+ * where p_max is the probability of the most likely sample value.
+ *
+ * This must be a compile-time constant.
+ */
+double min_entropy_per_sample ( void );
+
+/**
+ * Get noise sample
+ *
+ * @ret noise		Noise sample
+ * @ret rc		Return status code
+ *
+ * This is the GetNoise function defined in ANS X9.82 Part 2
+ * (October 2011 Draft) Section 6.5.2.
+ */
+int get_noise ( noise_sample_t *noise );
+
+extern int get_entropy_input_tmp ( unsigned int num_samples,
+				   uint8_t *tmp, size_t tmp_len );
+
+/** Use SHA-256 as the underlying hash algorithm for Hash_df
+ *
+ * Hash_df using SHA-256 is an Approved algorithm in ANS X9.82.
+ */
+#define entropy_hash_df_algorithm sha256_algorithm
+
+/** Underlying hash algorithm output length (in bytes) */
+#define ENTROPY_HASH_DF_OUTLEN_BYTES SHA256_DIGEST_SIZE
+
+/**
+ * Obtain entropy input
+ *
+ * @v min_entropy_bits	Minimum amount of entropy, in bits
+ * @v data		Data buffer
+ * @v min_len		Minimum length of entropy input, in bytes
+ * @v max_len		Maximum length of entropy input, in bytes
+ * @ret len		Length of entropy input, in bytes, or negative error
+ *
+ * This is the implementation of the Get_entropy_input function (using
+ * an entropy source as the source of entropy input and condensing
+ * each entropy source output after each GetEntropy call) as defined
+ * in ANS X9.82 Part 4 (April 2011 Draft) Section 13.3.4.2.
+ *
+ * To minimise code size, the number of samples required is calculated
+ * at compilation time.
+ */
+static inline __attribute__ (( always_inline )) int
+get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len,
+		    size_t max_len ) {
+	size_t tmp_len = ( ( ( min_entropy_bits * 2 ) + 7 ) / 8 );
+	uint8_t tmp_buf[ tmp_len ];
+	uint8_t *tmp = ( ( tmp_len > max_len ) ? tmp_buf : data );
+	double min_samples;
+	unsigned int num_samples;
+	unsigned int n;
+	int rc;
+
+	/* Sanity checks */
+	linker_assert ( ( min_entropy_per_sample() <=
+			  ( 8 * sizeof ( noise_sample_t ) ) ),
+			min_entropy_per_sample_is_impossibly_high );
+	linker_assert ( ( min_entropy_bits <= ( 8 * max_len ) ),
+			entropy_buffer_too_small );
+
+	/* Round up minimum entropy to an integral number of bytes */
+	min_entropy_bits = ( ( min_entropy_bits + 7 ) & ~7 );
+
+	/* Calculate number of samples required to contain sufficient entropy */
+	min_samples = ( ( min_entropy_bits * 1.0 ) / min_entropy_per_sample() );
+
+	/* Round up to a whole number of samples.  We don't have the
+	 * ceil() function available, so do the rounding by hand.
+	 */
+	num_samples = min_samples;
+	if ( num_samples < min_samples )
+		num_samples++;
+	linker_assert ( ( num_samples >= min_samples ), rounding_error );
+
+	/* Floating-point operations are not allowed in iPXE since we
+	 * never set up a suitable environment.  Abort the build
+	 * unless the calculated number of samples is a compile-time
+	 * constant.
+	 */
+	linker_assert ( __builtin_constant_p ( num_samples ),
+			num_samples_not_constant );
+
+	/* (Unnumbered).  The output length of the hash function shall
+	 * meet or exceed the security strength indicated by the
+	 * min_entropy parameter.
+	 */
+	linker_assert ( ( ( 8 * ENTROPY_HASH_DF_OUTLEN_BYTES ) >=
+			  min_entropy_bits ), hash_df_algorithm_too_weak );
+
+	/* 1.  If ( min_length > max_length ), then return ( FAILURE, Null ) */
+	linker_assert ( ( min_len <= max_len ), min_len_greater_than_max_len );
+
+	/* 2.  n = 2 * min_entropy */
+	n = ( 2 * min_entropy_bits );
+
+	/* 3.  entropy_total = 0
+	 * 4.  tmp = a fixed n-bit value, such as 0^n
+	 * 5.  While ( entropy_total < min_entropy )
+	 *     5.1.  ( status, entropy_bitstring, assessed_entropy )
+	 *           = GetEntropy()
+	 *     5.2.  If status indicates an error, return ( status, Null )
+	 *     5.3.  nonce = MakeNextNonce()
+	 *     5.4.  tmp = tmp XOR df ( ( nonce || entropy_bitstring ), n )
+	 *     5.5.  entropy_total = entropy_total + assessed_entropy
+	 *
+	 * (The implementation of these steps is inside the function
+	 * get_entropy_input_tmp().)
+	 */
+	linker_assert ( __builtin_constant_p ( tmp_len ),
+			tmp_len_not_constant );
+	linker_assert ( ( n == ( 8 * tmp_len ) ), tmp_len_mismatch );
+	if ( ( rc = get_entropy_input_tmp ( num_samples, tmp, tmp_len ) ) != 0 )
+		return rc;
+
+	/* 6.  If ( n < min_length ), then tmp = tmp || 0^(min_length-n)
+	 * 7.  If ( n > max_length ), then tmp = df ( tmp, max_length )
+	 * 8.  Return ( SUCCESS, tmp )
+	 */
+	if ( tmp_len < min_len ) {
+		/* (Data is already in-place.) */
+		linker_assert ( ( data == tmp ), data_not_inplace );
+		memset ( ( data + tmp_len ), 0, ( min_len - tmp_len ) );
+		return min_len;
+	} else if ( tmp_len > max_len ) {
+		linker_assert ( ( tmp == tmp_buf ), data_inplace );
+		hash_df ( &entropy_hash_df_algorithm, tmp, tmp_len,
+			  data, max_len );
+		return max_len;
+	} else {
+		/* (Data is already in-place.) */
+		linker_assert ( ( data == tmp ), data_not_inplace );
+		return tmp_len;
+	}
+}
+
+#endif /* _IPXE_ENTROPY_H */
diff --git a/roms/ipxe/src/include/ipxe/errfile.h b/roms/ipxe/src/include/ipxe/errfile.h
index 3073383baa22326003e7065f8bc0..514e1f8aef00475e017aedfd7f58 100644
--- a/roms/ipxe/src/include/ipxe/errfile.h
+++ b/roms/ipxe/src/include/ipxe/errfile.h
@@ -60,6 +60,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ERRFILE_null_sanboot	       ( ERRFILE_CORE | 0x00140000 )
 #define ERRFILE_edd		       ( ERRFILE_CORE | 0x00150000 )
 #define ERRFILE_parseopt	       ( ERRFILE_CORE | 0x00160000 )
+#define ERRFILE_test		       ( ERRFILE_CORE | 0x00170000 )
+#define ERRFILE_xferbuf		       ( ERRFILE_CORE | 0x00180000 )
+#define ERRFILE_pending		       ( ERRFILE_CORE | 0x00190000 )
 
 #define ERRFILE_eisa		     ( ERRFILE_DRIVER | 0x00000000 )
 #define ERRFILE_isa		     ( ERRFILE_DRIVER | 0x00010000 )
@@ -137,6 +140,14 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ERRFILE_virtio_net	     ( ERRFILE_DRIVER | 0x005c0000 )
 #define ERRFILE_tap		     ( ERRFILE_DRIVER | 0x005d0000 )
 #define ERRFILE_igbvf_main	     ( ERRFILE_DRIVER | 0x005e0000 )
+#define ERRFILE_ath9k		     ( ERRFILE_DRIVER | 0x005f0000 )
+#define ERRFILE_ath		     ( ERRFILE_DRIVER | 0x00600000 )
+#define ERRFILE_vmxnet3		     ( ERRFILE_DRIVER | 0x00610000 )
+#define ERRFILE_mii		     ( ERRFILE_DRIVER | 0x00620000 )
+#define ERRFILE_realtek		     ( ERRFILE_DRIVER | 0x00630000 )
+#define ERRFILE_skeleton	     ( ERRFILE_DRIVER | 0x00640000 )
+#define ERRFILE_intel		     ( ERRFILE_DRIVER | 0x00650000 )
+#define ERRFILE_myson		     ( ERRFILE_DRIVER | 0x00660000 )
 
 #define ERRFILE_scsi		     ( ERRFILE_DRIVER | 0x00700000 )
 #define ERRFILE_arbel		     ( ERRFILE_DRIVER | 0x00710000 )
@@ -158,7 +169,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ERRFILE_nullnet			( ERRFILE_NET | 0x00090000 )
 #define ERRFILE_tcp			( ERRFILE_NET | 0x000a0000 )
 #define ERRFILE_ftp			( ERRFILE_NET | 0x000b0000 )
-#define ERRFILE_http			( ERRFILE_NET | 0x000c0000 )
+#define ERRFILE_httpcore		( ERRFILE_NET | 0x000c0000 )
 #define ERRFILE_iscsi			( ERRFILE_NET | 0x000d0000 )
 #define ERRFILE_tcpip			( ERRFILE_NET | 0x000e0000 )
 #define ERRFILE_udp			( ERRFILE_NET | 0x000f0000 )
@@ -239,6 +250,21 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ERRFILE_bofm		      ( ERRFILE_OTHER | 0x00210000 )
 #define ERRFILE_prompt		      ( ERRFILE_OTHER | 0x00220000 )
 #define ERRFILE_nvo_cmd		      ( ERRFILE_OTHER | 0x00230000 )
+#define ERRFILE_hmac_drbg	      ( ERRFILE_OTHER | 0x00240000 )
+#define ERRFILE_drbg		      ( ERRFILE_OTHER | 0x00250000 )
+#define ERRFILE_entropy		      ( ERRFILE_OTHER | 0x00260000 )
+#define ERRFILE_rsa		      ( ERRFILE_OTHER | 0x00270000 )
+#define ERRFILE_linux_entropy	      ( ERRFILE_OTHER | 0x00280000 )
+#define ERRFILE_x509_test	      ( ERRFILE_OTHER | 0x00290000 )
+#define ERRFILE_cms		      ( ERRFILE_OTHER | 0x002a0000 )
+#define ERRFILE_imgtrust	      ( ERRFILE_OTHER | 0x002b0000 )
+#define ERRFILE_menu_ui		      ( ERRFILE_OTHER | 0x002c0000 )
+#define ERRFILE_menu_cmd	      ( ERRFILE_OTHER | 0x002d0000 )
+#define ERRFILE_validator	      ( ERRFILE_OTHER | 0x002e0000 )
+#define ERRFILE_ocsp		      ( ERRFILE_OTHER | 0x002f0000 )
+#define ERRFILE_nslookup	      ( ERRFILE_OTHER | 0x00300000 )
+#define ERRFILE_efi_snp_hii	      ( ERRFILE_OTHER | 0x00310000 )
+#define ERRFILE_readline	      ( ERRFILE_OTHER | 0x00320000 )
 
 /** @} */
 
diff --git a/roms/ipxe/src/include/ipxe/ethernet.h b/roms/ipxe/src/include/ipxe/ethernet.h
index 7e49655a33d1dbd650795ad98978..1794ff67ee37e58f118e91c97064 100644
--- a/roms/ipxe/src/include/ipxe/ethernet.h
+++ b/roms/ipxe/src/include/ipxe/ethernet.h
@@ -10,6 +10,8 @@
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/iobuf.h>
 
 /**
  * Check if Ethernet address is all zeroes
@@ -77,6 +79,13 @@ static inline int is_valid_ether_addr ( const void *addr ) {
 		 ( ! is_zero_ether_addr ( addr ) ) );
 }
 
+extern uint8_t eth_broadcast[];
+extern int eth_push ( struct net_device *netdev, struct io_buffer *iobuf,
+		      const void *ll_dest, const void *ll_source,
+		      uint16_t net_proto );
+extern int eth_pull ( struct net_device *netdev, struct io_buffer *iobuf,
+		      const void **ll_dest, const void **ll_source,
+		      uint16_t *net_proto, unsigned int *flags );
 extern void eth_init_addr ( const void *hw_addr, void *ll_addr );
 extern const char * eth_ntoa ( const void *ll_addr );
 extern int eth_mc_hash ( unsigned int af, const void *net_addr,
diff --git a/roms/ipxe/src/include/ipxe/fc.h b/roms/ipxe/src/include/ipxe/fc.h
index ab6b5bae77cf5bc2516f822a08f8..6689f394e489decc67c43767daf3 100644
--- a/roms/ipxe/src/include/ipxe/fc.h
+++ b/roms/ipxe/src/include/ipxe/fc.h
@@ -357,7 +357,15 @@ struct fc_peer {
 
 	/** List of upper-layer protocols */
 	struct list_head ulps;
-	/** Active usage count */
+	/** Active usage count
+	 *
+	 * A peer (and attached ULPs) may be created in response to
+	 * unsolicited login requests received via the fabric.  We
+	 * track our own active usage count independently of the
+	 * existence of the peer, so that if the peer becomes logged
+	 * out (e.g. due to a link failure) then we know whether or
+	 * not we should attempt to relogin.
+	 */
 	unsigned int usage;
 };
 
@@ -424,8 +432,15 @@ struct fc_ulp {
 	/** Service parameter length */
 	size_t param_len;
 
-	/** Active usage count */
-	unsigned int usage;
+	/** Active users of this upper-layer protocol
+	 *
+	 * As with peers, an upper-layer protocol may be created in
+	 * response to an unsolicited login request received via the
+	 * fabric.  This list records the number of active users of
+	 * the ULP; the number of entries in the list is equivalent to
+	 * the peer usage count.
+	 */
+	struct list_head users;
 };
 
 /** Fibre Channel upper-layer protocol flags */
@@ -434,6 +449,21 @@ enum fc_ulp_flags {
 	FC_ULP_ORIGINATED_LOGIN_OK = 0x0001,
 };
 
+/** A Fibre Channel upper-layer protocol user */
+struct fc_ulp_user {
+	/** Fibre Channel upper layer protocol */
+	struct fc_ulp *ulp;
+	/** List of users */
+	struct list_head list;
+	/** Containing object reference count, or NULL */
+	struct refcnt *refcnt;
+	/** Examine link state
+	 *
+	 * @v user		Fibre Channel upper-layer-protocol user
+	 */
+	void ( * examine ) ( struct fc_ulp_user *user );
+};
+
 /**
  * Get reference to Fibre Channel upper-layer protocol
  *
@@ -456,14 +486,51 @@ fc_ulp_put ( struct fc_ulp *ulp ) {
 	ref_put ( &ulp->refcnt );
 }
 
+/**
+ * Get reference to Fibre Channel upper-layer protocol user
+ *
+ * @v user		Fibre Channel upper-layer protocol user
+ * @ret user		Fibre Channel upper-layer protocol user
+ */
+static inline __attribute__ (( always_inline )) struct fc_ulp_user *
+fc_ulp_user_get ( struct fc_ulp_user *user ) {
+	ref_get ( user->refcnt );
+	return user;
+}
+
+/**
+ * Drop reference to Fibre Channel upper-layer protocol user
+ *
+ * @v user		Fibre Channel upper-layer protocol user
+ */
+static inline __attribute__ (( always_inline )) void
+fc_ulp_user_put ( struct fc_ulp_user *user ) {
+	ref_put ( user->refcnt );
+}
+
+/**
+ * Initialise Fibre Channel upper-layer protocol user
+ *
+ * @v user		Fibre Channel upper-layer protocol user
+ * @v examine		Examine link state method
+ * @v refcnt		Containing object reference count, or NULL
+ */
+static inline __attribute__ (( always_inline )) void
+fc_ulp_user_init ( struct fc_ulp_user *user,
+		   void ( * examine ) ( struct fc_ulp_user *user ),
+		   struct refcnt *refcnt ) {
+	user->examine = examine;
+	user->refcnt = refcnt;
+}
+
 extern struct fc_ulp * fc_ulp_get_wwn_type ( const struct fc_name *port_wwn,
 					     unsigned int type );
 extern struct fc_ulp *
 fc_ulp_get_port_id_type ( struct fc_port *port,
 			  const struct fc_port_id *peer_port_id,
 			  unsigned int type );
-extern void fc_ulp_increment ( struct fc_ulp *ulp );
-extern void fc_ulp_decrement ( struct fc_ulp *ulp );
+extern void fc_ulp_attach ( struct fc_ulp *ulp, struct fc_ulp_user *user );
+extern void fc_ulp_detach ( struct fc_ulp_user *user );
 extern int fc_ulp_login ( struct fc_ulp *ulp, const void *param,
 			  size_t param_len, int originated );
 extern void fc_ulp_logout ( struct fc_ulp *ulp, int rc );
diff --git a/roms/ipxe/src/include/ipxe/features.h b/roms/ipxe/src/include/ipxe/features.h
index 660015cd2a97780092b3c8622e54..0c92f5be9daeeb3cfffc0c1ab9cd 100644
--- a/roms/ipxe/src/include/ipxe/features.h
+++ b/roms/ipxe/src/include/ipxe/features.h
@@ -52,6 +52,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define DHCP_EB_FEATURE_EFI		0x24 /**< EFI format */
 #define DHCP_EB_FEATURE_FCOE		0x25 /**< FCoE protocol */
 #define DHCP_EB_FEATURE_VLAN		0x26 /**< VLAN support */
+#define DHCP_EB_FEATURE_MENU		0x27 /**< Menu support */
+#define DHCP_EB_FEATURE_SDI		0x28 /**< SDI image support */
 
 /** @} */
 
diff --git a/roms/ipxe/src/include/ipxe/fip.h b/roms/ipxe/src/include/ipxe/fip.h
index b81e8604e49a575552e28b251b33..8729233750e5d7b1992a871647ae 100644
--- a/roms/ipxe/src/include/ipxe/fip.h
+++ b/roms/ipxe/src/include/ipxe/fip.h
@@ -16,7 +16,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #include <stdint.h>
diff --git a/roms/ipxe/src/include/ipxe/hash_df.h b/roms/ipxe/src/include/ipxe/hash_df.h
new file mode 100644
index 0000000000000000000000000000000000000000..607a4a610050b8bcfd2bf8cf426309f70a03887b
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/hash_df.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_HASH_DF_H
+#define _IPXE_HASH_DF_H
+
+/** @file
+ *
+ * Hash-based derivation function (Hash_df)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/crypto.h>
+
+extern void hash_df ( struct digest_algorithm *hash, const void *input,
+		      size_t input_len, void *output, size_t output_len );
+
+#endif /* _IPXE_HASH_DF_H */
diff --git a/roms/ipxe/src/include/ipxe/hmac_drbg.h b/roms/ipxe/src/include/ipxe/hmac_drbg.h
new file mode 100644
index 0000000000000000000000000000000000000000..8dfd2924f64409a1f3e48a704932d1ebf6ce0852
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/hmac_drbg.h
@@ -0,0 +1,253 @@
+#ifndef _IPXE_HMAC_DRBG_H
+#define _IPXE_HMAC_DRBG_H
+
+/** @file
+ *
+ * HMAC_DRBG algorithm
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/crypto.h>
+
+/** Declare an HMAC_DRBG algorithm
+ *
+ * @v hash			Underlying hash algorithm
+ * @v max_security_strength	Maxmimum security strength
+ * @v out_len_bits		Output block length, in bits
+ * @ret hmac_drbg		HMAC_DRBG algorithm
+ */
+#define HMAC_DRBG( hash, max_security_strength, out_len_bits ) \
+	( hash, max_security_strength, out_len_bits )
+
+/** HMAC_DRBG using SHA-1
+ *
+ * The maximum security strength of HMAC_DRBG using SHA-1 is 128 bits
+ * according to the list of maximum security strengths documented in
+ * NIST SP 800-57 Part 1 Section 5.6.1 Table 3.
+ *
+ * The output block length of HMAC_DRBG using SHA-1 is 160 bits
+ * according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 (NIST SP
+ * 800-90 Section 10.1 Table 2).
+ */
+#define HMAC_DRBG_SHA1 HMAC_DRBG ( &sha1_algorithm, 128, 160 )
+
+/** HMAC_DRBG using SHA-224
+ *
+ * The maximum security strength of HMAC_DRBG using SHA-224 is 192
+ * bits according to the list of maximum security strengths documented
+ * in NIST SP 800-57 Part 1 Section 5.6.1 Table 3.
+ *
+ * The output block length of HMAC_DRBG using SHA-224 is 224 bits
+ * according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 (NIST SP
+ * 800-90 Section 10.1 Table 2).
+ */
+#define HMAC_DRBG_SHA224 HMAC_DRBG ( &sha224_algorithm, 192, 224 )
+
+/** HMAC_DRBG using SHA-256
+ *
+ * The maximum security strength of HMAC_DRBG using SHA-256 is 256
+ * bits according to the list of maximum security strengths documented
+ * in NIST SP 800-57 Part 1 Section 5.6.1 Table 3.
+ *
+ * The output block length of HMAC_DRBG using SHA-256 is 256 bits
+ * according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 (NIST SP
+ * 800-90 Section 10.1 Table 2).
+ */
+#define HMAC_DRBG_SHA256 HMAC_DRBG ( &sha256_algorithm, 256, 256 )
+
+/** HMAC_DRBG using SHA-384
+ *
+ * The maximum security strength of HMAC_DRBG using SHA-384 is 256
+ * bits according to the list of maximum security strengths documented
+ * in NIST SP 800-57 Part 1 Section 5.6.1 Table 3.
+ *
+ * The output block length of HMAC_DRBG using SHA-384 is 384 bits
+ * according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 (NIST SP
+ * 800-90 Section 10.1 Table 2).
+ */
+#define HMAC_DRBG_SHA384 HMAC_DRBG ( &sha384_algorithm, 256, 384 )
+
+/** HMAC_DRBG using SHA-512
+ *
+ * The maximum security strength of HMAC_DRBG using SHA-512 is 256
+ * bits according to the list of maximum security strengths documented
+ * in NIST SP 800-57 Part 1 Section 5.6.1 Table 3.
+ *
+ * The output block length of HMAC_DRBG using SHA-512 is 512 bits
+ * according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 (NIST SP
+ * 800-90 Section 10.1 Table 2).
+ */
+#define HMAC_DRBG_SHA512 HMAC_DRBG ( &sha512_algorithm, 256, 512 )
+
+/** Underlying hash algorithm
+ *
+ * @v hmac_drbg			HMAC_DRBG algorithm
+ * @ret hash			Underlying hash algorithm
+ */
+#define HMAC_DRBG_HASH( hmac_drbg ) \
+	HMAC_DRBG_EXTRACT_HASH hmac_drbg
+#define HMAC_DRBG_EXTRACT_HASH( hash, max_security_strength, out_len_bits ) \
+	hash
+
+/** Maximum security strength
+ *
+ * @v hmac_drbg			HMAC_DRBG algorithm
+ * @ret max_security_strength	Maxmimum security strength
+ */
+#define HMAC_DRBG_MAX_SECURITY_STRENGTH( hmac_drbg ) \
+	HMAC_DRBG_EXTRACT_MAX_SECURITY_STRENGTH hmac_drbg
+#define HMAC_DRBG_EXTRACT_MAX_SECURITY_STRENGTH( hash, max_security_strength, \
+						 out_len_bits ) \
+	max_security_strength
+
+/** Output block length, in bits
+ *
+ * @v hmac_drbg			HMAC_DRBG algorithm
+ * @ret out_len_bits		Output block length, in bits
+ */
+#define HMAC_DRBG_OUTLEN_BITS( hmac_drbg ) \
+	HMAC_DRBG_EXTRACT_OUTLEN_BITS hmac_drbg
+#define HMAC_DRBG_EXTRACT_OUTLEN_BITS( hash, max_security_strength, \
+				       out_len_bits ) \
+	out_len_bits
+
+/** Output block length, in bytes
+ *
+ * @v hmac_drbg			HMAC_DRBG algorithm
+ * @ret out_len_bytes		Output block length, in bytes
+ */
+#define HMAC_DRBG_OUTLEN_BYTES( hmac_drbg ) \
+	( HMAC_DRBG_OUTLEN_BITS ( hmac_drbg ) / 8 )
+
+/** Maximum output block length, in bytes
+ *
+ * The maximum output block length for HMAC_DRBG is 512 bits for
+ * SHA-512 according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2
+ * (NIST SP 800-90 Section 10.1 Table 2).
+ */
+#define HMAC_DRBG_MAX_OUTLEN_BYTES HMAC_DRBG_OUTLEN_BYTES ( HMAC_DRBG_SHA512 )
+
+/** Required minimum entropy for instantiate and reseed
+ *
+ * @v security_strength		Security strength
+ * @ret min_entropy		Required minimum entropy
+ *
+ * The minimum required entropy for HMAC_DRBG is equal to the security
+ * strength according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2
+ * (NIST SP 800-90 Section 10.1 Table 2).
+ */
+#define HMAC_DRBG_MIN_ENTROPY( security_strength ) (security_strength)
+
+/** Minimum entropy input length
+ *
+ * @v security_strength		Security strength
+ * @ret min_entropy_len_bytes	Required minimum entropy length (in bytes)
+ *
+ * The minimum entropy input length for HMAC_DRBG is equal to the
+ * security strength according to ANS X9.82 Part 3-2007 Section 10.2.1
+ * Table 2 (NIST SP 800-90 Section 10.1 Table 2).
+ */
+#define HMAC_DRBG_MIN_ENTROPY_LEN_BYTES( security_strength ) \
+	( (security_strength) / 8 )
+
+/** Maximum entropy input length
+ *
+ * The maximum entropy input length for HMAC_DRBG is 2^35 bits
+ * according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 (NIST SP
+ * 800-90 Section 10.1 Table 2).
+ *
+ * We choose to allow up to 32 bytes.
+ */
+#define HMAC_DRBG_MAX_ENTROPY_LEN_BYTES 32
+
+/** Maximum personalisation string length
+ *
+ * The maximum permitted personalisation string length for HMAC_DRBG
+ * is 2^35 bits according to ANS X9.82 Part 3-2007 Section 10.2.1
+ * Table 1 (NIST SP 800-90 Section 10.1 Table 2).
+ *
+ * We choose to allow up to 2^32-1 bytes (i.e. 2^35-8 bits).
+ */
+#define HMAC_DRBG_MAX_PERSONAL_LEN_BYTES 0xffffffffUL
+
+/** Maximum additional input length
+ *
+ * The maximum permitted additional input length for HMAC_DRBG is 2^35
+ * bits according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 1
+ * (NIST SP 800-90 Section 10.1 Table 2).
+ *
+ * We choose to allow up to 2^32-1 bytes (i.e. 2^35-8 bits).
+ */
+#define HMAC_DRBG_MAX_ADDITIONAL_LEN_BYTES 0xffffffffUL
+
+/** Maximum length of generated pseudorandom data per request
+ *
+ * The maximum number of bits per request for HMAC_DRBG is 2^19 bits
+ * according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 1 (NIST SP
+ * 800-90 Section 10.1 Table 2).
+ *
+ * We choose to allow up to 2^16-1 bytes (i.e. 2^19-8 bits).
+ */
+#define HMAC_DRBG_MAX_GENERATED_LEN_BYTES 0x0000ffffUL
+
+/** Reseed interval
+ *
+ * The maximum permitted reseed interval for HMAC_DRBG is 2^48
+ * according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 (NIST SP
+ * 800-90 Section 10.1 Table 2).  However, the sample implementation
+ * given in ANS X9.82 Part 3-2007 Annex E.2.1 (NIST SP 800-90 Appendix
+ * F.2) shows a reseed interval of 10000.
+ *
+ * We choose a very conservative reseed interval.
+ */
+#define HMAC_DRBG_RESEED_INTERVAL 1024
+
+/**
+ * HMAC_DRBG internal state
+ *
+ * This structure is defined by ANS X9.82 Part 3-2007 Section
+ * 10.2.2.2.1 (NIST SP 800-90 Section 10.1.2.1).
+ *
+ * The "administrative information" portions (security_strength and
+ * prediction_resistance) are design-time constants and so are not
+ * present as fields in this structure.
+ */
+struct hmac_drbg_state {
+	/** Current value
+	 *
+	 * "The value V of outlen bits, which is updated each time
+	 * another outlen bits of output are produced"
+	 */
+	uint8_t value[HMAC_DRBG_MAX_OUTLEN_BYTES];
+	/** Current key
+	 *
+	 * "The outlen-bit Key, which is updated at least once each
+	 * time that the DRBG mechanism generates pseudorandom bits."
+	 */
+	uint8_t key[HMAC_DRBG_MAX_OUTLEN_BYTES];
+	/** Reseed counter
+	 *
+	 * "A counter (reseed_counter) that indicates the number of
+	 * requests for pseudorandom bits since instantiation or
+	 * reseeding"
+	 */
+	unsigned int reseed_counter;
+};
+
+extern void hmac_drbg_instantiate ( struct digest_algorithm *hash,
+				    struct hmac_drbg_state *state,
+				    const void *entropy, size_t entropy_len,
+				    const void *personal, size_t personal_len );
+extern void hmac_drbg_reseed ( struct digest_algorithm *hash,
+			       struct hmac_drbg_state *state,
+			       const void *entropy, size_t entropy_len,
+			       const void *additional, size_t additional_len );
+extern int hmac_drbg_generate ( struct digest_algorithm *hash,
+				struct hmac_drbg_state *state,
+				const void *additional, size_t additional_len,
+				void *data, size_t len );
+
+#endif /* _IPXE_HMAC_DRBG_H */
diff --git a/roms/ipxe/src/include/ipxe/http.h b/roms/ipxe/src/include/ipxe/http.h
index d8f4ca5acb0bd23305faec660c6c..cf8c0c7fa4a549d74793695dc17e 100644
--- a/roms/ipxe/src/include/ipxe/http.h
+++ b/roms/ipxe/src/include/ipxe/http.h
@@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 extern int http_open_filter ( struct interface *xfer, struct uri *uri,
 			      unsigned int default_port,
 			      int ( * filter ) ( struct interface *,
+						 const char *,
 						 struct interface ** ) );
 
 #endif /* _IPXE_HTTP_H */
diff --git a/roms/ipxe/src/include/ipxe/ib_packet.h b/roms/ipxe/src/include/ipxe/ib_packet.h
index 4bd335764725b5bd8c34963b7ce1..a959967cbb859e5d6396afb7a052 100644
--- a/roms/ipxe/src/include/ipxe/ib_packet.h
+++ b/roms/ipxe/src/include/ipxe/ib_packet.h
@@ -152,9 +152,10 @@ 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 );
+		     const struct ib_address_vector *dest );
 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 );
+		     struct ib_address_vector *dest,
+		     struct ib_address_vector *source );
 
 #endif /* _IPXE_IB_PACKET_H */
diff --git a/roms/ipxe/src/include/ipxe/image.h b/roms/ipxe/src/include/ipxe/image.h
index dbcd6d64226e487d530794dc793e..6022dce66b22f15d900af23f69b4 100644
--- a/roms/ipxe/src/include/ipxe/image.h
+++ b/roms/ipxe/src/include/ipxe/image.h
@@ -29,7 +29,7 @@ struct image {
 	/** URI of image */
 	struct uri *uri;
 	/** Name */
-	char name[16];
+	char *name;
 	/** Flags */
 	unsigned int flags;
 
@@ -64,6 +64,12 @@ struct image {
 /** Image is selected for execution */
 #define IMAGE_SELECTED 0x0002
 
+/** Image is trusted */
+#define IMAGE_TRUSTED 0x0004
+
+/** Image will be automatically unregistered after execution */
+#define IMAGE_AUTO_UNREGISTER 0x0008
+
 /** An executable image type */
 struct image_type {
 	/** Name of this image type */
@@ -119,6 +125,10 @@ extern struct image *current_image;
 #define for_each_image( image ) \
 	list_for_each_entry ( (image), &images, list )
 
+/** Iterate over all registered images, safe against deletion */
+#define for_each_image_safe( image, tmp ) \
+	list_for_each_entry_safe ( (image), (tmp), &images, list )
+
 /**
  * Test for existence of images
  *
@@ -137,8 +147,8 @@ static inline struct image * first_image ( void ) {
 	return list_first_entry ( &images, struct image, list );
 }
 
-extern struct image * alloc_image ( void );
-extern void image_set_uri ( struct image *image, struct uri *uri );
+extern struct image * alloc_image ( struct uri *uri );
+extern int image_set_name ( struct image *image, const char *name );
 extern int image_set_cmdline ( struct image *image, const char *cmdline );
 extern int register_image ( struct image *image );
 extern void unregister_image ( struct image *image );
@@ -148,6 +158,7 @@ extern int image_exec ( struct image *image );
 extern int image_replace ( struct image *replacement );
 extern int image_select ( struct image *image );
 extern struct image * image_find_selected ( void );
+extern int image_set_trust ( int require_trusted, int permanent );
 
 /**
  * Increment reference count on an image
@@ -170,15 +181,30 @@ static inline void image_put ( struct image *image ) {
 }
 
 /**
- * Set image name
+ * Clear image command line
+ *
+ * @v image		Image
+ */
+static inline void image_clear_cmdline ( struct image *image ) {
+	image_set_cmdline ( image, NULL );
+}
+
+/**
+ * Set image as trusted
+ *
+ * @v image		Image
+ */
+static inline void image_trust ( struct image *image ) {
+	image->flags |= IMAGE_TRUSTED;
+}
+
+/**
+ * Set image as untrusted
  *
  * @v image		Image
- * @v name		New image name
- * @ret rc		Return status code
  */
-static inline int image_set_name ( struct image *image, const char *name ) {
-	strncpy ( image->name, name, ( sizeof ( image->name ) - 1 ) );
-	return 0;
+static inline void image_untrust ( struct image *image ) {
+	image->flags &= ~IMAGE_TRUSTED;
 }
 
 #endif /* _IPXE_IMAGE_H */
diff --git a/roms/ipxe/src/include/ipxe/infiniband.h b/roms/ipxe/src/include/ipxe/infiniband.h
index f97a5d4fe2a47d7fcc8b620a4a01..f546ea61b5036dbc6a882f15a122 100644
--- a/roms/ipxe/src/include/ipxe/infiniband.h
+++ b/roms/ipxe/src/include/ipxe/infiniband.h
@@ -142,6 +142,16 @@ enum ib_queue_pair_type {
 	IB_QPT_ETH,
 };
 
+/** Infiniband queue pair operations */
+struct ib_queue_pair_operations {
+	/** Allocate receive I/O buffer
+	 *
+	 * @v len		Maximum receive length
+	 * @ret iobuf		I/O buffer (or NULL if out of memory)
+	 */
+	struct io_buffer * ( * alloc_iob ) ( size_t len );
+};
+
 /** An Infiniband Queue Pair */
 struct ib_queue_pair {
 	/** Containing Infiniband device */
@@ -169,6 +179,8 @@ struct ib_queue_pair {
 	struct list_head mgids;
 	/** Address vector */
 	struct ib_address_vector av;
+	/** Queue pair operations */
+	struct ib_queue_pair_operations *op;
 	/** Driver private data */
 	void *drv_priv;
 	/** Queue owner private data */
@@ -193,13 +205,15 @@ struct ib_completion_queue_operations {
 	 *
 	 * @v ibdev		Infiniband device
 	 * @v qp		Queue pair
-	 * @v av		Address vector, or NULL
+	 * @v dest		Destination address vector, or NULL
+	 * @v source		Source 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 ib_address_vector *dest,
+				   struct ib_address_vector *source,
 				   struct io_buffer *iobuf, int rc );
 };
 
@@ -277,7 +291,7 @@ struct ib_device_operations {
 	 *
 	 * @v ibdev		Infiniband device
 	 * @v qp		Queue pair
-	 * @v av		Address vector
+	 * @v dest		Destination address vector
 	 * @v iobuf		I/O buffer
 	 * @ret rc		Return status code
 	 *
@@ -288,7 +302,7 @@ struct ib_device_operations {
 	 */
 	int ( * post_send ) ( struct ib_device *ibdev,
 			      struct ib_queue_pair *qp,
-			      struct ib_address_vector *av,
+			      struct ib_address_vector *dest,
 			      struct io_buffer *iobuf );
 	/** Post receive work queue entry
 	 *
@@ -478,8 +492,8 @@ extern void ib_poll_cq ( struct ib_device *ibdev,
 extern struct ib_queue_pair *
 ib_create_qp ( struct ib_device *ibdev, enum ib_queue_pair_type type,
 	       unsigned int num_send_wqes, struct ib_completion_queue *send_cq,
-	       unsigned int num_recv_wqes,
-	       struct ib_completion_queue *recv_cq );
+	       unsigned int num_recv_wqes, struct ib_completion_queue *recv_cq,
+	       struct ib_queue_pair_operations *op );
 extern int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp );
 extern void ib_destroy_qp ( struct ib_device *ibdev,
 			    struct ib_queue_pair *qp );
@@ -490,7 +504,7 @@ extern struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev,
 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 ib_address_vector *dest,
 			  struct io_buffer *iobuf );
 extern int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
 			  struct io_buffer *iobuf );
@@ -499,7 +513,8 @@ extern void ib_complete_send ( struct ib_device *ibdev,
 			       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 ib_address_vector *dest,
+			       struct ib_address_vector *source,
 			       struct io_buffer *iobuf, int rc );
 extern void ib_refill_recv ( struct ib_device *ibdev,
 			     struct ib_queue_pair *qp );
diff --git a/roms/ipxe/src/include/ipxe/iobuf.h b/roms/ipxe/src/include/ipxe/iobuf.h
index 82c8b8896f6bb8983f95e59f9879..b2b0cb4401d7d8e71099ea5007ea 100644
--- a/roms/ipxe/src/include/ipxe/iobuf.h
+++ b/roms/ipxe/src/include/ipxe/iobuf.h
@@ -13,17 +13,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <assert.h>
 #include <ipxe/list.h>
 
-/**
- * I/O buffer alignment
- *
- * I/O buffers allocated via alloc_iob() are guaranteed to be
- * physically aligned to this boundary.  Some cards cannot DMA across
- * a 4kB boundary.  With a standard Ethernet MTU, aligning to a 2kB
- * boundary is sufficient to guarantee no 4kB boundary crossings.  For
- * a jumbo Ethernet MTU, a packet may be larger than 4kB anyway.
- */
-#define IOB_ALIGN 2048
-
 /**
  * Minimum I/O buffer length
  *
@@ -221,9 +210,12 @@ static inline void iob_populate ( struct io_buffer *iobuf,
 	(iobuf) = NULL;					\
 	__iobuf; } )
 
+extern struct io_buffer * __malloc alloc_iob_raw ( size_t len, size_t align,
+						   size_t offset );
 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 );
 extern int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len );
+extern struct io_buffer * iob_concatenate ( struct list_head *list );
 
 #endif /* _IPXE_IOBUF_H */
diff --git a/roms/ipxe/src/include/ipxe/ip.h b/roms/ipxe/src/include/ipxe/ip.h
index 3f3dc1f77d592d1494936b3151b3..ca508e274b207c46a8f68ddbda3b 100644
--- a/roms/ipxe/src/include/ipxe/ip.h
+++ b/roms/ipxe/src/include/ipxe/ip.h
@@ -31,9 +31,6 @@ struct io_buffer;
 #define IP_TOS		0
 #define IP_TTL		64
 
-#define IP_FRAG_IOB_SIZE	1500
-#define IP_FRAG_TIMEOUT		50
-
 /** An IPv4 packet header */
 struct iphdr {
 	uint8_t  verhdrlen;
@@ -73,24 +70,22 @@ struct ipv4_miniroute {
 	struct in_addr gateway;
 };
 
-/* Fragment reassembly buffer */
-struct frag_buffer {
-	/* Identification number */
-	uint16_t ident;
-	/* Source network address */
-	struct in_addr src;
-	/* Destination network address */
-	struct in_addr dest;
-	/* Reassembled I/O buffer */
-	struct io_buffer *frag_iob;
-	/* Reassembly timer */
-	struct retry_timer frag_timer;
+/* IPv4 fragment reassembly buffer */
+struct ipv4_fragment {
 	/* List of fragment reassembly buffers */
 	struct list_head list;
+	/** Reassembled packet */
+	struct io_buffer *iobuf;
+	/** Current offset */
+	size_t offset;
+	/** Reassembly timer */
+	struct retry_timer timer;
 };
 
 extern struct list_head ipv4_miniroutes;
 
 extern struct net_protocol ipv4_protocol __net_protocol;
 
+extern int ipv4_has_any_addr ( struct net_device *netdev );
+
 #endif /* _IPXE_IP_H */
diff --git a/roms/ipxe/src/include/ipxe/ipoib.h b/roms/ipxe/src/include/ipxe/ipoib.h
index e8f12dc5d06e382f5133a58a6310..68ff8df49791a132b938ac25958a 100644
--- a/roms/ipxe/src/include/ipxe/ipoib.h
+++ b/roms/ipxe/src/include/ipxe/ipoib.h
@@ -8,6 +8,7 @@
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
+#include <ipxe/if_arp.h>
 #include <ipxe/infiniband.h>
 
 /** IPoIB MAC address length */
@@ -33,25 +34,32 @@ struct ipoib_hdr {
 	/** Network-layer protocol */
 	uint16_t proto;
 	/** Reserved, must be zero */
-	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;
+	uint16_t reserved;
 } __attribute__ (( packed ));
 
+/** GUID mask used for constructing eIPoIB Local Ethernet MAC address (LEMAC) */
+#define IPOIB_GUID_MASK 0xe7
+
+/** eIPoIB Remote Ethernet MAC address
+ *
+ * An eIPoIB REMAC address is an Ethernet-like (6 byte) link-layer
+ * pseudo-address used to look up a full IPoIB link-layer address.
+ */
+struct ipoib_remac {
+	/** Remote QPN
+	 *
+	 * Must be ORed with EIPOIB_QPN_LA so that eIPoIB REMAC
+	 * addresses are considered as locally-assigned Ethernet MAC
+	 * addreses.
+	 */
+	uint32_t qpn;
+	/** Remote LID */
+	uint16_t lid;
+} __attribute__ (( packed ));
+
+/** eIPoIB REMAC locally-assigned address indicator */
+#define EIPOIB_QPN_LA 0x02000000UL
+
 extern const char * ipoib_ntoa ( const void *ll_addr );
 extern struct net_device * alloc_ipoibdev ( size_t priv_size );
 
diff --git a/roms/ipxe/src/include/ipxe/isapnp.h b/roms/ipxe/src/include/ipxe/isapnp.h
index 47a47025bbf1958b64280902cf71..b0b0e98d6e25a80e585031777cae 100644
--- a/roms/ipxe/src/include/ipxe/isapnp.h
+++ b/roms/ipxe/src/include/ipxe/isapnp.h
@@ -15,7 +15,8 @@
 *
 *    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.
+*    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+*    02110-1301, USA.
 *
 *    Portions of this code:
 *		Copyright (C) 2001  P.J.H.Fox (fox@roestock.demon.co.uk)
diff --git a/roms/ipxe/src/include/ipxe/iscsi.h b/roms/ipxe/src/include/ipxe/iscsi.h
index 5d3d73b0ceb3cc93318dea07fb3a..be71360a0c66001eb3788df95b05 100644
--- a/roms/ipxe/src/include/ipxe/iscsi.h
+++ b/roms/ipxe/src/include/ipxe/iscsi.h
@@ -36,7 +36,7 @@ union iscsi_segment_lengths {
 		 */
 		uint8_t data_len[3];
 	} bytes;
-	/** Ths data length (measured in bytes), in network byte
+	/** The data length (measured in bytes), in network byte
 	 * order, with ahs_len as the first byte.
 	 */
 	uint32_t ahs_and_data_len;
@@ -515,8 +515,6 @@ enum iscsi_tx_state {
 	ISCSI_TX_AHS,
 	/** Sending the data segment */
 	ISCSI_TX_DATA,
-	/** Sending the data segment padding */
-	ISCSI_TX_DATA_PADDING,
 };
 
 /** State of an iSCSI RX engine */
diff --git a/roms/ipxe/src/include/ipxe/iso9660.h b/roms/ipxe/src/include/ipxe/iso9660.h
new file mode 100644
index 0000000000000000000000000000000000000000..02c2ae377969d1403b55f2d3b014cfbd71da0a75
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/iso9660.h
@@ -0,0 +1,44 @@
+#ifndef _IPXE_ISO9660_H
+#define _IPXE_ISO9660_H
+
+/**
+ * @file
+ *
+ * ISO9660 CD-ROM specification
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/** ISO9660 block size */
+#define ISO9660_BLKSIZE 2048
+
+/** An ISO9660 Primary Volume Descriptor (fixed portion) */
+struct iso9660_primary_descriptor_fixed {
+	/** Descriptor type */
+	uint8_t type;
+	/** Identifier ("CD001") */
+	uint8_t id[5];
+} __attribute__ (( packed ));
+
+/** An ISO9660 Primary Volume Descriptor */
+struct iso9660_primary_descriptor {
+	/** Fixed portion */
+	struct iso9660_primary_descriptor_fixed fixed;
+} __attribute__ (( packed ));
+
+/** ISO9660 Primary Volume Descriptor type */
+#define ISO9660_TYPE_PRIMARY 0x01
+
+/** ISO9660 Primary Volume Descriptor block address */
+#define ISO9660_PRIMARY_LBA 16
+
+/** ISO9660 Boot Volume Descriptor type */
+#define ISO9660_TYPE_BOOT 0x00
+
+/** ISO9660 identifier */
+#define ISO9660_ID "CD001"
+
+#endif /* _IPXE_ISO9660_H */
diff --git a/roms/ipxe/src/include/ipxe/lineconsole.h b/roms/ipxe/src/include/ipxe/lineconsole.h
new file mode 100644
index 0000000000000000000000000000000000000000..925c0acccedc3fe5e8bbcb0a6373a3571340142f
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/lineconsole.h
@@ -0,0 +1,36 @@
+#ifndef _IPXE_LINECONSOLE_H
+#define _IPXE_LINECONSOLE_H
+
+/** @file
+ *
+ * Line-based console
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/ansiesc.h>
+
+/** A line-based console */
+struct line_console {
+	/** Data buffer
+	 *
+	 * Must initially be filled with NULs
+	 */
+	char *buffer;
+	/** Current index within buffer */
+	size_t index;
+	/** Length of buffer
+	 *
+	 * The final character of the buffer will only ever be used as
+	 * a potential terminating NUL.
+	 */
+	size_t len;
+	/** ANSI escape sequence context */
+	struct ansiesc_context ctx;
+};
+
+extern size_t line_putchar ( struct line_console *line, int character );
+
+#endif /* _IPXE_LINECONSOLE_H */
diff --git a/roms/ipxe/src/include/ipxe/linux/linux_entropy.h b/roms/ipxe/src/include/ipxe/linux/linux_entropy.h
new file mode 100644
index 0000000000000000000000000000000000000000..bd89bd52f249f5fae929db49aa2171a55caff0fe
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/linux/linux_entropy.h
@@ -0,0 +1,32 @@
+#ifndef _IPXE_LINUX_ENTROPY_H
+#define _IPXE_LINUX_ENTROPY_H
+
+/** @file
+ *
+ * iPXE entropy API for linux
+ *
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#ifdef ENTROPY_LINUX
+#define ENTROPY_PREFIX_linux
+#else
+#define ENTROPY_PREFIX_linux __linux_
+#endif
+
+/**
+ * min-entropy per sample
+ *
+ * @ret min_entropy	min-entropy of each sample
+ */
+static inline __always_inline double
+ENTROPY_INLINE ( linux, min_entropy_per_sample ) ( void ) {
+
+	/* We read single bytes from /dev/random and assume that each
+	 * contains full entropy.
+	 */
+	return 8;
+}
+
+#endif /* _IPXE_LINUX_ENTROPY_H */
diff --git a/roms/ipxe/src/include/ipxe/linux/linux_time.h b/roms/ipxe/src/include/ipxe/linux/linux_time.h
new file mode 100644
index 0000000000000000000000000000000000000000..93a2577305f3284c90cb5137fbb617b71c58abad
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/linux/linux_time.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_LINUX_TIME_H
+#define _IPXE_LINUX_TIME_H
+
+/** @file
+ *
+ * Linux time source
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef TIME_LINUX
+#define TIME_PREFIX_linux
+#else
+#define TIME_PREFIX_linux __linux_
+#endif
+
+#endif /* _IPXE_LINUX_TIME_H */
diff --git a/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h b/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h
index 1b496117772e9be45179881383c8..e4dfdd357718c00b39151ad05df9 100644
--- a/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h
+++ b/roms/ipxe/src/include/ipxe/linux/linux_uaccess.h
@@ -71,6 +71,12 @@ UACCESS_INLINE(linux, userptr_add)(userptr_t userptr, off_t offset)
 	return trivial_userptr_add(userptr, offset);
 }
 
+static inline __always_inline off_t
+UACCESS_INLINE(linux, userptr_sub)(userptr_t userptr, userptr_t subtrahend)
+{
+	return trivial_userptr_sub ( userptr, subtrahend );
+}
+
 static inline __always_inline void
 UACCESS_INLINE(linux, memcpy_user)(userptr_t dest, off_t dest_off, userptr_t src, off_t src_off, size_t len)
 {
diff --git a/roms/ipxe/src/include/ipxe/list.h b/roms/ipxe/src/include/ipxe/list.h
index ab4c119dd775e93dfc003d757a32..0d0973077e88efc803f6b40dbe7f 100644
--- a/roms/ipxe/src/include/ipxe/list.h
+++ b/roms/ipxe/src/include/ipxe/list.h
@@ -42,9 +42,9 @@ struct list_head {
  *
  * @v list		List head
  */
-#define INIT_LIST_HEAD( list ) do {			\
-	(list)->next = (list);				\
-	(list)->prev = (list);				\
+#define INIT_LIST_HEAD( list ) do {				\
+	(list)->next = (list);					\
+	(list)->prev = (list);					\
 	} while ( 0 )
 
 /**
@@ -52,43 +52,35 @@ struct list_head {
  *
  * @v list		List entry or head
  */
-#define list_check( list ) ( {				\
-	assert ( (list) != NULL );			\
-	assert ( (list)->prev != NULL );		\
-	assert ( (list)->next != NULL );		\
-	assert ( (list)->next->prev == (list) );	\
-	assert ( (list)->prev->next == (list) );	\
+#define list_check( list ) ( {					\
+	assert ( (list) != NULL );				\
+	assert ( (list)->prev != NULL );			\
+	assert ( (list)->next != NULL );			\
+	assert ( (list)->next->prev == (list) );		\
+	assert ( (list)->prev->next == (list) );		\
 	} )
 
-/**
- * Insert a list entry between two known consecutive entries
- *
- * @v new		New list entry
- * @v prev		Previous list entry
- * @v next		Next list entry
- */
-static inline void __list_add ( struct list_head *new,
-				struct list_head *prev,
-				struct list_head *next ) {
-	next->prev = new;
-	new->next = next;
-	new->prev = prev;
-	prev->next = new;
-}
-
 /**
  * Add a new entry to the head of a list
  *
  * @v new		New entry to be added
  * @v head		List head, or entry after which to add the new entry
  */
-static inline void list_add ( struct list_head *new, struct list_head *head ) {
-	__list_add ( new, head, head->next );
-}
-#define list_add( new, head ) do {			\
-	list_check ( (head) );				\
-	list_add ( (new), (head) );			\
+#define list_add( new, head ) do {				\
+	list_check ( (head) );					\
+	extern_list_add ( (new), (head) );			\
 	} while ( 0 )
+static inline void inline_list_add ( struct list_head *new,
+				     struct list_head *head ) {
+	struct list_head *prev = head;
+	struct list_head *next = head->next;
+	next->prev = (new);
+	(new)->next = next;
+	(new)->prev = prev;
+	prev->next = (new);
+}
+extern void extern_list_add ( struct list_head *new,
+			      struct list_head *head );
 
 /**
  * Add a new entry to the tail of a list
@@ -96,26 +88,21 @@ static inline void list_add ( struct list_head *new, struct list_head *head ) {
  * @v new		New entry to be added
  * @v head		List head, or entry before which to add the new entry
  */
-static inline void list_add_tail ( struct list_head *new,
-				   struct list_head *head ) {
-	__list_add ( new, head->prev, head );
-}
-#define list_add_tail( new, head ) do {			\
-	list_check ( (head) );				\
-	list_add_tail ( (new), (head) );		\
+#define list_add_tail( new, head ) do {				\
+	list_check ( (head) );					\
+	extern_list_add_tail ( (new), (head) );			\
 	} while ( 0 )
-
-/**
- * Delete a list entry between two known consecutive entries
- *
- * @v prev		Previous list entry
- * @v next		Next list entry
- */
-static inline void __list_del ( struct list_head *prev,
-				struct list_head *next ) {
-	next->prev = prev;
-	prev->next = next;
+static inline void inline_list_add_tail ( struct list_head *new,
+					  struct list_head *head ) {
+	struct list_head *prev = head->prev;
+	struct list_head *next = head;
+	next->prev = (new);
+	(new)->next = next;
+	(new)->prev = prev;
+	prev->next = (new);
 }
+extern void extern_list_add_tail ( struct list_head *new,
+				   struct list_head *head );
 
 /**
  * Delete an entry from a list
@@ -125,25 +112,199 @@ static inline void __list_del ( struct list_head *prev,
  * Note that list_empty() on entry does not return true after this;
  * the entry is in an undefined state.
  */
-static inline void list_del ( struct list_head *list ) {
-	__list_del ( list->prev, list->next );
-}
-#define list_del( list ) do {				\
-	list_check ( (list) );				\
-	list_del ( (list) );				\
+#define list_del( list ) do {					\
+	list_check ( (list) );					\
+	inline_list_del ( (list) );				\
 	} while ( 0 )
+static inline void inline_list_del ( struct list_head *list ) {
+	struct list_head *next = (list)->next;
+	struct list_head *prev = (list)->prev;
+	next->prev = prev;
+	prev->next = next;
+}
+extern void extern_list_del ( struct list_head *list );
 
 /**
  * Test whether a list is empty
  *
  * @v list		List head
  */
-static inline int list_empty ( const struct list_head *list ) {
+#define list_empty( list ) ( {					\
+	list_check ( (list) );					\
+	inline_list_empty ( (list) ); } )
+static inline int inline_list_empty ( const struct list_head *list ) {
 	return ( list->next == list );
 }
-#define list_empty( list ) ( {				\
-	list_check ( (list) );				\
-	list_empty ( (list) ); } )
+extern int extern_list_empty ( const struct list_head *list );
+
+/**
+ * Test whether a list has just one entry
+ *
+ * @v list		List to test
+ */
+#define list_is_singular( list ) ( {				\
+	list_check ( (list) );					\
+	inline_list_is_singular ( (list) ); } )
+static inline int inline_list_is_singular ( const struct list_head *list ) {
+	return ( ( ! list_empty ( list ) ) && ( list->next == list->prev ) );
+}
+extern int extern_list_is_singular ( const struct list_head *list );
+
+/**
+ * Test whether an entry is the last entry in list
+ *
+ * @v list		List entry to test
+ * @v head		List head
+ */
+#define list_is_last( list, head ) ( {				\
+	list_check ( (list) );					\
+	list_check ( (head) );					\
+	inline_list_is_last ( (list), (head) ); } )
+static inline int inline_list_is_last ( const struct list_head *list,
+					const struct list_head *head ) {
+	return ( list->next == head );
+}
+extern int extern_list_is_last ( const struct list_head *list,
+				 const struct list_head *head );
+
+/**
+ * Cut a list into two
+ *
+ * @v new		A new list to contain all removed entries
+ * @v list		An existing list
+ * @v entry		An entry within the existing list
+ *
+ * All entries from @c list up to and including @c entry are moved to
+ * @c new, which should be an empty list.  @c entry may be equal to @c
+ * list, in which case no entries are moved.
+ */
+#define list_cut_position( new, list, entry ) do {		\
+	list_check ( (new) );					\
+	assert ( list_empty ( (new) ) );			\
+	list_check ( (list) );					\
+	list_check ( (entry) );					\
+	extern_list_cut_position ( (new), (list), (entry) );	\
+	} while ( 0 )
+static inline void inline_list_cut_position ( struct list_head *new,
+					      struct list_head *list,
+					      struct list_head *entry ) {
+	struct list_head *first = entry->next;
+
+	if ( list != entry ) {
+		new->next = list->next;
+		new->next->prev = new;
+		new->prev = entry;
+		new->prev->next = new;
+		list->next = first;
+		list->next->prev = list;
+	}
+}
+extern void extern_list_cut_position ( struct list_head *new,
+				       struct list_head *list,
+				       struct list_head *entry );
+
+/**
+ * Move all entries from one list into another list
+ *
+ * @v list		List of entries to add
+ * @v entry		Entry after which to add the new entries
+ *
+ * All entries from @c list are inserted after @c entry.  Note that @c
+ * list is left in an undefined state; use @c list_splice_init() if
+ * you want @c list to become an empty list.
+ */
+#define list_splice( list, entry ) do {				\
+	list_check ( (list) );					\
+	list_check ( (entry) );					\
+	extern_list_splice ( (list), (entry) );			\
+	} while ( 0 )
+static inline void inline_list_splice ( const struct list_head *list,
+					struct list_head *entry ) {
+	struct list_head *first = list->next;
+	struct list_head *last = list->prev;
+
+	if ( ! list_empty ( list ) ) {
+		last->next = entry->next;
+		last->next->prev = last;
+		first->prev = entry;
+		first->prev->next = first;
+	}
+}
+extern void extern_list_splice ( const struct list_head *list,
+				 struct list_head *entry );
+
+/**
+ * Move all entries from one list into another list
+ *
+ * @v list		List of entries to add
+ * @v entry		Entry before which to add the new entries
+ *
+ * All entries from @c list are inserted before @c entry.  Note that @c
+ * list is left in an undefined state; use @c list_splice_tail_init() if
+ * you want @c list to become an empty list.
+ */
+#define list_splice_tail( list, entry ) do {			\
+	list_check ( (list) );					\
+	list_check ( (entry) );					\
+	extern_list_splice_tail ( (list), (entry) );		\
+	} while ( 0 )
+static inline void inline_list_splice_tail ( const struct list_head *list,
+					     struct list_head *entry ) {
+	struct list_head *first = list->next;
+	struct list_head *last = list->prev;
+
+	if ( ! list_empty ( list ) ) {
+		first->prev = entry->prev;
+		first->prev->next = first;
+		last->next = entry;
+		last->next->prev = last;
+	}
+}
+extern void extern_list_splice_tail ( const struct list_head *list,
+				      struct list_head *entry );
+
+/**
+ * Move all entries from one list into another list and reinitialise empty list
+ *
+ * @v list		List of entries to add
+ * @v entry		Entry after which to add the new entries
+ *
+ * All entries from @c list are inserted after @c entry.
+ */
+#define list_splice_init( list, entry ) do {			\
+	list_check ( (list) );					\
+	list_check ( (entry) );					\
+	extern_list_splice_init ( (list), (entry) );		\
+	} while ( 0 )
+static inline void inline_list_splice_init ( struct list_head *list,
+					     struct list_head *entry ) {
+	list_splice ( list, entry );
+	INIT_LIST_HEAD ( list );
+}
+extern void extern_list_splice_init ( struct list_head *list,
+				      struct list_head *entry );
+
+/**
+ * Move all entries from one list into another list and reinitialise empty list
+ *
+ * @v list		List of entries to add
+ * @v entry		Entry before which to add the new entries
+ *
+ * All entries from @c list are inserted before @c entry.
+ */
+#define list_splice_tail_init( list, entry ) do {		\
+	list_check ( (list) );					\
+	list_check ( (entry) );					\
+	extern_list_splice_tail_init ( (list), (entry) );	\
+	} while ( 0 )
+
+static inline void inline_list_splice_tail_init ( struct list_head *list,
+						  struct list_head *entry ) {
+	list_splice_tail ( list, entry );
+	INIT_LIST_HEAD ( list );
+}
+extern void extern_list_splice_tail_init ( struct list_head *list,
+					   struct list_head *entry );
 
 /**
  * Get the container of a list entry
@@ -153,8 +314,8 @@ static inline int list_empty ( const struct list_head *list ) {
  * @v member		Name of list field within containing type
  * @ret container	Containing object
  */
-#define list_entry( list, type, member ) ( {		\
-	list_check ( (list) );				\
+#define list_entry( list, type, member ) ( {			\
+	list_check ( (list) );					\
 	container_of ( list, type, member ); } )
 
 /**
@@ -165,11 +326,36 @@ static inline int list_empty ( const struct list_head *list ) {
  * @v member		Name of list field within containing type
  * @ret first		First list entry, or NULL
  */
-#define list_first_entry( list, type, member )		\
-	( list_empty ( (list) ) ?			\
-	  ( type * ) NULL :				\
+#define list_first_entry( list, type, member )			\
+	( list_empty ( (list) ) ?				\
+	  ( type * ) NULL :					\
 	  list_entry ( (list)->next, type, member ) )
 
+/**
+ * Get the container of the last entry in a list
+ *
+ * @v list		List head
+ * @v type		Containing type
+ * @v member		Name of list field within containing type
+ * @ret first		First list entry, or NULL
+ */
+#define list_last_entry( list, type, member )			\
+	( list_empty ( (list) ) ?				\
+	  ( type * ) NULL :					\
+	  list_entry ( (list)->prev, type, member ) )
+
+/**
+ * Iterate over a list
+ *
+ * @v pos		Iterator
+ * @v head		List head
+ */
+#define list_for_each( pos, head )					      \
+	for ( list_check ( (head) ),					      \
+	      pos = (head)->next;					      \
+	      pos != (head);						      \
+	      pos = (pos)->next )
+
 /**
  * Iterate over entries in a list
  *
@@ -212,4 +398,75 @@ static inline int list_empty ( const struct list_head *list ) {
 	      pos = tmp,						      \
 	      tmp = list_entry ( tmp->member.next, typeof ( *tmp ), member ) )
 
+/**
+ * Iterate over entries in a list, starting after current position
+ *
+ * @v pos		Iterator
+ * @v head		List head
+ * @v member		Name of list field within iterator's type
+ */
+#define list_for_each_entry_continue( pos, head, member )		      \
+	for ( list_check ( (head) ),					      \
+	      pos = list_entry ( pos->member.next, typeof ( *pos ), member ); \
+	      &pos->member != (head);					      \
+	      pos = list_entry ( pos->member.next, typeof ( *pos ), member ) )
+
+/**
+ * Iterate over entries in a list in reverse, starting after current position
+ *
+ * @v pos		Iterator
+ * @v head		List head
+ * @v member		Name of list field within iterator's type
+ */
+#define list_for_each_entry_continue_reverse( pos, head, member )	      \
+	for ( list_check ( (head) ),					      \
+	      pos = list_entry ( pos->member.prev, typeof ( *pos ), member ); \
+	      &pos->member != (head);					      \
+	      pos = list_entry ( pos->member.prev, typeof ( *pos ), member ) )
+
+/**
+ * Test if list contains a specified entry
+ *
+ * @v entry		Entry
+ * @v head		List head
+ * @ret present		List contains specified entry
+ */
+#define list_contains( entry, head ) ( {			\
+	list_check ( (head) );					\
+	list_check ( (entry) );					\
+	extern_list_contains ( (entry), (head) ); } )
+static inline int inline_list_contains ( struct list_head *entry,
+					 struct list_head *head ) {
+	struct list_head *tmp;
+
+	list_for_each ( tmp, head ) {
+		if ( tmp == entry )
+			return 1;
+	}
+	return 0;
+}
+extern int extern_list_contains ( struct list_head *entry,
+				  struct list_head *head );
+
+/**
+ * Test if list contains a specified entry
+ *
+ * @v entry		Entry
+ * @v head		List head
+ * @ret present		List contains specified entry
+ */
+#define list_contains_entry( entry, head, member )		\
+	list_contains ( &(entry)->member, (head) )
+
+/**
+ * Check list contains a specified entry
+ *
+ * @v entry		Entry
+ * @v head		List head
+ * @v member		Name of list field within iterator's type
+ */
+#define list_check_contains_entry( entry, head, member ) do {		      \
+	assert ( list_contains_entry ( (entry), (head), member ) );	      \
+	} while ( 0 )
+
 #endif /* _IPXE_LIST_H */
diff --git a/roms/ipxe/src/include/ipxe/malloc.h b/roms/ipxe/src/include/ipxe/malloc.h
index c435a7ddb6472d2f65658272ae45..bbd6cb89850532f08f641e25cba5 100644
--- a/roms/ipxe/src/include/ipxe/malloc.h
+++ b/roms/ipxe/src/include/ipxe/malloc.h
@@ -23,7 +23,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 extern size_t freemem;
 
-extern void * __malloc alloc_memblock ( size_t size, size_t align );
+extern void * __malloc alloc_memblock ( size_t size, size_t align,
+					size_t offset );
 extern void free_memblock ( void *ptr, size_t size );
 extern void mpopulate ( void *start, size_t len );
 extern void mdumpfree ( void );
@@ -33,19 +34,37 @@ extern void mdumpfree ( void );
  *
  * @v size		Requested size
  * @v align		Physical alignment
+ * @v offset		Offset from physical alignment
  * @ret ptr		Memory, or NULL
  *
  * Allocates physically-aligned memory for DMA.
  *
  * @c align must be a power of two.  @c size may not be zero.
  */
-static inline void * __malloc malloc_dma ( size_t size, size_t phys_align ) {
-	void * ptr = alloc_memblock ( size, phys_align );
+static inline void * __malloc malloc_dma_offset ( size_t size,
+						  size_t phys_align,
+						  size_t offset ) {
+	void * ptr = alloc_memblock ( size, phys_align, offset );
 	if ( ptr && size )
 		VALGRIND_MALLOCLIKE_BLOCK ( ptr, size, 0, 0 );
 	return ptr;
 }
 
+/**
+ * Allocate memory for DMA
+ *
+ * @v size		Requested size
+ * @v align		Physical alignment
+ * @ret ptr		Memory, or NULL
+ *
+ * Allocates physically-aligned memory for DMA.
+ *
+ * @c align must be a power of two.  @c size may not be zero.
+ */
+static inline void * __malloc malloc_dma ( size_t size, size_t phys_align ) {
+	return malloc_dma_offset ( size, phys_align, 0 );
+}
+
 /**
  * Free memory allocated with malloc_dma()
  *
@@ -76,6 +95,17 @@ struct cache_discarder {
 #define CACHE_DISCARDERS __table ( struct cache_discarder, "cache_discarders" )
 
 /** Declare a cache discarder */
-#define __cache_discarder __table_entry ( CACHE_DISCARDERS, 01 )
+#define __cache_discarder( cost ) __table_entry ( CACHE_DISCARDERS, cost )
+
+/** @defgroup cache_cost Cache discarder costs
+ *
+ * @{
+ */
+
+#define CACHE_CHEAP	01	/**< Items with a low replacement cost */
+#define CACHE_NORMAL	02	/**< Items with a normal replacement cost */
+#define CACHE_EXPENSIVE	03	/**< Items with a high replacement cost */
+
+/** @} */
 
 #endif /* _IPXE_MALLOC_H */
diff --git a/roms/ipxe/src/include/ipxe/md5.h b/roms/ipxe/src/include/ipxe/md5.h
index c3dfeb7e01bb7fb1e0b30b3b4bb8..860bc4769013704da1cbd65cb15f 100644
--- a/roms/ipxe/src/include/ipxe/md5.h
+++ b/roms/ipxe/src/include/ipxe/md5.h
@@ -1,23 +1,72 @@
 #ifndef _IPXE_MD5_H
 #define _IPXE_MD5_H
 
-FILE_LICENCE ( GPL2_OR_LATER );
+/** @file
+ *
+ * MD5 algorithm
+ *
+ */
 
-struct digest_algorithm;
+FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
+#include <ipxe/crypto.h>
+
+/** An MD5 digest */
+struct md5_digest {
+	/** Hash output */
+	uint32_t h[4];
+};
 
-#define MD5_DIGEST_SIZE		16
-#define MD5_BLOCK_WORDS		16
-#define MD5_HASH_WORDS		4
+/** An MD5 data block */
+union md5_block {
+	/** Raw bytes */
+	uint8_t byte[64];
+	/** Raw dwords */
+	uint32_t dword[16];
+	/** Final block structure */
+	struct {
+		/** Padding */
+		uint8_t pad[56];
+		/** Length in bits */
+		uint64_t len;
+	} final;
+};
+
+/** MD5 digest and data block
+ *
+ * The order of fields within this structure is designed to minimise
+ * code size.
+ */
+struct md5_digest_data {
+	/** Digest of data already processed */
+	struct md5_digest digest;
+	/** Accumulated data */
+	union md5_block data;
+} __attribute__ (( packed ));
 
-struct md5_ctx {
-	u32 hash[MD5_HASH_WORDS];
-	u32 block[MD5_BLOCK_WORDS];
-	u64 byte_count;
+/** MD5 digest and data block */
+union md5_digest_data_dwords {
+	/** Digest and data block */
+	struct md5_digest_data dd;
+	/** Raw dwords */
+	uint32_t dword[ sizeof ( struct md5_digest_data ) /
+			sizeof ( uint32_t ) ];
 };
 
-#define MD5_CTX_SIZE sizeof ( struct md5_ctx )
+/** An MD5 context */
+struct md5_context {
+	/** Amount of accumulated data */
+	size_t len;
+	/** Digest and accumulated data */
+	union md5_digest_data_dwords ddd;
+} __attribute__ (( packed ));
+
+/** MD5 context size */
+#define MD5_CTX_SIZE sizeof ( struct md5_context )
+
+/** MD5 digest size */
+#define MD5_DIGEST_SIZE sizeof ( struct md5_digest )
 
 extern struct digest_algorithm md5_algorithm;
 
diff --git a/roms/ipxe/src/include/ipxe/memblock.h b/roms/ipxe/src/include/ipxe/memblock.h
new file mode 100644
index 0000000000000000000000000000000000000000..13af3e4336edaffcb3f1ec343f5be70657dc2fa8
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/memblock.h
@@ -0,0 +1,17 @@
+#ifndef _IPXE_MEMBLOCK_H
+#define _IPXE_MEMBLOCK_H
+
+/** @file
+ *
+ * Largest memory block
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/uaccess.h>
+
+extern size_t largest_memblock ( userptr_t *start );
+
+#endif /* _IPXE_MEMBLOCK_H */
diff --git a/roms/ipxe/src/include/ipxe/menu.h b/roms/ipxe/src/include/ipxe/menu.h
new file mode 100644
index 0000000000000000000000000000000000000000..993b027ea997eb1971481a466211805f22d0683d
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/menu.h
@@ -0,0 +1,49 @@
+#ifndef _IPXE_MENU_H
+#define _IPXE_MENU_H
+
+/** @file
+ *
+ * Menu selection
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/list.h>
+
+/** A menu */
+struct menu {
+	/** List of menus */
+	struct list_head list;
+	/** Name */
+	const char *name;
+	/** Title */
+	const char *title;
+	/** Menu items */
+	struct list_head items;
+};
+
+/** A menu item */
+struct menu_item {
+	/** List of menu items */
+	struct list_head list;
+	/** Label */
+	const char *label;
+	/** Text */
+	const char *text;
+	/** Shortcut key */
+	int shortcut;
+	/** Is default item */
+	int is_default;
+};
+
+extern struct menu * create_menu ( const char *name, const char *title );
+extern struct menu_item * add_menu_item ( struct menu *menu, const char *label,
+					  const char *text, int shortcut,
+					  int is_default );
+extern void destroy_menu ( struct menu *menu );
+extern struct menu * find_menu ( const char *name );
+extern int show_menu ( struct menu *menu, unsigned int timeout_ms,
+		       const char *select, struct menu_item **selected );
+
+#endif /* _IPXE_MENU_H */
diff --git a/roms/ipxe/src/include/ipxe/mii.h b/roms/ipxe/src/include/ipxe/mii.h
new file mode 100644
index 0000000000000000000000000000000000000000..cf462418a2a65821d908969fc5e76d522efcefa5
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/mii.h
@@ -0,0 +1,87 @@
+#ifndef _IPXE_MII_H
+#define _IPXE_MII_H
+
+/** @file
+ *
+ * Media Independent Interface
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <mii.h>
+#include <ipxe/netdevice.h>
+
+struct mii_interface;
+
+/** MII interface operations */
+struct mii_operations {
+	/**
+	 * Read from MII register
+	 *
+	 * @v mii		MII interface
+	 * @v reg		Register address
+	 * @ret data		Data read, or negative error
+	 */
+	int ( * read ) ( struct mii_interface *mii, unsigned int reg );
+	/**
+	 * Write to MII register
+	 *
+	 * @v mii		MII interface
+	 * @v reg		Register address
+	 * @v data		Data to write
+	 * @ret rc		Return status code
+	 */
+	int ( * write ) ( struct mii_interface *mii, unsigned int reg,
+			  unsigned int data );
+};
+
+/** An MII interface */
+struct mii_interface {
+	/** Interface operations */
+	struct mii_operations *op;
+};
+
+/**
+ * Initialise MII interface
+ *
+ * @v mii		MII interface
+ * @v op		MII interface operations
+ */
+static inline __attribute__ (( always_inline )) void
+mii_init ( struct mii_interface *mii, struct mii_operations *op ) {
+	mii->op = op;
+}
+
+/**
+ * Read from MII register
+ *
+ * @v mii		MII interface
+ * @v reg		Register address
+ * @ret data		Data read, or negative error
+ */
+static inline __attribute__ (( always_inline )) int
+mii_read ( struct mii_interface *mii, unsigned int reg ) {
+	return mii->op->read ( mii, reg );
+}
+
+/**
+ * Write to MII register
+ *
+ * @v mii		MII interface
+ * @v reg		Register address
+ * @v data		Data to write
+ * @ret rc		Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+mii_write ( struct mii_interface *mii, unsigned int reg, unsigned int data ) {
+	return mii->op->write ( mii, reg, data );
+}
+
+/** Maximum time to wait for a reset, in milliseconds */
+#define MII_RESET_MAX_WAIT_MS 500
+
+extern int mii_restart ( struct mii_interface *mii );
+extern int mii_reset ( struct mii_interface *mii );
+
+#endif /* _IPXE_MII_H */
diff --git a/roms/ipxe/src/include/ipxe/net80211.h b/roms/ipxe/src/include/ipxe/net80211.h
index 3c30f06c405f70b35fda9b999416..771872c82fb9b64c2dbfebdadcf8 100644
--- a/roms/ipxe/src/include/ipxe/net80211.h
+++ b/roms/ipxe/src/include/ipxe/net80211.h
@@ -272,7 +272,7 @@ enum net80211_crypto_alg {
 #define NET80211_MAX_RATES	16
 
 /** The maximum number of channels we allow to be configured simultaneously */
-#define NET80211_MAX_CHANNELS	32
+#define NET80211_MAX_CHANNELS	40
 
 /** Seconds we'll wait to get all fragments of a packet */
 #define NET80211_FRAG_TIMEOUT	2
diff --git a/roms/ipxe/src/include/ipxe/netdevice.h b/roms/ipxe/src/include/ipxe/netdevice.h
index e49191f4ae214268cb59246e2b13..e5dbd996b5ddd95826f677bd15bf 100644
--- a/roms/ipxe/src/include/ipxe/netdevice.h
+++ b/roms/ipxe/src/include/ipxe/netdevice.h
@@ -66,20 +66,23 @@ struct net_protocol {
 	/**
 	 * Process received packet
 	 *
-	 * @v iobuf	I/O buffer
-	 * @v netdev	Network device
-	 * @v ll_dest	Link-layer destination address
-	 * @v ll_source	Link-layer source address
+	 * @v iobuf		I/O buffer
+	 * @v netdev		Network device
+	 * @v ll_dest		Link-layer destination address
+	 * @v ll_source		Link-layer source address
+	 * @v flags		Packet flags
+	 * @ret rc		Return status code
 	 *
 	 * This method takes ownership of the I/O buffer.
 	 */
 	int ( * rx ) ( struct io_buffer *iobuf, struct net_device *netdev,
-		       const void *ll_dest, const void *ll_source );
+		       const void *ll_dest, const void *ll_source,
+		       unsigned int flags );
 	/**
 	 * Transcribe network-layer address
 	 *
-	 * @v net_addr	Network-layer address
-	 * @ret string	Human-readable transcription of address
+	 * @v net_addr		Network-layer address
+	 * @ret string		Human-readable transcription of address
 	 *
 	 * This method should convert the network-layer address into a
 	 * human-readable format (e.g. dotted quad notation for IPv4).
@@ -97,6 +100,12 @@ struct net_protocol {
 	uint8_t net_addr_len;
 };
 
+/** Packet is a multicast (including broadcast) packet */
+#define LL_MULTICAST 0x0001
+
+/** Packet is a broadcast packet */
+#define LL_BROADCAST 0x0002
+
 /**
  * A link-layer protocol
  *
@@ -125,11 +134,12 @@ struct ll_protocol {
 	 * @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 flags		Packet flags
 	 * @ret rc		Return status code
 	 */
 	int ( * pull ) ( struct net_device *netdev, struct io_buffer *iobuf,
 			 const void **ll_dest, const void **ll_source,
-			 uint16_t *net_proto );
+			 uint16_t *net_proto, unsigned int *flags );
 	/**
 	 * Initialise link-layer address
 	 *
@@ -178,8 +188,17 @@ struct ll_protocol {
 	uint8_t ll_addr_len;
 	/** Link-layer header length */
 	uint8_t ll_header_len;
+	/** Flags */
+	unsigned int flags;
 };
 
+/** Local link-layer address functions only as a name
+ *
+ * This flag indicates that the local link-layer address cannot
+ * directly be used as a destination address by a remote node.
+ */
+#define LL_NAME_ONLY 0x0001
+
 /** Network device operations */
 struct net_device_operations {
 	/** Open network device
@@ -586,6 +605,8 @@ netdev_rx_frozen ( struct net_device *netdev ) {
 extern void netdev_link_err ( struct net_device *netdev, int rc );
 extern void netdev_link_down ( struct net_device *netdev );
 extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf );
+extern void netdev_tx_err ( struct net_device *netdev,
+			    struct io_buffer *iobuf, int rc );
 extern void netdev_tx_complete_err ( struct net_device *netdev,
 				 struct io_buffer *iobuf, int rc );
 extern void netdev_tx_complete_next_err ( struct net_device *netdev, int rc );
@@ -609,7 +630,7 @@ extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
 		    const void *ll_source );
 extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
 		    uint16_t net_proto, const void *ll_dest,
-		    const void *ll_source );
+		    const void *ll_source, unsigned int flags );
 extern void net_poll ( void );
 
 /**
diff --git a/roms/ipxe/src/include/ipxe/null_entropy.h b/roms/ipxe/src/include/ipxe/null_entropy.h
new file mode 100644
index 0000000000000000000000000000000000000000..646d1a17e0f1d97992d8ce34e9e0366879be6075
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/null_entropy.h
@@ -0,0 +1,52 @@
+#ifndef _IPXE_NULL_ENTROPY_H
+#define _IPXE_NULL_ENTROPY_H
+
+/** @file
+ *
+ * Nonexistent entropy source
+ *
+ * This source provides no entropy and must NOT be used in a
+ * security-sensitive environment.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+#ifdef ENTROPY_NULL
+#define ENTROPY_PREFIX_null
+#else
+#define ENTROPY_PREFIX_null __null_
+#endif
+
+static inline __always_inline int
+ENTROPY_INLINE ( null, entropy_enable ) ( void ) {
+	/* Do nothing */
+	return 0;
+}
+
+static inline __always_inline void
+ENTROPY_INLINE ( null, entropy_disable ) ( void ) {
+	/* Do nothing */
+}
+
+static inline __always_inline double
+ENTROPY_INLINE ( null, min_entropy_per_sample ) ( void ) {
+	/* Actual amount of min-entropy is zero.  To avoid
+	 * division-by-zero errors and to allow compilation of
+	 * entropy-consuming code, pretend to have 1 bit of entropy in
+	 * each sample.
+	 */
+	return 1.0;
+}
+
+static inline __always_inline int
+ENTROPY_INLINE ( null, get_noise ) ( noise_sample_t *noise ) {
+
+	/* All sample values are constant */
+	*noise = 0x01;
+
+	return 0;
+}
+
+#endif /* _IPXE_NULL_ENTROPY_H */
diff --git a/roms/ipxe/src/include/ipxe/null_sanboot.h b/roms/ipxe/src/include/ipxe/null_sanboot.h
index 341a9a1d2ede601f9f444808b049..2b3a2c74d4406779161540c38b42 100644
--- a/roms/ipxe/src/include/ipxe/null_sanboot.h
+++ b/roms/ipxe/src/include/ipxe/null_sanboot.h
@@ -15,4 +15,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define SANBOOT_PREFIX_null __null_
 #endif
 
+static inline __always_inline unsigned int
+SANBOOT_INLINE ( null, san_default_drive ) ( void ) {
+	return 0;
+}
+
 #endif /* _IPXE_NULL_SANBOOT_H */
diff --git a/roms/ipxe/src/include/ipxe/null_time.h b/roms/ipxe/src/include/ipxe/null_time.h
new file mode 100644
index 0000000000000000000000000000000000000000..2b72cdf509f1bd5b1e3f9581cca603d979f1aad2
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/null_time.h
@@ -0,0 +1,23 @@
+#ifndef _IPXE_NULL_TIME_H
+#define _IPXE_NULL_TIME_H
+
+/** @file
+ *
+ * Nonexistent time source
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#ifdef TIME_NULL
+#define TIME_PREFIX_null
+#else
+#define TIME_PREFIX_null __null_
+#endif
+
+static inline __always_inline time_t
+TIME_INLINE ( null, time_now ) ( void ) {
+	return 0;
+}
+
+#endif /* _IPXE_NULL_TIME_H */
diff --git a/roms/ipxe/src/include/ipxe/nvo.h b/roms/ipxe/src/include/ipxe/nvo.h
index 995afd749901bf2f120f39da78b5..487f8b3f2077a3d902e34a87c43d 100644
--- a/roms/ipxe/src/include/ipxe/nvo.h
+++ b/roms/ipxe/src/include/ipxe/nvo.h
@@ -42,6 +42,10 @@ struct nvo_block {
 	struct dhcp_options dhcpopts;
 };
 
+/** Name of non-volatile options settings block */
+#define NVO_SETTINGS_NAME "nvo"
+
+extern int nvo_applies ( struct settings *settings, struct setting *setting );
 extern void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
 		       size_t address, size_t len,
 		       int ( * resize ) ( struct nvo_block *nvo, size_t len ),
diff --git a/roms/ipxe/src/include/ipxe/ocsp.h b/roms/ipxe/src/include/ipxe/ocsp.h
new file mode 100644
index 0000000000000000000000000000000000000000..fe825fd063d866bad7cce6affcfeee50b1827a04
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/ocsp.h
@@ -0,0 +1,102 @@
+#ifndef _IPXE_OCSP_H
+#define _IPXE_OCSP_H
+
+/** @file
+ *
+ * Online Certificate Status Protocol
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdarg.h>
+#include <time.h>
+#include <ipxe/asn1.h>
+#include <ipxe/x509.h>
+#include <ipxe/refcnt.h>
+
+/** OCSP algorithm identifier */
+#define OCSP_ALGORITHM_IDENTIFIER( ... )				\
+	ASN1_OID, VA_ARG_COUNT ( __VA_ARGS__ ), __VA_ARGS__,		\
+	ASN1_NULL, 0x00
+
+/* OCSP response statuses */
+#define OCSP_STATUS_SUCCESSFUL		0x00
+#define OCSP_STATUS_MALFORMED_REQUEST	0x01
+#define OCSP_STATUS_INTERNAL_ERROR	0x02
+#define OCSP_STATUS_TRY_LATER		0x03
+#define OCSP_STATUS_SIG_REQUIRED	0x05
+#define OCSP_STATUS_UNAUTHORIZED	0x06
+
+/** An OCSP request */
+struct ocsp_request {
+	/** Request builder */
+	struct asn1_builder builder;
+	/** Certificate ID */
+	struct asn1_cursor cert_id;
+};
+
+/** An OCSP response */
+struct ocsp_response {
+	/** Raw response */
+	void *data;
+	/** Raw tbsResponseData */
+	struct asn1_cursor tbs;
+	/** Time at which status is known to be correct */
+	time_t this_update;
+	/** Time at which newer status information will be available */
+	time_t next_update;
+	/** Signature algorithm */
+	struct asn1_algorithm *algorithm;
+	/** Signature value */
+	struct asn1_bit_string signature;
+	/** Signing certificate */
+	struct x509_certificate *signer;
+};
+
+/** An OCSP check */
+struct ocsp_check {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** Certificate being checked */
+	struct x509_certificate *cert;
+	/** Issuing certificate */
+	struct x509_certificate *issuer;
+	/** URI string */
+	char *uri_string;
+	/** Request */
+	struct ocsp_request request;
+	/** Response */
+	struct ocsp_response response;
+};
+
+/**
+ * Get reference to OCSP check
+ *
+ * @v ocsp		OCSP check
+ * @ret ocsp		OCSP check
+ */
+static inline __attribute__ (( always_inline )) struct ocsp_check *
+ocsp_get ( struct ocsp_check *ocsp ) {
+	ref_get ( &ocsp->refcnt );
+	return ocsp;
+}
+
+/**
+ * Drop reference to OCSP check
+ *
+ * @v ocsp		OCSP check
+ */
+static inline __attribute__ (( always_inline )) void
+ocsp_put ( struct ocsp_check *ocsp ) {
+	ref_put ( &ocsp->refcnt );
+}
+
+extern int ocsp_check ( struct x509_certificate *cert,
+			struct x509_certificate *issuer,
+			struct ocsp_check **ocsp );
+extern int ocsp_response ( struct ocsp_check *ocsp, const void *data,
+			   size_t len );
+extern int ocsp_validate ( struct ocsp_check *check, time_t time );
+
+#endif /* _IPXE_OCSP_H */
diff --git a/roms/ipxe/src/include/ipxe/parseopt.h b/roms/ipxe/src/include/ipxe/parseopt.h
index eed40b76999011aa37559696a879..b492a51e555fc447e2d527685442 100644
--- a/roms/ipxe/src/include/ipxe/parseopt.h
+++ b/roms/ipxe/src/include/ipxe/parseopt.h
@@ -13,7 +13,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <stddef.h>
 
 struct net_device;
-struct image;
+struct menu;
 
 /** A command-line option descriptor */
 struct option_descriptor {
@@ -117,9 +117,12 @@ struct command_descriptor {
 extern int parse_string ( const char *text, const char **value );
 extern int parse_integer ( const char *text, unsigned int *value );
 extern int parse_netdev ( const char *text, struct net_device **netdev );
-extern int parse_image ( const char *text, struct image **image );
+extern int parse_menu ( const char *text, struct menu **menu );
 extern int parse_flag ( const char *text __unused, int *flag );
+extern int parse_key ( const char *text, unsigned int *key );
 extern void print_usage ( struct command_descriptor *cmd, char **argv );
+extern int reparse_options ( int argc, char **argv,
+			     struct command_descriptor *cmd, void *opts );
 extern int parse_options ( int argc, char **argv,
 			   struct command_descriptor *cmd, void *opts );
 
diff --git a/roms/ipxe/src/include/ipxe/pci.h b/roms/ipxe/src/include/ipxe/pci.h
index 960454d69df678fbecc658039090..a6ed484f1c803d4141bbad45d269 100644
--- a/roms/ipxe/src/include/ipxe/pci.h
+++ b/roms/ipxe/src/include/ipxe/pci.h
@@ -172,7 +172,7 @@ FILE_LICENCE ( GPL2_ONLY );
 #define  PCI_PM_CAP_PME_CLOCK	0x0008	/* PME clock required */
 #define  PCI_PM_CAP_RESERVED    0x0010  /* Reserved field */
 #define  PCI_PM_CAP_DSI		0x0020	/* Device specific initialization */
-#define  PCI_PM_CAP_AUX_POWER	0x01C0	/* Auxilliary power support mask */
+#define  PCI_PM_CAP_AUX_POWER	0x01C0	/* Auxiliary power support mask */
 #define  PCI_PM_CAP_D1		0x0200	/* D1 power state support */
 #define  PCI_PM_CAP_D2		0x0400	/* D2 power state support */
 #define  PCI_PM_CAP_PME		0x0800	/* PME pin supported */
@@ -343,6 +343,9 @@ struct pci_driver {
 /** Declare a PCI driver */
 #define __pci_driver __table_entry ( PCI_DRIVERS, 01 )
 
+/** Declare a fallback PCI driver */
+#define __pci_driver_fallback __table_entry ( PCI_DRIVERS, 02 )
+
 #define PCI_BUS( busdevfn )		( ( (busdevfn) >> 8 ) & 0xff )
 #define PCI_SLOT( busdevfn )		( ( (busdevfn) >> 3 ) & 0x1f )
 #define PCI_FUNC( busdevfn )		( ( (busdevfn) >> 0 ) & 0x07 )
diff --git a/roms/ipxe/src/include/ipxe/pending.h b/roms/ipxe/src/include/ipxe/pending.h
new file mode 100644
index 0000000000000000000000000000000000000000..51afb43709c18cbb56432c09bf4b84b796cd1005
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/pending.h
@@ -0,0 +1,34 @@
+#ifndef _IPXE_PENDING_H
+#define _IPXE_PENDING_H
+
+/** @file
+ *
+ * Pending operations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/list.h>
+
+/** A pending operation */
+struct pending_operation {
+	/** Pending count */
+	unsigned int count;
+};
+
+/**
+ * Check if an operation is pending
+ *
+ * @v pending		Pending operation
+ * @v is_pending	Operation is pending
+ */
+static inline int is_pending ( struct pending_operation *pending ) {
+	return ( pending->count != 0 );
+}
+
+extern void pending_get ( struct pending_operation *pending );
+extern void pending_put ( struct pending_operation *pending );
+extern int pending_wait ( unsigned long timeout );
+
+#endif /* _IPXE_PENDING_H */
diff --git a/roms/ipxe/src/include/ipxe/process.h b/roms/ipxe/src/include/ipxe/process.h
index 45c2af639e5888b4ee0d841a6d9e..9b757981794be21eee4009352de1 100644
--- a/roms/ipxe/src/include/ipxe/process.h
+++ b/roms/ipxe/src/include/ipxe/process.h
@@ -17,6 +17,20 @@ FILE_LICENCE ( GPL2_OR_LATER );
 struct process {
 	/** List of processes */
 	struct list_head list;
+	/** Process descriptor */
+	struct process_descriptor *desc;
+	/** Reference counter
+	 *
+	 * If this process is not part of a reference-counted object,
+	 * this field may be NULL.
+	 */
+	struct refcnt *refcnt;
+};
+
+/** A process descriptor */
+struct process_descriptor {
+	/** Offset of process within containing object */
+	size_t offset;
 	/**
 	 * Single-step the process
 	 *
@@ -24,15 +38,81 @@ struct process {
 	 * Returning from this method is isomorphic to yielding the
 	 * CPU to another process.
 	 */
-	void ( * step ) ( struct process *process );
-	/** Reference counter
-	 *
-	 * If this interface is not part of a reference-counted
-	 * object, this field may be NULL.
-	 */
-	struct refcnt *refcnt;
+	void ( * step ) ( void *object );
+	/** Automatically reschedule the process */
+	int reschedule;
 };
 
+/**
+ * Define a process step() method
+ *
+ * @v object_type	Implementing method's expected object type
+ * @v step		Implementing method
+ * @ret step		Process step method
+ */
+#define PROC_STEP( object_type, step )					      \
+	( ( ( ( typeof ( step ) * ) NULL ) ==				      \
+	    ( ( void ( * ) ( object_type *object ) ) NULL ) ) ?		      \
+	  ( void ( * ) ( void *object ) ) step :			      \
+	  ( void ( * ) ( void *object ) ) step )
+
+/**
+ * Calculate offset of process within containing object
+ *
+ * @v object_type	Containing object data type
+ * @v name		Process name (i.e. field within object data type)
+ * @ret offset		Offset of process within containing object
+ */
+#define process_offset( object_type, name )				      \
+	( ( ( ( typeof ( ( ( object_type * ) NULL )->name ) * ) NULL )	      \
+	    == ( ( struct process * ) NULL ) )			      	      \
+	  ? offsetof ( object_type, name )				      \
+	  : offsetof ( object_type, name ) )
+
+/**
+ * Define a process descriptor
+ *
+ * @v object_type	Containing object data type
+ * @v process		Process name (i.e. field within object data type)
+ * @v step		Process' step() method
+ * @ret desc		Object interface descriptor
+ */
+#define PROC_DESC( object_type, process, _step ) {			      \
+		.offset = process_offset ( object_type, process ),	      \
+		.step = PROC_STEP ( object_type, _step ),		      \
+		.reschedule = 1,					      \
+	}
+
+/**
+ * Define a process descriptor for a process that runs only once
+ *
+ * @v object_type	Containing object data type
+ * @v process		Process name (i.e. field within object data type)
+ * @v step		Process' step() method
+ * @ret desc		Object interface descriptor
+ */
+#define PROC_DESC_ONCE( object_type, process, _step ) {			      \
+		.offset = process_offset ( object_type, process ),	      \
+		.step = PROC_STEP ( object_type, _step ),		      \
+		.reschedule = 0,					      \
+	}
+
+/**
+ * Define a process descriptor for a pure process
+ *
+ * A pure process is a process that does not have a containing object.
+ *
+ * @v step		Process' step() method
+ * @ret desc		Object interface descriptor
+ */
+#define PROC_DESC_PURE( _step ) {					      \
+		.offset = 0,						      \
+		.step = PROC_STEP ( struct process, _step ),		      \
+		.reschedule = 1,					      \
+	}
+
+extern void * __attribute__ (( pure ))
+process_object ( struct process *process );
 extern void process_add ( struct process *process );
 extern void process_del ( struct process *process );
 extern void step ( void );
@@ -41,14 +121,15 @@ extern void step ( void );
  * Initialise process without adding to process list
  *
  * @v process		Process
- * @v step		Process' step() method
+ * @v desc		Process descriptor
+ * @v refcnt		Containing object reference count, or NULL
  */
 static inline __attribute__ (( always_inline )) void
 process_init_stopped ( struct process *process,
-		       void ( * step ) ( struct process *process ),
+		       struct process_descriptor *desc,
 		       struct refcnt *refcnt ) {
 	INIT_LIST_HEAD ( &process->list );
-	process->step = step;
+	process->desc = desc;
 	process->refcnt = refcnt;
 }
 
@@ -56,13 +137,14 @@ process_init_stopped ( struct process *process,
  * Initialise process and add to process list
  *
  * @v process		Process
- * @v step		Process' step() method
+ * @v desc		Process descriptor
+ * @v refcnt		Containing object reference count, or NULL
  */
 static inline __attribute__ (( always_inline )) void
 process_init ( struct process *process,
-	       void ( * step ) ( struct process *process ),
+	       struct process_descriptor *desc,
 	       struct refcnt *refcnt ) {
-	process_init_stopped ( process, step, refcnt );
+	process_init_stopped ( process, desc, refcnt );
 	process_add ( process );
 }
 
@@ -88,4 +170,36 @@ process_running ( struct process *process ) {
  */
 #define __permanent_process __table_entry ( PERMANENT_PROCESSES, 01 )
 
+/** Define a permanent process
+ *
+ */
+#define PERMANENT_PROCESS( name, step )					      \
+struct process_descriptor name ## _desc = PROC_DESC_PURE ( step );	      \
+struct process name __permanent_process = {				      \
+	.list = LIST_HEAD_INIT ( name.list ),				      \
+	.desc = & name ## _desc,					      \
+	.refcnt = NULL,							      \
+};
+
+/**
+ * Find debugging colourisation for a process
+ *
+ * @v process		Process
+ * @ret col		Debugging colourisation
+ *
+ * Use as the first argument to DBGC() or equivalent macro.
+ */
+#define PROC_COL( process ) process_object ( process )
+
+/** printf() format string for PROC_DBG() */
+#define PROC_FMT "%p+%zx"
+
+/**
+ * printf() arguments for representing a process
+ *
+ * @v process		Process
+ * @ret args		printf() argument list corresponding to PROC_FMT
+ */
+#define PROC_DBG( process ) process_object ( process ), (process)->desc->offset
+
 #endif /* _IPXE_PROCESS_H */
diff --git a/roms/ipxe/src/include/ipxe/random_nz.h b/roms/ipxe/src/include/ipxe/random_nz.h
new file mode 100644
index 0000000000000000000000000000000000000000..6bb80d2abc988c6a6f88e4a243507c1cab4589b1
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/random_nz.h
@@ -0,0 +1,16 @@
+#ifndef _IPXE_RANDOM_NZ_H
+#define _IPXE_RANDOM_NZ_H
+
+/** @file
+ *
+ * HMAC_DRBG algorithm
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+extern int get_random_nz ( void *data, size_t len );
+
+#endif /* _IPXE_RANDOM_NZ_H */
diff --git a/roms/ipxe/src/include/ipxe/rbg.h b/roms/ipxe/src/include/ipxe/rbg.h
new file mode 100644
index 0000000000000000000000000000000000000000..9689142f8eb3be2ffd7f94ad41f132d505b02f83
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/rbg.h
@@ -0,0 +1,43 @@
+#ifndef _IPXE_RBG_H
+#define _IPXE_RBG_H
+
+/** @file
+ *
+ * RBG mechanism
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/drbg.h>
+
+/** An RBG */
+struct random_bit_generator {
+	/** DRBG state */
+	struct drbg_state state;
+};
+
+extern struct random_bit_generator rbg;
+
+/**
+ * Generate bits using RBG
+ *
+ * @v additional	Additional input
+ * @v additional_len	Length of additional input
+ * @v prediction_resist	Prediction resistance is required
+ * @v data		Output buffer
+ * @v len		Length of output buffer
+ * @ret rc		Return status code
+ *
+ * This is the RBG_Generate function defined in ANS X9.82 Part 4
+ * (April 2011 Draft) Section 9.1.2.2.
+ */
+static inline int rbg_generate ( const void *additional, size_t additional_len,
+				 int prediction_resist, void *data,
+				 size_t len ) {
+	return drbg_generate ( &rbg.state, additional, additional_len,
+			       prediction_resist, data, len );
+}
+
+#endif /* _IPXE_RBG_H */
diff --git a/roms/ipxe/src/include/ipxe/retry.h b/roms/ipxe/src/include/ipxe/retry.h
index 87f69a5d75edbad1dc0a0dcdc7bf..c514822b2940a12390e959ecb9a6 100644
--- a/roms/ipxe/src/include/ipxe/retry.h
+++ b/roms/ipxe/src/include/ipxe/retry.h
@@ -85,6 +85,7 @@ extern void start_timer ( struct retry_timer *timer );
 extern void start_timer_fixed ( struct retry_timer *timer,
 				unsigned long timeout );
 extern void stop_timer ( struct retry_timer *timer );
+extern void retry_poll ( void );
 
 /**
  * Start timer with no delay
diff --git a/roms/ipxe/src/include/ipxe/rootcert.h b/roms/ipxe/src/include/ipxe/rootcert.h
new file mode 100644
index 0000000000000000000000000000000000000000..6525df87a6f96c5a1001c5714850aa04f0c66ed2
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/rootcert.h
@@ -0,0 +1,16 @@
+#ifndef _IPXE_ROOTCERT_H
+#define _IPXE_ROOTCERT_H
+
+/** @file
+ *
+ * Root certificate store
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/x509.h>
+
+extern struct x509_root root_certificates;
+
+#endif /* _IPXE_ROOTCERT_H */
diff --git a/roms/ipxe/src/include/ipxe/rotate.h b/roms/ipxe/src/include/ipxe/rotate.h
index 745d84e6c25dd05d10d7f7fd52d2..ba271ca740d776b3a6c30634eb62 100644
--- a/roms/ipxe/src/include/ipxe/rotate.h
+++ b/roms/ipxe/src/include/ipxe/rotate.h
@@ -10,19 +10,23 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
 
-static inline uint32_t rol32 ( uint32_t data, unsigned int rotation ) {
+static inline __attribute__ (( always_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 ) {
+static inline __attribute__ (( always_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 ) {
+static inline __attribute__ (( always_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 ) {
+static inline __attribute__ (( always_inline )) uint64_t
+ror64 ( uint64_t data, unsigned int rotation ) {
         return ( ( data >> rotation ) | ( data << ( 64 - rotation ) ) );
 }
 
diff --git a/roms/ipxe/src/include/ipxe/rsa.h b/roms/ipxe/src/include/ipxe/rsa.h
index a080f9f08afe4bcb1537b6789f2f..1a5ad8bab30d056474ca7e286570 100644
--- a/roms/ipxe/src/include/ipxe/rsa.h
+++ b/roms/ipxe/src/include/ipxe/rsa.h
@@ -1,12 +1,81 @@
 #ifndef _IPXE_RSA_H
 #define _IPXE_RSA_H
 
+/** @file
+ *
+ * RSA public-key cryptography
+ */
+
 FILE_LICENCE ( GPL2_OR_LATER );
 
-struct pubkey_algorithm;
+#include <ipxe/crypto.h>
+#include <ipxe/bigint.h>
+#include <ipxe/asn1.h>
+#include <ipxe/tables.h>
 
-extern struct pubkey_algorithm rsa_algorithm;
+/** RSA digestAlgorithm sequence contents */
+#define RSA_DIGESTALGORITHM_CONTENTS( ... )				\
+	ASN1_OID, VA_ARG_COUNT ( __VA_ARGS__ ), __VA_ARGS__,		\
+	ASN1_NULL, 0x00
+
+/** RSA digestAlgorithm sequence */
+#define RSA_DIGESTALGORITHM( ... )					\
+	ASN1_SEQUENCE,							\
+	VA_ARG_COUNT ( RSA_DIGESTALGORITHM_CONTENTS ( __VA_ARGS__ ) ),	\
+	RSA_DIGESTALGORITHM_CONTENTS ( __VA_ARGS__ )
+
+/** RSA digest prefix */
+#define RSA_DIGEST_PREFIX( digest_size )				\
+	ASN1_OCTET_STRING, digest_size
+
+/** RSA digestInfo prefix */
+#define RSA_DIGESTINFO_PREFIX( digest_size, ... )			\
+	ASN1_SEQUENCE,							\
+	( VA_ARG_COUNT ( RSA_DIGESTALGORITHM ( __VA_ARGS__ ) ) +	\
+	  VA_ARG_COUNT ( RSA_DIGEST_PREFIX ( digest_size ) ) +		\
+	  digest_size ),						\
+	RSA_DIGESTALGORITHM ( __VA_ARGS__ ),				\
+	RSA_DIGEST_PREFIX ( digest_size )
 
-#include "crypto/axtls/crypto.h"
+/** An RSA digestInfo prefix */
+struct rsa_digestinfo_prefix {
+	/** Digest algorithm */
+	struct digest_algorithm *digest;
+	/** Prefix */
+	const void *data;
+	/** Length of prefix */
+	size_t len;
+};
+
+/** RSA digestInfo prefix table */
+#define RSA_DIGESTINFO_PREFIXES \
+	__table ( struct rsa_digestinfo_prefix, "rsa_digestinfo_prefixes" )
+
+/** Declare an RSA digestInfo prefix */
+#define __rsa_digestinfo_prefix __table_entry ( RSA_DIGESTINFO_PREFIXES, 01 )
+
+/** An RSA context */
+struct rsa_context {
+	/** Allocated memory */
+	void *dynamic;
+	/** Modulus */
+	bigint_element_t *modulus0;
+	/** Modulus size */
+	unsigned int size;
+	/** Modulus length */
+	size_t max_len;
+	/** Exponent */
+	bigint_element_t *exponent0;
+	/** Exponent size */
+	unsigned int exponent_size;
+	/** Input buffer */
+	bigint_element_t *input0;
+	/** Output buffer */
+	bigint_element_t *output0;
+	/** Temporary working space for modular exponentiation */
+	void *tmp;
+};
+
+extern struct pubkey_algorithm rsa_algorithm;
 
 #endif /* _IPXE_RSA_H */
diff --git a/roms/ipxe/src/include/ipxe/sanboot.h b/roms/ipxe/src/include/ipxe/sanboot.h
index 913282eb5c7144dbfee1ca74e5de..14c8a5da459864d8c309aad98a1c 100644
--- a/roms/ipxe/src/include/ipxe/sanboot.h
+++ b/roms/ipxe/src/include/ipxe/sanboot.h
@@ -58,12 +58,19 @@ struct uri;
 /* Include all architecture-dependent sanboot API headers */
 #include <bits/sanboot.h>
 
+/**
+ * Get default SAN drive number
+ *
+ * @ret drive		Default drive number
+ */
+unsigned int san_default_drive ( void );
+
 /**
  * Hook SAN device
  *
  * @v uri		URI
- * @v drive		Requested drive number
- * @ret drive		Assigned drive number, or negative error
+ * @v drive		Drive number
+ * @ret rc		Return status code
  */
 int san_hook ( struct uri *uri, unsigned int drive );
 
diff --git a/roms/ipxe/src/include/ipxe/sec80211.h b/roms/ipxe/src/include/ipxe/sec80211.h
index 59ca3eb85c42b7693232f6951d8f..3ca3d84f2d755e760050bfe52fc1 100644
--- a/roms/ipxe/src/include/ipxe/sec80211.h
+++ b/roms/ipxe/src/include/ipxe/sec80211.h
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #ifndef _IPXE_SEC80211_H
diff --git a/roms/ipxe/src/include/ipxe/serial.h b/roms/ipxe/src/include/ipxe/serial.h
index c16e56ae6ab4b4a317fbbe4b5a4b..b47b1d1252b78aa779409076ee8e 100644
--- a/roms/ipxe/src/include/ipxe/serial.h
+++ b/roms/ipxe/src/include/ipxe/serial.h
@@ -12,5 +12,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
 extern void serial_putc ( int ch );
 extern int serial_getc ( void );
 extern int serial_ischar ( void );
+extern int serial_initialized;
 
 #endif /* _IPXE_SERIAL_H */
diff --git a/roms/ipxe/src/include/ipxe/settings.h b/roms/ipxe/src/include/ipxe/settings.h
index 0f1ec5bacccaafa11df064355fbd..3f8876020a5ffb1fb1d3c8e72d5e 100644
--- a/roms/ipxe/src/include/ipxe/settings.h
+++ b/roms/ipxe/src/include/ipxe/settings.h
@@ -83,7 +83,8 @@ struct setting {
 #define SETTING_HOST_EXTRA	10 /**< Host identity additional settings */
 #define SETTING_AUTH		11 /**< Authentication settings */
 #define SETTING_AUTH_EXTRA	12 /**< Authentication additional settings */
-#define SETTING_MISC		13 /**< Miscellaneous settings */
+#define SETTING_CRYPTO		13 /**< Cryptography settings */
+#define SETTING_MISC		14 /**< Miscellaneous settings */
 
 /** @} */
 
@@ -161,25 +162,24 @@ struct setting_type {
 	 * This is the name exposed to the user (e.g. "string").
 	 */
 	const char *name;
-	/** Parse and set value of setting
+	/** Parse formatted setting value
 	 *
-	 * @v settings		Settings block
-	 * @v setting		Setting to store
-	 * @v value		Formatted setting data
-	 * @ret rc		Return status code
+	 * @v value		Formatted setting value
+	 * @v buf		Buffer to contain raw value
+	 * @v len		Length of buffer
+	 * @ret len		Length of raw value, or negative error
 	 */
-	int ( * storef ) ( struct settings *settings, struct setting *setting,
-			   const char *value );
-	/** Fetch and format value of setting
+	int ( * parse ) ( const char *value, void *buf, size_t len );
+	/** Format setting value
 	 *
-	 * @v settings		Settings block
-	 * @v setting		Setting to fetch
+	 * @v raw		Raw setting value
+	 * @v raw_len		Length of raw setting value
 	 * @v buf		Buffer to contain formatted value
 	 * @v len		Length of buffer
 	 * @ret len		Length of formatted value, or negative error
 	 */
-	int ( * fetchf ) ( struct settings *settings, struct setting *setting,
-			   char *buf, size_t len );
+	int ( * format ) ( const void *raw, size_t raw_len, char *buf,
+			   size_t len );
 };
 
 /** Configuration setting type table */
@@ -241,6 +241,8 @@ extern struct settings * fetch_setting_origin ( struct settings *settings,
 						struct setting *setting );
 extern int fetch_setting_len ( struct settings *settings,
 			       struct setting *setting );
+extern int fetch_setting_copy ( struct settings *settings,
+				struct setting *setting, void **data );
 extern int fetch_string_setting ( struct settings *settings,
 				  struct setting *setting,
 				  char *data, size_t len );
@@ -267,22 +269,33 @@ extern int fetch_uuid_setting ( struct settings *settings,
 extern void clear_settings ( struct settings *settings );
 extern int setting_cmp ( struct setting *a, struct setting *b );
 
+extern struct settings * find_child_settings ( struct settings *parent,
+					       const char *name );
 extern const char * settings_name ( struct settings *settings );
 extern struct settings * find_settings ( const char *name );
 extern struct setting * find_setting ( const char *name );
 
 extern int setting_name ( struct settings *settings, struct setting *setting,
 			  char *buf, size_t len );
+extern int fetchf_setting ( struct settings *settings, struct setting *setting,
+			    char *buf, size_t len );
 extern int storef_setting ( struct settings *settings,
 			    struct setting *setting,
 			    const char *value );
-extern int storef_named_setting ( const char *name, const char *value );
+extern int store_named_setting ( const char *name,
+				 struct setting_type *default_type,
+				 const void *data, size_t len );
+extern int storef_named_setting ( const char *name,
+				  struct setting_type *default_type,
+				  const char *value );
 extern int fetchf_named_setting ( const char *name, char *name_buf,
 				  size_t name_len, char *value_buf,
 				  size_t value_len );
+extern int fetchf_named_setting_copy ( const char *name, char **data );
 extern char * expand_settings ( const char *string );
 
 extern struct setting_type setting_type_string __setting_type;
+extern struct setting_type setting_type_uristring __setting_type;
 extern struct setting_type setting_type_ipv4 __setting_type;
 extern struct setting_type setting_type_int8 __setting_type;
 extern struct setting_type setting_type_int16 __setting_type;
@@ -291,6 +304,7 @@ extern struct setting_type setting_type_uint8 __setting_type;
 extern struct setting_type setting_type_uint16 __setting_type;
 extern struct setting_type setting_type_uint32 __setting_type;
 extern struct setting_type setting_type_hex __setting_type;
+extern struct setting_type setting_type_hexhyp __setting_type;
 extern struct setting_type setting_type_uuid __setting_type;
 
 extern struct setting ip_setting __setting ( SETTING_IPv4 );
@@ -298,6 +312,7 @@ extern struct setting netmask_setting __setting ( SETTING_IPv4 );
 extern struct setting gateway_setting __setting ( SETTING_IPv4 );
 extern struct setting dns_setting __setting ( SETTING_IPv4_EXTRA );
 extern struct setting hostname_setting __setting ( SETTING_HOST );
+extern struct setting domain_setting __setting ( SETTING_IPv4_EXTRA );
 extern struct setting filename_setting __setting ( SETTING_BOOT );
 extern struct setting root_path_setting __setting ( SETTING_SANBOOT );
 extern struct setting username_setting __setting ( SETTING_AUTH );
@@ -352,22 +367,6 @@ static inline int delete_setting ( struct settings *settings,
 	return store_setting ( settings, setting, NULL, 0 );
 }
 
-/**
- * Fetch and format value of setting
- *
- * @v settings		Settings block, or NULL to search all blocks
- * @v setting		Setting to fetch
- * @v type		Settings type
- * @v buf		Buffer to contain formatted value
- * @v len		Length of buffer
- * @ret len		Length of formatted value, or negative error
- */
-static inline int fetchf_setting ( struct settings *settings,
-				   struct setting *setting,
-				   char *buf, size_t len ) {
-	return setting->type->fetchf ( settings, setting, buf, len );
-}
-
 /**
  * Delete named setting
  *
@@ -375,7 +374,7 @@ static inline int fetchf_setting ( struct settings *settings,
  * @ret rc		Return status code
  */
 static inline int delete_named_setting ( const char *name ) {
-	return storef_named_setting ( name, NULL );
+	return store_named_setting ( name, NULL, NULL, 0 );
 }
 
 /**
diff --git a/roms/ipxe/src/include/ipxe/sha1.h b/roms/ipxe/src/include/ipxe/sha1.h
index 9b6f55147215bc6c180ea40f978a..a97035ec769a5842ceadfd4f6255 100644
--- a/roms/ipxe/src/include/ipxe/sha1.h
+++ b/roms/ipxe/src/include/ipxe/sha1.h
@@ -1,24 +1,80 @@
 #ifndef _IPXE_SHA1_H
 #define _IPXE_SHA1_H
 
+/** @file
+ *
+ * SHA-1 algorithm
+ *
+ */
+
 FILE_LICENCE ( GPL2_OR_LATER );
 
-#include "crypto/axtls/crypto.h"
+#include <stdint.h>
+#include <ipxe/crypto.h>
 
-struct digest_algorithm;
+/** An SHA-1 digest */
+struct sha1_digest {
+	/** Hash output */
+	uint32_t h[5];
+};
 
-#define SHA1_CTX_SIZE sizeof ( SHA1_CTX )
-#define SHA1_DIGEST_SIZE SHA1_SIZE
+/** An SHA-1 data block */
+union sha1_block {
+	/** Raw bytes */
+	uint8_t byte[64];
+	/** Raw dwords */
+	uint32_t dword[16];
+	/** Final block structure */
+	struct {
+		/** Padding */
+		uint8_t pad[56];
+		/** Length in bits */
+		uint64_t len;
+	} final;
+};
 
-extern struct digest_algorithm sha1_algorithm;
+/** SHA-1 digest and data block
+ *
+ * The order of fields within this structure is designed to minimise
+ * code size.
+ */
+struct sha1_digest_data {
+	/** Digest of data already processed */
+	struct sha1_digest digest;
+	/** Accumulated data */
+	union sha1_block data;
+} __attribute__ (( packed ));
+
+/** SHA-1 digest and data block */
+union sha1_digest_data_dwords {
+	/** Digest and data block */
+	struct sha1_digest_data dd;
+	/** Raw dwords */
+	uint32_t dword[ sizeof ( struct sha1_digest_data ) /
+			sizeof ( uint32_t ) ];
+};
 
-/* SHA1-wrapping functions defined in sha1extra.c: */
+/** An SHA-1 context */
+struct sha1_context {
+	/** Amount of accumulated data */
+	size_t len;
+	/** Digest and accumulated data */
+	union sha1_digest_data_dwords ddd;
+} __attribute__ (( packed ));
 
-void prf_sha1 ( const void *key, size_t key_len, const char *label,
-		const void *data, size_t data_len, void *prf, size_t prf_len );
+/** SHA-1 context size */
+#define SHA1_CTX_SIZE sizeof ( struct sha1_context )
+
+/** SHA-1 digest size */
+#define SHA1_DIGEST_SIZE sizeof ( struct sha1_digest )
+
+extern struct digest_algorithm sha1_algorithm;
 
-void pbkdf2_sha1 ( const void *passphrase, size_t pass_len,
-		   const void *salt, size_t salt_len,
-		   int iterations, void *key, size_t key_len );
+extern void prf_sha1 ( const void *key, size_t key_len, const char *label,
+		       const void *data, size_t data_len, void *prf,
+		       size_t prf_len );
+extern void pbkdf2_sha1 ( const void *passphrase, size_t pass_len,
+			  const void *salt, size_t salt_len,
+			  int iterations, void *key, size_t key_len );
 
 #endif /* _IPXE_SHA1_H */
diff --git a/roms/ipxe/src/include/ipxe/sha256.h b/roms/ipxe/src/include/ipxe/sha256.h
new file mode 100644
index 0000000000000000000000000000000000000000..9aa9f3e57e7acda479b7b6f34119a000a210ac3d
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/sha256.h
@@ -0,0 +1,73 @@
+#ifndef _IPXE_SHA256_H
+#define _IPXE_SHA256_H
+
+/** @file
+ *
+ * SHA-256 algorithm
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/crypto.h>
+
+/** An SHA-256 digest */
+struct sha256_digest {
+	/** Hash output */
+	uint32_t h[8];
+};
+
+/** An SHA-256 data block */
+union sha256_block {
+	/** Raw bytes */
+	uint8_t byte[64];
+	/** Raw dwords */
+	uint32_t dword[16];
+	/** Final block structure */
+	struct {
+		/** Padding */
+		uint8_t pad[56];
+		/** Length in bits */
+		uint64_t len;
+	} final;
+};
+
+/** SHA-256 digest and data block
+ *
+ * The order of fields within this structure is designed to minimise
+ * code size.
+ */
+struct sha256_digest_data {
+	/** Digest of data already processed */
+	struct sha256_digest digest;
+	/** Accumulated data */
+	union sha256_block data;
+} __attribute__ (( packed ));
+
+/** SHA-256 digest and data block */
+union sha256_digest_data_dwords {
+	/** Digest and data block */
+	struct sha256_digest_data dd;
+	/** Raw dwords */
+	uint32_t dword[ sizeof ( struct sha256_digest_data ) /
+			sizeof ( uint32_t ) ];
+};
+
+/** An SHA-256 context */
+struct sha256_context {
+	/** Amount of accumulated data */
+	size_t len;
+	/** Digest and accumulated data */
+	union sha256_digest_data_dwords ddd;
+} __attribute__ (( packed ));
+
+/** SHA-256 context size */
+#define SHA256_CTX_SIZE sizeof ( struct sha256_context )
+
+/** SHA-256 digest size */
+#define SHA256_DIGEST_SIZE sizeof ( struct sha256_digest )
+
+extern struct digest_algorithm sha256_algorithm;
+
+#endif /* _IPXE_SHA256_H */
diff --git a/roms/ipxe/src/include/ipxe/smbios.h b/roms/ipxe/src/include/ipxe/smbios.h
index fcf149ea7353031e8233e669982d..0765c4e4a3365cda290894312ab6 100644
--- a/roms/ipxe/src/include/ipxe/smbios.h
+++ b/roms/ipxe/src/include/ipxe/smbios.h
@@ -148,8 +148,19 @@ struct smbios {
 	size_t len;
 	/** Number of SMBIOS structures */
 	unsigned int count;
+	/** SMBIOS version */
+	uint16_t version;
 };
 
+/**
+ * Calculate SMBIOS version
+ *
+ * @v major		Major version
+ * @v minor		Minor version
+ * @ret version		SMBIOS version
+ */
+#define SMBIOS_VERSION( major, minor ) ( ( (major) << 8 ) | (minor) )
+
 extern int find_smbios ( struct smbios *smbios );
 extern int find_smbios_structure ( unsigned int type,
 				   struct smbios_structure *structure );
@@ -158,5 +169,6 @@ extern int read_smbios_structure ( struct smbios_structure *structure,
 extern int read_smbios_string ( struct smbios_structure *structure,
 				unsigned int index,
 				void *data, size_t len );
+extern int smbios_version ( void );
 
 #endif /* _IPXE_SMBIOS_H */
diff --git a/roms/ipxe/src/include/ipxe/syslog.h b/roms/ipxe/src/include/ipxe/syslog.h
index 25edc6b0c6eb2d93d220a590908c..131692654ead023fadeb0f5b4b16 100644
--- a/roms/ipxe/src/include/ipxe/syslog.h
+++ b/roms/ipxe/src/include/ipxe/syslog.h
@@ -9,6 +9,8 @@
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
+#include <syslog.h>
+
 /** Syslog server port */
 #define SYSLOG_PORT 514
 
@@ -18,19 +20,22 @@ FILE_LICENCE ( GPL2_OR_LATER );
  */
 #define SYSLOG_BUFSIZE 128
 
-/** Syslog facility
+/** Syslog default facility
  *
  * This is a policy decision
  */
-#define SYSLOG_FACILITY 0 /* kernel */
+#define SYSLOG_DEFAULT_FACILITY 0 /* kernel */
 
-/** Syslog severity
+/** Syslog default severity
  *
  * This is a policy decision
  */
-#define SYSLOG_SEVERITY 6 /* informational */
+#define SYSLOG_DEFAULT_SEVERITY LOG_INFO
 
 /** Syslog priority */
 #define SYSLOG_PRIORITY( facility, severity ) ( 8 * (facility) + (severity) )
 
+extern int syslog_send ( struct interface *xfer, unsigned int severity,
+			 const char *message, const char *terminator );
+
 #endif /* _IPXE_SYSLOG_H */
diff --git a/roms/ipxe/src/include/ipxe/tcp.h b/roms/ipxe/src/include/ipxe/tcp.h
index 197712b1188b84b7c6a243702767..6b6691175fcb05e65ad926bd8d24 100644
--- a/roms/ipxe/src/include/ipxe/tcp.h
+++ b/roms/ipxe/src/include/ipxe/tcp.h
@@ -54,6 +54,31 @@ struct tcp_mss_option {
 /** Code for the TCP MSS option */
 #define TCP_OPTION_MSS 2
 
+/** TCP window scale option */
+struct tcp_window_scale_option {
+	uint8_t kind;
+	uint8_t length;
+	uint8_t scale;
+} __attribute__ (( packed ));
+
+/** Padded TCP window scale option (used for sending) */
+struct tcp_window_scale_padded_option {
+	uint8_t nop;
+	struct tcp_window_scale_option wsopt;
+} __attribute (( packed ));
+
+/** Code for the TCP window scale option */
+#define TCP_OPTION_WS 3
+
+/** Advertised TCP window scale
+ *
+ * Using a scale factor of 2**9 provides for a maximum window of 32MB,
+ * which is sufficient to allow Gigabit-speed transfers with a 200ms
+ * RTT.  The minimum advertised window is 512 bytes, which is still
+ * less than a single packet.
+ */
+#define TCP_RX_WINDOW_SCALE 9
+
 /** TCP timestamp option */
 struct tcp_timestamp_option {
 	uint8_t kind;
@@ -75,7 +100,9 @@ struct tcp_timestamp_padded_option {
 struct tcp_options {
 	/** MSS option, if present */
 	const struct tcp_mss_option *mssopt;
-	/** Timestampe option, if present */
+	/** Window scale option, if present */
+	const struct tcp_window_scale_option *wsopt;
+	/** Timestamp option, if present */
 	const struct tcp_timestamp_option *tsopt;
 };
 
@@ -260,29 +287,31 @@ struct tcp_options {
 /**
  * Maxmimum advertised TCP window size
  *
- * We estimate the TCP window size as the amount of free memory we
- * have.  This is not strictly accurate (since it ignores any space
- * already allocated as RX buffers), but it will do for now.
+ * The maximum bandwidth on any link is limited by
+ *
+ *    max_bandwidth * round_trip_time = tcp_window
+ *
+ * Some rough expectations for achievable bandwidths over various
+ * links are:
+ *
+ *    a) Gigabit LAN: expected bandwidth 125MB/s, typical RTT 0.5ms,
+ *       minimum required window 64kB
  *
- * Since we don't store out-of-order received packets, the
- * retransmission penalty is that the whole window contents must be
- * resent.  This suggests keeping the window size small, but bear in
- * mind that the maximum bandwidth on any link is limited to
+ *    b) Home Internet connection: expected bandwidth 10MB/s, typical
+ *       RTT 25ms, minimum required window 256kB
  *
- *    max_bandwidth = ( tcp_window / round_trip_time )
+ *    c) WAN: expected bandwidth 2MB/s, typical RTT 100ms, minimum
+ *       required window 200kB.
  *
- * With a 48kB window, which probably accurately reflects our amount
- * of free memory, and a WAN RTT of say 200ms, this gives a maximum
- * bandwidth of 240kB/s.  This is sufficiently close to realistic that
- * we will need to be careful that our advertised window doesn't end
- * up limiting WAN download speeds.
+ * The maximum possible value for the TCP window size is 1GB (using
+ * the maximum window scale of 2**14).  However, it is advisable to
+ * keep the window size as small as possible (without limiting
+ * bandwidth), since in the event of a lost packet the window size
+ * represents the maximum amount that will need to be retransmitted.
  *
- * Finally, since the window goes into a 16-bit field and we cannot
- * actually use 65536, we use a window size of (65536-4) to ensure
- * that payloads remain dword-aligned.
+ * We therefore choose a maximum window size of 256kB.
  */
-//#define TCP_MAX_WINDOW_SIZE	( 65536 - 4 )
-#define TCP_MAX_WINDOW_SIZE	8192
+#define TCP_MAX_WINDOW_SIZE	( 256 * 1024 )
 
 /**
  * Path MTU
@@ -308,6 +337,17 @@ struct tcp_options {
  */
 #define TCP_MSL ( 2 * 60 * TICKS_PER_SEC )
 
+/**
+ * TCP maximum header length
+ *
+ */
+#define TCP_MAX_HEADER_LEN					\
+	( MAX_LL_NET_HEADER_LEN +				\
+	  sizeof ( struct tcp_header ) +			\
+	  sizeof ( struct tcp_mss_option ) +			\
+	  sizeof ( struct tcp_window_scale_padded_option ) +	\
+	  sizeof ( struct tcp_timestamp_padded_option ) )
+
 /**
  * Compare TCP sequence numbers
  *
diff --git a/roms/ipxe/src/include/ipxe/tcpip.h b/roms/ipxe/src/include/ipxe/tcpip.h
index cdf554eae63063ad0f8b0fd8b0e4..34d7f88f4d62c566bec8d6b72070 100644
--- a/roms/ipxe/src/include/ipxe/tcpip.h
+++ b/roms/ipxe/src/include/ipxe/tcpip.h
@@ -13,6 +13,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/socket.h>
 #include <ipxe/in.h>
 #include <ipxe/tables.h>
+#include <bits/tcpip.h>
 
 struct io_buffer;
 struct net_device;
@@ -121,8 +122,15 @@ extern int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip,
 		      struct sockaddr_tcpip *st_dest,
 		      struct net_device *netdev,
 		      uint16_t *trans_csum );
-extern uint16_t tcpip_continue_chksum ( uint16_t partial,
-					const void *data, size_t len );
+extern uint16_t generic_tcpip_continue_chksum ( uint16_t partial,
+						const void *data, size_t len );
 extern uint16_t tcpip_chksum ( const void *data, size_t len );
 
+/* Use generic_tcpip_continue_chksum() if no architecture-specific
+ * version is available
+ */
+#ifndef tcpip_continue_chksum
+#define tcpip_continue_chksum generic_tcpip_continue_chksum
+#endif
+
 #endif /* _IPXE_TCPIP_H */
diff --git a/roms/ipxe/src/include/ipxe/test.h b/roms/ipxe/src/include/ipxe/test.h
new file mode 100644
index 0000000000000000000000000000000000000000..8c361d284469d3d80789783a0e5042c045c5bed1
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/test.h
@@ -0,0 +1,45 @@
+#ifndef _IPXE_TEST_H
+#define _IPXE_TEST_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Self-test infrastructure
+ *
+ */
+
+#include <ipxe/tables.h>
+
+/** A self-test set */
+struct self_test {
+	/** Test set name */
+	const char *name;
+	/** Run self-tests */
+	void ( * exec ) ( void );
+	/** Number of tests run */
+	unsigned int total;
+	/** Number of test failures */
+	unsigned int failures;
+	/** Number of assertion failures */
+	unsigned int assertion_failures;
+};
+
+/** Self-test table */
+#define SELF_TESTS __table ( struct self_test, "self_tests" )
+
+/** Declare a self-test */
+#define __self_test __table_entry ( SELF_TESTS, 01 )
+
+extern void test_ok ( int success, const char *file, unsigned int line );
+
+/**
+ * Report test result
+ *
+ * @v success		Test succeeded
+ */
+#define ok( success ) do {				\
+	test_ok ( (success), __FILE__, __LINE__ );	\
+	} while ( 0 )
+
+#endif /* _IPXE_TEST_H */
diff --git a/roms/ipxe/src/include/ipxe/tftp.h b/roms/ipxe/src/include/ipxe/tftp.h
index 38be0d4da4710bc69ff1a3bf0e46..aecafa2aedd3f293a84503ed583b 100644
--- a/roms/ipxe/src/include/ipxe/tftp.h
+++ b/roms/ipxe/src/include/ipxe/tftp.h
@@ -80,6 +80,4 @@ union tftp_any {
 	struct tftp_oack	oack;
 };
 
-extern void tftp_set_request_blksize ( unsigned int blksize );
-
 #endif /* _IPXE_TFTP_H */
diff --git a/roms/ipxe/src/include/ipxe/threewire.h b/roms/ipxe/src/include/ipxe/threewire.h
index 135ef56a3b1d5d13158294ecb032..b5513ecdd384afe7a164711e394e 100644
--- a/roms/ipxe/src/include/ipxe/threewire.h
+++ b/roms/ipxe/src/include/ipxe/threewire.h
@@ -61,6 +61,19 @@ init_at93cx6 ( struct spi_device *device, unsigned int organisation ) {
 	device->nvs.write = threewire_write;
 }
 
+/**
+ * Initialise Atmel AT93C06 serial EEPROM
+ *
+ * @v device		SPI device
+ * @v organisation	Word organisation (8 or 16)
+ */
+static inline __attribute__ (( always_inline )) void
+init_at93c06 ( struct spi_device *device, unsigned int organisation ) {
+	device->nvs.size = ( 256 / organisation );
+	device->address_len = ( ( organisation == 8 ) ? 7 : 6 );
+	init_at93cx6 ( device, organisation );
+}
+
 /**
  * Initialise Atmel AT93C46 serial EEPROM
  *
diff --git a/roms/ipxe/src/include/ipxe/time.h b/roms/ipxe/src/include/ipxe/time.h
new file mode 100644
index 0000000000000000000000000000000000000000..673fe098aca09e8bdad72acc676ba308350d2562
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/time.h
@@ -0,0 +1,59 @@
+#ifndef _IPXE_TIME_H
+#define _IPXE_TIME_H
+
+/** @file
+ *
+ * Time source
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <sys/time.h>
+#include <ipxe/api.h>
+#include <config/time.h>
+
+/**
+ * Calculate static inline time API function name
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @ret _subsys_func	Subsystem API function
+ */
+#define TIME_INLINE( _subsys, _api_func ) \
+	SINGLE_API_INLINE ( TIME_PREFIX_ ## _subsys, _api_func )
+
+/**
+ * Provide a time API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ * @v _func		Implementing function
+ */
+#define PROVIDE_TIME( _subsys, _api_func, _func ) \
+	PROVIDE_SINGLE_API ( TIME_PREFIX_ ## _subsys, _api_func, _func )
+
+/**
+ * Provide a static inline time API implementation
+ *
+ * @v _prefix		Subsystem prefix
+ * @v _api_func		API function
+ */
+#define PROVIDE_TIME_INLINE( _subsys, _api_func ) \
+	PROVIDE_SINGLE_API_INLINE ( TIME_PREFIX_ ## _subsys, _api_func )
+
+/* Include all architecture-independent time API headers */
+#include <ipxe/null_time.h>
+#include <ipxe/linux/linux_time.h>
+
+/* Include all architecture-dependent time API headers */
+#include <bits/time.h>
+
+/**
+ * Get current time in seconds
+ *
+ * @ret time		Time, in seconds
+ */
+time_t time_now ( void );
+
+#endif /* _IPXE_TIME_H */
diff --git a/roms/ipxe/src/include/ipxe/tls.h b/roms/ipxe/src/include/ipxe/tls.h
index 94cd322c8b3e38c97063e51f9727..f8a754096e6860bdc2b1f2fd130c 100644
--- a/roms/ipxe/src/include/ipxe/tls.h
+++ b/roms/ipxe/src/include/ipxe/tls.h
@@ -16,7 +16,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/crypto.h>
 #include <ipxe/md5.h>
 #include <ipxe/sha1.h>
+#include <ipxe/sha256.h>
 #include <ipxe/x509.h>
+#include <ipxe/pending.h>
+#include <ipxe/iobuf.h>
 
 /** A TLS header */
 struct tls_header {
@@ -40,6 +43,9 @@ struct tls_header {
 /** TLS version 1.1 */
 #define TLS_VERSION_TLS_1_1 0x0302
 
+/** TLS version 1.2 */
+#define TLS_VERSION_TLS_1_2 0x0303
+
 /** Change cipher content type */
 #define TLS_TYPE_CHANGE_CIPHER 20
 
@@ -73,6 +79,27 @@ struct tls_header {
 #define TLS_RSA_WITH_NULL_SHA 0x0002
 #define TLS_RSA_WITH_AES_128_CBC_SHA 0x002f
 #define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035
+#define TLS_RSA_WITH_AES_128_CBC_SHA256 0x003c
+#define TLS_RSA_WITH_AES_256_CBC_SHA256 0x003d
+
+/* TLS hash algorithm identifiers */
+#define TLS_MD5_ALGORITHM 1
+#define TLS_SHA1_ALGORITHM 2
+#define TLS_SHA256_ALGORITHM 4
+
+/* TLS signature algorithm identifiers */
+#define TLS_RSA_ALGORITHM 1
+
+/* TLS server name extension */
+#define TLS_SERVER_NAME 0
+#define TLS_SERVER_NAME_HOST_NAME 0
+
+/* TLS maximum fragment length extension */
+#define TLS_MAX_FRAGMENT_LENGTH 1
+#define TLS_MAX_FRAGMENT_LENGTH_512 1
+#define TLS_MAX_FRAGMENT_LENGTH_1024 2
+#define TLS_MAX_FRAGMENT_LENGTH_2048 3
+#define TLS_MAX_FRAGMENT_LENGTH_4096 4
 
 /** TLS RX state machine state */
 enum tls_rx_state {
@@ -80,18 +107,18 @@ enum tls_rx_state {
 	TLS_RX_DATA,
 };
 
-/** TLS TX state machine state */
-enum tls_tx_state {
-	TLS_TX_NONE = 0,
-	TLS_TX_CLIENT_HELLO,
-	TLS_TX_CLIENT_KEY_EXCHANGE,
-	TLS_TX_CHANGE_CIPHER,
-	TLS_TX_FINISHED,
-	TLS_TX_DATA
+/** TLS TX pending flags */
+enum tls_tx_pending {
+	TLS_TX_CLIENT_HELLO = 0x0001,
+	TLS_TX_CERTIFICATE = 0x0002,
+	TLS_TX_CLIENT_KEY_EXCHANGE = 0x0004,
+	TLS_TX_CERTIFICATE_VERIFY = 0x0008,
+	TLS_TX_CHANGE_CIPHER = 0x0010,
+	TLS_TX_FINISHED = 0x0020,
 };
 
-/** A TLS cipher specification */
-struct tls_cipherspec {
+/** A TLS cipher suite */
+struct tls_cipher_suite {
 	/** Public-key encryption algorithm */
 	struct pubkey_algorithm *pubkey;
 	/** Bulk encryption cipher algorithm */
@@ -99,7 +126,15 @@ struct tls_cipherspec {
 	/** MAC digest algorithm */
 	struct digest_algorithm *digest;
 	/** Key length */
-	size_t key_len;
+	uint16_t key_len;
+	/** Numeric code (in network-endian order) */
+	uint16_t code;
+};
+
+/** A TLS cipher specification */
+struct tls_cipherspec {
+	/** Cipher suite */
+	struct tls_cipher_suite *suite;
 	/** Dynamically-allocated storage */
 	void *dynamic;
 	/** Public key encryption context */
@@ -112,6 +147,24 @@ struct tls_cipherspec {
 	void *mac_secret;
 };
 
+/** A TLS signature and hash algorithm identifier */
+struct tls_signature_hash_id {
+	/** Hash algorithm */
+	uint8_t hash;
+	/** Signature algorithm */
+	uint8_t signature;
+} __attribute__ (( packed ));
+
+/** A TLS signature algorithm */
+struct tls_signature_hash_algorithm {
+	/** Digest algorithm */
+	struct digest_algorithm *digest;
+	/** Public-key algorithm */
+	struct pubkey_algorithm *pubkey;
+	/** Numeric code */
+	struct tls_signature_hash_id code;
+};
+
 /** TLS pre-master secret */
 struct tls_pre_master_secret {
 	/** TLS version */
@@ -128,16 +181,42 @@ struct tls_client_random {
 	uint8_t random[28];
 } __attribute__ (( packed ));
 
+/** An MD5+SHA1 context */
+struct md5_sha1_context {
+	/** MD5 context */
+	uint8_t md5[MD5_CTX_SIZE];
+	/** SHA-1 context */
+	uint8_t sha1[SHA1_CTX_SIZE];
+} __attribute__ (( packed ));
+
+/** MD5+SHA1 context size */
+#define MD5_SHA1_CTX_SIZE sizeof ( struct md5_sha1_context )
+
+/** An MD5+SHA1 digest */
+struct md5_sha1_digest {
+	/** MD5 digest */
+	uint8_t md5[MD5_DIGEST_SIZE];
+	/** SHA-1 digest */
+	uint8_t sha1[SHA1_DIGEST_SIZE];
+} __attribute__ (( packed ));
+
+/** MD5+SHA1 digest size */
+#define MD5_SHA1_DIGEST_SIZE sizeof ( struct md5_sha1_digest )
+
 /** A TLS session */
 struct tls_session {
 	/** Reference counter */
 	struct refcnt refcnt;
 
+	/** Server name */
+	const char *name;
 	/** Plaintext stream */
 	struct interface plainstream;
 	/** Ciphertext stream */
 	struct interface cipherstream;
 
+	/** Protocol version */
+	uint16_t version;
 	/** Current TX cipher specification */
 	struct tls_cipherspec tx_cipherspec;
 	/** Next TX cipher specification */
@@ -154,18 +233,31 @@ struct tls_session {
 	uint8_t server_random[32];
 	/** Client random bytes */
 	struct tls_client_random client_random;
-	/** MD5 context for handshake verification */
-	uint8_t handshake_md5_ctx[MD5_CTX_SIZE];
-	/** SHA1 context for handshake verification */
-	uint8_t handshake_sha1_ctx[SHA1_CTX_SIZE];
+	/** MD5+SHA1 context for handshake verification */
+	uint8_t handshake_md5_sha1_ctx[MD5_SHA1_CTX_SIZE];
+	/** SHA256 context for handshake verification */
+	uint8_t handshake_sha256_ctx[SHA256_CTX_SIZE];
+	/** Digest algorithm used for handshake verification */
+	struct digest_algorithm *handshake_digest;
+	/** Digest algorithm context used for handshake verification */
+	uint8_t *handshake_ctx;
+	/** Public-key algorithm used for Certificate Verify (if sent) */
+	struct pubkey_algorithm *verify_pubkey;
 
-	/** Hack: server RSA public key */
-	struct x509_rsa_public_key rsa;
+	/** Server certificate chain */
+	struct x509_chain *chain;
+	/** Certificate validator */
+	struct interface validator;
+
+	/** Client security negotiation pending operation */
+	struct pending_operation client_negotiation;
+	/** Server security negotiation pending operation */
+	struct pending_operation server_negotiation;
 
 	/** TX sequence number */
 	uint64_t tx_seq;
-	/** TX state */
-	enum tls_tx_state tx_state;
+	/** TX pending transmissions */
+	unsigned int tx_pending;
 	/** TX process */
 	struct process process;
 
@@ -173,15 +265,36 @@ struct tls_session {
 	uint64_t rx_seq;
 	/** RX state */
 	enum tls_rx_state rx_state;
-	/** Offset within current RX state */
-	size_t rx_rcvd;
 	/** Current received record header */
 	struct tls_header rx_header;
-	/** Current received raw data buffer */
-	void *rx_data;
+	/** Current received record header (static I/O buffer) */
+	struct io_buffer rx_header_iobuf;
+	/** List of received data buffers */
+	struct list_head rx_data;
 };
 
-extern int add_tls ( struct interface *xfer,
+/** RX I/O buffer size
+ *
+ * The maximum fragment length extension is optional, and many common
+ * implementations (including OpenSSL) do not support it.  We must
+ * therefore be prepared to receive records of up to 16kB in length.
+ * The chance of an allocation of this size failing is non-negligible,
+ * so we must split received data into smaller allocations.
+ */
+#define TLS_RX_BUFSIZE 4096
+
+/** Minimum RX I/O buffer size
+ *
+ * To simplify manipulations, we ensure that no RX I/O buffer is
+ * smaller than this size.  This allows us to assume that the MAC and
+ * padding are entirely contained within the final I/O buffer.
+ */
+#define TLS_RX_MIN_BUFSIZE 512
+
+/** RX I/O buffer alignment */
+#define TLS_RX_ALIGN 16
+
+extern int add_tls ( struct interface *xfer, const char *name,
 		     struct interface **next );
 
 #endif /* _IPXE_TLS_H */
diff --git a/roms/ipxe/src/include/ipxe/uaccess.h b/roms/ipxe/src/include/ipxe/uaccess.h
index b574c318326da760e6ad1ffd64ad..95e9436759ff8d7970add4d4f6cc 100644
--- a/roms/ipxe/src/include/ipxe/uaccess.h
+++ b/roms/ipxe/src/include/ipxe/uaccess.h
@@ -82,6 +82,18 @@ trivial_userptr_add ( userptr_t userptr, off_t offset ) {
 	return ( userptr + offset );
 }
 
+/**
+ * Subtract user pointers
+ *
+ * @v userptr		User pointer
+ * @v subtrahend	User pointer to be subtracted
+ * @ret offset		Offset
+ */
+static inline __always_inline off_t
+trivial_userptr_sub ( userptr_t userptr, userptr_t subtrahend ) {
+	return ( userptr - subtrahend );
+}
+
 /**
  * Copy data between user buffers
  *
@@ -239,6 +251,15 @@ void * user_to_virt ( userptr_t userptr, off_t offset );
  */
 userptr_t userptr_add ( userptr_t userptr, off_t offset );
 
+/**
+ * Subtract user pointers
+ *
+ * @v userptr		User pointer
+ * @v subtrahend	User pointer to be subtracted
+ * @ret offset		Offset
+ */
+off_t userptr_sub ( userptr_t userptr, userptr_t subtrahend );
+
 /**
  * Convert virtual address to a physical address
  *
diff --git a/roms/ipxe/src/include/ipxe/uuid.h b/roms/ipxe/src/include/ipxe/uuid.h
index 2f3c224821e9c983885c2ee8f54e..ad515d0cb90dda52897d088af869 100644
--- a/roms/ipxe/src/include/ipxe/uuid.h
+++ b/roms/ipxe/src/include/ipxe/uuid.h
@@ -9,6 +9,7 @@
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
+#include <byteswap.h>
 
 /** A universally unique ID */
 union uuid {
@@ -28,6 +29,24 @@ union uuid {
 	uint8_t raw[16];
 };
 
-extern char * uuid_ntoa ( union uuid *uuid );
+/**
+ * Change UUID endianness
+ *
+ * @v uuid		UUID
+ *
+ * RFC4122 defines UUIDs as being encoded in network byte order, but
+ * leaves some wriggle room for "explicit application or presentation
+ * protocol specification to the contrary".  PXE, EFI and SMBIOS
+ * (versions 2.6 and above) treat the first three fields as being
+ * little-endian.
+ */
+static inline void uuid_mangle ( union uuid *uuid ) {
+
+	__bswap_32s ( &uuid->canonical.a );
+	__bswap_16s ( &uuid->canonical.b );
+	__bswap_16s ( &uuid->canonical.c );
+}
+
+extern char * uuid_ntoa ( const union uuid *uuid );
 
 #endif /* _IPXE_UUID_H */
diff --git a/roms/ipxe/src/include/ipxe/validator.h b/roms/ipxe/src/include/ipxe/validator.h
new file mode 100644
index 0000000000000000000000000000000000000000..23bdab4236437eaad7bd09b67076926cecc9dc87
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/validator.h
@@ -0,0 +1,17 @@
+#ifndef _IPXE_VALIDATOR_H
+#define _IPXE_VALIDATOR_H
+
+/** @file
+ *
+ * Certificate validator
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/interface.h>
+#include <ipxe/x509.h>
+
+extern int create_validator ( struct interface *job, struct x509_chain *chain );
+
+#endif /* _IPXE_VALIDATOR_H */
diff --git a/roms/ipxe/src/include/ipxe/version.h b/roms/ipxe/src/include/ipxe/version.h
new file mode 100644
index 0000000000000000000000000000000000000000..aa894d7e8df878ed4517374c0ceb758e2f120dbf
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/version.h
@@ -0,0 +1,16 @@
+#ifndef _IPXE_VERSION_H
+#define _IPXE_VERSION_H
+
+/** @file
+ *
+ * Version number
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+extern const int product_major_version;
+extern const int product_minor_version;
+extern const char *product_version;
+
+#endif /* _IPXE_VERSION_H */
diff --git a/roms/ipxe/src/include/ipxe/vlan.h b/roms/ipxe/src/include/ipxe/vlan.h
index d9f4484e6bc0e76731b5449912c0..083c219161fa300fc31c8088e553 100644
--- a/roms/ipxe/src/include/ipxe/vlan.h
+++ b/roms/ipxe/src/include/ipxe/vlan.h
@@ -61,6 +61,7 @@ struct vlan_header {
 
 extern struct net_device * vlan_find ( struct net_device *trunk,
 				       unsigned int tag );
+extern unsigned int vlan_tag ( struct net_device *netdev );
 extern int vlan_can_be_trunk ( struct net_device *trunk );
 extern int vlan_create ( struct net_device *trunk, unsigned int tag,
 			 unsigned int priority );
diff --git a/roms/ipxe/src/include/ipxe/wpa.h b/roms/ipxe/src/include/ipxe/wpa.h
index 293422828c4a5a0387aed5f42454..44934b3b95ab69aa6330a9cb6ce8 100644
--- a/roms/ipxe/src/include/ipxe/wpa.h
+++ b/roms/ipxe/src/include/ipxe/wpa.h
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #ifndef _IPXE_WPA_H
diff --git a/roms/ipxe/src/include/ipxe/x509.h b/roms/ipxe/src/include/ipxe/x509.h
index 37c5a4ee554104d9a0cd870687ac..a47942a75e992ad7f0b71ed5b01d 100644
--- a/roms/ipxe/src/include/ipxe/x509.h
+++ b/roms/ipxe/src/include/ipxe/x509.h
@@ -10,32 +10,372 @@
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
+#include <stddef.h>
+#include <time.h>
+#include <ipxe/asn1.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/list.h>
 
-struct asn1_cursor;
+/** An X.509 serial number */
+struct x509_serial {
+	/** Raw serial number */
+	struct asn1_cursor raw;
+};
+
+/** An X.509 issuer */
+struct x509_issuer {
+	/** Raw issuer */
+	struct asn1_cursor raw;
+};
+
+/** An X.509 time */
+struct x509_time {
+	/** Seconds since the Epoch */
+	time_t time;
+};
+
+/** An X.509 certificate validity period */
+struct x509_validity {
+	/** Not valid before */
+	struct x509_time not_before;
+	/** Not valid after */
+	struct x509_time not_after;
+};
+
+/** Margin of error allowed in X.509 response times
+ *
+ * We allow a generous margin of error: 12 hours to allow for the
+ * local time zone being non-GMT, plus 30 minutes to allow for general
+ * clock drift.
+ */
+#define X509_ERROR_MARGIN_TIME ( ( 12 * 60 + 30 ) * 60 )
+
+/** An X.509 certificate public key */
+struct x509_public_key {
+	/** Raw public key information */
+	struct asn1_cursor raw;
+	/** Public key algorithm */
+	struct asn1_algorithm *algorithm;
+	/** Raw public key bit string */
+	struct asn1_bit_string raw_bits;
+};
+
+/** An X.509 certificate subject */
+struct x509_subject {
+	/** Raw subject */
+	struct asn1_cursor raw;
+	/** Common name */
+	char *name;
+	/** Public key information */
+	struct x509_public_key public_key;
+};
+
+/** An X.509 certificate signature */
+struct x509_signature {
+	/** Signature algorithm */
+	struct asn1_algorithm *algorithm;
+	/** Signature value */
+	struct asn1_bit_string value;
+};
+
+/** An X.509 certificate basic constraints set */
+struct x509_basic_constraints {
+	/** Subject is a CA */
+	int ca;
+	/** Path length */
+	unsigned int path_len;
+};
+
+/** Unlimited path length
+ *
+ * We use -2U, since this quantity represents one *fewer* than the
+ * maximum number of remaining certificates in a chain.
+ */
+#define X509_PATH_LEN_UNLIMITED -2U
+
+/** An X.509 certificate key usage */
+struct x509_key_usage {
+	/** Key usage extension is present */
+	int present;
+	/** Usage bits */
+	unsigned int bits;
+};
 
-/** An X.509 RSA public key */
-struct x509_rsa_public_key {
-	/** Modulus */
-	uint8_t *modulus;
-	/** Modulus length */
-	size_t modulus_len;
-	/** Exponent */
-	uint8_t *exponent;
-	/** Exponent length */
-	size_t exponent_len;
+/** X.509 certificate key usage bits */
+enum x509_key_usage_bits {
+	X509_DIGITAL_SIGNATURE = 0x0080,
+	X509_NON_REPUDIATION = 0x0040,
+	X509_KEY_ENCIPHERMENT = 0x0020,
+	X509_DATA_ENCIPHERMENT = 0x0010,
+	X509_KEY_AGREEMENT = 0x0008,
+	X509_KEY_CERT_SIGN = 0x0004,
+	X509_CRL_SIGN = 0x0002,
+	X509_ENCIPHER_ONLY = 0x0001,
+	X509_DECIPHER_ONLY = 0x8000,
+};
+
+/** An X.509 certificate extended key usage */
+struct x509_extended_key_usage {
+	/** Usage bits */
+	unsigned int bits;
+};
+
+/** X.509 certificate extended key usage bits
+ *
+ * Extended key usages are identified by OID; these bits are purely an
+ * internal definition.
+ */
+enum x509_extended_key_usage_bits {
+	X509_CODE_SIGNING = 0x0001,
+	X509_OCSP_SIGNING = 0x0002,
+};
+
+/** X.509 certificate OCSP responder */
+struct x509_ocsp_responder {
+	/** URI */
+	char *uri;
+	/** OCSP status is good */
+	int good;
+};
+
+/** X.509 certificate authority information access */
+struct x509_authority_info_access {
+	/** OCSP responder */
+	struct x509_ocsp_responder ocsp;
+};
+
+/** An X.509 certificate extensions set */
+struct x509_extensions {
+	/** Basic constraints */
+	struct x509_basic_constraints basic;
+	/** Key usage */
+	struct x509_key_usage usage;
+	/** Extended key usage */
+	struct x509_extended_key_usage ext_usage;
+	/** Authority information access */
+	struct x509_authority_info_access auth_info;
+};
+
+/** An X.509 certificate */
+struct x509_certificate {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** List of certificates in cache */
+	struct list_head list;
+
+	/** Certificate has been validated */
+	int valid;
+	/** Maximum number of subsequent certificates in chain */
+	unsigned int path_remaining;
+
+	/** Raw certificate */
+	struct asn1_cursor raw;
+	/** Version */
+	unsigned int version;
+	/** Serial number */
+	struct x509_serial serial;
+	/** Raw tbsCertificate */
+	struct asn1_cursor tbs;
+	/** Signature algorithm */
+	struct asn1_algorithm *signature_algorithm;
+	/** Issuer */
+	struct x509_issuer issuer;
+	/** Validity */
+	struct x509_validity validity;
+	/** Subject */
+	struct x509_subject subject;
+	/** Signature */
+	struct x509_signature signature;
+	/** Extensions */
+	struct x509_extensions extensions;
 };
 
 /**
- * Free X.509 RSA public key
+ * Get reference to X.509 certificate
  *
- * @v rsa_pubkey	RSA public key
+ * @v cert		X.509 certificate
+ * @ret cert		X.509 certificate
  */
-static inline void
-x509_free_rsa_public_key ( struct x509_rsa_public_key *rsa_pubkey ) {
-	free ( rsa_pubkey->modulus );
+static inline __attribute__ (( always_inline )) struct x509_certificate *
+x509_get ( struct x509_certificate *cert ) {
+	ref_get ( &cert->refcnt );
+	return cert;
 }
 
-extern int x509_rsa_public_key ( const struct asn1_cursor *certificate,
-				 struct x509_rsa_public_key *rsa_pubkey );
+/**
+ * Drop reference to X.509 certificate
+ *
+ * @v cert		X.509 certificate
+ */
+static inline __attribute__ (( always_inline )) void
+x509_put ( struct x509_certificate *cert ) {
+	ref_put ( &cert->refcnt );
+}
+
+/** A link in an X.509 certificate chain */
+struct x509_link {
+	/** List of links */
+	struct list_head list;
+	/** Certificate */
+	struct x509_certificate *cert;
+};
+
+/** An X.509 certificate chain */
+struct x509_chain {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** List of links */
+	struct list_head links;
+};
+
+/**
+ * Get reference to X.509 certificate chain
+ *
+ * @v chain		X.509 certificate chain
+ * @ret chain		X.509 certificate chain
+ */
+static inline __attribute__ (( always_inline )) struct x509_chain *
+x509_chain_get ( struct x509_chain *chain ) {
+	ref_get ( &chain->refcnt );
+	return chain;
+}
+
+/**
+ * Drop reference to X.509 certificate chain
+ *
+ * @v chain		X.509 certificate chain
+ */
+static inline __attribute__ (( always_inline )) void
+x509_chain_put ( struct x509_chain *chain ) {
+	ref_put ( &chain->refcnt );
+}
+
+/**
+ * Get first certificate in X.509 certificate chain
+ *
+ * @v chain		X.509 certificate chain
+ * @ret cert		X.509 certificate, or NULL
+ */
+static inline __attribute__ (( always_inline )) struct x509_certificate *
+x509_first ( struct x509_chain *chain ) {
+	struct x509_link *link;
+
+	link = list_first_entry ( &chain->links, struct x509_link, list );
+	return ( link ? link->cert : NULL );
+}
+
+/**
+ * Get last certificate in X.509 certificate chain
+ *
+ * @v chain		X.509 certificate chain
+ * @ret cert		X.509 certificate, or NULL
+ */
+static inline __attribute__ (( always_inline )) struct x509_certificate *
+x509_last ( struct x509_chain *chain ) {
+	struct x509_link *link;
+
+	link = list_last_entry ( &chain->links, struct x509_link, list );
+	return ( link ? link->cert : NULL );
+}
+
+/** An X.509 extension */
+struct x509_extension {
+	/** Name */
+	const char *name;
+	/** Object identifier */
+	struct asn1_cursor oid;
+	/** Parse extension
+	 *
+	 * @v cert		X.509 certificate
+	 * @v raw		ASN.1 cursor
+	 * @ret rc		Return status code
+	 */
+	int ( * parse ) ( struct x509_certificate *cert,
+			  const struct asn1_cursor *raw );
+};
+
+/** An X.509 key purpose */
+struct x509_key_purpose {
+	/** Name */
+	const char *name;
+	/** Object identifier */
+	struct asn1_cursor oid;
+	/** Extended key usage bits */
+	unsigned int bits;
+};
+
+/** An X.509 access method */
+struct x509_access_method {
+	/** Name */
+	const char *name;
+	/** Object identifier */
+	struct asn1_cursor oid;
+	/** Parse access method
+	 *
+	 * @v cert		X.509 certificate
+	 * @v raw		ASN.1 cursor
+	 * @ret rc		Return status code
+	 */
+	int ( * parse ) ( struct x509_certificate *cert,
+			  const struct asn1_cursor *raw );
+};
+
+/** An X.509 root certificate store */
+struct x509_root {
+	/** Fingerprint digest algorithm */
+	struct digest_algorithm *digest;
+	/** Number of certificates */
+	unsigned int count;
+	/** Certificate fingerprints */
+	const void *fingerprints;
+};
+
+extern int x509_certificate ( const void *data, size_t len,
+			      struct x509_certificate **cert );
+extern int x509_validate ( struct x509_certificate *cert,
+			   struct x509_certificate *issuer,
+			   time_t time, struct x509_root *root );
+
+extern struct x509_chain * x509_alloc_chain ( void );
+extern int x509_append ( struct x509_chain *chain,
+			 struct x509_certificate *cert );
+extern int x509_append_raw ( struct x509_chain *chain, const void *data,
+			     size_t len );
+extern int x509_auto_append ( struct x509_chain *chain,
+			      struct x509_chain *certs );
+extern int x509_validate_chain ( struct x509_chain *chain, time_t time,
+				 struct x509_root *root );
+
+/* Functions exposed only for unit testing */
+extern int x509_check_issuer ( struct x509_certificate *cert,
+			       struct x509_certificate *issuer );
+extern void x509_fingerprint ( struct x509_certificate *cert,
+			       struct digest_algorithm *digest,
+			       void *fingerprint );
+extern int x509_check_root ( struct x509_certificate *cert,
+			     struct x509_root *root );
+extern int x509_check_time ( struct x509_certificate *cert, time_t time );
+
+/**
+ * Invalidate X.509 certificate
+ *
+ * @v cert		X.509 certificate
+ */
+static inline void x509_invalidate ( struct x509_certificate *cert ) {
+	cert->valid = 0;
+	cert->path_remaining = 0;
+}
+
+/**
+ * Invalidate X.509 certificate chain
+ *
+ * @v chain		X.509 certificate chain
+ */
+static inline void x509_invalidate_chain ( struct x509_chain *chain ) {
+	struct x509_link *link;
+
+	list_for_each_entry ( link, &chain->links, list )
+		x509_invalidate ( link->cert );
+}
 
 #endif /* _IPXE_X509_H */
diff --git a/roms/ipxe/src/include/ipxe/xferbuf.h b/roms/ipxe/src/include/ipxe/xferbuf.h
new file mode 100644
index 0000000000000000000000000000000000000000..2ca871e5950ef491a140f564596bfffc175ee9db
--- /dev/null
+++ b/roms/ipxe/src/include/ipxe/xferbuf.h
@@ -0,0 +1,31 @@
+#ifndef _IPXE_XFERBUF_H
+#define _IPXE_XFERBUF_H
+
+/** @file
+ *
+ * Data transfer buffer
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+
+/** A data transfer buffer */
+struct xfer_buffer {
+	/** Data */
+	void *data;
+	/** Size of data */
+	size_t len;
+	/** Current offset within data */
+	size_t pos;
+};
+
+extern void xferbuf_done ( struct xfer_buffer *xferbuf );
+extern int xferbuf_deliver ( struct xfer_buffer *xferbuf,
+			     struct io_buffer *iobuf,
+			     struct xfer_metadata *meta );
+
+#endif /* _IPXE_XFERBUF_H */
diff --git a/roms/ipxe/src/include/linux_api.h b/roms/ipxe/src/include/linux_api.h
index 066cdd305eeec77c2707e0df6e49..94dc991f05615bb679260fb5c8be 100644
--- a/roms/ipxe/src/include/linux_api.h
+++ b/roms/ipxe/src/include/linux_api.h
@@ -37,7 +37,6 @@ FILE_LICENCE(GPL2_OR_LATER);
 #include <linux/types.h>
 #include <linux/posix_types.h>
 typedef __kernel_pid_t pid_t;
-typedef __kernel_time_t time_t;
 typedef __kernel_suseconds_t suseconds_t;
 typedef __kernel_loff_t loff_t;
 #include <linux/time.h>
diff --git a/roms/ipxe/src/include/mii.h b/roms/ipxe/src/include/mii.h
index 2baff2f18415a2b81b8c5315d59f..e2afef854aae98e134732cf7f87e 100644
--- a/roms/ipxe/src/include/mii.h
+++ b/roms/ipxe/src/include/mii.h
@@ -1,144 +1,141 @@
-/*
- * linux/mii.h: definitions for MII-compatible transceivers
- * Originally drivers/net/sunhme.h.
+#ifndef _MII_H_
+#define _MII_H_
+
+/** @file
  *
- * Copyright (C) 1996, 1999, 2001 David S. Miller (davem@redhat.com)
+ * Media Independent Interface constants
+ *
+ * Extracted from Linux's include/linux/mii.h
  *
- * Copied Form Linux 2.4.25 an unneeded items removed by:
- * Timothy Legge (timlegge at etherboot dot org)
+ * Copyright (C) 1996, 1999, 2001 David S. Miller (davem@redhat.com)
  *
- * 03/26/2004
  */
 
 FILE_LICENCE ( GPL2_ONLY );
 
-#ifndef _MII_H_
-#define _MII_H_
-
 /* 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    */
+#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           */
+#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 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  */
 
 /* Advertisement control register. */
-#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)
+#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 )
 
 /* Link partner ability register. */
-#define LPA_SLCT                0x001f  /* Same as advertise selector  */
-#define LPA_10HALF              0x0020  /* Can do 10mbps half-duplex   */
-#define LPA_1000XFULL           0x0020  /* Can do 1000BASE-X full-duplex */
-#define LPA_10FULL              0x0040  /* Can do 10mbps full-duplex   */
-#define LPA_1000XHALF           0x0040  /* Can do 1000BASE-X half-duplex */
-#define LPA_100HALF             0x0080  /* Can do 100mbps half-duplex  */
-#define LPA_1000XPAUSE          0x0080  /* Can do 1000BASE-X pause     */
-#define LPA_100FULL             0x0100  /* Can do 100mbps full-duplex  */
-#define LPA_1000XPAUSE_ASYM     0x0100  /* Can do 1000BASE-X pause asym*/
-#define LPA_100BASE4            0x0200  /* Can do 100mbps 4k packets   */
-#define LPA_PAUSE_CAP           0x0400  /* Can pause                   */
-#define LPA_PAUSE_ASYM          0x0800  /* Can pause asymetrically     */
-#define LPA_RESV                0x1000  /* Unused...                   */
-#define LPA_RFAULT              0x2000  /* Link partner faulted        */
-#define LPA_LPACK               0x4000  /* Link partner acked us       */
-#define LPA_NPAGE               0x8000  /* Next page bit               */
-
-#define LPA_DUPLEX            (LPA_10FULL | LPA_100FULL)
-#define LPA_100                       (LPA_100FULL | LPA_100HALF | LPA_100BASE4)
+#define LPA_SLCT		0x001f	/* Same as advertise selector  */
+#define LPA_10HALF		0x0020	/* Can do 10mbps half-duplex   */
+#define LPA_1000XFULL		0x0020	/* Can do 1000BASE-X full-duplex */
+#define LPA_10FULL		0x0040	/* Can do 10mbps full-duplex   */
+#define LPA_1000XHALF		0x0040	/* Can do 1000BASE-X half-duplex */
+#define LPA_100HALF		0x0080	/* Can do 100mbps half-duplex  */
+#define LPA_1000XPAUSE		0x0080	/* Can do 1000BASE-X pause     */
+#define LPA_100FULL		0x0100	/* Can do 100mbps full-duplex  */
+#define LPA_1000XPAUSE_ASYM	0x0100	/* Can do 1000BASE-X pause asym*/
+#define LPA_100BASE4		0x0200	/* Can do 100mbps 4k packets   */
+#define LPA_PAUSE_CAP		0x0400	/* Can pause		       */
+#define LPA_PAUSE_ASYM		0x0800	/* Can pause asymetrically     */
+#define LPA_RESV		0x1000	/* Unused...		       */
+#define LPA_RFAULT		0x2000	/* Link partner faulted	       */
+#define LPA_LPACK		0x4000	/* Link partner acked us       */
+#define LPA_NPAGE		0x8000	/* Next page bit	       */
+
+#define LPA_DUPLEX		( LPA_10FULL | LPA_100FULL )
+#define LPA_100			( LPA_100FULL | LPA_100HALF | LPA_100BASE4 )
 
 /* Expansion register for auto-negotiation. */
-#define EXPANSION_NWAY          0x0001  /* Can do N-way auto-nego      */
-#define EXPANSION_LCWP          0x0002  /* Got new RX page code word   */
-#define EXPANSION_ENABLENPAGE   0x0004  /* This enables npage words    */
-#define EXPANSION_NPCAPABLE     0x0008  /* Link partner supports npage */
-#define EXPANSION_MFAULTS       0x0010  /* Multiple faults detected    */
-#define EXPANSION_RESV          0xffe0  /* Unused...                   */
+#define EXPANSION_NWAY		0x0001	/* Can do N-way auto-nego      */
+#define EXPANSION_LCWP		0x0002	/* Got new RX page code word   */
+#define EXPANSION_ENABLENPAGE	0x0004	/* This enables npage words    */
+#define EXPANSION_NPCAPABLE	0x0008	/* Link partner supports npage */
+#define EXPANSION_MFAULTS	0x0010	/* Multiple faults detected    */
+#define EXPANSION_RESV		0xffe0	/* Unused...		       */
 
-#define ESTATUS_1000_TFULL      0x2000  /* Can do 1000BT Full */
-#define ESTATUS_1000_THALF      0x1000  /* Can do 1000BT Half */
+#define ESTATUS_1000_TFULL	0x2000	/* Can do 1000BT Full */
+#define ESTATUS_1000_THALF	0x1000	/* Can do 1000BT Half */
 
 /* N-way test register. */
-#define NWAYTEST_RESV1          0x00ff  /* Unused...                   */
-#define NWAYTEST_LOOPBACK       0x0100  /* Enable loopback for N-way   */
-#define NWAYTEST_RESV2          0xfe00  /* Unused...                   */
+#define NWAYTEST_RESV1		0x00ff	/* Unused...		       */
+#define NWAYTEST_LOOPBACK	0x0100	/* Enable loopback for N-way   */
+#define NWAYTEST_RESV2		0xfe00	/* Unused...		       */
 
 /* 1000BASE-T Control register */
-#define ADVERTISE_1000FULL      0x0200  /* Advertise 1000BASE-T full duplex */
-#define ADVERTISE_1000HALF      0x0100  /* Advertise 1000BASE-T half duplex */
+#define ADVERTISE_1000FULL	0x0200	/* Advertise 1000BASE-T full duplex */
+#define ADVERTISE_1000HALF	0x0100	/* Advertise 1000BASE-T half duplex */
 
 /* 1000BASE-T Status register */
-#define LPA_1000LOCALRXOK       0x2000  /* Link partner local receiver status */
-#define LPA_1000REMRXOK         0x1000  /* Link partner remote receiver status */
-#define LPA_1000FULL            0x0800  /* Link partner 1000BASE-T full duplex */
-#define LPA_1000HALF            0x0400  /* Link partner 1000BASE-T half duplex */
+#define LPA_1000LOCALRXOK	0x2000	/* Partner local receiver status */
+#define LPA_1000REMRXOK		0x1000	/* Partner remote receiver status */
+#define LPA_1000FULL		0x0800	/* Partner 1000BASE-T full duplex */
+#define LPA_1000HALF		0x0400	/* Partner 1000BASE-T half duplex */
 
 #include <ipxe/netdevice.h>
 
@@ -157,63 +154,4 @@ struct mii_if_info {
         void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val);
 };
 
-
-extern int mii_link_ok (struct mii_if_info *mii);
-extern void mii_check_link (struct mii_if_info *mii);
-extern unsigned int mii_check_media (struct mii_if_info *mii,
-                                       unsigned int ok_to_print,
-                                       unsigned int init_media);
-
-
-/**
- * mii_nway_result
- * @negotiated: value of MII ANAR and'd with ANLPAR
- *
- * Given a set of MII abilities, check each bit and returns the
- * currently supported media, in the priority order defined by
- * IEEE 802.3u.  We use LPA_xxx constants but note this is not the
- * value of LPA solely, as described above.
- *
- * The one exception to IEEE 802.3u is that 100baseT4 is placed
- * between 100T-full and 100T-half.  If your phy does not support
- * 100T4 this is fine.  If your phy places 100T4 elsewhere in the
- * priority order, you will need to roll your own function.
- */
-static inline unsigned int mii_nway_result (unsigned int negotiated)
-{
-        unsigned int ret;
-
-        if (negotiated & LPA_100FULL)
-                ret = LPA_100FULL;
-        else if (negotiated & LPA_100BASE4)
-                ret = LPA_100BASE4;
-        else if (negotiated & LPA_100HALF)
-                ret = LPA_100HALF;
-        else if (negotiated & LPA_10FULL)
-                ret = LPA_10FULL;
-        else
-                ret = LPA_10HALF;
-
-        return ret;
-}
-
-/**
- * mii_duplex
- * @duplex_lock: Non-zero if duplex is locked at full
- * @negotiated: value of MII ANAR and'd with ANLPAR
- *
- * A small helper function for a common case.  Returns one
- * if the media is operating or locked at full duplex, and
- * returns zero otherwise.
- */
-static inline unsigned int mii_duplex (unsigned int duplex_lock,
-                                       unsigned int negotiated)
-{
-        if (duplex_lock)
-                return 1;
-        if (mii_nway_result(negotiated) & LPA_DUPLEX)
-                return 1;
-        return 0;
-}
-
 #endif
diff --git a/roms/ipxe/src/include/readline/readline.h b/roms/ipxe/src/include/readline/readline.h
index 42dfd8c4cf6daf3e35ad477d7482..0449a3f98307e9824d0863ad1ab7 100644
--- a/roms/ipxe/src/include/readline/readline.h
+++ b/roms/ipxe/src/include/readline/readline.h
@@ -50,8 +50,8 @@ struct readline_history {
 };
 
 extern void history_free ( struct readline_history *history );
-extern char * __malloc readline_history ( const char *prompt,
-					  struct readline_history *history );
+extern int readline_history ( const char *prompt, const char *prefill,
+			      struct readline_history *history, char **line );
 extern char * __malloc readline ( const char *prompt );
 
 #endif /* _READLINE_H */
diff --git a/roms/ipxe/src/include/stdarg.h b/roms/ipxe/src/include/stdarg.h
index 78b261ae3f98550fdd767df7c1b6..f317238a9caacd7330988d357465 100644
--- a/roms/ipxe/src/include/stdarg.h
+++ b/roms/ipxe/src/include/stdarg.h
@@ -9,4 +9,30 @@ typedef __builtin_va_list va_list;
 #define va_end( ap ) __builtin_va_end ( ap )
 #define va_copy( dest, src ) __builtin_va_copy ( dest, src )
 
+/**
+ * Count number of arguments to a variadic macro
+ *
+ * This rather neat, non-iterative solution is courtesy of Laurent
+ * Deniau.
+ *
+ */
+#define _VA_ARG_COUNT(  _1,  _2,  _3,  _4,  _5,  _6,  _7,  _8,		\
+		        _9, _10, _11, _12, _13, _14, _15, _16,		\
+		       _17, _18, _19, _20, _21, _22, _23, _24,		\
+		       _25, _26, _27, _28, _29, _30, _31, _32,		\
+		       _33, _34, _35, _36, _37, _38, _39, _40,		\
+		       _41, _42, _43, _44, _45, _46, _47, _48,		\
+		       _49, _50, _51, _52, _53, _54, _55, _56,		\
+		       _57, _58, _59, _60, _61, _62, _63,   N, ... ) N
+#define VA_ARG_COUNT( ... )						\
+	_VA_ARG_COUNT ( __VA_ARGS__, 					\
+			63, 62, 61, 60, 59, 58, 57, 56,			\
+			55, 54, 53, 52, 51, 50, 49, 48,			\
+			47, 46, 45, 44, 43, 42, 41, 40,			\
+			39, 38, 37, 36, 35, 34, 33, 32,			\
+			31, 30, 29, 28, 27, 26, 25, 24,			\
+			23, 22, 21, 20, 19, 18, 17, 16,			\
+			15, 14, 13, 12, 11, 10,  9,  8,			\
+			 7,  6,  5,  4,  3,  2,  1,  0 )
+
 #endif /* _STDARG_H */
diff --git a/roms/ipxe/src/include/stddef.h b/roms/ipxe/src/include/stddef.h
index c91a103f836f2aa85110a04f6534..83a0f0ed661ce5d04083c4b4a0fe 100644
--- a/roms/ipxe/src/include/stddef.h
+++ b/roms/ipxe/src/include/stddef.h
@@ -26,5 +26,6 @@ FILE_LICENCE ( GPL2_ONLY );
 #define __WCHAR_TYPE__ long int
 #endif
 typedef __WCHAR_TYPE__ wchar_t;
+typedef __WINT_TYPE__ wint_t;
 
 #endif /* STDDEF_H */
diff --git a/roms/ipxe/src/include/stdio.h b/roms/ipxe/src/include/stdio.h
index 84181f0a1820ba7df445f816b5c2..91840af5b8f2557c33aa701e9018 100644
--- a/roms/ipxe/src/include/stdio.h
+++ b/roms/ipxe/src/include/stdio.h
@@ -6,6 +6,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <stdint.h>
 #include <stdarg.h>
 
+extern void putchar ( int character );
+
+extern int getchar ( void );
+
 extern int __attribute__ (( format ( printf, 1, 2 ) ))
 printf ( const char *fmt, ... );
 
diff --git a/roms/ipxe/src/include/stdlib.h b/roms/ipxe/src/include/stdlib.h
index 19a7c8e09afb8e592ca6c67f074e..3d30858ffcd25e12b3b37da2b362 100644
--- a/roms/ipxe/src/include/stdlib.h
+++ b/roms/ipxe/src/include/stdlib.h
@@ -5,7 +5,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
 #include <assert.h>
-#include <ctype.h>
 
 /*****************************************************************************
  *
@@ -18,9 +17,6 @@ static inline int strtoul_base ( const char **pp, int base )
 {
 	const char *p = *pp;
 
-	while ( isspace ( *p ) )
-		p++;
-
 	if ( base == 0 ) {
 		base = 10;
 		if ( *p == '0' ) {
diff --git a/roms/ipxe/src/include/string.h b/roms/ipxe/src/include/string.h
index 2fd6acf1636e58f3bf54a70857e5..3482e1b2248c97fbcabe5431edeb 100644
--- a/roms/ipxe/src/include/string.h
+++ b/roms/ipxe/src/include/string.h
@@ -37,6 +37,7 @@ char * __pure strpbrk(const char * cs,const char * ct) __nonnull;
 char * strtok(char * s,const char * ct) __nonnull;
 char * strsep(char **s, const char *ct) __nonnull;
 void * memset(void * s,int c,size_t count) __nonnull;
+void * memcpy ( void *dest, const void *src, size_t len ) __nonnull;
 void * memmove(void * dest,const void *src,size_t count) __nonnull;
 int __pure memcmp(const void * cs,const void * ct,
 				    size_t count) __nonnull;
diff --git a/roms/ipxe/src/include/sys/time.h b/roms/ipxe/src/include/sys/time.h
index 21fb7e99d2d015b9ce82acf5b7f8..6c9b7421bbbd4d59fabcf8032d69 100644
--- a/roms/ipxe/src/include/sys/time.h
+++ b/roms/ipxe/src/include/sys/time.h
@@ -1,20 +1,18 @@
 #ifndef _SYS_TIME_H
 #define _SYS_TIME_H
 
-#include <time.h>
+/** @file
+ *
+ * Date and time
+ */
 
-typedef unsigned long suseconds_t;
+#include <stdint.h>
 
-struct timeval {
-	time_t tv_sec;		/* seconds */
-	suseconds_t tv_usec;	/* microseconds */
-};
-
-struct timezone {
-	int tz_minuteswest;	/* minutes W of Greenwich */
-	int tz_dsttime;		/* type of dst correction */
-};
-
-extern int gettimeofday ( struct timeval *tv, struct timezone *tz );
+/** Seconds since the Epoch
+ *
+ * We use a 64-bit type to avoid Y2K38 issues, since we may have to
+ * handle distant future dates (e.g. X.509 certificate expiry dates).
+ */
+typedef int64_t time_t;
 
 #endif /* _SYS_TIME_H */
diff --git a/roms/ipxe/src/include/syslog.h b/roms/ipxe/src/include/syslog.h
new file mode 100644
index 0000000000000000000000000000000000000000..93f32f8676d260f19d6878a73cd291ac69a440c3
--- /dev/null
+++ b/roms/ipxe/src/include/syslog.h
@@ -0,0 +1,100 @@
+#ifndef _SYSLOG_H
+#define _SYSLOG_H
+
+/** @file
+ *
+ * System logger
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdarg.h>
+#include <ipxe/ansiesc.h>
+#include <config/console.h>
+
+/**
+ * @defgroup syslogpri Syslog priorities
+ *
+ * These values are chosen to match those used in the syslog network
+ * protocol (RFC 5424).
+ *
+ * @{
+ */
+
+/** Emergency: system is unusable */
+#define LOG_EMERG 0
+
+/** Alert: action must be taken immediately */
+#define LOG_ALERT 1
+
+/** Critical: critical conditions */
+#define LOG_CRIT 2
+
+/** Error: error conditions */
+#define LOG_ERR 3
+
+/** Warning: warning conditions */
+#define LOG_WARNING 4
+
+/** Notice: normal but significant conditions */
+#define LOG_NOTICE 5
+
+/** Informational: informational messages */
+#define LOG_INFO 6
+
+/** Debug: debug-level messages */
+#define LOG_DEBUG 7
+
+/** @} */
+
+/** Do not log any messages */
+#define LOG_NONE -1
+
+/** Log all messages */
+#define LOG_ALL LOG_DEBUG
+
+extern void log_vprintf ( const char *fmt, va_list args );
+
+extern void __attribute__ (( format ( printf, 1, 2 ) ))
+log_printf ( const char *fmt, ... );
+
+/** ANSI private escape sequence to set syslog priority
+ *
+ * @v priority		Priority
+ */
+#define SYSLOG_SET_PRIORITY( priority ) \
+	"\033[" #priority "p"
+
+/** ANSI private escape sequence to clear syslog priority */
+#define SYSLOG_CLEAR_PRIORITY "\033[p"
+
+/**
+ * Write message to system log
+ *
+ * @v priority		Message priority
+ * @v fmt		Format string
+ * @v ...		Arguments
+ */
+#define vsyslog( priority, fmt, args ) do {				\
+	if ( (priority) <= LOG_LEVEL ) {				\
+		log_vprintf ( SYSLOG_SET_PRIORITY ( priority ) fmt	\
+			      SYSLOG_CLEAR_PRIORITY, (args) );		\
+	}								\
+	} while ( 0 )
+
+/**
+ * Write message to system log
+ *
+ * @v priority		Message priority
+ * @v fmt		Format string
+ * @v ...		Arguments
+ */
+#define syslog( priority, fmt, ... ) do {				\
+	if ( (priority) <= LOG_LEVEL ) {				\
+		log_printf ( SYSLOG_SET_PRIORITY ( priority ) fmt	\
+			     SYSLOG_CLEAR_PRIORITY, ##__VA_ARGS__ );	\
+	}								\
+	} while ( 0 )
+
+#endif /* _SYSLOG_H */
diff --git a/roms/ipxe/src/include/time.h b/roms/ipxe/src/include/time.h
index 6ea927c3250650560cdec4ae59b0..bc73af4cd25720742171a3cbe945 100644
--- a/roms/ipxe/src/include/time.h
+++ b/roms/ipxe/src/include/time.h
@@ -1,21 +1,50 @@
 #ifndef _TIME_H
 #define _TIME_H
 
-typedef unsigned long time_t;
+/** @file
+ *
+ * Date and time
+ */
 
+#include <sys/time.h>
+#include <ipxe/time.h>
+
+/** Broken-down time */
 struct tm {
-	int tm_sec;	/* seconds */
-	int tm_min;	/* minutes */
-	int tm_hour;	/* hours */
-	int tm_mday;	/* day of the month */
-	int tm_mon;	/* month */
-	int tm_year;	/* year */
-	int tm_wday;	/* day of the week */
-	int tm_yday;	/* day in the year */
-	int tm_isdst;	/* daylight saving time */
+	/** Seconds [0,60] */
+	int tm_sec;
+	/** Minutes [0,59] */
+	int tm_min;
+	/** Hour [0,23] */
+	int tm_hour;
+	/** Day of month [1,31] */
+	int tm_mday;
+	/** Month of year [0,11] */
+	int tm_mon;
+	/** Years since 1900 */
+	int tm_year;
+	/** Day of week [0,6] (Sunday=0) */
+	int tm_wday;
+	/** Day of year [0,365] */
+	int tm_yday;
+	/** Daylight savings flag */
+	int tm_isdst;
 };
 
-extern time_t time ( time_t *t );
+/**
+ * Get current time in seconds since the Epoch
+ *
+ * @v t			Time to fill in, or NULL
+ * @ret time		Current time
+ */
+static inline time_t time ( time_t *t ) {
+	time_t now;
+
+	now = time_now();
+	if ( t )
+		*t = now;
+	return now;
+}
 
 extern time_t mktime ( struct tm *tm );
 
diff --git a/roms/ipxe/src/include/usr/autoboot.h b/roms/ipxe/src/include/usr/autoboot.h
index a608b3dce7a850541f25317c69ba..cfa4c41eb290cba36486f9505216 100644
--- a/roms/ipxe/src/include/usr/autoboot.h
+++ b/roms/ipxe/src/include/usr/autoboot.h
@@ -14,11 +14,24 @@ struct net_device;
 struct uri;
 struct settings;
 
-extern int uriboot ( struct uri *filename, struct uri *root_path );
+/** uriboot() flags */
+enum uriboot_flags {
+	URIBOOT_NO_SAN_DESCRIBE = 0x0001,
+	URIBOOT_NO_SAN_BOOT = 0x0002,
+	URIBOOT_NO_SAN_UNHOOK = 0x0004,
+};
+
+#define URIBOOT_NO_SAN ( URIBOOT_NO_SAN_DESCRIBE | \
+			 URIBOOT_NO_SAN_BOOT |	   \
+			 URIBOOT_NO_SAN_UNHOOK )
+
+extern int uriboot ( struct uri *filename, struct uri *root_path, int drive,
+		     unsigned int flags );
 extern struct uri *
 fetch_next_server_and_filename ( struct settings *settings );
 extern int netboot ( struct net_device *netdev );
 extern int autoboot ( void );
+extern void ipxe ( struct net_device *netdev );
 
 extern int pxe_menu_boot ( struct net_device *netdev );
 
diff --git a/roms/ipxe/src/include/usr/imgmgmt.h b/roms/ipxe/src/include/usr/imgmgmt.h
index 1c0a212e3d030275c51e4b3ea7b2..8db5c9780f59c1ab6db569c8eb0d 100644
--- a/roms/ipxe/src/include/usr/imgmgmt.h
+++ b/roms/ipxe/src/include/usr/imgmgmt.h
@@ -11,46 +11,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <ipxe/image.h>
 
-extern int register_and_put_image ( struct image *image );
-extern int register_and_probe_image ( struct image *image );
-extern int register_and_select_image ( struct image *image );
-extern int register_and_boot_image ( struct image *image );
-extern int register_and_replace_image ( struct image *image );
-extern int imgdownload ( struct uri *uri, const char *name, const char *cmdline,
-			 int ( * action ) ( struct image *image ) );
-extern int imgdownload_string ( const char *uri_string, const char *name,
-				const char *cmdline,
-				int ( * action ) ( struct image *image ) );
+extern int imgdownload ( struct uri *uri, struct image **image );
+extern int imgdownload_string ( const char *uri_string, struct image **image );
+extern int imgacquire ( const char *name, struct image **image );
 extern void imgstat ( struct image *image );
-extern void imgfree ( struct image *image );
-
-/**
- * Select an image for execution
- *
- * @v image		Image
- * @ret rc		Return status code
- */
-static inline int imgselect ( struct image *image ) {
-	return image_select ( image );
-}
-
-/**
- * Find the previously-selected image
- *
- * @ret image		Image, or NULL
- */
-static inline struct image * imgautoselect ( void ) {
-	return image_find_selected();
-}
-
-/**
- * Execute an image
- *
- * @v image		Image
- * @ret rc		Return status code
- */
-static inline int imgexec ( struct image *image ) {
-	return image_exec ( image );
-}
 
 #endif /* _USR_IMGMGMT_H */
diff --git a/roms/ipxe/src/include/usr/imgtrust.h b/roms/ipxe/src/include/usr/imgtrust.h
new file mode 100644
index 0000000000000000000000000000000000000000..f47105af0a5733af84c9adf45485bcd75033bd9b
--- /dev/null
+++ b/roms/ipxe/src/include/usr/imgtrust.h
@@ -0,0 +1,17 @@
+#ifndef _USR_IMGTRUST_H
+#define _USR_IMGTRUST_H
+
+/** @file
+ *
+ * Image trust management
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/image.h>
+
+extern int imgverify ( struct image *image, struct image *signature,
+		       const char *name );
+
+#endif /* _USR_IMGTRUST_H */
diff --git a/roms/ipxe/src/include/usr/nslookup.h b/roms/ipxe/src/include/usr/nslookup.h
new file mode 100644
index 0000000000000000000000000000000000000000..d34649e9facffae0e3ca65903926c44380e5101d
--- /dev/null
+++ b/roms/ipxe/src/include/usr/nslookup.h
@@ -0,0 +1,14 @@
+#ifndef _USR_NSLOOKUP_H
+#define _USR_NSLOOKUP_H
+
+/** @file
+ *
+ * Standalone name resolution
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+extern int nslookup ( const char *name, const char *setting_name );
+
+#endif /* _USR_NSLOOKUP_H */
diff --git a/roms/ipxe/src/include/wchar.h b/roms/ipxe/src/include/wchar.h
new file mode 100644
index 0000000000000000000000000000000000000000..ba349aae8370b01fd634d8cf7e9c629888b9fac1
--- /dev/null
+++ b/roms/ipxe/src/include/wchar.h
@@ -0,0 +1,29 @@
+#ifndef WCHAR_H
+#define WCHAR_H
+
+FILE_LICENCE ( GPL2_ONLY );
+
+#include <stddef.h>
+
+typedef void mbstate_t;
+
+/**
+ * Convert wide character to multibyte sequence
+ *
+ * @v buf		Buffer
+ * @v wc		Wide character
+ * @v ps		Shift state
+ * @ret len		Number of characters written
+ *
+ * This is a stub implementation, sufficient to handle basic ASCII
+ * characters.
+ */
+static inline __attribute__ (( always_inline ))
+size_t wcrtomb ( char *buf, wchar_t wc, mbstate_t *ps __unused ) {
+	*buf = wc;
+	return 1;
+}
+
+extern size_t wcslen ( const wchar_t *string );
+
+#endif /* WCHAR_H */
diff --git a/roms/ipxe/src/interface/bofm/bofm.c b/roms/ipxe/src/interface/bofm/bofm.c
index dfa76d3252cd7bf656d078e33c0e..b0e92b27cec09d2653a9afc6b5bd 100644
--- a/roms/ipxe/src/interface/bofm/bofm.c
+++ b/roms/ipxe/src/interface/bofm/bofm.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -181,14 +182,14 @@ static int bofm_en ( struct bofm_device *bofm, struct bofm_en *en ) {
 
 	/* Retrieve current MAC address */
 	if ( ( rc = bofm->op->harvest ( bofm, en->mport, mac ) ) != 0 ) {
-		DBG ( "BOFM: " PCI_FMT " port %d could not harvest: %s\n",
+		DBG ( "BOFM: " PCI_FMT " mport %d could not harvest: %s\n",
 		      PCI_ARGS ( bofm->pci ), en->mport, strerror ( rc ) );
 		return rc;
 	}
 
 	/* Harvest MAC address if necessary */
 	if ( en->options & BOFM_EN_RQ_HVST_MASK ) {
-		DBG ( "BOFM: " PCI_FMT " port %d harvested MAC %s\n",
+		DBG ( "BOFM: " PCI_FMT " mport %d harvested MAC %s\n",
 		      PCI_ARGS ( bofm->pci ), en->mport, eth_ntoa ( mac ) );
 		memcpy ( en->mac_a, mac, sizeof ( en->mac_a ) );
 		en->options |= ( BOFM_EN_EN_A | BOFM_EN_HVST );
@@ -197,7 +198,7 @@ static int bofm_en ( struct bofm_device *bofm, struct bofm_en *en ) {
 	/* Mark as changed if necessary */
 	if ( ( en->options & BOFM_EN_EN_A ) &&
 	     ( memcmp ( en->mac_a, mac, sizeof ( en->mac_a ) ) != 0 ) ) {
-		DBG ( "BOFM: " PCI_FMT " port %d MAC %s",
+		DBG ( "BOFM: " PCI_FMT " mport %d MAC %s",
 		      PCI_ARGS ( bofm->pci ), en->mport, eth_ntoa ( mac ) );
 		DBG ( " changed to %s\n", eth_ntoa ( en->mac_a ) );
 		en->options |= BOFM_EN_CHG_CHANGED;
@@ -207,7 +208,7 @@ static int bofm_en ( struct bofm_device *bofm, struct bofm_en *en ) {
 	if ( ( en->options & BOFM_EN_EN_A ) &&
 	     ( en->options & BOFM_EN_USAGE_ENTRY ) &&
 	     ( ! ( en->options & BOFM_EN_USAGE_HARVEST ) ) ) {
-		DBG ( "BOFM: " PCI_FMT " port %d applied MAC %s\n",
+		DBG ( "BOFM: " PCI_FMT " mport %d applied MAC %s\n",
 		      PCI_ARGS ( bofm->pci ), en->mport,
 		      eth_ntoa ( en->mac_a ) );
 		memcpy ( mac, en->mac_a, sizeof ( mac ) );
@@ -215,7 +216,7 @@ static int bofm_en ( struct bofm_device *bofm, struct bofm_en *en ) {
 
 	/* Store MAC address */
 	if ( ( rc = bofm->op->update ( bofm, en->mport, mac ) ) != 0 ) {
-		DBG ( "BOFM: " PCI_FMT " port %d could not update: %s\n",
+		DBG ( "BOFM: " PCI_FMT " mport %d could not update: %s\n",
 		      PCI_ARGS ( bofm->pci ), en->mport, strerror ( rc ) );
 		return rc;
 	}
@@ -303,14 +304,19 @@ int bofm ( userptr_t bofmtab, struct pci_device *pci ) {
 		DBG2_HDA ( en_offset, &en, sizeof ( en ) );
 		if ( ( en.options & BOFM_EN_MAP_MASK ) != BOFM_EN_MAP_PFA ) {
 			DBG ( "BOFM: slot %d port %d has no PCI mapping\n",
-			      en.slot, en.port );
+			      en.slot, ( en.port + 1 ) );
 			continue;
 		}
+		DBG ( "BOFM: slot %d port %d%s is " PCI_FMT " mport %d\n",
+		      en.slot, ( en.port + 1 ),
+		      ( ( en.slot || en.port ) ? "" : "(?)" ),
+		      PCI_BUS ( en.busdevfn ), PCI_SLOT ( en.busdevfn ),
+		      PCI_FUNC ( en.busdevfn ), en.mport );
 		bofm = bofm_find_busdevfn ( en.busdevfn );
 		if ( ! bofm ) {
-			DBG ( "BOFM: " PCI_FMT " ignored\n",
+			DBG ( "BOFM: " PCI_FMT " mport %d ignored\n",
 			      PCI_BUS ( en.busdevfn ), PCI_SLOT ( en.busdevfn ),
-			      PCI_FUNC ( en.busdevfn ) );
+			      PCI_FUNC ( en.busdevfn ), en.mport );
 			continue;
 		}
 		if ( ( rc = bofm_en ( bofm, &en ) ) == 0 ) {
diff --git a/roms/ipxe/src/interface/efi/efi_bofm.c b/roms/ipxe/src/interface/efi/efi_bofm.c
index 1d647db4378afb27a543a8c65ea0..c313d2e97ab439313fb5fbed93c2 100644
--- a/roms/ipxe/src/interface/efi/efi_bofm.c
+++ b/roms/ipxe/src/interface/efi/efi_bofm.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -97,6 +98,9 @@ typedef struct {
 typedef struct _IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL
 	IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL;
 
+typedef struct _IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL2
+	IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL2;
+
 typedef EFI_STATUS ( EFIAPI *IBM_BOFM_DRIVER_CONFIGURATION_SUPPORT ) (
 	IN IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL *This,
 	EFI_HANDLE ControllerHandle,
@@ -112,20 +116,27 @@ typedef EFI_STATUS ( EFIAPI *IBM_BOFM_DRIVER_CONFIGURATION_STATUS ) (
 	UINT8 BOFMReturnCode
 );
 
+typedef EFI_STATUS ( EFIAPI *IBM_BOFM_DRIVER_CONFIGURATION_STATUS2 ) (
+	IN IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL2 *This,
+	EFI_HANDLE ControllerHandle,
+	BOOLEAN ResetRequired,
+	UINT8 BOFMReturnCode
+);
+
 struct _IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL {
 	IBM_BOFM_TABLE BofmTable;
 	IBM_BOFM_DRIVER_CONFIGURATION_STATUS SetStatus;
 	IBM_BOFM_DRIVER_CONFIGURATION_SUPPORT RegisterSupport;
 };
 
-typedef struct _IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL2 {
+struct _IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL2 {
 	UINT32 Signature;
 	UINT32 Reserved1;
 	UINT64 Reserved2;
-	IBM_BOFM_DRIVER_CONFIGURATION_STATUS SetStatus;
+	IBM_BOFM_DRIVER_CONFIGURATION_STATUS2 SetStatus;
 	IBM_BOFM_DRIVER_CONFIGURATION_SUPPORT RegisterSupport;
 	IBM_BOFM_TABLE BofmTable;
-} IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL2;
+};
 
 /***************************************************************************
  *
@@ -165,7 +176,7 @@ efi_bofm_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver,
 	EFI_STATUS efirc;
 	int rc;
 
-	DBGCP ( efidrv, "BOFM DRIVER_SUPPORTED %p (%p)\n", device, child );
+	DBGCP ( efidrv, "EFIBOFM DRIVER_SUPPORTED %p (%p)\n", device, child );
 
 	/* Create corresponding PCI device, if any */
 	efipci = efipci_create ( efidrv, device );
@@ -176,7 +187,7 @@ efi_bofm_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver,
 
 	/* Look for a BOFM driver */
 	if ( ( rc = bofm_find_driver ( &efipci->pci ) ) != 0 ) {
-		DBGC2 ( efidrv, "BOFM " PCI_FMT " has no driver\n",
+		DBGCP ( efidrv, "EFIBOFM " PCI_FMT " has no driver\n",
 			PCI_ARGS ( &efipci->pci ) );
 		efirc = EFI_UNSUPPORTED;
 		goto err_no_driver;
@@ -185,8 +196,8 @@ efi_bofm_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver,
 	/* Locate BOFM protocol */
 	if ( ( efirc = bs->LocateProtocol ( &bofm1_protocol_guid, NULL,
 					    &bofm1.interface ) ) != 0 ) {
-		DBGC ( efidrv, "BOFM " PCI_FMT " cannot find BOFM protocol\n",
-		       PCI_ARGS ( &efipci->pci ) );
+		DBGC ( efidrv, "EFIBOFM " PCI_FMT " cannot find BOFM "
+		       "protocol\n", PCI_ARGS ( &efipci->pci ) );
 		efirc = EFI_UNSUPPORTED;
 		goto err_not_bofm;
 	}
@@ -196,13 +207,13 @@ efi_bofm_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver,
 						      0x04 /* Can change MAC */,
 						      0x00 /* No iSCSI */,
 						      0x02 /* Version */ ))!=0){
-		DBGC ( efidrv, "BOFM " PCI_FMT " could not register support: "
-		       "%s\n", PCI_ARGS ( &efipci->pci ),
+		DBGC ( efidrv, "EFIBOFM " PCI_FMT " could not register "
+		       "support: %s\n", PCI_ARGS ( &efipci->pci ),
 		       efi_strerror ( efirc ) );
 		goto err_cannot_register;
 	}
 
-	DBGC ( efidrv, "BOFM " PCI_FMT " is supported by driver \"%s\"\n",
+	DBGC ( efidrv, "EFIBOFM " PCI_FMT " is supported by driver \"%s\"\n",
 	       PCI_ARGS ( &efipci->pci ), efipci->pci.id->name );
 
 	/* Destroy temporary PCI device */
@@ -241,11 +252,12 @@ static EFI_STATUS EFIAPI efi_bofm_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
 		void *interface;
 	} bofm2;
 	struct efi_pci_device *efipci;
-	userptr_t bofmtab;
+	IBM_BOFM_TABLE *bofmtab;
+	IBM_BOFM_TABLE *bofmtab2;
 	EFI_STATUS efirc;
 	int bofmrc;
 
-	DBGCP ( efidrv, "BOFM DRIVER_START %p (%p)\n", device, child );
+	DBGCP ( efidrv, "EFIBOFM DRIVER_START %p (%p)\n", device, child );
 
 	/* Create corresponding PCI device */
 	efipci = efipci_create ( efidrv, device );
@@ -261,46 +273,70 @@ static EFI_STATUS EFIAPI efi_bofm_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
 	/* Locate BOFM protocol */
 	if ( ( efirc = bs->LocateProtocol ( &bofm1_protocol_guid, NULL,
 					    &bofm1.interface ) ) != 0 ) {
-		DBGC ( efidrv, "BOFM " PCI_FMT " cannot find BOFM protocol\n",
-		       PCI_ARGS ( &efipci->pci ) );
+		DBGC ( efidrv, "EFIBOFM " PCI_FMT " cannot find BOFM "
+		       "protocol\n", PCI_ARGS ( &efipci->pci ) );
 		goto err_locate_bofm;
 	}
+	bofmtab = &bofm1.bofm1->BofmTable;
+	DBGC ( efidrv, "EFIBOFM " PCI_FMT " found version 1 BOFM table at "
+	       "%p+%04x\n", PCI_ARGS ( &efipci->pci ), bofmtab,
+	       bofmtab->Parameters.Length );
 
 	/* Locate BOFM2 protocol, if available */
 	if ( ( efirc = bs->LocateProtocol ( &bofm2_protocol_guid, NULL,
-					    &bofm2.interface ) ) != 0 ) {
-		DBGC ( efidrv, "BOFM " PCI_FMT " cannot find BOFM2 protocol\n",
-		       PCI_ARGS ( &efipci->pci ) );
-		/* Not a fatal error; may be a BOFM1-only system */
-		bofm2.bofm2 = NULL;
-	}
-
-	/* Select appropriate BOFM table (v1 or v2) to use */
-	if ( bofm2.bofm2 ) {
-		DBGC ( efidrv, "BOFM " PCI_FMT " using version 2 BOFM table\n",
-		       PCI_ARGS ( &efipci->pci ) );
+					    &bofm2.interface ) ) == 0 ) {
+		bofmtab2 = &bofm2.bofm2->BofmTable;
+		DBGC ( efidrv, "EFIBOFM " PCI_FMT " found version 2 BOFM table "
+		       "at %p+%04x\n", PCI_ARGS ( &efipci->pci ), bofmtab2,
+		       bofmtab2->Parameters.Length );
 		assert ( bofm2.bofm2->RegisterSupport ==
 			 bofm1.bofm1->RegisterSupport );
-		assert ( bofm2.bofm2->SetStatus == bofm1.bofm1->SetStatus );
-		bofmtab = virt_to_user ( &bofm2.bofm2->BofmTable );
 	} else {
-		DBGC ( efidrv, "BOFM " PCI_FMT " using version 1 BOFM table\n",
-		       PCI_ARGS ( &efipci->pci ) );
-		bofmtab = virt_to_user ( &bofm1.bofm1->BofmTable );
+		DBGC ( efidrv, "EFIBOFM " PCI_FMT " cannot find BOFM2 "
+		       "protocol\n", PCI_ARGS ( &efipci->pci ) );
+		/* Not a fatal error; may be a BOFM1-only system */
+		bofmtab2 = NULL;
 	}
 
 	/* Process BOFM table */
-	bofmrc = bofm ( bofmtab, &efipci->pci );
-	DBGC ( efidrv, "BOFM " PCI_FMT " status %08x\n",
+	DBGC2 ( efidrv, "EFIBOFM " PCI_FMT " version 1 before processing:\n",
+		PCI_ARGS ( &efipci->pci ) );
+	DBGC2_HD ( efidrv, bofmtab, bofmtab->Parameters.Length );
+	if ( bofmtab2 ) {
+		DBGC2 ( efidrv, "EFIBOFM " PCI_FMT " version 2 before "
+			"processing:\n", PCI_ARGS ( &efipci->pci ) );
+		DBGC2_HD ( efidrv, bofmtab2, bofmtab2->Parameters.Length );
+	}
+	bofmrc = bofm ( virt_to_user ( bofmtab2 ? bofmtab2 : bofmtab ),
+			&efipci->pci );
+	DBGC ( efidrv, "EFIBOFM " PCI_FMT " status %08x\n",
 	       PCI_ARGS ( &efipci->pci ), bofmrc );
+	DBGC2 ( efidrv, "EFIBOFM " PCI_FMT " version 1 after processing:\n",
+		PCI_ARGS ( &efipci->pci ) );
+	DBGC2_HD ( efidrv, bofmtab, bofmtab->Parameters.Length );
+	if ( bofmtab2 ) {
+		DBGC2 ( efidrv, "EFIBOFM " PCI_FMT " version 2 after "
+			"processing:\n", PCI_ARGS ( &efipci->pci ) );
+		DBGC2_HD ( efidrv, bofmtab2, bofmtab2->Parameters.Length );
+	}
 
 	/* Return BOFM status */
-	if ( ( efirc = bofm1.bofm1->SetStatus ( bofm1.bofm1, device, FALSE,
-						bofmrc ) ) != 0 ) {
-		DBGC ( efidrv, "BOFM " PCI_FMT " could not set BOFM status: "
-		       "%s\n", PCI_ARGS ( &efipci->pci ),
-		       efi_strerror ( efirc ) );
-		goto err_set_status;
+	if ( bofmtab2 ) {
+		if ( ( efirc = bofm2.bofm2->SetStatus ( bofm2.bofm2, device,
+							FALSE, bofmrc ) ) != 0){
+			DBGC ( efidrv, "EFIBOFM " PCI_FMT " could not set "
+			       "BOFM2 status: %s\n", PCI_ARGS ( &efipci->pci ),
+			       efi_strerror ( efirc ) );
+			goto err_set_status;
+		}
+	} else {
+		if ( ( efirc = bofm1.bofm1->SetStatus ( bofm1.bofm1, device,
+							FALSE, bofmrc ) ) != 0){
+			DBGC ( efidrv, "EFIBOFM " PCI_FMT " could not set "
+			       "BOFM status: %s\n", PCI_ARGS ( &efipci->pci ),
+			       efi_strerror ( efirc ) );
+			goto err_set_status;
+		}
 	}
 
 	/* Destroy the PCI device anyway; we have no further use for it */
@@ -332,7 +368,7 @@ static EFI_STATUS EFIAPI efi_bofm_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver,
 	struct efi_driver *efidrv =
 		container_of ( driver, struct efi_driver, driver );
 
-	DBGCP ( efidrv, "BOFM DRIVER_STOP %p (%ld %p)\n",
+	DBGCP ( efidrv, "EFIBOFM DRIVER_STOP %p (%ld %p)\n",
 		device, ( ( unsigned long ) num_children ), children );
 
 	return 0;
@@ -353,12 +389,12 @@ static void efi_bofm_driver_init ( void ) {
 
 	/* Install driver */
 	if ( ( efirc = efi_driver_install ( efidrv ) ) != 0 ) {
-		DBGC ( efidrv, "BOFM could not install driver: %s\n",
+		DBGC ( efidrv, "EFIBOFM could not install driver: %s\n",
 		       efi_strerror ( efirc ) );
 		return;
 	}
 
-	DBGC ( efidrv, "BOFM driver installed\n" );
+	DBGC ( efidrv, "EFIBOFM driver installed\n" );
 }
 
 /** EFI BOFM startup function */
diff --git a/roms/ipxe/src/interface/efi/efi_console.c b/roms/ipxe/src/interface/efi/efi_console.c
index 1303a4278821f90eb77e921d7ecb..a30ca301b85d76927912635b317f 100644
--- a/roms/ipxe/src/interface/efi/efi_console.c
+++ b/roms/ipxe/src/interface/efi/efi_console.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -23,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/efi/efi.h>
 #include <ipxe/ansiesc.h>
 #include <ipxe/console.h>
+#include <config/console.h>
 
 #define ATTR_BOLD		0x08
 
@@ -48,6 +50,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 #define ATTR_DEFAULT		ATTR_FCOL_WHITE
 
+/* Set default console usage if applicable */
+#if ! ( defined ( CONSOLE_EFI ) && CONSOLE_EXPLICIT ( CONSOLE_EFI ) )
+#undef CONSOLE_EFI
+#define CONSOLE_EFI ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
+#endif
+
 /** Current character attribute */
 static unsigned int efi_attr = ATTR_DEFAULT;
 
@@ -273,4 +281,5 @@ struct console_driver efi_console __console_driver = {
 	.putchar = efi_putchar,
 	.getchar = efi_getchar,
 	.iskey = efi_iskey,
+	.usage = CONSOLE_EFI,
 };
diff --git a/roms/ipxe/src/interface/efi/efi_debug.c b/roms/ipxe/src/interface/efi/efi_debug.c
new file mode 100644
index 0000000000000000000000000000000000000000..a7ba7e2edd4f2ede8324d87a74fe8a2aadac6c5e
--- /dev/null
+++ b/roms/ipxe/src/interface/efi/efi_debug.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * EFI debugging utilities
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ipxe/uuid.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_driver.h>
+#include <ipxe/efi/Protocol/DevicePath.h>
+#include <ipxe/efi/Protocol/DevicePathToText.h>
+
+/** Device path to text protocol */
+static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *efidpt;
+EFI_REQUIRE_PROTOCOL ( EFI_DEVICE_PATH_TO_TEXT_PROTOCOL, &efidpt );
+
+/**
+ * Convert GUID to a printable string
+ *
+ * @v guid		GUID
+ * @ret string		Printable string
+ */
+const char * efi_guid_ntoa ( EFI_GUID *guid ) {
+	union {
+		union uuid uuid;
+		EFI_GUID guid;
+	} u;
+
+	/* Convert GUID to standard endianness */
+	memcpy ( &u.guid, guid, sizeof ( u.guid ) );
+	uuid_mangle ( &u.uuid );
+	return uuid_ntoa ( &u.uuid );
+}
+
+/**
+ * Print list of protocol handlers attached to a handle
+ *
+ * @v handle		EFI handle
+ */
+void dbg_efi_protocols ( EFI_HANDLE handle ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+        EFI_GUID **protocols;
+	UINTN count;
+	unsigned int i;
+	EFI_STATUS efirc;
+
+	/* Retrieve list of protocols */
+	if ( ( efirc = bs->ProtocolsPerHandle ( handle, &protocols,
+						&count ) ) != 0 ) {
+		printf ( "EFI could not retrieve protocols for %p: %s\n",
+			 handle, efi_strerror ( efirc ) );
+		return;
+	}
+
+	/* Dump list of protocols */
+	for ( i = 0 ; i < count ; i++ )
+		printf ( "%s\n", efi_guid_ntoa ( protocols[i] ) );
+
+	/* Free list */
+	bs->FreePool ( protocols );
+}
+
+/**
+ * Print device path
+ *
+ * @v path		Device path
+ */
+void dbg_efi_devpath ( EFI_DEVICE_PATH_PROTOCOL *path ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	EFI_DEVICE_PATH_PROTOCOL *end;
+	CHAR16 *text;
+	size_t len;
+
+	/* Convert path to a textual representation */
+	text = efidpt->ConvertDevicePathToText ( path, TRUE, FALSE );
+	if ( ! text ) {
+		printf ( "<cannot convert>:\n" );
+		end = efi_devpath_end ( path );
+		len = ( ( ( void * ) end ) - ( ( void * ) path ) +
+			sizeof ( *end ) );
+		dbg_hex_dump_da ( 0, path, len );
+		return;
+	}
+
+	/* Print path */
+	printf ( "%ls", text );
+
+	/* Free path */
+	bs->FreePool ( text );
+}
diff --git a/roms/ipxe/src/interface/efi/efi_download.c b/roms/ipxe/src/interface/efi/efi_download.c
new file mode 100644
index 0000000000000000000000000000000000000000..7b19ad3a2ddcfa43759c031390bc5cf41e1de017
--- /dev/null
+++ b/roms/ipxe/src/interface/efi/efi_download.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2010 VMware, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <string.h>
+#include <ipxe/open.h>
+#include <ipxe/process.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_download.h>
+
+/** iPXE download protocol GUID */
+static EFI_GUID ipxe_download_protocol_guid
+	= IPXE_DOWNLOAD_PROTOCOL_GUID;
+
+/** A single in-progress file */
+struct efi_download_file {
+	/** Data transfer interface that provides downloaded data */
+	struct interface xfer;
+
+	/** Current file position */
+	size_t pos;
+
+	/** Data callback */
+	IPXE_DOWNLOAD_DATA_CALLBACK data_callback;
+
+	/** Finish callback */
+	IPXE_DOWNLOAD_FINISH_CALLBACK finish_callback;
+
+	/** Callback context */
+	void *context;
+};
+
+/* xfer interface */
+
+/**
+ * Transfer finished or was aborted
+ *
+ * @v file		Data transfer file
+ * @v rc		Reason for close
+ */
+static void efi_download_close ( struct efi_download_file *file, int rc ) {
+
+	file->finish_callback ( file->context, RC_TO_EFIRC ( rc ) );
+
+	intf_shutdown ( &file->xfer, rc );
+}
+
+/**
+ * Process received data
+ *
+ * @v file		Data transfer file
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int efi_download_deliver_iob ( struct efi_download_file *file,
+				      struct io_buffer *iobuf,
+				      struct xfer_metadata *meta ) {
+	EFI_STATUS efirc;
+	size_t len = iob_len ( iobuf );
+
+	/* Calculate new buffer position */
+	if ( meta->flags & XFER_FL_ABS_OFFSET )
+		file->pos = 0;
+	file->pos += meta->offset;
+
+	/* Call out to the data handler */
+	efirc = file->data_callback ( file->context, iobuf->data,
+				      len, file->pos );
+
+	/* Update current buffer position */
+	file->pos += len;
+
+	free_iob ( iobuf );
+	return EFIRC_TO_RC ( efirc );
+}
+
+/** Data transfer interface operations */
+static struct interface_operation efi_xfer_operations[] = {
+	INTF_OP ( xfer_deliver, struct efi_download_file *, efi_download_deliver_iob ),
+	INTF_OP ( intf_close, struct efi_download_file *, efi_download_close ),
+};
+
+/** EFI download data transfer interface descriptor */
+static struct interface_descriptor efi_download_file_xfer_desc =
+	INTF_DESC ( struct efi_download_file, xfer, efi_xfer_operations );
+
+/**
+ * Start downloading a file, and register callback functions to handle the
+ * download.
+ *
+ * @v This		iPXE Download Protocol instance
+ * @v Url		URL to download from
+ * @v DataCallback	Callback that will be invoked when data arrives
+ * @v FinishCallback	Callback that will be invoked when the download ends
+ * @v Context		Context passed to the Data and Finish callbacks
+ * @v File		Token that can be used to abort the download
+ * @ret Status		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_download_start ( IPXE_DOWNLOAD_PROTOCOL *This __unused,
+		     CHAR8 *Url,
+		     IPXE_DOWNLOAD_DATA_CALLBACK DataCallback,
+		     IPXE_DOWNLOAD_FINISH_CALLBACK FinishCallback,
+		     VOID *Context,
+		     IPXE_DOWNLOAD_FILE *File ) {
+	struct efi_download_file *file;
+	int rc;
+
+	file = malloc ( sizeof ( struct efi_download_file ) );
+	if ( file == NULL ) {
+		return EFI_OUT_OF_RESOURCES;
+	}
+
+	intf_init ( &file->xfer, &efi_download_file_xfer_desc, NULL );
+	rc = xfer_open ( &file->xfer, LOCATION_URI_STRING, Url );
+	if ( rc ) {
+		free ( file );
+		return RC_TO_EFIRC ( rc );
+	}
+
+	file->pos = 0;
+	file->data_callback = DataCallback;
+	file->finish_callback = FinishCallback;
+	file->context = Context;
+	*File = file;
+	return EFI_SUCCESS;
+}
+
+/**
+ * Forcibly abort downloading a file that is currently in progress.
+ *
+ * It is not safe to call this function after the Finish callback has executed.
+ *
+ * @v This		iPXE Download Protocol instance
+ * @v File		Token obtained from Start
+ * @v Status		Reason for aborting the download
+ * @ret Status		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_download_abort ( IPXE_DOWNLOAD_PROTOCOL *This __unused,
+		     IPXE_DOWNLOAD_FILE File,
+		     EFI_STATUS Status ) {
+	struct efi_download_file *file = File;
+
+	efi_download_close ( file, EFIRC_TO_RC ( Status ) );
+	return EFI_SUCCESS;
+}
+
+/**
+ * Poll for more data from iPXE. This function will invoke the registered
+ * callbacks if data is available or if downloads complete.
+ *
+ * @v This		iPXE Download Protocol instance
+ * @ret Status		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_download_poll ( IPXE_DOWNLOAD_PROTOCOL *This __unused ) {
+	step();
+	return EFI_SUCCESS;
+}
+
+/** Publicly exposed iPXE download protocol */
+static IPXE_DOWNLOAD_PROTOCOL ipxe_download_protocol_interface = {
+	.Start = efi_download_start,
+	.Abort = efi_download_abort,
+	.Poll = efi_download_poll
+};
+
+/**
+ * Install iPXE download protocol
+ *
+ * @v handle		EFI handle
+ * @ret rc		Return status code
+ */
+int efi_download_install ( EFI_HANDLE *handle ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	EFI_STATUS efirc;
+
+	efirc = bs->InstallMultipleProtocolInterfaces (
+			handle,
+			&ipxe_download_protocol_guid,
+			&ipxe_download_protocol_interface,
+			NULL );
+	if ( efirc ) {
+		DBG ( "Could not install download protocol: %s\n",
+		      efi_strerror ( efirc ) );
+		return EFIRC_TO_RC ( efirc );
+	}
+
+	return 0;
+}
+
+/**
+ * Uninstall iPXE download protocol
+ *
+ * @v handle		EFI handle
+ */
+void efi_download_uninstall ( EFI_HANDLE handle ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+
+	bs->UninstallMultipleProtocolInterfaces (
+			handle,
+			&ipxe_download_protocol_guid,
+			&ipxe_download_protocol_interface, NULL );
+}
diff --git a/roms/ipxe/src/interface/efi/efi_driver.c b/roms/ipxe/src/interface/efi/efi_driver.c
index 4aa976f90e290a1c45ab0dc069b6..deb3cf2cd59c906c9ad0bb23de3d 100644
--- a/roms/ipxe/src/interface/efi/efi_driver.c
+++ b/roms/ipxe/src/interface/efi/efi_driver.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -89,12 +90,29 @@ efi_driver_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf,
  */
 static EFI_STATUS EFIAPI
 efi_driver_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
-				 EFI_HANDLE device __unused,
-				 EFI_HANDLE child __unused,
-				 CHAR8 *language __unused,
-				 CHAR16 **controller_name __unused ) {
+				 EFI_HANDLE device, EFI_HANDLE child,
+				 CHAR8 *language, CHAR16 **controller_name ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	union {
+		EFI_COMPONENT_NAME2_PROTOCOL *name2;
+		void *interface;
+	} name2;
+	EFI_STATUS efirc;
+
+	/* Delegate to the EFI_COMPONENT_NAME2_PROTOCOL instance
+	 * installed on child handle, if present.
+	 */
+	if ( ( child != NULL ) &&
+	     ( ( efirc = bs->OpenProtocol (
+			  child, &efi_component_name2_protocol_guid,
+			  &name2.interface, NULL, NULL,
+			  EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) == 0 ) ) {
+		return name2.name2->GetControllerName ( name2.name2, device,
+							child, language,
+							controller_name );
+	}
 
-	/* Just let EFI use the default Device Path Name */
+	/* Otherwise, let EFI use the default Device Path Name */
 	return EFI_UNSUPPORTED;
 }
 
diff --git a/roms/ipxe/src/interface/efi/efi_file.c b/roms/ipxe/src/interface/efi/efi_file.c
new file mode 100644
index 0000000000000000000000000000000000000000..6f9d44f83e39357b1d07f8c736091354de7e13ec
--- /dev/null
+++ b/roms/ipxe/src/interface/efi/efi_file.c
@@ -0,0 +1,593 @@
+/*
+ * Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * EFI file protocols
+ *
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <ipxe/image.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/Protocol/SimpleFileSystem.h>
+#include <ipxe/efi/Protocol/BlockIo.h>
+#include <ipxe/efi/Guid/FileInfo.h>
+#include <ipxe/efi/Guid/FileSystemInfo.h>
+#include <ipxe/efi/efi_strings.h>
+#include <ipxe/efi/efi_file.h>
+
+/** EFI simple file system protocol GUID */
+static EFI_GUID efi_simple_file_system_protocol_guid
+	= EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
+
+/** EFI file information GUID */
+static EFI_GUID efi_file_info_id = EFI_FILE_INFO_ID;
+
+/** EFI file system information GUID */
+static EFI_GUID efi_file_system_info_id = EFI_FILE_SYSTEM_INFO_ID;
+
+/** EFI block I/O protocol GUID */
+static EFI_GUID efi_block_io_protocol_guid
+	= EFI_BLOCK_IO_PROTOCOL_GUID;
+
+/** EFI media ID */
+#define EFI_MEDIA_ID_MAGIC 0x69505845
+
+/** An image exposed as an EFI file */
+struct efi_file {
+	/** EFI file protocol */
+	EFI_FILE_PROTOCOL file;
+	/** Image */
+	struct image *image;
+	/** Current file position */
+	size_t pos;
+};
+
+static struct efi_file efi_file_root;
+
+/**
+ * Get EFI file name (for debugging)
+ *
+ * @v file		EFI file
+ * @ret name		Name
+ */
+static const char * efi_file_name ( struct efi_file *file ) {
+
+	return ( file->image ? file->image->name : "<root>" );
+}
+
+/**
+ * Open file
+ *
+ * @v this		EFI file
+ * @ret new		New EFI file
+ * @v wname		Filename
+ * @v mode		File mode
+ * @v attributes	File attributes (for newly-created files)
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
+		CHAR16 *wname, UINT64 mode __unused,
+		UINT64 attributes __unused ) {
+	struct efi_file *file = container_of ( this, struct efi_file, file );
+	char name[ wcslen ( wname ) + 1 /* NUL */ ];
+	struct efi_file *new_file;
+	struct image *image;
+
+	/* Initial '\' indicates opening from the root directory */
+	while ( *wname == L'\\' ) {
+		file = &efi_file_root;
+		wname++;
+	}
+
+	/* Allow root directory itself to be opened */
+	if ( ( wname[0] == L'\0' ) || ( wname[0] == L'.' ) ) {
+		*new = &efi_file_root.file;
+		return 0;
+	}
+
+	/* Fail unless opening from the root */
+	if ( file->image ) {
+		DBGC ( file, "EFIFILE %s is not a directory\n",
+		       efi_file_name ( file ) );
+		return EFI_NOT_FOUND;
+	}
+
+	/* Identify image */
+	snprintf ( name, sizeof ( name ), "%ls", wname );
+	image = find_image ( name );
+	if ( ! image ) {
+		DBGC ( file, "EFIFILE \"%s\" does not exist\n", name );
+		return EFI_NOT_FOUND;
+	}
+
+	/* Fail unless opening read-only */
+	if ( mode != EFI_FILE_MODE_READ ) {
+		DBGC ( file, "EFIFILE %s cannot be opened in mode %#08llx\n",
+		       image->name, mode );
+		return EFI_WRITE_PROTECTED;
+	}
+
+	/* Allocate and initialise file */
+	new_file = zalloc ( sizeof ( *new_file ) );
+	memcpy ( &new_file->file, &efi_file_root.file,
+		 sizeof ( new_file->file ) );
+	new_file->image = image_get ( image );
+	*new = &new_file->file;
+	DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) );
+
+	return 0;
+}
+
+/**
+ * Close file
+ *
+ * @v this		EFI file
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI efi_file_close ( EFI_FILE_PROTOCOL *this ) {
+	struct efi_file *file = container_of ( this, struct efi_file, file );
+
+	/* Do nothing if this is the root */
+	if ( ! file->image )
+		return 0;
+
+	/* Close file */
+	DBGC ( file, "EFIFILE %s closed\n", efi_file_name ( file ) );
+	image_put ( file->image );
+	free ( file );
+
+	return 0;
+}
+
+/**
+ * Close and delete file
+ *
+ * @v this		EFI file
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI efi_file_delete ( EFI_FILE_PROTOCOL *this ) {
+	struct efi_file *file = container_of ( this, struct efi_file, file );
+
+	DBGC ( file, "EFIFILE %s cannot be deleted\n", efi_file_name ( file ) );
+
+	/* Close file */
+	efi_file_close ( this );
+
+	/* Warn of failure to delete */
+	return EFI_WARN_DELETE_FAILURE;
+}
+
+/**
+ * Return variable-length data structure
+ *
+ * @v base		Base data structure (starting with UINT64)
+ * @v base_len		Length of base data structure
+ * @v name		Name to append to base data structure
+ * @v len		Length of data buffer
+ * @v data		Data buffer
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS efi_file_varlen ( UINT64 *base, size_t base_len,
+				    const char *name, UINTN *len, VOID *data ) {
+	size_t name_len;
+
+	/* Calculate structure length */
+	name_len = strlen ( name );
+	*base = ( base_len + ( name_len + 1 /* NUL */ ) * sizeof ( wchar_t ) );
+	if ( *len < *base ) {
+		*len = *base;
+		return EFI_BUFFER_TOO_SMALL;
+	}
+
+	/* Copy data to buffer */
+	*len = *base;
+	memcpy ( data, base, base_len );
+	efi_snprintf ( ( data + base_len ), ( name_len + 1 /* NUL */ ),
+		       "%s", name );
+
+	return 0;
+}
+
+/**
+ * Return file information structure
+ *
+ * @v image		Image, or NULL for the root directory
+ * @v len		Length of data buffer
+ * @v data		Data buffer
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS efi_file_info ( struct image *image, UINTN *len,
+				  VOID *data ) {
+	EFI_FILE_INFO info;
+	const char *name;
+
+	/* Populate file information */
+	memset ( &info, 0, sizeof ( info ) );
+	if ( image ) {
+		info.FileSize = image->len;
+		info.PhysicalSize = image->len;
+		info.Attribute = EFI_FILE_READ_ONLY;
+		name = image->name;
+	} else {
+		info.Attribute = ( EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY );
+		name = "";
+	}
+
+	return efi_file_varlen ( &info.Size, SIZE_OF_EFI_FILE_INFO, name,
+				 len, data );
+}
+
+/**
+ * Read directory entry
+ *
+ * @v file		EFI file
+ * @v len		Length to read
+ * @v data		Data buffer
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
+				      VOID *data ) {
+	EFI_STATUS efirc;
+	struct image *image;
+	unsigned int index;
+
+	/* Construct directory entry at current position */
+	index = file->pos;
+	for_each_image ( image ) {
+		if ( index-- == 0 ) {
+			efirc = efi_file_info ( image, len, data );
+			if ( efirc == 0 )
+				file->pos++;
+			return efirc;
+		}
+	}
+
+	/* No more entries */
+	*len = 0;
+	return 0;
+}
+
+/**
+ * Read from file
+ *
+ * @v this		EFI file
+ * @v len		Length to read
+ * @v data		Data buffer
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI efi_file_read ( EFI_FILE_PROTOCOL *this,
+					 UINTN *len, VOID *data ) {
+	struct efi_file *file = container_of ( this, struct efi_file, file );
+	size_t remaining;
+
+	/* If this is the root directory, then construct a directory entry */
+	if ( ! file->image )
+		return efi_file_read_dir ( file, len, data );
+
+	/* Read from the file */
+	remaining = ( file->image->len - file->pos );
+	if ( *len > remaining )
+		*len = remaining;
+	DBGC ( file, "EFIFILE %s read [%#08zx,%#08zx)\n",
+	       efi_file_name ( file ), file->pos,
+	       ( ( size_t ) ( file->pos + *len ) ) );
+	copy_from_user ( data, file->image->data, file->pos, *len );
+	file->pos += *len;
+	return 0;
+}
+
+/**
+ * Write to file
+ *
+ * @v this		EFI file
+ * @v len		Length to write
+ * @v data		Data buffer
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI efi_file_write ( EFI_FILE_PROTOCOL *this,
+					  UINTN *len, VOID *data __unused ) {
+	struct efi_file *file = container_of ( this, struct efi_file, file );
+
+	DBGC ( file, "EFIFILE %s cannot write [%#08zx, %#08zx)\n",
+	       efi_file_name ( file ), file->pos,
+	       ( ( size_t ) ( file->pos + *len ) ) );
+	return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * Set file position
+ *
+ * @v this		EFI file
+ * @v position		New file position
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI efi_file_set_position ( EFI_FILE_PROTOCOL *this,
+						 UINT64 position ) {
+	struct efi_file *file = container_of ( this, struct efi_file, file );
+
+	/* If this is the root directory, reset to the start */
+	if ( ! file->image ) {
+		DBGC ( file, "EFIFILE root directory rewound\n" );
+		file->pos = 0;
+		return 0;
+	}
+
+	/* Check for the magic end-of-file value */
+	if ( position == 0xffffffffffffffffULL )
+		position = file->image->len;
+
+	/* Fail if we attempt to seek past the end of the file (since
+	 * we do not support writes).
+	 */
+	if ( position > file->image->len ) {
+		DBGC ( file, "EFIFILE %s cannot seek to %#08llx of %#08zx\n",
+		       efi_file_name ( file ), position, file->image->len );
+		return EFI_UNSUPPORTED;
+	}
+
+	/* Set position */
+	file->pos = position;
+	DBGC ( file, "EFIFILE %s position set to %#08zx\n",
+	       efi_file_name ( file ), file->pos );
+
+	return 0;
+}
+
+/**
+ * Get file position
+ *
+ * @v this		EFI file
+ * @ret position	New file position
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI efi_file_get_position ( EFI_FILE_PROTOCOL *this,
+						 UINT64 *position ) {
+	struct efi_file *file = container_of ( this, struct efi_file, file );
+
+	*position = file->pos;
+	return 0;
+}
+
+/**
+ * Get file information
+ *
+ * @v this		EFI file
+ * @v type		Type of information
+ * @v len		Buffer size
+ * @v data		Buffer
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI efi_file_get_info ( EFI_FILE_PROTOCOL *this,
+					     EFI_GUID *type,
+					     UINTN *len, VOID *data ) {
+	struct efi_file *file = container_of ( this, struct efi_file, file );
+	EFI_FILE_SYSTEM_INFO fsinfo;
+	struct image *image;
+
+	/* Determine information to return */
+	if ( memcmp ( type, &efi_file_info_id, sizeof ( *type ) ) == 0 ) {
+
+		/* Get file information */
+		DBGC ( file, "EFIFILE %s get file information\n",
+		       efi_file_name ( file ) );
+		return efi_file_info ( file->image, len, data );
+
+	} else if ( memcmp ( type, &efi_file_system_info_id,
+			     sizeof ( *type ) ) == 0 ) {
+
+		/* Get file system information */
+		DBGC ( file, "EFIFILE %s get file system information\n",
+		       efi_file_name ( file ) );
+		memset ( &fsinfo, 0, sizeof ( fsinfo ) );
+		fsinfo.ReadOnly = 1;
+		for_each_image ( image )
+			fsinfo.VolumeSize += image->len;
+		return efi_file_varlen ( &fsinfo.Size,
+					 SIZE_OF_EFI_FILE_SYSTEM_INFO, "iPXE",
+					 len, data );
+	} else {
+
+		DBGC ( file, "EFIFILE %s cannot get information of type %s\n",
+		       efi_file_name ( file ), efi_guid_ntoa ( type ) );
+		return EFI_UNSUPPORTED;
+	}
+}
+
+/**
+ * Set file information
+ *
+ * @v this		EFI file
+ * @v type		Type of information
+ * @v len		Buffer size
+ * @v data		Buffer
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_file_set_info ( EFI_FILE_PROTOCOL *this, EFI_GUID *type,
+		    UINTN len __unused, VOID *data __unused ) {
+	struct efi_file *file = container_of ( this, struct efi_file, file );
+
+	DBGC ( file, "EFIFILE %s cannot set information of type %s\n",
+	       efi_file_name ( file ), efi_guid_ntoa ( type ) );
+	return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * Flush file modified data
+ *
+ * @v this		EFI file
+ * @v type		Type of information
+ * @v len		Buffer size
+ * @v data		Buffer
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI efi_file_flush ( EFI_FILE_PROTOCOL *this ) {
+	struct efi_file *file = container_of ( this, struct efi_file, file );
+
+	DBGC ( file, "EFIFILE %s flushed\n", efi_file_name ( file ) );
+	return 0;
+}
+
+/** Root directory */
+static struct efi_file efi_file_root = {
+	.file = {
+		.Revision = EFI_FILE_PROTOCOL_REVISION,
+		.Open = efi_file_open,
+		.Close = efi_file_close,
+		.Delete = efi_file_delete,
+		.Read = efi_file_read,
+		.Write = efi_file_write,
+		.GetPosition = efi_file_get_position,
+		.SetPosition = efi_file_set_position,
+		.GetInfo = efi_file_get_info,
+		.SetInfo = efi_file_set_info,
+		.Flush = efi_file_flush,
+	},
+	.image = NULL,
+};
+
+/**
+ * Open root directory
+ *
+ * @v filesystem	EFI simple file system
+ * @ret file		EFI file handle
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_file_open_volume ( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *filesystem __unused,
+		       EFI_FILE_PROTOCOL **file ) {
+
+	*file = &efi_file_root.file;
+	return 0;
+}
+
+/** EFI simple file system protocol */
+static EFI_SIMPLE_FILE_SYSTEM_PROTOCOL efi_simple_file_system_protocol = {
+	.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
+	.OpenVolume = efi_file_open_volume,
+};
+
+/** Dummy block I/O reset */
+static EFI_STATUS EFIAPI
+efi_block_io_reset ( EFI_BLOCK_IO_PROTOCOL *this __unused,
+		     BOOLEAN extended __unused ) {
+	return 0;
+}
+
+/** Dummy block I/O read */
+static EFI_STATUS EFIAPI
+efi_block_io_read_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused,
+			   UINT32 MediaId __unused, EFI_LBA lba __unused,
+			   UINTN len __unused, VOID *data __unused ) {
+	return EFI_DEVICE_ERROR;
+}
+
+/** Dummy block I/O write */
+static EFI_STATUS EFIAPI
+efi_block_io_write_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused,
+			    UINT32 MediaId __unused, EFI_LBA lba __unused,
+			    UINTN len __unused, VOID *data __unused ) {
+	return EFI_DEVICE_ERROR;
+}
+
+/** Dummy block I/O flush */
+static EFI_STATUS EFIAPI
+efi_block_io_flush_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused ) {
+	return 0;
+}
+
+/** Dummy block I/O media */
+static EFI_BLOCK_IO_MEDIA efi_block_io_media = {
+	.MediaId = EFI_MEDIA_ID_MAGIC,
+	.MediaPresent = 1,
+	.ReadOnly = 1,
+	.BlockSize = 1,
+};
+
+/** Dummy EFI block I/O protocol */
+static EFI_BLOCK_IO_PROTOCOL efi_block_io_protocol = {
+	.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION,
+	.Media = &efi_block_io_media,
+	.Reset = efi_block_io_reset,
+	.ReadBlocks = efi_block_io_read_blocks,
+	.WriteBlocks = efi_block_io_write_blocks,
+	.FlushBlocks = efi_block_io_flush_blocks,
+};
+
+/**
+ * Install EFI simple file system protocol
+ *
+ * @v handle		EFI handle
+ * @ret rc		Return status code
+ */
+int efi_file_install ( EFI_HANDLE *handle ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	EFI_STATUS efirc;
+
+	/* Install the simple file system protocol and the block I/O
+	 * protocol.  We don't have a block device, but large parts of
+	 * the EDK2 codebase make the assumption that file systems are
+	 * normally attached to block devices, and so we create a
+	 * dummy block device on the same handle just to keep things
+	 * looking normal.
+	 */
+	if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
+			handle,
+			&efi_block_io_protocol_guid,
+			&efi_block_io_protocol,
+			&efi_simple_file_system_protocol_guid,
+			&efi_simple_file_system_protocol, NULL ) ) != 0 ) {
+		DBGC ( handle, "Could not install simple file system protocol: "
+		       "%s\n", efi_strerror ( efirc ) );
+		return EFIRC_TO_RC ( efirc );
+	}
+
+	return 0;
+}
+
+/**
+ * Uninstall EFI simple file system protocol
+ *
+ * @v handle		EFI handle
+ */
+void efi_file_uninstall ( EFI_HANDLE handle ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+
+	/* We must install the file system protocol first, since
+	 * otherwise the EDK2 code will attempt to helpfully uninstall
+	 * it when the block I/O protocol is uninstalled, leading to a
+	 * system lock-up.
+	 */
+	bs->UninstallMultipleProtocolInterfaces (
+			handle,
+			&efi_simple_file_system_protocol_guid,
+			&efi_simple_file_system_protocol,
+			&efi_block_io_protocol_guid,
+			&efi_block_io_protocol, NULL );
+}
diff --git a/roms/ipxe/src/interface/efi/efi_hii.c b/roms/ipxe/src/interface/efi/efi_hii.c
new file mode 100644
index 0000000000000000000000000000000000000000..834060b546bda44be9f0f314b614d1ca055686b2
--- /dev/null
+++ b/roms/ipxe/src/interface/efi/efi_hii.c
@@ -0,0 +1,577 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_strings.h>
+#include <ipxe/efi/efi_hii.h>
+
+/** Tiano GUID */
+static const EFI_GUID tiano_guid = EFI_IFR_TIANO_GUID;
+
+/**
+ * Add string to IFR builder
+ *
+ * @v ifr		IFR builder
+ * @v fmt		Format string
+ * @v ...		Arguments
+ * @ret string_id	String identifier, or zero on failure
+ */
+unsigned int efi_ifr_string ( struct efi_ifr_builder *ifr, const char *fmt,
+			      ... ) {
+	EFI_HII_STRING_BLOCK *new_strings;
+	EFI_HII_SIBT_STRING_UCS2_BLOCK *ucs2;
+	size_t new_strings_len;
+	va_list args;
+	size_t len;
+	unsigned int string_id;
+
+	/* Do nothing if a previous allocation has failed */
+	if ( ifr->failed )
+		return 0;
+
+	/* Calculate string length */
+	va_start ( args, fmt );
+	len = ( efi_vsnprintf ( NULL, 0, fmt, args ) + 1 /* wNUL */ );
+	va_end ( args );
+
+	/* Reallocate strings */
+	new_strings_len = ( ifr->strings_len +
+			    offsetof ( typeof ( *ucs2 ), StringText ) +
+			    ( len * sizeof ( ucs2->StringText[0] ) ) );
+	new_strings = realloc ( ifr->strings, new_strings_len );
+	if ( ! new_strings ) {
+		ifr->failed = 1;
+		return 0;
+	}
+	ucs2 = ( ( ( void * ) new_strings ) + ifr->strings_len );
+	ifr->strings = new_strings;
+	ifr->strings_len = new_strings_len;
+
+	/* Fill in string */
+	ucs2->Header.BlockType = EFI_HII_SIBT_STRING_UCS2;
+	va_start ( args, fmt );
+	efi_vsnprintf ( ucs2->StringText, len, fmt, args );
+	va_end ( args );
+
+	/* Allocate string ID */
+	string_id = ++(ifr->string_id);
+
+	DBGC ( ifr, "IFR %p string %#04x is \"%ls\"\n",
+	       ifr, string_id, ucs2->StringText );
+	return string_id;
+}
+
+/**
+ * Add IFR opcode to IFR builder
+ *
+ * @v ifr		IFR builder
+ * @v opcode		Opcode
+ * @v len		Opcode length
+ * @ret op		Opcode, or NULL
+ */
+static void * efi_ifr_op ( struct efi_ifr_builder *ifr, unsigned int opcode,
+			   size_t len ) {
+	EFI_IFR_OP_HEADER *new_ops;
+	EFI_IFR_OP_HEADER *op;
+	size_t new_ops_len;
+
+	/* Do nothing if a previous allocation has failed */
+	if ( ifr->failed )
+		return NULL;
+
+	/* Reallocate opcodes */
+	new_ops_len = ( ifr->ops_len + len );
+	new_ops = realloc ( ifr->ops, new_ops_len );
+	if ( ! new_ops ) {
+		ifr->failed = 1;
+		return NULL;
+	}
+	op = ( ( ( void * ) new_ops ) + ifr->ops_len );
+	ifr->ops = new_ops;
+	ifr->ops_len = new_ops_len;
+
+	/* Fill in opcode header */
+	op->OpCode = opcode;
+	op->Length = len;
+
+	return op;
+}
+
+/**
+ * Add end opcode to IFR builder
+ *
+ * @v ifr		IFR builder
+ */
+void efi_ifr_end_op ( struct efi_ifr_builder *ifr ) {
+	size_t dispaddr = ifr->ops_len;
+	EFI_IFR_END *end;
+
+	/* Add opcode */
+	end = efi_ifr_op ( ifr, EFI_IFR_END_OP, sizeof ( *end ) );
+
+	DBGC ( ifr, "IFR %p end\n", ifr );
+	DBGC2_HDA ( ifr, dispaddr, end, sizeof ( *end ) );
+}
+
+/**
+ * Add false opcode to IFR builder
+ *
+ * @v ifr		IFR builder
+ */
+void efi_ifr_false_op ( struct efi_ifr_builder *ifr ) {
+	size_t dispaddr = ifr->ops_len;
+	EFI_IFR_FALSE *false;
+
+	/* Add opcode */
+	false = efi_ifr_op ( ifr, EFI_IFR_FALSE_OP, sizeof ( *false ) );
+
+	DBGC ( ifr, "IFR %p false\n", ifr );
+	DBGC2_HDA ( ifr, dispaddr, false, sizeof ( *false ) );
+}
+
+/**
+ * Add form opcode to IFR builder
+ *
+ * @v ifr		IFR builder
+ * @v title_id		Title string identifier
+ * @ret form_id		Form identifier
+ */
+unsigned int efi_ifr_form_op ( struct efi_ifr_builder *ifr,
+			       unsigned int title_id ) {
+	size_t dispaddr = ifr->ops_len;
+	EFI_IFR_FORM *form;
+
+	/* Add opcode */
+	form = efi_ifr_op ( ifr, EFI_IFR_FORM_OP, sizeof ( *form ) );
+	if ( ! form )
+		return 0;
+	form->Header.Scope = 1;
+	form->FormId = ++(ifr->form_id);
+	form->FormTitle = title_id;
+
+	DBGC ( ifr, "IFR %p name/value store %#04x title %#04x\n",
+	       ifr, form->FormId, title_id );
+	DBGC2_HDA ( ifr, dispaddr, form, sizeof ( *form ) );
+	return form->FormId;
+}
+
+/**
+ * Add formset opcode to IFR builder
+ *
+ * @v ifr		IFR builder
+ * @v guid		GUID
+ * @v title_id		Title string identifier
+ * @v help_id		Help string identifier
+ * @v ...		Class GUIDs (terminated by NULL)
+ */
+void efi_ifr_form_set_op ( struct efi_ifr_builder *ifr, const EFI_GUID *guid,
+			   unsigned int title_id, unsigned int help_id, ... ) {
+	size_t dispaddr = ifr->ops_len;
+	EFI_IFR_FORM_SET *formset;
+	EFI_GUID *class_guid;
+	unsigned int num_class_guids = 0;
+	size_t len;
+	va_list args;
+
+	/* Count number of class GUIDs */
+	va_start ( args, help_id );
+	while ( va_arg ( args, const EFI_GUID * ) != NULL )
+		num_class_guids++;
+	va_end ( args );
+
+	/* Add opcode */
+	len = ( sizeof ( *formset ) +
+		( num_class_guids * sizeof ( *class_guid ) ) );
+	formset = efi_ifr_op ( ifr, EFI_IFR_FORM_SET_OP, len );
+	if ( ! formset )
+		return;
+	formset->Header.Scope = 1;
+	memcpy ( &formset->Guid, guid, sizeof ( formset->Guid ) );
+	formset->FormSetTitle = title_id;
+	formset->Help = help_id;
+	formset->Flags = num_class_guids;
+
+	/* Add class GUIDs */
+	class_guid = ( ( ( void * ) formset ) + sizeof ( *formset ) );
+	va_start ( args, help_id );
+	while ( num_class_guids-- ) {
+		memcpy ( class_guid++, va_arg ( args, const EFI_GUID * ),
+			 sizeof ( *class_guid ) );
+	}
+	va_end ( args );
+
+	DBGC ( ifr, "IFR %p formset title %#04x help %#04x\n",
+	       ifr, title_id, help_id );
+	DBGC2_HDA ( ifr, dispaddr, formset, len );
+}
+
+/**
+ * Add get opcode to IFR builder
+ *
+ * @v ifr		IFR builder
+ * @v varstore_id	Variable store identifier
+ * @v varstore_info	Variable string identifier or offset
+ * @v varstore_type	Variable type
+ */
+void efi_ifr_get_op ( struct efi_ifr_builder *ifr, unsigned int varstore_id,
+		      unsigned int varstore_info, unsigned int varstore_type ) {
+	size_t dispaddr = ifr->ops_len;
+	EFI_IFR_GET *get;
+
+	/* Add opcode */
+	get = efi_ifr_op ( ifr, EFI_IFR_GET_OP, sizeof ( *get ) );
+	get->VarStoreId = varstore_id;
+	get->VarStoreInfo.VarName = varstore_info;
+	get->VarStoreType = varstore_type;
+
+	DBGC ( ifr, "IFR %p get varstore %#04x:%#04x type %#02x\n",
+	       ifr, varstore_id, varstore_info, varstore_type );
+	DBGC2_HDA ( ifr, dispaddr, get, sizeof ( *get ) );
+}
+
+/**
+ * Add GUID class opcode to IFR builder
+ *
+ * @v ifr		IFR builder
+ * @v class		Class
+ */
+void efi_ifr_guid_class_op ( struct efi_ifr_builder *ifr, unsigned int class ) {
+	size_t dispaddr = ifr->ops_len;
+	EFI_IFR_GUID_CLASS *guid_class;
+
+	/* Add opcode */
+	guid_class = efi_ifr_op ( ifr, EFI_IFR_GUID_OP,
+				  sizeof ( *guid_class ) );
+	if ( ! guid_class )
+		return;
+	memcpy ( &guid_class->Guid, &tiano_guid, sizeof ( guid_class->Guid ) );
+	guid_class->ExtendOpCode = EFI_IFR_EXTEND_OP_CLASS;
+	guid_class->Class = class;
+
+	DBGC ( ifr, "IFR %p GUID class %#02x\n", ifr, class );
+	DBGC2_HDA ( ifr, dispaddr, guid_class, sizeof ( *guid_class ) );
+}
+
+/**
+ * Add GUID subclass opcode to IFR builder
+ *
+ * @v ifr		IFR builder
+ * @v subclass		Subclass
+ */
+void efi_ifr_guid_subclass_op ( struct efi_ifr_builder *ifr,
+				unsigned int subclass ) {
+	size_t dispaddr = ifr->ops_len;
+	EFI_IFR_GUID_SUBCLASS *guid_subclass;
+
+	/* Add opcode */
+	guid_subclass = efi_ifr_op ( ifr, EFI_IFR_GUID_OP,
+				     sizeof ( *guid_subclass ) );
+	if ( ! guid_subclass )
+		return;
+	memcpy ( &guid_subclass->Guid, &tiano_guid,
+		 sizeof ( guid_subclass->Guid ) );
+	guid_subclass->ExtendOpCode = EFI_IFR_EXTEND_OP_SUBCLASS;
+	guid_subclass->SubClass = subclass;
+
+	DBGC ( ifr, "IFR %p GUID subclass %#02x\n", ifr, subclass );
+	DBGC2_HDA ( ifr, dispaddr, guid_subclass, sizeof ( *guid_subclass ) );
+}
+
+/**
+ * Add numeric opcode to IFR builder
+ *
+ * @v ifr		IFR builder
+ * @v prompt_id		Prompt string identifier
+ * @v help_id		Help string identifier
+ * @v question_id	Question identifier
+ * @v varstore_id	Variable store identifier
+ * @v varstore_info	Variable string identifier or offset
+ * @v vflags		Variable flags
+ * @v min_value		Minimum value
+ * @v max_value		Maximum value
+ * @v step		Step
+ * @v flags		Flags
+ */
+void efi_ifr_numeric_op ( struct efi_ifr_builder *ifr, unsigned int prompt_id,
+			  unsigned int help_id, unsigned int question_id,
+			  unsigned int varstore_id, unsigned int varstore_info,
+			  unsigned int vflags, unsigned long min_value,
+			  unsigned long max_value, unsigned int step,
+			  unsigned int flags ) {
+	size_t dispaddr = ifr->ops_len;
+	EFI_IFR_NUMERIC *numeric;
+	unsigned int size;
+
+	/* Add opcode */
+	numeric = efi_ifr_op ( ifr, EFI_IFR_NUMERIC_OP, sizeof ( *numeric ) );
+	if ( ! numeric )
+		return;
+	numeric->Question.Header.Prompt = prompt_id;
+	numeric->Question.Header.Help = help_id;
+	numeric->Question.QuestionId = question_id;
+	numeric->Question.VarStoreId = varstore_id;
+	numeric->Question.VarStoreInfo.VarName = varstore_info;
+	numeric->Question.Flags = vflags;
+	size = ( flags & EFI_IFR_NUMERIC_SIZE );
+	switch ( size ) {
+	case EFI_IFR_NUMERIC_SIZE_1 :
+		numeric->data.u8.MinValue = min_value;
+		numeric->data.u8.MaxValue = max_value;
+		numeric->data.u8.Step = step;
+		break;
+	case EFI_IFR_NUMERIC_SIZE_2 :
+		numeric->data.u16.MinValue = min_value;
+		numeric->data.u16.MaxValue = max_value;
+		numeric->data.u16.Step = step;
+		break;
+	case EFI_IFR_NUMERIC_SIZE_4 :
+		numeric->data.u32.MinValue = min_value;
+		numeric->data.u32.MaxValue = max_value;
+		numeric->data.u32.Step = step;
+		break;
+	case EFI_IFR_NUMERIC_SIZE_8 :
+		numeric->data.u64.MinValue = min_value;
+		numeric->data.u64.MaxValue = max_value;
+		numeric->data.u64.Step = step;
+		break;
+	}
+
+	DBGC ( ifr, "IFR %p numeric prompt %#04x help %#04x question %#04x "
+	       "varstore %#04x:%#04x\n", ifr, prompt_id, help_id, question_id,
+	       varstore_id, varstore_info );
+	DBGC2_HDA ( ifr, dispaddr, numeric, sizeof ( *numeric ) );
+}
+
+/**
+ * Add string opcode to IFR builder
+ *
+ * @v ifr		IFR builder
+ * @v prompt_id		Prompt string identifier
+ * @v help_id		Help string identifier
+ * @v question_id	Question identifier
+ * @v varstore_id	Variable store identifier
+ * @v varstore_info	Variable string identifier or offset
+ * @v vflags		Variable flags
+ * @v min_size		Minimum size
+ * @v max_size		Maximum size
+ * @v flags		Flags
+ */
+void efi_ifr_string_op ( struct efi_ifr_builder *ifr, unsigned int prompt_id,
+			 unsigned int help_id, unsigned int question_id,
+			 unsigned int varstore_id, unsigned int varstore_info,
+			 unsigned int vflags, unsigned int min_size,
+			 unsigned int max_size, unsigned int flags ) {
+	size_t dispaddr = ifr->ops_len;
+	EFI_IFR_STRING *string;
+
+	/* Add opcode */
+	string = efi_ifr_op ( ifr, EFI_IFR_STRING_OP, sizeof ( *string ) );
+	if ( ! string )
+		return;
+	string->Question.Header.Prompt = prompt_id;
+	string->Question.Header.Help = help_id;
+	string->Question.QuestionId = question_id;
+	string->Question.VarStoreId = varstore_id;
+	string->Question.VarStoreInfo.VarName = varstore_info;
+	string->Question.Flags = vflags;
+	string->MinSize = min_size;
+	string->MaxSize = max_size;
+	string->Flags = flags;
+
+	DBGC ( ifr, "IFR %p string prompt %#04x help %#04x question %#04x "
+	       "varstore %#04x:%#04x\n", ifr, prompt_id, help_id, question_id,
+	       varstore_id, varstore_info );
+	DBGC2_HDA ( ifr, dispaddr, string, sizeof ( *string ) );
+}
+
+/**
+ * Add suppress-if opcode to IFR builder
+ *
+ * @v ifr		IFR builder
+ */
+void efi_ifr_suppress_if_op ( struct efi_ifr_builder *ifr ) {
+	size_t dispaddr = ifr->ops_len;
+	EFI_IFR_SUPPRESS_IF *suppress_if;
+
+	/* Add opcode */
+	suppress_if = efi_ifr_op ( ifr, EFI_IFR_SUPPRESS_IF_OP,
+				   sizeof ( *suppress_if ) );
+	suppress_if->Header.Scope = 1;
+
+	DBGC ( ifr, "IFR %p suppress-if\n", ifr );
+	DBGC2_HDA ( ifr, dispaddr, suppress_if, sizeof ( *suppress_if ) );
+}
+
+/**
+ * Add text opcode to IFR builder
+ *
+ * @v ifr		IFR builder
+ * @v prompt_id		Prompt string identifier
+ * @v help_id		Help string identifier
+ * @v text_id		Text string identifier
+ */
+void efi_ifr_text_op ( struct efi_ifr_builder *ifr, unsigned int prompt_id,
+		       unsigned int help_id, unsigned int text_id ) {
+	size_t dispaddr = ifr->ops_len;
+	EFI_IFR_TEXT *text;
+
+	/* Add opcode */
+	text = efi_ifr_op ( ifr, EFI_IFR_TEXT_OP, sizeof ( *text ) );
+	if ( ! text )
+		return;
+	text->Statement.Prompt = prompt_id;
+	text->Statement.Help = help_id;
+	text->TextTwo = text_id;
+
+	DBGC ( ifr, "IFR %p text prompt %#04x help %#04x text %#04x\n",
+	       ifr, prompt_id, help_id, text_id );
+	DBGC2_HDA ( ifr, dispaddr, text, sizeof ( *text ) );
+}
+
+/**
+ * Add true opcode to IFR builder
+ *
+ * @v ifr		IFR builder
+ */
+void efi_ifr_true_op ( struct efi_ifr_builder *ifr ) {
+	size_t dispaddr = ifr->ops_len;
+	EFI_IFR_TRUE *true;
+
+	/* Add opcode */
+	true = efi_ifr_op ( ifr, EFI_IFR_TRUE_OP, sizeof ( *true ) );
+
+	DBGC ( ifr, "IFR %p true\n", ifr );
+	DBGC2_HDA ( ifr, dispaddr, true, sizeof ( *true ) );
+}
+
+/**
+ * Add name/value store opcode to IFR builder
+ *
+ * @v ifr		IFR builder
+ * @v guid		GUID
+ * @ret varstore_id	Variable store identifier, or 0 on failure
+ */
+unsigned int efi_ifr_varstore_name_value_op ( struct efi_ifr_builder *ifr,
+					      const EFI_GUID *guid ) {
+	size_t dispaddr = ifr->ops_len;
+	EFI_IFR_VARSTORE_NAME_VALUE *varstore;
+
+	/* Add opcode */
+	varstore = efi_ifr_op ( ifr, EFI_IFR_VARSTORE_NAME_VALUE_OP,
+				sizeof ( *varstore ) );
+	if ( ! varstore )
+		return 0;
+	varstore->VarStoreId = ++(ifr->varstore_id);
+	memcpy ( &varstore->Guid, guid, sizeof ( varstore->Guid ) );
+
+	DBGC ( ifr, "IFR %p name/value store %#04x\n",
+	       ifr, varstore->VarStoreId );
+	DBGC2_HDA ( ifr, dispaddr, varstore, sizeof ( *varstore ) );
+	return varstore->VarStoreId;
+}
+
+/**
+ * Free memory used by IFR builder
+ *
+ * @v ifr		IFR builder
+ */
+void efi_ifr_free ( struct efi_ifr_builder *ifr ) {
+
+	free ( ifr->ops );
+	free ( ifr->strings );
+	memset ( ifr, 0, sizeof ( *ifr ) );
+}
+
+/**
+ * Construct package list from IFR builder
+ *
+ * @v ifr		IFR builder
+ * @v guid		Package GUID
+ * @v language		Language
+ * @v language_id	Language string ID
+ * @ret package		Package list, or NULL
+ *
+ * The package list is allocated using malloc(), and must eventually
+ * be freed by the caller.  (The caller must also call efi_ifr_free()
+ * to free the temporary storage used during construction.)
+ */
+EFI_HII_PACKAGE_LIST_HEADER * efi_ifr_package ( struct efi_ifr_builder *ifr,
+						const EFI_GUID *guid,
+						const char *language,
+						unsigned int language_id ) {
+	struct {
+		EFI_HII_PACKAGE_LIST_HEADER header;
+		struct {
+			EFI_HII_PACKAGE_HEADER header;
+			uint8_t data[ifr->ops_len];
+		} __attribute__ (( packed )) ops;
+		struct {
+			union {
+				EFI_HII_STRING_PACKAGE_HDR header;
+				uint8_t pad[offsetof(EFI_HII_STRING_PACKAGE_HDR,
+						     Language) +
+					    strlen ( language ) + 1 /* NUL */ ];
+			} __attribute__ (( packed )) header;
+			uint8_t data[ifr->strings_len];
+			EFI_HII_STRING_BLOCK end;
+		} __attribute__ (( packed )) strings;
+		EFI_HII_PACKAGE_HEADER end;
+	} __attribute__ (( packed )) *package;
+
+	/* Fail if any previous allocation failed */
+	if ( ifr->failed )
+		return NULL;
+
+	/* Allocate package list */
+	package = zalloc ( sizeof ( *package ) );
+	if ( ! package )
+		return NULL;
+
+	/* Populate package list */
+	package->header.PackageLength = sizeof ( *package );
+	memcpy ( &package->header.PackageListGuid, guid,
+		 sizeof ( package->header.PackageListGuid ) );
+	package->ops.header.Length = sizeof ( package->ops );
+	package->ops.header.Type = EFI_HII_PACKAGE_FORMS;
+	memcpy ( package->ops.data, ifr->ops, sizeof ( package->ops.data ) );
+	package->strings.header.header.Header.Length =
+		sizeof ( package->strings );
+	package->strings.header.header.Header.Type =
+		EFI_HII_PACKAGE_STRINGS;
+	package->strings.header.header.HdrSize =
+		sizeof ( package->strings.header );
+	package->strings.header.header.StringInfoOffset =
+		sizeof ( package->strings.header );
+	package->strings.header.header.LanguageName = language_id;
+	strcpy ( package->strings.header.header.Language, language );
+	memcpy ( package->strings.data, ifr->strings,
+		 sizeof ( package->strings.data ) );
+	package->strings.end.BlockType = EFI_HII_SIBT_END;
+	package->end.Type = EFI_HII_PACKAGE_END;
+	package->end.Length = sizeof ( package->end );
+
+	return &package->header;
+}
+
diff --git a/roms/ipxe/src/interface/efi/efi_init.c b/roms/ipxe/src/interface/efi/efi_init.c
index 6c7b4955f6b2056f97822a627da9..48cac538f4f7990223deffb5f691 100644
--- a/roms/ipxe/src/interface/efi/efi_init.c
+++ b/roms/ipxe/src/interface/efi/efi_init.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -120,13 +121,14 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
 
 	/* Look up used protocols */
 	for_each_table_entry ( prot, EFI_PROTOCOLS ) {
-		if ( ( efirc = bs->LocateProtocol ( &prot->u.guid, NULL,
+		if ( ( efirc = bs->LocateProtocol ( &prot->guid, NULL,
 						    prot->protocol ) ) == 0 ) {
 			DBGC ( systab, "EFI protocol %s is at %p\n",
-			       uuid_ntoa ( &prot->u.uuid ), *(prot->protocol));
+			       efi_guid_ntoa ( &prot->guid ),
+			       *(prot->protocol) );
 		} else {
 			DBGC ( systab, "EFI does not provide protocol %s\n",
-			       uuid_ntoa ( &prot->u.uuid ) );
+			       efi_guid_ntoa ( &prot->guid ) );
 			/* All protocols are required */
 			return efirc;
 		}
@@ -134,12 +136,12 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
 
 	/* Look up used configuration tables */
 	for_each_table_entry ( tab, EFI_CONFIG_TABLES ) {
-		if ( ( *(tab->table) = efi_find_table ( &tab->u.guid ) ) ) {
+		if ( ( *(tab->table) = efi_find_table ( &tab->guid ) ) ) {
 			DBGC ( systab, "EFI configuration table %s is at %p\n",
-			       uuid_ntoa ( &tab->u.uuid ), *(tab->table) );
+			       efi_guid_ntoa ( &tab->guid ), *(tab->table) );
 		} else {
 			DBGC ( systab, "EFI does not provide configuration "
-			       "table %s\n", uuid_ntoa ( &tab->u.uuid ) );
+			       "table %s\n", efi_guid_ntoa ( &tab->guid ) );
 			if ( tab->required )
 				return EFI_NOT_AVAILABLE_YET;
 		}
diff --git a/roms/ipxe/src/interface/efi/efi_io.c b/roms/ipxe/src/interface/efi/efi_io.c
index 9a9aad31c5acae7f2f2a8a6e329d..a620d6e4344ba09f831c3d0dc863 100644
--- a/roms/ipxe/src/interface/efi/efi_io.c
+++ b/roms/ipxe/src/interface/efi/efi_io.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/interface/efi/efi_pci.c b/roms/ipxe/src/interface/efi/efi_pci.c
index fa71e7d847502a0889aebec610e2..0288cf326d3088ecbc6cb35c8a97 100644
--- a/roms/ipxe/src/interface/efi/efi_pci.c
+++ b/roms/ipxe/src/interface/efi/efi_pci.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -216,17 +217,19 @@ struct efi_pci_device * efipci_create ( struct efi_driver *efidrv,
  */
 EFI_STATUS efipci_enable ( struct efi_pci_device *efipci ) {
 	EFI_PCI_IO_PROTOCOL *pci_io = efipci->pci_io;
-	EFI_STATUS efirc;
 
-	/* Enable device */
-	if ( ( efirc = pci_io->Attributes ( pci_io,
-					    EfiPciIoAttributeOperationSet,
-					    EFI_PCI_DEVICE_ENABLE,
-					    NULL ) ) != 0 ) {
-		DBGC ( efipci, "EFIPCI " PCI_FMT " could not be enabled: %s\n",
-		       PCI_ARGS ( &efipci->pci ), efi_strerror ( efirc ) );
-		return efirc;
-	}
+	/* Try to enable I/O cycles, memory cycles, and bus mastering.
+	 * Some platforms will 'helpfully' report errors if these bits
+	 * can't be enabled (for example, if the card doesn't actually
+	 * support I/O cycles).  Work around any such platforms by
+	 * enabling bits individually and simply ignoring any errors.
+	 */
+	pci_io->Attributes ( pci_io, EfiPciIoAttributeOperationEnable,
+			     EFI_PCI_IO_ATTRIBUTE_IO, NULL );
+	pci_io->Attributes ( pci_io, EfiPciIoAttributeOperationEnable,
+			     EFI_PCI_IO_ATTRIBUTE_MEMORY, NULL );
+	pci_io->Attributes ( pci_io, EfiPciIoAttributeOperationEnable,
+			     EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL );
 
 	return 0;
 }
diff --git a/roms/ipxe/src/interface/efi/efi_smbios.c b/roms/ipxe/src/interface/efi/efi_smbios.c
index 4b58d84667821fdaf4643edc6c79..304f95a56750905a81f231d5a383 100644
--- a/roms/ipxe/src/interface/efi/efi_smbios.c
+++ b/roms/ipxe/src/interface/efi/efi_smbios.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -54,6 +55,8 @@ static int efi_find_smbios ( struct smbios *smbios ) {
 	smbios->address = phys_to_user ( smbios_entry->smbios_address );
 	smbios->len = smbios_entry->smbios_len;
 	smbios->count = smbios_entry->smbios_count;
+	smbios->version =
+		SMBIOS_VERSION ( smbios_entry->major, smbios_entry->minor );
 	DBG ( "Found SMBIOS v%d.%d entry point at %p (%x+%zx)\n",
 	      smbios_entry->major, smbios_entry->minor, smbios_entry,
 	      smbios_entry->smbios_address, smbios->len );
diff --git a/roms/ipxe/src/interface/efi/efi_snp.c b/roms/ipxe/src/interface/efi/efi_snp.c
index f40bfff94bdf1172662197bb373b..95e39b7d954916a2c438d52255f3 100644
--- a/roms/ipxe/src/interface/efi/efi_snp.c
+++ b/roms/ipxe/src/interface/efi/efi_snp.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -31,65 +32,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/efi/efi_pci.h>
 #include <ipxe/efi/efi_driver.h>
 #include <ipxe/efi/efi_strings.h>
-#include <ipxe/efi/efi_hii.h>
-#include <ipxe/efi/Protocol/SimpleNetwork.h>
-#include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h>
-#include <ipxe/efi/Protocol/DevicePath.h>
-#include <ipxe/efi/Protocol/HiiConfigAccess.h>
-#include <ipxe/efi/Protocol/HiiDatabase.h>
+#include <ipxe/efi/efi_snp.h>
 #include <config/general.h>
-
-/** @file
- *
- * iPXE EFI SNP interface
- *
- */
-
-/** An SNP device */
-struct efi_snp_device {
-	/** List of SNP devices */
-	struct list_head list;
-	/** The underlying iPXE network device */
-	struct net_device *netdev;
-	/** The underlying EFI PCI device */
-	struct efi_pci_device *efipci;
-	/** EFI device handle */
-	EFI_HANDLE handle;
-	/** 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;
-	/** The network interface identifier */
-	EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii;
-	/** HII configuration access protocol */
-	EFI_HII_CONFIG_ACCESS_PROTOCOL hii;
-	/** HII package list */
-	EFI_HII_PACKAGE_LIST_HEADER *package_list;
-	/** HII handle */
-	EFI_HII_HANDLE hii_handle;
-	/** Device name */
-	wchar_t name[ sizeof ( ( ( struct net_device * ) NULL )->name ) ];
-	/** The device path
-	 *
-	 * This field is variable in size and must appear at the end
-	 * of the structure.
-	 */
-	EFI_DEVICE_PATH_PROTOCOL path;
-};
+#include <usr/autoboot.h>
 
 /** EFI simple network protocol GUID */
 static EFI_GUID efi_simple_network_protocol_guid
@@ -113,6 +58,14 @@ static EFI_GUID efi_nii31_protocol_guid = {
 	{ 0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 }
 };
 
+/** EFI component name protocol GUID */
+static EFI_GUID efi_component_name2_protocol_guid
+	= EFI_COMPONENT_NAME2_PROTOCOL_GUID;
+
+/** EFI load file protocol GUID */
+static EFI_GUID efi_load_file_protocol_guid
+	= EFI_LOAD_FILE_PROTOCOL_GUID;
+
 /** List of SNP devices */
 static LIST_HEAD ( efi_snp_devices );
 
@@ -535,7 +488,7 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
 		container_of ( snp, struct efi_snp_device, snp );
 	struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
 	struct io_buffer *iobuf;
-	size_t ll_headroom;
+	size_t payload_len;
 	int rc;
 	EFI_STATUS efirc;
 
@@ -588,20 +541,22 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
 	}
 
 	/* Allocate buffer */
-	ll_headroom = ( MAX_LL_HEADER_LEN - ll_header_len );
-	iobuf = alloc_iob ( ll_headroom + len );
+	payload_len = ( len - ll_protocol->ll_header_len );
+	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + ( ( payload_len > IOB_ZLEN ) ?
+						  payload_len : IOB_ZLEN ) );
 	if ( ! iobuf ) {
 		DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte "
 		       "buffer\n", snpdev, ( ( unsigned long ) len ) );
 		efirc = EFI_DEVICE_ERROR;
 		goto err_alloc_iob;
 	}
-	iob_reserve ( iobuf, ll_headroom );
+	iob_reserve ( iobuf, ( MAX_LL_HEADER_LEN -
+			       ll_protocol->ll_header_len ) );
 	memcpy ( iob_put ( iobuf, len ), data, len );
 
 	/* Create link-layer header, if specified */
 	if ( ll_header_len ) {
-		iob_pull ( iobuf, ll_header_len );
+		iob_pull ( iobuf, ll_protocol->ll_header_len );
 		if ( ( rc = ll_protocol->push ( snpdev->netdev,
 						iobuf, ll_dest, ll_src,
 						htons ( *net_proto ) )) != 0 ){
@@ -658,6 +613,7 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
 	const void *iob_ll_dest;
 	const void *iob_ll_src;
 	uint16_t iob_net_proto;
+	unsigned int iob_flags;
 	int rc;
 	EFI_STATUS efirc;
 
@@ -682,7 +638,8 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
 
 	/* Attempt to decode link-layer header */
 	if ( ( rc = ll_protocol->pull ( snpdev->netdev, iobuf, &iob_ll_dest,
-					&iob_ll_src, &iob_net_proto ) ) != 0 ){
+					&iob_ll_src, &iob_net_proto,
+					&iob_flags ) ) != 0 ) {
 		DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n",
 		       snpdev, strerror ( rc ) );
 		efirc = RC_TO_EFIRC ( rc );
@@ -756,328 +713,93 @@ static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = {
 
 /******************************************************************************
  *
- * Human Interface Infrastructure
+ * Component name protocol
  *
  ******************************************************************************
  */
 
-/** EFI configuration access protocol GUID */
-static EFI_GUID efi_hii_config_access_protocol_guid
-	= EFI_HII_CONFIG_ACCESS_PROTOCOL_GUID;
-
-/** EFI HII database protocol */
-static EFI_HII_DATABASE_PROTOCOL *efihii;
-EFI_REQUIRE_PROTOCOL ( EFI_HII_DATABASE_PROTOCOL, &efihii );
-
-/** Local GUID used for our EFI SNP formset */
-#define EFI_SNP_FORMSET_GUID						\
-	{ 0xc4f84019, 0x6dfd, 0x4a27,					\
-	  { 0x9b, 0x94, 0xb7, 0x2e, 0x1f, 0xbc, 0xad, 0xca } }
-
-/** Form identifiers used for our EFI SNP HII */
-enum efi_snp_hii_form_id {
-	EFI_SNP_FORM = 0x0001,		/**< The only form */
-};
-
-/** String identifiers used for our EFI SNP HII */
-enum efi_snp_hii_string_id {
-	/* Language name */
-	EFI_SNP_LANGUAGE_NAME = 0x0001,
-	/* Formset */
-	EFI_SNP_FORMSET_TITLE, EFI_SNP_FORMSET_HELP,
-	/* Product name */
-	EFI_SNP_PRODUCT_PROMPT, EFI_SNP_PRODUCT_HELP, EFI_SNP_PRODUCT_TEXT,
-	/* Version */
-	EFI_SNP_VERSION_PROMPT, EFI_SNP_VERSION_HELP, EFI_SNP_VERSION_TEXT,
-	/* Driver */
-	EFI_SNP_DRIVER_PROMPT, EFI_SNP_DRIVER_HELP, EFI_SNP_DRIVER_TEXT,
-	/* Device */
-	EFI_SNP_DEVICE_PROMPT, EFI_SNP_DEVICE_HELP, EFI_SNP_DEVICE_TEXT,
-	/* End of list */
-	EFI_SNP_MAX_STRING_ID
-};
-
-/** EFI SNP formset */
-struct efi_snp_formset {
-	EFI_HII_PACKAGE_HEADER Header;
-	EFI_IFR_FORM_SET_TYPE(1) FormSet;
-	EFI_IFR_GUID_CLASS Class;
-	EFI_IFR_GUID_SUBCLASS SubClass;
-	EFI_IFR_FORM Form;
-	EFI_IFR_TEXT ProductText;
-	EFI_IFR_TEXT VersionText;
-	EFI_IFR_TEXT DriverText;
-	EFI_IFR_TEXT DeviceText;
-	EFI_IFR_END EndForm;
-	EFI_IFR_END EndFormSet;
-} __attribute__ (( packed )) efi_snp_formset = {
-	.Header = {
-		.Length = sizeof ( efi_snp_formset ),
-		.Type = EFI_HII_PACKAGE_FORMS,
-	},
-	.FormSet = EFI_IFR_FORM_SET ( EFI_SNP_FORMSET_GUID,
-				      EFI_SNP_FORMSET_TITLE,
-				      EFI_SNP_FORMSET_HELP,
-				      typeof ( efi_snp_formset.FormSet ),
-				      EFI_HII_PLATFORM_SETUP_FORMSET_GUID ),
-	.Class = EFI_IFR_GUID_CLASS ( EFI_NETWORK_DEVICE_CLASS ),
-	.SubClass = EFI_IFR_GUID_SUBCLASS ( 0x03 ),
-	.Form = EFI_IFR_FORM ( EFI_SNP_FORM, EFI_SNP_FORMSET_TITLE ),
-	.ProductText = EFI_IFR_TEXT ( EFI_SNP_PRODUCT_PROMPT,
-				      EFI_SNP_PRODUCT_HELP,
-				      EFI_SNP_PRODUCT_TEXT ),
-	.VersionText = EFI_IFR_TEXT ( EFI_SNP_VERSION_PROMPT,
-				      EFI_SNP_VERSION_HELP,
-				      EFI_SNP_VERSION_TEXT ),
-	.DriverText = EFI_IFR_TEXT ( EFI_SNP_DRIVER_PROMPT,
-				     EFI_SNP_DRIVER_HELP,
-				     EFI_SNP_DRIVER_TEXT ),
-	.DeviceText = EFI_IFR_TEXT ( EFI_SNP_DEVICE_PROMPT,
-				     EFI_SNP_DEVICE_HELP,
-				     EFI_SNP_DEVICE_TEXT ),
-	.EndForm = EFI_IFR_END(),
-	.EndFormSet = EFI_IFR_END(),
-};
-
-/**
- * Generate EFI SNP string
- *
- * @v wbuf		Buffer
- * @v swlen		Size of buffer (in wide characters)
- * @v snpdev		SNP device
- * @ret wlen		Length of string (in wide characters)
- */
-static int efi_snp_string ( wchar_t *wbuf, ssize_t swlen,
-			    enum efi_snp_hii_string_id id,
-			    struct efi_snp_device *snpdev ) {
-	struct net_device *netdev = snpdev->netdev;
-	struct device *dev = netdev->dev;
-
-	switch ( id ) {
-	case EFI_SNP_LANGUAGE_NAME:
-		return efi_ssnprintf ( wbuf, swlen, "English" );
-	case EFI_SNP_FORMSET_TITLE:
-		return efi_ssnprintf ( wbuf, swlen, "%s (%s)",
-				       ( PRODUCT_NAME[0] ?
-					 PRODUCT_NAME : PRODUCT_SHORT_NAME ),
-				       netdev_addr ( netdev ) );
-	case EFI_SNP_FORMSET_HELP:
-		return efi_ssnprintf ( wbuf, swlen,
-				       "Configure " PRODUCT_SHORT_NAME );
-	case EFI_SNP_PRODUCT_PROMPT:
-		return efi_ssnprintf ( wbuf, swlen, "Name" );
-	case EFI_SNP_PRODUCT_HELP:
-		return efi_ssnprintf ( wbuf, swlen, "Firmware product name" );
-	case EFI_SNP_PRODUCT_TEXT:
-		return efi_ssnprintf ( wbuf, swlen, "%s",
-				       ( PRODUCT_NAME[0] ?
-					 PRODUCT_NAME : PRODUCT_SHORT_NAME ) );
-	case EFI_SNP_VERSION_PROMPT:
-		return efi_ssnprintf ( wbuf, swlen, "Version" );
-	case EFI_SNP_VERSION_HELP:
-		return efi_ssnprintf ( wbuf, swlen, "Firmware version" );
-	case EFI_SNP_VERSION_TEXT:
-		return efi_ssnprintf ( wbuf, swlen, VERSION );
-	case EFI_SNP_DRIVER_PROMPT:
-		return efi_ssnprintf ( wbuf, swlen, "Driver" );
-	case EFI_SNP_DRIVER_HELP:
-		return efi_ssnprintf ( wbuf, swlen, "Firmware driver" );
-	case EFI_SNP_DRIVER_TEXT:
-		return efi_ssnprintf ( wbuf, swlen, "%s", dev->driver_name );
-	case EFI_SNP_DEVICE_PROMPT:
-		return efi_ssnprintf ( wbuf, swlen, "Device" );
-	case EFI_SNP_DEVICE_HELP:
-		return efi_ssnprintf ( wbuf, swlen, "Hardware device" );
-	case EFI_SNP_DEVICE_TEXT:
-		return efi_ssnprintf ( wbuf, swlen, "%s", dev->name );
-	default:
-		assert ( 0 );
-		return 0;
-	}
-}
-
 /**
- * Generate EFI SNP string package
+ * Look up driver name
  *
- * @v strings		String package header buffer
- * @v max_len		Buffer length
- * @v snpdev		SNP device
- * @ret len		Length of string package
- */
-static int efi_snp_strings ( EFI_HII_STRING_PACKAGE_HDR *strings,
-			     size_t max_len, struct efi_snp_device *snpdev ) {
-	static const char language[] = "en-us";
-	void *buf = strings;
-	ssize_t remaining = max_len;
-	size_t hdrsize;
-	EFI_HII_SIBT_STRING_UCS2_BLOCK *string;
-	ssize_t wremaining;
-	size_t string_wlen;
-	unsigned int id;
-	EFI_HII_STRING_BLOCK *end;
-	size_t len;
-
-	/* Calculate header size */
-	hdrsize = ( offsetof ( typeof ( *strings ), Language ) +
-		    sizeof ( language ) );
-	buf += hdrsize;
-	remaining -= hdrsize;
-
-	/* Fill in strings */
-	for ( id = 1 ; id < EFI_SNP_MAX_STRING_ID ; id++ ) {
-		string = buf;
-		if ( remaining >= ( ( ssize_t ) sizeof ( string->Header ) ) )
-			string->Header.BlockType = EFI_HII_SIBT_STRING_UCS2;
-		buf += offsetof ( typeof ( *string ), StringText );
-		remaining -= offsetof ( typeof ( *string ), StringText );
-		wremaining = ( remaining /
-			       ( ( ssize_t ) sizeof ( string->StringText[0] )));
-		assert ( ! ( ( remaining <= 0 ) && ( wremaining > 0 ) ) );
-		string_wlen = efi_snp_string ( string->StringText, wremaining,
-					       id, snpdev );
-		buf += ( ( string_wlen + 1 /* wNUL */ ) *
-			 sizeof ( string->StringText[0] ) );
-		remaining -= ( ( string_wlen + 1 /* wNUL */ ) *
-			       sizeof ( string->StringText[0] ) );
-	}
-
-	/* Fill in end marker */
-	end = buf;
-	if ( remaining >= ( ( ssize_t ) sizeof ( *end ) ) )
-		end->BlockType = EFI_HII_SIBT_END;
-	buf += sizeof ( *end );
-	remaining -= sizeof ( *end );
-
-	/* Calculate overall length */
-	len = ( max_len - remaining );
-
-	/* Fill in string package header */
-	if ( strings ) {
-		memset ( strings, 0, sizeof ( *strings ) );
-		strings->Header.Length = len;
-		strings->Header.Type = EFI_HII_PACKAGE_STRINGS;
-		strings->HdrSize = hdrsize;
-		strings->StringInfoOffset = hdrsize;
-		strings->LanguageName = EFI_SNP_LANGUAGE_NAME;
-		memcpy ( strings->Language, language, sizeof ( language ) );
-	}
-
-	return len;
-}
-
-/**
- * Generate EFI SNP package list
- *
- * @v snpdev		SNP device
- * @ret package_list	Package list, or NULL on error
- *
- * The package list is allocated using malloc(), and must eventually
- * be freed by the caller.
- */
-static EFI_HII_PACKAGE_LIST_HEADER *
-efi_snp_package_list ( struct efi_snp_device *snpdev ) {
-	size_t strings_len = efi_snp_strings ( NULL, 0, snpdev );
-	struct {
-		EFI_HII_PACKAGE_LIST_HEADER header;
-		struct efi_snp_formset formset;
-		union {
-			EFI_HII_STRING_PACKAGE_HDR strings;
-			uint8_t pad[strings_len];
-		} __attribute__ (( packed )) strings;
-		EFI_HII_PACKAGE_HEADER end;
-	} __attribute__ (( packed )) *package_list;
-
-	/* Allocate package list */
-	package_list = zalloc ( sizeof ( *package_list ) );
-	if ( ! package_list )
-		return NULL;
-
-	/* Populate package list */
-	memcpy ( &package_list->header.PackageListGuid,
-		 &efi_snp_formset.FormSet.FormSet.Guid,
-		 sizeof ( package_list->header.PackageListGuid ) );
-	package_list->header.PackageLength = sizeof ( *package_list );
-	memcpy ( &package_list->formset, &efi_snp_formset,
-		 sizeof ( package_list->formset ) );
-	efi_snp_strings ( &package_list->strings.strings,
-			  sizeof ( package_list->strings ), snpdev );
-	package_list->end.Length = sizeof ( package_list->end );
-	package_list->end.Type = EFI_HII_PACKAGE_END;
-
-	return &package_list->header;
-}
-
-/**
- * Fetch configuration
- *
- * @v hii		HII configuration access protocol
- * @v request		Configuration to fetch
- * @ret progress	Progress made through configuration to fetch
- * @ret results		Query results
+ * @v name2		Component name protocol
+ * @v language		Language to use
+ * @v driver_name	Driver name to fill in
  * @ret efirc		EFI status code
  */
 static EFI_STATUS EFIAPI
-efi_snp_hii_extract_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
-			     EFI_STRING request, EFI_STRING *progress,
-			     EFI_STRING *results __unused ) {
+efi_snp_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *name2,
+			  CHAR8 *language __unused, CHAR16 **driver_name ) {
 	struct efi_snp_device *snpdev =
-		container_of ( hii, struct efi_snp_device, hii );
-
-	DBGC ( snpdev, "SNPDEV %p ExtractConfig\n", snpdev );
+		container_of ( name2, struct efi_snp_device, name2 );
 
-	*progress = request;
-	return EFI_INVALID_PARAMETER;
+	*driver_name = snpdev->driver_name;
+	return 0;
 }
 
 /**
- * Store configuration
+ * Look up controller name
  *
- * @v hii		HII configuration access protocol
- * @v config		Configuration to store
- * @ret progress	Progress made through configuration to store
+ * @v name2     		Component name protocol
+ * @v device		Device
+ * @v child		Child device, or NULL
+ * @v language		Language to use
+ * @v driver_name	Device name to fill in
  * @ret efirc		EFI status code
  */
 static EFI_STATUS EFIAPI
-efi_snp_hii_route_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
-			   EFI_STRING config, EFI_STRING *progress ) {
+efi_snp_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *name2,
+			      EFI_HANDLE device __unused,
+			      EFI_HANDLE child __unused,
+			      CHAR8 *language __unused,
+			      CHAR16 **controller_name ) {
 	struct efi_snp_device *snpdev =
-		container_of ( hii, struct efi_snp_device, hii );
-
-	DBGC ( snpdev, "SNPDEV %p RouteConfig\n", snpdev );
+		container_of ( name2, struct efi_snp_device, name2 );
 
-	*progress = config;
-	return EFI_INVALID_PARAMETER;
+	*controller_name = snpdev->controller_name;
+	return 0;
 }
 
+/******************************************************************************
+ *
+ * Load file protocol
+ *
+ ******************************************************************************
+ */
+
 /**
- * Handle form actions
+ * Load file
  *
- * @v hii		HII configuration access protocol
- * @v action		Form browser action
- * @v question_id	Question ID
- * @v type		Type of value
- * @v value		Value
- * @ret action_request	Action requested by driver
+ * @v loadfile		Load file protocol
+ * @v path		File path
+ * @v booting		Loading as part of a boot attempt
  * @ret efirc		EFI status code
  */
 static EFI_STATUS EFIAPI
-efi_snp_hii_callback ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
-		       EFI_BROWSER_ACTION action __unused,
-		       EFI_QUESTION_ID question_id __unused,
-		       UINT8 type __unused, EFI_IFR_TYPE_VALUE *value __unused,
-		       EFI_BROWSER_ACTION_REQUEST *action_request __unused ) {
+efi_snp_load_file ( EFI_LOAD_FILE_PROTOCOL *load_file,
+		    EFI_DEVICE_PATH_PROTOCOL *path __unused,
+		    BOOLEAN booting, UINTN *len __unused,
+		    VOID *data __unused ) {
 	struct efi_snp_device *snpdev =
-		container_of ( hii, struct efi_snp_device, hii );
+		container_of ( load_file, struct efi_snp_device, load_file );
+	struct net_device *netdev = snpdev->netdev;
 
-	DBGC ( snpdev, "SNPDEV %p Callback\n", snpdev );
-	return EFI_UNSUPPORTED;
+	/* Fail unless this is a boot attempt */
+	if ( ! booting ) {
+		DBGC ( snpdev, "SNPDEV %p cannot load non-boot file\n",
+		       snpdev );
+		return EFI_UNSUPPORTED;
+	}
+
+	/* Boot from network device */
+	ipxe ( netdev );
+
+	/* Assume boot process was aborted */
+	return EFI_ABORTED;
 }
 
-/** HII configuration access protocol */
-static EFI_HII_CONFIG_ACCESS_PROTOCOL efi_snp_device_hii = {
-	.ExtractConfig	= efi_snp_hii_extract_config,
-	.RouteConfig	= efi_snp_hii_route_config,
-	.Callback	= efi_snp_hii_callback,
+/** Load file protocol */
+static EFI_LOAD_FILE_PROTOCOL efi_snp_load_file_protocol = {
+	.LoadFile	= efi_snp_load_file,
 };
 
 /******************************************************************************
@@ -1173,8 +895,23 @@ static int efi_snp_probe ( struct net_device *netdev ) {
 	strncpy ( snpdev->nii.StringId, "iPXE",
 		  sizeof ( snpdev->nii.StringId ) );
 
-	/* Populate the HII configuration access structure */
-	memcpy ( &snpdev->hii, &efi_snp_device_hii, sizeof ( snpdev->hii ) );
+	/* Populate the component name structure */
+	efi_snprintf ( snpdev->driver_name,
+		       ( sizeof ( snpdev->driver_name ) /
+			 sizeof ( snpdev->driver_name[0] ) ),
+		       PRODUCT_SHORT_NAME " %s", netdev->dev->driver_name );
+	efi_snprintf ( snpdev->controller_name,
+		       ( sizeof ( snpdev->controller_name ) /
+			 sizeof ( snpdev->controller_name[0] ) ),
+		       PRODUCT_SHORT_NAME " %s (%s)",
+		       netdev->name, netdev_addr ( netdev ) );
+	snpdev->name2.GetDriverName = efi_snp_get_driver_name;
+	snpdev->name2.GetControllerName = efi_snp_get_controller_name;
+	snpdev->name2.SupportedLanguages = "en";
+
+	/* Populate the load file protocol structure */
+	memcpy ( &snpdev->load_file, &efi_snp_load_file_protocol,
+		 sizeof ( snpdev->load_file ) );
 
 	/* Populate the device name */
 	efi_snprintf ( snpdev->name, ( sizeof ( snpdev->name ) /
@@ -1204,7 +941,8 @@ static int efi_snp_probe ( struct net_device *netdev ) {
 			&efi_device_path_protocol_guid, &snpdev->path,
 			&efi_nii_protocol_guid, &snpdev->nii,
 			&efi_nii31_protocol_guid, &snpdev->nii,
-			&efi_hii_config_access_protocol_guid, &snpdev->hii,
+			&efi_component_name2_protocol_guid, &snpdev->name2,
+			&efi_load_file_protocol_guid, &snpdev->load_file,
 			NULL ) ) != 0 ) {
 		DBGC ( snpdev, "SNPDEV %p could not install protocols: "
 		       "%s\n", snpdev, efi_strerror ( efirc ) );
@@ -1221,23 +959,11 @@ static int efi_snp_probe ( struct net_device *netdev ) {
 		goto err_efipci_child_add;
 	}
 
-	/* Create HII package list */
-	snpdev->package_list = efi_snp_package_list ( snpdev );
-	if ( ! snpdev->package_list ) {
-		DBGC ( snpdev, "SNPDEV %p could not create HII package list\n",
-		       snpdev );
-		rc = -ENOMEM;
-		goto err_create_hii;
-	}
-
-	/* Add HII packages */
-	if ( ( efirc = efihii->NewPackageList ( efihii, snpdev->package_list,
-						snpdev->handle,
-						&snpdev->hii_handle ) ) != 0 ) {
-		DBGC ( snpdev, "SNPDEV %p could not add HII packages: %s\n",
-		       snpdev, efi_strerror ( efirc ) );
-		rc = EFIRC_TO_RC ( efirc );
-		goto err_register_hii;
+	/* Install HII */
+	if ( ( rc = efi_snp_hii_install ( snpdev ) ) != 0 ) {
+		DBGC ( snpdev, "SNPDEV %p could not install HII: %s\n",
+		       snpdev, strerror ( rc ) );
+		goto err_hii_install;
 	}
 
 	/* Add to list of SNP devices */
@@ -1247,10 +973,8 @@ static int efi_snp_probe ( struct net_device *netdev ) {
 	       snpdev, netdev->name, snpdev->handle );
 	return 0;
 
-	efihii->RemovePackageList ( efihii, snpdev->hii_handle );
- err_register_hii:
-	free ( snpdev->package_list );
- err_create_hii:
+	efi_snp_hii_uninstall ( snpdev );
+ err_hii_install:
 	efipci_child_del ( efipci, snpdev->handle );
  err_efipci_child_add:
 	bs->UninstallMultipleProtocolInterfaces (
@@ -1259,7 +983,8 @@ static int efi_snp_probe ( struct net_device *netdev ) {
 			&efi_device_path_protocol_guid, &snpdev->path,
 			&efi_nii_protocol_guid, &snpdev->nii,
 			&efi_nii31_protocol_guid, &snpdev->nii,
-			&efi_hii_config_access_protocol_guid, &snpdev->hii,
+			&efi_component_name2_protocol_guid, &snpdev->name2,
+			&efi_load_file_protocol_guid, &snpdev->load_file,
 			NULL );
  err_install_protocol_interface:
 	bs->CloseEvent ( snpdev->snp.WaitForPacket );
@@ -1277,8 +1002,21 @@ static int efi_snp_probe ( struct net_device *netdev ) {
  *
  * @v netdev		Network device
  */
-static void efi_snp_notify ( struct net_device *netdev __unused ) {
-	/* Nothing to do */
+static void efi_snp_notify ( struct net_device *netdev ) {
+	struct efi_snp_device *snpdev;
+
+	/* Locate SNP device */
+	snpdev = efi_snp_demux ( netdev );
+	if ( ! snpdev ) {
+		DBG ( "SNP skipping non-SNP device %s\n", netdev->name );
+		return;
+	}
+
+	/* Update link state */
+	snpdev->mode.MediaPresent =
+		( netdev_link_ok ( netdev ) ? TRUE : FALSE );
+	DBGC ( snpdev, "SNPDEV %p link is %s\n", snpdev,
+	       ( snpdev->mode.MediaPresent ? "up" : "down" ) );
 }
 
 /**
@@ -1298,8 +1036,7 @@ static void efi_snp_remove ( struct net_device *netdev ) {
 	}
 
 	/* Uninstall the SNP */
-	efihii->RemovePackageList ( efihii, snpdev->hii_handle );
-	free ( snpdev->package_list );
+	efi_snp_hii_uninstall ( snpdev );
 	efipci_child_del ( snpdev->efipci, snpdev->handle );
 	list_del ( &snpdev->list );
 	bs->UninstallMultipleProtocolInterfaces (
@@ -1308,7 +1045,8 @@ static void efi_snp_remove ( struct net_device *netdev ) {
 			&efi_device_path_protocol_guid, &snpdev->path,
 			&efi_nii_protocol_guid, &snpdev->nii,
 			&efi_nii31_protocol_guid, &snpdev->nii,
-			&efi_hii_config_access_protocol_guid, &snpdev->hii,
+			&efi_component_name2_protocol_guid, &snpdev->name2,
+			&efi_load_file_protocol_guid, &snpdev->load_file,
 			NULL );
 	bs->CloseEvent ( snpdev->snp.WaitForPacket );
 	netdev_put ( snpdev->netdev );
@@ -1322,3 +1060,18 @@ struct net_driver efi_snp_driver __net_driver = {
 	.notify = efi_snp_notify,
 	.remove = efi_snp_remove,
 };
+
+/**
+ * Get most recently opened SNP device
+ *
+ * @ret snpdev		Most recently opened SNP device, or NULL
+ */
+struct efi_snp_device * last_opened_snpdev ( void ) {
+	struct net_device *netdev;
+
+	netdev = last_opened_netdev();
+	if ( ! netdev )
+		return NULL;
+
+	return efi_snp_demux ( netdev );
+}
diff --git a/roms/ipxe/src/interface/efi/efi_snp_hii.c b/roms/ipxe/src/interface/efi/efi_snp_hii.c
new file mode 100644
index 0000000000000000000000000000000000000000..3a1193a3855f4a6c128d8f5bad18afd18baaa9ee
--- /dev/null
+++ b/roms/ipxe/src/interface/efi/efi_snp_hii.c
@@ -0,0 +1,707 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * EFI SNP HII protocol
+ *
+ * The HII protocols are some of the less-well designed parts of the
+ * entire EFI specification.  This is a significant accomplishment.
+ *
+ * The face-slappingly ludicrous query string syntax seems to be
+ * motivated by the desire to allow a caller to query multiple drivers
+ * simultaneously via the single-instance HII_CONFIG_ROUTING_PROTOCOL,
+ * which is supposed to pass relevant subsets of the query string to
+ * the relevant drivers.
+ *
+ * Nobody uses the HII_CONFIG_ROUTING_PROTOCOL.  Not even the EFI
+ * setup browser uses the HII_CONFIG_ROUTING_PROTOCOL.  To the best of
+ * my knowledge, there has only ever been one implementation of the
+ * HII_CONFIG_ROUTING_PROTOCOL (as part of EDK2), and it just doesn't
+ * work.  It's so badly broken that I can't even figure out what the
+ * code is _trying_ to do.
+ *
+ * Fundamentally, the problem seems to be that Javascript programmers
+ * should not be allowed to design APIs for C code.
+ */
+
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <errno.h>
+#include <ipxe/settings.h>
+#include <ipxe/nvo.h>
+#include <ipxe/device.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/version.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_hii.h>
+#include <ipxe/efi/efi_snp.h>
+#include <ipxe/efi/efi_strings.h>
+#include <config/general.h>
+
+/** EFI configuration access protocol GUID */
+static EFI_GUID efi_hii_config_access_protocol_guid
+	= EFI_HII_CONFIG_ACCESS_PROTOCOL_GUID;
+
+/** EFI platform setup formset GUID */
+static EFI_GUID efi_hii_platform_setup_formset_guid
+	= EFI_HII_PLATFORM_SETUP_FORMSET_GUID;
+
+/** EFI IBM UCM compliant formset GUID */
+static EFI_GUID efi_hii_ibm_ucm_compliant_formset_guid
+	= EFI_HII_IBM_UCM_COMPLIANT_FORMSET_GUID;
+
+/** EFI HII database protocol */
+static EFI_HII_DATABASE_PROTOCOL *efihii;
+EFI_REQUIRE_PROTOCOL ( EFI_HII_DATABASE_PROTOCOL, &efihii );
+
+/**
+ * Identify settings to be exposed via HII
+ *
+ * @v snpdev		SNP device
+ * @ret settings	Settings, or NULL
+ */
+static struct settings * efi_snp_hii_settings ( struct efi_snp_device *snpdev ){
+
+	return find_child_settings ( netdev_settings ( snpdev->netdev ),
+				     NVO_SETTINGS_NAME );
+}
+
+/**
+ * Check whether or not setting is applicable
+ *
+ * @v snpdev		SNP device
+ * @v setting		Setting
+ * @ret applies		Setting applies
+ */
+static int efi_snp_hii_setting_applies ( struct efi_snp_device *snpdev,
+					 struct setting *setting ) {
+
+	return nvo_applies ( efi_snp_hii_settings ( snpdev ), setting );
+}
+
+/**
+ * Generate a random GUID
+ *
+ * @v guid		GUID to fill in
+ */
+static void efi_snp_hii_random_guid ( EFI_GUID *guid ) {
+	uint8_t *byte = ( ( uint8_t * ) guid );
+	unsigned int i;
+
+	for ( i = 0 ; i < sizeof ( *guid ) ; i++ )
+		*(byte++) = random();
+}
+
+/**
+ * Generate EFI SNP questions
+ *
+ * @v snpdev		SNP device
+ * @v ifr		IFR builder
+ * @v varstore_id	Variable store identifier
+ */
+static void efi_snp_hii_questions ( struct efi_snp_device *snpdev,
+				    struct efi_ifr_builder *ifr,
+				    unsigned int varstore_id ) {
+	struct setting *setting;
+	unsigned int name_id;
+	unsigned int prompt_id;
+	unsigned int help_id;
+	unsigned int question_id;
+
+	/* Add all applicable settings */
+	for_each_table_entry ( setting, SETTINGS ) {
+		if ( ! efi_snp_hii_setting_applies ( snpdev, setting ) )
+			continue;
+		name_id = efi_ifr_string ( ifr, "%s", setting->name );
+		prompt_id = efi_ifr_string ( ifr, "%s", setting->description );
+		help_id = efi_ifr_string ( ifr, "http://ipxe.org/cfg/%s",
+					   setting->name );
+		question_id = setting->tag;
+		efi_ifr_string_op ( ifr, prompt_id, help_id,
+				    question_id, varstore_id, name_id,
+				    0, 0x00, 0xff, 0 );
+	}
+}
+
+/**
+ * Build HII package list for SNP device
+ *
+ * @v snpdev		SNP device
+ * @ret package		Package list, or NULL on error
+ */
+static EFI_HII_PACKAGE_LIST_HEADER *
+efi_snp_hii_package_list ( struct efi_snp_device *snpdev ) {
+	struct net_device *netdev = snpdev->netdev;
+	struct device *dev = netdev->dev;
+	struct efi_ifr_builder ifr;
+	EFI_HII_PACKAGE_LIST_HEADER *package;
+	const char *product_name;
+	EFI_GUID package_guid;
+	EFI_GUID formset_guid;
+	EFI_GUID varstore_guid;
+	unsigned int title_id;
+	unsigned int varstore_id;
+
+	/* Initialise IFR builder */
+	efi_ifr_init ( &ifr );
+
+	/* Determine product name */
+	product_name = ( PRODUCT_NAME[0] ? PRODUCT_NAME : PRODUCT_SHORT_NAME );
+
+	/* Generate GUIDs */
+	efi_snp_hii_random_guid ( &package_guid );
+	efi_snp_hii_random_guid ( &formset_guid );
+	efi_snp_hii_random_guid ( &varstore_guid );
+
+	/* Generate title string (used more than once) */
+	title_id = efi_ifr_string ( &ifr, "%s (%s)", product_name,
+				    netdev_addr ( netdev ) );
+
+	/* Generate opcodes */
+	efi_ifr_form_set_op ( &ifr, &formset_guid, title_id,
+			      efi_ifr_string ( &ifr,
+					       "Configure " PRODUCT_SHORT_NAME),
+			      &efi_hii_platform_setup_formset_guid,
+			      &efi_hii_ibm_ucm_compliant_formset_guid, NULL );
+	efi_ifr_guid_class_op ( &ifr, EFI_NETWORK_DEVICE_CLASS );
+	efi_ifr_guid_subclass_op ( &ifr, 0x03 );
+	varstore_id = efi_ifr_varstore_name_value_op ( &ifr, &varstore_guid );
+	efi_ifr_form_op ( &ifr, title_id );
+	efi_ifr_text_op ( &ifr,
+			  efi_ifr_string ( &ifr, "Name" ),
+			  efi_ifr_string ( &ifr, "Firmware product name" ),
+			  efi_ifr_string ( &ifr, "%s", product_name ) );
+	efi_ifr_text_op ( &ifr,
+			  efi_ifr_string ( &ifr, "Version" ),
+			  efi_ifr_string ( &ifr, "Firmware version" ),
+			  efi_ifr_string ( &ifr, "%s", product_version ) );
+	efi_ifr_text_op ( &ifr,
+			  efi_ifr_string ( &ifr, "Driver" ),
+			  efi_ifr_string ( &ifr, "Firmware driver" ),
+			  efi_ifr_string ( &ifr, "%s", dev->driver_name ) );
+	efi_ifr_text_op ( &ifr,
+			  efi_ifr_string ( &ifr, "Device" ),
+			  efi_ifr_string ( &ifr, "Hardware device" ),
+			  efi_ifr_string ( &ifr, "%s", dev->name ) );
+	efi_snp_hii_questions ( snpdev, &ifr, varstore_id );
+	efi_ifr_end_op ( &ifr );
+	efi_ifr_end_op ( &ifr );
+
+	/* Build package */
+	package = efi_ifr_package ( &ifr, &package_guid, "en-us",
+				    efi_ifr_string ( &ifr, "English" ) );
+	if ( ! package ) {
+		DBGC ( snpdev, "SNPDEV %p could not build IFR package\n",
+		       snpdev );
+		efi_ifr_free ( &ifr );
+		return NULL;
+	}
+
+	/* Free temporary storage */
+	efi_ifr_free ( &ifr );
+	return package;
+}
+
+/**
+ * Append response to result string
+ *
+ * @v snpdev		SNP device
+ * @v key		Key
+ * @v value		Value
+ * @v results		Result string
+ * @ret rc		Return status code
+ *
+ * The result string is allocated dynamically using
+ * BootServices::AllocatePool(), and the caller is responsible for
+ * eventually calling BootServices::FreePool().
+ */
+static int efi_snp_hii_append ( struct efi_snp_device *snpdev __unused,
+				const char *key, const char *value,
+				wchar_t **results ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	size_t len;
+	void *new;
+
+	/* Allocate new string */
+	len = ( ( *results ? ( wcslen ( *results ) + 1 /* "&" */ ) : 0 ) +
+		strlen ( key ) + 1 /* "=" */ + strlen ( value ) + 1 /* NUL */ );
+	bs->AllocatePool ( EfiBootServicesData, ( len * sizeof ( wchar_t ) ),
+			   &new );
+	if ( ! new )
+		return -ENOMEM;
+
+	/* Populate string */
+	efi_snprintf ( new, len, "%ls%s%s=%s", ( *results ? *results : L"" ),
+		       ( *results ? L"&" : L"" ), key, value );
+	bs->FreePool ( *results );
+	*results = new;
+
+	return 0;
+}
+
+/**
+ * Fetch HII setting
+ *
+ * @v snpdev		SNP device
+ * @v key		Key
+ * @v value		Value
+ * @v results		Result string
+ * @v have_setting	Flag indicating detection of a setting
+ * @ret rc		Return status code
+ */
+static int efi_snp_hii_fetch ( struct efi_snp_device *snpdev,
+			       const char *key, const char *value,
+			       wchar_t **results, int *have_setting ) {
+	struct settings *settings = efi_snp_hii_settings ( snpdev );
+	struct setting *setting;
+	int len;
+	char *buf;
+	char *encoded;
+	int i;
+	int rc;
+
+	/* Handle ConfigHdr components */
+	if ( ( strcasecmp ( key, "GUID" ) == 0 ) ||
+	     ( strcasecmp ( key, "NAME" ) == 0 ) ||
+	     ( strcasecmp ( key, "PATH" ) == 0 ) ) {
+		return efi_snp_hii_append ( snpdev, key, value, results );
+	}
+	if ( have_setting )
+		*have_setting = 1;
+
+	/* Do nothing more unless we have a settings block */
+	if ( ! settings ) {
+		rc = -ENOTSUP;
+		goto err_no_settings;
+	}
+
+	/* Identify setting */
+	setting = find_setting ( key );
+	if ( ! setting ) {
+		DBGC ( snpdev, "SNPDEV %p no such setting \"%s\"\n",
+		       snpdev, key );
+		rc = -ENODEV;
+		goto err_find_setting;
+	}
+
+	/* Encode value */
+	if ( setting_exists ( settings, setting ) ) {
+
+		/* Calculate formatted length */
+		len = fetchf_setting ( settings, setting, NULL, 0 );
+		if ( len < 0 ) {
+			rc = len;
+			DBGC ( snpdev, "SNPDEV %p could not fetch %s: %s\n",
+			       snpdev, setting->name, strerror ( rc ) );
+			goto err_fetchf_len;
+		}
+
+		/* Allocate buffer for formatted value and HII-encoded value */
+		buf = zalloc ( len + 1 /* NUL */ + ( len * 4 ) + 1 /* NUL */ );
+		if ( ! buf ) {
+			rc = -ENOMEM;
+			goto err_alloc;
+		}
+		encoded = ( buf + len + 1 /* NUL */ );
+
+		/* Format value */
+		fetchf_setting ( settings, setting, buf, ( len + 1 /* NUL */ ));
+		for ( i = 0 ; i < len ; i++ ) {
+			sprintf ( ( encoded + ( 4 * i ) ), "%04x",
+				  *( ( uint8_t * ) buf + i ) );
+		}
+
+	} else {
+
+		/* Non-existent or inapplicable setting */
+		buf = NULL;
+		encoded = "";
+	}
+
+	/* Append results */
+	if ( ( rc = efi_snp_hii_append ( snpdev, key, encoded,
+					 results ) ) != 0 ) {
+		goto err_append;
+	}
+
+	/* Success */
+	rc = 0;
+
+ err_append:
+	free ( buf );
+ err_alloc:
+ err_fetchf_len:
+ err_find_setting:
+ err_no_settings:
+	return rc;
+}
+
+/**
+ * Fetch HII setting
+ *
+ * @v snpdev		SNP device
+ * @v key		Key
+ * @v value		Value
+ * @v results		Result string (unused)
+ * @v have_setting	Flag indicating detection of a setting (unused)
+ * @ret rc		Return status code
+ */
+static int efi_snp_hii_store ( struct efi_snp_device *snpdev,
+			       const char *key, const char *value,
+			       wchar_t **results __unused,
+			       int *have_setting __unused ) {
+	struct settings *settings = efi_snp_hii_settings ( snpdev );
+	struct setting *setting;
+	char *buf;
+	char tmp[5];
+	char *endp;
+	int len;
+	int i;
+	int rc;
+
+	/* Handle ConfigHdr components */
+	if ( ( strcasecmp ( key, "GUID" ) == 0 ) ||
+	     ( strcasecmp ( key, "NAME" ) == 0 ) ||
+	     ( strcasecmp ( key, "PATH" ) == 0 ) ) {
+		/* Nothing to do */
+		return 0;
+	}
+
+	/* Do nothing more unless we have a settings block */
+	if ( ! settings ) {
+		rc = -ENOTSUP;
+		goto err_no_settings;
+	}
+
+	/* Identify setting */
+	setting = find_setting ( key );
+	if ( ! setting ) {
+		DBGC ( snpdev, "SNPDEV %p no such setting \"%s\"\n",
+		       snpdev, key );
+		rc = -ENODEV;
+		goto err_find_setting;
+	}
+
+	/* Allocate buffer */
+	len = ( strlen ( value ) / 4 );
+	buf = zalloc ( len + 1 /* NUL */ );
+	if ( ! buf ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+
+	/* Decode value */
+	tmp[4] = '\0';
+	for ( i = 0 ; i < len ; i++ ) {
+		memcpy ( tmp, ( value + ( i * 4 ) ), 4 );
+		buf[i] = strtoul ( tmp, &endp, 16 );
+		if ( endp != &tmp[4] ) {
+			DBGC ( snpdev, "SNPDEV %p invalid character %s\n",
+			       snpdev, tmp );
+			rc = -EINVAL;
+			goto err_inval;
+		}
+	}
+
+	/* Store value */
+	if ( ( rc = storef_setting ( settings, setting, buf ) ) != 0 ) {
+		DBGC ( snpdev, "SNPDEV %p could not store \"%s\" into %s: %s\n",
+		       snpdev, buf, setting->name, strerror ( rc ) );
+		goto err_storef;
+	}
+
+	/* Success */
+	rc = 0;
+
+ err_storef:
+ err_inval:
+	free ( buf );
+ err_alloc:
+ err_find_setting:
+ err_no_settings:
+	return rc;
+}
+
+/**
+ * Process portion of HII configuration string
+ *
+ * @v snpdev		SNP device
+ * @v string		HII configuration string
+ * @v progress		Progress through HII configuration string
+ * @v results		Results string
+ * @v have_setting	Flag indicating detection of a setting (unused)
+ * @v process		Function used to process key=value pairs
+ * @ret rc		Return status code
+ */
+static int efi_snp_hii_process ( struct efi_snp_device *snpdev,
+				 wchar_t *string, wchar_t **progress,
+				 wchar_t **results, int *have_setting,
+				 int ( * process ) ( struct efi_snp_device *,
+						     const char *key,
+						     const char *value,
+						     wchar_t **results,
+						     int *have_setting ) ) {
+	wchar_t *wkey = string;
+	wchar_t *wend = string;
+	wchar_t *wvalue = NULL;
+	size_t key_len;
+	size_t value_len;
+	void *temp;
+	char *key;
+	char *value;
+	int rc;
+
+	/* Locate key, value (if any), and end */
+	while ( *wend ) {
+		if ( *wend == L'&' )
+			break;
+		if ( *(wend++) == L'=' )
+			wvalue = wend;
+	}
+
+	/* Allocate memory for key and value */
+	key_len = ( ( wvalue ? ( wvalue - 1 ) : wend ) - wkey );
+	value_len = ( wvalue ? ( wend - wvalue ) : 0 );
+	temp = zalloc ( key_len + 1 /* NUL */ + value_len + 1 /* NUL */ );
+	if ( ! temp )
+		return -ENOMEM;
+	key = temp;
+	value = ( temp + key_len + 1 /* NUL */ );
+
+	/* Copy key and value */
+	while ( key_len-- )
+		key[key_len] = wkey[key_len];
+	while ( value_len-- )
+		value[value_len] = wvalue[value_len];
+
+	/* Process key and value */
+	if ( ( rc = process ( snpdev, key, value, results,
+			      have_setting ) ) != 0 ) {
+		goto err;
+	}
+
+	/* Update progress marker */
+	*progress = wend;
+
+ err:
+	/* Free temporary storage */
+	free ( temp );
+
+	return rc;
+}
+
+/**
+ * Fetch configuration
+ *
+ * @v hii		HII configuration access protocol
+ * @v request		Configuration to fetch
+ * @ret progress	Progress made through configuration to fetch
+ * @ret results		Query results
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_hii_extract_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
+			     EFI_STRING request, EFI_STRING *progress,
+			     EFI_STRING *results ) {
+	struct efi_snp_device *snpdev =
+		container_of ( hii, struct efi_snp_device, hii );
+	int have_setting = 0;
+	wchar_t *pos;
+	int rc;
+
+	DBGC ( snpdev, "SNPDEV %p ExtractConfig request \"%ls\"\n",
+	       snpdev, request );
+
+	/* Initialise results */
+	*results = NULL;
+
+	/* Process all request fragments */
+	for ( pos = *progress = request ; *progress && **progress ;
+	      pos = *progress + 1 ) {
+		if ( ( rc = efi_snp_hii_process ( snpdev, pos, progress,
+						  results, &have_setting,
+						  efi_snp_hii_fetch ) ) != 0 ) {
+			return RC_TO_EFIRC ( rc );
+		}
+	}
+
+	/* If we have no explicit request, return all settings */
+	if ( ! have_setting ) {
+		struct setting *setting;
+
+		for_each_table_entry ( setting, SETTINGS ) {
+			if ( ! efi_snp_hii_setting_applies ( snpdev, setting ) )
+				continue;
+			if ( ( rc = efi_snp_hii_fetch ( snpdev, setting->name,
+							NULL, results,
+							NULL ) ) != 0 ) {
+				return RC_TO_EFIRC ( rc );
+			}
+		}
+	}
+
+	DBGC ( snpdev, "SNPDEV %p ExtractConfig results \"%ls\"\n",
+	       snpdev, *results );
+	return 0;
+}
+
+/**
+ * Store configuration
+ *
+ * @v hii		HII configuration access protocol
+ * @v config		Configuration to store
+ * @ret progress	Progress made through configuration to store
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_hii_route_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
+			   EFI_STRING config, EFI_STRING *progress ) {
+	struct efi_snp_device *snpdev =
+		container_of ( hii, struct efi_snp_device, hii );
+	wchar_t *pos;
+	int rc;
+
+	DBGC ( snpdev, "SNPDEV %p RouteConfig \"%ls\"\n", snpdev, config );
+
+	/* Process all request fragments */
+	for ( pos = *progress = config ; *progress && **progress ;
+	      pos = *progress + 1 ) {
+		if ( ( rc = efi_snp_hii_process ( snpdev, pos, progress,
+						  NULL, NULL,
+						  efi_snp_hii_store ) ) != 0 ) {
+			return RC_TO_EFIRC ( rc );
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Handle form actions
+ *
+ * @v hii		HII configuration access protocol
+ * @v action		Form browser action
+ * @v question_id	Question ID
+ * @v type		Type of value
+ * @v value		Value
+ * @ret action_request	Action requested by driver
+ * @ret efirc		EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_hii_callback ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
+		       EFI_BROWSER_ACTION action __unused,
+		       EFI_QUESTION_ID question_id __unused,
+		       UINT8 type __unused, EFI_IFR_TYPE_VALUE *value __unused,
+		       EFI_BROWSER_ACTION_REQUEST *action_request __unused ) {
+	struct efi_snp_device *snpdev =
+		container_of ( hii, struct efi_snp_device, hii );
+
+	DBGC ( snpdev, "SNPDEV %p Callback\n", snpdev );
+	return EFI_UNSUPPORTED;
+}
+
+/** HII configuration access protocol */
+static EFI_HII_CONFIG_ACCESS_PROTOCOL efi_snp_device_hii = {
+	.ExtractConfig	= efi_snp_hii_extract_config,
+	.RouteConfig	= efi_snp_hii_route_config,
+	.Callback	= efi_snp_hii_callback,
+};
+
+/**
+ * Install HII protocol and packages for SNP device
+ *
+ * @v snpdev		SNP device
+ * @ret rc		Return status code
+ */
+int efi_snp_hii_install ( struct efi_snp_device *snpdev ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+	int efirc;
+	int rc;
+
+	/* Initialise HII protocol */
+	memcpy ( &snpdev->hii, &efi_snp_device_hii, sizeof ( snpdev->hii ) );
+
+	/* Create HII package list */
+	snpdev->package_list = efi_snp_hii_package_list ( snpdev );
+	if ( ! snpdev->package_list ) {
+		DBGC ( snpdev, "SNPDEV %p could not create HII package list\n",
+		       snpdev );
+		rc = -ENOMEM;
+		goto err_build_package_list;
+	}
+
+	/* Add HII packages */
+	if ( ( efirc = efihii->NewPackageList ( efihii, snpdev->package_list,
+						snpdev->handle,
+						&snpdev->hii_handle ) ) != 0 ) {
+		DBGC ( snpdev, "SNPDEV %p could not add HII packages: %s\n",
+		       snpdev, efi_strerror ( efirc ) );
+		rc = EFIRC_TO_RC ( efirc );
+		goto err_new_package_list;
+	}
+
+	/* Install HII protocol */
+	if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
+			 &snpdev->handle,
+			 &efi_hii_config_access_protocol_guid, &snpdev->hii,
+			 NULL ) ) != 0 ) {
+		DBGC ( snpdev, "SNPDEV %p could not install HII protocol: %s\n",
+		       snpdev, efi_strerror ( efirc ) );
+		rc = EFIRC_TO_RC ( efirc );
+		goto err_install_protocol;
+	}
+
+	return 0;
+
+	bs->UninstallMultipleProtocolInterfaces (
+			snpdev->handle,
+			&efi_hii_config_access_protocol_guid, &snpdev->hii,
+			NULL );
+ err_install_protocol:
+	efihii->RemovePackageList ( efihii, snpdev->hii_handle );
+ err_new_package_list:
+	free ( snpdev->package_list );
+	snpdev->package_list = NULL;
+ err_build_package_list:
+	return rc;
+}
+
+/**
+ * Uninstall HII protocol and package for SNP device
+ *
+ * @v snpdev		SNP device
+ */
+void efi_snp_hii_uninstall ( struct efi_snp_device *snpdev ) {
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+
+	bs->UninstallMultipleProtocolInterfaces (
+			snpdev->handle,
+			&efi_hii_config_access_protocol_guid, &snpdev->hii,
+			NULL );
+	efihii->RemovePackageList ( efihii, snpdev->hii_handle );
+	free ( snpdev->package_list );
+	snpdev->package_list = NULL;
+}
diff --git a/roms/ipxe/src/interface/efi/efi_strerror.c b/roms/ipxe/src/interface/efi/efi_strerror.c
index 430758f83b6e09b4c2de56ad0259..46bfbbb5be2427ae64b518ad944b 100644
--- a/roms/ipxe/src/interface/efi/efi_strerror.c
+++ b/roms/ipxe/src/interface/efi/efi_strerror.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/interface/efi/efi_strings.c b/roms/ipxe/src/interface/efi/efi_strings.c
index 0fbc45384b549fca49f5cef78fd5..751589b466692f7641386c53549d 100644
--- a/roms/ipxe/src/interface/efi/efi_strings.c
+++ b/roms/ipxe/src/interface/efi/efi_strings.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/interface/efi/efi_timer.c b/roms/ipxe/src/interface/efi/efi_timer.c
index 1f8ad15045143ddcd6238a5a0e53..b110cae29b8c31815dae0af2ab2a 100644
--- a/roms/ipxe/src/interface/efi/efi_timer.c
+++ b/roms/ipxe/src/interface/efi/efi_timer.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/interface/efi/efi_uaccess.c b/roms/ipxe/src/interface/efi/efi_uaccess.c
index d80ca7a7556cd4296d48892b9d00..8b429b9ee6dac4faf8e576c1f2ad 100644
--- a/roms/ipxe/src/interface/efi/efi_uaccess.c
+++ b/roms/ipxe/src/interface/efi/efi_uaccess.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/interface/efi/efi_umalloc.c b/roms/ipxe/src/interface/efi/efi_umalloc.c
index d1d689ea2fc91cfde68e59c0a410..b49949327531a30ddea3e970f2d0 100644
--- a/roms/ipxe/src/interface/efi/efi_umalloc.c
+++ b/roms/ipxe/src/interface/efi/efi_umalloc.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/interface/linux/linux_console.c b/roms/ipxe/src/interface/linux/linux_console.c
index aeb7c6618324bec49cbdd1ac6a4a..5105eaa9499cbd1c2c956f144561 100644
--- a/roms/ipxe/src/interface/linux/linux_console.c
+++ b/roms/ipxe/src/interface/linux/linux_console.c
@@ -33,6 +33,14 @@ FILE_LICENCE(GPL2_OR_LATER);
 #include <linux/termios.h>
 #include <asm/errno.h>
 
+#include <config/console.h>
+
+/* Set default console usage if applicable */
+#if ! ( defined ( CONSOLE_LINUX ) && CONSOLE_EXPLICIT ( CONSOLE_LINUX ) )
+#undef CONSOLE_LINUX
+#define CONSOLE_LINUX ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
+#endif
+
 static void linux_console_putchar(int c)
 {
 	/* write to stdout */
@@ -79,6 +87,7 @@ struct console_driver linux_console __console_driver = {
 	.putchar = linux_console_putchar,
 	.getchar = linux_console_getchar,
 	.iskey = linux_console_iskey,
+	.usage = CONSOLE_LINUX,
 };
 
 static int linux_tcgetattr(int fd, struct termios *termios_p)
diff --git a/roms/ipxe/src/interface/linux/linux_entropy.c b/roms/ipxe/src/interface/linux/linux_entropy.c
new file mode 100644
index 0000000000000000000000000000000000000000..4671a48da1d670c4b2a6402be09786ed46eb67b2
--- /dev/null
+++ b/roms/ipxe/src/interface/linux/linux_entropy.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Linux entropy source
+ *
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <linux_api.h>
+#include <ipxe/entropy.h>
+
+/** Entropy source filename */
+static const char entropy_filename[] = "/dev/random";
+
+/** Entropy source file handle */
+static int entropy_fd;
+
+/**
+ * Enable entropy gathering
+ *
+ * @ret rc		Return status code
+ */
+static int linux_entropy_enable ( void ) {
+
+	/* Open entropy source */
+	entropy_fd = linux_open ( entropy_filename, O_RDONLY );
+	if ( entropy_fd < 0 ) {
+		DBGC ( &entropy_fd, "ENTROPY could not open %s: %s\n",
+		       entropy_filename, linux_strerror ( linux_errno ) );
+		return entropy_fd;
+	}
+
+	return 0;
+}
+
+/**
+ * Disable entropy gathering
+ *
+ */
+static void linux_entropy_disable ( void ) {
+
+	/* Close entropy source */
+	linux_close ( entropy_fd );
+}
+
+/**
+ * Get noise sample
+ *
+ * @ret noise		Noise sample
+ * @ret rc		Return status code
+ */
+static int linux_get_noise ( noise_sample_t *noise ) {
+	uint8_t byte;
+	ssize_t len;
+
+	/* Read a single byte from entropy source */
+	len = linux_read ( entropy_fd, &byte, sizeof ( byte ) );
+	if ( len < 0 ) {
+		DBGC ( &entropy_fd, "ENTROPY could not read from %s: %s\n",
+		       entropy_filename, linux_strerror ( linux_errno ) );
+		return len;
+	}
+	if ( len == 0 ) {
+		DBGC ( &entropy_fd, "ENTROPY EOF on reading from %s: %s\n",
+		       entropy_filename, linux_strerror ( linux_errno ) );
+		return -EPIPE;
+	}
+	*noise = byte;
+
+	return 0;
+}
+
+PROVIDE_ENTROPY_INLINE ( linux, min_entropy_per_sample );
+PROVIDE_ENTROPY ( linux, entropy_enable, linux_entropy_enable );
+PROVIDE_ENTROPY ( linux, entropy_disable, linux_entropy_disable );
+PROVIDE_ENTROPY ( linux, get_noise, linux_get_noise );
diff --git a/roms/ipxe/src/interface/linux/linux_nap.c b/roms/ipxe/src/interface/linux/linux_nap.c
index 98642bad06c44b963fde01e4ca22..f1d3cd962f1dfc0d7da193a4a168 100644
--- a/roms/ipxe/src/interface/linux/linux_nap.c
+++ b/roms/ipxe/src/interface/linux/linux_nap.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE(GPL2_OR_LATER);
diff --git a/roms/ipxe/src/interface/linux/linux_time.c b/roms/ipxe/src/interface/linux/linux_time.c
new file mode 100644
index 0000000000000000000000000000000000000000..6d722aad064f80762cf46e878df6bfcf15746a9e
--- /dev/null
+++ b/roms/ipxe/src/interface/linux/linux_time.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Linux time source
+ *
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <linux_api.h>
+#include <ipxe/time.h>
+
+/**
+ * Get current time in seconds
+ *
+ * @ret time		Time, in seconds
+ */
+static time_t linux_now ( void ) {
+	struct timeval now;
+
+	linux_gettimeofday ( &now, NULL );
+	return now.tv_sec;
+}
+
+PROVIDE_TIME ( linux, time_now, linux_now );
diff --git a/roms/ipxe/src/interface/linux/linux_uaccess.c b/roms/ipxe/src/interface/linux/linux_uaccess.c
index d4e52d0936af67a015ccf0227b5a..5ab0b6b65903a667fa1c83c13c7f 100644
--- a/roms/ipxe/src/interface/linux/linux_uaccess.c
+++ b/roms/ipxe/src/interface/linux/linux_uaccess.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE(GPL2_OR_LATER);
diff --git a/roms/ipxe/src/interface/smbios/smbios.c b/roms/ipxe/src/interface/smbios/smbios.c
index b60e10f76abf8723e9b8084a25e9..2adaa53d98070f98fa3d3ae3ec8b 100644
--- a/roms/ipxe/src/interface/smbios/smbios.c
+++ b/roms/ipxe/src/interface/smbios/smbios.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -178,3 +179,20 @@ int read_smbios_string ( struct smbios_structure *structure,
 	DBG ( "SMBIOS string index %d not found\n", index );
 	return -ENOENT;
 }
+
+/**
+ * Get SMBIOS version
+ *
+ * @ret version		Version, or negative error
+ */
+int smbios_version ( void ) {
+	int rc;
+
+	/* Find SMBIOS */
+	if ( ( smbios.address == UNULL ) &&
+	     ( ( rc = find_smbios ( &smbios ) ) != 0 ) )
+		return rc;
+	assert ( smbios.address != UNULL );
+
+	return smbios.version;
+}
diff --git a/roms/ipxe/src/interface/smbios/smbios_settings.c b/roms/ipxe/src/interface/smbios/smbios_settings.c
index 92dc41272b831e6251e9eb6db788..663da96872c3d9c2e11cc17e267b 100644
--- a/roms/ipxe/src/interface/smbios/smbios_settings.c
+++ b/roms/ipxe/src/interface/smbios/smbios_settings.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -111,24 +112,52 @@ static int smbios_fetch ( struct settings *settings __unused,
 
 	{
 		uint8_t buf[structure.header.len];
+		const void *raw;
+		union uuid uuid;
 
 		/* Read SMBIOS structure */
 		if ( ( rc = read_smbios_structure ( &structure, buf,
 						    sizeof ( buf ) ) ) != 0 )
 			return rc;
 
+		/* A tag length of zero indicates a string */
 		if ( tag_len == 0 ) {
-			/* String */
-			return read_smbios_string ( &structure,
-						    buf[tag_offset],
-						    data, len );
-		} else {
-			/* Raw data */
-			if ( len > tag_len )
-				len = tag_len;
-			memcpy ( data, &buf[tag_offset], len );
-			return tag_len;
+			if ( ( rc = read_smbios_string ( &structure,
+							 buf[tag_offset],
+							 data, len ) ) < 0 ) {
+				return rc;
+			}
+			if ( ! setting->type )
+				setting->type = &setting_type_string;
+			return rc;
+		}
+
+		/* Mangle UUIDs if necessary.  iPXE treats UUIDs as
+		 * being in network byte order (big-endian).  SMBIOS
+		 * specification version 2.6 states that UUIDs are
+		 * stored with little-endian values in the first three
+		 * fields; earlier versions did not specify an
+		 * endianness.  dmidecode assumes that the byte order
+		 * is little-endian if and only if the SMBIOS version
+		 * is 2.6 or higher; we match this behaviour.
+		 */
+		raw = &buf[tag_offset];
+		if ( ( setting->type == &setting_type_uuid ) &&
+		     ( tag_len == sizeof ( uuid ) ) &&
+		     ( smbios_version() >= SMBIOS_VERSION ( 2, 6 ) ) ) {
+			DBG ( "SMBIOS detected mangled UUID\n" );
+			memcpy ( &uuid, &buf[tag_offset], sizeof ( uuid ) );
+			uuid_mangle ( &uuid );
+			raw = &uuid;
 		}
+
+		/* Return data */
+		if ( len > tag_len )
+			len = tag_len;
+		memcpy ( data, raw, len );
+		if ( ! setting->type )
+			setting->type = &setting_type_hex;
+		return tag_len;
 	}
 }
 
diff --git a/roms/ipxe/src/net/80211/net80211.c b/roms/ipxe/src/net/80211/net80211.c
index f5ab65f0420d6497d574dc79df67..2181fc4ac4a0ee8698b10473e9c5 100644
--- a/roms/ipxe/src/net/80211/net80211.c
+++ b/roms/ipxe/src/net/80211/net80211.c
@@ -15,7 +15,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -135,7 +136,8 @@ static int net80211_ll_push ( struct net_device *netdev,
 			      const void *ll_source, uint16_t net_proto );
 static int net80211_ll_pull ( struct net_device *netdev,
 			      struct io_buffer *iobuf, const void **ll_dest,
-			      const void **ll_source, uint16_t * net_proto );
+			      const void **ll_source, uint16_t * net_proto,
+			      unsigned int *flags );
 /** @} */
 
 /**
@@ -159,7 +161,7 @@ net80211_marshal_request_info ( struct net80211_device *dev,
  * @defgroup net80211_assoc_ll 802.11 association handling functions
  * @{
  */
-static void net80211_step_associate ( struct process *proc );
+static void net80211_step_associate ( struct net80211_device *dev );
 static void net80211_handle_auth ( struct net80211_device *dev,
 				   struct io_buffer *iob );
 static void net80211_handle_assoc_reply ( struct net80211_device *dev,
@@ -385,9 +387,6 @@ static struct net_device_operations net80211_netdev_ops = {
 
 /* ---------- 802.11 link-layer protocol ---------- */
 
-/** 802.11 broadcast MAC address */
-static u8 net80211_ll_broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
 /**
  * Determine whether a transmission rate uses ERP/OFDM
  *
@@ -529,6 +528,7 @@ static int net80211_ll_push ( struct net_device *netdev,
  * @ret ll_dest		Link-layer destination address
  * @ret ll_source	Link-layer source
  * @ret net_proto	Network-layer protocol, in network byte order
+ * @ret flags		Packet flags
  * @ret rc		Return status code
  *
  * This expects and removes both the 802.11 frame header and the 802.2
@@ -537,7 +537,7 @@ static int net80211_ll_push ( struct net_device *netdev,
 static int net80211_ll_pull ( struct net_device *netdev __unused,
 			      struct io_buffer *iobuf,
 			      const void **ll_dest, const void **ll_source,
-			      uint16_t * net_proto )
+			      uint16_t * net_proto, unsigned int *flags )
 {
 	struct ieee80211_frame *hdr = iobuf->data;
 	struct ieee80211_llc_snap_header *lhdr =
@@ -586,6 +586,10 @@ static int net80211_ll_pull ( struct net_device *netdev __unused,
 	*ll_dest = hdr->addr1;
 	*ll_source = hdr->addr3;
 	*net_proto = lhdr->ethertype;
+	*flags = ( ( is_multicast_ether_addr ( hdr->addr1 ) ?
+		     LL_MULTICAST : 0 ) |
+		   ( is_broadcast_ether_addr ( hdr->addr1 ) ?
+		     LL_BROADCAST : 0 ) );
 	return 0;
 }
 
@@ -729,6 +733,11 @@ int net80211_tx_mgmt ( struct net80211_device *dev, u16 fc, u8 dest[6],
 
 /* ---------- Driver API ---------- */
 
+/** 802.11 association process descriptor */
+static struct process_descriptor net80211_process_desc =
+	PROC_DESC ( struct net80211_device, proc_assoc,
+		    net80211_step_associate );
+
 /**
  * Allocate 802.11 device
  *
@@ -751,7 +760,7 @@ struct net80211_device * net80211_alloc ( size_t priv_size )
 		return NULL;
 
 	netdev->ll_protocol = &net80211_ll_protocol;
-	netdev->ll_broadcast = net80211_ll_broadcast;
+	netdev->ll_broadcast = eth_broadcast;
 	netdev->max_pkt_len = IEEE80211_MAX_DATA_LEN;
 	netdev_init ( netdev, &net80211_netdev_ops );
 
@@ -760,7 +769,7 @@ struct net80211_device * net80211_alloc ( size_t priv_size )
 	dev->priv = ( u8 * ) dev + sizeof ( *dev );
 	dev->op = &net80211_null_ops;
 
-	process_init_stopped ( &dev->proc_assoc, net80211_step_associate,
+	process_init_stopped ( &dev->proc_assoc, &net80211_process_desc,
 			       &netdev->refcnt );
 	INIT_LIST_HEAD ( &dev->mgmt_queue );
 	INIT_LIST_HEAD ( &dev->mgmt_info_queue );
@@ -1387,7 +1396,7 @@ int net80211_probe_step ( struct net80211_probe_ctx *ctx )
 
 			ctx->probe = iob;
 			rc = net80211_tx_mgmt ( dev, IEEE80211_STYPE_PROBE_REQ,
-						net80211_ll_broadcast,
+						eth_broadcast,
 						iob_disown ( siob ) );
 			if ( rc ) {
 				DBGC ( dev, "802.11 %p send probe failed: "
@@ -1630,12 +1639,10 @@ void net80211_free_wlanlist ( struct list_head *list )
 /**
  * Step 802.11 association process
  *
- * @v proc	Association process
+ * @v dev	802.11 device
  */
-static void net80211_step_associate ( struct process *proc )
+static void net80211_step_associate ( struct net80211_device *dev )
 {
-	struct net80211_device *dev =
-	    container_of ( proc, struct net80211_device, proc_assoc );
 	int rc = 0;
 	int status = dev->state & NET80211_STATUS_MASK;
 
@@ -1836,7 +1843,7 @@ static void net80211_step_associate ( struct process *proc )
 
 	dev->rctl = rc80211_init ( dev );
 
-	process_del ( proc );
+	process_del ( &dev->proc_assoc );
 
 	DBGC ( dev, "802.11 %p associated with %s (%s)\n", dev,
 	       dev->essid, eth_ntoa ( dev->bssid ) );
@@ -1861,7 +1868,7 @@ static void net80211_step_associate ( struct process *proc )
 	net80211_free_wlan ( dev->associating );
 	dev->associating = NULL;
 
-	process_del ( proc );
+	process_del ( &dev->proc_assoc );
 
 	DBGC ( dev, "802.11 %p association failed (state=%04x): "
 	       "%s\n", dev, dev->state, strerror ( dev->assoc_rc ) );
diff --git a/roms/ipxe/src/net/80211/rc80211.c b/roms/ipxe/src/net/80211/rc80211.c
index 56bbc8a06d532aa89cb7b058cbd0..eea3bc908f3eeaec098f8503cedf 100644
--- a/roms/ipxe/src/net/80211/rc80211.c
+++ b/roms/ipxe/src/net/80211/rc80211.c
@@ -15,7 +15,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/80211/sec80211.c b/roms/ipxe/src/net/80211/sec80211.c
index 82b1ce941e8b974438e138fad8fd..d159edbdfa225a7d3b8a9ce3b576 100644
--- a/roms/ipxe/src/net/80211/sec80211.c
+++ b/roms/ipxe/src/net/80211/sec80211.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/80211/wep.c b/roms/ipxe/src/net/80211/wep.c
index 3b1045525787844504992d2321dd..37b27f71a44fb38e1d926c86280e 100644
--- a/roms/ipxe/src/net/80211/wep.c
+++ b/roms/ipxe/src/net/80211/wep.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/80211/wpa.c b/roms/ipxe/src/net/80211/wpa.c
index 38ddb911ba6dbc3a94d9550287fc..e2c4945f9c674832b2e81c6cbb66 100644
--- a/roms/ipxe/src/net/80211/wpa.c
+++ b/roms/ipxe/src/net/80211/wpa.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -29,9 +30,11 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/hmac.h>
 #include <ipxe/list.h>
 #include <ipxe/ethernet.h>
+#include <ipxe/rbg.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <byteswap.h>
 
 /** @file
  *
@@ -514,7 +517,8 @@ static int wpa_handle_1_of_4 ( struct wpa_common_ctx *ctx,
 	ctx->state = WPA_WORKING;
 	memcpy ( ctx->Anonce, pkt->nonce, sizeof ( ctx->Anonce ) );
 	if ( ! ctx->have_Snonce ) {
-		get_random_bytes ( ctx->Snonce, sizeof ( ctx->Snonce ) );
+		rbg_generate ( NULL, 0, 0, ctx->Snonce,
+			       sizeof ( ctx->Snonce ) );
 		ctx->have_Snonce = 1;
 	}
 
diff --git a/roms/ipxe/src/net/80211/wpa_ccmp.c b/roms/ipxe/src/net/80211/wpa_ccmp.c
index 89bb36fd8a63b1f5bb232c723259..f98ebea26cbc79d2b8785367290d 100644
--- a/roms/ipxe/src/net/80211/wpa_ccmp.c
+++ b/roms/ipxe/src/net/80211/wpa_ccmp.c
@@ -13,11 +13,13 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
+#include <string.h>
 #include <ipxe/net80211.h>
 #include <ipxe/crypto.h>
 #include <ipxe/hmac.h>
diff --git a/roms/ipxe/src/net/80211/wpa_psk.c b/roms/ipxe/src/net/80211/wpa_psk.c
index 780738e794d0197ee2d8a2832f15..71190b139d293abfb67bf22f2533 100644
--- a/roms/ipxe/src/net/80211/wpa_psk.c
+++ b/roms/ipxe/src/net/80211/wpa_psk.c
@@ -13,11 +13,13 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
+#include <string.h>
 #include <ipxe/net80211.h>
 #include <ipxe/sha1.h>
 #include <ipxe/wpa.h>
diff --git a/roms/ipxe/src/net/80211/wpa_tkip.c b/roms/ipxe/src/net/80211/wpa_tkip.c
index 0a94df07e18760b2788abdb37d2d..fa3e0763b02fec3949b05c2eb9fe 100644
--- a/roms/ipxe/src/net/80211/wpa_tkip.c
+++ b/roms/ipxe/src/net/80211/wpa_tkip.c
@@ -13,11 +13,13 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
+#include <string.h>
 #include <ipxe/net80211.h>
 #include <ipxe/crypto.h>
 #include <ipxe/hmac.h>
@@ -543,15 +545,15 @@ struct net80211_crypto tkip_crypto __net80211_crypto = {
 static void tkip_kie_mic ( const void *kck, const void *msg, size_t len,
 			   void *mic )
 {
-	struct md5_ctx md5;
+	uint8_t ctx[MD5_CTX_SIZE];
 	u8 kckb[16];
 	size_t kck_len = 16;
 
 	memcpy ( kckb, kck, kck_len );
 
-	hmac_init ( &md5_algorithm, &md5, kckb, &kck_len );
-	hmac_update ( &md5_algorithm, &md5, msg, len );
-	hmac_final ( &md5_algorithm, &md5, kckb, &kck_len, mic );
+	hmac_init ( &md5_algorithm, ctx, kckb, &kck_len );
+	hmac_update ( &md5_algorithm, ctx, msg, len );
+	hmac_final ( &md5_algorithm, ctx, kckb, &kck_len, mic );
 }
 
 /**
diff --git a/roms/ipxe/src/net/aoe.c b/roms/ipxe/src/net/aoe.c
index 3b1953a2fda5ac3488d89abd46ee..a6d7b3e7b55ae436a2fe022b1800 100644
--- a/roms/ipxe/src/net/aoe.c
+++ b/roms/ipxe/src/net/aoe.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -906,13 +907,14 @@ static int aoedev_open ( struct interface *parent, struct net_device *netdev,
  * @v netdev		Network device
  * @v ll_dest		Link-layer destination address
  * @v ll_source		Link-layer source address
+ * @v flags		Packet flags
  * @ret rc		Return status code
- *
  */
 static int aoe_rx ( struct io_buffer *iobuf,
 		    struct net_device *netdev __unused,
 		    const void *ll_dest __unused,
-		    const void *ll_source ) {
+		    const void *ll_source,
+		    unsigned int flags __unused ) {
 	struct aoehdr *aoehdr = iobuf->data;
 	struct aoe_command *aoecmd;
 	int rc;
diff --git a/roms/ipxe/src/net/arp.c b/roms/ipxe/src/net/arp.c
index 9b5fd220efd7a9311376dc40be35..b94eb9064b25b7965f84d158ddc4 100644
--- a/roms/ipxe/src/net/arp.c
+++ b/roms/ipxe/src/net/arp.c
@@ -13,12 +13,14 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
 #include <byteswap.h>
 #include <errno.h>
@@ -26,6 +28,11 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/if_arp.h>
 #include <ipxe/iobuf.h>
 #include <ipxe/netdevice.h>
+#include <ipxe/list.h>
+#include <ipxe/retry.h>
+#include <ipxe/timer.h>
+#include <ipxe/malloc.h>
+#include <ipxe/refcnt.h>
 #include <ipxe/arp.h>
 
 /** @file
@@ -38,104 +45,291 @@ FILE_LICENCE ( GPL2_OR_LATER );
  *
  */
 
+/** ARP minimum timeout */
+#define ARP_MIN_TIMEOUT ( TICKS_PER_SEC / 8 )
+
+/** ARP maximum timeout */
+#define ARP_MAX_TIMEOUT ( TICKS_PER_SEC * 3 )
+
 /** An ARP cache entry */
 struct arp_entry {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** List of ARP cache entries */
+	struct list_head list;
+	/** Network device */
+	struct net_device *netdev;
 	/** Network-layer protocol */
 	struct net_protocol *net_protocol;
-	/** Link-layer protocol */
-	struct ll_protocol *ll_protocol;
-	/** Network-layer address */
-	uint8_t net_addr[MAX_NET_ADDR_LEN];
-	/** Link-layer address */
-	uint8_t ll_addr[MAX_LL_ADDR_LEN];
+	/** Network-layer destination address */
+	uint8_t net_dest[MAX_NET_ADDR_LEN];
+	/** Network-layer source address */
+	uint8_t net_source[MAX_NET_ADDR_LEN];
+	/** Link-layer destination address */
+	uint8_t ll_dest[MAX_LL_ADDR_LEN];
+	/** Retransmission timer */
+	struct retry_timer timer;
+	/** Pending I/O buffers */
+	struct list_head tx_queue;
 };
 
-/** Number of entries in the ARP cache
+/** The ARP cache */
+static LIST_HEAD ( arp_entries );
+
+struct net_protocol arp_protocol __net_protocol;
+
+static void arp_expired ( struct retry_timer *timer, int over );
+
+/**
+ * Free ARP cache entry
  *
- * This is a global cache, covering all network interfaces,
- * network-layer protocols and link-layer protocols.
+ * @v refcnt		Reference count
  */
-#define NUM_ARP_ENTRIES 4
+static void arp_free ( struct refcnt *refcnt ) {
+	struct arp_entry *arp =
+		container_of ( refcnt, struct arp_entry, refcnt );
 
-/** The ARP cache */
-static struct arp_entry arp_table[NUM_ARP_ENTRIES];
-#define arp_table_end &arp_table[NUM_ARP_ENTRIES]
+	/* Sanity check */
+	assert ( list_empty ( &arp->tx_queue ) );
 
-static unsigned int next_new_arp_entry = 0;
+	/* Drop reference to network device */
+	netdev_put ( arp->netdev );
 
-struct net_protocol arp_protocol __net_protocol;
+	/* Free entry */
+	free ( arp );
+}
+
+/**
+ * Create ARP cache entry
+ *
+ * @v netdev		Network device
+ * @v net_protocol	Network-layer protocol
+ * @v net_dest		Destination network-layer address
+ * @v net_source	Source network-layer address
+ * @ret arp		ARP cache entry, or NULL if allocation failed
+ */
+static struct arp_entry * arp_create ( struct net_device *netdev,
+				       struct net_protocol *net_protocol,
+				       const void *net_dest,
+				       const void *net_source ) {
+	struct arp_entry *arp;
+
+	/* Allocate and initialise entry */
+	arp = zalloc ( sizeof ( *arp ) );
+	if ( ! arp )
+		return NULL;
+	ref_init ( &arp->refcnt, arp_free );
+	arp->netdev = netdev_get ( netdev );
+	arp->net_protocol = net_protocol;
+	memcpy ( arp->net_dest, net_dest,
+		 net_protocol->net_addr_len );
+	memcpy ( arp->net_source, net_source,
+		 net_protocol->net_addr_len );
+	timer_init ( &arp->timer, arp_expired, &arp->refcnt );
+	arp->timer.min_timeout = ARP_MIN_TIMEOUT;
+	arp->timer.max_timeout = ARP_MAX_TIMEOUT;
+	INIT_LIST_HEAD ( &arp->tx_queue );
+
+	/* Start timer running to trigger initial transmission */
+	start_timer_nodelay ( &arp->timer );
+
+	/* Transfer ownership to cache */
+	list_add ( &arp->list, &arp_entries );
+
+	DBGC ( arp, "ARP %p %s %s %s created\n", arp, netdev->name,
+	       net_protocol->name, net_protocol->ntoa ( net_dest ) );
+	return arp;
+}
 
 /**
  * Find entry in the ARP cache
  *
- * @v ll_protocol	Link-layer protocol
+ * @v netdev		Network device
  * @v net_protocol	Network-layer protocol
- * @v net_addr		Network-layer address
+ * @v net_dest		Destination network-layer address
  * @ret arp		ARP cache entry, or NULL if not found
- *
  */
-static struct arp_entry *
-arp_find_entry ( struct ll_protocol *ll_protocol,
-		 struct net_protocol *net_protocol,
-		 const void *net_addr ) {
+static struct arp_entry * arp_find ( struct net_device *netdev,
+				     struct net_protocol *net_protocol,
+				     const void *net_dest ) {
 	struct arp_entry *arp;
 
-	for ( arp = arp_table ; arp < arp_table_end ; arp++ ) {
-		if ( ( arp->ll_protocol == ll_protocol ) &&
+	list_for_each_entry ( arp, &arp_entries, list ) {
+		if ( ( arp->netdev == netdev ) &&
 		     ( arp->net_protocol == net_protocol ) &&
-		     ( memcmp ( arp->net_addr, net_addr,
-				net_protocol->net_addr_len ) == 0 ) )
+		     ( memcmp ( arp->net_dest, net_dest,
+				net_protocol->net_addr_len ) == 0 ) ) {
+
+			/* Move to start of cache */
+			list_del ( &arp->list );
+			list_add ( &arp->list, &arp_entries );
+
 			return arp;
+		}
 	}
 	return NULL;
 }
 
 /**
- * Look up media-specific link-layer address in the ARP cache
+ * Destroy ARP cache entry
  *
+ * @v arp		ARP cache entry
+ * @v rc		Reason for destruction
+ */
+static void arp_destroy ( struct arp_entry *arp, int rc ) {
+	struct net_device *netdev = arp->netdev;
+	struct net_protocol *net_protocol = arp->net_protocol;
+	struct io_buffer *iobuf;
+
+	/* Take ownership from cache */
+	list_del ( &arp->list );
+
+	/* Stop timer */
+	stop_timer ( &arp->timer );
+
+	/* Discard any outstanding I/O buffers */
+	while ( ( iobuf = list_first_entry ( &arp->tx_queue, struct io_buffer,
+					     list ) ) != NULL ) {
+		DBGC2 ( arp, "ARP %p %s %s %s discarding deferred packet: "
+			"%s\n", arp, netdev->name, net_protocol->name,
+			net_protocol->ntoa ( arp->net_dest ), strerror ( rc ) );
+		list_del ( &iobuf->list );
+		netdev_tx_err ( arp->netdev, iobuf, rc );
+	}
+
+	DBGC ( arp, "ARP %p %s %s %s destroyed: %s\n", arp, netdev->name,
+	       net_protocol->name, net_protocol->ntoa ( arp->net_dest ),
+	       strerror ( rc ) );
+
+	/* Drop remaining reference */
+	ref_put ( &arp->refcnt );
+}
+
+/**
+ * Test if ARP cache entry has a valid link-layer address
+ *
+ * @v arp		ARP cache entry
+ * @ret resolved	ARP cache entry is resolved
+ */
+static inline int arp_resolved ( struct arp_entry *arp ) {
+	return ( ! timer_running ( &arp->timer ) );
+}
+
+/**
+ * Transmit packet, determining link-layer address via ARP
+ *
+ * @v iobuf		I/O buffer
  * @v netdev		Network device
  * @v net_protocol	Network-layer protocol
- * @v dest_net_addr	Destination network-layer address
- * @v source_net_addr	Source network-layer address
- * @ret dest_ll_addr	Destination link layer address
+ * @v net_dest		Destination network-layer address
+ * @v net_source	Source network-layer address
+ * @v ll_source		Source link-layer address
  * @ret rc		Return status code
+ */
+int arp_tx ( struct io_buffer *iobuf, struct net_device *netdev,
+	     struct net_protocol *net_protocol, const void *net_dest,
+	     const void *net_source, const void *ll_source ) {
+	struct arp_entry *arp;
+
+	/* Find or create ARP cache entry */
+	arp = arp_find ( netdev, net_protocol, net_dest );
+	if ( ! arp ) {
+		arp = arp_create ( netdev, net_protocol, net_dest,
+				   net_source );
+		if ( ! arp )
+			return -ENOMEM;
+	}
+
+	/* If a link-layer address is available then transmit
+	 * immediately, otherwise queue for later transmission.
+	 */
+	if ( arp_resolved ( arp ) ) {
+		return net_tx ( iobuf, netdev, net_protocol, arp->ll_dest,
+				ll_source );
+	} else {
+		DBGC2 ( arp, "ARP %p %s %s %s deferring packet\n",
+			arp, netdev->name, net_protocol->name,
+			net_protocol->ntoa ( net_dest ) );
+		list_add_tail ( &iobuf->list, &arp->tx_queue );
+		return -EAGAIN;
+	}
+}
+
+/**
+ * Update ARP cache entry
  *
- * This function will use the ARP cache to look up the link-layer
- * address for the link-layer protocol associated with the network
- * device and the given network-layer protocol and addresses.  If
- * found, the destination link-layer address will be filled in in @c
- * dest_ll_addr.
+ * @v arp		ARP cache entry
+ * @v ll_dest		Destination link-layer address
+ */
+static void arp_update ( struct arp_entry *arp, const void *ll_dest ) {
+	struct net_device *netdev = arp->netdev;
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
+	struct net_protocol *net_protocol = arp->net_protocol;
+	struct io_buffer *iobuf;
+	int rc;
+
+	DBGC ( arp, "ARP %p %s %s %s updated => %s\n", arp, netdev->name,
+	       net_protocol->name, net_protocol->ntoa ( arp->net_dest ),
+	       ll_protocol->ntoa ( ll_dest ) );
+
+	/* Fill in link-layer address */
+	memcpy ( arp->ll_dest, ll_dest, ll_protocol->ll_addr_len );
+
+	/* Stop retransmission timer */
+	stop_timer ( &arp->timer );
+
+	/* Transmit any packets in queue.  Take out a temporary
+	 * reference on the entry to prevent it from going out of
+	 * scope during the call to net_tx().
+	 */
+	ref_get ( &arp->refcnt );
+	while ( ( iobuf = list_first_entry ( &arp->tx_queue, struct io_buffer,
+					     list ) ) != NULL ) {
+		DBGC2 ( arp, "ARP %p %s %s %s transmitting deferred packet\n",
+			arp, netdev->name, net_protocol->name,
+			net_protocol->ntoa ( arp->net_dest ) );
+		list_del ( &iobuf->list );
+		if ( ( rc = net_tx ( iobuf, netdev, net_protocol, ll_dest,
+				     netdev->ll_addr ) ) != 0 ) {
+			DBGC ( arp, "ARP %p could not transmit deferred "
+			       "packet: %s\n", arp, strerror ( rc ) );
+			/* Ignore error and continue */
+		}
+	}
+	ref_put ( &arp->refcnt );
+}
+
+/**
+ * Handle ARP timer expiry
  *
- * If no address is found in the ARP cache, an ARP request will be
- * transmitted on the specified network device and -ENOENT will be
- * returned.
+ * @v timer		Retry timer
+ * @v fail		Failure indicator
  */
-int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol,
-		  const void *dest_net_addr, const void *source_net_addr,
-		  void *dest_ll_addr ) {
+static void arp_expired ( struct retry_timer *timer, int fail ) {
+	struct arp_entry *arp = container_of ( timer, struct arp_entry, timer );
+	struct net_device *netdev = arp->netdev;
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
-	const struct arp_entry *arp;
+	struct net_protocol *net_protocol = arp->net_protocol;
 	struct io_buffer *iobuf;
 	struct arphdr *arphdr;
 	int rc;
 
-	/* Look for existing entry in ARP table */
-	arp = arp_find_entry ( ll_protocol, net_protocol, dest_net_addr );
-	if ( arp ) {
-		DBG ( "ARP cache hit: %s %s => %s %s\n",
-		      net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
-		      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
-		memcpy ( dest_ll_addr, arp->ll_addr, ll_protocol->ll_addr_len);
-		return 0;
+	/* If we have failed, destroy the cache entry */
+	if ( fail ) {
+		arp_destroy ( arp, -ETIMEDOUT );
+		return;
 	}
-	DBG ( "ARP cache miss: %s %s\n", net_protocol->name,
-	      net_protocol->ntoa ( dest_net_addr ) );
+
+	/* Restart the timer */
+	start_timer ( &arp->timer );
 
 	/* Allocate ARP packet */
 	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) +
-			  2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) );
-	if ( ! iobuf )
-		return -ENOMEM;
+			    ( 2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) ) );
+	if ( ! iobuf ) {
+		/* Leave timer running and try again later */
+		return;
+	}
 	iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
 
 	/* Build up ARP request */
@@ -148,18 +342,19 @@ int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol,
 	memcpy ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
 		 netdev->ll_addr, ll_protocol->ll_addr_len );
 	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
-		 source_net_addr, net_protocol->net_addr_len );
+		 arp->net_source, net_protocol->net_addr_len );
 	memset ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
 		 0, ll_protocol->ll_addr_len );
 	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
-		 dest_net_addr, net_protocol->net_addr_len );
+		 arp->net_dest, net_protocol->net_addr_len );
 
 	/* Transmit ARP request */
 	if ( ( rc = net_tx ( iobuf, netdev, &arp_protocol,
-			     netdev->ll_broadcast, netdev->ll_addr ) ) != 0 )
-		return rc;
-
-	return -ENOENT;
+			     netdev->ll_broadcast, netdev->ll_addr ) ) != 0 ) {
+		DBGC ( arp, "ARP %p could not transmit request: %s\n",
+		       arp, strerror ( rc ) );
+		return;
+	}
 }
 
 /**
@@ -186,87 +381,80 @@ static struct arp_net_protocol * arp_find_protocol ( uint16_t net_proto ) {
  * @v iobuf		I/O buffer
  * @v netdev		Network device
  * @v ll_source		Link-layer source address
+ * @v flags		Packet flags
  * @ret rc		Return status code
- *
- * This handles ARP requests and responses as detailed in RFC826.  The
- * method detailed within the RFC is pretty optimised, handling
- * requests and responses with basically a single code path and
- * avoiding the need for extraneous ARP requests; read the RFC for
- * details.
  */
 static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
 		    const void *ll_dest __unused,
-		    const void *ll_source __unused ) {
+		    const void *ll_source __unused,
+		    unsigned int flags __unused ) {
 	struct arphdr *arphdr = iobuf->data;
 	struct arp_net_protocol *arp_net_protocol;
 	struct net_protocol *net_protocol;
 	struct ll_protocol *ll_protocol;
 	struct arp_entry *arp;
-	int merge = 0;
+	int rc;
 
 	/* Identify network-layer and link-layer protocols */
 	arp_net_protocol = arp_find_protocol ( arphdr->ar_pro );
-	if ( ! arp_net_protocol )
+	if ( ! arp_net_protocol ) {
+		rc = -EPROTONOSUPPORT;
 		goto done;
+	}
 	net_protocol = arp_net_protocol->net_protocol;
 	ll_protocol = netdev->ll_protocol;
 
 	/* Sanity checks */
 	if ( ( arphdr->ar_hrd != ll_protocol->ll_proto ) ||
 	     ( arphdr->ar_hln != ll_protocol->ll_addr_len ) ||
-	     ( arphdr->ar_pln != net_protocol->net_addr_len ) )
+	     ( arphdr->ar_pln != net_protocol->net_addr_len ) ) {
+		rc = -EINVAL;
 		goto done;
+	}
 
 	/* See if we have an entry for this sender, and update it if so */
-	arp = arp_find_entry ( ll_protocol, net_protocol,
-			       arp_sender_pa ( arphdr ) );
+	arp = arp_find ( netdev, net_protocol, arp_sender_pa ( arphdr ) );
 	if ( arp ) {
-		memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
-			 arphdr->ar_hln );
-		merge = 1;
-		DBG ( "ARP cache update: %s %s => %s %s\n",
-		      net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
-		      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
+		arp_update ( arp, arp_sender_ha ( arphdr ) );
 	}
 
-	/* See if we own the target protocol address */
-	if ( arp_net_protocol->check ( netdev, arp_target_pa ( arphdr ) ) != 0)
+	/* If it's not a request, there's nothing more to do */
+	if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) ) {
+		rc = 0;
 		goto done;
-	
-	/* Create new ARP table entry if necessary */
-	if ( ! merge ) {
-		arp = &arp_table[next_new_arp_entry++ % NUM_ARP_ENTRIES];
-		arp->ll_protocol = ll_protocol;
-		arp->net_protocol = net_protocol;
-		memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
-			 arphdr->ar_hln );
-		memcpy ( arp->net_addr, arp_sender_pa ( arphdr ),
-			 arphdr->ar_pln);
-		DBG ( "ARP cache add: %s %s => %s %s\n",
-		      net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
-		      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
 	}
 
-	/* If it's not a request, there's nothing more to do */
-	if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) )
+	/* See if we own the target protocol address */
+	if ( arp_net_protocol->check ( netdev, arp_target_pa ( arphdr ) ) != 0){
+		rc = 0;
 		goto done;
+	}
 
 	/* Change request to a reply */
-	DBG ( "ARP reply: %s %s => %s %s\n", net_protocol->name,
-	      net_protocol->ntoa ( arp_target_pa ( arphdr ) ),
-	      ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) );
+	DBGC ( netdev, "ARP reply %s %s %s => %s %s\n",
+	       netdev->name, net_protocol->name,
+	       net_protocol->ntoa ( arp_target_pa ( arphdr ) ),
+	       ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) );
 	arphdr->ar_op = htons ( ARPOP_REPLY );
 	memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
 		 arphdr->ar_hln + arphdr->ar_pln );
 	memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln );
 
 	/* Send reply */
-	net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol,
-		 arp_target_ha ( arphdr ), netdev->ll_addr );
+	if ( ( rc = net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol,
+			     arp_target_ha ( arphdr ),
+			     netdev->ll_addr ) ) != 0 ) {
+		DBGC ( netdev, "ARP could not transmit reply via %s: %s\n",
+		       netdev->name, strerror ( rc ) );
+		goto done;
+	}
+
+	/* Success */
+	rc = 0;
 
  done:
 	free_iob ( iobuf );
-	return 0;
+	return rc;
 }
 
 /**
@@ -288,3 +476,65 @@ struct net_protocol arp_protocol __net_protocol = {
 	.rx = arp_rx,
 	.ntoa = arp_ntoa,
 };
+
+/**
+ * Update ARP cache on network device creation
+ *
+ * @v netdev		Network device
+ */
+static int arp_probe ( struct net_device *netdev __unused ) {
+	/* Nothing to do */
+	return 0;
+}
+
+/**
+ * Update ARP cache on network device state change or removal
+ *
+ * @v netdev		Network device
+ */
+static void arp_flush ( struct net_device *netdev ) {
+	struct arp_entry *arp;
+	struct arp_entry *tmp;
+
+	/* Remove all ARP cache entries when a network device is closed */
+	if ( ! netdev_is_open ( netdev ) ) {
+		list_for_each_entry_safe ( arp, tmp, &arp_entries, list )
+			arp_destroy ( arp, -ENODEV );
+	}
+}
+
+/** ARP driver (for net device notifications) */
+struct net_driver arp_net_driver __net_driver = {
+	.name = "ARP",
+	.probe = arp_probe,
+	.notify = arp_flush,
+	.remove = arp_flush,
+};
+
+/**
+ * Discard some cached ARP entries
+ *
+ * @ret discarded	Number of cached items discarded
+ */
+static unsigned int arp_discard ( void ) {
+	struct arp_entry *arp;
+
+	/* Drop oldest cache entry, if any */
+	arp = list_last_entry ( &arp_entries, struct arp_entry, list );
+	if ( arp ) {
+		arp_destroy ( arp, -ENOBUFS );
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+/** ARP cache discarder
+ *
+ * ARP cache entries are deemed to have a high replacement cost, since
+ * flushing an active ARP cache entry midway through a TCP transfer
+ * will cause substantial disruption.
+ */
+struct cache_discarder arp_discarder __cache_discarder ( CACHE_EXPENSIVE ) = {
+	.discard = arp_discard,
+};
diff --git a/roms/ipxe/src/net/cachedhcp.c b/roms/ipxe/src/net/cachedhcp.c
index 36f480a96f025d8db98e141e69c9..fc7dabc90b40f1bb04061b81a0a4 100644
--- a/roms/ipxe/src/net/cachedhcp.c
+++ b/roms/ipxe/src/net/cachedhcp.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/dhcpopts.c b/roms/ipxe/src/net/dhcpopts.c
index 249fde151bc2fc10bb6458af9bc0..6d29a7b5ec18edb67cc715899a2d 100644
--- a/roms/ipxe/src/net/dhcpopts.c
+++ b/roms/ipxe/src/net/dhcpopts.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/dhcppkt.c b/roms/ipxe/src/net/dhcppkt.c
index 0a0e458fceb602ad9ac7f97502a0..528f900372f193f86d938a7f57fa 100644
--- a/roms/ipxe/src/net/dhcppkt.c
+++ b/roms/ipxe/src/net/dhcppkt.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/eapol.c b/roms/ipxe/src/net/eapol.c
index 9e5f2640157a57f52214c136af3f..eb0362994ed8cca5924c8ba2ff9f 100644
--- a/roms/ipxe/src/net/eapol.c
+++ b/roms/ipxe/src/net/eapol.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -38,11 +39,13 @@ FILE_LICENCE ( GPL2_OR_LATER );
  * @v netdev	Network device
  * @v ll_dest	Link-layer destination address
  * @v ll_source	Link-layer source address
+ * @v flags	Packet flags
  *
  * This function takes ownership of the I/O buffer passed to it.
  */
 static int eapol_rx ( struct io_buffer *iob, struct net_device *netdev,
-		      const void *ll_dest, const void *ll_source ) {
+		      const void *ll_dest, const void *ll_source,
+		      unsigned int flags __unused ) {
 	struct eapol_frame *eapol = iob->data;
 	struct eapol_handler *handler;
 
diff --git a/roms/ipxe/src/net/eth_slow.c b/roms/ipxe/src/net/eth_slow.c
index 9e68939cf3789ea2ffe65c9efd56..69c38f30a6e70915da379434ce26 100644
--- a/roms/ipxe/src/net/eth_slow.c
+++ b/roms/ipxe/src/net/eth_slow.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -234,12 +235,14 @@ static int eth_slow_marker_rx ( struct io_buffer *iobuf,
  * @v netdev		Network device
  * @v ll_dest		Link-layer destination address
  * @v ll_source		Link-layer source address
+ * @v flags		Packet flags
  * @ret rc		Return status code
  */
 static int eth_slow_rx ( struct io_buffer *iobuf,
 			 struct net_device *netdev,
 			 const void *ll_dest __unused,
-			 const void *ll_source __unused ) {
+			 const void *ll_source __unused,
+			 unsigned int flags __unused ) {
 	union eth_slow_packet *eth_slow = iobuf->data;
 
 	/* Sanity checks */
diff --git a/roms/ipxe/src/net/ethernet.c b/roms/ipxe/src/net/ethernet.c
index d14cfefcc1259f7eade913539c96..4fd2ab6e538f8d674565ff899357 100644
--- a/roms/ipxe/src/net/ethernet.c
+++ b/roms/ipxe/src/net/ethernet.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -38,7 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
  */
 
 /** Ethernet broadcast MAC address */
-static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
 /**
  * Add Ethernet link-layer header
@@ -50,9 +51,9 @@ static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  * @v net_proto		Network-layer protocol, in network-byte order
  * @ret rc		Return status code
  */
-static int eth_push ( struct net_device *netdev __unused,
-		      struct io_buffer *iobuf, const void *ll_dest,
-		      const void *ll_source, uint16_t net_proto ) {
+int eth_push ( struct net_device *netdev __unused, 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 */
@@ -71,11 +72,12 @@ static int eth_push ( struct net_device *netdev __unused,
  * @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 flags		Packet flags
  * @ret rc		Return status code
  */
-static int eth_pull ( struct net_device *netdev __unused, 
-		      struct io_buffer *iobuf, const void **ll_dest,
-		      const void **ll_source, uint16_t *net_proto ) {
+int eth_pull ( struct net_device *netdev __unused, struct io_buffer *iobuf,
+	       const void **ll_dest, const void **ll_source,
+	       uint16_t *net_proto, unsigned int *flags ) {
 	struct ethhdr *ethhdr = iobuf->data;
 
 	/* Sanity check */
@@ -92,6 +94,10 @@ static int eth_pull ( struct net_device *netdev __unused,
 	*ll_dest = ethhdr->h_dest;
 	*ll_source = ethhdr->h_source;
 	*net_proto = ethhdr->h_protocol;
+	*flags = ( ( is_multicast_ether_addr ( ethhdr->h_dest ) ?
+		     LL_MULTICAST : 0 ) |
+		   ( is_broadcast_ether_addr ( ethhdr->h_dest ) ?
+		     LL_BROADCAST : 0 ) );
 
 	return 0;
 }
diff --git a/roms/ipxe/src/net/fakedhcp.c b/roms/ipxe/src/net/fakedhcp.c
index b43e9b12486d0144227a5720a8a1..d67501ed3e48643faf9f5de12bd9 100644
--- a/roms/ipxe/src/net/fakedhcp.c
+++ b/roms/ipxe/src/net/fakedhcp.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -114,7 +115,8 @@ int create_fakedhcpdiscover ( struct net_device *netdev,
 	int rc;
 
 	if ( ( rc = dhcp_create_request ( &dhcppkt, netdev, DHCPDISCOVER,
-					  ciaddr, data, max_len ) ) != 0 ) {
+					  dhcp_last_xid, ciaddr, data,
+					  max_len ) ) != 0 ) {
 		DBG ( "Could not create DHCPDISCOVER: %s\n",
 		      strerror ( rc ) );
 		return rc;
@@ -139,7 +141,8 @@ int create_fakedhcpack ( struct net_device *netdev,
 	int rc;
 
 	/* Create base DHCPACK packet */
-	if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0,
+	if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK,
+					 dhcp_last_xid, NULL, 0,
 					 data, max_len ) ) != 0 ) {
 		DBG ( "Could not create DHCPACK: %s\n", strerror ( rc ) );
 		return rc;
@@ -190,7 +193,8 @@ int create_fakepxebsack ( struct net_device *netdev,
 	}
 
 	/* Create base DHCPACK packet */
-	if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0,
+	if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK,
+					 dhcp_last_xid, NULL, 0,
 					 data, max_len ) ) != 0 ) {
 		DBG ( "Could not create PXE BS ACK: %s\n",
 		      strerror ( rc ) );
diff --git a/roms/ipxe/src/net/fc.c b/roms/ipxe/src/net/fc.c
index 1934fab3d4c32d0dce868d4f5031..58008995cc47b1cef233389a9bb9 100644
--- a/roms/ipxe/src/net/fc.c
+++ b/roms/ipxe/src/net/fc.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -1580,7 +1581,7 @@ static void fc_ulp_close ( struct fc_ulp *ulp, int rc ) {
 	       fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) );
 
 	/* Sanity check */
-	assert ( ulp->usage == 0 );
+	assert ( list_empty ( &ulp->users ) );
 
 	/* Stop link monitor */
 	fc_link_stop ( &ulp->link );
@@ -1594,35 +1595,50 @@ static void fc_ulp_close ( struct fc_ulp *ulp, int rc ) {
 }
 
 /**
- * Increment Fibre Channel upper-layer protocol active usage count
+ * Attach Fibre Channel upper-layer protocol user
  *
- * @v ulp		Fibre Channel ulp
+ * @v ulp		Fibre Channel upper-layer protocol
+ * @v user		Fibre Channel upper-layer protocol user
  */
-void fc_ulp_increment ( struct fc_ulp *ulp ) {
+void fc_ulp_attach ( struct fc_ulp *ulp, struct fc_ulp_user *user ) {
+
+	/* Sanity check */
+	assert ( user->ulp == NULL );
 
 	/* Increment peer's usage count */
 	fc_peer_increment ( ulp->peer );
 
-	/* Increment our usage count */
-	ulp->usage++;
+	/* Attach user */
+	user->ulp = fc_ulp_get ( ulp );
+	list_add ( &user->list, &ulp->users );
 }
 
 /**
- * Decrement Fibre Channel upper-layer protocol active usage count
+ * Detach Fibre Channel upper-layer protocol user
  *
- * @v ulp		Fibre Channel ulp
+ * @v user		Fibre Channel upper-layer protocol user
  */
-void fc_ulp_decrement ( struct fc_ulp *ulp ) {
+void fc_ulp_detach ( struct fc_ulp_user *user ) {
+	struct fc_ulp *ulp = user->ulp;
 
-	/* Sanity check */
-	assert ( ulp->usage > 0 );
+	/* Do nothing if not attached */
+	if ( ! ulp )
+		return;
 
-	/* Decrement our usage count and log out if we reach zero */
-	if ( --(ulp->usage) == 0 )
+	/* Sanity checks */
+	list_check_contains_entry ( user, &ulp->users, list );
+
+	/* Detach user and log out if no users remain */
+	list_del ( &user->list );
+	if ( list_empty ( &ulp->users ) )
 		fc_ulp_logout ( ulp, 0 );
 
 	/* Decrement our peer's usage count */
 	fc_peer_decrement ( ulp->peer );
+
+	/* Drop reference */
+	user->ulp = NULL;
+	fc_ulp_put ( ulp );
 }
 
 /**
@@ -1636,6 +1652,8 @@ void fc_ulp_decrement ( struct fc_ulp *ulp ) {
  */
 int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len,
 		   int originated ) {
+	struct fc_ulp_user *user;
+	struct fc_ulp_user *tmp;
 
 	/* Perform implicit logout if logged in and service parameters differ */
 	if ( fc_link_ok ( &ulp->link ) &&
@@ -1644,6 +1662,22 @@ int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len,
 		fc_ulp_logout ( ulp, 0 );
 	}
 
+	/* Work around a bug in some versions of the Linux Fibre
+	 * Channel stack, which fail to fully initialise image pairs
+	 * established via a PRLI originated by the Linux stack
+	 * itself.
+	 */
+	if ( originated )
+		ulp->flags |= FC_ULP_ORIGINATED_LOGIN_OK;
+	if ( ! ( ulp->flags & FC_ULP_ORIGINATED_LOGIN_OK ) ) {
+		DBGC ( ulp, "FCULP %s/%02x sending extra PRLI to work around "
+		       "Linux bug\n",
+		       fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
+		fc_link_stop ( &ulp->link );
+		fc_link_start ( &ulp->link );
+		return 0;
+	}
+
 	/* Log in, if applicable */
 	if ( ! fc_link_ok ( &ulp->link ) ) {
 
@@ -1670,18 +1704,11 @@ int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len,
 	/* Record login */
 	fc_link_up ( &ulp->link );
 
-	/* Work around a bug in some versions of the Linux Fibre
-	 * Channel stack, which fail to fully initialise image pairs
-	 * established via a PRLI originated by the Linux stack
-	 * itself.
-	 */
-	if ( originated )
-		ulp->flags |= FC_ULP_ORIGINATED_LOGIN_OK;
-	if ( ! ( ulp->flags & FC_ULP_ORIGINATED_LOGIN_OK ) ) {
-		DBGC ( ulp, "FCULP %s/%02x sending extra PRLI to work around "
-		       "Linux bug\n",
-		       fc_ntoa ( &ulp->peer->port_wwn ), ulp->type );
-		fc_link_start ( &ulp->link );
+	/* Notify users of link state change */
+	list_for_each_entry_safe ( user, tmp, &ulp->users, list ) {
+		fc_ulp_user_get ( user );
+		user->examine ( user );
+		fc_ulp_user_put ( user );
 	}
 
 	return 0;
@@ -1694,6 +1721,8 @@ int fc_ulp_login ( struct fc_ulp *ulp, const void *param, size_t param_len,
  * @v rc		Reason for logout
  */
 void fc_ulp_logout ( struct fc_ulp *ulp, int rc ) {
+	struct fc_ulp_user *user;
+	struct fc_ulp_user *tmp;
 
 	DBGC ( ulp, "FCULP %s/%02x logged out: %s\n",
 	       fc_ntoa ( &ulp->peer->port_wwn ), ulp->type, strerror ( rc ) );
@@ -1711,8 +1740,15 @@ void fc_ulp_logout ( struct fc_ulp *ulp, int rc ) {
 	/* Record logout */
 	fc_link_err ( &ulp->link, rc );
 
+	/* Notify users of link state change */
+	list_for_each_entry_safe ( user, tmp, &ulp->users, list ) {
+		fc_ulp_user_get ( user );
+		user->examine ( user );
+		fc_ulp_user_put ( user );
+	}
+
 	/* Close ULP if there are no clients attached */
-	if ( ulp->usage == 0 )
+	if ( list_empty ( &ulp->users ) )
 		fc_ulp_close ( ulp, rc );
 }
 
@@ -1795,6 +1831,7 @@ static struct fc_ulp * fc_ulp_create ( struct fc_peer *peer,
 	ulp->peer = fc_peer_get ( peer );
 	list_add_tail ( &ulp->list, &peer->ulps );
 	ulp->type = type;
+	INIT_LIST_HEAD ( &ulp->users );
 
 	/* Start link state monitor */
 	fc_link_start ( &ulp->link );
diff --git a/roms/ipxe/src/net/fcels.c b/roms/ipxe/src/net/fcels.c
index f8bcb865fef8ccec49dbefe429db..1cfe90727ea7315bf5519ae93ed7 100644
--- a/roms/ipxe/src/net/fcels.c
+++ b/roms/ipxe/src/net/fcels.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -244,20 +245,15 @@ static struct interface_descriptor fc_els_job_desc =
 /**
  * Fibre Channel ELS process
  *
- * @v process		Process
+ * @v els		Fibre Channel ELS transaction
  */
-static void fc_els_step ( struct process *process ) {
-	struct fc_els *els =
-		container_of ( process, struct fc_els, process );
+static void fc_els_step ( struct fc_els *els ) {
 	int xchg_id;
 	int rc;
 
 	/* Sanity check */
 	assert ( fc_els_is_request ( els ) );
 
-	/* Stop process */
-	process_del ( &els->process );
-
 	/* Create exchange */
 	if ( ( xchg_id = fc_xchg_originate ( &els->xchg, els->port,
 					     &els->peer_port_id,
@@ -278,6 +274,10 @@ static void fc_els_step ( struct process *process ) {
 	}
 }
 
+/** Fibre Channel ELS process descriptor */
+static struct process_descriptor fc_els_process_desc =
+	PROC_DESC_ONCE ( struct fc_els, process, fc_els_step );
+
 /**
  * Create ELS transaction
  *
@@ -298,7 +298,8 @@ static struct fc_els * fc_els_create ( struct fc_port *port,
 	ref_init ( &els->refcnt, fc_els_free );
 	intf_init ( &els->job, &fc_els_job_desc, &els->refcnt );
 	intf_init ( &els->xchg, &fc_els_xchg_desc, &els->refcnt );
-	process_init_stopped ( &els->process, fc_els_step, &els->refcnt );
+	process_init_stopped ( &els->process, &fc_els_process_desc,
+			       &els->refcnt );
 	els->port = fc_port_get ( port );
 	memcpy ( &els->port_id, port_id, sizeof ( els->port_id ) );
 	memcpy ( &els->peer_port_id, peer_port_id,
diff --git a/roms/ipxe/src/net/fcns.c b/roms/ipxe/src/net/fcns.c
index 7769e255e63e4abbbc93471338d5..3ca4ad557da345382b98522a92a6 100644
--- a/roms/ipxe/src/net/fcns.c
+++ b/roms/ipxe/src/net/fcns.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -153,19 +154,14 @@ static int fc_ns_query_deliver ( struct fc_ns_query *query,
 /**
  * Name server query process
  *
- * @v process		Process
+ * @v query		Name server query
  */
-static void fc_ns_query_step ( struct process *process ) {
-	struct fc_ns_query *query =
-		container_of ( process, struct fc_ns_query, process );
+static void fc_ns_query_step ( struct fc_ns_query *query ) {
 	struct xfer_metadata meta;
 	struct fc_ns_gid_pn_request gid_pn;
 	int xchg_id;
 	int rc;
 
-	/* Stop process */
-	process_del ( &query->process );
-
 	/* Create exchange */
 	if ( ( xchg_id = fc_xchg_originate ( &query->xchg, query->port,
 					     &fc_gs_port_id,
@@ -208,6 +204,10 @@ static struct interface_operation fc_ns_query_xchg_op[] = {
 static struct interface_descriptor fc_ns_query_xchg_desc =
 	INTF_DESC ( struct fc_ns_query, xchg, fc_ns_query_xchg_op );
 
+/** Name server process descriptor */
+static struct process_descriptor fc_ns_query_process_desc =
+	PROC_DESC_ONCE ( struct fc_ns_query, process, fc_ns_query_step );
+
 /**
  * Issue Fibre Channel name server query
  *
@@ -226,7 +226,8 @@ int fc_ns_query ( struct fc_peer *peer, struct fc_port *port,
 		return -ENOMEM;
 	ref_init ( &query->refcnt, fc_ns_query_free );
 	intf_init ( &query->xchg, &fc_ns_query_xchg_desc, &query->refcnt );
-	process_init ( &query->process, fc_ns_query_step, &query->refcnt );
+	process_init ( &query->process, &fc_ns_query_process_desc,
+		       &query->refcnt );
 	query->peer = fc_peer_get ( peer );
 	query->port = fc_port_get ( port );
 	query->done = done;
diff --git a/roms/ipxe/src/net/fcoe.c b/roms/ipxe/src/net/fcoe.c
index db2fc980645c59ceb04f734c5b39..d11304258fba0073f204dc7d9b4e 100644
--- a/roms/ipxe/src/net/fcoe.c
+++ b/roms/ipxe/src/net/fcoe.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -331,10 +332,12 @@ static struct io_buffer * fcoe_alloc_iob ( struct fcoe_port *fcoe __unused,
  * @v netdev		Network device
  * @v ll_dest		Link-layer destination address
  * @v ll_source		Link-layer source address
+ * @v flags		Packet flags
  * @ret rc		Return status code
  */
 static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev,
-		     const void *ll_dest, const void *ll_source ) {
+		     const void *ll_dest, const void *ll_source,
+		     unsigned int flags __unused ) {
 	struct fcoe_header *fcoehdr;
 	struct fcoe_footer *fcoeftr;
 	struct fcoe_port *fcoe;
@@ -924,12 +927,14 @@ static struct fip_handler fip_handlers[] = {
  * @v netdev		Network device
  * @v ll_dest		Link-layer destination address
  * @v ll_source		Link-layer source address
+ * @v flags		Packet flags
  * @ret rc		Return status code
  */
 static int fcoe_fip_rx ( struct io_buffer *iobuf,
 			 struct net_device *netdev,
 			 const void *ll_dest,
-			 const void *ll_source __unused ) {
+			 const void *ll_source __unused,
+			 unsigned int flags __unused ) {
 	struct fip_header *fiphdr = iobuf->data;
 	struct fip_descriptors descs;
 	struct fip_handler *handler;
diff --git a/roms/ipxe/src/net/fcp.c b/roms/ipxe/src/net/fcp.c
index 40cd057e6c93b2bb91f086095ab0..241b546385ae3df924d17d9a0a57 100644
--- a/roms/ipxe/src/net/fcp.c
+++ b/roms/ipxe/src/net/fcp.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -146,8 +147,8 @@ struct fc_els_prli_descriptor fcp_prli_descriptor __fc_els_prli_descriptor = {
 struct fcp_device {
 	/** Reference count */
 	struct refcnt refcnt;
-	/** Fibre Channel upper-layer protocol */
-	struct fc_ulp *ulp;
+	/** Fibre Channel upper-layer protocol user */
+	struct fc_ulp_user user;
 	/** SCSI command issuing interface */
 	struct interface scsi;
 	/** List of active commands */
@@ -649,11 +650,9 @@ static int fcpcmd_recv_unknown ( struct fcp_command *fcpcmd,
 /**
  * Transmit FCP frame
  *
- * @v process		FCP command process
+ * @v fcpcmd		FCP command
  */
-static void fcpcmd_step ( struct process *process ) {
-	struct fcp_command *fcpcmd =
-		container_of ( process, struct fcp_command, process );
+static void fcpcmd_step ( struct fcp_command *fcpcmd ) {
 	int rc;
 
 	/* Send the current IU */
@@ -723,6 +722,10 @@ static struct interface_operation fcpcmd_xchg_op[] = {
 static struct interface_descriptor fcpcmd_xchg_desc =
 	INTF_DESC_PASSTHRU ( struct fcp_command, xchg, fcpcmd_xchg_op, scsi );
 
+/** FCP command process descriptor */
+static struct process_descriptor fcpcmd_process_desc =
+	PROC_DESC ( struct fcp_command, process, fcpcmd_step );
+
 /**
  * Issue FCP SCSI command
  *
@@ -734,13 +737,13 @@ static struct interface_descriptor fcpcmd_xchg_desc =
 static int fcpdev_scsi_command ( struct fcp_device *fcpdev,
 				 struct interface *parent,
 				 struct scsi_cmd *command ) {
-	struct fcp_prli_service_parameters *param = fcpdev->ulp->param;
+	struct fcp_prli_service_parameters *param = fcpdev->user.ulp->param;
 	struct fcp_command *fcpcmd;
 	int xchg_id;
 	int rc;
 
 	/* Check link */
-	if ( ( rc = fcpdev->ulp->link.rc ) != 0 ) {
+	if ( ( rc = fcpdev->user.ulp->link.rc ) != 0 ) {
 		DBGC ( fcpdev, "FCP %p could not issue command while link is "
 		       "down: %s\n", fcpdev, strerror ( rc ) );
 		goto err_link;
@@ -748,7 +751,7 @@ static int fcpdev_scsi_command ( struct fcp_device *fcpdev,
 
 	/* Check target capability */
 	assert ( param != NULL );
-	assert ( fcpdev->ulp->param_len >= sizeof ( *param ) );
+	assert ( fcpdev->user.ulp->param_len >= sizeof ( *param ) );
 	if ( ! ( param->flags & htonl ( FCP_PRLI_TARGET ) ) ) {
 		DBGC ( fcpdev, "FCP %p could not issue command: not a target\n",
 		       fcpdev );
@@ -765,15 +768,16 @@ static int fcpdev_scsi_command ( struct fcp_device *fcpdev,
 	ref_init ( &fcpcmd->refcnt, fcpcmd_free );
 	intf_init ( &fcpcmd->scsi, &fcpcmd_scsi_desc, &fcpcmd->refcnt );
 	intf_init ( &fcpcmd->xchg, &fcpcmd_xchg_desc, &fcpcmd->refcnt );
-	process_init_stopped ( &fcpcmd->process, fcpcmd_step, &fcpcmd->refcnt );
+	process_init_stopped ( &fcpcmd->process, &fcpcmd_process_desc,
+			       &fcpcmd->refcnt );
 	fcpcmd->fcpdev = fcpdev_get ( fcpdev );
 	list_add ( &fcpcmd->list, &fcpdev->fcpcmds );
 	memcpy ( &fcpcmd->command, command, sizeof ( fcpcmd->command ) );
 
 	/* Create new exchange */
 	if ( ( xchg_id = fc_xchg_originate ( &fcpcmd->xchg,
-					     fcpdev->ulp->peer->port,
-					     &fcpdev->ulp->peer->port_id,
+					     fcpdev->user.ulp->peer->port,
+					     &fcpdev->user.ulp->peer->port_id,
 					     FC_TYPE_FCP ) ) < 0 ) {
 		rc = xchg_id;
 		DBGC ( fcpdev, "FCP %p could not create exchange: %s\n",
@@ -822,11 +826,7 @@ static void fcpdev_close ( struct fcp_device *fcpdev, int rc ) {
 	}
 
 	/* Drop reference to ULP */
-	if ( fcpdev->ulp ) {
-		fc_ulp_decrement ( fcpdev->ulp );
-		fc_ulp_put ( fcpdev->ulp );
-		fcpdev->ulp = NULL;
-	}
+	fc_ulp_detach ( &fcpdev->user );
 }
 
 /**
@@ -836,7 +836,8 @@ static void fcpdev_close ( struct fcp_device *fcpdev, int rc ) {
  * @ret len		Length of window
  */
 static size_t fcpdev_window ( struct fcp_device *fcpdev ) {
-	return ( fc_link_ok ( &fcpdev->ulp->link ) ? ~( ( size_t ) 0 ) : 0 );
+	return ( fc_link_ok ( &fcpdev->user.ulp->link ) ?
+		 ~( ( size_t ) 0 ) : 0 );
 }
 
 /**
@@ -897,15 +898,15 @@ static struct device * fcpdev_identify_device ( struct fcp_device *fcpdev ) {
 	/* We know the underlying device only if the link is up;
 	 * otherwise we don't have a port to examine.
 	 */
-	if ( ! fc_link_ok ( &fcpdev->ulp->link ) ) {
+	if ( ! fc_link_ok ( &fcpdev->user.ulp->link ) ) {
 		DBGC ( fcpdev, "FCP %p doesn't know underlying device "
 		       "until link is up\n", fcpdev );
 		return NULL;
 	}
 
 	/* Hand off to port's transport interface */
-	assert ( fcpdev->ulp->peer->port != NULL );
-	return identify_device ( &fcpdev->ulp->peer->port->transport );
+	assert ( fcpdev->user.ulp->peer->port != NULL );
+	return identify_device ( &fcpdev->user.ulp->peer->port->transport );
 }
 
 /** FCP device SCSI interface operations */
@@ -923,6 +924,26 @@ static struct interface_operation fcpdev_scsi_op[] = {
 static struct interface_descriptor fcpdev_scsi_desc =
 	INTF_DESC ( struct fcp_device, scsi, fcpdev_scsi_op );
 
+/**
+ * Examine FCP ULP link state
+ *
+ * @v user		Fibre Channel upper-layer protocol user
+ */
+static void fcpdev_examine ( struct fc_ulp_user *user ) {
+	struct fcp_device *fcpdev =
+		container_of ( user, struct fcp_device, user );
+
+	if ( fc_link_ok ( &fcpdev->user.ulp->link ) ) {
+		DBGC ( fcpdev, "FCP %p link is up\n", fcpdev );
+	} else {
+		DBGC ( fcpdev, "FCP %p link is down: %s\n",
+		       fcpdev, strerror ( fcpdev->user.ulp->link.rc ) );
+	}
+
+	/* Notify SCSI layer of window change */
+	xfer_window_changed ( &fcpdev->scsi );
+}
+
 /**
  * Open FCP device
  *
@@ -953,11 +974,13 @@ static int fcpdev_open ( struct interface *parent, struct fc_name *wwn,
 	ref_init ( &fcpdev->refcnt, NULL );
 	intf_init ( &fcpdev->scsi, &fcpdev_scsi_desc, &fcpdev->refcnt );
 	INIT_LIST_HEAD ( &fcpdev->fcpcmds );
-	fcpdev->ulp = fc_ulp_get ( ulp );
-	fc_ulp_increment ( fcpdev->ulp );
+	fc_ulp_user_init ( &fcpdev->user, fcpdev_examine, &fcpdev->refcnt );
 
 	DBGC ( fcpdev, "FCP %p opened for %s\n", fcpdev, fc_ntoa ( wwn ) );
 
+	/* Attach to Fibre Channel ULP */
+	fc_ulp_attach ( ulp, &fcpdev->user );
+
 	/* Preserve parameters required for boot firmware table */
 	memcpy ( &fcpdev->wwn, wwn, sizeof ( fcpdev->wwn ) );
 	memcpy ( &fcpdev->lun, lun, sizeof ( fcpdev->lun ) );
diff --git a/roms/ipxe/src/net/icmp.c b/roms/ipxe/src/net/icmp.c
index 84dad42561bf5a0a45064129dd97..830d829244e950034003076cb8a6 100644
--- a/roms/ipxe/src/net/icmp.c
+++ b/roms/ipxe/src/net/icmp.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/infiniband.c b/roms/ipxe/src/net/infiniband.c
index c2cb834df6b085344d3a46394b0c..12d1d83cee34eed80e49a6c4106a 100644
--- a/roms/ipxe/src/net/infiniband.c
+++ b/roms/ipxe/src/net/infiniband.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -167,6 +168,7 @@ void ib_poll_cq ( struct ib_device *ibdev,
  * @v send_cq		Send completion queue
  * @v num_recv_wqes	Number of receive work queue entries
  * @v recv_cq		Receive completion queue
+ * @v op		Queue pair operations
  * @ret qp		Queue pair
  *
  * The queue pair will be left in the INIT state; you must call
@@ -177,7 +179,8 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
 				      unsigned int num_send_wqes,
 				      struct ib_completion_queue *send_cq,
 				      unsigned int num_recv_wqes,
-				      struct ib_completion_queue *recv_cq ) {
+				      struct ib_completion_queue *recv_cq,
+				      struct ib_queue_pair_operations *op ) {
 	struct ib_queue_pair *qp;
 	size_t total_size;
 	int rc;
@@ -209,6 +212,7 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
 	qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) +
 			    ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ));
 	INIT_LIST_HEAD ( &qp->mgids );
+	qp->op = op;
 
 	/* Perform device-specific initialisation and get QPN */
 	if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) {
@@ -259,7 +263,6 @@ struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		New address vector, if applicable
  * @ret rc		Return status code
  */
 int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
@@ -301,7 +304,7 @@ void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
 	}
 	for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) {
 		if ( ( iobuf = qp->recv.iobufs[i] ) != NULL ) {
-			ib_complete_recv ( ibdev, qp, NULL, iobuf,
+			ib_complete_recv ( ibdev, qp, NULL, NULL, iobuf,
 					   -ECANCELED );
 		}
 	}
@@ -380,14 +383,14 @@ struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector
+ * @v dest		Destination address vector
  * @v iobuf		I/O buffer
  * @ret rc		Return status code
  */
 int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
-		   struct ib_address_vector *av,
+		   struct ib_address_vector *dest,
 		   struct io_buffer *iobuf ) {
-	struct ib_address_vector av_copy;
+	struct ib_address_vector dest_copy;
 	int rc;
 
 	/* Check queue fill level */
@@ -398,21 +401,21 @@ int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
 	}
 
 	/* Use default address vector if none specified */
-	if ( ! av )
-		av = &qp->av;
+	if ( ! dest )
+		dest = &qp->av;
 
 	/* Make modifiable copy of address vector */
-	memcpy ( &av_copy, av, sizeof ( av_copy ) );
-	av = &av_copy;
+	memcpy ( &dest_copy, dest, sizeof ( dest_copy ) );
+	dest = &dest_copy;
 
 	/* Fill in optional parameters in address vector */
-	if ( ! av->qkey )
-		av->qkey = qp->qkey;
-	if ( ! av->rate )
-		av->rate = IB_RATE_2_5;
+	if ( ! dest->qkey )
+		dest->qkey = qp->qkey;
+	if ( ! dest->rate )
+		dest->rate = IB_RATE_2_5;
 
 	/* Post to hardware */
-	if ( ( rc = ibdev->op->post_send ( ibdev, qp, av, iobuf ) ) != 0 ) {
+	if ( ( rc = ibdev->op->post_send ( ibdev, qp, dest, iobuf ) ) != 0 ) {
 		DBGC ( ibdev, "IBDEV %p QPN %#lx could not post send WQE: "
 		       "%s\n", ibdev, qp->qpn, strerror ( rc ) );
 		return rc;
@@ -483,16 +486,19 @@ void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector, or NULL
+ * @v dest		Destination address vector, or NULL
+ * @v source		Source address vector, or NULL
  * @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 ib_address_vector *dest,
+			struct ib_address_vector *source,
 			struct io_buffer *iobuf, int rc ) {
 
 	if ( qp->recv.cq->op->complete_recv ) {
-		qp->recv.cq->op->complete_recv ( ibdev, qp, av, iobuf, rc );
+		qp->recv.cq->op->complete_recv ( ibdev, qp, dest, source,
+						 iobuf, rc );
 	} else {
 		free_iob ( iobuf );
 	}
@@ -513,7 +519,7 @@ void ib_refill_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
 	while ( qp->recv.fill < qp->recv.num_wqes ) {
 
 		/* Allocate I/O buffer */
-		iobuf = alloc_iob ( IB_MAX_PAYLOAD_SIZE );
+		iobuf = qp->op->alloc_iob ( IB_MAX_PAYLOAD_SIZE );
 		if ( ! iobuf ) {
 			/* Non-fatal; we will refill on next attempt */
 			return;
@@ -610,6 +616,13 @@ int ib_open ( struct ib_device *ibdev ) {
 		return 0;
 	}
 
+	/* Open device */
+	if ( ( rc = ibdev->op->open ( ibdev ) ) != 0 ) {
+		DBGC ( ibdev, "IBDEV %p could not open: %s\n",
+		       ibdev, strerror ( rc ) );
+		goto err_open;
+	}
+
 	/* Create subnet management interface */
 	ibdev->smi = ib_create_mi ( ibdev, IB_QPT_SMI );
 	if ( ! ibdev->smi ) {
@@ -633,13 +646,6 @@ int ib_open ( struct ib_device *ibdev ) {
 		goto err_create_gsi;
 	}
 
-	/* Open device */
-	if ( ( rc = ibdev->op->open ( ibdev ) ) != 0 ) {
-		DBGC ( ibdev, "IBDEV %p could not open: %s\n",
-		       ibdev, strerror ( rc ) );
-		goto err_open;
-	}
-
 	/* Add to head of open devices list */
 	list_add ( &ibdev->open_list, &open_ib_devices );
 
@@ -649,14 +655,14 @@ int ib_open ( struct ib_device *ibdev ) {
 	assert ( ibdev->open_count == 1 );
 	return 0;
 
-	ibdev->op->close ( ibdev );
- err_open:
 	ib_destroy_mi ( ibdev, ibdev->gsi );
  err_create_gsi:
 	ib_destroy_sma ( ibdev, ibdev->smi );
  err_create_sma:
 	ib_destroy_mi ( ibdev, ibdev->smi );
  err_create_smi:
+	ibdev->op->close ( ibdev );
+ err_open:
 	assert ( ibdev->open_count == 1 );
 	ibdev->open_count = 0;
 	return rc;
@@ -680,6 +686,7 @@ void ib_close ( struct ib_device *ibdev ) {
 		ib_destroy_sma ( ibdev, ibdev->smi );
 		ib_destroy_mi ( ibdev, ibdev->smi );
 		ibdev->op->close ( ibdev );
+		ibdev->port_state = IB_PORT_STATE_DOWN;
 	}
 }
 
@@ -861,15 +868,12 @@ void ib_poll_eq ( struct ib_device *ibdev ) {
 static void ib_step ( struct process *process __unused ) {
 	struct ib_device *ibdev;
 
-	for_each_ibdev ( ibdev )
+	list_for_each_entry ( ibdev, &open_ib_devices, open_list )
 		ib_poll_eq ( ibdev );
 }
 
 /** Infiniband event queue process */
-struct process ib_process __permanent_process = {
-	.list = LIST_HEAD_INIT ( ib_process.list ),
-	.step = ib_step,
-};
+PERMANENT_PROCESS ( ib_process, ib_step );
 
 /***************************************************************************
  *
diff --git a/roms/ipxe/src/net/infiniband/ib_cm.c b/roms/ipxe/src/net/infiniband/ib_cm.c
index 1a0646beba2fa03321bf4e9eba99..797639bc8503876927e7a8250435 100644
--- a/roms/ipxe/src/net/infiniband/ib_cm.c
+++ b/roms/ipxe/src/net/infiniband/ib_cm.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/infiniband/ib_cmrc.c b/roms/ipxe/src/net/infiniband/ib_cmrc.c
index ed388b2f1fa377fc9fe57018c460..1cc0fcfefb6ea9e27b281b9b2971 100644
--- a/roms/ipxe/src/net/infiniband/ib_cmrc.c
+++ b/roms/ipxe/src/net/infiniband/ib_cmrc.c
@@ -92,7 +92,7 @@ struct ib_cmrc_connection {
 /**
  * Shut down CMRC connection gracefully
  *
- * @v process		Process
+ * @v cmrc		Communication-Managed Reliable Connection
  *
  * The Infiniband data structures are not reference-counted or
  * guarded.  It is therefore unsafe to shut them down while we may be
@@ -107,9 +107,7 @@ struct ib_cmrc_connection {
  * connection, ensuring that the structure is not freed before the
  * shutdown process has run.
  */
-static void ib_cmrc_shutdown ( struct process *process ) {
-	struct ib_cmrc_connection *cmrc =
-		container_of ( process, struct ib_cmrc_connection, shutdown );
+static void ib_cmrc_shutdown ( struct ib_cmrc_connection *cmrc ) {
 
 	DBGC ( cmrc, "CMRC %p shutting down\n", cmrc );
 
@@ -119,9 +117,6 @@ static void ib_cmrc_shutdown ( struct process *process ) {
 	ib_destroy_cq ( cmrc->ibdev, cmrc->cq );
 	ib_close ( cmrc->ibdev );
 
-	/* Remove process from run queue */
-	process_del ( &cmrc->shutdown );
-
 	/* Drop the remaining reference */
 	ref_put ( &cmrc->refcnt );
 }
@@ -180,6 +175,9 @@ static void ib_cmrc_changed ( struct ib_device *ibdev __unused,
 		return;
 	}
 
+	/* Notify upper connection of window change */
+	xfer_window_changed ( &cmrc->xfer );
+
 	/* If we are disconnected, close the upper connection */
 	if ( rc_cm != 0 ) {
 		ib_cmrc_close ( cmrc, rc_cm );
@@ -222,13 +220,15 @@ static void ib_cmrc_complete_send ( struct ib_device *ibdev __unused,
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector, or NULL
+ * @v dest		Destination address vector, or NULL
+ * @v source		Source address vector, or NULL
  * @v iobuf		I/O buffer
  * @v rc		Completion status code
  */
 static void ib_cmrc_complete_recv ( struct ib_device *ibdev __unused,
 				    struct ib_queue_pair *qp,
-				    struct ib_address_vector *av __unused,
+				    struct ib_address_vector *dest __unused,
+				    struct ib_address_vector *source __unused,
 				    struct io_buffer *iobuf, int rc ) {
 	struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
 
@@ -259,6 +259,11 @@ static struct ib_completion_queue_operations ib_cmrc_completion_ops = {
 	.complete_recv = ib_cmrc_complete_recv,
 };
 
+/** Infiniband CMRC queue pair operations */
+static struct ib_queue_pair_operations ib_cmrc_queue_pair_ops = {
+	.alloc_iob = alloc_iob,
+};
+
 /**
  * Send data via CMRC
  *
@@ -360,6 +365,11 @@ static struct interface_operation ib_cmrc_xfer_operations[] = {
 static struct interface_descriptor ib_cmrc_xfer_desc =
 	INTF_DESC ( struct ib_cmrc_connection, xfer, ib_cmrc_xfer_operations );
 
+/** CMRC shutdown process descriptor */
+static struct process_descriptor ib_cmrc_shutdown_desc =
+	PROC_DESC_ONCE ( struct ib_cmrc_connection, shutdown,
+			 ib_cmrc_shutdown );
+
 /**
  * Open CMRC connection
  *
@@ -385,7 +395,7 @@ int ib_cmrc_open ( struct interface *xfer, struct ib_device *ibdev,
 	cmrc->ibdev = ibdev;
 	memcpy ( &cmrc->dgid, dgid, sizeof ( cmrc->dgid ) );
 	memcpy ( &cmrc->service_id, service_id, sizeof ( cmrc->service_id ) );
-	process_init_stopped ( &cmrc->shutdown, ib_cmrc_shutdown,
+	process_init_stopped ( &cmrc->shutdown, &ib_cmrc_shutdown_desc,
 			       &cmrc->refcnt );
 
 	/* Open Infiniband device */
@@ -407,7 +417,8 @@ int ib_cmrc_open ( struct interface *xfer, struct ib_device *ibdev,
 
 	/* Create queue pair */
 	cmrc->qp = ib_create_qp ( ibdev, IB_QPT_RC, IB_CMRC_NUM_SEND_WQES,
-				  cmrc->cq, IB_CMRC_NUM_RECV_WQES, cmrc->cq );
+				  cmrc->cq, IB_CMRC_NUM_RECV_WQES, cmrc->cq,
+				  &ib_cmrc_queue_pair_ops );
 	if ( ! cmrc->qp ) {
 		DBGC ( cmrc, "CMRC %p could not create queue pair\n", cmrc );
 		rc = -ENOMEM;
diff --git a/roms/ipxe/src/net/infiniband/ib_mcast.c b/roms/ipxe/src/net/infiniband/ib_mcast.c
index 0f03b54ac94b4261642bf7030724..0a5e72a37b47d14b90d5485fc4eb 100644
--- a/roms/ipxe/src/net/infiniband/ib_mcast.c
+++ b/roms/ipxe/src/net/infiniband/ib_mcast.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/infiniband/ib_mi.c b/roms/ipxe/src/net/infiniband/ib_mi.c
index d4cf58a66ed38f1999340eaa135e..ef6d539f112a8317d392c6e39559 100644
--- a/roms/ipxe/src/net/infiniband/ib_mi.c
+++ b/roms/ipxe/src/net/infiniband/ib_mi.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -111,13 +112,15 @@ static int ib_mi_handle ( struct ib_device *ibdev,
  *
  * @v ibdev		Infiniband device
  * @v qp		Queue pair
- * @v av		Address vector
+ * @v dest		Destination address vector
+ * @v source		Source address vector
  * @v iobuf		I/O buffer
  * @v rc		Completion status code
  */
 static void ib_mi_complete_recv ( struct ib_device *ibdev,
 				  struct ib_queue_pair *qp,
-				  struct ib_address_vector *av,
+				  struct ib_address_vector *dest __unused,
+				  struct ib_address_vector *source,
 				  struct io_buffer *iobuf, int rc ) {
 	struct ib_mad_interface *mi = ib_qp_get_ownerdata ( qp );
 	union ib_mad *mad;
@@ -151,7 +154,7 @@ static void ib_mi_complete_recv ( struct ib_device *ibdev,
 	DBGC2_HDA ( mi, 0, mad, sizeof ( *mad ) );
 
 	/* Handle MAD */
-	if ( ( rc = ib_mi_handle ( ibdev, mi, mad, av ) ) != 0 )
+	if ( ( rc = ib_mi_handle ( ibdev, mi, mad, source ) ) != 0 )
 		goto out;
 
  out:
@@ -163,6 +166,11 @@ static struct ib_completion_queue_operations ib_mi_completion_ops = {
 	.complete_recv = ib_mi_complete_recv,
 };
 
+/** Management interface queue pair operations */
+static struct ib_queue_pair_operations ib_mi_queue_pair_ops = {
+	.alloc_iob = alloc_iob,
+};
+
 /**
  * Transmit MAD
  *
@@ -352,7 +360,8 @@ struct ib_mad_interface * ib_create_mi ( struct ib_device *ibdev,
 
 	/* Create queue pair */
 	mi->qp = ib_create_qp ( ibdev, type, IB_MI_NUM_SEND_WQES, mi->cq,
-				IB_MI_NUM_RECV_WQES, mi->cq );
+				IB_MI_NUM_RECV_WQES, mi->cq,
+				&ib_mi_queue_pair_ops );
 	if ( ! mi->qp ) {
 		DBGC ( mi, "MI %p could not allocate queue pair\n", mi );
 		goto err_create_qp;
diff --git a/roms/ipxe/src/net/infiniband/ib_packet.c b/roms/ipxe/src/net/infiniband/ib_packet.c
index d58e0ad4b08a764043c6a96b1f90..6c850e39b602c5b0f49a32ce89c9 100644
--- a/roms/ipxe/src/net/infiniband/ib_packet.c
+++ b/roms/ipxe/src/net/infiniband/ib_packet.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -41,11 +42,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
  * @v iobuf		I/O buffer to contain headers
  * @v qp		Queue pair
  * @v payload_len	Payload length
- * @v av		Address vector
+ * @v dest		Destination address vector
+ * @ret rc		Return status code
  */
 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 ) {
+	      const struct ib_address_vector *dest ) {
 	struct ib_local_route_header *lrh;
 	struct ib_global_route_header *grh;
 	struct ib_base_transport_header *bth;
@@ -58,7 +60,8 @@ int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
 	unsigned int lnh;
 
 	DBGC2 ( ibdev, "IBDEV %p TX %04x:%08lx => %04x:%08lx (key %08lx)\n",
-		ibdev, ibdev->lid, qp->ext_qpn, av->lid, av->qpn, av->qkey );
+		ibdev, ibdev->lid, qp->ext_qpn, dest->lid, dest->qpn,
+		dest->qkey );
 
 	/* Calculate packet length */
 	pad_len = ( (-payload_len) & 0x3 );
@@ -70,7 +73,7 @@ int ib_push ( struct ib_device *ibdev, struct io_buffer *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 ?
+	grh = ( dest->gid_present ?
 		iob_push ( iobuf, sizeof ( *grh ) ) : NULL );
 	lrh = iob_push ( iobuf, sizeof ( *lrh ) );
 	lrh_len = ( payload_len + iob_len ( iobuf ) - orig_iob_len );
@@ -79,8 +82,8 @@ int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
 	vl = ( ( qp->ext_qpn == IB_QPN_SMI ) ? 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->sl__lnh = ( ( dest->sl << 4 ) | lnh );
+	lrh->dlid = htons ( dest->lid );
 	lrh->length = htons ( lrh_len >> 2 );
 	lrh->slid = htons ( ibdev->lid );
 
@@ -92,18 +95,18 @@ int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
 		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 ) );
+		memcpy ( &grh->dgid, &dest->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->dest_qp = htonl ( dest->qpn );
 	bth->ack__psn = htonl ( ( qp->send.psn++ ) & 0xffffffUL );
 
 	/* Construct DETH */
-	deth->qkey = htonl ( av->qkey );
+	deth->qkey = htonl ( dest->qkey );
 	deth->src_qp = htonl ( qp->ext_qpn );
 
 	DBGCP_HDA ( ibdev, 0, iobuf->data,
@@ -119,11 +122,14 @@ int ib_push ( struct ib_device *ibdev, struct io_buffer *iobuf,
  * @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
+ * @v dest		Destination address vector to fill in
+ * @v source		Source address vector to fill in
+ * @ret rc		Return status code
  */
 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_address_vector *dest,
+	      struct ib_address_vector *source ) {
 	struct ib_local_route_header *lrh;
 	struct ib_global_route_header *grh;
 	struct ib_base_transport_header *bth;
@@ -131,15 +137,14 @@ int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
 	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 ) );
+	memset ( dest, 0, sizeof ( *dest ) );
+	memset ( source, 0, sizeof ( *source ) );
 
 	/* Extract LRH */
 	if ( iob_len ( iobuf ) < sizeof ( *lrh ) ) {
@@ -149,10 +154,11 @@ int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
 	}
 	lrh = iobuf->data;
 	iob_pull ( iobuf, sizeof ( *lrh ) );
-	av->lid = ntohs ( lrh->slid );
-	av->sl = ( lrh->sl__lnh >> 4 );
+	dest->lid = ntohs ( lrh->dlid );
+	dest->sl = ( lrh->sl__lnh >> 4 );
+	source->lid = ntohs ( lrh->slid );
+	source->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 ) ) ) {
@@ -170,8 +176,10 @@ int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
 		}
 		grh = iobuf->data;
 		iob_pull ( iobuf, sizeof ( *grh ) );
-		av->gid_present = 1;
-		memcpy ( &av->gid, &grh->sgid, sizeof ( av->gid ) );
+		dest->gid_present = 1;
+		memcpy ( &dest->gid, &grh->dgid, sizeof ( dest->gid ) );
+		source->gid_present = 1;
+		memcpy ( &source->gid, &grh->sgid, sizeof ( source->gid ) );
 	} else {
 		grh = NULL;
 	}
@@ -189,7 +197,7 @@ int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
 		       ibdev, bth->opcode );
 		return -ENOTSUP;
 	}
-	qpn = ntohl ( bth->dest_qp );
+	dest->qpn = ntohl ( bth->dest_qp );
 
 	/* Extract DETH */
 	if ( iob_len ( iobuf ) < sizeof ( *deth ) ) {
@@ -199,8 +207,8 @@ int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
 	}
 	deth = iobuf->data;
 	iob_pull ( iobuf, sizeof ( *deth ) );
-	av->qpn = ntohl ( deth->src_qp );
-	av->qkey = ntohl ( deth->qkey );
+	source->qpn = ntohl ( deth->src_qp );
+	source->qkey = ntohl ( deth->qkey );
 
 	/* Calculate payload length, if applicable */
 	if ( payload_len ) {
@@ -212,7 +220,7 @@ int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
 
 	/* Determine destination QP, if applicable */
 	if ( qp ) {
-		if ( IB_LID_MULTICAST ( lid ) && grh ) {
+		if ( IB_LID_MULTICAST ( dest->lid ) && grh ) {
 			if ( ! ( *qp = ib_find_qp_mgid ( ibdev, &grh->dgid ))){
 				DBGC ( ibdev, "IBDEV %p RX for unknown MGID "
 				       IB_GID_FMT "\n",
@@ -220,9 +228,9 @@ int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
 				return -ENODEV;
 			}
 		} else {
-			if ( ! ( *qp = ib_find_qp_qpn ( ibdev, qpn ) ) ) {
+			if ( ! ( *qp = ib_find_qp_qpn ( ibdev, dest->qpn ) ) ) {
 				DBGC ( ibdev, "IBDEV %p RX for nonexistent "
-				       "QPN %lx\n", ibdev, qpn );
+				       "QPN %lx\n", ibdev, dest->qpn );
 				return -ENODEV;
 			}
 		}
@@ -230,9 +238,9 @@ int ib_pull ( struct ib_device *ibdev, struct io_buffer *iobuf,
 	}
 
 	DBGC2 ( ibdev, "IBDEV %p RX %04x:%08lx <= %04x:%08lx (key %08x)\n",
-		ibdev, lid, ( IB_LID_MULTICAST( lid ) ?
-			      ( qp ? (*qp)->ext_qpn : -1UL ) : qpn ),
-		av->lid, av->qpn, ntohl ( deth->qkey ) );
+		ibdev, dest->lid, ( IB_LID_MULTICAST ( dest->lid ) ?
+			      ( qp ? (*qp)->ext_qpn : -1UL ) : dest->qpn ),
+		source->lid, source->qpn, ntohl ( deth->qkey ) );
 	DBGCP_HDA ( ibdev, 0,
 		    ( iobuf->data - ( orig_iob_len - iob_len ( iobuf ) ) ),
 		    ( orig_iob_len - iob_len ( iobuf ) ) );
diff --git a/roms/ipxe/src/net/infiniband/ib_pathrec.c b/roms/ipxe/src/net/infiniband/ib_pathrec.c
index 7b9146547f9bbcda383b5c4a5b6f..1b95cbfa8c6de0ffd0cd312ec2c0 100644
--- a/roms/ipxe/src/net/infiniband/ib_pathrec.c
+++ b/roms/ipxe/src/net/infiniband/ib_pathrec.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/infiniband/ib_sma.c b/roms/ipxe/src/net/infiniband/ib_sma.c
index 1f3c6d8041d4de979deadb24bd31..86553732ae7c619958563311ef2f 100644
--- a/roms/ipxe/src/net/infiniband/ib_sma.c
+++ b/roms/ipxe/src/net/infiniband/ib_sma.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/infiniband/ib_smc.c b/roms/ipxe/src/net/infiniband/ib_smc.c
index 8196cb7e39c3f82aba86596f54b8..4d947d56806bc5b559a2fdd4d0a8 100644
--- a/roms/ipxe/src/net/infiniband/ib_smc.c
+++ b/roms/ipxe/src/net/infiniband/ib_smc.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/iobpad.c b/roms/ipxe/src/net/iobpad.c
index f83c76d87fb20e82fa98236fa553..9cc8328e904f99ad22b78ecd439c 100644
--- a/roms/ipxe/src/net/iobpad.c
+++ b/roms/ipxe/src/net/iobpad.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/ipv4.c b/roms/ipxe/src/net/ipv4.c
index b2d51ada42854b24bd6a32ecd904..791d419514440152a6182c4ca928 100644
--- a/roms/ipxe/src/net/ipv4.c
+++ b/roms/ipxe/src/net/ipv4.c
@@ -14,6 +14,7 @@
 #include <ipxe/tcpip.h>
 #include <ipxe/dhcp.h>
 #include <ipxe/settings.h>
+#include <ipxe/timer.h>
 
 /** @file
  *
@@ -23,14 +24,17 @@
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
-/* Unique IP datagram identification number */
-static uint16_t next_ident = 0;
+/* Unique IP datagram identification number (high byte) */
+static uint8_t next_ident_high = 0;
 
 /** List of IPv4 miniroutes */
 struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes );
 
 /** List of fragment reassembly buffers */
-static LIST_HEAD ( frag_buffers );
+static LIST_HEAD ( ipv4_fragments );
+
+/** Fragment reassembly timeout */
+#define IP_FRAG_TIMEOUT ( TICKS_PER_SEC / 2 )
 
 /**
  * Add IPv4 minirouting table entry
@@ -46,16 +50,16 @@ add_ipv4_miniroute ( struct net_device *netdev, struct in_addr address,
 		     struct in_addr netmask, struct in_addr gateway ) {
 	struct ipv4_miniroute *miniroute;
 
-	DBG ( "IPv4 add %s", inet_ntoa ( address ) );
-	DBG ( "/%s ", inet_ntoa ( netmask ) );
+	DBGC ( netdev, "IPv4 add %s", inet_ntoa ( address ) );
+	DBGC ( netdev, "/%s ", inet_ntoa ( netmask ) );
 	if ( gateway.s_addr )
-		DBG ( "gw %s ", inet_ntoa ( gateway ) );
-	DBG ( "via %s\n", netdev->name );
+		DBGC ( netdev, "gw %s ", inet_ntoa ( gateway ) );
+	DBGC ( netdev, "via %s\n", netdev->name );
 
 	/* Allocate and populate miniroute structure */
 	miniroute = malloc ( sizeof ( *miniroute ) );
 	if ( ! miniroute ) {
-		DBG ( "IPv4 could not add miniroute\n" );
+		DBGC ( netdev, "IPv4 could not add miniroute\n" );
 		return NULL;
 	}
 
@@ -83,12 +87,13 @@ add_ipv4_miniroute ( struct net_device *netdev, struct in_addr address,
  * @v miniroute		Routing table entry
  */
 static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
+	struct net_device *netdev = miniroute->netdev;
 
-	DBG ( "IPv4 del %s", inet_ntoa ( miniroute->address ) );
-	DBG ( "/%s ", inet_ntoa ( miniroute->netmask ) );
+	DBGC ( netdev, "IPv4 del %s", inet_ntoa ( miniroute->address ) );
+	DBGC ( netdev, "/%s ", inet_ntoa ( miniroute->netmask ) );
 	if ( miniroute->gateway.s_addr )
-		DBG ( "gw %s ", inet_ntoa ( miniroute->gateway ) );
-	DBG ( "via %s\n", miniroute->netdev->name );
+		DBGC ( netdev, "gw %s ", inet_ntoa ( miniroute->gateway ) );
+	DBGC ( netdev, "via %s\n", miniroute->netdev->name );
 
 	netdev_put ( miniroute->netdev );
 	list_del ( &miniroute->list );
@@ -110,10 +115,6 @@ static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
 	int local;
 	int has_gw;
 
-	/* Never attempt to route the broadcast address */
-	if ( dest->s_addr == INADDR_BROADCAST )
-		return NULL;
-
 	/* Find first usable route in routing table */
 	list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
 		if ( ! netdev_is_open ( miniroute->netdev ) )
@@ -132,103 +133,128 @@ static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
 }
 
 /**
- * Fragment reassembly counter timeout
+ * Expire fragment reassembly buffer
  *
- * @v timer	Retry timer
- * @v over	If asserted, the timer is greater than @c MAX_TIMEOUT 
+ * @v timer		Retry timer
+ * @v fail		Failure indicator
  */
-static void ipv4_frag_expired ( struct retry_timer *timer __unused,
-				int over ) {
-	if ( over ) {
-		DBG ( "Fragment reassembly timeout" );
-		/* Free the fragment buffer */
-	}
+static void ipv4_fragment_expired ( struct retry_timer *timer,
+				    int fail __unused ) {
+	struct ipv4_fragment *frag =
+		container_of ( timer, struct ipv4_fragment, timer );
+	struct iphdr *iphdr = frag->iobuf->data;
+
+	DBGC ( iphdr->src, "IPv4 fragment %04x expired\n",
+	       ntohs ( iphdr->ident ) );
+	free_iob ( frag->iobuf );
+	list_del ( &frag->list );
+	free ( frag );
 }
 
 /**
- * Free fragment buffer
+ * Find matching fragment reassembly buffer
  *
- * @v fragbug	Fragment buffer
+ * @v iphdr		IPv4 header
+ * @ret frag		Fragment reassembly buffer, or NULL
  */
-static void free_fragbuf ( struct frag_buffer *fragbuf ) {
-	free ( fragbuf );
+static struct ipv4_fragment * ipv4_fragment ( struct iphdr *iphdr ) {
+	struct ipv4_fragment *frag;
+	struct iphdr *frag_iphdr;
+
+	list_for_each_entry ( frag, &ipv4_fragments, list ) {
+		frag_iphdr = frag->iobuf->data;
+
+		if ( ( iphdr->src.s_addr == frag_iphdr->src.s_addr ) &&
+		     ( iphdr->ident == frag_iphdr->ident ) ) {
+			return frag;
+		}
+	}
+
+	return NULL;
 }
 
 /**
  * Fragment reassembler
  *
- * @v iobuf		I/O buffer, fragment of the datagram
- * @ret frag_iob	Reassembled packet, or NULL
+ * @v iobuf		I/O buffer
+ * @ret iobuf		Reassembled packet, or NULL
  */
-static struct io_buffer * ipv4_reassemble ( struct io_buffer * iobuf ) {
+static struct io_buffer * ipv4_reassemble ( struct io_buffer *iobuf ) {
 	struct iphdr *iphdr = iobuf->data;
-	struct frag_buffer *fragbuf;
-	
-	/**
-	 * Check if the fragment belongs to any fragment series
-	 */
-	list_for_each_entry ( fragbuf, &frag_buffers, list ) {
-		if ( fragbuf->ident == iphdr->ident &&
-		     fragbuf->src.s_addr == iphdr->src.s_addr ) {
-			/**
-			 * Check if the packet is the expected fragment
-			 * 
-			 * The offset of the new packet must be equal to the
-			 * length of the data accumulated so far (the length of
-			 * the reassembled I/O buffer
-			 */
-			if ( iob_len ( fragbuf->frag_iob ) == 
-			      ( iphdr->frags & IP_MASK_OFFSET ) ) {
-				/**
-				 * Append the contents of the fragment to the
-				 * reassembled I/O buffer
-				 */
-				iob_pull ( iobuf, sizeof ( *iphdr ) );
-				memcpy ( iob_put ( fragbuf->frag_iob,
-							iob_len ( iobuf ) ),
-					 iobuf->data, iob_len ( iobuf ) );
-				free_iob ( iobuf );
-
-				/** Check if the fragment series is over */
-				if ( ! ( iphdr->frags & IP_MASK_MOREFRAGS ) ) {
-					iobuf = fragbuf->frag_iob;
-					free_fragbuf ( fragbuf );
-					return iobuf;
-				}
-
-			} else {
-				/* Discard the fragment series */
-				free_fragbuf ( fragbuf );
-				free_iob ( iobuf );
-			}
-			return NULL;
-		}
+	size_t offset = ( ( ntohs ( iphdr->frags ) & IP_MASK_OFFSET ) << 3 );
+	unsigned int more_frags = ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ));
+	size_t hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
+	struct ipv4_fragment *frag;
+	size_t expected_offset;
+	struct io_buffer *new_iobuf;
+
+	/* Find matching fragment reassembly buffer, if any */
+	frag = ipv4_fragment ( iphdr );
+
+	/* Drop out-of-order fragments */
+	expected_offset = ( frag ? frag->offset : 0 );
+	if ( offset != expected_offset ) {
+		DBGC ( iphdr->src, "IPv4 dropping out-of-sequence fragment "
+		       "%04x (%zd+%zd, expected %zd)\n",
+		       ntohs ( iphdr->ident ), offset,
+		      ( iob_len ( iobuf ) - hdrlen ), expected_offset );
+		goto drop;
 	}
-	
-	/** Check if the fragment is the first in the fragment series */
-	if ( iphdr->frags & IP_MASK_MOREFRAGS &&
-			( ( iphdr->frags & IP_MASK_OFFSET ) == 0 ) ) {
-	
-		/** Create a new fragment buffer */
-		fragbuf = ( struct frag_buffer* ) malloc ( sizeof( *fragbuf ) );
-		fragbuf->ident = iphdr->ident;
-		fragbuf->src = iphdr->src;
-
-		/* Set up the reassembly I/O buffer */
-		fragbuf->frag_iob = alloc_iob ( IP_FRAG_IOB_SIZE );
-		iob_pull ( iobuf, sizeof ( *iphdr ) );
-		memcpy ( iob_put ( fragbuf->frag_iob, iob_len ( iobuf ) ),
+
+	/* Create or extend fragment reassembly buffer as applicable */
+	if ( frag == NULL ) {
+
+		/* Create new fragment reassembly buffer */
+		frag = zalloc ( sizeof ( *frag ) );
+		if ( ! frag )
+			goto drop;
+		list_add ( &frag->list, &ipv4_fragments );
+		frag->iobuf = iobuf;
+		frag->offset = ( iob_len ( iobuf ) - hdrlen );
+		timer_init ( &frag->timer, ipv4_fragment_expired, NULL );
+
+	} else {
+
+		/* Extend reassembly buffer */
+		iob_pull ( iobuf, hdrlen );
+		new_iobuf = alloc_iob ( iob_len ( frag->iobuf ) +
+					iob_len ( iobuf ) );
+		if ( ! new_iobuf ) {
+			DBGC ( iphdr->src, "IPv4 could not extend reassembly "
+			       "buffer to %zd bytes\n",
+			       iob_len ( frag->iobuf ) + iob_len ( iobuf ) );
+			goto drop;
+		}
+		memcpy ( iob_put ( new_iobuf, iob_len ( frag->iobuf ) ),
+			 frag->iobuf->data, iob_len ( frag->iobuf ) );
+		memcpy ( iob_put ( new_iobuf, iob_len ( iobuf ) ),
 			 iobuf->data, iob_len ( iobuf ) );
+		free_iob ( frag->iobuf );
+		frag->iobuf = new_iobuf;
+		frag->offset += iob_len ( iobuf );
 		free_iob ( iobuf );
+		iphdr = frag->iobuf->data;
+		iphdr->len = ntohs ( iob_len ( frag->iobuf ) );
+
+		/* Stop fragment reassembly timer */
+		stop_timer ( &frag->timer );
+
+		/* If this is the final fragment, return it */
+		if ( ! more_frags ) {
+			iobuf = frag->iobuf;
+			list_del ( &frag->list );
+			free ( frag );
+			return iobuf;
+		}
+	}
 
-		/* Set the reassembly timer */
-		timer_init ( &fragbuf->frag_timer, ipv4_frag_expired, NULL );
-		start_timer_fixed ( &fragbuf->frag_timer, IP_FRAG_TIMEOUT );
+	/* (Re)start fragment reassembly timer */
+	start_timer_fixed ( &frag->timer, IP_FRAG_TIMEOUT );
 
-		/* Add the fragment buffer to the list of fragment buffers */
-		list_add ( &fragbuf->list, &frag_buffers );
-	}
-	
+	return NULL;
+
+ drop:
+	free_iob ( iobuf );
 	return NULL;
 }
 
@@ -255,33 +281,6 @@ static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) {
 	return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) );
 }
 
-/**
- * Determine link-layer address
- *
- * @v dest		IPv4 destination address
- * @v src		IPv4 source address
- * @v netdev		Network device
- * @v ll_dest		Link-layer destination address buffer
- * @ret rc		Return status code
- */
-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;
-
-	if ( dest.s_addr == INADDR_BROADCAST ) {
-		/* Broadcast address */
-		memcpy ( ll_dest, netdev->ll_broadcast,
-			 ll_protocol->ll_addr_len );
-		return 0;
-	} else if ( IN_MULTICAST ( ntohl ( dest.s_addr ) ) ) {
-		return ll_protocol->mc_hash ( AF_INET, &dest, ll_dest );
-	} else {
-		/* Unicast address: resolve via ARP */
-		return arp_resolve ( netdev, &ipv4_protocol, &dest,
-				     &src, ll_dest );
-	}
-}
-
 /**
  * Transmit IP packet
  *
@@ -306,7 +305,9 @@ static int ipv4_tx ( struct io_buffer *iobuf,
 	struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
 	struct ipv4_miniroute *miniroute;
 	struct in_addr next_hop;
-	uint8_t ll_dest[MAX_LL_ADDR_LEN];
+	struct in_addr netmask = { .s_addr = 0 };
+	uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
+	const void *ll_dest;
 	int rc;
 
 	/* Fill up the IP header, except source address */
@@ -314,7 +315,6 @@ static int ipv4_tx ( struct io_buffer *iobuf,
 	iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) );
 	iphdr->service = IP_TOS;
 	iphdr->len = htons ( iob_len ( iobuf ) );	
-	iphdr->ident = htons ( ++next_ident );
 	iphdr->ttl = IP_TTL;
 	iphdr->protocol = tcpip_protocol->tcpip_proto;
 	iphdr->dest = sin_dest->sin_addr;
@@ -327,21 +327,23 @@ static int ipv4_tx ( struct io_buffer *iobuf,
 	     ( ! IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) &&
 	     ( ( miniroute = ipv4_route ( &next_hop ) ) != NULL ) ) {
 		iphdr->src = miniroute->address;
+		netmask = miniroute->netmask;
 		netdev = miniroute->netdev;
 	}
 	if ( ! netdev ) {
-		DBG ( "IPv4 has no route to %s\n", inet_ntoa ( iphdr->dest ) );
+		DBGC ( sin_dest->sin_addr, "IPv4 has no route to %s\n",
+		       inet_ntoa ( iphdr->dest ) );
 		rc = -ENETUNREACH;
 		goto err;
 	}
 
-	/* Determine link-layer destination address */
-	if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, netdev,
-				   ll_dest ) ) != 0 ) {
-		DBG ( "IPv4 has no link-layer address for %s: %s\n",
-		      inet_ntoa ( next_hop ), strerror ( rc ) );
-		goto err;
-	}
+	/* (Ab)use the "ident" field to convey metadata about the
+	 * network device statistics into packet traces.  Useful for
+	 * extracting debug information from non-debug builds.
+	 */
+	iphdr->ident = htons ( ( (++next_ident_high) << 8 ) |
+			       ( ( netdev->rx_stats.bad & 0xf ) << 4 ) |
+			       ( ( netdev->rx_stats.good & 0xf ) << 0 ) );
 
 	/* Fix up checksums */
 	if ( trans_csum )
@@ -349,17 +351,48 @@ static int ipv4_tx ( struct io_buffer *iobuf,
 	iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
 
 	/* Print IP4 header for debugging */
-	DBG ( "IPv4 TX %s->", inet_ntoa ( iphdr->src ) );
-	DBG ( "%s len %d proto %d id %04x csum %04x\n",
-	      inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ), iphdr->protocol,
-	      ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
-
-	/* Hand off to link layer */
-	if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest,
-			     netdev->ll_addr ) ) != 0 ) {
-		DBG ( "IPv4 could not transmit packet via %s: %s\n",
-		      netdev->name, strerror ( rc ) );
-		return rc;
+	DBGC2 ( sin_dest->sin_addr, "IPv4 TX %s->", inet_ntoa ( iphdr->src ) );
+	DBGC2 ( sin_dest->sin_addr, "%s len %d proto %d id %04x csum %04x\n",
+		inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ),
+		iphdr->protocol, ntohs ( iphdr->ident ),
+		ntohs ( iphdr->chksum ) );
+
+	/* Calculate link-layer destination address, if possible */
+	if ( ( ( next_hop.s_addr ^ INADDR_BROADCAST ) & ~netmask.s_addr ) == 0){
+		/* Broadcast address */
+		ll_dest = netdev->ll_broadcast;
+	} else if ( IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) {
+		/* Multicast address */
+		if ( ( rc = netdev->ll_protocol->mc_hash ( AF_INET, &next_hop,
+							   ll_dest_buf ) ) !=0){
+			DBGC ( sin_dest->sin_addr, "IPv4 could not hash "
+			       "multicast %s: %s\n",
+			       inet_ntoa ( next_hop ), strerror ( rc ) );
+			return rc;
+		}
+		ll_dest = ll_dest_buf;
+	} else {
+		/* Unicast address */
+		ll_dest = NULL;
+	}
+
+	/* Hand off to link layer (via ARP if applicable) */
+	if ( ll_dest ) {
+		if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest,
+				     netdev->ll_addr ) ) != 0 ) {
+			DBGC ( sin_dest->sin_addr, "IPv4 could not transmit "
+			       "packet via %s: %s\n",
+			       netdev->name, strerror ( rc ) );
+			return rc;
+		}
+	} else {
+		if ( ( rc = arp_tx ( iobuf, netdev, &ipv4_protocol, &next_hop,
+				     &iphdr->src, netdev->ll_addr ) ) != 0 ) {
+			DBGC ( sin_dest->sin_addr, "IPv4 could not transmit "
+			       "packet via %s: %s\n",
+			       netdev->name, strerror ( rc ) );
+			return rc;
+		}
 	}
 
 	return 0;
@@ -369,21 +402,60 @@ static int ipv4_tx ( struct io_buffer *iobuf,
 	return rc;
 }
 
+/**
+ * Check if network device has any IPv4 address
+ *
+ * @v netdev		Network device
+ * @ret has_any_addr	Network device has any IPv4 address
+ */
+int ipv4_has_any_addr ( struct net_device *netdev ) {
+	struct ipv4_miniroute *miniroute;
+
+	list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
+		if ( miniroute->netdev == netdev )
+			return 1;
+	}
+	return 0;
+}
+
+/**
+ * Check if network device has a specific IPv4 address
+ *
+ * @v netdev		Network device
+ * @v addr		IPv4 address
+ * @ret has_addr	Network device has this IPv4 address
+ */
+static int ipv4_has_addr ( struct net_device *netdev, struct in_addr addr ) {
+	struct ipv4_miniroute *miniroute;
+
+	list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
+		if ( ( miniroute->netdev == netdev ) &&
+		     ( miniroute->address.s_addr == addr.s_addr ) ) {
+			/* Found matching address */
+			return 1;
+		}
+	}
+	return 0;
+}
+
 /**
  * Process incoming packets
  *
- * @v iobuf	I/O buffer
- * @v netdev	Network device
- * @v ll_dest	Link-layer destination address
- * @v ll_source	Link-layer destination source
+ * @v iobuf		I/O buffer
+ * @v netdev		Network device
+ * @v ll_dest		Link-layer destination address
+ * @v ll_source		Link-layer destination source
+ * @v flags		Packet flags
+ * @ret rc		Return status code
  *
  * This function expects an IP4 network datagram. It processes the headers 
  * and sends it to the transport layer.
  */
 static int ipv4_rx ( struct io_buffer *iobuf,
-		     struct net_device *netdev __unused,
+		     struct net_device *netdev,
 		     const void *ll_dest __unused,
-		     const void *ll_source __unused ) {
+		     const void *ll_source __unused,
+		     unsigned int flags ) {
 	struct iphdr *iphdr = iobuf->data;
 	size_t hdrlen;
 	size_t len;
@@ -397,77 +469,88 @@ static int ipv4_rx ( struct io_buffer *iobuf,
 
 	/* Sanity check the IPv4 header */
 	if ( iob_len ( iobuf ) < sizeof ( *iphdr ) ) {
-		DBG ( "IPv4 packet too short at %zd bytes (min %zd bytes)\n",
-		      iob_len ( iobuf ), sizeof ( *iphdr ) );
+		DBGC ( iphdr->src, "IPv4 packet too short at %zd bytes (min "
+		       "%zd bytes)\n", iob_len ( iobuf ), sizeof ( *iphdr ) );
 		goto err;
 	}
 	if ( ( iphdr->verhdrlen & IP_MASK_VER ) != IP_VER ) {
-		DBG ( "IPv4 version %#02x not supported\n", iphdr->verhdrlen );
+		DBGC ( iphdr->src, "IPv4 version %#02x not supported\n",
+		       iphdr->verhdrlen );
 		goto err;
 	}
 	hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
 	if ( hdrlen < sizeof ( *iphdr ) ) {
-		DBG ( "IPv4 header too short at %zd bytes (min %zd bytes)\n",
-		      hdrlen, sizeof ( *iphdr ) );
+		DBGC ( iphdr->src, "IPv4 header too short at %zd bytes (min "
+		       "%zd bytes)\n", hdrlen, sizeof ( *iphdr ) );
 		goto err;
 	}
 	if ( hdrlen > iob_len ( iobuf ) ) {
-		DBG ( "IPv4 header too long at %zd bytes "
-		      "(packet is %zd bytes)\n", hdrlen, iob_len ( iobuf ) );
+		DBGC ( iphdr->src, "IPv4 header too long at %zd bytes "
+		       "(packet is %zd bytes)\n", hdrlen, iob_len ( iobuf ) );
 		goto err;
 	}
 	if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
-		DBG ( "IPv4 checksum incorrect (is %04x including checksum "
-		      "field, should be 0000)\n", csum );
+		DBGC ( iphdr->src, "IPv4 checksum incorrect (is %04x "
+		       "including checksum field, should be 0000)\n", csum );
 		goto err;
 	}
 	len = ntohs ( iphdr->len );
 	if ( len < hdrlen ) {
-		DBG ( "IPv4 length too short at %zd bytes "
-		      "(header is %zd bytes)\n", len, hdrlen );
+		DBGC ( iphdr->src, "IPv4 length too short at %zd bytes "
+		       "(header is %zd bytes)\n", len, hdrlen );
 		goto err;
 	}
 	if ( len > iob_len ( iobuf ) ) {
-		DBG ( "IPv4 length too long at %zd bytes "
-		      "(packet is %zd bytes)\n", len, iob_len ( iobuf ) );
+		DBGC ( iphdr->src, "IPv4 length too long at %zd bytes "
+		       "(packet is %zd bytes)\n", len, iob_len ( iobuf ) );
 		goto err;
 	}
 
-	/* Print IPv4 header for debugging */
-	DBG ( "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
-	DBG ( "%s len %d proto %d id %04x csum %04x\n",
-	      inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
-	      ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
-
-	/* Truncate packet to correct length, calculate pseudo-header
-	 * checksum and then strip off the IPv4 header.
-	 */
+	/* Truncate packet to correct length */
 	iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) );
-	pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
-	iob_pull ( iobuf, hdrlen );
 
-	/* Fragment reassembly */
-	if ( ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ) || 
-	     ( ( iphdr->frags & htons ( IP_MASK_OFFSET ) ) != 0 ) ) {
-		/* Pass the fragment to ipv4_reassemble() which either
-		 * returns a fully reassembled I/O buffer or NULL.
+	/* Print IPv4 header for debugging */
+	DBGC2 ( iphdr->src, "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
+	DBGC2 ( iphdr->src, "%s len %d proto %d id %04x csum %04x\n",
+		inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
+		ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
+
+	/* Discard unicast packets not destined for us */
+	if ( ( ! ( flags & LL_MULTICAST ) ) &&
+	     ipv4_has_any_addr ( netdev ) &&
+	     ( ! ipv4_has_addr ( netdev, iphdr->dest ) ) ) {
+		DBGC ( iphdr->src, "IPv4 discarding non-local unicast packet "
+		       "for %s\n", inet_ntoa ( iphdr->dest ) );
+		goto err;
+	}
+
+	/* Perform fragment reassembly if applicable */
+	if ( iphdr->frags & htons ( IP_MASK_OFFSET | IP_MASK_MOREFRAGS ) ) {
+		/* Pass the fragment to ipv4_reassemble() which returns
+		 * either a fully reassembled I/O buffer or NULL.
 		 */
 		iobuf = ipv4_reassemble ( iobuf );
 		if ( ! iobuf )
 			return 0;
+		iphdr = iobuf->data;
+		hdrlen = ( ( iphdr->verhdrlen & IP_MASK_HLEN ) * 4 );
 	}
 
-	/* Construct socket addresses and hand off to transport layer */
+	/* Construct socket addresses, calculate pseudo-header
+	 * checksum, and hand off to transport layer
+	 */
 	memset ( &src, 0, sizeof ( src ) );
 	src.sin.sin_family = AF_INET;
 	src.sin.sin_addr = iphdr->src;
 	memset ( &dest, 0, sizeof ( dest ) );
 	dest.sin.sin_family = AF_INET;
 	dest.sin.sin_addr = iphdr->dest;
+	pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
+	iob_pull ( iobuf, hdrlen );
 	if ( ( rc = tcpip_rx ( iobuf, iphdr->protocol, &src.st,
 			       &dest.st, pshdr_csum ) ) != 0 ) {
-		DBG ( "IPv4 received packet rejected by stack: %s\n",
-		      strerror ( rc ) );
+		DBGC ( src.sin.sin_addr, "IPv4 received packet rejected by "
+		       "stack: %s\n", strerror ( rc ) );
 		return rc;
 	}
 
@@ -487,15 +570,10 @@ static int ipv4_rx ( struct io_buffer *iobuf,
  */
 static int ipv4_arp_check ( struct net_device *netdev, const void *net_addr ) {
 	const struct in_addr *address = net_addr;
-	struct ipv4_miniroute *miniroute;
 
-	list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
-		if ( ( miniroute->netdev == netdev ) &&
-		     ( miniroute->address.s_addr == address->s_addr ) ) {
-			/* Found matching address */
-			return 0;
-		}
-	}
+	if ( ipv4_has_addr ( netdev, *address ) )
+		return 0;
+
 	return -ENOENT;
 }
 
diff --git a/roms/ipxe/src/net/ipv6.c b/roms/ipxe/src/net/ipv6.c
index 712aa49e5459de2db9cc059747c6..57bf94d8d9d5c1b891c168eb1d7e 100644
--- a/roms/ipxe/src/net/ipv6.c
+++ b/roms/ipxe/src/net/ipv6.c
@@ -288,13 +288,15 @@ static int ipv6_process_nxt_hdr ( struct io_buffer *iobuf, uint8_t nxt_hdr,
  * @v netdev		Network device
  * @v ll_dest		Link-layer destination address
  * @v ll_source		Link-layer source address
+ * @v flags		Packet flags
  *
  * This function processes a IPv6 packet
  */
 static int ipv6_rx ( struct io_buffer *iobuf,
 		     __unused struct net_device *netdev,
 		     __unused const void *ll_dest,
-		     __unused const void *ll_source ) {
+		     __unused const void *ll_source,
+		     __unused unsigned int flags ) {
 
 	struct ip6_header *ip6hdr = iobuf->data;
 	union {
diff --git a/roms/ipxe/src/net/mii.c b/roms/ipxe/src/net/mii.c
deleted file mode 100644
index dbaecf11c5a08950f3cecc59677003c7849136eb..0000000000000000000000000000000000000000
--- a/roms/ipxe/src/net/mii.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
-
-	mii.c: MII interface library
-
-	Ported to iPXE by Daniel Verkamp <daniel@drv.nu>
-	from Linux drivers/net/mii.c
-
-	Maintained by Jeff Garzik <jgarzik@pobox.com>
-	Copyright 2001,2002 Jeff Garzik
-
-	Various code came from myson803.c and other files by
-	Donald Becker.  Copyright:
-
-		Written 1998-2002 by Donald Becker.
-
-		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.
-		This file is not a complete program and may only be
-		used when the entire operating system is licensed
-		under the GPL.
-
-		The author may be reached as becker@scyld.com, or C/O
-		Scyld Computing Corporation
-		410 Severn Ave., Suite 210
-		Annapolis MD 21403
-
-*/
-
-#include <mii.h>
-
-/**
- * mii_link_ok - is link status up/ok
- * @mii: the MII interface
- *
- * Returns 1 if the MII reports link status up/ok, 0 otherwise.
- */
-int
-mii_link_ok ( struct mii_if_info *mii )
-{
-	/* first, a dummy read, needed to latch some MII phys */
-	mii->mdio_read ( mii->dev, mii->phy_id, MII_BMSR );
-	if ( mii->mdio_read ( mii->dev, mii->phy_id, MII_BMSR ) & BMSR_LSTATUS )
-		return 1;
-	return 0;
-}
-
-/**
- * mii_check_link - check MII link status
- * @mii: MII interface
- *
- * If the link status changed (previous != current), call
- * netif_carrier_on() if current link status is Up or call
- * netif_carrier_off() if current link status is Down.
- */
-void
-mii_check_link ( struct mii_if_info *mii )
-{
-	int cur_link = mii_link_ok ( mii );
-	int prev_link = netdev_link_ok ( mii->dev );
-
-	if ( cur_link && !prev_link )
-		netdev_link_up ( mii->dev );
-	else if (prev_link && !cur_link)
-		netdev_link_down ( mii->dev );
-}
-
-
-/**
- * mii_check_media - check the MII interface for a duplex change
- * @mii: the MII interface
- * @ok_to_print: OK to print link up/down messages
- * @init_media: OK to save duplex mode in @mii
- *
- * Returns 1 if the duplex mode changed, 0 if not.
- * If the media type is forced, always returns 0.
- */
-unsigned int
-mii_check_media ( struct mii_if_info *mii,
-                  unsigned int ok_to_print,
-                  unsigned int init_media )
-{
-	unsigned int old_carrier, new_carrier;
-	int advertise, lpa, media, duplex;
-	int lpa2 = 0;
-
-	/* if forced media, go no further */
-	if (mii->force_media)
-		return 0; /* duplex did not change */
-
-	/* check current and old link status */
-	old_carrier = netdev_link_ok ( mii->dev ) ? 1 : 0;
-	new_carrier = (unsigned int) mii_link_ok ( mii );
-
-	/* if carrier state did not change, this is a "bounce",
-	 * just exit as everything is already set correctly
-	 */
-	if ( ( ! init_media ) && ( old_carrier == new_carrier ) )
-		return 0; /* duplex did not change */
-
-	/* no carrier, nothing much to do */
-	if ( ! new_carrier ) {
-		netdev_link_down ( mii->dev );
-		if ( ok_to_print )
-			DBG ( "%s: link down\n", mii->dev->name);
-		return 0; /* duplex did not change */
-	}
-
-	/*
-	 * we have carrier, see who's on the other end
-	 */
-	netdev_link_up ( mii->dev );
-
-	/* get MII advertise and LPA values */
-	if ( ( ! init_media ) && ( mii->advertising ) ) {
-		advertise = mii->advertising;
-	} else {
-		advertise = mii->mdio_read ( mii->dev, mii->phy_id, MII_ADVERTISE );
-		mii->advertising = advertise;
-	}
-	lpa = mii->mdio_read ( mii->dev, mii->phy_id, MII_LPA );
-	if ( mii->supports_gmii )
-		lpa2 = mii->mdio_read ( mii->dev, mii->phy_id, MII_STAT1000 );
-
-	/* figure out media and duplex from advertise and LPA values */
-	media = mii_nway_result ( lpa & advertise );
-	duplex = ( media & ADVERTISE_FULL ) ? 1 : 0;
-	if ( lpa2 & LPA_1000FULL )
-		duplex = 1;
-
-	if ( ok_to_print )
-		DBG ( "%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n",
-		       mii->dev->name,
-		       lpa2 & ( LPA_1000FULL | LPA_1000HALF ) ? "1000" :
-		       media & ( ADVERTISE_100FULL | ADVERTISE_100HALF ) ? "100" : "10",
-		       duplex ? "full" : "half",
-		       lpa);
-
-	if ( ( init_media ) || ( mii->full_duplex != duplex ) ) {
-		mii->full_duplex = duplex;
-		return 1; /* duplex changed */
-	}
-
-	return 0; /* duplex did not change */
-}
diff --git a/roms/ipxe/src/net/netdev_settings.c b/roms/ipxe/src/net/netdev_settings.c
index 2ef3984d929b6192e6364e3375a1..9efe6811c3ab8b8b69122d4af277 100644
--- a/roms/ipxe/src/net/netdev_settings.c
+++ b/roms/ipxe/src/net/netdev_settings.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/netdevice.c b/roms/ipxe/src/net/netdevice.c
index 9b0ea199a4c968855c15ca34165c..e9cbb9e96b438b6558d93881f0ff 100644
--- a/roms/ipxe/src/net/netdevice.c
+++ b/roms/ipxe/src/net/netdevice.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -32,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/init.h>
 #include <ipxe/device.h>
 #include <ipxe/errortab.h>
+#include <ipxe/vlan.h>
 #include <ipxe/netdevice.h>
 
 /** @file
@@ -62,6 +64,23 @@ struct errortab netdev_errors[] __errortab = {
 	__einfo_errortab ( EINFO_ENOTCONN_LINK_DOWN ),
 };
 
+/**
+ * Check whether or not network device has a link-layer address
+ *
+ * @v netdev		Network device
+ * @ret has_ll_addr	Network device has a link-layer address
+ */
+static int netdev_has_ll_addr ( struct net_device *netdev ) {
+	uint8_t *ll_addr = netdev->ll_addr;
+	size_t remaining = sizeof ( netdev->ll_addr );
+
+	while ( remaining-- ) {
+		if ( *(ll_addr++) != 0 )
+			return 1;
+	}
+	return 0;
+}
+
 /**
  * Notify drivers of network device or link state change
  *
@@ -163,8 +182,8 @@ static void netdev_record_stat ( struct net_device_stats *stats, int rc ) {
 int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) {
 	int rc;
 
-	DBGC ( netdev, "NETDEV %s transmitting %p (%p+%zx)\n",
-	       netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) );
+	DBGC2 ( netdev, "NETDEV %s transmitting %p (%p+%zx)\n",
+		netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) );
 
 	/* Enqueue packet */
 	list_add_tail ( &iobuf->list, &netdev->tx_queue );
@@ -194,34 +213,50 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) {
 }
 
 /**
- * Complete network transmission
+ * Discard transmitted packet
  *
  * @v netdev		Network device
- * @v iobuf		I/O buffer
+ * @v iobuf		I/O buffer, or NULL
  * @v rc		Packet status code
  *
- * The packet must currently be in the network device's TX queue.
+ * The packet is discarded and a TX error is recorded.  This function
+ * takes ownership of the I/O buffer.
  */
-void netdev_tx_complete_err ( struct net_device *netdev,
-			      struct io_buffer *iobuf, int rc ) {
+void netdev_tx_err ( struct net_device *netdev,
+		     struct io_buffer *iobuf, int rc ) {
 
 	/* Update statistics counter */
 	netdev_record_stat ( &netdev->tx_stats, rc );
 	if ( rc == 0 ) {
-		DBGC ( netdev, "NETDEV %s transmission %p complete\n",
-		       netdev->name, iobuf );
+		DBGC2 ( netdev, "NETDEV %s transmission %p complete\n",
+			netdev->name, iobuf );
 	} else {
 		DBGC ( netdev, "NETDEV %s transmission %p failed: %s\n",
 		       netdev->name, iobuf, strerror ( rc ) );
 	}
 
+	/* Discard packet */
+	free_iob ( iobuf );
+}
+
+/**
+ * Complete network transmission
+ *
+ * @v netdev		Network device
+ * @v iobuf		I/O buffer
+ * @v rc		Packet status code
+ *
+ * The packet must currently be in the network device's TX queue.
+ */
+void netdev_tx_complete_err ( struct net_device *netdev,
+			      struct io_buffer *iobuf, int rc ) {
+
 	/* Catch data corruption as early as possible */
-	assert ( iobuf->list.next != NULL );
-	assert ( iobuf->list.prev != NULL );
+	list_check_contains_entry ( iobuf, &netdev->tx_queue, list );
 
 	/* Dequeue and free I/O buffer */
 	list_del ( &iobuf->list );
-	free_iob ( iobuf );
+	netdev_tx_err ( netdev, iobuf, rc );
 }
 
 /**
@@ -265,8 +300,8 @@ static void netdev_tx_flush ( struct net_device *netdev ) {
  */
 void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) {
 
-	DBGC ( netdev, "NETDEV %s received %p (%p+%zx)\n",
-	       netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) );
+	DBGC2 ( netdev, "NETDEV %s received %p (%p+%zx)\n",
+		netdev->name, iobuf, iobuf->data, iob_len ( iobuf ) );
 
 	/* Discard packet (for test purposes) if applicable */
 	if ( ( NETDEV_DISCARD_RATE > 0 ) &&
@@ -416,8 +451,11 @@ int register_netdev ( struct net_device *netdev ) {
 			   ifindex++ );
 	}
 
-	/* Set initial link-layer address */
-	netdev->ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
+	/* Set initial link-layer address, if not already set */
+	if ( ! netdev_has_ll_addr ( netdev ) ) {
+		netdev->ll_protocol->init_addr ( netdev->hw_addr,
+						 netdev->ll_addr );
+	}
 
 	/* Add to device list */
 	netdev_get ( netdev );
@@ -449,6 +487,7 @@ int register_netdev ( struct net_device *netdev ) {
  err_probe:
 	for_each_table_entry_continue_reverse ( driver, NET_DRIVERS )
 		driver->remove ( netdev );
+	clear_settings ( netdev_settings ( netdev ) );
 	unregister_settings ( netdev_settings ( netdev ) );
  err_register_settings:
 	return rc;
@@ -533,6 +572,7 @@ void unregister_netdev ( struct net_device *netdev ) {
 		driver->remove ( netdev );
 
 	/* Unregister per-netdev configuration settings */
+	clear_settings ( netdev_settings ( netdev ) );
 	unregister_settings ( netdev_settings ( netdev ) );
 
 	/* Remove from device list */
@@ -635,17 +675,11 @@ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
 	struct ll_protocol *ll_protocol = netdev->ll_protocol;
 	int rc;
 
-	/* Force a poll on the netdevice to (potentially) clear any
-	 * backed-up TX completions.  This is needed on some network
-	 * devices to avoid excessive losses due to small TX ring
-	 * sizes.
-	 */
-	netdev_poll ( netdev );
-
 	/* Add link-layer header */
 	if ( ( rc = ll_protocol->push ( netdev, iobuf, ll_dest, ll_source,
 					net_protocol->net_proto ) ) != 0 ) {
-		free_iob ( iobuf );
+		/* Record error for diagnosis */
+		netdev_tx_err ( netdev, iobuf, rc );
 		return rc;
 	}
 
@@ -661,17 +695,19 @@ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
  * @v net_proto		Network-layer protocol, in network-byte order
  * @v ll_dest		Destination link-layer address
  * @v ll_source		Source link-layer address
+ * @v flags		Packet flags
  * @ret rc		Return status code
  */
 int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,
-	     uint16_t net_proto, const void *ll_dest, const void *ll_source ) {
+	     uint16_t net_proto, const void *ll_dest, const void *ll_source,
+	     unsigned int flags ) {
 	struct net_protocol *net_protocol;
 
 	/* Hand off to network-layer protocol, if any */
 	for_each_table_entry ( net_protocol, NET_PROTOCOLS ) {
 		if ( net_protocol->net_proto == net_proto )
 			return net_protocol->rx ( iobuf, netdev, ll_dest,
-						  ll_source );
+						  ll_source, flags );
 	}
 
 	DBGC ( netdev, "NETDEV %s unknown network protocol %04x\n",
@@ -693,6 +729,7 @@ void net_poll ( void ) {
 	const void *ll_dest;
 	const void *ll_source;
 	uint16_t net_proto;
+	unsigned int flags;
 	int rc;
 
 	/* Poll and process each network device */
@@ -710,23 +747,19 @@ void net_poll ( void ) {
 		if ( netdev_rx_frozen ( netdev ) )
 			continue;
 
-		/* Process at most one received packet.  Give priority
-		 * to getting packets out of the NIC over processing
-		 * the received packets, because we advertise a window
-		 * that assumes that we can receive packets from the
-		 * NIC faster than they arrive.
-		 */
-		if ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
+		/* Process all received packets */
+		while ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) {
 
-			DBGC ( netdev, "NETDEV %s processing %p (%p+%zx)\n",
-			       netdev->name, iobuf, iobuf->data,
-			       iob_len ( iobuf ) );
+			DBGC2 ( netdev, "NETDEV %s processing %p (%p+%zx)\n",
+				netdev->name, iobuf, iobuf->data,
+				iob_len ( iobuf ) );
 
 			/* Remove link-layer header */
 			ll_protocol = netdev->ll_protocol;
 			if ( ( rc = ll_protocol->pull ( netdev, iobuf,
 							&ll_dest, &ll_source,
-							&net_proto ) ) != 0 ) {
+							&net_proto,
+							&flags ) ) != 0 ) {
 				free_iob ( iobuf );
 				continue;
 			}
@@ -734,7 +767,7 @@ void net_poll ( void ) {
 			/* Hand packet to network layer */
 			if ( ( rc = net_rx ( iob_disown ( iobuf ), netdev,
 					     net_proto, ll_dest,
-					     ll_source ) ) != 0 ) {
+					     ll_source, flags ) ) != 0 ) {
 				/* Record error for diagnosis */
 				netdev_rx_err ( netdev, NULL, rc );
 			}
@@ -751,8 +784,27 @@ static void net_step ( struct process *process __unused ) {
 	net_poll();
 }
 
+/**
+ * Get the VLAN tag (when VLAN support is not present)
+ *
+ * @v netdev		Network device
+ * @ret tag		0, indicating that device is not a VLAN device
+ */
+__weak unsigned int vlan_tag ( struct net_device *netdev __unused ) {
+	return 0;
+}
+
+/**
+ * Identify VLAN device (when VLAN support is not present)
+ *
+ * @v trunk		Trunk network device
+ * @v tag		VLAN tag
+ * @ret netdev		VLAN device, if any
+ */
+__weak struct net_device * vlan_find ( struct net_device *trunk __unused,
+				       unsigned int tag __unused ) {
+	return NULL;
+}
+
 /** Networking stack process */
-struct process net_process __permanent_process = {
-	.list = LIST_HEAD_INIT ( net_process.list ),
-	.step = net_step,
-};
+PERMANENT_PROCESS ( net_process, net_step );
diff --git a/roms/ipxe/src/net/nullnet.c b/roms/ipxe/src/net/nullnet.c
index 48849dfd67e5a22125dd727b3cab..4ac50f64b7060998c0a65c777da1 100644
--- a/roms/ipxe/src/net/nullnet.c
+++ b/roms/ipxe/src/net/nullnet.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/rarp.c b/roms/ipxe/src/net/rarp.c
index da67c459dba2a9b9e0fba0029e97..371145015e1c60caf6a588f58836 100644
--- a/roms/ipxe/src/net/rarp.c
+++ b/roms/ipxe/src/net/rarp.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -38,6 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
  * @v netdev		Network device
  * @v ll_dest		Link-layer destination address
  * @v ll_source		Link-layer source address
+ * @v flags		Packet flags
  * @ret rc		Return status code
  *
  * This is a dummy method which simply discards RARP packets.
@@ -45,7 +47,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
 static int rarp_rx ( struct io_buffer *iobuf,
 		     struct net_device *netdev __unused,
 		     const void *ll_dest __unused,
-		     const void *ll_source __unused ) {
+		     const void *ll_source __unused,
+		     unsigned int flags __unused ) {
 	free_iob ( iobuf );
 	return 0;
 }
diff --git a/roms/ipxe/src/net/retry.c b/roms/ipxe/src/net/retry.c
index 082be39bb8db662fd2111db4bca3..8f210bdcc45d512da87b3689861d 100644
--- a/roms/ipxe/src/net/retry.c
+++ b/roms/ipxe/src/net/retry.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -148,6 +149,7 @@ void stop_timer ( struct retry_timer *timer ) {
  * @v timer		Retry timer
  */
 static void timer_expired ( struct retry_timer *timer ) {
+	struct refcnt *refcnt = timer->refcnt;
 	int fail;
 
 	/* Stop timer without performing RTT calculations */
@@ -169,16 +171,16 @@ static void timer_expired ( struct retry_timer *timer ) {
 
 	/* Call expiry callback */
 	timer->expired ( timer, fail );
+	/* If refcnt is NULL, then timer may already have been freed */
 
-	ref_put ( timer->refcnt );
+	ref_put ( refcnt );
 }
 
 /**
- * Single-step the retry timer list
+ * Poll the retry timer list
  *
- * @v process		Retry timer process
  */
-static void retry_step ( struct process *process __unused ) {
+void retry_poll ( void ) {
 	struct retry_timer *timer;
 	unsigned long now = currticks();
 	unsigned long used;
@@ -197,8 +199,14 @@ static void retry_step ( struct process *process __unused ) {
 	}
 }
 
+/**
+ * Single-step the retry timer list
+ *
+ * @v process		Retry timer process
+ */
+static void retry_step ( struct process *process __unused ) {
+	retry_poll();
+}
+
 /** Retry timer process */
-struct process retry_process __permanent_process = {
-	.list = LIST_HEAD_INIT ( retry_process.list ),
-	.step = retry_step,
-};
+PERMANENT_PROCESS ( retry_process, retry_step );
diff --git a/roms/ipxe/src/net/tcp.c b/roms/ipxe/src/net/tcp.c
index fbcf279e160737bb35b940e5068e..938edd577ddcfe9bf8c9af98924c 100644
--- a/roms/ipxe/src/net/tcp.c
+++ b/roms/ipxe/src/net/tcp.c
@@ -7,8 +7,10 @@
 #include <ipxe/timer.h>
 #include <ipxe/iobuf.h>
 #include <ipxe/malloc.h>
+#include <ipxe/init.h>
 #include <ipxe/retry.h>
 #include <ipxe/refcnt.h>
+#include <ipxe/pending.h>
 #include <ipxe/xfer.h>
 #include <ipxe/open.h>
 #include <ipxe/uri.h>
@@ -85,6 +87,18 @@ struct tcp_connection {
 	 * Equivalent to TS.Recent in RFC 1323 terminology.
 	 */
 	uint32_t ts_recent;
+	/** Send window scale
+	 *
+	 * Equivalent to Snd.Wind.Scale in RFC 1323 terminology
+	 */
+	uint8_t snd_win_scale;
+	/** Receive window scale
+	 *
+	 * Equivalent to Rcv.Wind.Scale in RFC 1323 terminology
+	 */
+	uint8_t rcv_win_scale;
+	/** Maximum receive window */
+	uint32_t max_rcv_win;
 
 	/** Transmit queue */
 	struct list_head tx_queue;
@@ -94,6 +108,11 @@ struct tcp_connection {
 	struct retry_timer timer;
 	/** Shutdown (TIME_WAIT) timer */
 	struct retry_timer wait;
+
+	/** Pending operations for SYN and FIN */
+	struct pending_operation pending_flags;
+	/** Pending operations for transmit queue */
+	struct pending_operation pending_data;
 };
 
 /** TCP flags */
@@ -278,6 +297,7 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer,
 	tcp->tcp_state = TCP_STATE_SENT ( TCP_SYN );
 	tcp_dump_state ( tcp );
 	tcp->snd_seq = random();
+	tcp->max_rcv_win = TCP_MAX_WINDOW_SIZE;
 	INIT_LIST_HEAD ( &tcp->tx_queue );
 	INIT_LIST_HEAD ( &tcp->rx_queue );
 	memcpy ( &tcp->peer, st_peer, sizeof ( tcp->peer ) );
@@ -290,6 +310,9 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer,
 	/* Start timer to initiate SYN */
 	start_timer_nodelay ( &tcp->timer );
 
+	/* Add a pending operation for the SYN */
+	pending_get ( &tcp->pending_flags );
+
 	/* Attach parent interface, transfer reference to connection
 	 * list and return
 	 */
@@ -339,10 +362,17 @@ static void tcp_close ( struct tcp_connection *tcp, int rc ) {
 		list_for_each_entry_safe ( iobuf, tmp, &tcp->tx_queue, list ) {
 			list_del ( &iobuf->list );
 			free_iob ( iobuf );
+			pending_put ( &tcp->pending_data );
 		}
+		assert ( ! is_pending ( &tcp->pending_data ) );
+
+		/* Remove pending operations for SYN and FIN, if applicable */
+		pending_put ( &tcp->pending_flags );
+		pending_put ( &tcp->pending_flags );
 
 		/* Remove from list and drop reference */
 		stop_timer ( &tcp->timer );
+		stop_timer ( &tcp->wait );
 		list_del ( &tcp->list );
 		ref_put ( &tcp->refcnt );
 		DBGC ( tcp, "TCP %p connection deleted\n", tcp );
@@ -357,9 +387,14 @@ static void tcp_close ( struct tcp_connection *tcp, int rc ) {
 		tcp_rx_ack ( tcp, ( tcp->snd_seq + 1 ), 0 );
 
 	/* If we have no data remaining to send, start sending FIN */
-	if ( list_empty ( &tcp->tx_queue ) ) {
+	if ( list_empty ( &tcp->tx_queue ) &&
+	     ! ( tcp->tcp_state & TCP_STATE_SENT ( TCP_FIN ) ) ) {
+
 		tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
 		tcp_dump_state ( tcp );
+
+		/* Add a pending operation for the FIN */
+		pending_get ( &tcp->pending_flags );
 	}
 }
 
@@ -391,6 +426,25 @@ static size_t tcp_xmit_win ( struct tcp_connection *tcp ) {
 	return len;
 }
 
+/**
+ * Check data-transfer flow control window
+ *
+ * @v tcp		TCP connection
+ * @ret len		Length of window
+ */
+static size_t tcp_xfer_window ( struct tcp_connection *tcp ) {
+
+	/* Not ready if data queue is non-empty.  This imposes a limit
+	 * of only one unACKed packet in the TX queue at any time; we
+	 * do this to conserve memory usage.
+	 */
+	if ( ! list_empty ( &tcp->tx_queue ) )
+		return 0;
+
+	/* Return TCP window length */
+	return tcp_xmit_win ( tcp );
+}
+
 /**
  * Process TCP transmit queue
  *
@@ -425,6 +479,7 @@ static size_t tcp_process_tx_queue ( struct tcp_connection *tcp, size_t max_len,
 			if ( ! iob_len ( iobuf ) ) {
 				list_del ( &iobuf->list );
 				free_iob ( iobuf );
+				pending_put ( &tcp->pending_data );
 			}
 		}
 		len += frag_len;
@@ -448,6 +503,7 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
 	struct io_buffer *iobuf;
 	struct tcp_header *tcphdr;
 	struct tcp_mss_option *mssopt;
+	struct tcp_window_scale_padded_option *wsopt;
 	struct tcp_timestamp_padded_option *tsopt;
 	void *payload;
 	unsigned int flags;
@@ -455,6 +511,7 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
 	uint32_t seq_len;
 	uint32_t app_win;
 	uint32_t max_rcv_win;
+	uint32_t max_representable_win;
 	int rc;
 
 	/* If retransmission timer is already running, do nothing */
@@ -490,25 +547,26 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
 		start_timer ( &tcp->timer );
 
 	/* Allocate I/O buffer */
-	iobuf = alloc_iob ( len + MAX_LL_NET_HEADER_LEN );
+	iobuf = alloc_iob ( len + TCP_MAX_HEADER_LEN );
 	if ( ! iobuf ) {
 		DBGC ( tcp, "TCP %p could not allocate iobuf for %08x..%08x "
 		       "%08x\n", tcp, tcp->snd_seq, ( tcp->snd_seq + seq_len ),
 		       tcp->rcv_ack );
 		return -ENOMEM;
 	}
-	iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
+	iob_reserve ( iobuf, TCP_MAX_HEADER_LEN );
 
 	/* Fill data payload from transmit queue */
 	tcp_process_tx_queue ( tcp, len, iobuf, 0 );
 
 	/* Expand receive window if possible */
-	max_rcv_win = ( ( freemem * 3 ) / 4 );
-	if ( max_rcv_win > TCP_MAX_WINDOW_SIZE )
-		max_rcv_win = TCP_MAX_WINDOW_SIZE;
+	max_rcv_win = tcp->max_rcv_win;
 	app_win = xfer_window ( &tcp->xfer );
 	if ( max_rcv_win > app_win )
 		max_rcv_win = app_win;
+	max_representable_win = ( 0xffff << tcp->rcv_win_scale );
+	if ( max_rcv_win > max_representable_win )
+		max_rcv_win = max_representable_win;
 	max_rcv_win &= ~0x03; /* Keep everything dword-aligned */
 	if ( tcp->rcv_win < max_rcv_win )
 		tcp->rcv_win = max_rcv_win;
@@ -520,6 +578,11 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
 		mssopt->kind = TCP_OPTION_MSS;
 		mssopt->length = sizeof ( *mssopt );
 		mssopt->mss = htons ( TCP_MSS );
+		wsopt = iob_push ( iobuf, sizeof ( *wsopt ) );
+		wsopt->nop = TCP_OPTION_NOP;
+		wsopt->wsopt.kind = TCP_OPTION_WS;
+		wsopt->wsopt.length = sizeof ( wsopt->wsopt );
+		wsopt->wsopt.scale = TCP_RX_WINDOW_SCALE;
 	}
 	if ( ( flags & TCP_SYN ) || ( tcp->flags & TCP_TS_ENABLED ) ) {
 		tsopt = iob_push ( iobuf, sizeof ( *tsopt ) );
@@ -539,7 +602,7 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
 	tcphdr->ack = htonl ( tcp->rcv_ack );
 	tcphdr->hlen = ( ( payload - iobuf->data ) << 2 );
 	tcphdr->flags = flags;
-	tcphdr->win = htons ( tcp->rcv_win );
+	tcphdr->win = htons ( tcp->rcv_win >> tcp->rcv_win_scale );
 	tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) );
 
 	/* Dump header */
@@ -634,14 +697,14 @@ static int tcp_xmit_reset ( struct tcp_connection *tcp,
 	int rc;
 
 	/* Allocate space for dataless TX buffer */
-	iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN );
+	iobuf = alloc_iob ( TCP_MAX_HEADER_LEN );
 	if ( ! iobuf ) {
 		DBGC ( tcp, "TCP %p could not allocate iobuf for RST "
 		       "%08x..%08x %08x\n", tcp, ntohl ( in_tcphdr->ack ),
 		       ntohl ( in_tcphdr->ack ), ntohl ( in_tcphdr->seq ) );
 		return -ENOMEM;
 	}
-	iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
+	iob_reserve ( iobuf, TCP_MAX_HEADER_LEN );
 
 	/* Construct RST response */
 	tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) );
@@ -652,7 +715,7 @@ static int tcp_xmit_reset ( struct tcp_connection *tcp,
 	tcphdr->ack = in_tcphdr->seq;
 	tcphdr->hlen = ( ( sizeof ( *tcphdr ) / 4 ) << 4 );
 	tcphdr->flags = ( TCP_RST | TCP_ACK );
-	tcphdr->win = htons ( TCP_MAX_WINDOW_SIZE );
+	tcphdr->win = htons ( 0 );
 	tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) );
 
 	/* Dump header */
@@ -727,6 +790,9 @@ static void tcp_rx_opts ( struct tcp_connection *tcp, const void *data,
 		case TCP_OPTION_MSS:
 			options->mssopt = data;
 			break;
+		case TCP_OPTION_WS:
+			options->wsopt = data;
+			break;
 		case TCP_OPTION_TS:
 			options->tsopt = data;
 			break;
@@ -783,6 +849,10 @@ static int tcp_rx_syn ( struct tcp_connection *tcp, uint32_t seq,
 		tcp->rcv_ack = seq;
 		if ( options->tsopt )
 			tcp->flags |= TCP_TS_ENABLED;
+		if ( options->wsopt ) {
+			tcp->snd_win_scale = options->wsopt->scale;
+			tcp->rcv_win_scale = TCP_RX_WINDOW_SCALE;
+		}
 	}
 
 	/* Ignore duplicate SYN */
@@ -848,8 +918,10 @@ static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack,
 	len = ack_len;
 	acked_flags = ( TCP_FLAGS_SENDING ( tcp->tcp_state ) &
 			( TCP_SYN | TCP_FIN ) );
-	if ( acked_flags )
+	if ( acked_flags ) {
 		len--;
+		pending_put ( &tcp->pending_flags );
+	}
 
 	/* Update SEQ and sent counters, and window size */
 	tcp->snd_seq = ack;
@@ -864,8 +936,12 @@ static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack,
 		tcp->tcp_state |= TCP_STATE_ACKED ( acked_flags );
 
 	/* Start sending FIN if we've had all possible data ACKed */
-	if ( list_empty ( &tcp->tx_queue ) && ( tcp->flags & TCP_XFER_CLOSED ) )
+	if ( list_empty ( &tcp->tx_queue ) &&
+	     ( tcp->flags & TCP_XFER_CLOSED ) &&
+	     ! ( tcp->tcp_state & TCP_STATE_SENT ( TCP_FIN ) ) ) {
 		tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
+		pending_get ( &tcp->pending_flags );
+	}
 
 	return 0;
 }
@@ -1080,10 +1156,12 @@ static int tcp_rx ( struct io_buffer *iobuf,
 	uint16_t csum;
 	uint32_t seq;
 	uint32_t ack;
+	uint16_t raw_win;
 	uint32_t win;
 	unsigned int flags;
 	size_t len;
 	uint32_t seq_len;
+	size_t old_xfer_window;
 	int rc;
 
 	/* Sanity check packet */
@@ -1119,11 +1197,11 @@ static int tcp_rx ( struct io_buffer *iobuf,
 	tcp = tcp_demux ( ntohs ( tcphdr->dest ) );
 	seq = ntohl ( tcphdr->seq );
 	ack = ntohl ( tcphdr->ack );
-	win = ntohs ( tcphdr->win );
+	raw_win = ntohs ( tcphdr->win );
 	flags = tcphdr->flags;
 	tcp_rx_opts ( tcp, ( ( ( void * ) tcphdr ) + sizeof ( *tcphdr ) ),
 		      ( hlen - sizeof ( *tcphdr ) ), &options );
-	if ( options.tsopt )
+	if ( tcp && options.tsopt )
 		tcp->ts_val = ntohl ( options.tsopt->tsval );
 	iob_pull ( iobuf, hlen );
 	len = iob_len ( iobuf );
@@ -1145,8 +1223,12 @@ static int tcp_rx ( struct io_buffer *iobuf,
 		goto discard;
 	}
 
+	/* Record old data-transfer window */
+	old_xfer_window = tcp_xfer_window ( tcp );
+
 	/* Handle ACK, if present */
 	if ( flags & TCP_ACK ) {
+		win = ( raw_win << tcp->snd_win_scale );
 		if ( ( rc = tcp_rx_ack ( tcp, ack, win ) ) != 0 ) {
 			tcp_xmit_reset ( tcp, st_src, tcphdr );
 			goto discard;
@@ -1191,6 +1273,10 @@ static int tcp_rx ( struct io_buffer *iobuf,
 		start_timer_fixed ( &tcp->wait, ( 2 * TCP_MSL ) );
 	}
 
+	/* Notify application if window has changed */
+	if ( tcp_xfer_window ( tcp ) != old_xfer_window )
+		xfer_window_changed ( &tcp->xfer );
+
 	return 0;
 
  discard:
@@ -1214,13 +1300,29 @@ struct tcpip_protocol tcp_protocol __tcpip_protocol = {
 static unsigned int tcp_discard ( void ) {
 	struct tcp_connection *tcp;
 	struct io_buffer *iobuf;
+	struct tcp_rx_queued_header *tcpqhdr;
+	uint32_t max_win;
 	unsigned int discarded = 0;
 
 	/* Try to drop one queued RX packet from each connection */
 	list_for_each_entry ( tcp, &tcp_conns, list ) {
 		list_for_each_entry_reverse ( iobuf, &tcp->rx_queue, list ) {
+
+			/* Limit window to prevent future discards */
+			tcpqhdr = iobuf->data;
+			max_win = ( tcpqhdr->seq - tcp->rcv_ack );
+			if ( max_win < tcp->max_rcv_win ) {
+				DBGC ( tcp, "TCP %p reducing maximum window "
+				       "from %d to %d\n",
+				       tcp, tcp->max_rcv_win, max_win );
+				tcp->max_rcv_win = max_win;
+			}
+
+			/* Remove packet from queue */
 			list_del ( &iobuf->list );
 			free_iob ( iobuf );
+
+			/* Report discard */
 			discarded++;
 			break;
 		}
@@ -1230,10 +1332,30 @@ static unsigned int tcp_discard ( void ) {
 }
 
 /** TCP cache discarder */
-struct cache_discarder tcp_cache_discarder __cache_discarder = {
+struct cache_discarder tcp_discarder __cache_discarder ( CACHE_NORMAL ) = {
 	.discard = tcp_discard,
 };
 
+/**
+ * Shut down all TCP connections
+ *
+ */
+static void tcp_shutdown ( int booting __unused ) {
+	struct tcp_connection *tcp;
+
+	while ( ( tcp = list_first_entry ( &tcp_conns, struct tcp_connection,
+					   list ) ) != NULL ) {
+		tcp->tcp_state = TCP_CLOSED;
+		tcp_dump_state ( tcp );
+		tcp_close ( tcp, -ECANCELED );
+	}
+}
+
+/** TCP shutdown function */
+struct startup_fn tcp_startup_fn __startup_fn ( STARTUP_EARLY ) = {
+	.shutdown = tcp_shutdown,
+};
+
 /***************************************************************************
  *
  * Data transfer interface
@@ -1256,25 +1378,6 @@ static void tcp_xfer_close ( struct tcp_connection *tcp, int rc ) {
 	tcp_xmit ( tcp );
 }
 
-/**
- * Check flow control window
- *
- * @v tcp		TCP connection
- * @ret len		Length of window
- */
-static size_t tcp_xfer_window ( struct tcp_connection *tcp ) {
-
-	/* Not ready if data queue is non-empty.  This imposes a limit
-	 * of only one unACKed packet in the TX queue at any time; we
-	 * do this to conserve memory usage.
-	 */
-	if ( ! list_empty ( &tcp->tx_queue ) )
-		return 0;
-
-	/* Return TCP window length */
-	return tcp_xmit_win ( tcp );
-}
-
 /**
  * Deliver datagram as I/O buffer
  *
@@ -1290,6 +1393,9 @@ static int tcp_xfer_deliver ( struct tcp_connection *tcp,
 	/* Enqueue packet */
 	list_add_tail ( &iobuf->list, &tcp->tx_queue );
 
+	/* Each enqueued packet is a pending operation */
+	pending_get ( &tcp->pending_data );
+
 	/* Transmit data, if possible */
 	tcp_xmit ( tcp );
 
diff --git a/roms/ipxe/src/net/tcp/ftp.c b/roms/ipxe/src/net/tcp/ftp.c
index 957f05cc8aeab39c1f7982d8db8a..9f93fb66f1769d4ec7a2ad7e481c 100644
--- a/roms/ipxe/src/net/tcp/ftp.c
+++ b/roms/ipxe/src/net/tcp/ftp.c
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -34,6 +53,7 @@ enum ftp_state {
 	FTP_USER,
 	FTP_PASS,
 	FTP_TYPE,
+	FTP_SIZE,
 	FTP_PASV,
 	FTP_RETR,
 	FTP_WAIT,
@@ -68,6 +88,8 @@ struct ftp_request {
 	char status_text[5];
 	/** Passive-mode parameters, as text */
 	char passive_text[24]; /* "aaa,bbb,ccc,ddd,eee,fff" */
+	/** File size, as text */
+	char filesize[20];
 };
 
 /**
@@ -157,6 +179,7 @@ static struct ftp_control_string ftp_strings[] = {
 	[FTP_USER]	= { "USER ", ftp_user },
 	[FTP_PASS]	= { "PASS ", ftp_password },
 	[FTP_TYPE]	= { "TYPE I", NULL },
+	[FTP_SIZE]	= { "SIZE ", ftp_uri_path },
 	[FTP_PASV]	= { "PASV", NULL },
 	[FTP_RETR]	= { "RETR ", ftp_uri_path },
 	[FTP_WAIT]	= { NULL, NULL },
@@ -234,6 +257,14 @@ static void ftp_reply ( struct ftp_request *ftp ) {
 	if ( status_major == '1' )
 		return;
 
+	/* If the SIZE command is not supported by the server, we go to
+	 * the next step.
+	 */
+	if ( ( status_major == '5' ) && ( ftp->state == FTP_SIZE ) ) {
+		ftp_next_state ( ftp );
+		return;
+	}
+
 	/* Anything other than success (2xx) or, in the case of a
 	 * repsonse to a "USER" command, a password prompt (3xx), is a
 	 * fatal error.
@@ -245,6 +276,26 @@ static void ftp_reply ( struct ftp_request *ftp ) {
 		return;
 	}
 
+	/* Parse file size */
+	if ( ftp->state == FTP_SIZE ) {
+		size_t filesize;
+		char *endptr;
+
+		/* Parse size */
+		filesize = strtoul ( ftp->filesize, &endptr, 10 );
+		if ( *endptr != '\0' ) {
+			DBGC ( ftp, "FTP %p invalid SIZE \"%s\"\n",
+			       ftp, ftp->filesize );
+			ftp_done ( ftp, -EPROTO );
+			return;
+		}
+
+		/* Use seek() to notify recipient of filesize */
+		DBGC ( ftp, "FTP %p file size is %zd bytes\n", ftp, filesize );
+		xfer_seek ( &ftp->xfer, filesize );
+		xfer_seek ( &ftp->xfer, 0 );
+	}
+
 	/* Open passive connection when we get "PASV" response */
 	if ( ftp->state == FTP_PASV ) {
 		char *ptr = ftp->passive_text;
@@ -295,35 +346,33 @@ static int ftp_control_deliver ( struct ftp_request *ftp,
 	
 	while ( len-- ) {
 		c = *(data++);
-		switch ( c ) {
-		case '\r' :
-		case '\n' :
+		if ( ( c == '\r' ) || ( c == '\n' ) ) {
 			/* End of line: call ftp_reply() to handle
 			 * completed reply.  Avoid calling ftp_reply()
 			 * twice if we receive both \r and \n.
 			 */
-			if ( recvsize == 0 )
+			if ( recvbuf != ftp->status_text )
 				ftp_reply ( ftp );
 			/* Start filling up the status code buffer */
 			recvbuf = ftp->status_text;
 			recvsize = sizeof ( ftp->status_text ) - 1;
-			break;
-		case '(' :
+		} else if ( ( ftp->state == FTP_PASV ) && ( c == '(' ) ) {
 			/* Start filling up the passive parameter buffer */
 			recvbuf = ftp->passive_text;
 			recvsize = sizeof ( ftp->passive_text ) - 1;
-			break;
-		case ')' :
+		} else if ( ( ftp->state == FTP_PASV ) && ( c == ')' ) ) {
 			/* Stop filling the passive parameter buffer */
 			recvsize = 0;
-			break;
-		default :
+		} else if ( ( ftp->state == FTP_SIZE ) && ( c == ' ' ) ) {
+			/* Start filling up the file size buffer */
+			recvbuf = ftp->filesize;
+			recvsize = sizeof ( ftp->filesize ) - 1;
+		} else {
 			/* Fill up buffer if applicable */
 			if ( recvsize > 0 ) {
 				*(recvbuf++) = c;
 				recvsize--;
 			}
-			break;
 		}
 	}
 
@@ -378,37 +427,15 @@ static void ftp_data_closed ( struct ftp_request *ftp, int rc ) {
 	}
 }
 
-/**
- * Handle data delivery via FTP data channel
- *
- * @v ftp		FTP request
- * @v iobuf		I/O buffer
- * @v meta		Data transfer metadata
- * @ret rc		Return status code
- */
-static int ftp_data_deliver ( struct ftp_request *ftp,
-			      struct io_buffer *iobuf,
-			      struct xfer_metadata *meta __unused ) {
-	int rc;
-
-	if ( ( rc = xfer_deliver_iob ( &ftp->xfer, iobuf ) ) != 0 ) {
-		DBGC ( ftp, "FTP %p failed to deliver data: %s\n",
-		       ftp, strerror ( rc ) );
-		return rc;
-	}
-
-	return 0;
-}
-
 /** FTP data channel interface operations */
 static struct interface_operation ftp_data_operations[] = {
-	INTF_OP ( xfer_deliver, struct ftp_request *, ftp_data_deliver ),
 	INTF_OP ( intf_close, struct ftp_request *, ftp_data_closed ),
 };
 
 /** FTP data channel interface descriptor */
 static struct interface_descriptor ftp_data_desc =
-	INTF_DESC ( struct ftp_request, data, ftp_data_operations );
+	INTF_DESC_PASSTHRU ( struct ftp_request, data, ftp_data_operations,
+			     xfer );
 
 /*****************************************************************************
  *
@@ -423,7 +450,8 @@ static struct interface_operation ftp_xfer_operations[] = {
 
 /** FTP data transfer interface descriptor */
 static struct interface_descriptor ftp_xfer_desc =
-	INTF_DESC ( struct ftp_request, xfer, ftp_xfer_operations );
+	INTF_DESC_PASSTHRU ( struct ftp_request, xfer, ftp_xfer_operations,
+			     data );
 
 /*****************************************************************************
  *
diff --git a/roms/ipxe/src/net/tcp/http.c b/roms/ipxe/src/net/tcp/http.c
index 20f14e680898779331f4f30da353..90bae9d7a2d9bffc0be3ec75de8b 100644
--- a/roms/ipxe/src/net/tcp/http.c
+++ b/roms/ipxe/src/net/tcp/http.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -25,525 +26,13 @@ FILE_LICENCE ( GPL2_OR_LATER );
  *
  */
 
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <strings.h>
-#include <byteswap.h>
-#include <errno.h>
-#include <assert.h>
-#include <ipxe/uri.h>
-#include <ipxe/refcnt.h>
-#include <ipxe/iobuf.h>
-#include <ipxe/xfer.h>
+#include <stddef.h>
 #include <ipxe/open.h>
-#include <ipxe/socket.h>
-#include <ipxe/tcpip.h>
-#include <ipxe/process.h>
-#include <ipxe/linebuf.h>
-#include <ipxe/features.h>
-#include <ipxe/base64.h>
 #include <ipxe/http.h>
+#include <ipxe/features.h>
 
 FEATURE ( FEATURE_PROTOCOL, "HTTP", DHCP_EB_FEATURE_HTTP, 1 );
 
-/** HTTP receive state */
-enum http_rx_state {
-	HTTP_RX_RESPONSE = 0,
-	HTTP_RX_HEADER,
-	HTTP_RX_DATA,
-	HTTP_RX_DEAD,
-};
-
-/**
- * An HTTP request
- *
- */
-struct http_request {
-	/** Reference count */
-	struct refcnt refcnt;
-	/** Data transfer interface */
-	struct interface xfer;
-
-	/** URI being fetched */
-	struct uri *uri;
-	/** Transport layer interface */
-	struct interface socket;
-
-	/** TX process */
-	struct process process;
-
-	/** HTTP response code */
-	unsigned int response;
-	/** HTTP Content-Length */
-	size_t content_length;
-	/** Received length */
-	size_t rx_len;
-	/** RX state */
-	enum http_rx_state rx_state;
-	/** Line buffer for received header lines */
-	struct line_buffer linebuf;
-};
-
-/**
- * Free HTTP request
- *
- * @v refcnt		Reference counter
- */
-static void http_free ( struct refcnt *refcnt ) {
-	struct http_request *http =
-		container_of ( refcnt, struct http_request, refcnt );
-
-	uri_put ( http->uri );
-	empty_line_buffer ( &http->linebuf );
-	free ( http );
-};
-
-/**
- * Mark HTTP request as complete
- *
- * @v http		HTTP request
- * @v rc		Return status code
- */
-static void http_done ( struct http_request *http, int rc ) {
-
-	/* Prevent further processing of any current packet */
-	http->rx_state = HTTP_RX_DEAD;
-
-	/* If we had a Content-Length, and the received content length
-	 * isn't correct, flag an error
-	 */
-	if ( http->content_length &&
-	     ( http->content_length != http->rx_len ) ) {
-		DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n",
-		       http, http->rx_len, http->content_length );
-		rc = -EIO;
-	}
-
-	/* Remove process */
-	process_del ( &http->process );
-
-	/* Close all data transfer interfaces */
-	intf_shutdown ( &http->socket, rc );
-	intf_shutdown ( &http->xfer, rc );
-}
-
-/**
- * Convert HTTP response code to return status code
- *
- * @v response		HTTP response code
- * @ret rc		Return status code
- */
-static int http_response_to_rc ( unsigned int response ) {
-	switch ( response ) {
-	case 200:
-	case 301:
-	case 302:
-		return 0;
-	case 404:
-		return -ENOENT;
-	case 403:
-		return -EPERM;
-	case 401:
-		return -EACCES;
-	default:
-		return -EIO;
-	}
-}
-
-/**
- * Handle HTTP response
- *
- * @v http		HTTP request
- * @v response		HTTP response
- * @ret rc		Return status code
- */
-static int http_rx_response ( struct http_request *http, char *response ) {
-	char *spc;
-	int rc;
-
-	DBGC ( http, "HTTP %p response \"%s\"\n", http, response );
-
-	/* Check response starts with "HTTP/" */
-	if ( strncmp ( response, "HTTP/", 5 ) != 0 )
-		return -EIO;
-
-	/* Locate and check response code */
-	spc = strchr ( response, ' ' );
-	if ( ! spc )
-		return -EIO;
-	http->response = strtoul ( spc, NULL, 10 );
-	if ( ( rc = http_response_to_rc ( http->response ) ) != 0 )
-		return rc;
-
-	/* Move to received headers */
-	http->rx_state = HTTP_RX_HEADER;
-	return 0;
-}
-
-/**
- * Handle HTTP Location header
- *
- * @v http		HTTP request
- * @v value		HTTP header value
- * @ret rc		Return status code
- */
-static int http_rx_location ( struct http_request *http, const char *value ) {
-	int rc;
-
-	/* Redirect to new location */
-	DBGC ( http, "HTTP %p redirecting to %s\n", http, value );
-	if ( ( rc = xfer_redirect ( &http->xfer, LOCATION_URI_STRING,
-				    value ) ) != 0 ) {
-		DBGC ( http, "HTTP %p could not redirect: %s\n",
-		       http, strerror ( rc ) );
-		return rc;
-	}
-
-	return 0;
-}
-
-/**
- * Handle HTTP Content-Length header
- *
- * @v http		HTTP request
- * @v value		HTTP header value
- * @ret rc		Return status code
- */
-static int http_rx_content_length ( struct http_request *http,
-				    const char *value ) {
-	char *endp;
-
-	http->content_length = strtoul ( value, &endp, 10 );
-	if ( *endp != '\0' ) {
-		DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n",
-		       http, value );
-		return -EIO;
-	}
-
-	/* Use seek() to notify recipient of filesize */
-	xfer_seek ( &http->xfer, http->content_length );
-	xfer_seek ( &http->xfer, 0 );
-
-	return 0;
-}
-
-/** An HTTP header handler */
-struct http_header_handler {
-	/** Name (e.g. "Content-Length") */
-	const char *header;
-	/** Handle received header
-	 *
-	 * @v http	HTTP request
-	 * @v value	HTTP header value
-	 * @ret rc	Return status code
-	 *
-	 * If an error is returned, the download will be aborted.
-	 */
-	int ( * rx ) ( struct http_request *http, const char *value );
-};
-
-/** List of HTTP header handlers */
-static struct http_header_handler http_header_handlers[] = {
-	{
-		.header = "Location",
-		.rx = http_rx_location,
-	},
-	{
-		.header = "Content-Length",
-		.rx = http_rx_content_length,
-	},
-	{ NULL, NULL }
-};
-
-/**
- * Handle HTTP header
- *
- * @v http		HTTP request
- * @v header		HTTP header
- * @ret rc		Return status code
- */
-static int http_rx_header ( struct http_request *http, char *header ) {
-	struct http_header_handler *handler;
-	char *separator;
-	char *value;
-	int rc;
-
-	/* An empty header line marks the transition to the data phase */
-	if ( ! header[0] ) {
-		DBGC ( http, "HTTP %p start of data\n", http );
-		empty_line_buffer ( &http->linebuf );
-		http->rx_state = HTTP_RX_DATA;
-		return 0;
-	}
-
-	DBGC ( http, "HTTP %p header \"%s\"\n", http, header );
-
-	/* Split header at the ": " */
-	separator = strstr ( header, ": " );
-	if ( ! separator ) {
-		DBGC ( http, "HTTP %p malformed header\n", http );
-		return -EIO;
-	}
-	*separator = '\0';
-	value = ( separator + 2 );
-
-	/* Hand off to header handler, if one exists */
-	for ( handler = http_header_handlers ; handler->header ; handler++ ) {
-		if ( strcasecmp ( header, handler->header ) == 0 ) {
-			if ( ( rc = handler->rx ( http, value ) ) != 0 )
-				return rc;
-			break;
-		}
-	}
-	return 0;
-}
-
-/** An HTTP line-based data handler */
-struct http_line_handler {
-	/** Handle line
-	 *
-	 * @v http	HTTP request
-	 * @v line	Line to handle
-	 * @ret rc	Return status code
-	 */
-	int ( * rx ) ( struct http_request *http, char *line );
-};
-
-/** List of HTTP line-based data handlers */
-static struct http_line_handler http_line_handlers[] = {
-	[HTTP_RX_RESPONSE]	= { .rx = http_rx_response },
-	[HTTP_RX_HEADER]	= { .rx = http_rx_header },
-};
-
-/**
- * Handle new data arriving via HTTP connection in the data phase
- *
- * @v http		HTTP request
- * @v iobuf		I/O buffer
- * @ret rc		Return status code
- */
-static int http_rx_data ( struct http_request *http,
-			  struct io_buffer *iobuf ) {
-	int rc;
-
-	/* Update received length */
-	http->rx_len += iob_len ( iobuf );
-
-	/* Hand off data buffer */
-	if ( ( rc = xfer_deliver_iob ( &http->xfer, iobuf ) ) != 0 )
-		return rc;
-
-	/* If we have reached the content-length, stop now */
-	if ( http->content_length &&
-	     ( http->rx_len >= http->content_length ) ) {
-		http_done ( http, 0 );
-	}
-
-	return 0;
-}
-
-/**
- * Handle new data arriving via HTTP connection
- *
- * @v http		HTTP request
- * @v iobuf		I/O buffer
- * @v meta		Data transfer metadata
- * @ret rc		Return status code
- */
-static int http_socket_deliver ( struct http_request *http,
-				 struct io_buffer *iobuf,
-				 struct xfer_metadata *meta __unused ) {
-	struct http_line_handler *lh;
-	char *line;
-	ssize_t len;
-	int rc = 0;
-
-	while ( iob_len ( iobuf ) ) {
-		switch ( http->rx_state ) {
-		case HTTP_RX_DEAD:
-			/* Do no further processing */
-			goto done;
-		case HTTP_RX_DATA:
-			/* Once we're into the data phase, just fill
-			 * the data buffer
-			 */
-			rc = http_rx_data ( http, iob_disown ( iobuf ) );
-			goto done;
-		case HTTP_RX_RESPONSE:
-		case HTTP_RX_HEADER:
-			/* In the other phases, buffer and process a
-			 * line at a time
-			 */
-			len = line_buffer ( &http->linebuf, iobuf->data,
-					    iob_len ( iobuf ) );
-			if ( len < 0 ) {
-				rc = len;
-				DBGC ( http, "HTTP %p could not buffer line: "
-				       "%s\n", http, strerror ( rc ) );
-				goto done;
-			}
-			iob_pull ( iobuf, len );
-			line = buffered_line ( &http->linebuf );
-			if ( line ) {
-				lh = &http_line_handlers[http->rx_state];
-				if ( ( rc = lh->rx ( http, line ) ) != 0 )
-					goto done;
-			}
-			break;
-		default:
-			assert ( 0 );
-			break;
-		}
-	}
-
- done:
-	if ( rc )
-		http_done ( http, rc );
-	free_iob ( iobuf );
-	return rc;
-}
-
-/**
- * HTTP process
- *
- * @v process		Process
- */
-static void http_step ( struct process *process ) {
-	struct http_request *http =
-		container_of ( process, struct http_request, process );
-	const char *host = http->uri->host;
-	const char *user = http->uri->user;
-	const char *password =
-		( http->uri->password ? http->uri->password : "" );
-	size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ +
-					strlen ( password ) ) : 0 );
-	size_t user_pw_base64_len = base64_encoded_len ( user_pw_len );
-	uint8_t user_pw[ user_pw_len + 1 /* NUL */ ];
-	char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ];
-	int rc;
-	int request_len = unparse_uri ( NULL, 0, http->uri,
-					URI_PATH_BIT | URI_QUERY_BIT );
-
-	if ( xfer_window ( &http->socket ) ) {
-		char request[request_len + 1];
-
-		/* Construct path?query request */
-		unparse_uri ( request, sizeof ( request ), http->uri,
-			      URI_PATH_BIT | URI_QUERY_BIT );
-
-		/* We want to execute only once */
-		process_del ( &http->process );
-
-		/* Construct authorisation, if applicable */
-		if ( user ) {
-			/* Make "user:password" string from decoded fields */
-			snprintf ( ( ( char * ) user_pw ), sizeof ( user_pw ),
-				   "%s:%s", user, password );
-
-			/* Base64-encode the "user:password" string */
-			base64_encode ( user_pw, user_pw_len, user_pw_base64 );
-		}
-
-		/* Send GET request */
-		if ( ( rc = xfer_printf ( &http->socket,
-					  "GET %s%s HTTP/1.0\r\n"
-					  "User-Agent: iPXE/" VERSION "\r\n"
-					  "%s%s%s"
-					  "Host: %s\r\n"
-					  "\r\n",
-					  http->uri->path ? "" : "/",
-					  request,
-					  ( user ?
-					    "Authorization: Basic " : "" ),
-					  ( user ? user_pw_base64 : "" ),
-					  ( user ? "\r\n" : "" ),
-					  host ) ) != 0 ) {
-			http_done ( http, rc );
-		}
-	}
-}
-
-/** HTTP socket interface operations */
-static struct interface_operation http_socket_operations[] = {
-	INTF_OP ( xfer_deliver, struct http_request *, http_socket_deliver ),
-	INTF_OP ( intf_close, struct http_request *, http_done ),
-};
-
-/** HTTP socket interface descriptor */
-static struct interface_descriptor http_socket_desc =
-	INTF_DESC_PASSTHRU ( struct http_request, socket,
-			     http_socket_operations, xfer );
-
-/** HTTP data transfer interface operations */
-static struct interface_operation http_xfer_operations[] = {
-	INTF_OP ( intf_close, struct http_request *, http_done ),
-};
-
-/** HTTP data transfer interface descriptor */
-static struct interface_descriptor http_xfer_desc =
-	INTF_DESC_PASSTHRU ( struct http_request, xfer,
-			     http_xfer_operations, socket );
-
-/**
- * Initiate an HTTP connection, with optional filter
- *
- * @v xfer		Data transfer interface
- * @v uri		Uniform Resource Identifier
- * @v default_port	Default port number
- * @v filter		Filter to apply to socket, or NULL
- * @ret rc		Return status code
- */
-int http_open_filter ( struct interface *xfer, struct uri *uri,
-		       unsigned int default_port,
-		       int ( * filter ) ( struct interface *xfer,
-					  struct interface **next ) ) {
-	struct http_request *http;
-	struct sockaddr_tcpip server;
-	struct interface *socket;
-	int rc;
-
-	/* Sanity checks */
-	if ( ! uri->host )
-		return -EINVAL;
-
-	/* Allocate and populate HTTP structure */
-	http = zalloc ( sizeof ( *http ) );
-	if ( ! http )
-		return -ENOMEM;
-	ref_init ( &http->refcnt, http_free );
-	intf_init ( &http->xfer, &http_xfer_desc, &http->refcnt );
-       	http->uri = uri_get ( uri );
-	intf_init ( &http->socket, &http_socket_desc, &http->refcnt );
-	process_init ( &http->process, http_step, &http->refcnt );
-
-	/* Open socket */
-	memset ( &server, 0, sizeof ( server ) );
-	server.st_port = htons ( uri_port ( http->uri, default_port ) );
-	socket = &http->socket;
-	if ( filter ) {
-		if ( ( rc = filter ( socket, &socket ) ) != 0 )
-			goto err;
-	}
-	if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM,
-					     ( struct sockaddr * ) &server,
-					     uri->host, NULL ) ) != 0 )
-		goto err;
-
-	/* Attach to parent interface, mortalise self, and return */
-	intf_plug_plug ( &http->xfer, xfer );
-	ref_put ( &http->refcnt );
-	return 0;
-
- err:
-	DBGC ( http, "HTTP %p could not create request: %s\n", 
-	       http, strerror ( rc ) );
-	http_done ( http, rc );
-	ref_put ( &http->refcnt );
-	return rc;
-}
-
 /**
  * Initiate an HTTP connection
  *
diff --git a/roms/ipxe/src/net/tcp/httpcore.c b/roms/ipxe/src/net/tcp/httpcore.c
new file mode 100644
index 0000000000000000000000000000000000000000..bccb35f5f4b7bacc84e73fb41e16bac0df459ee0
--- /dev/null
+++ b/roms/ipxe/src/net/tcp/httpcore.c
@@ -0,0 +1,1363 @@
+/*
+ * Copyright (C) 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Hyper Text Transfer Protocol (HTTP) core functionality
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <byteswap.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/uri.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/socket.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/process.h>
+#include <ipxe/linebuf.h>
+#include <ipxe/base64.h>
+#include <ipxe/base16.h>
+#include <ipxe/md5.h>
+#include <ipxe/blockdev.h>
+#include <ipxe/acpi.h>
+#include <ipxe/version.h>
+#include <ipxe/http.h>
+
+/* Disambiguate the various error causes */
+#define EACCES_401 __einfo_error ( EINFO_EACCES_401 )
+#define EINFO_EACCES_401 \
+	__einfo_uniqify ( EINFO_EACCES, 0x01, "HTTP 401 Unauthorized" )
+#define EIO_OTHER __einfo_error ( EINFO_EIO_OTHER )
+#define EINFO_EIO_OTHER \
+	__einfo_uniqify ( EINFO_EIO, 0x01, "Unrecognised HTTP response code" )
+#define EIO_CONTENT_LENGTH __einfo_error ( EINFO_EIO_CONTENT_LENGTH )
+#define EINFO_EIO_CONTENT_LENGTH \
+	__einfo_uniqify ( EINFO_EIO, 0x02, "Content length mismatch" )
+#define EINVAL_RESPONSE __einfo_error ( EINFO_EINVAL_RESPONSE )
+#define EINFO_EINVAL_RESPONSE \
+	__einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid content length" )
+#define EINVAL_HEADER __einfo_error ( EINFO_EINVAL_HEADER )
+#define EINFO_EINVAL_HEADER \
+	__einfo_uniqify ( EINFO_EINVAL, 0x02, "Invalid header" )
+#define EINVAL_CONTENT_LENGTH __einfo_error ( EINFO_EINVAL_CONTENT_LENGTH )
+#define EINFO_EINVAL_CONTENT_LENGTH \
+	__einfo_uniqify ( EINFO_EINVAL, 0x03, "Invalid content length" )
+#define EINVAL_CHUNK_LENGTH __einfo_error ( EINFO_EINVAL_CHUNK_LENGTH )
+#define EINFO_EINVAL_CHUNK_LENGTH \
+	__einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid chunk length" )
+#define ENOENT_404 __einfo_error ( EINFO_ENOENT_404 )
+#define EINFO_ENOENT_404 \
+	__einfo_uniqify ( EINFO_ENOENT, 0x01, "HTTP 404 Not Found" )
+#define EPERM_403 __einfo_error ( EINFO_EPERM_403 )
+#define EINFO_EPERM_403 \
+	__einfo_uniqify ( EINFO_EPERM, 0x01, "HTTP 403 Forbidden" )
+#define EPROTO_UNSOLICITED __einfo_error ( EINFO_EPROTO_UNSOLICITED )
+#define EINFO_EPROTO_UNSOLICITED \
+	__einfo_uniqify ( EINFO_EPROTO, 0x01, "Unsolicited data" )
+
+/** Block size used for HTTP block device request */
+#define HTTP_BLKSIZE 512
+
+/** HTTP flags */
+enum http_flags {
+	/** Request is waiting to be transmitted */
+	HTTP_TX_PENDING = 0x0001,
+	/** Fetch header only */
+	HTTP_HEAD_ONLY = 0x0002,
+	/** Client would like to keep connection alive */
+	HTTP_CLIENT_KEEPALIVE = 0x0004,
+	/** Server will keep connection alive */
+	HTTP_SERVER_KEEPALIVE = 0x0008,
+	/** Discard the current request and try again */
+	HTTP_TRY_AGAIN = 0x0010,
+	/** Provide Basic authentication details */
+	HTTP_BASIC_AUTH = 0x0020,
+	/** Provide Digest authentication details */
+	HTTP_DIGEST_AUTH = 0x0040,
+};
+
+/** HTTP receive state */
+enum http_rx_state {
+	HTTP_RX_RESPONSE = 0,
+	HTTP_RX_HEADER,
+	HTTP_RX_CHUNK_LEN,
+	/* In HTTP_RX_DATA, it is acceptable for the server to close
+	 * the connection (unless we are in the middle of a chunked
+	 * transfer).
+	 */
+	HTTP_RX_DATA,
+	/* In the following states, it is acceptable for the server to
+	 * close the connection.
+	 */
+	HTTP_RX_TRAILER,
+	HTTP_RX_IDLE,
+	HTTP_RX_DEAD,
+};
+
+/**
+ * An HTTP request
+ *
+ */
+struct http_request {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** Data transfer interface */
+	struct interface xfer;
+	/** Partial transfer interface */
+	struct interface partial;
+
+	/** URI being fetched */
+	struct uri *uri;
+	/** Default port */
+	unsigned int default_port;
+	/** Filter (if any) */
+	int ( * filter ) ( struct interface *xfer,
+			   const char *name,
+			   struct interface **next );
+	/** Transport layer interface */
+	struct interface socket;
+
+	/** Flags */
+	unsigned int flags;
+	/** Starting offset of partial transfer (if applicable) */
+	size_t partial_start;
+	/** Length of partial transfer (if applicable) */
+	size_t partial_len;
+
+	/** TX process */
+	struct process process;
+
+	/** RX state */
+	enum http_rx_state rx_state;
+	/** Response code */
+	unsigned int code;
+	/** Received length */
+	size_t rx_len;
+	/** Length remaining (or 0 if unknown) */
+	size_t remaining;
+	/** HTTP is using Transfer-Encoding: chunked */
+	int chunked;
+	/** Current chunk length remaining (if applicable) */
+	size_t chunk_remaining;
+	/** Line buffer for received header lines */
+	struct line_buffer linebuf;
+	/** Receive data buffer (if applicable) */
+	userptr_t rx_buffer;
+
+	/** Authentication realm (if any) */
+	char *auth_realm;
+	/** Authentication nonce (if any) */
+	char *auth_nonce;
+	/** Authentication opaque string (if any) */
+	char *auth_opaque;
+};
+
+/**
+ * Free HTTP request
+ *
+ * @v refcnt		Reference counter
+ */
+static void http_free ( struct refcnt *refcnt ) {
+	struct http_request *http =
+		container_of ( refcnt, struct http_request, refcnt );
+
+	uri_put ( http->uri );
+	empty_line_buffer ( &http->linebuf );
+	free ( http->auth_realm );
+	free ( http->auth_nonce );
+	free ( http->auth_opaque );
+	free ( http );
+};
+
+/**
+ * Close HTTP request
+ *
+ * @v http		HTTP request
+ * @v rc		Return status code
+ */
+static void http_close ( struct http_request *http, int rc ) {
+
+	/* Prevent further processing of any current packet */
+	http->rx_state = HTTP_RX_DEAD;
+
+	/* Prevent reconnection */
+	http->flags &= ~HTTP_CLIENT_KEEPALIVE;
+
+	/* Remove process */
+	process_del ( &http->process );
+
+	/* Close all data transfer interfaces */
+	intf_shutdown ( &http->socket, rc );
+	intf_shutdown ( &http->partial, rc );
+	intf_shutdown ( &http->xfer, rc );
+}
+
+/**
+ * Open HTTP socket
+ *
+ * @v http		HTTP request
+ * @ret rc		Return status code
+ */
+static int http_socket_open ( struct http_request *http ) {
+	struct uri *uri = http->uri;
+	struct sockaddr_tcpip server;
+	struct interface *socket;
+	int rc;
+
+	/* Open socket */
+	memset ( &server, 0, sizeof ( server ) );
+	server.st_port = htons ( uri_port ( uri, http->default_port ) );
+	socket = &http->socket;
+	if ( http->filter ) {
+		if ( ( rc = http->filter ( socket, uri->host, &socket ) ) != 0 )
+			return rc;
+	}
+	if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM,
+					     ( struct sockaddr * ) &server,
+					     uri->host, NULL ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Mark HTTP request as completed successfully
+ *
+ * @v http		HTTP request
+ */
+static void http_done ( struct http_request *http ) {
+	int rc;
+
+	/* If we are not at an appropriate stage of the protocol
+	 * (including being in the middle of a chunked transfer),
+	 * force an error.
+	 */
+	if ( ( http->rx_state < HTTP_RX_DATA ) || ( http->chunked != 0 ) ) {
+		DBGC ( http, "HTTP %p connection closed unexpectedly in state "
+		       "%d\n", http, http->rx_state );
+		http_close ( http, -ECONNRESET );
+		return;
+	}
+
+	/* If we had a Content-Length, and the received content length
+	 * isn't correct, force an error
+	 */
+	if ( http->remaining != 0 ) {
+		DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n",
+		       http, http->rx_len, ( http->rx_len + http->remaining ) );
+		http_close ( http, -EIO_CONTENT_LENGTH );
+		return;
+	}
+
+	/* Enter idle state */
+	http->rx_state = HTTP_RX_IDLE;
+	http->rx_len = 0;
+	assert ( http->remaining == 0 );
+	assert ( http->chunked == 0 );
+	assert ( http->chunk_remaining == 0 );
+
+	/* Close partial transfer interface */
+	if ( ! ( http->flags & HTTP_TRY_AGAIN ) )
+		intf_restart ( &http->partial, 0 );
+
+	/* Close everything unless we want to keep the connection alive */
+	if ( ! ( http->flags & ( HTTP_CLIENT_KEEPALIVE | HTTP_TRY_AGAIN ) ) ) {
+		http_close ( http, 0 );
+		return;
+	}
+
+	/* If the server is not intending to keep the connection
+	 * alive, then reopen the socket.
+	 */
+	if ( ! ( http->flags & HTTP_SERVER_KEEPALIVE ) ) {
+		DBGC ( http, "HTTP %p reopening connection\n", http );
+		intf_restart ( &http->socket, 0 );
+		if ( ( rc = http_socket_open ( http ) ) != 0 ) {
+			http_close ( http, rc );
+			return;
+		}
+	}
+	http->flags &= ~HTTP_SERVER_KEEPALIVE;
+
+	/* Retry the request if applicable */
+	if ( http->flags & HTTP_TRY_AGAIN ) {
+		http->flags &= ~HTTP_TRY_AGAIN;
+		http->flags |= HTTP_TX_PENDING;
+		http->rx_state = HTTP_RX_RESPONSE;
+		process_add ( &http->process );
+	}
+}
+
+/**
+ * Convert HTTP response code to return status code
+ *
+ * @v response		HTTP response code
+ * @ret rc		Return status code
+ */
+static int http_response_to_rc ( unsigned int response ) {
+	switch ( response ) {
+	case 200:
+	case 206:
+	case 301:
+	case 302:
+	case 303:
+		return 0;
+	case 404:
+		return -ENOENT_404;
+	case 403:
+		return -EPERM_403;
+	case 401:
+		return -EACCES_401;
+	default:
+		return -EIO_OTHER;
+	}
+}
+
+/**
+ * Handle HTTP response
+ *
+ * @v http		HTTP request
+ * @v response		HTTP response
+ * @ret rc		Return status code
+ */
+static int http_rx_response ( struct http_request *http, char *response ) {
+	char *spc;
+
+	DBGC ( http, "HTTP %p response \"%s\"\n", http, response );
+
+	/* Check response starts with "HTTP/" */
+	if ( strncmp ( response, "HTTP/", 5 ) != 0 )
+		return -EINVAL_RESPONSE;
+
+	/* Locate and store response code */
+	spc = strchr ( response, ' ' );
+	if ( ! spc )
+		return -EINVAL_RESPONSE;
+	http->code = strtoul ( spc, NULL, 10 );
+
+	/* Move to receive headers */
+	http->rx_state = ( ( http->flags & HTTP_HEAD_ONLY ) ?
+			   HTTP_RX_TRAILER : HTTP_RX_HEADER );
+	return 0;
+}
+
+/**
+ * Handle HTTP Location header
+ *
+ * @v http		HTTP request
+ * @v value		HTTP header value
+ * @ret rc		Return status code
+ */
+static int http_rx_location ( struct http_request *http, char *value ) {
+	int rc;
+
+	/* Redirect to new location */
+	DBGC ( http, "HTTP %p redirecting to %s\n", http, value );
+	if ( ( rc = xfer_redirect ( &http->xfer, LOCATION_URI_STRING,
+				    value ) ) != 0 ) {
+		DBGC ( http, "HTTP %p could not redirect: %s\n",
+		       http, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle HTTP Content-Length header
+ *
+ * @v http		HTTP request
+ * @v value		HTTP header value
+ * @ret rc		Return status code
+ */
+static int http_rx_content_length ( struct http_request *http, char *value ) {
+	struct block_device_capacity capacity;
+	size_t content_len;
+	char *endp;
+
+	/* Parse content length */
+	content_len = strtoul ( value, &endp, 10 );
+	if ( *endp != '\0' ) {
+		DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n",
+		       http, value );
+		return -EINVAL_CONTENT_LENGTH;
+	}
+
+	/* If we already have an expected content length, and this
+	 * isn't it, then complain
+	 */
+	if ( http->remaining && ( http->remaining != content_len ) ) {
+		DBGC ( http, "HTTP %p incorrect Content-Length %zd (expected "
+		       "%zd)\n", http, content_len, http->remaining );
+		return -EIO_CONTENT_LENGTH;
+	}
+	if ( ! ( http->flags & HTTP_HEAD_ONLY ) )
+		http->remaining = content_len;
+
+	/* Do nothing more if we are retrying the request */
+	if ( http->flags & HTTP_TRY_AGAIN )
+		return 0;
+
+	/* Use seek() to notify recipient of filesize */
+	xfer_seek ( &http->xfer, http->remaining );
+	xfer_seek ( &http->xfer, 0 );
+
+	/* Report block device capacity if applicable */
+	if ( http->flags & HTTP_HEAD_ONLY ) {
+		capacity.blocks = ( content_len / HTTP_BLKSIZE );
+		capacity.blksize = HTTP_BLKSIZE;
+		capacity.max_count = -1U;
+		block_capacity ( &http->partial, &capacity );
+	}
+	return 0;
+}
+
+/**
+ * Handle HTTP Transfer-Encoding header
+ *
+ * @v http		HTTP request
+ * @v value		HTTP header value
+ * @ret rc		Return status code
+ */
+static int http_rx_transfer_encoding ( struct http_request *http, char *value ){
+
+	if ( strcasecmp ( value, "chunked" ) == 0 ) {
+		/* Mark connection as using chunked transfer encoding */
+		http->chunked = 1;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle HTTP Connection header
+ *
+ * @v http		HTTP request
+ * @v value		HTTP header value
+ * @ret rc		Return status code
+ */
+static int http_rx_connection ( struct http_request *http, char *value ) {
+
+	if ( strcasecmp ( value, "keep-alive" ) == 0 ) {
+		/* Mark connection as being kept alive by the server */
+		http->flags |= HTTP_SERVER_KEEPALIVE;
+	}
+
+	return 0;
+}
+
+/**
+ * Handle WWW-Authenticate Basic header
+ *
+ * @v http		HTTP request
+ * @v params		Parameters
+ * @ret rc		Return status code
+ */
+static int http_rx_basic_auth ( struct http_request *http, char *params ) {
+
+	DBGC ( http, "HTTP %p Basic authentication required (%s)\n",
+	       http, params );
+
+	/* If we received a 401 Unauthorized response, then retry
+	 * using Basic authentication
+	 */
+	if ( ( http->code == 401 ) &&
+	     ( ! ( http->flags & HTTP_BASIC_AUTH ) ) &&
+	     ( http->uri->user != NULL ) ) {
+		http->flags |= ( HTTP_TRY_AGAIN | HTTP_BASIC_AUTH );
+	}
+
+	return 0;
+}
+
+/**
+ * Parse Digest authentication parameter
+ *
+ * @v params		Parameters
+ * @v name		Parameter name (including trailing "=\"")
+ * @ret value		Parameter value, or NULL
+ */
+static char * http_digest_param ( char *params, const char *name ) {
+	char *key;
+	char *value;
+	char *terminator;
+
+	/* Locate parameter */
+	key = strstr ( params, name );
+	if ( ! key )
+		return NULL;
+
+	/* Extract value */
+	value = ( key + strlen ( name ) );
+	terminator = strchr ( value, '"' );
+	if ( ! terminator )
+		return NULL;
+	return strndup ( value, ( terminator - value ) );
+}
+
+/**
+ * Handle WWW-Authenticate Digest header
+ *
+ * @v http		HTTP request
+ * @v params		Parameters
+ * @ret rc		Return status code
+ */
+static int http_rx_digest_auth ( struct http_request *http, char *params ) {
+
+	DBGC ( http, "HTTP %p Digest authentication required (%s)\n",
+	       http, params );
+
+	/* If we received a 401 Unauthorized response, then retry
+	 * using Digest authentication
+	 */
+	if ( ( http->code == 401 ) &&
+	     ( ! ( http->flags & HTTP_DIGEST_AUTH ) ) &&
+	     ( http->uri->user != NULL ) ) {
+
+		/* Extract realm */
+		free ( http->auth_realm );
+		http->auth_realm = http_digest_param ( params, "realm=\"" );
+		if ( ! http->auth_realm ) {
+			DBGC ( http, "HTTP %p Digest prompt missing realm\n",
+			       http );
+			return -EINVAL_HEADER;
+		}
+
+		/* Extract nonce */
+		free ( http->auth_nonce );
+		http->auth_nonce = http_digest_param ( params, "nonce=\"" );
+		if ( ! http->auth_nonce ) {
+			DBGC ( http, "HTTP %p Digest prompt missing nonce\n",
+			       http );
+			return -EINVAL_HEADER;
+		}
+
+		/* Extract opaque */
+		free ( http->auth_opaque );
+		http->auth_opaque = http_digest_param ( params, "opaque=\"" );
+		if ( ! http->auth_opaque ) {
+			/* Not an error; "opaque" is optional */
+		}
+
+		http->flags |= ( HTTP_TRY_AGAIN | HTTP_DIGEST_AUTH );
+	}
+
+	return 0;
+}
+
+/** An HTTP WWW-Authenticate header handler */
+struct http_auth_header_handler {
+	/** Scheme (e.g. "Basic") */
+	const char *scheme;
+	/** Handle received parameters
+	 *
+	 * @v http	HTTP request
+	 * @v params	Parameters
+	 * @ret rc	Return status code
+	 */
+	int ( * rx ) ( struct http_request *http, char *params );
+};
+
+/** List of HTTP WWW-Authenticate header handlers */
+static struct http_auth_header_handler http_auth_header_handlers[] = {
+	{
+		.scheme = "Basic",
+		.rx = http_rx_basic_auth,
+	},
+	{
+		.scheme = "Digest",
+		.rx = http_rx_digest_auth,
+	},
+	{ NULL, NULL },
+};
+
+/**
+ * Handle HTTP WWW-Authenticate header
+ *
+ * @v http		HTTP request
+ * @v value		HTTP header value
+ * @ret rc		Return status code
+ */
+static int http_rx_www_authenticate ( struct http_request *http, char *value ) {
+	struct http_auth_header_handler *handler;
+	char *separator;
+	char *scheme;
+	char *params;
+	int rc;
+
+	/* Extract scheme */
+	separator = strchr ( value, ' ' );
+	if ( ! separator ) {
+		DBGC ( http, "HTTP %p malformed WWW-Authenticate header\n",
+		       http );
+		return -EINVAL_HEADER;
+	}
+	*separator = '\0';
+	scheme = value;
+	params = ( separator + 1 );
+
+	/* Hand off to header handler, if one exists */
+	for ( handler = http_auth_header_handlers; handler->scheme; handler++ ){
+		if ( strcasecmp ( scheme, handler->scheme ) == 0 ) {
+			if ( ( rc = handler->rx ( http, params ) ) != 0 )
+				return rc;
+			break;
+		}
+	}
+	return 0;
+}
+
+/** An HTTP header handler */
+struct http_header_handler {
+	/** Name (e.g. "Content-Length") */
+	const char *header;
+	/** Handle received header
+	 *
+	 * @v http	HTTP request
+	 * @v value	HTTP header value
+	 * @ret rc	Return status code
+	 *
+	 * If an error is returned, the download will be aborted.
+	 */
+	int ( * rx ) ( struct http_request *http, char *value );
+};
+
+/** List of HTTP header handlers */
+static struct http_header_handler http_header_handlers[] = {
+	{
+		.header = "Location",
+		.rx = http_rx_location,
+	},
+	{
+		.header = "Content-Length",
+		.rx = http_rx_content_length,
+	},
+	{
+		.header = "Transfer-Encoding",
+		.rx = http_rx_transfer_encoding,
+	},
+	{
+		.header = "Connection",
+		.rx = http_rx_connection,
+	},
+	{
+		.header = "WWW-Authenticate",
+		.rx = http_rx_www_authenticate,
+	},
+	{ NULL, NULL }
+};
+
+/**
+ * Handle HTTP header
+ *
+ * @v http		HTTP request
+ * @v header		HTTP header
+ * @ret rc		Return status code
+ */
+static int http_rx_header ( struct http_request *http, char *header ) {
+	struct http_header_handler *handler;
+	char *separator;
+	char *value;
+	int rc;
+
+	/* An empty header line marks the end of this phase */
+	if ( ! header[0] ) {
+		empty_line_buffer ( &http->linebuf );
+
+		/* Handle response code */
+		if ( ! ( http->flags & HTTP_TRY_AGAIN ) ) {
+			if ( ( rc = http_response_to_rc ( http->code ) ) != 0 )
+				return rc;
+		}
+
+		/* Move to next state */
+		if ( http->rx_state == HTTP_RX_HEADER ) {
+			DBGC ( http, "HTTP %p start of data\n", http );
+			http->rx_state = ( http->chunked ?
+					   HTTP_RX_CHUNK_LEN : HTTP_RX_DATA );
+			if ( ( http->partial_len != 0 ) &&
+			     ( ! ( http->flags & HTTP_TRY_AGAIN ) ) ) {
+				http->remaining = http->partial_len;
+			}
+			return 0;
+		} else {
+			DBGC ( http, "HTTP %p end of trailer\n", http );
+			http_done ( http );
+			return 0;
+		}
+	}
+
+	DBGC ( http, "HTTP %p header \"%s\"\n", http, header );
+
+	/* Split header at the ": " */
+	separator = strstr ( header, ": " );
+	if ( ! separator ) {
+		DBGC ( http, "HTTP %p malformed header\n", http );
+		return -EINVAL_HEADER;
+	}
+	*separator = '\0';
+	value = ( separator + 2 );
+
+	/* Hand off to header handler, if one exists */
+	for ( handler = http_header_handlers ; handler->header ; handler++ ) {
+		if ( strcasecmp ( header, handler->header ) == 0 ) {
+			if ( ( rc = handler->rx ( http, value ) ) != 0 )
+				return rc;
+			break;
+		}
+	}
+	return 0;
+}
+
+/**
+ * Handle HTTP chunk length
+ *
+ * @v http		HTTP request
+ * @v length		HTTP chunk length
+ * @ret rc		Return status code
+ */
+static int http_rx_chunk_len ( struct http_request *http, char *length ) {
+	char *endp;
+
+	/* Skip blank lines between chunks */
+	if ( length[0] == '\0' )
+		return 0;
+
+	/* Parse chunk length */
+	http->chunk_remaining = strtoul ( length, &endp, 16 );
+	if ( *endp != '\0' ) {
+		DBGC ( http, "HTTP %p invalid chunk length \"%s\"\n",
+		       http, length );
+		return -EINVAL_CHUNK_LENGTH;
+	}
+
+	/* Terminate chunked encoding if applicable */
+	if ( http->chunk_remaining == 0 ) {
+		DBGC ( http, "HTTP %p end of chunks\n", http );
+		http->chunked = 0;
+		http->rx_state = HTTP_RX_TRAILER;
+		return 0;
+	}
+
+	/* Use seek() to notify recipient of new filesize */
+	DBGC ( http, "HTTP %p start of chunk of length %zd\n",
+	       http, http->chunk_remaining );
+	if ( ! ( http->flags & HTTP_TRY_AGAIN ) ) {
+		xfer_seek ( &http->xfer,
+			    ( http->rx_len + http->chunk_remaining ) );
+		xfer_seek ( &http->xfer, http->rx_len );
+	}
+
+	/* Start receiving data */
+	http->rx_state = HTTP_RX_DATA;
+
+	return 0;
+}
+
+/** An HTTP line-based data handler */
+struct http_line_handler {
+	/** Handle line
+	 *
+	 * @v http	HTTP request
+	 * @v line	Line to handle
+	 * @ret rc	Return status code
+	 */
+	int ( * rx ) ( struct http_request *http, char *line );
+};
+
+/** List of HTTP line-based data handlers */
+static struct http_line_handler http_line_handlers[] = {
+	[HTTP_RX_RESPONSE]	= { .rx = http_rx_response },
+	[HTTP_RX_HEADER]	= { .rx = http_rx_header },
+	[HTTP_RX_CHUNK_LEN]	= { .rx = http_rx_chunk_len },
+	[HTTP_RX_TRAILER]	= { .rx = http_rx_header },
+};
+
+/**
+ * Handle new data arriving via HTTP connection
+ *
+ * @v http		HTTP request
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int http_socket_deliver ( struct http_request *http,
+				 struct io_buffer *iobuf,
+				 struct xfer_metadata *meta __unused ) {
+	struct http_line_handler *lh;
+	char *line;
+	size_t data_len;
+	ssize_t line_len;
+	int rc = 0;
+
+	while ( iobuf && iob_len ( iobuf ) ) {
+
+		switch ( http->rx_state ) {
+		case HTTP_RX_IDLE:
+			/* Receiving any data in this state is an error */
+			DBGC ( http, "HTTP %p received %zd bytes while %s\n",
+			       http, iob_len ( iobuf ),
+			       ( ( http->rx_state == HTTP_RX_IDLE ) ?
+				 "idle" : "dead" ) );
+			rc = -EPROTO_UNSOLICITED;
+			goto done;
+		case HTTP_RX_DEAD:
+			/* Do no further processing */
+			goto done;
+		case HTTP_RX_DATA:
+			/* Pass received data to caller */
+			data_len = iob_len ( iobuf );
+			if ( http->chunk_remaining &&
+			     ( http->chunk_remaining < data_len ) ) {
+				data_len = http->chunk_remaining;
+			}
+			if ( http->remaining &&
+			     ( http->remaining < data_len ) ) {
+				data_len = http->remaining;
+			}
+			if ( http->flags & HTTP_TRY_AGAIN ) {
+				/* Discard all received data */
+				iob_pull ( iobuf, data_len );
+			} else if ( http->rx_buffer != UNULL ) {
+				/* Copy to partial transfer buffer */
+				copy_to_user ( http->rx_buffer, http->rx_len,
+					       iobuf->data, data_len );
+				iob_pull ( iobuf, data_len );
+			} else if ( data_len < iob_len ( iobuf ) ) {
+				/* Deliver partial buffer as raw data */
+				rc = xfer_deliver_raw ( &http->xfer,
+							iobuf->data, data_len );
+				iob_pull ( iobuf, data_len );
+				if ( rc != 0 )
+					goto done;
+			} else {
+				/* Deliver whole I/O buffer */
+				if ( ( rc = xfer_deliver_iob ( &http->xfer,
+						 iob_disown ( iobuf ) ) ) != 0 )
+					goto done;
+			}
+			http->rx_len += data_len;
+			if ( http->chunk_remaining ) {
+				http->chunk_remaining -= data_len;
+				if ( http->chunk_remaining == 0 )
+					http->rx_state = HTTP_RX_CHUNK_LEN;
+			}
+			if ( http->remaining ) {
+				http->remaining -= data_len;
+				if ( ( http->remaining == 0 ) &&
+				     ( http->rx_state == HTTP_RX_DATA ) ) {
+					http_done ( http );
+				}
+			}
+			break;
+		case HTTP_RX_RESPONSE:
+		case HTTP_RX_HEADER:
+		case HTTP_RX_CHUNK_LEN:
+		case HTTP_RX_TRAILER:
+			/* In the other phases, buffer and process a
+			 * line at a time
+			 */
+			line_len = line_buffer ( &http->linebuf, iobuf->data,
+						 iob_len ( iobuf ) );
+			if ( line_len < 0 ) {
+				rc = line_len;
+				DBGC ( http, "HTTP %p could not buffer line: "
+				       "%s\n", http, strerror ( rc ) );
+				goto done;
+			}
+			iob_pull ( iobuf, line_len );
+			line = buffered_line ( &http->linebuf );
+			if ( line ) {
+				lh = &http_line_handlers[http->rx_state];
+				if ( ( rc = lh->rx ( http, line ) ) != 0 )
+					goto done;
+			}
+			break;
+		default:
+			assert ( 0 );
+			break;
+		}
+	}
+
+ done:
+	if ( rc )
+		http_close ( http, rc );
+	free_iob ( iobuf );
+	return rc;
+}
+
+/**
+ * Check HTTP socket flow control window
+ *
+ * @v http		HTTP request
+ * @ret len		Length of window
+ */
+static size_t http_socket_window ( struct http_request *http __unused ) {
+
+	/* Window is always open.  This is to prevent TCP from
+	 * stalling if our parent window is not currently open.
+	 */
+	return ( ~( ( size_t ) 0 ) );
+}
+
+/**
+ * Close HTTP socket
+ *
+ * @v http		HTTP request
+ * @v rc		Reason for close
+ */
+static void http_socket_close ( struct http_request *http, int rc ) {
+
+	/* If we have an error, terminate */
+	if ( rc != 0 ) {
+		http_close ( http, rc );
+		return;
+	}
+
+	/* Mark HTTP request as complete */
+	http_done ( http );
+}
+
+/**
+ * Generate HTTP Basic authorisation string
+ *
+ * @v http		HTTP request
+ * @ret auth		Authorisation string, or NULL on error
+ *
+ * The authorisation string is dynamically allocated, and must be
+ * freed by the caller.
+ */
+static char * http_basic_auth ( struct http_request *http ) {
+	const char *user = http->uri->user;
+	const char *password =
+		( http->uri->password ? http->uri->password : "" );
+	size_t user_pw_len =
+		( strlen ( user ) + 1 /* ":" */ + strlen ( password ) );
+	char user_pw[ user_pw_len + 1 /* NUL */ ];
+	size_t user_pw_base64_len = base64_encoded_len ( user_pw_len );
+	char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ];
+	char *auth;
+	int len;
+
+	/* Sanity check */
+	assert ( user != NULL );
+
+	/* Make "user:password" string from decoded fields */
+	snprintf ( user_pw, sizeof ( user_pw ), "%s:%s", user, password );
+
+	/* Base64-encode the "user:password" string */
+	base64_encode ( ( void * ) user_pw, user_pw_len, user_pw_base64 );
+
+	/* Generate the authorisation string */
+	len = asprintf ( &auth, "Authorization: Basic %s\r\n",
+			 user_pw_base64 );
+	if ( len < 0 )
+		return NULL;
+
+	return auth;
+}
+
+/**
+ * Generate HTTP Digest authorisation string
+ *
+ * @v http		HTTP request
+ * @v method		HTTP method (e.g. "GET")
+ * @v uri		HTTP request URI (e.g. "/index.html")
+ * @ret auth		Authorisation string, or NULL on error
+ *
+ * The authorisation string is dynamically allocated, and must be
+ * freed by the caller.
+ */
+static char * http_digest_auth ( struct http_request *http,
+				 const char *method, const char *uri ) {
+	const char *user = http->uri->user;
+	const char *password =
+		( http->uri->password ? http->uri->password : "" );
+	const char *realm = http->auth_realm;
+	const char *nonce = http->auth_nonce;
+	const char *opaque = http->auth_opaque;
+	static const char colon = ':';
+	uint8_t ctx[MD5_CTX_SIZE];
+	uint8_t digest[MD5_DIGEST_SIZE];
+	char ha1[ base16_encoded_len ( sizeof ( digest ) ) + 1 /* NUL */ ];
+	char ha2[ base16_encoded_len ( sizeof ( digest ) ) + 1 /* NUL */ ];
+	char response[ base16_encoded_len ( sizeof ( digest ) ) + 1 /* NUL */ ];
+	char *auth;
+	int len;
+
+	/* Sanity checks */
+	assert ( user != NULL );
+	assert ( realm != NULL );
+	assert ( nonce != NULL );
+
+	/* Generate HA1 */
+	digest_init ( &md5_algorithm, ctx );
+	digest_update ( &md5_algorithm, ctx, user, strlen ( user ) );
+	digest_update ( &md5_algorithm, ctx, &colon, sizeof ( colon ) );
+	digest_update ( &md5_algorithm, ctx, realm, strlen ( realm ) );
+	digest_update ( &md5_algorithm, ctx, &colon, sizeof ( colon ) );
+	digest_update ( &md5_algorithm, ctx, password, strlen ( password ) );
+	digest_final ( &md5_algorithm, ctx, digest );
+	base16_encode ( digest, sizeof ( digest ), ha1 );
+
+	/* Generate HA2 */
+	digest_init ( &md5_algorithm, ctx );
+	digest_update ( &md5_algorithm, ctx, method, strlen ( method ) );
+	digest_update ( &md5_algorithm, ctx, &colon, sizeof ( colon ) );
+	digest_update ( &md5_algorithm, ctx, uri, strlen ( uri ) );
+	digest_final ( &md5_algorithm, ctx, digest );
+	base16_encode ( digest, sizeof ( digest ), ha2 );
+
+	/* Generate response */
+	digest_init ( &md5_algorithm, ctx );
+	digest_update ( &md5_algorithm, ctx, ha1, strlen ( ha1 ) );
+	digest_update ( &md5_algorithm, ctx, &colon, sizeof ( colon ) );
+	digest_update ( &md5_algorithm, ctx, nonce, strlen ( nonce ) );
+	digest_update ( &md5_algorithm, ctx, &colon, sizeof ( colon ) );
+	digest_update ( &md5_algorithm, ctx, ha2, strlen ( ha2 ) );
+	digest_final ( &md5_algorithm, ctx, digest );
+	base16_encode ( digest, sizeof ( digest ), response );
+
+	/* Generate the authorisation string */
+	len = asprintf ( &auth, "Authorization: Digest username=\"%s\", "
+			 "realm=\"%s\", nonce=\"%s\", uri=\"%s\", "
+			 "%s%s%sresponse=\"%s\"\r\n", user, realm, nonce, uri,
+			 ( opaque ? "opaque=\"" : "" ),
+			 ( opaque ? opaque : "" ),
+			 ( opaque ? "\", " : "" ), response );
+	if ( len < 0 )
+		return NULL;
+
+	return auth;
+}
+
+/**
+ * HTTP process
+ *
+ * @v http		HTTP request
+ */
+static void http_step ( struct http_request *http ) {
+	size_t uri_len;
+	char *method;
+	char *uri;
+	char *range;
+	char *auth;
+	int len;
+	int rc;
+
+	/* Do nothing if we have already transmitted the request */
+	if ( ! ( http->flags & HTTP_TX_PENDING ) )
+		return;
+
+	/* Do nothing until socket is ready */
+	if ( ! xfer_window ( &http->socket ) )
+		return;
+
+	/* Force a HEAD request if we have nowhere to send any received data */
+	if ( ( xfer_window ( &http->xfer ) == 0 ) &&
+	     ( http->rx_buffer == UNULL ) ) {
+		http->flags |= ( HTTP_HEAD_ONLY | HTTP_CLIENT_KEEPALIVE );
+	}
+
+	/* Determine method */
+	method = ( ( http->flags & HTTP_HEAD_ONLY ) ? "HEAD" : "GET" );
+
+	/* Construct path?query request */
+	uri_len = ( unparse_uri ( NULL, 0, http->uri,
+				  URI_PATH_BIT | URI_QUERY_BIT )
+		    + 1 /* possible "/" */ + 1 /* NUL */ );
+	uri = malloc ( uri_len );
+	if ( ! uri ) {
+		rc = -ENOMEM;
+		goto err_uri;
+	}
+	unparse_uri ( uri, uri_len, http->uri, URI_PATH_BIT | URI_QUERY_BIT );
+	if ( ! uri[0] ) {
+		uri[0] = '/';
+		uri[1] = '\0';
+	}
+
+	/* Calculate range request parameters if applicable */
+	if ( http->partial_len ) {
+		len = asprintf ( &range, "Range: bytes=%zd-%zd\r\n",
+				 http->partial_start,
+				 ( http->partial_start + http->partial_len
+				   - 1 ) );
+		if ( len < 0 ) {
+			rc = len;
+			goto err_range;
+		}
+	} else {
+		range = NULL;
+	}
+
+	/* Construct authorisation, if applicable */
+	if ( http->flags & HTTP_BASIC_AUTH ) {
+		auth = http_basic_auth ( http );
+		if ( ! auth ) {
+			rc = -ENOMEM;
+			goto err_auth;
+		}
+	} else if ( http->flags & HTTP_DIGEST_AUTH ) {
+		auth = http_digest_auth ( http, method, uri );
+		if ( ! auth ) {
+			rc = -ENOMEM;
+			goto err_auth;
+		}
+	} else {
+		auth = NULL;
+	}
+
+	/* Mark request as transmitted */
+	http->flags &= ~HTTP_TX_PENDING;
+
+	/* Send request */
+	if ( ( rc = xfer_printf ( &http->socket,
+				  "%s %s HTTP/1.1\r\n"
+				  "User-Agent: iPXE/%s\r\n"
+				  "Host: %s%s%s\r\n"
+				  "%s%s%s"
+				  "\r\n",
+				  method, uri, product_version, http->uri->host,
+				  ( http->uri->port ?
+				    ":" : "" ),
+				  ( http->uri->port ?
+				    http->uri->port : "" ),
+				  ( ( http->flags & HTTP_CLIENT_KEEPALIVE ) ?
+				    "Connection: keep-alive\r\n" : "" ),
+				  ( range ? range : "" ),
+				  ( auth ? auth : "" ) ) ) != 0 ) {
+		goto err_xfer;
+	}
+
+ err_xfer:
+	free ( auth );
+ err_auth:
+	free ( range );
+ err_range:
+	free ( uri );
+ err_uri:
+	if ( rc != 0 )
+		http_close ( http, rc );
+}
+
+/**
+ * Check HTTP data transfer flow control window
+ *
+ * @v http		HTTP request
+ * @ret len		Length of window
+ */
+static size_t http_xfer_window ( struct http_request *http ) {
+
+	/* New block commands may be issued only when we are idle */
+	return ( ( http->rx_state == HTTP_RX_IDLE ) ? 1 : 0 );
+}
+
+/**
+ * Initiate HTTP partial read
+ *
+ * @v http		HTTP request
+ * @v partial		Partial transfer interface
+ * @v offset		Starting offset
+ * @v buffer		Data buffer
+ * @v len		Length
+ * @ret rc		Return status code
+ */
+static int http_partial_read ( struct http_request *http,
+			       struct interface *partial,
+			       size_t offset, userptr_t buffer, size_t len ) {
+
+	/* Sanity check */
+	if ( http_xfer_window ( http ) == 0 )
+		return -EBUSY;
+
+	/* Initialise partial transfer parameters */
+	http->rx_buffer = buffer;
+	http->partial_start = offset;
+	http->partial_len = len;
+
+	/* Schedule request */
+	http->rx_state = HTTP_RX_RESPONSE;
+	http->flags = ( HTTP_TX_PENDING | HTTP_CLIENT_KEEPALIVE );
+	if ( ! len )
+		http->flags |= HTTP_HEAD_ONLY;
+	process_add ( &http->process );
+
+	/* Attach to parent interface and return */
+	intf_plug_plug ( &http->partial, partial );
+
+	return 0;
+}
+
+/**
+ * Issue HTTP block device read
+ *
+ * @v http		HTTP request
+ * @v block		Block data interface
+ * @v lba		Starting logical block address
+ * @v count		Number of blocks to transfer
+ * @v buffer		Data buffer
+ * @v len		Length of data buffer
+ * @ret rc		Return status code
+ */
+static int http_block_read ( struct http_request *http,
+			     struct interface *block,
+			     uint64_t lba, unsigned int count,
+			     userptr_t buffer, size_t len __unused ) {
+
+	return http_partial_read ( http, block, ( lba * HTTP_BLKSIZE ),
+				   buffer, ( count * HTTP_BLKSIZE ) );
+}
+
+/**
+ * Read HTTP block device capacity
+ *
+ * @v http		HTTP request
+ * @v block		Block data interface
+ * @ret rc		Return status code
+ */
+static int http_block_read_capacity ( struct http_request *http,
+				      struct interface *block ) {
+
+	return http_partial_read ( http, block, 0, 0, 0 );
+}
+
+/**
+ * Describe HTTP device in an ACPI table
+ *
+ * @v http		HTTP request
+ * @v acpi		ACPI table
+ * @v len		Length of ACPI table
+ * @ret rc		Return status code
+ */
+static int http_acpi_describe ( struct http_request *http,
+				struct acpi_description_header *acpi,
+				size_t len ) {
+
+	DBGC ( http, "HTTP %p cannot yet describe device in an ACPI table\n",
+	       http );
+	( void ) acpi;
+	( void ) len;
+	return 0;
+}
+
+/** HTTP socket interface operations */
+static struct interface_operation http_socket_operations[] = {
+	INTF_OP ( xfer_window, struct http_request *, http_socket_window ),
+	INTF_OP ( xfer_deliver, struct http_request *, http_socket_deliver ),
+	INTF_OP ( xfer_window_changed, struct http_request *, http_step ),
+	INTF_OP ( intf_close, struct http_request *, http_socket_close ),
+};
+
+/** HTTP socket interface descriptor */
+static struct interface_descriptor http_socket_desc =
+	INTF_DESC_PASSTHRU ( struct http_request, socket,
+			     http_socket_operations, xfer );
+
+/** HTTP partial transfer interface operations */
+static struct interface_operation http_partial_operations[] = {
+	INTF_OP ( intf_close, struct http_request *, http_close ),
+};
+
+/** HTTP partial transfer interface descriptor */
+static struct interface_descriptor http_partial_desc =
+	INTF_DESC ( struct http_request, partial, http_partial_operations );
+
+/** HTTP data transfer interface operations */
+static struct interface_operation http_xfer_operations[] = {
+	INTF_OP ( xfer_window, struct http_request *, http_xfer_window ),
+	INTF_OP ( block_read, struct http_request *, http_block_read ),
+	INTF_OP ( block_read_capacity, struct http_request *,
+		  http_block_read_capacity ),
+	INTF_OP ( intf_close, struct http_request *, http_close ),
+	INTF_OP ( acpi_describe, struct http_request *, http_acpi_describe ),
+};
+
+/** HTTP data transfer interface descriptor */
+static struct interface_descriptor http_xfer_desc =
+	INTF_DESC_PASSTHRU ( struct http_request, xfer,
+			     http_xfer_operations, socket );
+
+/** HTTP process descriptor */
+static struct process_descriptor http_process_desc =
+	PROC_DESC_ONCE ( struct http_request, process, http_step );
+
+/**
+ * Initiate an HTTP connection, with optional filter
+ *
+ * @v xfer		Data transfer interface
+ * @v uri		Uniform Resource Identifier
+ * @v default_port	Default port number
+ * @v filter		Filter to apply to socket, or NULL
+ * @ret rc		Return status code
+ */
+int http_open_filter ( struct interface *xfer, struct uri *uri,
+		       unsigned int default_port,
+		       int ( * filter ) ( struct interface *xfer,
+					  const char *name,
+					  struct interface **next ) ) {
+	struct http_request *http;
+	int rc;
+
+	/* Sanity checks */
+	if ( ! uri->host )
+		return -EINVAL;
+
+	/* Allocate and populate HTTP structure */
+	http = zalloc ( sizeof ( *http ) );
+	if ( ! http )
+		return -ENOMEM;
+	ref_init ( &http->refcnt, http_free );
+	intf_init ( &http->xfer, &http_xfer_desc, &http->refcnt );
+	intf_init ( &http->partial, &http_partial_desc, &http->refcnt );
+	http->uri = uri_get ( uri );
+	http->default_port = default_port;
+	http->filter = filter;
+	intf_init ( &http->socket, &http_socket_desc, &http->refcnt );
+	process_init ( &http->process, &http_process_desc, &http->refcnt );
+	http->flags = HTTP_TX_PENDING;
+
+	/* Open socket */
+	if ( ( rc = http_socket_open ( http ) ) != 0 )
+		goto err;
+
+	/* Attach to parent interface, mortalise self, and return */
+	intf_plug_plug ( &http->xfer, xfer );
+	ref_put ( &http->refcnt );
+	return 0;
+
+ err:
+	DBGC ( http, "HTTP %p could not create request: %s\n",
+	       http, strerror ( rc ) );
+	http_close ( http, rc );
+	ref_put ( &http->refcnt );
+	return rc;
+}
diff --git a/roms/ipxe/src/net/tcp/https.c b/roms/ipxe/src/net/tcp/https.c
index 805d108bb2eee7340d72b19373f7..6112acdaee301cf54794ea2ad679 100644
--- a/roms/ipxe/src/net/tcp/https.c
+++ b/roms/ipxe/src/net/tcp/https.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/tcp/iscsi.c b/roms/ipxe/src/net/tcp/iscsi.c
index cde3ed6db02fdac23bcd2081bb2f..c9daf1ff4d14fa865c55bb9dfe4b 100644
--- a/roms/ipxe/src/net/tcp/iscsi.c
+++ b/roms/ipxe/src/net/tcp/iscsi.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -131,6 +132,14 @@ FEATURE ( FEATURE_PROTOCOL, "iSCSI", DHCP_EB_FEATURE_ISCSI, 1 );
 	__einfo_error ( EINFO_EPROTO_INVALID_CHAP_RESPONSE )
 #define EINFO_EPROTO_INVALID_CHAP_RESPONSE \
 	__einfo_uniqify ( EINFO_EPROTO, 0x04, "Invalid CHAP response" )
+#define EPROTO_INVALID_KEY_VALUE_PAIR \
+	__einfo_error ( EINFO_EPROTO_INVALID_KEY_VALUE_PAIR )
+#define EINFO_EPROTO_INVALID_KEY_VALUE_PAIR \
+	__einfo_uniqify ( EINFO_EPROTO, 0x05, "Invalid key/value pair" )
+#define EPROTO_VALUE_REJECTED \
+	__einfo_error ( EINFO_EPROTO_VALUE_REJECTED )
+#define EINFO_EPROTO_VALUE_REJECTED					\
+	__einfo_uniqify ( EINFO_EPROTO, 0x06, "Parameter rejected" )
 
 static void iscsi_start_tx ( struct iscsi_session *iscsi );
 static void iscsi_start_login ( struct iscsi_session *iscsi );
@@ -329,7 +338,8 @@ static void iscsi_scsi_done ( struct iscsi_session *iscsi, int rc,
 	iscsi->command = NULL;
 
 	/* Send SCSI response, if any */
-	scsi_response ( &iscsi->data, rsp );
+	if ( rsp )
+		scsi_response ( &iscsi->data, rsp );
 
 	/* Close SCSI command, if this is still the same command.  (It
 	 * is possible that the command interface has already been
@@ -562,20 +572,23 @@ static int iscsi_tx_data_out ( struct iscsi_session *iscsi ) {
 	struct io_buffer *iobuf;
 	unsigned long offset;
 	size_t len;
+	size_t pad_len;
 
 	offset = ntohl ( data_out->offset );
 	len = ISCSI_DATA_LEN ( data_out->lengths );
+	pad_len = ISCSI_DATA_PAD_LEN ( data_out->lengths );
 
 	assert ( iscsi->command != NULL );
 	assert ( iscsi->command->data_out );
 	assert ( ( offset + len ) <= iscsi->command->data_out_len );
 
-	iobuf = xfer_alloc_iob ( &iscsi->socket, len );
+	iobuf = xfer_alloc_iob ( &iscsi->socket, ( len + pad_len ) );
 	if ( ! iobuf )
 		return -ENOMEM;
 	
 	copy_from_user ( iob_put ( iobuf, len ),
 			 iscsi->command->data_out, offset, len );
+	memset ( iob_put ( iobuf, pad_len ), 0, pad_len );
 
 	return xfer_deliver_iob ( &iscsi->socket, iobuf );
 }
@@ -793,13 +806,17 @@ static int iscsi_tx_login_request ( struct iscsi_session *iscsi ) {
 	struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request;
 	struct io_buffer *iobuf;
 	size_t len;
+	size_t pad_len;
 
 	len = ISCSI_DATA_LEN ( request->lengths );
-	iobuf = xfer_alloc_iob ( &iscsi->socket, len );
+	pad_len = ISCSI_DATA_PAD_LEN ( request->lengths );
+	iobuf = xfer_alloc_iob ( &iscsi->socket, ( len + pad_len ) );
 	if ( ! iobuf )
 		return -ENOMEM;
 	iob_put ( iobuf, len );
 	iscsi_build_login_request_strings ( iscsi, iobuf->data, len );
+	memset ( iob_put ( iobuf, pad_len ), 0, pad_len );
+
 	return xfer_deliver_iob ( &iscsi->socket, iobuf );
 }
 
@@ -1083,8 +1100,8 @@ static int iscsi_handle_chap_r_value ( struct iscsi_session *iscsi,
 struct iscsi_string_type {
 	/** String key
 	 *
-	 * This is the portion up to and including the "=" sign,
-	 * e.g. "InitiatorName=", "CHAP_A=", etc.
+	 * This is the portion preceding the "=" sign,
+	 * e.g. "InitiatorName", "CHAP_A", etc.
 	 */
 	const char *key;
 	/** Handle iSCSI string value
@@ -1098,13 +1115,13 @@ struct iscsi_string_type {
 
 /** iSCSI text strings that we want to handle */
 static struct iscsi_string_type iscsi_string_types[] = {
-	{ "TargetAddress=", iscsi_handle_targetaddress_value },
-	{ "AuthMethod=", iscsi_handle_authmethod_value },
-	{ "CHAP_A=", iscsi_handle_chap_a_value },
-	{ "CHAP_I=", iscsi_handle_chap_i_value },
-	{ "CHAP_C=", iscsi_handle_chap_c_value },
-	{ "CHAP_N=", iscsi_handle_chap_n_value },
-	{ "CHAP_R=", iscsi_handle_chap_r_value },
+	{ "TargetAddress", iscsi_handle_targetaddress_value },
+	{ "AuthMethod", iscsi_handle_authmethod_value },
+	{ "CHAP_A", iscsi_handle_chap_a_value },
+	{ "CHAP_I", iscsi_handle_chap_i_value },
+	{ "CHAP_C", iscsi_handle_chap_c_value },
+	{ "CHAP_N", iscsi_handle_chap_n_value },
+	{ "CHAP_R", iscsi_handle_chap_r_value },
 	{ NULL, NULL }
 };
 
@@ -1118,16 +1135,35 @@ static struct iscsi_string_type iscsi_string_types[] = {
 static int iscsi_handle_string ( struct iscsi_session *iscsi,
 				 const char *string ) {
 	struct iscsi_string_type *type;
+	const char *separator;
+	const char *value;
 	size_t key_len;
 	int rc;
 
+	/* Find separator */
+	separator = strchr ( string, '=' );
+	if ( ! separator ) {
+		DBGC ( iscsi, "iSCSI %p malformed string %s\n",
+		       iscsi, string );
+		return -EPROTO_INVALID_KEY_VALUE_PAIR;
+	}
+	key_len = ( separator - string );
+	value = ( separator + 1 );
+
+	/* Check for rejections.  Since we send only non-rejectable
+	 * values, any rejection is a fatal protocol error.
+	 */
+	if ( strcmp ( value, "Reject" ) == 0 ) {
+		DBGC ( iscsi, "iSCSI %p rejection: %s\n", iscsi, string );
+		return -EPROTO_VALUE_REJECTED;
+	}
+
+	/* Handle key/value pair */
 	for ( type = iscsi_string_types ; type->key ; type++ ) {
-		key_len = strlen ( type->key );
 		if ( strncmp ( string, type->key, key_len ) != 0 )
 			continue;
 		DBGC ( iscsi, "iSCSI %p handling %s\n", iscsi, string );
-		if ( ( rc = type->handle ( iscsi,
-					   ( string + key_len ) ) ) != 0 ) {
+		if ( ( rc = type->handle ( iscsi, value ) ) != 0 ) {
 			DBGC ( iscsi, "iSCSI %p could not handle %s: %s\n",
 			       iscsi, string, strerror ( rc ) );
 			return rc;
@@ -1304,6 +1340,24 @@ static int iscsi_rx_login_response ( struct iscsi_session *iscsi,
  *
  */
 
+/**
+ * Pause TX engine
+ *
+ * @v iscsi		iSCSI session
+ */
+static void iscsi_tx_pause ( struct iscsi_session *iscsi ) {
+	process_del ( &iscsi->process );
+}
+
+/**
+ * Resume TX engine
+ *
+ * @v iscsi		iSCSI session
+ */
+static void iscsi_tx_resume ( struct iscsi_session *iscsi ) {
+	process_add ( &iscsi->process );
+}
+
 /**
  * Start up a new TX PDU
  *
@@ -1315,8 +1369,7 @@ static int iscsi_rx_login_response ( struct iscsi_session *iscsi,
 static void iscsi_start_tx ( struct iscsi_session *iscsi ) {
 
 	assert ( iscsi->tx_state == ISCSI_TX_IDLE );
-	assert ( ! process_running ( &iscsi->process ) );
-	
+
 	/* Initialise TX BHS */
 	memset ( &iscsi->tx_bhs, 0, sizeof ( iscsi->tx_bhs ) );
 
@@ -1324,7 +1377,7 @@ static void iscsi_start_tx ( struct iscsi_session *iscsi ) {
 	iscsi->tx_state = ISCSI_TX_BHS;
 
 	/* Start transmission process */
-	process_add ( &iscsi->process );
+	iscsi_tx_resume ( iscsi );
 }
 
 /**
@@ -1371,27 +1424,6 @@ static int iscsi_tx_data ( struct iscsi_session *iscsi ) {
 	}
 }
 
-/**
- * Transmit data padding of an iSCSI PDU
- *
- * @v iscsi		iSCSI session
- * @ret rc		Return status code
- * 
- * Handle transmission of any data padding in a PDU data segment.
- * iscsi::tx_bhs will be valid when this is called.
- */
-static int iscsi_tx_data_padding ( struct iscsi_session *iscsi ) {
-	static const char pad[] = { '\0', '\0', '\0' };
-	struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
-	size_t pad_len;
-	
-	pad_len = ISCSI_DATA_PAD_LEN ( common->lengths );
-	if ( ! pad_len )
-		return 0;
-
-	return xfer_deliver_raw ( &iscsi->socket, pad, pad_len );
-}
-
 /**
  * Complete iSCSI PDU transmission
  *
@@ -1405,7 +1437,7 @@ static void iscsi_tx_done ( struct iscsi_session *iscsi ) {
 	struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
 
 	/* Stop transmission process */
-	process_del ( &iscsi->process );
+	iscsi_tx_pause ( iscsi );
 
 	switch ( common->opcode & ISCSI_OPCODE_MASK ) {
 	case ISCSI_OPCODE_DATA_OUT:
@@ -1427,9 +1459,7 @@ static void iscsi_tx_done ( struct iscsi_session *iscsi ) {
  * 
  * Constructs data to be sent for the current TX state
  */
-static void iscsi_tx_step ( struct process *process ) {
-	struct iscsi_session *iscsi =
-		container_of ( process, struct iscsi_session, process );
+static void iscsi_tx_step ( struct iscsi_session *iscsi ) {
 	struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
 	int ( * tx ) ( struct iscsi_session *iscsi );
 	enum iscsi_tx_state next_state;
@@ -1452,16 +1482,11 @@ static void iscsi_tx_step ( struct process *process ) {
 		case ISCSI_TX_DATA:
 			tx = iscsi_tx_data;
 			tx_len = ISCSI_DATA_LEN ( common->lengths );
-			next_state = ISCSI_TX_DATA_PADDING;
-			break;
-		case ISCSI_TX_DATA_PADDING:
-			tx = iscsi_tx_data_padding;
-			tx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
 			next_state = ISCSI_TX_IDLE;
 			break;
 		case ISCSI_TX_IDLE:
-			/* Stop processing */
-			iscsi_tx_done ( iscsi );
+			/* Nothing to do; pause processing */
+			iscsi_tx_pause ( iscsi );
 			return;
 		default:
 			assert ( 0 );
@@ -1470,7 +1495,10 @@ static void iscsi_tx_step ( struct process *process ) {
 
 		/* Check for window availability, if needed */
 		if ( tx_len && ( xfer_window ( &iscsi->socket ) == 0 ) ) {
-			/* Cannot transmit at this point; stop processing */
+			/* Cannot transmit at this point; pause
+			 * processing and wait for window to reopen
+			 */
+			iscsi_tx_pause ( iscsi );
 			return;
 		}
 
@@ -1485,9 +1513,19 @@ static void iscsi_tx_step ( struct process *process ) {
 
 		/* Move to next state */
 		iscsi->tx_state = next_state;
+
+		/* If we have moved to the idle state, mark
+		 * transmission as complete
+		 */
+		if ( iscsi->tx_state == ISCSI_TX_IDLE )
+			iscsi_tx_done ( iscsi );
 	}
 }
 
+/** iSCSI TX process descriptor */
+static struct process_descriptor iscsi_process_desc =
+	PROC_DESC ( struct iscsi_session, process, iscsi_tx_step );
+
 /**
  * Receive basic header segment of an iSCSI PDU
  *
@@ -1694,6 +1732,8 @@ static int iscsi_vredirect ( struct iscsi_session *iscsi, int type,
 /** iSCSI socket interface operations */
 static struct interface_operation iscsi_socket_operations[] = {
 	INTF_OP ( xfer_deliver, struct iscsi_session *, iscsi_socket_deliver ),
+	INTF_OP ( xfer_window_changed, struct iscsi_session *,
+		  iscsi_tx_resume ),
 	INTF_OP ( xfer_vredirect, struct iscsi_session *, iscsi_vredirect ),
 	INTF_OP ( intf_close, struct iscsi_session *, iscsi_close ),
 };
@@ -2034,7 +2074,7 @@ static int iscsi_open ( struct interface *parent, struct uri *uri ) {
 	intf_init ( &iscsi->control, &iscsi_control_desc, &iscsi->refcnt );
 	intf_init ( &iscsi->data, &iscsi_data_desc, &iscsi->refcnt );
 	intf_init ( &iscsi->socket, &iscsi_socket_desc, &iscsi->refcnt );
-	process_init_stopped ( &iscsi->process, iscsi_tx_step,
+	process_init_stopped ( &iscsi->process, &iscsi_process_desc,
 			       &iscsi->refcnt );
 
 	/* Parse root path */
diff --git a/roms/ipxe/src/net/tcp/syslogs.c b/roms/ipxe/src/net/tcp/syslogs.c
new file mode 100644
index 0000000000000000000000000000000000000000..dae6ba18b6171f825d4710707afb8514990e64d0
--- /dev/null
+++ b/roms/ipxe/src/net/tcp/syslogs.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Encrypted syslog protocol
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <byteswap.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/settings.h>
+#include <ipxe/console.h>
+#include <ipxe/lineconsole.h>
+#include <ipxe/tls.h>
+#include <ipxe/syslog.h>
+#include <config/console.h>
+
+/* Set default console usage if applicable */
+#if ! ( defined ( CONSOLE_SYSLOGS ) && CONSOLE_EXPLICIT ( CONSOLE_SYSLOGS ) )
+#undef CONSOLE_SYSLOGS
+#define CONSOLE_SYSLOGS ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_TUI )
+#endif
+
+struct console_driver syslogs_console __console_driver;
+
+/** The encrypted syslog server */
+static struct sockaddr_tcpip logserver = {
+	.st_family = AF_INET,
+	.st_port = htons ( SYSLOG_PORT ),
+};
+
+/**
+ * Handle encrypted syslog TLS interface close
+ *
+ * @v intf		Interface
+ * @v rc		Reason for close
+ */
+static void syslogs_close ( struct interface *intf __unused, int rc ) {
+
+	DBG ( "SYSLOGS console disconnected: %s\n", strerror ( rc ) );
+}
+
+/**
+ * Handle encrypted syslog TLS interface window change
+ *
+ * @v intf		Interface
+ */
+static void syslogs_window_changed ( struct interface *intf ) {
+
+	/* Mark console as enabled when window first opens, indicating
+	 * that TLS negotiation is complete.  (Do not disable console
+	 * when window closes again, since TCP will close the window
+	 * whenever there is unACKed data.)
+	 */
+	if ( xfer_window ( intf ) ) {
+		if ( syslogs_console.disabled )
+			DBG ( "SYSLOGS console connected\n" );
+		syslogs_console.disabled = 0;
+	}
+}
+
+/** Encrypted syslog TLS interface operations */
+static struct interface_operation syslogs_operations[] = {
+	INTF_OP ( xfer_window_changed, struct interface *,
+		  syslogs_window_changed ),
+	INTF_OP ( intf_close, struct interface *, syslogs_close ),
+};
+
+/** Encrypted syslog TLS interface descriptor */
+static struct interface_descriptor syslogs_desc =
+	INTF_DESC_PURE ( syslogs_operations );
+
+/** The encrypted syslog TLS interface */
+static struct interface syslogs = INTF_INIT ( syslogs_desc );
+
+/******************************************************************************
+ *
+ * Console driver
+ *
+ ******************************************************************************
+ */
+
+/** Encrypted syslog line buffer */
+static char syslogs_buffer[SYSLOG_BUFSIZE];
+
+/** Encrypted syslog severity */
+static unsigned int syslogs_severity = SYSLOG_DEFAULT_SEVERITY;
+
+/**
+ * Handle ANSI set encrypted syslog priority (private sequence)
+ *
+ * @v count		Parameter count
+ * @v params		List of graphic rendition aspects
+ */
+static void syslogs_handle_priority ( unsigned int count __unused,
+				      int params[] ) {
+	if ( params[0] >= 0 ) {
+		syslogs_severity = params[0];
+	} else {
+		syslogs_severity = SYSLOG_DEFAULT_SEVERITY;
+	}
+}
+
+/** Encrypted syslog ANSI escape sequence handlers */
+static struct ansiesc_handler syslogs_handlers[] = {
+	{ ANSIESC_LOG_PRIORITY, syslogs_handle_priority },
+	{ 0, NULL }
+};
+
+/** Encrypted syslog line console */
+static struct line_console syslogs_line = {
+	.buffer = syslogs_buffer,
+	.len = sizeof ( syslogs_buffer ),
+	.ctx = {
+		.handlers = syslogs_handlers,
+	},
+};
+
+/** Encrypted syslog recursion marker */
+static int syslogs_entered;
+
+/**
+ * Print a character to encrypted syslog console
+ *
+ * @v character		Character to be printed
+ */
+static void syslogs_putchar ( int character ) {
+	int rc;
+
+	/* Ignore if we are already mid-logging */
+	if ( syslogs_entered )
+		return;
+
+	/* Fill line buffer */
+	if ( line_putchar ( &syslogs_line, character ) == 0 )
+		return;
+
+	/* Guard against re-entry */
+	syslogs_entered = 1;
+
+	/* Send log message */
+	if ( ( rc = syslog_send ( &syslogs, syslogs_severity,
+				  syslogs_buffer, "\n" ) ) != 0 ) {
+		DBG ( "SYSLOGS could not send log message: %s\n",
+		      strerror ( rc ) );
+	}
+
+	/* Clear re-entry flag */
+	syslogs_entered = 0;
+}
+
+/** Encrypted syslog console driver */
+struct console_driver syslogs_console __console_driver = {
+	.putchar = syslogs_putchar,
+	.disabled = 1,
+	.usage = CONSOLE_SYSLOGS,
+};
+
+/******************************************************************************
+ *
+ * Settings
+ *
+ ******************************************************************************
+ */
+
+/** Encrypted syslog server setting */
+struct setting syslogs_setting __setting ( SETTING_MISC ) = {
+	.name = "syslogs",
+	.description = "Encrypted syslog server",
+	.tag = DHCP_EB_SYSLOGS_SERVER,
+	.type = &setting_type_string,
+};
+
+/**
+ * Apply encrypted syslog settings
+ *
+ * @ret rc		Return status code
+ */
+static int apply_syslogs_settings ( void ) {
+	static char *old_server;
+	char *server;
+	struct interface *socket;
+	int len;
+	int rc;
+
+	/* Fetch log server */
+	len = fetch_string_setting_copy ( NULL, &syslogs_setting, &server );
+	if ( len < 0 ) {
+		rc = len;
+		goto err_fetch_server;
+	}
+
+	/* Do nothing unless log server has changed */
+	if ( ( ( server == NULL ) && ( old_server == NULL ) ) ||
+	     ( ( server != NULL ) && ( old_server != NULL ) &&
+	       ( strcmp ( server, old_server ) == 0 ) ) ) {
+		rc = 0;
+		goto out_no_change;
+	}
+	free ( old_server );
+	old_server = NULL;
+
+	/* Reset encrypted syslog connection */
+	syslogs_console.disabled = 1;
+	intf_restart ( &syslogs, 0 );
+
+	/* Do nothing unless we have a log server */
+	if ( ! server ) {
+		DBG ( "SYSLOGS has no log server\n" );
+		rc = 0;
+		goto out_no_server;
+	}
+
+	/* Add TLS filter */
+	if ( ( rc = add_tls ( &syslogs, server, &socket ) ) != 0 ) {
+		DBG ( "SYSLOGS cannot create TLS filter: %s\n",
+		      strerror ( rc ) );
+		goto err_add_tls;
+	}
+
+	/* Connect to log server */
+	if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM,
+					     (( struct sockaddr *) &logserver ),
+					     server, NULL ) ) != 0 ) {
+		DBG ( "SYSLOGS cannot connect to log server: %s\n",
+		      strerror ( rc ) );
+		goto err_open_named_socket;
+	}
+	DBG ( "SYSLOGS using log server %s\n", server );
+
+	/* Record log server */
+	old_server = server;
+	server = NULL;
+
+	/* Success */
+	rc = 0;
+
+ err_open_named_socket:
+ err_add_tls:
+ out_no_server:
+ out_no_change:
+	free ( server );
+ err_fetch_server:
+	return rc;
+}
+
+/** Encrypted syslog settings applicator */
+struct settings_applicator syslogs_applicator __settings_applicator = {
+	.apply = apply_syslogs_settings,
+};
diff --git a/roms/ipxe/src/net/tcpip.c b/roms/ipxe/src/net/tcpip.c
index 4451bf11126f909b729221ce109e..8e187f7ecc7603865ecadfb3abdb 100644
--- a/roms/ipxe/src/net/tcpip.c
+++ b/roms/ipxe/src/net/tcpip.c
@@ -97,8 +97,8 @@ int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol,
  * or both.  Deciding which to swap is left as an exercise for the
  * interested reader.
  */
-uint16_t tcpip_continue_chksum ( uint16_t partial, const void *data,
-				 size_t len ) {
+uint16_t generic_tcpip_continue_chksum ( uint16_t partial,
+					 const void *data, size_t len ) {
 	unsigned int cksum = ( ( ~partial ) & 0xffff );
 	unsigned int value;
 	unsigned int i;
diff --git a/roms/ipxe/src/net/tls.c b/roms/ipxe/src/net/tls.c
index 5e22221d2974da61bf29e38bb50a..5e18f72665cdd5fd56bc272ac64b 100644
--- a/roms/ipxe/src/net/tls.c
+++ b/roms/ipxe/src/net/tls.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -28,20 +29,143 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <stdlib.h>
 #include <stdarg.h>
 #include <string.h>
+#include <time.h>
 #include <errno.h>
 #include <byteswap.h>
+#include <ipxe/pending.h>
 #include <ipxe/hmac.h>
 #include <ipxe/md5.h>
 #include <ipxe/sha1.h>
+#include <ipxe/sha256.h>
 #include <ipxe/aes.h>
 #include <ipxe/rsa.h>
 #include <ipxe/iobuf.h>
 #include <ipxe/xfer.h>
 #include <ipxe/open.h>
-#include <ipxe/asn1.h>
 #include <ipxe/x509.h>
+#include <ipxe/clientcert.h>
+#include <ipxe/rbg.h>
+#include <ipxe/validator.h>
 #include <ipxe/tls.h>
 
+/* Disambiguate the various error causes */
+#define EACCES_WRONG_NAME __einfo_error ( EINFO_EACCES_WRONG_NAME )
+#define EINFO_EACCES_WRONG_NAME						\
+	__einfo_uniqify ( EINFO_EACCES, 0x02,				\
+			  "Incorrect server name" )
+#define EINVAL_CHANGE_CIPHER __einfo_error ( EINFO_EINVAL_CHANGE_CIPHER )
+#define EINFO_EINVAL_CHANGE_CIPHER					\
+	__einfo_uniqify ( EINFO_EINVAL, 0x01,				\
+			  "Invalid Change Cipher record" )
+#define EINVAL_ALERT __einfo_error ( EINFO_EINVAL_ALERT )
+#define EINFO_EINVAL_ALERT						\
+	__einfo_uniqify ( EINFO_EINVAL, 0x02,				\
+			  "Invalid Alert record" )
+#define EINVAL_HELLO __einfo_error ( EINFO_EINVAL_HELLO )
+#define EINFO_EINVAL_HELLO						\
+	__einfo_uniqify ( EINFO_EINVAL, 0x03,				\
+			  "Invalid Server Hello record" )
+#define EINVAL_CERTIFICATE __einfo_error ( EINFO_EINVAL_CERTIFICATE )
+#define EINFO_EINVAL_CERTIFICATE					\
+	__einfo_uniqify ( EINFO_EINVAL, 0x04,				\
+			  "Invalid Certificate" )
+#define EINVAL_CERTIFICATES __einfo_error ( EINFO_EINVAL_CERTIFICATES )
+#define EINFO_EINVAL_CERTIFICATES					\
+	__einfo_uniqify ( EINFO_EINVAL, 0x05,				\
+			  "Invalid Server Certificate record" )
+#define EINVAL_HELLO_DONE __einfo_error ( EINFO_EINVAL_HELLO_DONE )
+#define EINFO_EINVAL_HELLO_DONE						\
+	__einfo_uniqify ( EINFO_EINVAL, 0x06,				\
+			  "Invalid Server Hello Done record" )
+#define EINVAL_FINISHED __einfo_error ( EINFO_EINVAL_FINISHED )
+#define EINFO_EINVAL_FINISHED						\
+	__einfo_uniqify ( EINFO_EINVAL, 0x07,				\
+			  "Invalid Server Finished record" )
+#define EINVAL_HANDSHAKE __einfo_error ( EINFO_EINVAL_HANDSHAKE )
+#define EINFO_EINVAL_HANDSHAKE						\
+	__einfo_uniqify ( EINFO_EINVAL, 0x08,				\
+			  "Invalid Handshake record" )
+#define EINVAL_STREAM __einfo_error ( EINFO_EINVAL_STREAM )
+#define EINFO_EINVAL_STREAM						\
+	__einfo_uniqify ( EINFO_EINVAL, 0x09,				\
+			  "Invalid stream-ciphered record" )
+#define EINVAL_BLOCK __einfo_error ( EINFO_EINVAL_BLOCK )
+#define EINFO_EINVAL_BLOCK						\
+	__einfo_uniqify ( EINFO_EINVAL, 0x0a,				\
+			  "Invalid block-ciphered record" )
+#define EINVAL_PADDING __einfo_error ( EINFO_EINVAL_PADDING )
+#define EINFO_EINVAL_PADDING						\
+	__einfo_uniqify ( EINFO_EINVAL, 0x0b,				\
+			  "Invalid block padding" )
+#define EINVAL_RX_STATE __einfo_error ( EINFO_EINVAL_RX_STATE )
+#define EINFO_EINVAL_RX_STATE						\
+	__einfo_uniqify ( EINFO_EINVAL, 0x0c,				\
+			  "Invalid receive state" )
+#define EINVAL_MAC __einfo_error ( EINFO_EINVAL_MAC )
+#define EINFO_EINVAL_MAC						\
+	__einfo_uniqify ( EINFO_EINVAL, 0x0d,				\
+			  "Invalid MAC" )
+#define EIO_ALERT __einfo_error ( EINFO_EIO_ALERT )
+#define EINFO_EIO_ALERT							\
+	__einfo_uniqify ( EINFO_EINVAL, 0x01,				\
+			  "Unknown alert level" )
+#define ENOMEM_CONTEXT __einfo_error ( EINFO_ENOMEM_CONTEXT )
+#define EINFO_ENOMEM_CONTEXT						\
+	__einfo_uniqify ( EINFO_ENOMEM, 0x01,				\
+			  "Not enough space for crypto context" )
+#define ENOMEM_CERTIFICATE __einfo_error ( EINFO_ENOMEM_CERTIFICATE )
+#define EINFO_ENOMEM_CERTIFICATE					\
+	__einfo_uniqify ( EINFO_ENOMEM, 0x02,				\
+			  "Not enough space for certificate" )
+#define ENOMEM_CHAIN __einfo_error ( EINFO_ENOMEM_CHAIN )
+#define EINFO_ENOMEM_CHAIN						\
+	__einfo_uniqify ( EINFO_ENOMEM, 0x03,				\
+			  "Not enough space for certificate chain" )
+#define ENOMEM_TX_PLAINTEXT __einfo_error ( EINFO_ENOMEM_TX_PLAINTEXT )
+#define EINFO_ENOMEM_TX_PLAINTEXT					\
+	__einfo_uniqify ( EINFO_ENOMEM, 0x04,				\
+			  "Not enough space for transmitted plaintext" )
+#define ENOMEM_TX_CIPHERTEXT __einfo_error ( EINFO_ENOMEM_TX_CIPHERTEXT )
+#define EINFO_ENOMEM_TX_CIPHERTEXT					\
+	__einfo_uniqify ( EINFO_ENOMEM, 0x05,				\
+			  "Not enough space for transmitted ciphertext" )
+#define ENOMEM_RX_DATA __einfo_error ( EINFO_ENOMEM_RX_DATA )
+#define EINFO_ENOMEM_RX_DATA						\
+	__einfo_uniqify ( EINFO_ENOMEM, 0x07,				\
+			  "Not enough space for received data" )
+#define ENOMEM_RX_CONCAT __einfo_error ( EINFO_ENOMEM_RX_CONCAT )
+#define EINFO_ENOMEM_RX_CONCAT						\
+	__einfo_uniqify ( EINFO_ENOMEM, 0x08,				\
+			  "Not enough space to concatenate received data" )
+#define ENOTSUP_CIPHER __einfo_error ( EINFO_ENOTSUP_CIPHER )
+#define EINFO_ENOTSUP_CIPHER						\
+	__einfo_uniqify ( EINFO_ENOTSUP, 0x01,				\
+			  "Unsupported cipher" )
+#define ENOTSUP_NULL __einfo_error ( EINFO_ENOTSUP_NULL )
+#define EINFO_ENOTSUP_NULL						\
+	__einfo_uniqify ( EINFO_ENOTSUP, 0x02,				\
+			  "Refusing to use null cipher" )
+#define ENOTSUP_SIG_HASH __einfo_error ( EINFO_ENOTSUP_SIG_HASH )
+#define EINFO_ENOTSUP_SIG_HASH						\
+	__einfo_uniqify ( EINFO_ENOTSUP, 0x03,				\
+			  "Unsupported signature and hash algorithm" )
+#define ENOTSUP_VERSION __einfo_error ( EINFO_ENOTSUP_VERSION )
+#define EINFO_ENOTSUP_VERSION						\
+	__einfo_uniqify ( EINFO_ENOTSUP, 0x04,				\
+			  "Unsupported protocol version" )
+#define EPERM_ALERT __einfo_error ( EINFO_EPERM_ALERT )
+#define EINFO_EPERM_ALERT						\
+	__einfo_uniqify ( EINFO_EPERM, 0x01,				\
+			  "Received fatal alert" )
+#define EPERM_VERIFY __einfo_error ( EINFO_EPERM_VERIFY )
+#define EINFO_EPERM_VERIFY						\
+	__einfo_uniqify ( EINFO_EPERM, 0x02,				\
+			  "Handshake verification failed" )
+#define EPROTO_VERSION __einfo_error ( EINFO_EPROTO_VERSION )
+#define EINFO_EPROTO_VERSION						\
+	__einfo_uniqify ( EINFO_EPROTO, 0x01,				\
+			  "Illegal protocol version upgrade" )
+
 static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
 				const void *data, size_t len );
 static void tls_clear_cipher ( struct tls_session *tls,
@@ -63,10 +187,103 @@ static void tls_clear_cipher ( struct tls_session *tls,
  * TLS uses 24-bit integers in several places, which are awkward to
  * parse in C.
  */
-static unsigned long tls_uint24 ( uint8_t field24[3] ) {
-	return ( ( field24[0] << 16 ) + ( field24[1] << 8 ) + field24[2] );
+static inline __attribute__ (( always_inline )) unsigned long
+tls_uint24 ( const uint8_t field24[3] ) {
+	const uint32_t *field32 __attribute__ (( may_alias )) =
+		( ( const void * ) field24 );
+	return ( be32_to_cpu ( *field32 ) >> 8 );
+}
+
+/**
+ * Set 24-bit field value
+ *
+ * @v field24		24-bit field
+ * @v value		Field value
+ *
+ * The field must be pre-zeroed.
+ */
+static void tls_set_uint24 ( uint8_t field24[3], unsigned long value ) {
+	uint32_t *field32 __attribute__ (( may_alias )) =
+		( ( void * ) field24 );
+	*field32 |= cpu_to_be32 ( value << 8 );
+}
+
+/**
+ * Determine if TLS session is ready for application data
+ *
+ * @v tls		TLS session
+ * @ret is_ready	TLS session is ready
+ */
+static int tls_ready ( struct tls_session *tls ) {
+	return ( ( ! is_pending ( &tls->client_negotiation ) ) &&
+		 ( ! is_pending ( &tls->server_negotiation ) ) );
+}
+
+/******************************************************************************
+ *
+ * Hybrid MD5+SHA1 hash as used by TLSv1.1 and earlier
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Initialise MD5+SHA1 algorithm
+ *
+ * @v ctx		MD5+SHA1 context
+ */
+static void md5_sha1_init ( void *ctx ) {
+	struct md5_sha1_context *context = ctx;
+
+	digest_init ( &md5_algorithm, context->md5 );
+	digest_init ( &sha1_algorithm, context->sha1 );
+}
+
+/**
+ * Accumulate data with MD5+SHA1 algorithm
+ *
+ * @v ctx		MD5+SHA1 context
+ * @v data		Data
+ * @v len		Length of data
+ */
+static void md5_sha1_update ( void *ctx, const void *data, size_t len ) {
+	struct md5_sha1_context *context = ctx;
+
+	digest_update ( &md5_algorithm, context->md5, data, len );
+	digest_update ( &sha1_algorithm, context->sha1, data, len );
+}
+
+/**
+ * Generate MD5+SHA1 digest
+ *
+ * @v ctx		MD5+SHA1 context
+ * @v out		Output buffer
+ */
+static void md5_sha1_final ( void *ctx, void *out ) {
+	struct md5_sha1_context *context = ctx;
+	struct md5_sha1_digest *digest = out;
+
+	digest_final ( &md5_algorithm, context->md5, digest->md5 );
+	digest_final ( &sha1_algorithm, context->sha1, digest->sha1 );
 }
 
+/** Hybrid MD5+SHA1 digest algorithm */
+static struct digest_algorithm md5_sha1_algorithm = {
+	.name		= "md5+sha1",
+	.ctxsize	= sizeof ( struct md5_sha1_context ),
+	.blocksize	= 0, /* Not applicable */
+	.digestsize	= sizeof ( struct md5_sha1_digest ),
+	.init		= md5_sha1_init,
+	.update		= md5_sha1_update,
+	.final		= md5_sha1_final,
+};
+
+/** RSA digestInfo prefix for MD5+SHA1 algorithm */
+struct rsa_digestinfo_prefix rsa_md5_sha1_prefix __rsa_digestinfo_prefix = {
+	.digest = &md5_sha1_algorithm,
+	.data = NULL, /* MD5+SHA1 signatures have no digestInfo */
+	.len = 0,
+};
+
 /******************************************************************************
  *
  * Cleanup functions
@@ -82,14 +299,19 @@ static unsigned long tls_uint24 ( uint8_t field24[3] ) {
 static void free_tls ( struct refcnt *refcnt ) {
 	struct tls_session *tls =
 		container_of ( refcnt, struct tls_session, refcnt );
+	struct io_buffer *iobuf;
+	struct io_buffer *tmp;
 
 	/* Free dynamically-allocated resources */
 	tls_clear_cipher ( tls, &tls->tx_cipherspec );
 	tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
 	tls_clear_cipher ( tls, &tls->rx_cipherspec );
 	tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
-	x509_free_rsa_public_key ( &tls->rsa );
-	free ( tls->rx_data );
+	list_for_each_entry_safe ( iobuf, tmp, &tls->rx_data, list ) {
+		list_del ( &iobuf->list );
+		free_iob ( iobuf );
+	}
+	x509_chain_put ( tls->chain );
 
 	/* Free TLS structure itself */
 	free ( tls );	
@@ -103,12 +325,17 @@ static void free_tls ( struct refcnt *refcnt ) {
  */
 static void tls_close ( struct tls_session *tls, int rc ) {
 
+	/* Remove pending operations, if applicable */
+	pending_put ( &tls->client_negotiation );
+	pending_put ( &tls->server_negotiation );
+
 	/* Remove process */
 	process_del ( &tls->process );
-	
-	/* Close ciphertext and plaintext streams */
+
+	/* Close all interfaces */
 	intf_shutdown ( &tls->cipherstream, rc );
 	intf_shutdown ( &tls->plainstream, rc );
+	intf_shutdown ( &tls->validator, rc );
 }
 
 /******************************************************************************
@@ -121,12 +348,25 @@ static void tls_close ( struct tls_session *tls, int rc ) {
 /**
  * Generate random data
  *
+ * @v tls		TLS session
  * @v data		Buffer to fill
  * @v len		Length of buffer
+ * @ret rc		Return status code
  */
-static void tls_generate_random ( void *data, size_t len ) {
-	/* FIXME: Some real random data source would be nice... */
-	memset ( data, 0x01, len );
+static int tls_generate_random ( struct tls_session *tls,
+				 void *data, size_t len ) {
+	int rc;
+
+	/* Generate random bits with no additional input and without
+	 * prediction resistance
+	 */
+	if ( ( rc = rbg_generate ( NULL, 0, 0, data, len ) ) != 0 ) {
+		DBGC ( tls, "TLS %p could not generate random data: %s\n",
+		       tls, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
 }
 
 /**
@@ -233,32 +473,40 @@ static void tls_prf ( struct tls_session *tls, void *secret, size_t secret_len,
 	size_t subsecret_len;
 	void *md5_secret;
 	void *sha1_secret;
-	uint8_t out_md5[out_len];
-	uint8_t out_sha1[out_len];
+	uint8_t buf[out_len];
 	unsigned int i;
 
 	va_start ( seeds, out_len );
 
-	/* Split secret into two, with an overlap of up to one byte */
-	subsecret_len = ( ( secret_len + 1 ) / 2 );
-	md5_secret = secret;
-	sha1_secret = ( secret + secret_len - subsecret_len );
+	if ( tls->version >= TLS_VERSION_TLS_1_2 ) {
+		/* Use P_SHA256 for TLSv1.2 and later */
+		tls_p_hash_va ( tls, &sha256_algorithm, secret, secret_len,
+				out, out_len, seeds );
+	} else {
+		/* Use combination of P_MD5 and P_SHA-1 for TLSv1.1
+		 * and earlier
+		 */
 
-	/* Calculate MD5 portion */
-	va_copy ( tmp, seeds );
-	tls_p_hash_va ( tls, &md5_algorithm, md5_secret, subsecret_len,
-			out_md5, out_len, seeds );
-	va_end ( tmp );
+		/* Split secret into two, with an overlap of up to one byte */
+		subsecret_len = ( ( secret_len + 1 ) / 2 );
+		md5_secret = secret;
+		sha1_secret = ( secret + secret_len - subsecret_len );
 
-	/* Calculate SHA1 portion */
-	va_copy ( tmp, seeds );
-	tls_p_hash_va ( tls, &sha1_algorithm, sha1_secret, subsecret_len,
-			out_sha1, out_len, seeds );
-	va_end ( tmp );
+		/* Calculate MD5 portion */
+		va_copy ( tmp, seeds );
+		tls_p_hash_va ( tls, &md5_algorithm, md5_secret,
+				subsecret_len, out, out_len, seeds );
+		va_end ( tmp );
 
-	/* XOR the two portions together into the final output buffer */
-	for ( i = 0 ; i < out_len ; i++ ) {
-		*( ( uint8_t * ) out + i ) = ( out_md5[i] ^ out_sha1[i] );
+		/* Calculate SHA1 portion */
+		va_copy ( tmp, seeds );
+		tls_p_hash_va ( tls, &sha1_algorithm, sha1_secret,
+				subsecret_len, buf, out_len, seeds );
+		va_end ( tmp );
+
+		/* XOR the two portions together into the final output buffer */
+		for ( i = 0 ; i < out_len ; i++ )
+			*( ( uint8_t * ) out + i ) ^= buf[i];
 	}
 
 	va_end ( seeds );
@@ -323,9 +571,9 @@ static void tls_generate_master_secret ( struct tls_session *tls ) {
 static int tls_generate_keys ( struct tls_session *tls ) {
 	struct tls_cipherspec *tx_cipherspec = &tls->tx_cipherspec_pending;
 	struct tls_cipherspec *rx_cipherspec = &tls->rx_cipherspec_pending;
-	size_t hash_size = tx_cipherspec->digest->digestsize;
-	size_t key_size = tx_cipherspec->key_len;
-	size_t iv_size = tx_cipherspec->cipher->blocksize;
+	size_t hash_size = tx_cipherspec->suite->digest->digestsize;
+	size_t key_size = tx_cipherspec->suite->key_len;
+	size_t iv_size = tx_cipherspec->suite->cipher->blocksize;
 	size_t total = ( 2 * ( hash_size + key_size + iv_size ) );
 	uint8_t key_block[total];
 	uint8_t *key;
@@ -353,7 +601,7 @@ static int tls_generate_keys ( struct tls_session *tls ) {
 	key += hash_size;
 
 	/* TX key */
-	if ( ( rc = cipher_setkey ( tx_cipherspec->cipher,
+	if ( ( rc = cipher_setkey ( tx_cipherspec->suite->cipher,
 				    tx_cipherspec->cipher_ctx,
 				    key, key_size ) ) != 0 ) {
 		DBGC ( tls, "TLS %p could not set TX key: %s\n",
@@ -365,7 +613,7 @@ static int tls_generate_keys ( struct tls_session *tls ) {
 	key += key_size;
 
 	/* RX key */
-	if ( ( rc = cipher_setkey ( rx_cipherspec->cipher,
+	if ( ( rc = cipher_setkey ( rx_cipherspec->suite->cipher,
 				    rx_cipherspec->cipher_ctx,
 				    key, key_size ) ) != 0 ) {
 		DBGC ( tls, "TLS %p could not set TX key: %s\n",
@@ -377,13 +625,15 @@ static int tls_generate_keys ( struct tls_session *tls ) {
 	key += key_size;
 
 	/* TX initialisation vector */
-	cipher_setiv ( tx_cipherspec->cipher, tx_cipherspec->cipher_ctx, key );
+	cipher_setiv ( tx_cipherspec->suite->cipher,
+		       tx_cipherspec->cipher_ctx, key );
 	DBGC ( tls, "TLS %p TX IV:\n", tls );
 	DBGC_HD ( tls, key, iv_size );
 	key += iv_size;
 
 	/* RX initialisation vector */
-	cipher_setiv ( rx_cipherspec->cipher, rx_cipherspec->cipher_ctx, key );
+	cipher_setiv ( rx_cipherspec->suite->cipher,
+		       rx_cipherspec->cipher_ctx, key );
 	DBGC ( tls, "TLS %p RX IV:\n", tls );
 	DBGC_HD ( tls, key, iv_size );
 	key += iv_size;
@@ -400,6 +650,70 @@ static int tls_generate_keys ( struct tls_session *tls ) {
  ******************************************************************************
  */
 
+/** Null cipher suite */
+struct tls_cipher_suite tls_cipher_suite_null = {
+	.pubkey = &pubkey_null,
+	.cipher = &cipher_null,
+	.digest = &digest_null,
+};
+
+/** Supported cipher suites, in order of preference */
+struct tls_cipher_suite tls_cipher_suites[] = {
+	{
+		.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ),
+		.key_len = ( 256 / 8 ),
+		.pubkey = &rsa_algorithm,
+		.cipher = &aes_cbc_algorithm,
+		.digest = &sha256_algorithm,
+	},
+	{
+		.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ),
+		.key_len = ( 128 / 8 ),
+		.pubkey = &rsa_algorithm,
+		.cipher = &aes_cbc_algorithm,
+		.digest = &sha256_algorithm,
+	},
+	{
+		.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ),
+		.key_len = ( 256 / 8 ),
+		.pubkey = &rsa_algorithm,
+		.cipher = &aes_cbc_algorithm,
+		.digest = &sha1_algorithm,
+	},
+	{
+		.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ),
+		.key_len = ( 128 / 8 ),
+		.pubkey = &rsa_algorithm,
+		.cipher = &aes_cbc_algorithm,
+		.digest = &sha1_algorithm,
+	},
+};
+
+/** Number of supported cipher suites */
+#define TLS_NUM_CIPHER_SUITES \
+	( sizeof ( tls_cipher_suites ) / sizeof ( tls_cipher_suites[0] ) )
+
+/**
+ * Identify cipher suite
+ *
+ * @v cipher_suite	Cipher suite specification
+ * @ret suite		Cipher suite, or NULL
+ */
+static struct tls_cipher_suite *
+tls_find_cipher_suite ( unsigned int cipher_suite ) {
+	struct tls_cipher_suite *suite;
+	unsigned int i;
+
+	/* Identify cipher suite */
+	for ( i = 0 ; i < TLS_NUM_CIPHER_SUITES ; i++ ) {
+		suite = &tls_cipher_suites[i];
+		if ( suite->code == cipher_suite )
+			return suite;
+	}
+
+	return NULL;
+}
+
 /**
  * Clear cipher suite
  *
@@ -407,11 +721,14 @@ static int tls_generate_keys ( struct tls_session *tls ) {
  */
 static void tls_clear_cipher ( struct tls_session *tls __unused,
 			       struct tls_cipherspec *cipherspec ) {
+
+	if ( cipherspec->suite ) {
+		pubkey_final ( cipherspec->suite->pubkey,
+			       cipherspec->pubkey_ctx );
+	}
 	free ( cipherspec->dynamic );
-	memset ( cipherspec, 0, sizeof ( cipherspec ) );
-	cipherspec->pubkey = &pubkey_null;
-	cipherspec->cipher = &cipher_null;
-	cipherspec->digest = &digest_null;
+	memset ( cipherspec, 0, sizeof ( *cipherspec ) );
+	cipherspec->suite = &tls_cipher_suite_null;
 }
 
 /**
@@ -419,18 +736,15 @@ static void tls_clear_cipher ( struct tls_session *tls __unused,
  *
  * @v tls		TLS session
  * @v cipherspec	TLS cipher specification
- * @v pubkey		Public-key encryption elgorithm
- * @v cipher		Bulk encryption cipher algorithm
- * @v digest		MAC digest algorithm
- * @v key_len		Key length
+ * @v suite		Cipher suite
  * @ret rc		Return status code
  */
 static int tls_set_cipher ( struct tls_session *tls,
 			    struct tls_cipherspec *cipherspec,
-			    struct pubkey_algorithm *pubkey,
-			    struct cipher_algorithm *cipher,
-			    struct digest_algorithm *digest,
-			    size_t key_len ) {
+			    struct tls_cipher_suite *suite ) {
+	struct pubkey_algorithm *pubkey = suite->pubkey;
+	struct cipher_algorithm *cipher = suite->cipher;
+	struct digest_algorithm *digest = suite->digest;
 	size_t total;
 	void *dynamic;
 
@@ -439,13 +753,12 @@ static int tls_set_cipher ( struct tls_session *tls,
 	
 	/* Allocate dynamic storage */
 	total = ( pubkey->ctxsize + 2 * cipher->ctxsize + digest->digestsize );
-	dynamic = malloc ( total );
+	dynamic = zalloc ( total );
 	if ( ! dynamic ) {
 		DBGC ( tls, "TLS %p could not allocate %zd bytes for crypto "
 		       "context\n", tls, total );
-		return -ENOMEM;
+		return -ENOMEM_CONTEXT;
 	}
-	memset ( dynamic, 0, total );
 
 	/* Assign storage */
 	cipherspec->dynamic = dynamic;
@@ -456,10 +769,7 @@ static int tls_set_cipher ( struct tls_session *tls,
 	assert ( ( cipherspec->dynamic + total ) == dynamic );
 
 	/* Store parameters */
-	cipherspec->pubkey = pubkey;
-	cipherspec->cipher = cipher;
-	cipherspec->digest = digest;
-	cipherspec->key_len = key_len;
+	cipherspec->suite = suite;
 
 	return 0;
 }
@@ -473,39 +783,28 @@ static int tls_set_cipher ( struct tls_session *tls,
  */
 static int tls_select_cipher ( struct tls_session *tls,
 			       unsigned int cipher_suite ) {
-	struct pubkey_algorithm *pubkey = &pubkey_null;
-	struct cipher_algorithm *cipher = &cipher_null;
-	struct digest_algorithm *digest = &digest_null;
-	unsigned int key_len = 0;
+	struct tls_cipher_suite *suite;
 	int rc;
 
-	switch ( cipher_suite ) {
-	case htons ( TLS_RSA_WITH_AES_128_CBC_SHA ):
-		key_len = ( 128 / 8 );
-		cipher = &aes_cbc_algorithm;
-		digest = &sha1_algorithm;
-		break;
-	case htons ( TLS_RSA_WITH_AES_256_CBC_SHA ):
-		key_len = ( 256 / 8 );
-		cipher = &aes_cbc_algorithm;
-		digest = &sha1_algorithm;
-		break;
-	default:
+	/* Identify cipher suite */
+	suite = tls_find_cipher_suite ( cipher_suite );
+	if ( ! suite ) {
 		DBGC ( tls, "TLS %p does not support cipher %04x\n",
 		       tls, ntohs ( cipher_suite ) );
-		return -ENOTSUP;
+		return -ENOTSUP_CIPHER;
 	}
 
 	/* Set ciphers */
-	if ( ( rc = tls_set_cipher ( tls, &tls->tx_cipherspec_pending, pubkey,
-				     cipher, digest, key_len ) ) != 0 )
+	if ( ( rc = tls_set_cipher ( tls, &tls->tx_cipherspec_pending,
+				     suite ) ) != 0 )
 		return rc;
-	if ( ( rc = tls_set_cipher ( tls, &tls->rx_cipherspec_pending, pubkey,
-				     cipher, digest, key_len ) ) != 0 )
+	if ( ( rc = tls_set_cipher ( tls, &tls->rx_cipherspec_pending,
+				     suite ) ) != 0 )
 		return rc;
 
-	DBGC ( tls, "TLS %p selected %s-%s-%d-%s\n", tls,
-	       pubkey->name, cipher->name, ( key_len * 8 ), digest->name );
+	DBGC ( tls, "TLS %p selected %s-%s-%d-%s\n", tls, suite->pubkey->name,
+	       suite->cipher->name, ( suite->key_len * 8 ),
+	       suite->digest->name );
 
 	return 0;
 }
@@ -523,12 +822,9 @@ static int tls_change_cipher ( struct tls_session *tls,
 			       struct tls_cipherspec *active ) {
 
 	/* Sanity check */
-	if ( /* FIXME (when pubkey is not hard-coded to RSA):
-	      * ( pending->pubkey == &pubkey_null ) || */
-	     ( pending->cipher == &cipher_null ) ||
-	     ( pending->digest == &digest_null ) ) {
+	if ( pending->suite == &tls_cipher_suite_null ) {
 		DBGC ( tls, "TLS %p refusing to use null cipher\n", tls );
-		return -ENOTSUP;
+		return -ENOTSUP_NULL;
 	}
 
 	tls_clear_cipher ( tls, active );
@@ -536,6 +832,59 @@ static int tls_change_cipher ( struct tls_session *tls,
 	return 0;
 }
 
+/******************************************************************************
+ *
+ * Signature and hash algorithms
+ *
+ ******************************************************************************
+ */
+
+/** Supported signature and hash algorithms
+ *
+ * Note that the default (TLSv1.1 and earlier) algorithm using
+ * MD5+SHA1 is never explicitly specified.
+ */
+struct tls_signature_hash_algorithm tls_signature_hash_algorithms[] = {
+	{
+		.code = {
+			.signature = TLS_RSA_ALGORITHM,
+			.hash = TLS_SHA256_ALGORITHM,
+		},
+		.pubkey = &rsa_algorithm,
+		.digest = &sha256_algorithm,
+	},
+};
+
+/** Number of supported signature and hash algorithms */
+#define TLS_NUM_SIG_HASH_ALGORITHMS			\
+	( sizeof ( tls_signature_hash_algorithms ) /	\
+	  sizeof ( tls_signature_hash_algorithms[0] ) )
+
+/**
+ * Find TLS signature and hash algorithm
+ *
+ * @v pubkey		Public-key algorithm
+ * @v digest		Digest algorithm
+ * @ret sig_hash	Signature and hash algorithm, or NULL
+ */
+static struct tls_signature_hash_algorithm *
+tls_signature_hash_algorithm ( struct pubkey_algorithm *pubkey,
+			       struct digest_algorithm *digest ) {
+	struct tls_signature_hash_algorithm *sig_hash;
+	unsigned int i;
+
+	/* Identify signature and hash algorithm */
+	for ( i = 0 ; i < TLS_NUM_SIG_HASH_ALGORITHMS ; i++ ) {
+		sig_hash = &tls_signature_hash_algorithms[i];
+		if ( ( sig_hash->pubkey == pubkey ) &&
+		     ( sig_hash->digest == digest ) ) {
+			return sig_hash;
+		}
+	}
+
+	return NULL;
+}
+
 /******************************************************************************
  *
  * Handshake verification
@@ -553,8 +902,10 @@ static int tls_change_cipher ( struct tls_session *tls,
 static void tls_add_handshake ( struct tls_session *tls,
 				const void *data, size_t len ) {
 
-	digest_update ( &md5_algorithm, tls->handshake_md5_ctx, data, len );
-	digest_update ( &sha1_algorithm, tls->handshake_sha1_ctx, data, len );
+	digest_update ( &md5_sha1_algorithm, tls->handshake_md5_sha1_ctx,
+			data, len );
+	digest_update ( &sha256_algorithm, tls->handshake_sha256_ctx,
+			data, len );
 }
 
 /**
@@ -563,21 +914,15 @@ static void tls_add_handshake ( struct tls_session *tls,
  * @v tls		TLS session
  * @v out		Output buffer
  *
- * Calculates the MD5+SHA1 digest over all handshake messages seen so
- * far.
+ * Calculates the MD5+SHA1 or SHA256 digest over all handshake
+ * messages seen so far.
  */
 static void tls_verify_handshake ( struct tls_session *tls, void *out ) {
-	struct digest_algorithm *md5 = &md5_algorithm;
-	struct digest_algorithm *sha1 = &sha1_algorithm;
-	uint8_t md5_ctx[md5->ctxsize];
-	uint8_t sha1_ctx[sha1->ctxsize];
-	void *md5_digest = out;
-	void *sha1_digest = ( out + md5->digestsize );
-
-	memcpy ( md5_ctx, tls->handshake_md5_ctx, sizeof ( md5_ctx ) );
-	memcpy ( sha1_ctx, tls->handshake_sha1_ctx, sizeof ( sha1_ctx ) );
-	digest_final ( md5, md5_ctx, md5_digest );
-	digest_final ( sha1, sha1_ctx, sha1_digest );
+	struct digest_algorithm *digest = tls->handshake_digest;
+	uint8_t ctx[ digest->ctxsize ];
+
+	memcpy ( ctx, tls->handshake_ctx, sizeof ( ctx ) );
+	digest_final ( digest, ctx, out );
 }
 
 /******************************************************************************
@@ -587,6 +932,15 @@ static void tls_verify_handshake ( struct tls_session *tls, void *out ) {
  ******************************************************************************
  */
 
+/**
+ * Resume TX state machine
+ *
+ * @v tls		TLS session
+ */
+static void tls_tx_resume ( struct tls_session *tls ) {
+	process_add ( &tls->process );
+}
+
 /**
  * Transmit Handshake record
  *
@@ -618,25 +972,134 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
 		uint8_t random[32];
 		uint8_t session_id_len;
 		uint16_t cipher_suite_len;
-		uint16_t cipher_suites[2];
+		uint16_t cipher_suites[TLS_NUM_CIPHER_SUITES];
 		uint8_t compression_methods_len;
 		uint8_t compression_methods[1];
+		uint16_t extensions_len;
+		struct {
+			uint16_t server_name_type;
+			uint16_t server_name_len;
+			struct {
+				uint16_t len;
+				struct {
+					uint8_t type;
+					uint16_t len;
+					uint8_t name[ strlen ( tls->name ) ];
+				} __attribute__ (( packed )) list[1];
+			} __attribute__ (( packed )) server_name;
+			uint16_t max_fragment_length_type;
+			uint16_t max_fragment_length_len;
+			struct {
+				uint8_t max;
+			} __attribute__ (( packed )) max_fragment_length;
+		} __attribute__ (( packed )) extensions;
 	} __attribute__ (( packed )) hello;
+	unsigned int i;
 
 	memset ( &hello, 0, sizeof ( hello ) );
 	hello.type_length = ( cpu_to_le32 ( TLS_CLIENT_HELLO ) |
 			      htonl ( sizeof ( hello ) -
 				      sizeof ( hello.type_length ) ) );
-	hello.version = htons ( TLS_VERSION_TLS_1_0 );
+	hello.version = htons ( tls->version );
 	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 );
+	for ( i = 0 ; i < TLS_NUM_CIPHER_SUITES ; i++ )
+		hello.cipher_suites[i] = tls_cipher_suites[i].code;
 	hello.compression_methods_len = sizeof ( hello.compression_methods );
+	hello.extensions_len = htons ( sizeof ( hello.extensions ) );
+	hello.extensions.server_name_type = htons ( TLS_SERVER_NAME );
+	hello.extensions.server_name_len
+		= htons ( sizeof ( hello.extensions.server_name ) );
+	hello.extensions.server_name.len
+		= htons ( sizeof ( hello.extensions.server_name.list ) );
+	hello.extensions.server_name.list[0].type = TLS_SERVER_NAME_HOST_NAME;
+	hello.extensions.server_name.list[0].len
+		= htons ( sizeof ( hello.extensions.server_name.list[0].name ));
+	memcpy ( hello.extensions.server_name.list[0].name, tls->name,
+		 sizeof ( hello.extensions.server_name.list[0].name ) );
+	hello.extensions.max_fragment_length_type
+		= htons ( TLS_MAX_FRAGMENT_LENGTH );
+	hello.extensions.max_fragment_length_len
+		= htons ( sizeof ( hello.extensions.max_fragment_length ) );
+	hello.extensions.max_fragment_length.max
+		= TLS_MAX_FRAGMENT_LENGTH_4096;
 
 	return tls_send_handshake ( tls, &hello, sizeof ( hello ) );
 }
 
+/**
+ * Transmit Certificate record
+ *
+ * @v tls		TLS session
+ * @ret rc		Return status code
+ */
+static int tls_send_certificate ( struct tls_session *tls ) {
+	int num_certificates = ( have_client_certificate() ? 1 : 0 );
+	struct {
+		uint32_t type_length;
+		uint8_t length[3];
+		struct {
+			uint8_t length[3];
+			uint8_t data[ client_certificate.len ];
+		} __attribute__ (( packed )) certificates[num_certificates];
+	} __attribute__ (( packed )) *certificate;
+	struct x509_certificate *cert;
+	int rc;
+
+	/* If we have a certificate to send, determine the applicable
+	 * public-key algorithm and schedule transmission of
+	 * CertificateVerify.
+	 */
+	if ( num_certificates ) {
+
+		/* Parse certificate to determine public-key algorithm */
+		if ( ( rc = x509_certificate ( client_certificate.data,
+					       client_certificate.len,
+					       &cert ) ) != 0 ) {
+			DBGC ( tls, "TLS %p could not parse client "
+			       "certificate: %s\n", tls, strerror ( rc ) );
+			return rc;
+		}
+		tls->verify_pubkey = cert->signature_algorithm->pubkey;
+		x509_put ( cert );
+		cert = NULL;
+
+		/* Schedule CertificateVerify transmission */
+		tls->tx_pending |= TLS_TX_CERTIFICATE_VERIFY;
+		tls_tx_resume ( tls );
+	}
+
+	/* Allocate storage for Certificate record (which may be too
+	 * large for the stack).
+	 */
+	certificate = zalloc ( sizeof ( *certificate ) );
+	if ( ! certificate )
+		return -ENOMEM_CERTIFICATE;
+
+	/* Populate record */
+	certificate->type_length =
+		( cpu_to_le32 ( TLS_CERTIFICATE ) |
+		  htonl ( sizeof ( *certificate ) -
+			  sizeof ( certificate->type_length ) ) );
+	tls_set_uint24 ( certificate->length,
+			 sizeof ( certificate->certificates ) );
+	if ( num_certificates ) {
+		tls_set_uint24 ( certificate->certificates[0].length,
+				 sizeof ( certificate->certificates[0].data ) );
+		memcpy ( certificate->certificates[0].data,
+			 client_certificate.data,
+			 sizeof ( certificate->certificates[0].data ) );
+	}
+
+	/* Transmit record */
+	rc = tls_send_handshake ( tls, certificate, sizeof ( *certificate ) );
+
+	/* Free record */
+	free ( certificate );
+
+	return rc;
+}
+
 /**
  * Transmit Client Key Exchange record
  *
@@ -644,39 +1107,130 @@ static int tls_send_client_hello ( struct tls_session *tls ) {
  * @ret rc		Return status code
  */
 static int tls_send_client_key_exchange ( struct tls_session *tls ) {
-	/* FIXME: Hack alert */
-	RSA_CTX *rsa_ctx;
-	RSA_pub_key_new ( &rsa_ctx, tls->rsa.modulus, tls->rsa.modulus_len,
-			  tls->rsa.exponent, tls->rsa.exponent_len );
+	struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
+	struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
+	size_t max_len = pubkey_max_len ( pubkey, cipherspec->pubkey_ctx );
 	struct {
 		uint32_t type_length;
 		uint16_t encrypted_pre_master_secret_len;
-		uint8_t encrypted_pre_master_secret[rsa_ctx->num_octets];
+		uint8_t encrypted_pre_master_secret[max_len];
 	} __attribute__ (( packed )) key_xchg;
+	size_t unused;
+	int len;
+	int rc;
 
+	/* Encrypt pre-master secret using server's public key */
 	memset ( &key_xchg, 0, sizeof ( key_xchg ) );
-	key_xchg.type_length = ( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) |
-				 htonl ( sizeof ( key_xchg ) -
-					 sizeof ( key_xchg.type_length ) ) );
-	key_xchg.encrypted_pre_master_secret_len
-		= htons ( sizeof ( key_xchg.encrypted_pre_master_secret ) );
-
-	/* FIXME: Hack alert */
-	DBGC ( tls, "RSA encrypting plaintext, modulus, exponent:\n" );
-	DBGC_HD ( tls, &tls->pre_master_secret,
-		  sizeof ( tls->pre_master_secret ) );
-	DBGC_HD ( tls, tls->rsa.modulus, tls->rsa.modulus_len );
-	DBGC_HD ( tls, tls->rsa.exponent, tls->rsa.exponent_len );
-	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" );
-	DBGC_HD ( tls, &key_xchg.encrypted_pre_master_secret,
-		  sizeof ( key_xchg.encrypted_pre_master_secret ) );
-	RSA_free ( rsa_ctx );
-
-
-	return tls_send_handshake ( tls, &key_xchg, sizeof ( key_xchg ) );
+	len = pubkey_encrypt ( pubkey, cipherspec->pubkey_ctx,
+			       &tls->pre_master_secret,
+			       sizeof ( tls->pre_master_secret ),
+			       key_xchg.encrypted_pre_master_secret );
+	if ( len < 0 ) {
+		rc = len;
+		DBGC ( tls, "TLS %p could not encrypt pre-master secret: %s\n",
+		       tls, strerror ( rc ) );
+		return rc;
+	}
+	unused = ( max_len - len );
+	key_xchg.type_length =
+		( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) |
+		  htonl ( sizeof ( key_xchg ) -
+			  sizeof ( key_xchg.type_length ) - unused ) );
+	key_xchg.encrypted_pre_master_secret_len =
+		htons ( sizeof ( key_xchg.encrypted_pre_master_secret ) -
+			unused );
+
+	return tls_send_handshake ( tls, &key_xchg,
+				    ( sizeof ( key_xchg ) - unused ) );
+}
+
+/**
+ * Transmit Certificate Verify record
+ *
+ * @v tls		TLS session
+ * @ret rc		Return status code
+ */
+static int tls_send_certificate_verify ( struct tls_session *tls ) {
+	struct digest_algorithm *digest = tls->handshake_digest;
+	struct pubkey_algorithm *pubkey = tls->verify_pubkey;
+	uint8_t digest_out[ digest->digestsize ];
+	uint8_t ctx[ pubkey->ctxsize ];
+	struct tls_signature_hash_algorithm *sig_hash = NULL;
+	int rc;
+
+	/* Generate digest to be signed */
+	tls_verify_handshake ( tls, digest_out );
+
+	/* Initialise public-key algorithm */
+	if ( ( rc = pubkey_init ( pubkey, ctx, client_private_key.data,
+				  client_private_key.len ) ) != 0 ) {
+		DBGC ( tls, "TLS %p could not initialise %s client private "
+		       "key: %s\n", tls, pubkey->name, strerror ( rc ) );
+		goto err_pubkey_init;
+	}
+
+	/* TLSv1.2 and later use explicit algorithm identifiers */
+	if ( tls->version >= TLS_VERSION_TLS_1_2 ) {
+		sig_hash = tls_signature_hash_algorithm ( pubkey, digest );
+		if ( ! sig_hash ) {
+			DBGC ( tls, "TLS %p could not identify (%s,%s) "
+			       "signature and hash algorithm\n", tls,
+			       pubkey->name, digest->name );
+			rc = -ENOTSUP_SIG_HASH;
+			goto err_sig_hash;
+		}
+	}
+
+	/* Generate and transmit record */
+	{
+		size_t max_len = pubkey_max_len ( pubkey, ctx );
+		int use_sig_hash = ( ( sig_hash == NULL ) ? 0 : 1 );
+		struct {
+			uint32_t type_length;
+			struct tls_signature_hash_id sig_hash[use_sig_hash];
+			uint16_t signature_len;
+			uint8_t signature[max_len];
+		} __attribute__ (( packed )) certificate_verify;
+		size_t unused;
+		int len;
+
+		/* Sign digest */
+		len = pubkey_sign ( pubkey, ctx, digest, digest_out,
+				    certificate_verify.signature );
+		if ( len < 0 ) {
+			rc = len;
+			DBGC ( tls, "TLS %p could not sign %s digest using %s "
+			       "client private key: %s\n", tls, digest->name,
+			       pubkey->name, strerror ( rc ) );
+			goto err_pubkey_sign;
+		}
+		unused = ( max_len - len );
+
+		/* Construct Certificate Verify record */
+		certificate_verify.type_length =
+			( cpu_to_le32 ( TLS_CERTIFICATE_VERIFY ) |
+			  htonl ( sizeof ( certificate_verify ) -
+				  sizeof ( certificate_verify.type_length ) -
+				  unused ) );
+		if ( use_sig_hash ) {
+			memcpy ( &certificate_verify.sig_hash[0],
+				 &sig_hash->code,
+				 sizeof ( certificate_verify.sig_hash[0] ) );
+		}
+		certificate_verify.signature_len =
+			htons ( sizeof ( certificate_verify.signature ) -
+				unused );
+
+		/* Transmit record */
+		rc = tls_send_handshake ( tls, &certificate_verify,
+				   ( sizeof ( certificate_verify ) - unused ) );
+	}
+
+ err_pubkey_sign:
+ err_sig_hash:
+	pubkey_final ( pubkey, ctx );
+ err_pubkey_init:
+	return rc;
 }
 
 /**
@@ -698,22 +1252,33 @@ static int tls_send_change_cipher ( struct tls_session *tls ) {
  * @ret rc		Return status code
  */
 static int tls_send_finished ( struct tls_session *tls ) {
+	struct digest_algorithm *digest = tls->handshake_digest;
 	struct {
 		uint32_t type_length;
 		uint8_t verify_data[12];
 	} __attribute__ (( packed )) finished;
-	uint8_t digest[MD5_DIGEST_SIZE + SHA1_DIGEST_SIZE];
+	uint8_t digest_out[ digest->digestsize ];
+	int rc;
 
+	/* Construct record */
 	memset ( &finished, 0, sizeof ( finished ) );
 	finished.type_length = ( cpu_to_le32 ( TLS_FINISHED ) |
 				 htonl ( sizeof ( finished ) -
 					 sizeof ( finished.type_length ) ) );
-	tls_verify_handshake ( tls, digest );
+	tls_verify_handshake ( tls, digest_out );
 	tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
 			finished.verify_data, sizeof ( finished.verify_data ),
-			"client finished", digest, sizeof ( digest ) );
+			"client finished", digest_out, sizeof ( digest_out ) );
 
-	return tls_send_handshake ( tls, &finished, sizeof ( finished ) );
+	/* Transmit record */
+	if ( ( rc = tls_send_handshake ( tls, &finished,
+					 sizeof ( finished ) ) ) != 0 )
+		return rc;
+
+	/* Mark client as finished */
+	pending_put ( &tls->client_negotiation );
+
+	return 0;
 }
 
 /**
@@ -725,13 +1290,13 @@ static int tls_send_finished ( struct tls_session *tls ) {
  * @ret rc		Return status code
  */
 static int tls_new_change_cipher ( struct tls_session *tls,
-				   void *data, size_t len ) {
+				   const void *data, size_t len ) {
 	int rc;
 
 	if ( ( len != 1 ) || ( *( ( uint8_t * ) data ) != 1 ) ) {
 		DBGC ( tls, "TLS %p received invalid Change Cipher\n", tls );
 		DBGC_HD ( tls, data, len );
-		return -EINVAL;
+		return -EINVAL_CHANGE_CIPHER;
 	}
 
 	if ( ( rc = tls_change_cipher ( tls, &tls->rx_cipherspec_pending,
@@ -753,19 +1318,20 @@ static int tls_new_change_cipher ( struct tls_session *tls,
  * @v len		Length of plaintext record
  * @ret rc		Return status code
  */
-static int tls_new_alert ( struct tls_session *tls, void *data, size_t len ) {
-	struct {
+static int tls_new_alert ( struct tls_session *tls, const void *data,
+			   size_t len ) {
+	const struct {
 		uint8_t level;
 		uint8_t description;
 		char next[0];
 	} __attribute__ (( packed )) *alert = data;
-	void *end = alert->next;
+	const void *end = alert->next;
 
 	/* Sanity check */
 	if ( end != ( data + len ) ) {
 		DBGC ( tls, "TLS %p received overlength Alert\n", tls );
 		DBGC_HD ( tls, data, len );
-		return -EINVAL;
+		return -EINVAL_ALERT;
 	}
 
 	switch ( alert->level ) {
@@ -776,11 +1342,11 @@ static int tls_new_alert ( struct tls_session *tls, void *data, size_t len ) {
 	case TLS_ALERT_FATAL:
 		DBGC ( tls, "TLS %p received fatal alert %d\n",
 		       tls, alert->description );
-		return -EPERM;
+		return -EPERM_ALERT;
 	default:
 		DBGC ( tls, "TLS %p received unknown alert level %d"
 		       "(alert %d)\n", tls, alert->level, alert->description );
-		return -EIO;
+		return -EIO_ALERT;
 	}
 }
 
@@ -793,35 +1359,53 @@ static int tls_new_alert ( struct tls_session *tls, void *data, size_t len ) {
  * @ret rc		Return status code
  */
 static int tls_new_server_hello ( struct tls_session *tls,
-				  void *data, size_t len ) {
-	struct {
+				  const void *data, size_t len ) {
+	const struct {
 		uint16_t version;
 		uint8_t random[32];
 		uint8_t session_id_len;
 		char next[0];
 	} __attribute__ (( packed )) *hello_a = data;
-	struct {
+	const struct {
 		uint8_t session_id[hello_a->session_id_len];
 		uint16_t cipher_suite;
 		uint8_t compression_method;
 		char next[0];
 	} __attribute__ (( packed )) *hello_b = ( void * ) &hello_a->next;
-	void *end = hello_b->next;
+	const void *end = hello_b->next;
+	uint16_t version;
 	int rc;
 
 	/* Sanity check */
-	if ( end != ( data + len ) ) {
-		DBGC ( tls, "TLS %p received overlength Server Hello\n", tls );
+	if ( end > ( data + len ) ) {
+		DBGC ( tls, "TLS %p received underlength Server Hello\n", tls );
 		DBGC_HD ( tls, data, len );
-		return -EINVAL;
+		return -EINVAL_HELLO;
 	}
 
-	/* Check protocol version */
-	if ( ntohs ( hello_a->version ) < TLS_VERSION_TLS_1_0 ) {
+	/* Check and store protocol version */
+	version = ntohs ( hello_a->version );
+	if ( version < TLS_VERSION_TLS_1_0 ) {
 		DBGC ( tls, "TLS %p does not support protocol version %d.%d\n",
-		       tls, ( ntohs ( hello_a->version ) >> 8 ),
-		       ( ntohs ( hello_a->version ) & 0xff ) );
-		return -ENOTSUP;
+		       tls, ( version >> 8 ), ( version & 0xff ) );
+		return -ENOTSUP_VERSION;
+	}
+	if ( version > tls->version ) {
+		DBGC ( tls, "TLS %p server attempted to illegally upgrade to "
+		       "protocol version %d.%d\n",
+		       tls, ( version >> 8 ), ( version & 0xff ) );
+		return -EPROTO_VERSION;
+	}
+	tls->version = version;
+	DBGC ( tls, "TLS %p using protocol version %d.%d\n",
+	       tls, ( version >> 8 ), ( version & 0xff ) );
+
+	/* Use MD5+SHA1 digest algorithm for handshake verification
+	 * for versions earlier than TLSv1.2.
+	 */
+	if ( tls->version < TLS_VERSION_TLS_1_2 ) {
+		tls->handshake_digest = &md5_sha1_algorithm;
+		tls->handshake_ctx = tls->handshake_md5_sha1_ctx;
 	}
 
 	/* Copy out server random bytes */
@@ -840,6 +1424,77 @@ static int tls_new_server_hello ( struct tls_session *tls,
 	return 0;
 }
 
+/**
+ * Parse certificate chain
+ *
+ * @v tls		TLS session
+ * @v data		Certificate chain
+ * @v len		Length of certificate chain
+ * @ret rc		Return status code
+ */
+static int tls_parse_chain ( struct tls_session *tls,
+			     const void *data, size_t len ) {
+	const void *end = ( data + len );
+	const struct {
+		uint8_t length[3];
+		uint8_t data[0];
+	} __attribute__ (( packed )) *certificate;
+	size_t certificate_len;
+	struct x509_certificate *cert;
+	const void *next;
+	int rc;
+
+	/* Free any existing certificate chain */
+	x509_chain_put ( tls->chain );
+	tls->chain = NULL;
+
+	/* Create certificate chain */
+	tls->chain = x509_alloc_chain();
+	if ( ! tls->chain ) {
+		rc = -ENOMEM_CHAIN;
+		goto err_alloc_chain;
+	}
+
+	/* Add certificates to chain */
+	while ( data < end ) {
+
+		/* Extract raw certificate data */
+		certificate = data;
+		certificate_len = tls_uint24 ( certificate->length );
+		next = ( certificate->data + certificate_len );
+		if ( next > end ) {
+			DBGC ( tls, "TLS %p overlength certificate:\n", tls );
+			DBGC_HDA ( tls, 0, data, ( end - data ) );
+			rc = -EINVAL_CERTIFICATE;
+			goto err_overlength;
+		}
+
+		/* Add certificate to chain */
+		if ( ( rc = x509_append_raw ( tls->chain, certificate->data,
+					      certificate_len ) ) != 0 ) {
+			DBGC ( tls, "TLS %p could not append certificate: %s\n",
+			       tls, strerror ( rc ) );
+			DBGC_HDA ( tls, 0, data, ( end - data ) );
+			goto err_parse;
+		}
+		cert = x509_last ( tls->chain );
+		DBGC ( tls, "TLS %p found certificate %s\n",
+		       tls, cert->subject.name );
+
+		/* Move to next certificate in list */
+		data = next;
+	}
+
+	return 0;
+
+ err_parse:
+ err_overlength:
+	x509_chain_put ( tls->chain );
+	tls->chain = NULL;
+ err_alloc_chain:
+	return rc;
+}
+
 /**
  * Receive new Certificate handshake record
  *
@@ -849,19 +1504,13 @@ static int tls_new_server_hello ( struct tls_session *tls,
  * @ret rc		Return status code
  */
 static int tls_new_certificate ( struct tls_session *tls,
-				 void *data, size_t len ) {
-	struct {
+				 const void *data, size_t len ) {
+	const struct {
 		uint8_t length[3];
 		uint8_t certificates[0];
 	} __attribute__ (( packed )) *certificate = data;
-	struct {
-		uint8_t length[3];
-		uint8_t certificate[0];
-	} __attribute__ (( packed )) *element =
-		  ( ( void * ) certificate->certificates );
-	size_t elements_len = tls_uint24 ( certificate->length );
-	void *end = ( certificate->certificates + elements_len );
-	struct asn1_cursor cursor;
+	size_t certificates_len = tls_uint24 ( certificate->length );
+	const void *end = ( certificate->certificates + certificates_len );
 	int rc;
 
 	/* Sanity check */
@@ -869,33 +1518,38 @@ static int tls_new_certificate ( struct tls_session *tls,
 		DBGC ( tls, "TLS %p received overlength Server Certificate\n",
 		       tls );
 		DBGC_HD ( tls, data, len );
-		return -EINVAL;
+		return -EINVAL_CERTIFICATES;
 	}
 
-	/* Traverse certificate chain */
-	do {
-		cursor.data = element->certificate;
-		cursor.len = tls_uint24 ( element->length );
-		if ( ( cursor.data + cursor.len ) > end ) {
-			DBGC ( tls, "TLS %p received corrupt Server "
-			       "Certificate\n", tls );
-			DBGC_HD ( tls, data, len );
-			return -EINVAL;
-		}
+	/* Parse certificate chain */
+	if ( ( rc = tls_parse_chain ( tls, certificate->certificates,
+				      certificates_len ) ) != 0 )
+		return rc;
 
-		// HACK
-		if ( ( rc = x509_rsa_public_key ( &cursor,
-						  &tls->rsa ) ) != 0 ) {
-			DBGC ( tls, "TLS %p cannot determine RSA public key: "
-			       "%s\n", tls, strerror ( rc ) );
-			return rc;
-		}
-		return 0;
+	return 0;
+}
 
-		element = ( cursor.data + cursor.len );
-	} while ( element != end );
+/**
+ * Receive new Certificate Request handshake record
+ *
+ * @v tls		TLS session
+ * @v data		Plaintext handshake record
+ * @v len		Length of plaintext handshake record
+ * @ret rc		Return status code
+ */
+static int tls_new_certificate_request ( struct tls_session *tls,
+					 const void *data __unused,
+					 size_t len __unused ) {
+
+	/* We can only send a single certificate, so there is no point
+	 * in parsing the Certificate Request.
+	 */
+
+	/* Schedule Certificate transmission */
+	tls->tx_pending |= TLS_TX_CERTIFICATE;
+	tls_tx_resume ( tls );
 
-	return -EINVAL;
+	return 0;
 }
 
 /**
@@ -907,30 +1561,28 @@ static int tls_new_certificate ( struct tls_session *tls,
  * @ret rc		Return status code
  */
 static int tls_new_server_hello_done ( struct tls_session *tls,
-				       void *data, size_t len ) {
-	struct {
+				       const void *data, size_t len ) {
+	const struct {
 		char next[0];
 	} __attribute__ (( packed )) *hello_done = data;
-	void *end = hello_done->next;
+	const void *end = hello_done->next;
+	int rc;
 
 	/* Sanity check */
 	if ( end != ( data + len ) ) {
 		DBGC ( tls, "TLS %p received overlength Server Hello Done\n",
 		       tls );
 		DBGC_HD ( tls, data, len );
-		return -EINVAL;
+		return -EINVAL_HELLO_DONE;
 	}
 
-	/* Check that we are ready to send the Client Key Exchange */
-	if ( tls->tx_state != TLS_TX_NONE ) {
-		DBGC ( tls, "TLS %p received Server Hello Done while in "
-		       "TX state %d\n", tls, tls->tx_state );
-		return -EIO;
+	/* Begin certificate validation */
+	if ( ( rc = create_validator ( &tls->validator, tls->chain ) ) != 0 ) {
+		DBGC ( tls, "TLS %p could not start certificate validation: "
+		       "%s\n", tls, strerror ( rc ) );
+		return rc;
 	}
 
-	/* Start sending the Client Key Exchange */
-	tls->tx_state = TLS_TX_CLIENT_KEY_EXCHANGE;
-
 	return 0;
 }
 
@@ -943,12 +1595,40 @@ static int tls_new_server_hello_done ( struct tls_session *tls,
  * @ret rc		Return status code
  */
 static int tls_new_finished ( struct tls_session *tls,
-			      void *data, size_t len ) {
+			      const void *data, size_t len ) {
+	struct digest_algorithm *digest = tls->handshake_digest;
+	const struct {
+		uint8_t verify_data[12];
+		char next[0];
+	} __attribute__ (( packed )) *finished = data;
+	const void *end = finished->next;
+	uint8_t digest_out[ digest->digestsize ];
+	uint8_t verify_data[ sizeof ( finished->verify_data ) ];
+
+	/* Sanity check */
+	if ( end != ( data + len ) ) {
+		DBGC ( tls, "TLS %p received overlength Finished\n", tls );
+		DBGC_HD ( tls, data, len );
+		return -EINVAL_FINISHED;
+	}
+
+	/* Verify data */
+	tls_verify_handshake ( tls, digest_out );
+	tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ),
+			verify_data, sizeof ( verify_data ), "server finished",
+			digest_out, sizeof ( digest_out ) );
+	if ( memcmp ( verify_data, finished->verify_data,
+		      sizeof ( verify_data ) ) != 0 ) {
+		DBGC ( tls, "TLS %p verification failed\n", tls );
+		return -EPERM_VERIFY;
+	}
+
+	/* Mark server as finished */
+	pending_put ( &tls->server_negotiation );
+
+	/* Send notification of a window change */
+	xfer_window_changed ( &tls->plainstream );
 
-	/* FIXME: Handle this properly */
-	tls->tx_state = TLS_TX_DATA;
-	( void ) data;
-	( void ) len;
 	return 0;
 }
 
@@ -961,12 +1641,12 @@ static int tls_new_finished ( struct tls_session *tls,
  * @ret rc		Return status code
  */
 static int tls_new_handshake ( struct tls_session *tls,
-			       void *data, size_t len ) {
-	void *end = ( data + len );
+			       const void *data, size_t len ) {
+	const void *end = ( data + len );
 	int rc;
 
 	while ( data != end ) {
-		struct {
+		const struct {
 			uint8_t type;
 			uint8_t length[3];
 			uint8_t payload[0];
@@ -980,7 +1660,7 @@ static int tls_new_handshake ( struct tls_session *tls,
 			DBGC ( tls, "TLS %p received overlength Handshake\n",
 			       tls );
 			DBGC_HD ( tls, data, len );
-			return -EINVAL;
+			return -EINVAL_HANDSHAKE;
 		}
 
 		switch ( handshake->type ) {
@@ -990,6 +1670,10 @@ static int tls_new_handshake ( struct tls_session *tls,
 		case TLS_CERTIFICATE:
 			rc = tls_new_certificate ( tls, payload, payload_len );
 			break;
+		case TLS_CERTIFICATE_REQUEST:
+			rc = tls_new_certificate_request ( tls, payload,
+							   payload_len );
+			break;
 		case TLS_SERVER_HELLO_DONE:
 			rc = tls_new_server_hello_done ( tls, payload,
 							 payload_len );
@@ -1028,29 +1712,69 @@ static int tls_new_handshake ( struct tls_session *tls,
  *
  * @v tls		TLS session
  * @v type		Record type
- * @v data		Plaintext record
- * @v len		Length of plaintext record
+ * @v rx_data		List of received data buffers
  * @ret rc		Return status code
  */
-static int tls_new_record ( struct tls_session *tls,
-			    unsigned int type, void *data, size_t len ) {
+static int tls_new_record ( struct tls_session *tls, unsigned int type,
+			    struct list_head *rx_data ) {
+	struct io_buffer *iobuf;
+	int ( * handler ) ( struct tls_session *tls, const void *data,
+			    size_t len );
+	int rc;
 
+	/* Deliver data records to the plainstream interface */
+	if ( type == TLS_TYPE_DATA ) {
+
+		/* Fail unless we are ready to receive data */
+		if ( ! tls_ready ( tls ) )
+			return -ENOTCONN;
+
+		/* Deliver each I/O buffer in turn */
+		while ( ( iobuf = list_first_entry ( rx_data, struct io_buffer,
+						     list ) ) ) {
+			list_del ( &iobuf->list );
+			if ( ( rc = xfer_deliver_iob ( &tls->plainstream,
+						       iobuf ) ) != 0 ) {
+				DBGC ( tls, "TLS %p could not deliver data: "
+				       "%s\n", tls, strerror ( rc ) );
+				return rc;
+			}
+		}
+		return 0;
+	}
+
+	/* For all other records, merge into a single I/O buffer */
+	iobuf = iob_concatenate ( rx_data );
+	if ( ! iobuf ) {
+		DBGC ( tls, "TLS %p could not concatenate non-data record "
+		       "type %d\n", tls, type );
+		return -ENOMEM_RX_CONCAT;
+	}
+
+	/* Determine handler */
 	switch ( type ) {
 	case TLS_TYPE_CHANGE_CIPHER:
-		return tls_new_change_cipher ( tls, data, len );
+		handler = tls_new_change_cipher;
+		break;
 	case TLS_TYPE_ALERT:
-		return tls_new_alert ( tls, data, len );
+		handler = tls_new_alert;
+		break;
 	case TLS_TYPE_HANDSHAKE:
-		return tls_new_handshake ( tls, data, len );
-	case TLS_TYPE_DATA:
-		return xfer_deliver_raw ( &tls->plainstream, data, len );
+		handler = tls_new_handshake;
+		break;
 	default:
 		/* RFC4346 says that we should just ignore unknown
 		 * record types.
 		 */
+		handler = NULL;
 		DBGC ( tls, "TLS %p ignoring record type %d\n", tls, type );
-		return 0;
+		break;
 	}
+
+	/* Handle record and free I/O buffer */
+	rc = ( handler ? handler ( tls, iobuf->data, iob_len ( iobuf ) ) : 0 );
+	free_iob ( iobuf );
+	return rc;
 }
 
 /******************************************************************************
@@ -1060,10 +1784,57 @@ static int tls_new_record ( struct tls_session *tls,
  ******************************************************************************
  */
 
+/**
+ * Initialise HMAC
+ *
+ * @v cipherspec	Cipher specification
+ * @v ctx		Context
+ * @v seq		Sequence number
+ * @v tlshdr		TLS header
+ */
+static void tls_hmac_init ( struct tls_cipherspec *cipherspec, void *ctx,
+			    uint64_t seq, struct tls_header *tlshdr ) {
+	struct digest_algorithm *digest = cipherspec->suite->digest;
+
+	hmac_init ( digest, ctx, cipherspec->mac_secret, &digest->digestsize );
+	seq = cpu_to_be64 ( seq );
+	hmac_update ( digest, ctx, &seq, sizeof ( seq ) );
+	hmac_update ( digest, ctx, tlshdr, sizeof ( *tlshdr ) );
+}
+
+/**
+ * Update HMAC
+ *
+ * @v cipherspec	Cipher specification
+ * @v ctx		Context
+ * @v data		Data
+ * @v len		Length of data
+ */
+static void tls_hmac_update ( struct tls_cipherspec *cipherspec, void *ctx,
+			      const void *data, size_t len ) {
+	struct digest_algorithm *digest = cipherspec->suite->digest;
+
+	hmac_update ( digest, ctx, data, len );
+}
+
+/**
+ * Finalise HMAC
+ *
+ * @v cipherspec	Cipher specification
+ * @v ctx		Context
+ * @v mac		HMAC to fill in
+ */
+static void tls_hmac_final ( struct tls_cipherspec *cipherspec, void *ctx,
+			     void *hmac ) {
+	struct digest_algorithm *digest = cipherspec->suite->digest;
+
+	hmac_final ( digest, ctx, cipherspec->mac_secret,
+		     &digest->digestsize, hmac );
+}
+
 /**
  * Calculate HMAC
  *
- * @v tls		TLS session
  * @v cipherspec	Cipher specification
  * @v seq		Sequence number
  * @v tlshdr		TLS header
@@ -1071,21 +1842,15 @@ static int tls_new_record ( struct tls_session *tls,
  * @v len		Length of data
  * @v mac		HMAC to fill in
  */
-static void tls_hmac ( struct tls_session *tls __unused,
-		       struct tls_cipherspec *cipherspec,
+static void tls_hmac ( struct tls_cipherspec *cipherspec,
 		       uint64_t seq, struct tls_header *tlshdr,
 		       const void *data, size_t len, void *hmac ) {
-	struct digest_algorithm *digest = cipherspec->digest;
-	uint8_t digest_ctx[digest->ctxsize];
+	struct digest_algorithm *digest = cipherspec->suite->digest;
+	uint8_t ctx[digest->ctxsize];
 
-	hmac_init ( digest, digest_ctx, cipherspec->mac_secret,
-		    &digest->digestsize );
-	seq = cpu_to_be64 ( seq );
-	hmac_update ( digest, digest_ctx, &seq, sizeof ( seq ) );
-	hmac_update ( digest, digest_ctx, tlshdr, sizeof ( *tlshdr ) );
-	hmac_update ( digest, digest_ctx, data, len );
-	hmac_final ( digest, digest_ctx, cipherspec->mac_secret,
-		     &digest->digestsize, hmac );
+	tls_hmac_init ( cipherspec, ctx, seq, tlshdr );
+	tls_hmac_update ( cipherspec, ctx, data, len );
+	tls_hmac_final ( cipherspec, ctx, hmac );
 }
 
 /**
@@ -1101,7 +1866,7 @@ static void tls_hmac ( struct tls_session *tls __unused,
 static void * __malloc tls_assemble_stream ( struct tls_session *tls,
 				    const void *data, size_t len,
 				    void *digest, size_t *plaintext_len ) {
-	size_t mac_len = tls->tx_cipherspec.digest->digestsize;
+	size_t mac_len = tls->tx_cipherspec.suite->digest->digestsize;
 	void *plaintext;
 	void *content;
 	void *mac;
@@ -1136,9 +1901,9 @@ static void * __malloc tls_assemble_stream ( struct tls_session *tls,
 static void * tls_assemble_block ( struct tls_session *tls,
 				   const void *data, size_t len,
 				   void *digest, size_t *plaintext_len ) {
-	size_t blocksize = tls->tx_cipherspec.cipher->blocksize;
-	size_t iv_len = blocksize;
-	size_t mac_len = tls->tx_cipherspec.digest->digestsize;
+	size_t blocksize = tls->tx_cipherspec.suite->cipher->blocksize;
+	size_t mac_len = tls->tx_cipherspec.suite->digest->digestsize;
+	size_t iv_len;
 	size_t padding_len;
 	void *plaintext;
 	void *iv;
@@ -1146,8 +1911,8 @@ static void * tls_assemble_block ( struct tls_session *tls,
 	void *mac;
 	void *padding;
 
-	/* FIXME: TLSv1.1 has an explicit IV */
-	iv_len = 0;
+	/* TLSv1.1 and later use an explicit IV */
+	iv_len = ( ( tls->version >= TLS_VERSION_TLS_1_1 ) ? blocksize : 0 );
 
 	/* Calculate block-ciphered struct length */
 	padding_len = ( ( blocksize - 1 ) & -( iv_len + len + mac_len + 1 ) );
@@ -1163,7 +1928,7 @@ static void * tls_assemble_block ( struct tls_session *tls,
 	padding = ( mac + mac_len );
 
 	/* Fill in block-ciphered struct */
-	memset ( iv, 0, iv_len );
+	tls_generate_random ( tls, iv, iv_len );
 	memcpy ( content, data, len );
 	memcpy ( mac, digest, mac_len );
 	memset ( padding, padding_len, ( padding_len + 1 ) );
@@ -1185,25 +1950,25 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
 	struct tls_header plaintext_tlshdr;
 	struct tls_header *tlshdr;
 	struct tls_cipherspec *cipherspec = &tls->tx_cipherspec;
+	struct cipher_algorithm *cipher = cipherspec->suite->cipher;
 	void *plaintext = NULL;
 	size_t plaintext_len;
 	struct io_buffer *ciphertext = NULL;
 	size_t ciphertext_len;
-	size_t mac_len = cipherspec->digest->digestsize;
+	size_t mac_len = cipherspec->suite->digest->digestsize;
 	uint8_t mac[mac_len];
 	int rc;
 
 	/* Construct header */
 	plaintext_tlshdr.type = type;
-	plaintext_tlshdr.version = htons ( TLS_VERSION_TLS_1_0 );
+	plaintext_tlshdr.version = htons ( tls->version );
 	plaintext_tlshdr.length = htons ( len );
 
 	/* Calculate MAC */
-	tls_hmac ( tls, cipherspec, tls->tx_seq, &plaintext_tlshdr,
-		   data, len, mac );
+	tls_hmac ( cipherspec, tls->tx_seq, &plaintext_tlshdr, data, len, mac );
 
 	/* Allocate and assemble plaintext struct */
-	if ( is_stream_cipher ( cipherspec->cipher ) ) {
+	if ( is_stream_cipher ( cipher ) ) {
 		plaintext = tls_assemble_stream ( tls, data, len, mac,
 						  &plaintext_len );
 	} else {
@@ -1213,7 +1978,7 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
 	if ( ! plaintext ) {
 		DBGC ( tls, "TLS %p could not allocate %zd bytes for "
 		       "plaintext\n", tls, plaintext_len );
-		rc = -ENOMEM;
+		rc = -ENOMEM_TX_PLAINTEXT;
 		goto done;
 	}
 
@@ -1226,20 +1991,19 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
 	if ( ! ciphertext ) {
 		DBGC ( tls, "TLS %p could not allocate %zd bytes for "
 		       "ciphertext\n", tls, ciphertext_len );
-		rc = -ENOMEM;
+		rc = -ENOMEM_TX_CIPHERTEXT;
 		goto done;
 	}
 
 	/* Assemble ciphertext */
 	tlshdr = iob_put ( ciphertext, sizeof ( *tlshdr ) );
 	tlshdr->type = type;
-	tlshdr->version = htons ( TLS_VERSION_TLS_1_0 );
+	tlshdr->version = htons ( tls->version );
 	tlshdr->length = htons ( plaintext_len );
 	memcpy ( cipherspec->cipher_next_ctx, cipherspec->cipher_ctx,
-		 cipherspec->cipher->ctxsize );
-	cipher_encrypt ( cipherspec->cipher, cipherspec->cipher_next_ctx,
-			 plaintext, iob_put ( ciphertext, plaintext_len ),
-			 plaintext_len );
+		 cipher->ctxsize );
+	cipher_encrypt ( cipher, cipherspec->cipher_next_ctx, plaintext,
+			 iob_put ( ciphertext, plaintext_len ), plaintext_len );
 
 	/* Free plaintext as soon as possible to conserve memory */
 	free ( plaintext );
@@ -1256,8 +2020,7 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
 	/* Update TX state machine to next record */
 	tls->tx_seq += 1;
 	memcpy ( tls->tx_cipherspec.cipher_ctx,
-		 tls->tx_cipherspec.cipher_next_ctx,
-		 tls->tx_cipherspec.cipher->ctxsize );
+		 tls->tx_cipherspec.cipher_next_ctx, cipher->ctxsize );
 
  done:
 	free ( plaintext );
@@ -1269,36 +2032,25 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
  * Split stream-ciphered record into data and MAC portions
  *
  * @v tls		TLS session
- * @v plaintext		Plaintext record
- * @v plaintext_len	Length of record
- * @ret data		Data
- * @ret len		Length of data
- * @ret digest		MAC digest
+ * @v rx_data		List of received data buffers
+ * @v mac		MAC to fill in
  * @ret rc		Return status code
  */
 static int tls_split_stream ( struct tls_session *tls,
-			      void *plaintext, size_t plaintext_len,
-			      void **data, size_t *len, void **digest ) {
-	void *content;
-	size_t content_len;
-	void *mac;
-	size_t mac_len;
-
-	/* Decompose stream-ciphered data */
-	mac_len = tls->rx_cipherspec.digest->digestsize;
-	if ( plaintext_len < mac_len ) {
-		DBGC ( tls, "TLS %p received underlength record\n", tls );
-		DBGC_HD ( tls, plaintext, plaintext_len );
-		return -EINVAL;
+			      struct list_head *rx_data, void **mac ) {
+	size_t mac_len = tls->rx_cipherspec.suite->digest->digestsize;
+	struct io_buffer *iobuf;
+
+	/* Extract MAC */
+	iobuf = list_last_entry ( rx_data, struct io_buffer, list );
+	assert ( iobuf != NULL );
+	if ( iob_len ( iobuf ) < mac_len ) {
+		DBGC ( tls, "TLS %p received underlength MAC\n", tls );
+		DBGC_HD ( tls, iobuf->data, iob_len ( iobuf ) );
+		return -EINVAL_STREAM;
 	}
-	content_len = ( plaintext_len - mac_len );
-	content = plaintext;
-	mac = ( content + content_len );
-
-	/* Fill in return values */
-	*data = content;
-	*len = content_len;
-	*digest = mac;
+	iob_unput ( iobuf, mac_len );
+	*mac = iobuf->tail;
 
 	return 0;
 }
@@ -1307,64 +2059,56 @@ static int tls_split_stream ( struct tls_session *tls,
  * Split block-ciphered record into data and MAC portions
  *
  * @v tls		TLS session
- * @v plaintext		Plaintext record
- * @v plaintext_len	Length of record
- * @ret data		Data
- * @ret len		Length of data
- * @ret digest		MAC digest
+ * @v rx_data		List of received data buffers
+ * @v mac		MAC to fill in
  * @ret rc		Return status code
  */
 static int tls_split_block ( struct tls_session *tls,
-			     void *plaintext, size_t plaintext_len,
-			     void **data, size_t *len,
-			     void **digest ) {
-	void *iv;
+			     struct list_head *rx_data, void **mac ) {
+	size_t mac_len = tls->rx_cipherspec.suite->digest->digestsize;
+	struct io_buffer *iobuf;
 	size_t iv_len;
-	void *content;
-	size_t content_len;
-	void *mac;
-	size_t mac_len;
-	void *padding;
+	uint8_t *padding_final;
+	uint8_t *padding;
 	size_t padding_len;
-	unsigned int i;
 
-	/* Decompose block-ciphered data */
-	if ( plaintext_len < 1 ) {
-		DBGC ( tls, "TLS %p received underlength record\n", tls );
-		DBGC_HD ( tls, plaintext, plaintext_len );
-		return -EINVAL;
+	/* TLSv1.1 and later use an explicit IV */
+	iobuf = list_first_entry ( rx_data, struct io_buffer, list );
+	iv_len = ( ( tls->version >= TLS_VERSION_TLS_1_1 ) ?
+		   tls->rx_cipherspec.suite->cipher->blocksize : 0 );
+	if ( iob_len ( iobuf ) < iv_len ) {
+		DBGC ( tls, "TLS %p received underlength IV\n", tls );
+		DBGC_HD ( tls, iobuf->data, iob_len ( iobuf ) );
+		return -EINVAL_BLOCK;
 	}
-	iv_len = tls->rx_cipherspec.cipher->blocksize;
-
-	/* FIXME: TLSv1.1 uses an explicit IV */
-	iv_len = 0;
-
-	mac_len = tls->rx_cipherspec.digest->digestsize;
-	padding_len = *( ( uint8_t * ) ( plaintext + plaintext_len - 1 ) );
-	if ( plaintext_len < ( iv_len + mac_len + padding_len + 1 ) ) {
-		DBGC ( tls, "TLS %p received underlength record\n", tls );
-		DBGC_HD ( tls, plaintext, plaintext_len );
-		return -EINVAL;
+	iob_pull ( iobuf, iv_len );
+
+	/* Extract and verify padding */
+	iobuf = list_last_entry ( rx_data, struct io_buffer, list );
+	padding_final = ( iobuf->tail - 1 );
+	padding_len = *padding_final;
+	if ( ( padding_len + 1 ) > iob_len ( iobuf ) ) {
+		DBGC ( tls, "TLS %p received underlength padding\n", tls );
+		DBGC_HD ( tls, iobuf->data, iob_len ( iobuf ) );
+		return -EINVAL_BLOCK;
 	}
-	content_len = ( plaintext_len - iv_len - mac_len - padding_len - 1 );
-	iv = plaintext;
-	content = ( iv + iv_len );
-	mac = ( content + content_len );
-	padding = ( mac + mac_len );
-
-	/* Verify padding bytes */
-	for ( i = 0 ; i < padding_len ; i++ ) {
-		if ( *( ( uint8_t * ) ( padding + i ) ) != padding_len ) {
+	iob_unput ( iobuf, ( padding_len + 1 ) );
+	for ( padding = iobuf->tail ; padding < padding_final ; padding++ ) {
+		if ( *padding != padding_len ) {
 			DBGC ( tls, "TLS %p received bad padding\n", tls );
-			DBGC_HD ( tls, plaintext, plaintext_len );
-			return -EINVAL;
+			DBGC_HD ( tls, padding, padding_len );
+			return -EINVAL_PADDING;
 		}
 	}
 
-	/* Fill in return values */
-	*data = content;
-	*len = content_len;
-	*digest = mac;
+	/* Extract MAC */
+	if ( iob_len ( iobuf ) < mac_len ) {
+		DBGC ( tls, "TLS %p received underlength MAC\n", tls );
+		DBGC_HD ( tls, iobuf->data, iob_len ( iobuf ) );
+		return -EINVAL_BLOCK;
+	}
+	iob_unput ( iobuf, mac_len );
+	*mac = iobuf->tail;
 
 	return 0;
 }
@@ -1374,69 +2118,65 @@ static int tls_split_block ( struct tls_session *tls,
  *
  * @v tls		TLS session
  * @v tlshdr		Record header
- * @v ciphertext	Ciphertext record
+ * @v rx_data		List of received data buffers
  * @ret rc		Return status code
  */
 static int tls_new_ciphertext ( struct tls_session *tls,
-				struct tls_header *tlshdr, void *ciphertext ) {
+				struct tls_header *tlshdr,
+				struct list_head *rx_data ) {
 	struct tls_header plaintext_tlshdr;
 	struct tls_cipherspec *cipherspec = &tls->rx_cipherspec;
-	size_t record_len = ntohs ( tlshdr->length );
-	void *plaintext = NULL;
-	void *data;
-	size_t len;
+	struct cipher_algorithm *cipher = cipherspec->suite->cipher;
+	struct digest_algorithm *digest = cipherspec->suite->digest;
+	uint8_t ctx[digest->ctxsize];
+	uint8_t verify_mac[digest->digestsize];
+	struct io_buffer *iobuf;
 	void *mac;
-	size_t mac_len = cipherspec->digest->digestsize;
-	uint8_t verify_mac[mac_len];
+	size_t len = 0;
 	int rc;
 
-	/* Allocate buffer for plaintext */
-	plaintext = malloc ( record_len );
-	if ( ! plaintext ) {
-		DBGC ( tls, "TLS %p could not allocate %zd bytes for "
-		       "decryption buffer\n", tls, record_len );
-		rc = -ENOMEM;
-		goto done;
+	/* Decrypt the received data */
+	list_for_each_entry ( iobuf, &tls->rx_data, list ) {
+		cipher_decrypt ( cipher, cipherspec->cipher_ctx,
+				 iobuf->data, iobuf->data, iob_len ( iobuf ) );
 	}
 
-	/* Decrypt the record */
-	cipher_decrypt ( cipherspec->cipher, cipherspec->cipher_ctx,
-			 ciphertext, plaintext, record_len );
-
 	/* Split record into content and MAC */
-	if ( is_stream_cipher ( cipherspec->cipher ) ) {
-		if ( ( rc = tls_split_stream ( tls, plaintext, record_len,
-					       &data, &len, &mac ) ) != 0 )
-			goto done;
+	if ( is_stream_cipher ( cipher ) ) {
+		if ( ( rc = tls_split_stream ( tls, rx_data, &mac ) ) != 0 )
+			return rc;
 	} else {
-		if ( ( rc = tls_split_block ( tls, plaintext, record_len,
-					      &data, &len, &mac ) ) != 0 )
-			goto done;
+		if ( ( rc = tls_split_block ( tls, rx_data, &mac ) ) != 0 )
+			return rc;
+	}
+
+	/* Calculate total length */
+	DBGC2 ( tls, "Received plaintext data:\n" );
+	list_for_each_entry ( iobuf, rx_data, list ) {
+		DBGC2_HD ( tls, iobuf->data, iob_len ( iobuf ) );
+		len += iob_len ( iobuf );
 	}
 
 	/* Verify MAC */
 	plaintext_tlshdr.type = tlshdr->type;
 	plaintext_tlshdr.version = tlshdr->version;
 	plaintext_tlshdr.length = htons ( len );
-	tls_hmac ( tls, cipherspec, tls->rx_seq, &plaintext_tlshdr,
-		   data, len, verify_mac);
-	if ( memcmp ( mac, verify_mac, mac_len ) != 0 ) {
+	tls_hmac_init ( cipherspec, ctx, tls->rx_seq, &plaintext_tlshdr );
+	list_for_each_entry ( iobuf, rx_data, list ) {
+		tls_hmac_update ( cipherspec, ctx, iobuf->data,
+				  iob_len ( iobuf ) );
+	}
+	tls_hmac_final ( cipherspec, ctx, verify_mac );
+	if ( memcmp ( mac, verify_mac, sizeof ( verify_mac ) ) != 0 ) {
 		DBGC ( tls, "TLS %p failed MAC verification\n", tls );
-		DBGC_HD ( tls, plaintext, record_len );
-		goto done;
+		return -EINVAL_MAC;
 	}
 
-	DBGC2 ( tls, "Received plaintext data:\n" );
-	DBGC2_HD ( tls, data, len );
-
 	/* Process plaintext record */
-	if ( ( rc = tls_new_record ( tls, tlshdr->type, data, len ) ) != 0 )
-		goto done;
+	if ( ( rc = tls_new_record ( tls, tlshdr->type, rx_data ) ) != 0 )
+		return rc;
 
-	rc = 0;
- done:
-	free ( plaintext );
-	return rc;
+	return 0;
 }
 
 /******************************************************************************
@@ -1455,7 +2195,7 @@ static int tls_new_ciphertext ( struct tls_session *tls,
 static size_t tls_plainstream_window ( struct tls_session *tls ) {
 
 	/* Block window unless we are ready to accept data */
-	if ( tls->tx_state != TLS_TX_DATA )
+	if ( ! tls_ready ( tls ) )
 		return 0;
 
 	return xfer_window ( &tls->cipherstream );
@@ -1475,7 +2215,7 @@ static int tls_plainstream_deliver ( struct tls_session *tls,
 	int rc;
 	
 	/* Refuse unless we are ready to accept data */
-	if ( tls->tx_state != TLS_TX_DATA ) {
+	if ( ! tls_ready ( tls ) ) {
 		rc = -ENOTCONN;
 		goto done;
 	}
@@ -1516,20 +2256,61 @@ static struct interface_descriptor tls_plainstream_desc =
  */
 static int tls_newdata_process_header ( struct tls_session *tls ) {
 	size_t data_len = ntohs ( tls->rx_header.length );
+	size_t remaining = data_len;
+	size_t frag_len;
+	struct io_buffer *iobuf;
+	struct io_buffer *tmp;
+	int rc;
+
+	/* Allocate data buffers now that we know the length */
+	assert ( list_empty ( &tls->rx_data ) );
+	while ( remaining ) {
+
+		/* Calculate fragment length.  Ensure that no block is
+		 * smaller than TLS_RX_MIN_BUFSIZE (by increasing the
+		 * allocation length if necessary).
+		 */
+		frag_len = remaining;
+		if ( frag_len > TLS_RX_BUFSIZE )
+			frag_len = TLS_RX_BUFSIZE;
+		remaining -= frag_len;
+		if ( remaining < TLS_RX_MIN_BUFSIZE ) {
+			frag_len += remaining;
+			remaining = 0;
+		}
+
+		/* Allocate buffer */
+		iobuf = alloc_iob_raw ( frag_len, TLS_RX_ALIGN, 0 );
+		if ( ! iobuf ) {
+			DBGC ( tls, "TLS %p could not allocate %zd of %zd "
+			       "bytes for receive buffer\n", tls,
+			       remaining, data_len );
+			rc = -ENOMEM_RX_DATA;
+			goto err;
+		}
 
-	/* Allocate data buffer now that we know the length */
-	assert ( tls->rx_data == NULL );
-	tls->rx_data = malloc ( data_len );
-	if ( ! tls->rx_data ) {
-		DBGC ( tls, "TLS %p could not allocate %zd bytes "
-		       "for receive buffer\n", tls, data_len );
-		return -ENOMEM;
+		/* Ensure tailroom is exactly what we asked for.  This
+		 * will result in unaligned I/O buffers when the
+		 * fragment length is unaligned, which can happen only
+		 * before we switch to using a block cipher.
+		 */
+		iob_reserve ( iobuf, ( iob_tailroom ( iobuf ) - frag_len ) );
+
+		/* Add I/O buffer to list */
+		list_add_tail ( &iobuf->list, &tls->rx_data );
 	}
 
 	/* Move to data state */
 	tls->rx_state = TLS_RX_DATA;
 
 	return 0;
+
+ err:
+	list_for_each_entry_safe ( iobuf, tmp, &tls->rx_data, list ) {
+		list_del ( &iobuf->list );
+		free_iob ( iobuf );
+	}
+	return rc;
 }
 
 /**
@@ -1539,22 +2320,31 @@ static int tls_newdata_process_header ( struct tls_session *tls ) {
  * @ret rc		Returned status code
  */
 static int tls_newdata_process_data ( struct tls_session *tls ) {
+	struct io_buffer *iobuf;
 	int rc;
 
+	/* Move current buffer to end of list */
+	iobuf = list_first_entry ( &tls->rx_data, struct io_buffer, list );
+	list_del ( &iobuf->list );
+	list_add_tail ( &iobuf->list, &tls->rx_data );
+
+	/* Continue receiving data if any space remains */
+	iobuf = list_first_entry ( &tls->rx_data, struct io_buffer, list );
+	if ( iob_tailroom ( iobuf ) )
+		return 0;
+
 	/* Process record */
 	if ( ( rc = tls_new_ciphertext ( tls, &tls->rx_header,
-					 tls->rx_data ) ) != 0 )
+					 &tls->rx_data ) ) != 0 )
 		return rc;
 
 	/* Increment RX sequence number */
 	tls->rx_seq += 1;
 
-	/* Free data buffer */
-	free ( tls->rx_data );
-	tls->rx_data = NULL;
-
 	/* Return to header state */
+	assert ( list_empty ( &tls->rx_data ) );
 	tls->rx_state = TLS_RX_HEADER;
+	iob_unput ( &tls->rx_header_iobuf, sizeof ( tls->rx_header ) );
 
 	return 0;
 }
@@ -1571,45 +2361,43 @@ static int tls_cipherstream_deliver ( struct tls_session *tls,
 				      struct io_buffer *iobuf,
 				      struct xfer_metadata *xfer __unused ) {
 	size_t frag_len;
-	void *buf;
-	size_t buf_len;
 	int ( * process ) ( struct tls_session *tls );
+	struct io_buffer *dest;
 	int rc;
 
 	while ( iob_len ( iobuf ) ) {
+
 		/* Select buffer according to current state */
 		switch ( tls->rx_state ) {
 		case TLS_RX_HEADER:
-			buf = &tls->rx_header;
-			buf_len = sizeof ( tls->rx_header );
+			dest = &tls->rx_header_iobuf;
 			process = tls_newdata_process_header;
 			break;
 		case TLS_RX_DATA:
-			buf = tls->rx_data;
-			buf_len = ntohs ( tls->rx_header.length );
+			dest = list_first_entry ( &tls->rx_data,
+						  struct io_buffer, list );
+			assert ( dest != NULL );
 			process = tls_newdata_process_data;
 			break;
 		default:
 			assert ( 0 );
-			rc = -EINVAL;
+			rc = -EINVAL_RX_STATE;
 			goto done;
 		}
 
 		/* Copy data portion to buffer */
-		frag_len = ( buf_len - tls->rx_rcvd );
-		if ( frag_len > iob_len  ( iobuf ) )
-			frag_len = iob_len ( iobuf );
-		memcpy ( ( buf + tls->rx_rcvd ), iobuf->data, frag_len );
-		tls->rx_rcvd += frag_len;
+		frag_len = iob_len ( iobuf );
+		if ( frag_len > iob_tailroom ( dest ) )
+			frag_len = iob_tailroom ( dest );
+		memcpy ( iob_put ( dest, frag_len ), iobuf->data, frag_len );
 		iob_pull ( iobuf, frag_len );
 
 		/* Process data if buffer is now full */
-		if ( tls->rx_rcvd == buf_len ) {
+		if ( iob_tailroom ( dest ) == 0 ) {
 			if ( ( rc = process ( tls ) ) != 0 ) {
 				tls_close ( tls, rc );
 				goto done;
 			}
-			tls->rx_rcvd = 0;
 		}
 	}
 	rc = 0;
@@ -1623,6 +2411,7 @@ static int tls_cipherstream_deliver ( struct tls_session *tls,
 static struct interface_operation tls_cipherstream_ops[] = {
 	INTF_OP ( xfer_deliver, struct tls_session *,
 		  tls_cipherstream_deliver ),
+	INTF_OP ( xfer_window_changed, struct tls_session *, tls_tx_resume ),
 	INTF_OP ( intf_close, struct tls_session *, tls_close ),
 };
 
@@ -1631,6 +2420,79 @@ static struct interface_descriptor tls_cipherstream_desc =
 	INTF_DESC_PASSTHRU ( struct tls_session, cipherstream,
 			     tls_cipherstream_ops, plainstream );
 
+/******************************************************************************
+ *
+ * Certificate validator
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Handle certificate validation completion
+ *
+ * @v tls		TLS session
+ * @v rc		Reason for completion
+ */
+static void tls_validator_done ( struct tls_session *tls, int rc ) {
+	struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
+	struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
+	struct x509_certificate *cert;
+
+	/* Close validator interface */
+	intf_restart ( &tls->validator, rc );
+
+	/* Check for validation failure */
+	if ( rc != 0 ) {
+		DBGC ( tls, "TLS %p certificate validation failed: %s\n",
+		       tls, strerror ( rc ) );
+		goto err;
+	}
+	DBGC ( tls, "TLS %p certificate validation succeeded\n", tls );
+
+	/* Extract first certificate */
+	cert = x509_first ( tls->chain );
+	assert ( cert != NULL );
+
+	/* Verify server name */
+	if ( ( cert->subject.name == NULL ) ||
+	     ( strcmp ( cert->subject.name, tls->name ) != 0 ) ) {
+		DBGC ( tls, "TLS %p server name incorrect (expected %s, got "
+		       "%s)\n", tls, tls->name, cert->subject.name );
+		rc = -EACCES_WRONG_NAME;
+		goto err;
+	}
+
+	/* Initialise public key algorithm */
+	if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx,
+				  cert->subject.public_key.raw.data,
+				  cert->subject.public_key.raw.len ) ) != 0 ) {
+		DBGC ( tls, "TLS %p cannot initialise public key: %s\n",
+		       tls, strerror ( rc ) );
+		goto err;
+	}
+
+	/* Schedule Client Key Exchange, Change Cipher, and Finished */
+	tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE |
+			     TLS_TX_CHANGE_CIPHER |
+			     TLS_TX_FINISHED );
+	tls_tx_resume ( tls );
+
+	return;
+
+ err:
+	tls_close ( tls, rc );
+	return;
+}
+
+/** TLS certificate validator interface operations */
+static struct interface_operation tls_validator_ops[] = {
+	INTF_OP ( intf_close, struct tls_session *, tls_validator_done ),
+};
+
+/** TLS certificate validator interface descriptor */
+static struct interface_descriptor tls_validator_desc =
+	INTF_DESC ( struct tls_session, validator, tls_validator_ops );
+
 /******************************************************************************
  *
  * Controlling process
@@ -1641,40 +2503,49 @@ static struct interface_descriptor tls_cipherstream_desc =
 /**
  * TLS TX state machine
  *
- * @v process		TLS process
+ * @v tls		TLS session
  */
-static void tls_step ( struct process *process ) {
-	struct tls_session *tls =
-		container_of ( process, struct tls_session, process );
+static void tls_tx_step ( struct tls_session *tls ) {
 	int rc;
 
 	/* Wait for cipherstream to become ready */
 	if ( ! xfer_window ( &tls->cipherstream ) )
 		return;
 
-	switch ( tls->tx_state ) {
-	case TLS_TX_NONE:
-		/* Nothing to do */
-		break;
-	case TLS_TX_CLIENT_HELLO:
+	/* Send first pending transmission */
+	if ( tls->tx_pending & TLS_TX_CLIENT_HELLO ) {
 		/* Send Client Hello */
 		if ( ( rc = tls_send_client_hello ( tls ) ) != 0 ) {
 			DBGC ( tls, "TLS %p could not send Client Hello: %s\n",
 			       tls, strerror ( rc ) );
 			goto err;
 		}
-		tls->tx_state = TLS_TX_NONE;
-		break;
-	case TLS_TX_CLIENT_KEY_EXCHANGE:
+		tls->tx_pending &= ~TLS_TX_CLIENT_HELLO;
+	} else if ( tls->tx_pending & TLS_TX_CERTIFICATE ) {
+		/* Send Certificate */
+		if ( ( rc = tls_send_certificate ( tls ) ) != 0 ) {
+			DBGC ( tls, "TLS %p cold not send Certificate: %s\n",
+			       tls, strerror ( rc ) );
+			goto err;
+		}
+		tls->tx_pending &= ~TLS_TX_CERTIFICATE;
+	} else if ( tls->tx_pending & TLS_TX_CLIENT_KEY_EXCHANGE ) {
 		/* Send Client Key Exchange */
 		if ( ( rc = tls_send_client_key_exchange ( tls ) ) != 0 ) {
-			DBGC ( tls, "TLS %p could send Client Key Exchange: "
-			       "%s\n", tls, strerror ( rc ) );
+			DBGC ( tls, "TLS %p could not send Client Key "
+			       "Exchange: %s\n", tls, strerror ( rc ) );
 			goto err;
 		}
-		tls->tx_state = TLS_TX_CHANGE_CIPHER;
-		break;
-	case TLS_TX_CHANGE_CIPHER:
+		tls->tx_pending &= ~TLS_TX_CLIENT_KEY_EXCHANGE;
+	} else if ( tls->tx_pending & TLS_TX_CERTIFICATE_VERIFY ) {
+		/* Send Certificate Verify */
+		if ( ( rc = tls_send_certificate_verify ( tls ) ) != 0 ) {
+			DBGC ( tls, "TLS %p could not send Certificate "
+			       "Verify: %s\n", tls, strerror ( rc ) );
+			goto err;
+		}
+		tls->tx_pending &= ~TLS_TX_CERTIFICATE_VERIFY;
+	} else if ( tls->tx_pending & TLS_TX_CHANGE_CIPHER ) {
 		/* Send Change Cipher, and then change the cipher in use */
 		if ( ( rc = tls_send_change_cipher ( tls ) ) != 0 ) {
 			DBGC ( tls, "TLS %p could not send Change Cipher: "
@@ -1689,30 +2560,31 @@ static void tls_step ( struct process *process ) {
 			goto err;
 		}
 		tls->tx_seq = 0;
-		tls->tx_state = TLS_TX_FINISHED;
-		break;
-	case TLS_TX_FINISHED:
+		tls->tx_pending &= ~TLS_TX_CHANGE_CIPHER;
+	} else if ( tls->tx_pending & TLS_TX_FINISHED ) {
 		/* Send Finished */
 		if ( ( rc = tls_send_finished ( tls ) ) != 0 ) {
 			DBGC ( tls, "TLS %p could not send Finished: %s\n",
 			       tls, strerror ( rc ) );
 			goto err;
 		}
-		tls->tx_state = TLS_TX_NONE;
-		break;
-	case TLS_TX_DATA:
-		/* Nothing to do */
-		break;
-	default:
-		assert ( 0 );
+		tls->tx_pending &= ~TLS_TX_FINISHED;
 	}
 
+	/* Reschedule process if pending transmissions remain */
+	if ( tls->tx_pending )
+		tls_tx_resume ( tls );
+
 	return;
 
  err:
 	tls_close ( tls, rc );
 }
 
+/** TLS TX process descriptor */
+static struct process_descriptor tls_process_desc =
+	PROC_DESC_ONCE ( struct tls_session, process, tls_tx_step );
+
 /******************************************************************************
  *
  * Instantiator
@@ -1720,35 +2592,60 @@ static void tls_step ( struct process *process ) {
  ******************************************************************************
  */
 
-int add_tls ( struct interface *xfer, struct interface **next ) {
+int add_tls ( struct interface *xfer, const char *name,
+	      struct interface **next ) {
 	struct tls_session *tls;
+	int rc;
 
 	/* Allocate and initialise TLS structure */
 	tls = malloc ( sizeof ( *tls ) );
-	if ( ! tls )
-		return -ENOMEM;
+	if ( ! tls ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
 	memset ( tls, 0, sizeof ( *tls ) );
 	ref_init ( &tls->refcnt, free_tls );
+	tls->name = name;
 	intf_init ( &tls->plainstream, &tls_plainstream_desc, &tls->refcnt );
 	intf_init ( &tls->cipherstream, &tls_cipherstream_desc, &tls->refcnt );
+	intf_init ( &tls->validator, &tls_validator_desc, &tls->refcnt );
+	process_init ( &tls->process, &tls_process_desc, &tls->refcnt );
+	tls->version = TLS_VERSION_TLS_1_2;
 	tls_clear_cipher ( tls, &tls->tx_cipherspec );
 	tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
 	tls_clear_cipher ( tls, &tls->rx_cipherspec );
 	tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
-	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;
-	process_init ( &tls->process, tls_step, &tls->refcnt );
+	tls->client_random.gmt_unix_time = time ( NULL );
+	if ( ( rc = tls_generate_random ( tls, &tls->client_random.random,
+			  ( sizeof ( tls->client_random.random ) ) ) ) != 0 ) {
+		goto err_random;
+	}
+	tls->pre_master_secret.version = htons ( tls->version );
+	if ( ( rc = tls_generate_random ( tls, &tls->pre_master_secret.random,
+		      ( sizeof ( tls->pre_master_secret.random ) ) ) ) != 0 ) {
+		goto err_random;
+	}
+	digest_init ( &md5_sha1_algorithm, tls->handshake_md5_sha1_ctx );
+	digest_init ( &sha256_algorithm, tls->handshake_sha256_ctx );
+	tls->handshake_digest = &sha256_algorithm;
+	tls->handshake_ctx = tls->handshake_sha256_ctx;
+	tls->tx_pending = TLS_TX_CLIENT_HELLO;
+	iob_populate ( &tls->rx_header_iobuf, &tls->rx_header, 0,
+		       sizeof ( tls->rx_header ) );
+	INIT_LIST_HEAD ( &tls->rx_data );
+
+	/* Add pending operations for server and client Finished messages */
+	pending_get ( &tls->client_negotiation );
+	pending_get ( &tls->server_negotiation );
 
 	/* Attach to parent interface, mortalise self, and return */
 	intf_plug_plug ( &tls->plainstream, xfer );
 	*next = &tls->cipherstream;
 	ref_put ( &tls->refcnt );
 	return 0;
+
+ err_random:
+	ref_put ( &tls->refcnt );
+ err_alloc:
+	return rc;
 }
diff --git a/roms/ipxe/src/net/udp.c b/roms/ipxe/src/net/udp.c
index 5f452535ce43fdc207c4a5c02456..20badb7f0fcf3f4845ab18e92389 100644
--- a/roms/ipxe/src/net/udp.c
+++ b/roms/ipxe/src/net/udp.c
@@ -386,10 +386,9 @@ static int udp_xfer_deliver ( struct udp_connection *udp,
 			      struct xfer_metadata *meta ) {
 
 	/* Transmit data, if possible */
-	udp_tx ( udp, iobuf, ( ( struct sockaddr_tcpip * ) meta->src ),
-		 ( ( struct sockaddr_tcpip * ) meta->dest ), meta->netdev );
-
-	return 0;
+	return udp_tx ( udp, iobuf, ( ( struct sockaddr_tcpip * ) meta->src ),
+			( ( struct sockaddr_tcpip * ) meta->dest ),
+			meta->netdev );
 }
 
 /** UDP data transfer interface operations */
diff --git a/roms/ipxe/src/net/udp/dhcp.c b/roms/ipxe/src/net/udp/dhcp.c
index a0b74dfe5647804cd495cd709ad7..762ae732aa3a1992e6a106bb758c 100644
--- a/roms/ipxe/src/net/udp/dhcp.c
+++ b/roms/ipxe/src/net/udp/dhcp.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -85,13 +86,11 @@ static uint8_t dhcp_request_options_data[] = {
 		      DHCP_LOG_SERVERS, DHCP_HOST_NAME, DHCP_DOMAIN_NAME,
 		      DHCP_ROOT_PATH, DHCP_VENDOR_ENCAP, DHCP_VENDOR_CLASS_ID,
 		      DHCP_TFTP_SERVER_NAME, DHCP_BOOTFILE_NAME,
+		      128, 129, 130, 131, 132, 133, 134, 135, /* for PXE */
 		      DHCP_EB_ENCAP, DHCP_ISCSI_INITIATOR_IQN ),
 	DHCP_END
 };
 
-/** Version number feature */
-FEATURE_VERSION ( VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH );
-
 /** DHCP server address setting */
 struct setting dhcp_server_setting __setting ( SETTING_MISC ) = {
 	.name = "dhcp-server",
@@ -116,6 +115,14 @@ struct setting use_cached_setting __setting ( SETTING_MISC ) = {
 	.type = &setting_type_uint8,
 };
 
+/**
+ * Most recent DHCP transaction ID
+ *
+ * This is exposed for use by the fakedhcp code when reconstructing
+ * DHCP packets for PXE NBPs.
+ */
+uint32_t dhcp_last_xid;
+
 /**
  * Name a DHCP packet type
  *
@@ -137,23 +144,6 @@ static inline const char * dhcp_msgtype_name ( unsigned int msgtype ) {
 	}
 }
 
-/**
- * Calculate DHCP transaction ID for a network device
- *
- * @v netdev		Network device
- * @ret xid		DHCP XID
- *
- * Extract the least significant bits of the hardware address for use
- * as the transaction ID.
- */
-static uint32_t dhcp_xid ( struct net_device *netdev ) {
-	uint32_t xid;
-
-	memcpy ( &xid, ( netdev->ll_addr + netdev->ll_protocol->ll_addr_len
-			 - sizeof ( xid ) ), sizeof ( xid ) );
-	return xid;
-}
-
 /****************************************************************************
  *
  * DHCP session
@@ -219,6 +209,8 @@ struct dhcp_session {
 	struct sockaddr_in local;
 	/** State of the session */
 	struct dhcp_session_state *state;
+	/** Transaction ID (in network-endian order) */
+	uint32_t xid;
 
 	/** Offered IP address */
 	struct in_addr offer;
@@ -916,6 +908,7 @@ unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
  * @v dhcppkt		DHCP packet structure to fill in
  * @v netdev		Network device
  * @v msgtype		DHCP message type
+ * @v xid		Transaction ID (in network-endian order)
  * @v options		Initial options to include (or NULL)
  * @v options_len	Length of initial options
  * @v data		Buffer for DHCP packet
@@ -927,7 +920,7 @@ unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
  */
 int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
 			 struct net_device *netdev, uint8_t msgtype,
-			 const void *options, size_t options_len,
+			 uint32_t xid, const void *options, size_t options_len,
 			 void *data, size_t max_len ) {
 	struct dhcphdr *dhcphdr = data;
 	int rc;
@@ -938,14 +931,29 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
 
 	/* Initialise DHCP packet content */
 	memset ( dhcphdr, 0, max_len );
-	dhcphdr->xid = dhcp_xid ( netdev );
+	dhcphdr->xid = xid;
 	dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
 	dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
 	dhcphdr->op = dhcp_op[msgtype];
-	dhcphdr->hlen = dhcp_chaddr ( netdev, dhcphdr->chaddr,
-				      &dhcphdr->flags );
+	dhcphdr->hlen = netdev->ll_protocol->ll_addr_len;
+	memcpy ( dhcphdr->chaddr, netdev->ll_addr,
+		 netdev->ll_protocol->ll_addr_len );
 	memcpy ( dhcphdr->options, options, options_len );
 
+	/* If the local link-layer address functions only as a name
+	 * (i.e. cannot be used as a destination address), then
+	 * request broadcast responses.
+	 */
+	if ( netdev->ll_protocol->flags & LL_NAME_ONLY )
+		dhcphdr->flags |= htons ( BOOTP_FL_BROADCAST );
+
+	/* If the network device already has an IPv4 address then
+	 * unicast responses from the DHCP server may be rejected, so
+	 * request broadcast responses.
+	 */
+	if ( ipv4_has_any_addr ( netdev ) )
+		dhcphdr->flags |= htons ( BOOTP_FL_BROADCAST );
+
 	/* Initialise DHCP packet structure */
 	memset ( dhcppkt, 0, sizeof ( *dhcppkt ) );
 	dhcppkt_init ( dhcppkt, data, max_len );
@@ -964,6 +972,7 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
  * @v dhcppkt		DHCP packet structure to fill in
  * @v netdev		Network device
  * @v msgtype		DHCP message type
+ * @v xid		Transaction ID (in network-endian order)
  * @v ciaddr		Client IP address
  * @v data		Buffer for DHCP packet
  * @v max_len		Size of DHCP packet buffer
@@ -974,7 +983,8 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
  */
 int dhcp_create_request ( struct dhcp_packet *dhcppkt,
 			  struct net_device *netdev, unsigned int msgtype,
-			  struct in_addr ciaddr, void *data, size_t max_len ) {
+			  uint32_t xid, struct in_addr ciaddr,
+			  void *data, size_t max_len ) {
 	struct dhcp_netdev_desc dhcp_desc;
 	struct dhcp_client_id client_id;
 	struct dhcp_client_uuid client_uuid;
@@ -985,7 +995,7 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt,
 	int rc;
 
 	/* Create DHCP packet */
-	if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype,
+	if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype, xid,
 					 dhcp_request_options_data,
 					 sizeof ( dhcp_request_options_data ),
 					 data, max_len ) ) != 0 ) {
@@ -1031,10 +1041,15 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt,
 		return rc;
 	}
 
-	/* Add client UUID, if we have one.  Required for PXE. */
+	/* Add client UUID, if we have one.  Required for PXE.  The
+	 * PXE spec does not specify a byte ordering for UUIDs, but
+	 * RFC4578 suggests that it follows the EFI spec, in which the
+	 * first three fields are little-endian.
+	 */
 	client_uuid.type = DHCP_CLIENT_UUID_TYPE;
 	if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting,
 					  &client_uuid.uuid ) ) >= 0 ) {
+		uuid_mangle ( &client_uuid.uuid );
 		if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_UUID,
 					    &client_uuid,
 					    sizeof ( client_uuid ) ) ) != 0 ) {
@@ -1099,7 +1114,8 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
 
 	/* Create basic DHCP packet in temporary buffer */
 	if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev, msgtype,
-					  dhcp->local.sin_addr, iobuf->data,
+					  dhcp->xid, dhcp->local.sin_addr,
+					  iobuf->data,
 					  iob_tailroom ( iobuf ) ) ) != 0 ) {
 		DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n",
 		       dhcp, strerror ( rc ) );
@@ -1187,7 +1203,7 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
 			&server_id, sizeof ( server_id ) );
 
 	/* Check for matching transaction ID */
-	if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
+	if ( dhcphdr->xid != dhcp->xid ) {
 		DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
 		       "ID\n", dhcp, dhcp_msgtype_name ( msgtype ),
 		       inet_ntoa ( peer->sin_addr ),
@@ -1311,6 +1327,10 @@ int start_dhcp ( struct interface *job, struct net_device *netdev ) {
 	dhcp->netdev = netdev_get ( netdev );
 	dhcp->local.sin_family = AF_INET;
 	dhcp->local.sin_port = htons ( BOOTPC_PORT );
+	dhcp->xid = random();
+
+	/* Store DHCP transaction ID for fakedhcp code */
+	dhcp_last_xid = dhcp->xid;
 
 	/* Instantiate child objects and attach to our interfaces */
 	if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
diff --git a/roms/ipxe/src/net/udp/dns.c b/roms/ipxe/src/net/udp/dns.c
index d1435e769a966edf78297d936004..613541f5a11c735deeb37a3844e4 100644
--- a/roms/ipxe/src/net/udp/dns.c
+++ b/roms/ipxe/src/net/udp/dns.c
@@ -16,7 +16,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -222,18 +223,24 @@ static char * dns_qualify_name ( const char *string ) {
  * DNS names consist of "<length>element" pairs.
  */
 static char * dns_make_name ( const char *string, char *buf ) {
-	char *length_byte = buf++;
+	char *length_byte;
 	char c;
 
-	while ( ( c = *(string++) ) ) {
-		if ( c == '.' ) {
-			*length_byte = buf - length_byte - 1;
-			length_byte = buf;
+	length_byte = buf++;
+	*length_byte = 0;
+	do {
+		c = *(string++);
+		if ( ( c == '.' ) || ( c == '\0' ) ) {
+			if ( *length_byte ) {
+				length_byte = buf++;
+				*length_byte = 0;
+			}
+		} else {
+			*(buf++) = c;
+			(*length_byte)++;
 		}
-		*(buf++) = c;
-	}
-	*length_byte = buf - length_byte - 1;
-	*(buf++) = '\0';
+	} while ( c );
+
 	return buf;
 }
 
@@ -421,7 +428,7 @@ static int dns_xfer_deliver ( struct dns_request *dns,
 	}
 	
 	/* Determine what to do next based on the type of query we
-	 * issued and the reponse we received
+	 * issued and the response we received
 	 */
 	switch ( qtype ) {
 
@@ -594,14 +601,6 @@ struct setting dns_setting __setting ( SETTING_IPv4_EXTRA ) = {
 	.type = &setting_type_ipv4,
 };
 
-/** Domain name setting */
-struct setting domain_setting __setting ( SETTING_IPv4_EXTRA ) = {
-	.name = "domain",
-	.description = "DNS domain",
-	.tag = DHCP_DOMAIN_NAME,
-	.type = &setting_type_string,
-};
-
 /**
  * Apply DNS settings
  *
diff --git a/roms/ipxe/src/net/udp/slam.c b/roms/ipxe/src/net/udp/slam.c
index 0de138cdfba538de9cb90fbc6f97..e1b584fec75247242a9f3f59b60c 100644
--- a/roms/ipxe/src/net/udp/slam.c
+++ b/roms/ipxe/src/net/udp/slam.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/net/udp/syslog.c b/roms/ipxe/src/net/udp/syslog.c
index 6d9fc2165bc09c6986ae488b0a36..00101008bcffd6b2ad95cb49041d 100644
--- a/roms/ipxe/src/net/udp/syslog.c
+++ b/roms/ipxe/src/net/udp/syslog.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -25,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
  */
 
 #include <stdint.h>
+#include <stdlib.h>
 #include <byteswap.h>
 #include <ipxe/xfer.h>
 #include <ipxe/open.h>
@@ -32,11 +34,19 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/dhcp.h>
 #include <ipxe/settings.h>
 #include <ipxe/console.h>
-#include <ipxe/ansiesc.h>
+#include <ipxe/lineconsole.h>
 #include <ipxe/syslog.h>
+#include <config/console.h>
+
+/* Set default console usage if applicable */
+#if ! ( defined ( CONSOLE_SYSLOG ) && CONSOLE_EXPLICIT ( CONSOLE_SYSLOG ) )
+#undef CONSOLE_SYSLOG
+#define CONSOLE_SYSLOG ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_TUI )
+#endif
 
 /** The syslog server */
 static struct sockaddr_tcpip logserver = {
+	.st_family = AF_INET,
 	.st_port = htons ( SYSLOG_PORT ),
 };
 
@@ -50,6 +60,41 @@ static struct interface_descriptor syslogger_desc =
 /** The syslog UDP interface */
 static struct interface syslogger = INTF_INIT ( syslogger_desc );
 
+/******************************************************************************
+ *
+ * Console driver
+ *
+ ******************************************************************************
+ */
+
+/** Host name (for log messages) */
+static char *syslog_hostname;
+
+/** Domain name (for log messages) */
+static char *syslog_domain;
+
+/**
+ * Transmit formatted syslog message
+ *
+ * @v xfer		Data transfer interface
+ * @v severity		Severity
+ * @v message		Message
+ * @v terminator	Message terminator
+ * @ret rc		Return status code
+ */
+int syslog_send ( struct interface *xfer, unsigned int severity,
+		  const char *message, const char *terminator ) {
+
+	return xfer_printf ( xfer, "<%d>%s%s%s%sipxe: %s%s",
+			     SYSLOG_PRIORITY ( SYSLOG_DEFAULT_FACILITY,
+					       severity ),
+			     ( syslog_hostname ? syslog_hostname : "" ),
+			     ( syslog_domain ? "." : "" ),
+			     ( syslog_domain ? syslog_domain : "" ),
+			     ( ( syslog_hostname || syslog_domain ) ? " " : ""),
+			     message, terminator );
+}
+
 /******************************************************************************
  *
  * Console driver
@@ -60,22 +105,42 @@ static struct interface syslogger = INTF_INIT ( syslogger_desc );
 /** Syslog line buffer */
 static char syslog_buffer[SYSLOG_BUFSIZE];
 
-/** Index into syslog line buffer */
-static unsigned int syslog_idx;
+/** Syslog severity */
+static unsigned int syslog_severity = SYSLOG_DEFAULT_SEVERITY;
 
-/** Syslog recursion marker */
-static int syslog_entered;
+/**
+ * Handle ANSI set syslog priority (private sequence)
+ *
+ * @v count		Parameter count
+ * @v params		List of graphic rendition aspects
+ */
+static void syslog_handle_priority ( unsigned int count __unused,
+				     int params[] ) {
+	if ( params[0] >= 0 ) {
+		syslog_severity = params[0];
+	} else {
+		syslog_severity = SYSLOG_DEFAULT_SEVERITY;
+	}
+}
 
 /** Syslog ANSI escape sequence handlers */
-static struct ansiesc_handler syslog_ansiesc_handlers[] = {
+static struct ansiesc_handler syslog_handlers[] = {
+	{ ANSIESC_LOG_PRIORITY, syslog_handle_priority },
 	{ 0, NULL }
 };
 
-/** Syslog ANSI escape sequence context */
-static struct ansiesc_context syslog_ansiesc_ctx = {
-	.handlers = syslog_ansiesc_handlers,
+/** Syslog line console */
+static struct line_console syslog_line = {
+	.buffer = syslog_buffer,
+	.len = sizeof ( syslog_buffer ),
+	.ctx = {
+		.handlers = syslog_handlers,
+	},
 };
 
+/** Syslog recursion marker */
+static int syslog_entered;
+
 /**
  * Print a character to syslog console
  *
@@ -84,47 +149,20 @@ static struct ansiesc_context syslog_ansiesc_ctx = {
 static void syslog_putchar ( int character ) {
 	int rc;
 
-	/* Do nothing if we have no log server */
-	if ( ! logserver.st_family )
-		return;
-
 	/* Ignore if we are already mid-logging */
 	if ( syslog_entered )
 		return;
 
-	/* Strip ANSI escape sequences */
-	character = ansiesc_process ( &syslog_ansiesc_ctx, character );
-	if ( character < 0 )
-		return;
-
-	/* Ignore carriage return */
-	if ( character == '\r' )
+	/* Fill line buffer */
+	if ( line_putchar ( &syslog_line, character ) == 0 )
 		return;
 
-	/* Treat newline as a terminator */
-	if ( character == '\n' )
-		character = 0;
-
-	/* Add character to buffer */
-	syslog_buffer[syslog_idx++] = character;
-
-	/* Do nothing more unless we reach end-of-line (or end-of-buffer) */
-	if ( ( character != 0 ) &&
-	     ( syslog_idx < ( sizeof ( syslog_buffer ) - 1 /* NUL */ ) ) ) {
-		return;
-	}
-
-	/* Reset to start of buffer */
-	syslog_idx = 0;
-
 	/* Guard against re-entry */
 	syslog_entered = 1;
 
 	/* Send log message */
-	if ( ( rc = xfer_printf ( &syslogger, "<%d>ipxe: %s",
-				  SYSLOG_PRIORITY ( SYSLOG_FACILITY,
-						    SYSLOG_SEVERITY ),
-				  syslog_buffer ) ) != 0 ) {
+	if ( ( rc = syslog_send ( &syslogger, syslog_severity,
+				  syslog_buffer, "" ) ) != 0 ) {
 		DBG ( "SYSLOG could not send log message: %s\n",
 		      strerror ( rc ) );
 	}
@@ -136,6 +174,8 @@ static void syslog_putchar ( int character ) {
 /** Syslog console driver */
 struct console_driver syslog_console __console_driver = {
 	.putchar = syslog_putchar,
+	.disabled = 1,
+	.usage = CONSOLE_SYSLOG,
 };
 
 /******************************************************************************
@@ -165,12 +205,26 @@ static int apply_syslog_settings ( void ) {
 	int len;
 	int rc;
 
+	/* Fetch hostname and domain name */
+	free ( syslog_hostname );
+	if ( ( len = fetch_string_setting_copy ( NULL, &hostname_setting,
+						 &syslog_hostname ) ) < 0 ) {
+		rc = len;
+		DBG ( "SYSLOG could not fetch hostname: %s\n", strerror ( rc ));
+	}
+	free ( syslog_domain );
+	if ( ( len = fetch_string_setting_copy ( NULL, &domain_setting,
+						 &syslog_domain ) ) < 0 ) {
+		rc = len;
+		DBG ( "SYSLOG could not fetch domain: %s\n", strerror ( rc ) );
+	}
+
 	/* Fetch log server */
+	syslog_console.disabled = 1;
 	old_addr.s_addr = sin_logserver->sin_addr.s_addr;
-	logserver.st_family = 0;
 	if ( ( len = fetch_ipv4_setting ( NULL, &syslog_setting,
 					  &sin_logserver->sin_addr ) ) >= 0 ) {
-		sin_logserver->sin_family = AF_INET;
+		syslog_console.disabled = 0;
 	}
 
 	/* Do nothing unless log server has changed */
@@ -181,7 +235,7 @@ static int apply_syslog_settings ( void ) {
 	intf_restart ( &syslogger, 0 );
 
 	/* Do nothing unless we have a log server */
-	if ( ! logserver.st_family ) {
+	if ( syslog_console.disabled ) {
 		DBG ( "SYSLOG has no log server\n" );
 		return 0;
 	}
diff --git a/roms/ipxe/src/net/udp/tftp.c b/roms/ipxe/src/net/udp/tftp.c
index 7cd211e41ab8de61df667450078f..d686aac9adbc81afa02975768caf 100644
--- a/roms/ipxe/src/net/udp/tftp.c
+++ b/roms/ipxe/src/net/udp/tftp.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -286,24 +287,6 @@ static int tftp_presize ( struct tftp_request *tftp, size_t filesize ) {
 	return 0;
 }
 
-/**
- * TFTP requested blocksize
- *
- * This is treated as a global configuration parameter.
- */
-static unsigned int tftp_request_blksize = TFTP_MAX_BLKSIZE;
-
-/**
- * Set TFTP request blocksize
- *
- * @v blksize		Requested block size
- */
-void tftp_set_request_blksize ( unsigned int blksize ) {
-	if ( blksize < TFTP_DEFAULT_BLKSIZE )
-		blksize = TFTP_DEFAULT_BLKSIZE;
-	tftp_request_blksize = blksize;
-}
-
 /**
  * MTFTP multicast receive address
  *
@@ -344,6 +327,7 @@ static int tftp_send_rrq ( struct tftp_request *tftp ) {
 	const char *path;
 	size_t len;
 	struct io_buffer *iobuf;
+	size_t blksize;
 
 	/* Strip initial '/' if present.  If we were opened via the
 	 * URI interface, then there will be an initial '/', since a
@@ -369,6 +353,11 @@ static int tftp_send_rrq ( struct tftp_request *tftp ) {
 	if ( ! iobuf )
 		return -ENOMEM;
 
+	/* Determine block size */
+	blksize = xfer_window ( &tftp->xfer );
+	if ( blksize > TFTP_MAX_BLKSIZE )
+		blksize = TFTP_MAX_BLKSIZE;
+
 	/* Build request */
 	rrq = iob_put ( iobuf, sizeof ( *rrq ) );
 	rrq->opcode = htons ( TFTP_RRQ );
@@ -377,8 +366,8 @@ static int tftp_send_rrq ( struct tftp_request *tftp ) {
 	if ( tftp->flags & TFTP_FL_RRQ_SIZES ) {
 		iob_put ( iobuf, snprintf ( iobuf->tail,
 					    iob_tailroom ( iobuf ),
-					    "blksize%c%d%ctsize%c0", 0,
-					    tftp_request_blksize, 0, 0 ) + 1 );
+					    "blksize%c%zd%ctsize%c0",
+					    0, blksize, 0, 0 ) + 1 );
 	}
 	if ( tftp->flags & TFTP_FL_RRQ_MULTICAST ) {
 		iob_put ( iobuf, snprintf ( iobuf->tail,
@@ -1214,14 +1203,6 @@ struct uri_opener mtftp_uri_opener __uri_opener = {
  ******************************************************************************
  */
 
-/** TFTP server setting */
-struct setting next_server_setting __setting ( SETTING_BOOT ) = {
-	.name = "next-server",
-	.description = "TFTP server",
-	.tag = DHCP_EB_SIADDR,
-	.type = &setting_type_ipv4,
-};
-
 /**
  * Apply TFTP configuration settings
  *
diff --git a/roms/ipxe/src/net/validator.c b/roms/ipxe/src/net/validator.c
new file mode 100644
index 0000000000000000000000000000000000000000..d61cb92f47f8cb8900adf10fbe392f8d392177b6
--- /dev/null
+++ b/roms/ipxe/src/net/validator.c
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ipxe/refcnt.h>
+#include <ipxe/malloc.h>
+#include <ipxe/interface.h>
+#include <ipxe/xfer.h>
+#include <ipxe/open.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/xferbuf.h>
+#include <ipxe/process.h>
+#include <ipxe/x509.h>
+#include <ipxe/settings.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/base64.h>
+#include <ipxe/crc32.h>
+#include <ipxe/ocsp.h>
+#include <ipxe/validator.h>
+
+/** @file
+ *
+ * Certificate validator
+ *
+ */
+
+/** A certificate validator */
+struct validator {
+	/** Reference count */
+	struct refcnt refcnt;
+	/** Job control interface */
+	struct interface job;
+	/** Data transfer interface */
+	struct interface xfer;
+
+	/** Process */
+	struct process process;
+
+	/** X.509 certificate chain */
+	struct x509_chain *chain;
+	/** OCSP check */
+	struct ocsp_check *ocsp;
+	/** Data buffer */
+	struct xfer_buffer buffer;
+	/** Action to take upon completed transfer */
+	int ( * done ) ( struct validator *validator, const void *data,
+			 size_t len );
+};
+
+/**
+ * Free certificate validator
+ *
+ * @v refcnt		Reference count
+ */
+static void validator_free ( struct refcnt *refcnt ) {
+	struct validator *validator =
+		container_of ( refcnt, struct validator, refcnt );
+
+	DBGC2 ( validator, "VALIDATOR %p freed\n", validator );
+	x509_chain_put ( validator->chain );
+	ocsp_put ( validator->ocsp );
+	xferbuf_done ( &validator->buffer );
+	free ( validator );
+}
+
+/**
+ * Mark certificate validation as finished
+ *
+ * @v validator		Certificate validator
+ * @v rc		Reason for finishing
+ */
+static void validator_finished ( struct validator *validator, int rc ) {
+
+	/* Remove process */
+	process_del ( &validator->process );
+
+	/* Close all interfaces */
+	intf_shutdown ( &validator->xfer, rc );
+	intf_shutdown ( &validator->job, rc );
+}
+
+/****************************************************************************
+ *
+ * Job control interface
+ *
+ */
+
+/** Certificate validator job control interface operations */
+static struct interface_operation validator_job_operations[] = {
+	INTF_OP ( intf_close, struct validator *, validator_finished ),
+};
+
+/** Certificate validator job control interface descriptor */
+static struct interface_descriptor validator_job_desc =
+	INTF_DESC ( struct validator, job, validator_job_operations );
+
+/****************************************************************************
+ *
+ * Cross-signing certificates
+ *
+ */
+
+/** Cross-signed certificate source setting */
+struct setting crosscert_setting __setting ( SETTING_CRYPTO ) = {
+	.name = "crosscert",
+	.description = "Cross-signed certificate source",
+	.tag = DHCP_EB_CROSS_CERT,
+	.type = &setting_type_string,
+};
+
+/** Default cross-signed certificate source */
+static const char crosscert_default[] = "http://ca.ipxe.org/auto";
+
+/**
+ * Append cross-signing certificates to certificate chain
+ *
+ * @v validator		Certificate validator
+ * @v data		Raw cross-signing certificate data
+ * @v len		Length of raw data
+ * @ret rc		Return status code
+ */
+static int validator_append ( struct validator *validator,
+			      const void *data, size_t len ) {
+	struct asn1_cursor cursor;
+	struct x509_chain *certs;
+	struct x509_certificate *cert;
+	struct x509_certificate *last;
+	int rc;
+
+	/* Allocate certificate list */
+	certs = x509_alloc_chain();
+	if ( ! certs ) {
+		rc = -ENOMEM;
+		goto err_alloc_certs;
+	}
+
+	/* Initialise cursor */
+	cursor.data = data;
+	cursor.len = len;
+
+	/* Enter certificateSet */
+	if ( ( rc = asn1_enter ( &cursor, ASN1_SET ) ) != 0 ) {
+		DBGC ( validator, "VALIDATOR %p could not enter "
+		       "certificateSet: %s\n", validator, strerror ( rc ) );
+		goto err_certificateset;
+	}
+
+	/* Add each certificate to list */
+	while ( cursor.len ) {
+
+		/* Add certificate to chain */
+		if ( ( rc = x509_append_raw ( certs, cursor.data,
+					      cursor.len ) ) != 0 ) {
+			DBGC ( validator, "VALIDATOR %p could not append "
+			       "certificate: %s\n",
+			       validator, strerror ( rc) );
+			DBGC_HDA ( validator, 0, cursor.data, cursor.len );
+			return rc;
+		}
+		cert = x509_last ( certs );
+		DBGC ( validator, "VALIDATOR %p found certificate %s\n",
+		       validator, cert->subject.name );
+
+		/* Move to next certificate */
+		asn1_skip_any ( &cursor );
+	}
+
+	/* Append certificates to chain */
+	last = x509_last ( validator->chain );
+	if ( ( rc = x509_auto_append ( validator->chain, certs ) ) != 0 ) {
+		DBGC ( validator, "VALIDATOR %p could not append "
+		       "certificates: %s\n", validator, strerror ( rc ) );
+		goto err_auto_append;
+	}
+
+	/* Check that at least one certificate has been added */
+	if ( last == x509_last ( validator->chain ) ) {
+		DBGC ( validator, "VALIDATOR %p failed to append any "
+		       "applicable certificates\n", validator );
+		rc = -EACCES;
+		goto err_no_progress;
+	}
+
+	/* Drop reference to certificate list */
+	x509_chain_put ( certs );
+
+	return 0;
+
+ err_no_progress:
+ err_auto_append:
+ err_certificateset:
+	x509_chain_put ( certs );
+ err_alloc_certs:
+	return rc;
+}
+
+/**
+ * Start download of cross-signing certificate
+ *
+ * @v validator		Certificate validator
+ * @v issuer		Required issuer
+ * @ret rc		Return status code
+ */
+static int validator_start_download ( struct validator *validator,
+				      const struct asn1_cursor *issuer ) {
+	const char *crosscert;
+	char *crosscert_copy;
+	char *uri_string;
+	size_t uri_string_len;
+	uint32_t crc;
+	int len;
+	int rc;
+
+	/* Determine cross-signed certificate source */
+	len = fetch_string_setting_copy ( NULL, &crosscert_setting,
+					  &crosscert_copy );
+	if ( len < 0 ) {
+		rc = len;
+		DBGC ( validator, "VALIDATOR %p could not fetch crosscert "
+		       "setting: %s\n", validator, strerror ( rc ) );
+		goto err_fetch_crosscert;
+	}
+	crosscert = ( crosscert_copy ? crosscert_copy : crosscert_default );
+
+	/* Allocate URI string */
+	uri_string_len = ( strlen ( crosscert ) + 22 /* "/%08x.der?subject=" */
+			   + base64_encoded_len ( issuer->len ) + 1 /* NUL */ );
+	uri_string = zalloc ( uri_string_len );
+	if ( ! uri_string ) {
+		rc = -ENOMEM;
+		goto err_alloc_uri_string;
+	}
+
+	/* Generate CRC32 */
+	crc = crc32_le ( 0xffffffffUL, issuer->data, issuer->len );
+
+	/* Generate URI string */
+	len = snprintf ( uri_string, uri_string_len, "%s/%08x.der?subject=",
+			 crosscert, crc );
+	base64_encode ( issuer->data, issuer->len, ( uri_string + len ) );
+	DBGC ( validator, "VALIDATOR %p downloading cross-signed certificate "
+	       "from %s\n", validator, uri_string );
+
+	/* Set completion handler */
+	validator->done = validator_append;
+
+	/* Open URI */
+	if ( ( rc = xfer_open_uri_string ( &validator->xfer,
+					   uri_string ) ) != 0 ) {
+		DBGC ( validator, "VALIDATOR %p could not open %s: %s\n",
+		       validator, uri_string, strerror ( rc ) );
+		goto err_open_uri_string;
+	}
+
+	/* Success */
+	rc = 0;
+
+ err_open_uri_string:
+	free ( uri_string );
+ err_alloc_uri_string:
+	free ( crosscert_copy );
+ err_fetch_crosscert:
+	return rc;
+}
+
+/****************************************************************************
+ *
+ * OCSP checks
+ *
+ */
+
+/**
+ * Validate OCSP response
+ *
+ * @v validator		Certificate validator
+ * @v data		Raw OCSP response
+ * @v len		Length of raw data
+ * @ret rc		Return status code
+ */
+static int validator_ocsp_validate ( struct validator *validator,
+				     const void *data, size_t len ) {
+	time_t now;
+	int rc;
+
+	/* Record OCSP response */
+	if ( ( rc = ocsp_response ( validator->ocsp, data, len ) ) != 0 ) {
+		DBGC ( validator, "VALIDATOR %p could not record OCSP "
+		       "response: %s\n", validator, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Validate OCSP response */
+	now = time ( NULL );
+	if ( ( rc = ocsp_validate ( validator->ocsp, now ) ) != 0 ) {
+		DBGC ( validator, "VALIDATOR %p could not validate OCSP "
+		       "response: %s\n", validator, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Drop reference to OCSP check */
+	ocsp_put ( validator->ocsp );
+	validator->ocsp = NULL;
+
+	return 0;
+}
+
+/**
+ * Start OCSP check
+ *
+ * @v validator		Certificate validator
+ * @v cert		Certificate to check
+ * @v issuer		Issuing certificate
+ * @ret rc		Return status code
+ */
+static int validator_start_ocsp ( struct validator *validator,
+				  struct x509_certificate *cert,
+				  struct x509_certificate *issuer ) {
+	const char *uri_string;
+	int rc;
+
+	/* Create OCSP check */
+	assert ( validator->ocsp == NULL );
+	if ( ( rc = ocsp_check ( cert, issuer, &validator->ocsp ) ) != 0 ) {
+		DBGC ( validator, "VALIDATOR %p could not create OCSP check: "
+		       "%s\n", validator, strerror ( rc ) );
+		return rc;
+	}
+
+	/* Set completion handler */
+	validator->done = validator_ocsp_validate;
+
+	/* Open URI */
+	uri_string = validator->ocsp->uri_string;
+	DBGC ( validator, "VALIDATOR %p performing OCSP check at %s\n",
+	       validator, uri_string );
+	if ( ( rc = xfer_open_uri_string ( &validator->xfer,
+					   uri_string ) ) != 0 ) {
+		DBGC ( validator, "VALIDATOR %p could not open %s: %s\n",
+		       validator, uri_string, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+ *
+ * Data transfer interface
+ *
+ */
+
+/**
+ * Close data transfer interface
+ *
+ * @v validator		Certificate validator
+ * @v rc		Reason for close
+ */
+static void validator_xfer_close ( struct validator *validator, int rc ) {
+
+	/* Close data transfer interface */
+	intf_restart ( &validator->xfer, rc );
+
+	/* Check for errors */
+	if ( rc != 0 ) {
+		DBGC ( validator, "VALIDATOR %p transfer failed: %s\n",
+		       validator, strerror ( rc ) );
+		goto err_transfer;
+	}
+	DBGC2 ( validator, "VALIDATOR %p transfer complete\n", validator );
+
+	/* Process completed download */
+	assert ( validator->done != NULL );
+	if ( ( rc = validator->done ( validator, validator->buffer.data,
+				       validator->buffer.len ) ) != 0 )
+		goto err_append;
+
+	/* Free downloaded data */
+	xferbuf_done ( &validator->buffer );
+
+	/* Resume validation process */
+	process_add ( &validator->process );
+
+	return;
+
+ err_append:
+ err_transfer:
+	validator_finished ( validator, rc );
+}
+
+/**
+ * Receive data
+ *
+ * @v validator		Certificate validator
+ * @v iobuf		I/O buffer
+ * @v meta		Data transfer metadata
+ * @ret rc		Return status code
+ */
+static int validator_xfer_deliver ( struct validator *validator,
+				    struct io_buffer *iobuf,
+				    struct xfer_metadata *meta ) {
+	int rc;
+
+	/* Add data to buffer */
+	if ( ( rc = xferbuf_deliver ( &validator->buffer, iob_disown ( iobuf ),
+				      meta ) ) != 0 ) {
+		DBGC ( validator, "VALIDATOR %p could not receive data: %s\n",
+		       validator, strerror ( rc ) );
+		validator_finished ( validator, rc );
+		return rc;
+	}
+
+	return 0;
+}
+
+/** Certificate validator data transfer interface operations */
+static struct interface_operation validator_xfer_operations[] = {
+	INTF_OP ( xfer_deliver, struct validator *, validator_xfer_deliver ),
+	INTF_OP ( intf_close, struct validator *, validator_xfer_close ),
+};
+
+/** Certificate validator data transfer interface descriptor */
+static struct interface_descriptor validator_xfer_desc =
+	INTF_DESC ( struct validator, xfer, validator_xfer_operations );
+
+/****************************************************************************
+ *
+ * Validation process
+ *
+ */
+
+/**
+ * Certificate validation process
+ *
+ * @v validator		Certificate validator
+ */
+static void validator_step ( struct validator *validator ) {
+	struct x509_link *link;
+	struct x509_certificate *cert;
+	struct x509_certificate *issuer = NULL;
+	struct x509_certificate *last;
+	time_t now;
+	int rc;
+
+	/* Try validating chain.  Try even if the chain is incomplete,
+	 * since certificates may already have been validated
+	 * previously.
+	 */
+	now = time ( NULL );
+	if ( ( rc = x509_validate_chain ( validator->chain, now,
+					  NULL ) ) == 0 ) {
+		validator_finished ( validator, 0 );
+		return;
+	}
+
+	/* If there is a certificate that could be validated using
+	 * OCSP, try it.
+	 */
+	list_for_each_entry ( link, &validator->chain->links, list ) {
+		cert = issuer;
+		issuer = link->cert;
+		if ( ! cert )
+			continue;
+		if ( ! issuer->valid )
+			continue;
+		/* The issuer is valid, but this certificate is not
+		 * yet valid.  If OCSP is applicable, start it.
+		 */
+		if ( cert->extensions.auth_info.ocsp.uri &&
+		     ( ! cert->extensions.auth_info.ocsp.good ) ) {
+			/* Start OCSP */
+			if ( ( rc = validator_start_ocsp ( validator, cert,
+							   issuer ) ) != 0 ) {
+				validator_finished ( validator, rc );
+				return;
+			}
+			return;
+		}
+		/* Otherwise, this is a permanent failure */
+		validator_finished ( validator, rc );
+		return;
+	}
+
+	/* If chain ends with a self-issued certificate, then there is
+	 * nothing more to do.
+	 */
+	last = x509_last ( validator->chain );
+	if ( asn1_compare ( &last->issuer.raw, &last->subject.raw ) == 0 ) {
+		validator_finished ( validator, rc );
+		return;
+	}
+
+	/* Otherwise, try to download a suitable cross-signing
+	 * certificate.
+	 */
+	if ( ( rc = validator_start_download ( validator,
+					       &last->issuer.raw ) ) != 0 ) {
+		validator_finished ( validator, rc );
+		return;
+	}
+}
+
+/** Certificate validator process descriptor */
+static struct process_descriptor validator_process_desc =
+	PROC_DESC_ONCE ( struct validator, process, validator_step );
+
+/****************************************************************************
+ *
+ * Instantiator
+ *
+ */
+
+/**
+ * Instantiate a certificate validator
+ *
+ * @v job		Job control interface
+ * @v chain		X.509 certificate chain
+ * @ret rc		Return status code
+ */
+int create_validator ( struct interface *job, struct x509_chain *chain ) {
+	struct validator *validator;
+	int rc;
+
+	/* Sanity check */
+	if ( ! chain ) {
+		rc = -EINVAL;
+		goto err_sanity;
+	}
+
+	/* Allocate and initialise structure */
+	validator = zalloc ( sizeof ( *validator ) );
+	if ( ! validator ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	ref_init ( &validator->refcnt, validator_free );
+	intf_init ( &validator->job, &validator_job_desc,
+		    &validator->refcnt );
+	intf_init ( &validator->xfer, &validator_xfer_desc,
+		    &validator->refcnt );
+	process_init ( &validator->process, &validator_process_desc,
+		       &validator->refcnt );
+	validator->chain = x509_chain_get ( chain );
+
+	/* Attach parent interface, mortalise self, and return */
+	intf_plug_plug ( &validator->job, job );
+	ref_put ( &validator->refcnt );
+	DBGC2 ( validator, "VALIDATOR %p validating X509 chain %p\n",
+		validator, validator->chain );
+	return 0;
+
+	validator_finished ( validator, rc );
+	ref_put ( &validator->refcnt );
+ err_alloc:
+ err_sanity:
+	return rc;
+}
diff --git a/roms/ipxe/src/net/vlan.c b/roms/ipxe/src/net/vlan.c
index 9ac560f1e8a0a9594eac85015d48..1a2a08622121fd18ac81c43623d1 100644
--- a/roms/ipxe/src/net/vlan.c
+++ b/roms/ipxe/src/net/vlan.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -91,12 +92,13 @@ static int vlan_transmit ( struct net_device *netdev,
 	const void *ll_dest;
 	const void *ll_source;
 	uint16_t net_proto;
+	unsigned int flags;
 	int rc;
 
 	/* Strip link-layer header and preserve link-layer header fields */
 	ll_protocol = netdev->ll_protocol;
 	if ( ( rc = ll_protocol->pull ( netdev, iobuf, &ll_dest, &ll_source,
-					&net_proto ) ) != 0 ) {
+					&net_proto, &flags ) ) != 0 ) {
 		DBGC ( netdev, "VLAN %s could not parse link-layer header: "
 		       "%s\n", netdev->name, strerror ( rc ) );
 		return rc;
@@ -214,10 +216,12 @@ struct net_device * vlan_find ( struct net_device *trunk, unsigned int tag ) {
  * @v trunk		Trunk network device
  * @v ll_dest		Link-layer destination address
  * @v ll_source		Link-layer source address
+ * @v flags		Packet flags
  * @ret rc		Return status code
  */
 static int vlan_rx ( struct io_buffer *iobuf, struct net_device *trunk,
-		     const void *ll_dest, const void *ll_source ) {
+		     const void *ll_dest, const void *ll_source,
+		     unsigned int flags __unused ) {
 	struct vlan_header *vlanhdr = iobuf->data;
 	struct net_device *netdev;
 	struct ll_protocol *ll_protocol;
@@ -278,6 +282,23 @@ struct net_protocol vlan_protocol __net_protocol = {
 	.rx = vlan_rx,
 };
 
+/**
+ * Get the VLAN tag
+ *
+ * @v netdev		Network device
+ * @ret tag		VLAN tag, or 0 if device is not a VLAN device
+ */
+unsigned int vlan_tag ( struct net_device *netdev ) {
+	struct vlan_device *vlan;
+
+	if ( netdev->op == &vlan_operations ) {
+		vlan = netdev->priv;
+		return vlan->tag;
+	} else {
+		return 0;
+	}
+}
+
 /**
  * Check if network device can be used as a VLAN trunk device
  *
diff --git a/roms/ipxe/src/tests/aes_cbc_test.c b/roms/ipxe/src/tests/aes_cbc_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..4ae3a92e53f3774f8813e9fd8948b9705e98942d
--- /dev/null
+++ b/roms/ipxe/src/tests/aes_cbc_test.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * AES-in-CBC-mode tests
+ *
+ * These test vectors are provided by NIST as part of the
+ * Cryptographic Toolkit Examples, downloadable from:
+ *
+ *    http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/AES_CBC.pdf
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <assert.h>
+#include <string.h>
+#include <ipxe/aes.h>
+#include <ipxe/test.h>
+#include "cbc_test.h"
+
+/** Define inline key */
+#define KEY(...) { __VA_ARGS__ }
+
+/** Define inline initialisation vector */
+#define IV(...) { __VA_ARGS__ }
+
+/** Define inline plaintext data */
+#define PLAINTEXT(...) { __VA_ARGS__ }
+
+/** Define inline ciphertext data */
+#define CIPHERTEXT(...) { __VA_ARGS__ }
+
+/** An AES-in-CBC-mode test */
+struct aes_cbc_test {
+	/** Key */
+	const void *key;
+	/** Length of key */
+	size_t key_len;
+	/** Initialisation vector */
+	const void *iv;
+	/** Length of initialisation vector */
+	size_t iv_len;
+	/** Plaintext */
+	const void *plaintext;
+	/** Length of plaintext */
+	size_t plaintext_len;
+	/** Ciphertext */
+	const void *ciphertext;
+	/** Length of ciphertext */
+	size_t ciphertext_len;
+};
+
+/**
+ * Define an AES-in-CBC-mode test
+ *
+ * @v name		Test name
+ * @v key_array		Key
+ * @v iv_array		Initialisation vector
+ * @v plaintext_array	Plaintext
+ * @v ciphertext_array	Ciphertext
+ * @ret test		AES-in-CBC-mode test
+ */
+#define AES_CBC_TEST( name, key_array, iv_array, plaintext_array,	\
+		      ciphertext_array )				\
+	static const uint8_t name ## _key [] = key_array;		\
+	static const uint8_t name ## _iv [] = iv_array;			\
+	static const uint8_t name ## _plaintext [] = plaintext_array;	\
+	static const uint8_t name ## _ciphertext [] = ciphertext_array;	\
+	static struct aes_cbc_test name = {				\
+		.key = name ## _key,					\
+		.key_len = sizeof ( name ## _key ),			\
+		.iv = name ## _iv,					\
+		.iv_len = sizeof ( name ## _iv ),			\
+		.plaintext = name ## _plaintext,			\
+		.plaintext_len = sizeof ( name ## _plaintext ),		\
+		.ciphertext = name ## _ciphertext,			\
+		.ciphertext_len = sizeof ( name ## _ciphertext ),	\
+	}
+
+/**
+ * Report AES-in-CBC-mode
+ *
+ * @v state		HMAC_DRBG internal state
+ * @v test		Instantiation test
+ */
+#define aes_cbc_ok( test ) do {						\
+	struct cipher_algorithm *cipher = &aes_cbc_algorithm;		\
+									\
+	assert ( (test)->iv_len == cipher->blocksize );			\
+	assert ( (test)->plaintext_len == (test)->ciphertext_len );	\
+	cbc_encrypt_ok ( cipher, (test)->key, (test)->key_len,		\
+			 (test)->iv, (test)->plaintext,			\
+			 (test)->ciphertext, (test)->plaintext_len );	\
+	cbc_decrypt_ok ( cipher, (test)->key, (test)->key_len,		\
+			 (test)->iv, (test)->ciphertext,		\
+			 (test)->plaintext, (test)->ciphertext_len );	\
+	} while ( 0 )
+
+/** CBC_AES128 */
+AES_CBC_TEST ( test_128,
+	KEY ( 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15,
+	      0x88, 0x09, 0xcf, 0x4f, 0x3c ),
+	IV ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+	     0x0b, 0x0c, 0x0d, 0x0e, 0x0f ),
+	PLAINTEXT ( 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+		    0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+		    0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+		    0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+		    0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+		    0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+		    0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+		    0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 ),
+	CIPHERTEXT ( 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46,
+		     0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
+		     0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee,
+		     0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
+		     0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b,
+		     0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
+		     0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09,
+		     0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7 ) );
+
+/** CBC_AES256 */
+AES_CBC_TEST ( test_256,
+	KEY ( 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae,
+	      0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61,
+	      0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 ),
+	IV ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+	     0x0b, 0x0c, 0x0d, 0x0e, 0x0f ),
+	PLAINTEXT ( 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+		    0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+		    0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+		    0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+		    0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+		    0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+		    0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+		    0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 ),
+	CIPHERTEXT ( 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba,
+		     0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6,
+		     0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d,
+		     0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d,
+		     0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf,
+		     0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61,
+		     0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc,
+		     0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b ) );
+
+/**
+ * Perform AES-in-CBC-mode self-test
+ *
+ */
+static void aes_cbc_test_exec ( void ) {
+	struct cipher_algorithm *cipher = &aes_cbc_algorithm;
+
+	/* Correctness tests */
+	aes_cbc_ok ( &test_128 );
+	aes_cbc_ok ( &test_256 );
+
+	/* Speed tests */
+	DBG ( "AES128 encryption required %ld cycles per byte\n",
+	      cbc_cost_encrypt ( cipher, test_128.key_len ) );
+	DBG ( "AES128 decryption required %ld cycles per byte\n",
+	      cbc_cost_decrypt ( cipher, test_128.key_len ) );
+	DBG ( "AES256 encryption required %ld cycles per byte\n",
+	      cbc_cost_encrypt ( cipher, test_256.key_len ) );
+	DBG ( "AES256 decryption required %ld cycles per byte\n",
+	      cbc_cost_decrypt ( cipher, test_256.key_len ) );
+}
+
+/** AES-in-CBC-mode self-test */
+struct self_test aes_cbc_test __self_test = {
+	.name = "aes_cbc",
+	.exec = aes_cbc_test_exec,
+};
diff --git a/roms/ipxe/src/tests/base64_test.c b/roms/ipxe/src/tests/base64_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..c088298ca62f40729ab6c361cc729f5ca76fd4bb
--- /dev/null
+++ b/roms/ipxe/src/tests/base64_test.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Base64 tests
+ *
+ * Test vectors generated using "base64 -w 0"
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stdint.h>
+#include <string.h>
+#include <ipxe/base64.h>
+#include <ipxe/test.h>
+
+/** A Base64 test */
+struct base64_test {
+	/** Raw data */
+	const void *data;
+	/** Length of raw data */
+	size_t len;
+	/** Base64-encoded data */
+	const char *encoded;
+};
+
+/** Define inline data */
+#define DATA(...) { __VA_ARGS__ }
+
+/** Define a base64 test */
+#define BASE64( name, DATA, ENCODED )					\
+	static const uint8_t name ## _data[] = DATA;			\
+	static struct base64_test name = {				\
+		.data = name ## _data,					\
+		.len = sizeof ( name ## _data ),			\
+		.encoded = ENCODED,					\
+	}
+
+/** Empty data test */
+BASE64 ( empty_test, DATA(), "" );
+
+/** "Hello world" test */
+BASE64 ( hw_test,
+	 DATA ( 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' ),
+	 "SGVsbG8gd29ybGQ=" );
+
+/** Random data test */
+BASE64 ( random_test,
+	 DATA ( 0x36, 0x03, 0x84, 0xdc, 0x4e, 0x03, 0x46, 0xa0, 0xb5, 0x2d,
+		0x03, 0x6e, 0xd0, 0x56, 0xed, 0xa0, 0x37, 0x02, 0xac, 0xc6,
+		0x65, 0xd1 ),
+	 "NgOE3E4DRqC1LQNu0FbtoDcCrMZl0Q==" );
+
+/**
+ * Report a base64 encoding test result
+ *
+ * @v test		Base64 test
+ */
+#define base64_encode_ok( test ) do {					\
+	size_t len = base64_encoded_len ( (test)->len );		\
+	char buf[ len + 1 /* NUL */ ];					\
+	ok ( len == strlen ( (test)->encoded ) );			\
+	base64_encode ( (test)->data, (test)->len, buf );		\
+	ok ( strcmp ( (test)->encoded, buf ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Report a base64 decoding test result
+ *
+ * @v test		Base64 test
+ */
+#define base64_decode_ok( test ) do {					\
+	size_t max_len = base64_decoded_max_len ( (test)->encoded );	\
+	uint8_t buf[max_len];						\
+	int len;							\
+	len = base64_decode ( (test)->encoded, buf );			\
+	ok ( len >= 0 );						\
+	ok ( ( size_t ) len <= max_len );				\
+	ok ( ( size_t ) len == (test)->len );				\
+	ok ( memcmp ( (test)->data, buf, len ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Perform Base64 self-tests
+ *
+ */
+static void base64_test_exec ( void ) {
+
+	base64_encode_ok ( &empty_test );
+	base64_decode_ok ( &empty_test );
+
+	base64_encode_ok ( &hw_test );
+	base64_decode_ok ( &hw_test );
+
+	base64_encode_ok ( &random_test );
+	base64_decode_ok ( &random_test );
+}
+
+/** Base64 self-test */
+struct self_test base64_test __self_test = {
+	.name = "base64",
+	.exec = base64_test_exec,
+};
diff --git a/roms/ipxe/src/tests/bigint_test.c b/roms/ipxe/src/tests/bigint_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..75a80622f44229b8b22b492d6873ad4e4b92d5ab
--- /dev/null
+++ b/roms/ipxe/src/tests/bigint_test.c
@@ -0,0 +1,2437 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Big integer self-tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <assert.h>
+#include <string.h>
+#include <ipxe/bigint.h>
+#include <ipxe/test.h>
+
+/** Define inline big integer */
+#define BIGINT(...) { __VA_ARGS__ }
+
+/* Provide global functions to allow inspection of generated assembly code */
+
+void bigint_init_sample ( bigint_element_t *value0, unsigned int size,
+			  const void *data, size_t len ) {
+	bigint_t ( size ) *value __attribute__ (( may_alias ))
+		= ( ( void * ) value0 );
+
+	bigint_init ( value, data, len );
+}
+
+void bigint_done_sample ( const bigint_element_t *value0, unsigned int size,
+			  void *out, size_t len ) {
+	const bigint_t ( size ) *value __attribute__ (( may_alias ))
+		= ( ( const void * ) value0 );
+
+	bigint_done ( value, out, len );
+}
+
+void bigint_add_sample ( const bigint_element_t *addend0,
+			 bigint_element_t *value0, unsigned int size ) {
+	const bigint_t ( size ) *addend __attribute__ (( may_alias ))
+		= ( ( const void * ) addend0 );
+	bigint_t ( size ) *value __attribute__ (( may_alias ))
+		= ( ( void * ) value0 );
+
+	bigint_add ( addend, value );
+}
+
+void bigint_subtract_sample ( const bigint_element_t *subtrahend0,
+			      bigint_element_t *value0, unsigned int size ) {
+	const bigint_t ( size ) *subtrahend __attribute__ (( may_alias ))
+		= ( ( const void * ) subtrahend0 );
+	bigint_t ( size ) *value __attribute__ (( may_alias ))
+		= ( ( void * ) value0 );
+
+	bigint_subtract ( subtrahend, value );
+}
+
+void bigint_rol_sample ( bigint_element_t *value0, unsigned int size ) {
+	bigint_t ( size ) *value __attribute__ (( may_alias ))
+		= ( ( void * ) value0 );
+
+	bigint_rol ( value );
+}
+
+void bigint_ror_sample ( bigint_element_t *value0, unsigned int size ) {
+	bigint_t ( size ) *value __attribute__ (( may_alias ))
+		= ( ( void * ) value0 );
+
+	bigint_ror ( value );
+}
+
+int bigint_is_zero_sample ( const bigint_element_t *value0,
+			    unsigned int size ) {
+	const bigint_t ( size ) *value __attribute__ (( may_alias ))
+		= ( ( const void * ) value0 );
+
+	return bigint_is_zero ( value );
+}
+
+int bigint_is_geq_sample ( const bigint_element_t *value0,
+			   const bigint_element_t *reference0,
+			   unsigned int size ) {
+	const bigint_t ( size ) *value __attribute__ (( may_alias ))
+		= ( ( const void * ) value0 );
+	const bigint_t ( size ) *reference __attribute__ (( may_alias ))
+		= ( ( const void * ) reference0 );
+
+	return bigint_is_geq ( value, reference );
+}
+
+int bigint_bit_is_set_sample ( const bigint_element_t *value0,
+			       unsigned int size, unsigned int bit ) {
+	const bigint_t ( size ) *value __attribute__ (( may_alias ))
+		= ( ( const void * ) value0 );
+
+	return bigint_bit_is_set ( value, bit );
+}
+
+int bigint_max_set_bit_sample ( const bigint_element_t *value0,
+				unsigned int size ) {
+	const bigint_t ( size ) *value __attribute__ (( may_alias ))
+		= ( ( const void * ) value0 );
+
+	return bigint_max_set_bit ( value );
+}
+
+void bigint_grow_sample ( const bigint_element_t *source0,
+			  unsigned int source_size, bigint_element_t *dest0,
+			  unsigned int dest_size ) {
+	const bigint_t ( source_size ) *source __attribute__ (( may_alias ))
+		= ( ( const void * ) source0 );
+	bigint_t ( dest_size ) *dest __attribute__ (( may_alias ))
+		= ( ( void * ) dest0 );
+
+	bigint_grow ( source, dest );
+}
+
+void bigint_shrink_sample ( const bigint_element_t *source0,
+			    unsigned int source_size, bigint_element_t *dest0,
+			    unsigned int dest_size ) {
+	const bigint_t ( source_size ) *source __attribute__ (( may_alias ))
+		= ( ( const void * ) source0 );
+	bigint_t ( dest_size ) *dest __attribute__ (( may_alias ))
+		= ( ( void * ) dest0 );
+
+	bigint_shrink ( source, dest );
+}
+
+void bigint_multiply_sample ( const bigint_element_t *multiplicand0,
+			      const bigint_element_t *multiplier0,
+			      bigint_element_t *result0,
+			      unsigned int size ) {
+	const bigint_t ( size ) *multiplicand __attribute__ (( may_alias ))
+		= ( ( const void * ) multiplicand0 );
+	const bigint_t ( size ) *multiplier __attribute__ (( may_alias ))
+		= ( ( const void * ) multiplier0 );
+	bigint_t ( size * 2 ) *result __attribute__ (( may_alias ))
+		= ( ( void * ) result0 );
+
+	bigint_multiply ( multiplicand, multiplier, result );
+}
+
+void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0,
+				  const bigint_element_t *multiplier0,
+				  const bigint_element_t *modulus0,
+				  bigint_element_t *result0,
+				  unsigned int size,
+				  void *tmp ) {
+	const bigint_t ( size ) *multiplicand __attribute__ (( may_alias ))
+		= ( ( const void * ) multiplicand0 );
+	const bigint_t ( size ) *multiplier __attribute__ (( may_alias ))
+		= ( ( const void * ) multiplier0 );
+	const bigint_t ( size ) *modulus __attribute__ (( may_alias ))
+		= ( ( const void * ) modulus0 );
+	bigint_t ( size ) *result __attribute__ (( may_alias ))
+		= ( ( void * ) result0 );
+
+	bigint_mod_multiply ( multiplicand, multiplier, modulus, result, tmp );
+}
+
+void bigint_mod_exp_sample ( const bigint_element_t *base0,
+			     const bigint_element_t *modulus0,
+			     const bigint_element_t *exponent0,
+			     bigint_element_t *result0,
+			     unsigned int size, unsigned int exponent_size,
+			     void *tmp ) {
+	const bigint_t ( size ) *base __attribute__ (( may_alias ))
+		= ( ( const void * ) base0 );
+	const bigint_t ( size ) *modulus __attribute__ (( may_alias ))
+		= ( ( const void * ) modulus0 );
+	const bigint_t ( exponent_size ) *exponent __attribute__ (( may_alias ))
+		= ( ( const void * ) exponent0 );
+	bigint_t ( size ) *result __attribute__ (( may_alias ))
+		= ( ( void * ) result0 );
+
+	bigint_mod_exp ( base, modulus, exponent, result, tmp );
+}
+
+/**
+ * Report result of big integer addition test
+ *
+ * @v addend		Big integer to add
+ * @v value		Big integer to be added to
+ * @v expected		Big integer expected result
+ */
+#define bigint_add_ok( addend, value, expected ) do {			\
+	static const uint8_t addend_raw[] = addend;			\
+	static const uint8_t value_raw[] = value;			\
+	static const uint8_t expected_raw[] = expected;			\
+	uint8_t result_raw[ sizeof ( expected_raw ) ];			\
+	unsigned int size =						\
+		bigint_required_size ( sizeof ( value_raw ) );		\
+	bigint_t ( size ) addend_temp;					\
+	bigint_t ( size ) value_temp;					\
+	{} /* Fix emacs alignment */					\
+									\
+	assert ( bigint_size ( &addend_temp ) ==			\
+		 bigint_size ( &value_temp ) );				\
+	bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) );	\
+	bigint_init ( &addend_temp, addend_raw,				\
+		      sizeof ( addend_raw ) );				\
+	DBG ( "Add:\n" );						\
+	DBG_HDA ( 0, &addend_temp, sizeof ( addend_temp ) );		\
+	DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) );		\
+	bigint_add ( &addend_temp, &value_temp );			\
+	DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) );		\
+	bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) );	\
+									\
+	ok ( memcmp ( result_raw, expected_raw,				\
+		      sizeof ( result_raw ) ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Report result of big integer subtraction test
+ *
+ * @v subtrahend	Big integer to subtract
+ * @v value		Big integer to be subtracted from
+ * @v expected		Big integer expected result
+ */
+#define bigint_subtract_ok( subtrahend, value, expected ) do {		\
+	static const uint8_t subtrahend_raw[] = subtrahend;		\
+	static const uint8_t value_raw[] = value;			\
+	static const uint8_t expected_raw[] = expected;			\
+	uint8_t result_raw[ sizeof ( expected_raw ) ];			\
+	unsigned int size =						\
+		bigint_required_size ( sizeof ( value_raw ) );		\
+	bigint_t ( size ) subtrahend_temp;				\
+	bigint_t ( size ) value_temp;					\
+	{} /* Fix emacs alignment */					\
+									\
+	assert ( bigint_size ( &subtrahend_temp ) ==			\
+		 bigint_size ( &value_temp ) );				\
+	bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) );	\
+	bigint_init ( &subtrahend_temp, subtrahend_raw,			\
+		      sizeof ( subtrahend_raw ) );			\
+	DBG ( "Subtract:\n" );						\
+	DBG_HDA ( 0, &subtrahend_temp, sizeof ( subtrahend_temp ) );	\
+	DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) );		\
+	bigint_subtract ( &subtrahend_temp, &value_temp );		\
+	DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) );		\
+	bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) );	\
+									\
+	ok ( memcmp ( result_raw, expected_raw,				\
+		      sizeof ( result_raw ) ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Report result of big integer left rotation test
+ *
+ * @v value		Big integer
+ * @v expected		Big integer expected result
+ */
+#define bigint_rol_ok( value, expected ) do {				\
+	static const uint8_t value_raw[] = value;			\
+	static const uint8_t expected_raw[] = expected;			\
+	uint8_t result_raw[ sizeof ( expected_raw ) ];			\
+	unsigned int size =						\
+		bigint_required_size ( sizeof ( value_raw ) );		\
+	bigint_t ( size ) value_temp;					\
+	{} /* Fix emacs alignment */					\
+									\
+	bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) );	\
+	DBG ( "Rotate left:\n" );					\
+	DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) );		\
+	bigint_rol ( &value_temp );					\
+	DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) );		\
+	bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) );	\
+									\
+	ok ( memcmp ( result_raw, expected_raw,				\
+		      sizeof ( result_raw ) ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Report result of big integer right rotation test
+ *
+ * @v value		Big integer
+ * @v expected		Big integer expected result
+ */
+#define bigint_ror_ok( value, expected ) do {				\
+	static const uint8_t value_raw[] = value;			\
+	static const uint8_t expected_raw[] = expected;			\
+	uint8_t result_raw[ sizeof ( expected_raw ) ];			\
+	unsigned int size =						\
+		bigint_required_size ( sizeof ( value_raw ) );		\
+	bigint_t ( size ) value_temp;					\
+	{} /* Fix emacs alignment */					\
+									\
+	bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) );	\
+	DBG ( "Rotate right:\n" );					\
+	DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) );		\
+	bigint_ror ( &value_temp );					\
+	DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) );		\
+	bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) );	\
+									\
+	ok ( memcmp ( result_raw, expected_raw,				\
+		      sizeof ( result_raw ) ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Report result of big integer zero comparison test
+ *
+ * @v value		Big integer
+ * @v expected		Expected result
+ */
+#define bigint_is_zero_ok( value, expected ) do {			\
+	static const uint8_t value_raw[] = value;			\
+	unsigned int size =						\
+		bigint_required_size ( sizeof ( value_raw ) );		\
+	bigint_t ( size ) value_temp;					\
+	int is_zero;							\
+	{} /* Fix emacs alignment */					\
+									\
+	bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) );	\
+	DBG ( "Zero comparison:\n" );					\
+	DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) );		\
+	is_zero = bigint_is_zero ( &value_temp );			\
+	DBG ( "...is %szero\n", ( is_zero ? "" : "not " ) );		\
+	ok ( ( !! is_zero ) == ( !! (expected) ) );			\
+	} while ( 0 )
+
+/**
+ * Report result of big integer greater-than-or-equal comparison test
+ *
+ * @v value		Big integer
+ * @v reference		Reference big integer
+ * @v expected		Expected result
+ */
+#define bigint_is_geq_ok( value, reference, expected ) do {		\
+	static const uint8_t value_raw[] = value;			\
+	static const uint8_t reference_raw[] = reference;		\
+	unsigned int size =						\
+		bigint_required_size ( sizeof ( value_raw ) );		\
+	bigint_t ( size ) value_temp;					\
+	bigint_t ( size ) reference_temp;				\
+	int is_geq;							\
+	{} /* Fix emacs alignment */					\
+									\
+	assert ( bigint_size ( &reference_temp ) ==			\
+		 bigint_size ( &value_temp ) );				\
+	bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) );	\
+	bigint_init ( &reference_temp, reference_raw,			\
+		      sizeof ( reference_raw ) );			\
+	DBG ( "Greater-than-or-equal comparison:\n" );			\
+	DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) );		\
+	DBG_HDA ( 0, &reference_temp, sizeof ( reference_temp ) );	\
+	is_geq = bigint_is_geq ( &value_temp, &reference_temp );	\
+	DBG ( "...is %sgreater than or equal\n",			\
+	      ( is_geq ? "" : "not " ) );				\
+	ok ( ( !! is_geq ) == ( !! (expected) ) );			\
+	} while ( 0 )
+
+/**
+ * Report result of big integer bit-set test
+ *
+ * @v value		Big integer
+ * @v bit		Bit to test
+ * @v expected		Expected result
+ */
+#define bigint_bit_is_set_ok( value, bit, expected ) do {		\
+	static const uint8_t value_raw[] = value;			\
+	unsigned int size =						\
+		bigint_required_size ( sizeof ( value_raw ) );		\
+	bigint_t ( size ) value_temp;					\
+	int bit_is_set;							\
+	{} /* Fix emacs alignment */					\
+									\
+	bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) );	\
+	DBG ( "Bit set:\n" );						\
+	DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) );		\
+	bit_is_set = bigint_bit_is_set ( &value_temp, bit );		\
+	DBG ( "...bit %d is %sset\n", bit,				\
+	      ( bit_is_set ? "" : "not " ) );				\
+	ok ( ( !! bit_is_set ) == ( !! (expected) ) );			\
+	} while ( 0 )
+
+/**
+ * Report result of big integer maximum set bit test
+ *
+ * @v value		Big integer
+ * @v expected		Expected result
+ */
+#define bigint_max_set_bit_ok( value, expected ) do {			\
+	static const uint8_t value_raw[] = value;			\
+	unsigned int size =						\
+		bigint_required_size ( sizeof ( value_raw ) );		\
+	bigint_t ( size ) value_temp;					\
+	int max_set_bit;						\
+	{} /* Fix emacs alignment */					\
+									\
+	bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) );	\
+	DBG ( "Maximum set bit:\n" );					\
+	DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) );		\
+	max_set_bit = bigint_max_set_bit ( &value_temp );		\
+	DBG ( "...maximum set bit is bit %d\n", ( max_set_bit - 1 ) );	\
+	ok ( max_set_bit == (expected) );				\
+	} while ( 0 )
+
+/**
+ * Report result of big integer multiplication test
+ *
+ * @v multiplicand	Big integer to be multiplied
+ * @v multiplier	Big integer to be multiplied
+ * @v expected		Big integer expected result
+ */
+#define bigint_multiply_ok( multiplicand, multiplier, expected ) do {	\
+	static const uint8_t multiplicand_raw[] = multiplicand;		\
+	static const uint8_t multiplier_raw[] = multiplier;		\
+	static const uint8_t expected_raw[] = expected;			\
+	uint8_t result_raw[ sizeof ( expected_raw ) ];			\
+	unsigned int size =						\
+		bigint_required_size ( sizeof ( multiplicand_raw ) );	\
+	bigint_t ( size ) multiplicand_temp;				\
+	bigint_t ( size ) multiplier_temp;				\
+	bigint_t ( size * 2 ) result_temp;				\
+	{} /* Fix emacs alignment */					\
+									\
+	assert ( bigint_size ( &multiplier_temp ) ==			\
+		 bigint_size ( &multiplicand_temp ) );			\
+	assert ( bigint_size ( &result_temp ) ==			\
+		 ( 2 * bigint_size ( &multiplicand_temp ) ) );		\
+	bigint_init ( &multiplicand_temp, multiplicand_raw,		\
+		      sizeof ( multiplicand_raw ) );			\
+	bigint_init ( &multiplier_temp, multiplier_raw,			\
+		      sizeof ( multiplier_raw ) );			\
+	DBG ( "Multiply:\n" );						\
+	DBG_HDA ( 0, &multiplicand_temp, sizeof ( multiplicand_temp ) );\
+	DBG_HDA ( 0, &multiplier_temp, sizeof ( multiplier_temp ) );	\
+	bigint_multiply ( &multiplicand_temp, &multiplier_temp,		\
+			  &result_temp );				\
+	DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) );		\
+	bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) );\
+									\
+	ok ( memcmp ( result_raw, expected_raw,				\
+		      sizeof ( result_raw ) ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Report result of big integer modular multiplication test
+ *
+ * @v multiplicand	Big integer to be multiplied
+ * @v multiplier	Big integer to be multiplied
+ * @v modulus		Big integer modulus
+ * @v expected		Big integer expected result
+ */
+#define bigint_mod_multiply_ok( multiplicand, multiplier, modulus,	\
+				expected ) do {				\
+	static const uint8_t multiplicand_raw[] = multiplicand;		\
+	static const uint8_t multiplier_raw[] = multiplier;		\
+	static const uint8_t modulus_raw[] = modulus;			\
+	static const uint8_t expected_raw[] = expected;			\
+	uint8_t result_raw[ sizeof ( expected_raw ) ];			\
+	unsigned int size =						\
+		bigint_required_size ( sizeof ( multiplicand_raw ) );	\
+	bigint_t ( size ) multiplicand_temp;				\
+	bigint_t ( size ) multiplier_temp;				\
+	bigint_t ( size ) modulus_temp;					\
+	bigint_t ( size ) result_temp;					\
+	size_t tmp_len = bigint_mod_multiply_tmp_len ( &modulus_temp ); \
+	uint8_t tmp[tmp_len];						\
+	{} /* Fix emacs alignment */					\
+									\
+	assert ( bigint_size ( &multiplier_temp ) ==			\
+		 bigint_size ( &multiplicand_temp ) );			\
+	assert ( bigint_size ( &multiplier_temp ) ==			\
+		 bigint_size ( &modulus_temp ) );			\
+	assert ( bigint_size ( &multiplier_temp ) ==			\
+		 bigint_size ( &result_temp ) );			\
+	bigint_init ( &multiplicand_temp, multiplicand_raw,		\
+		      sizeof ( multiplicand_raw ) );			\
+	bigint_init ( &multiplier_temp, multiplier_raw,			\
+		      sizeof ( multiplier_raw ) );			\
+	bigint_init ( &modulus_temp, modulus_raw,			\
+		      sizeof ( modulus_raw ) );				\
+	DBG ( "Modular multiply:\n" );					\
+	DBG_HDA ( 0, &multiplicand_temp, sizeof ( multiplicand_temp ) );\
+	DBG_HDA ( 0, &multiplier_temp, sizeof ( multiplier_temp ) );	\
+	DBG_HDA ( 0, &modulus_temp, sizeof ( modulus_temp ) );		\
+	bigint_mod_multiply ( &multiplicand_temp, &multiplier_temp,	\
+			      &modulus_temp, &result_temp, tmp );	\
+	DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) );		\
+	bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) );\
+									\
+	ok ( memcmp ( result_raw, expected_raw,				\
+		      sizeof ( result_raw ) ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Report result of big integer modular exponentiation test
+ *
+ * @v base		Big integer base
+ * @v modulus		Big integer modulus
+ * @v exponent		Big integer exponent
+ * @v expected		Big integer expected result
+ */
+#define bigint_mod_exp_ok( base, modulus, exponent, expected ) do {	\
+	static const uint8_t base_raw[] = base;				\
+	static const uint8_t modulus_raw[] = modulus;			\
+	static const uint8_t exponent_raw[] = exponent;			\
+	static const uint8_t expected_raw[] = expected;			\
+	uint8_t result_raw[ sizeof ( expected_raw ) ];			\
+	unsigned int size =						\
+		bigint_required_size ( sizeof ( base_raw ) );		\
+	unsigned int exponent_size =					\
+		bigint_required_size ( sizeof ( exponent_raw ) );	\
+	bigint_t ( size ) base_temp;					\
+	bigint_t ( size ) modulus_temp;					\
+	bigint_t ( exponent_size ) exponent_temp;			\
+	bigint_t ( size ) result_temp;					\
+	size_t tmp_len = bigint_mod_exp_tmp_len ( &modulus_temp,	\
+						  &exponent_temp );	\
+	uint8_t tmp[tmp_len];						\
+	{} /* Fix emacs alignment */					\
+									\
+	assert ( bigint_size ( &modulus_temp ) ==			\
+		 bigint_size ( &base_temp ) );				\
+	assert ( bigint_size ( &modulus_temp ) ==			\
+		 bigint_size ( &result_temp ) );			\
+	bigint_init ( &base_temp, base_raw, sizeof ( base_raw ) );	\
+	bigint_init ( &modulus_temp, modulus_raw,			\
+		      sizeof ( modulus_raw ) );				\
+	bigint_init ( &exponent_temp, exponent_raw,			\
+		      sizeof ( exponent_raw ) );			\
+	DBG ( "Modular exponentiation:\n" );				\
+	DBG_HDA ( 0, &base_temp, sizeof ( base_temp ) );		\
+	DBG_HDA ( 0, &modulus_temp, sizeof ( modulus_temp ) );		\
+	DBG_HDA ( 0, &exponent_temp, sizeof ( exponent_temp ) );	\
+	bigint_mod_exp ( &base_temp, &modulus_temp, &exponent_temp,	\
+			 &result_temp, tmp );				\
+	DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) );		\
+	bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) );\
+									\
+	ok ( memcmp ( result_raw, expected_raw,				\
+		      sizeof ( result_raw ) ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Perform big integer self-tests
+ *
+ */
+static void bigint_test_exec ( void ) {
+
+	bigint_add_ok ( BIGINT ( 0x8a ),
+			BIGINT ( 0x43 ),
+			BIGINT ( 0xcd ) );
+	bigint_add_ok ( BIGINT ( 0xc5, 0x7b ),
+			BIGINT ( 0xd6, 0xb1 ),
+			BIGINT ( 0x9c, 0x2c ) );
+	bigint_add_ok ( BIGINT ( 0xf9, 0xd9, 0xdc ),
+			BIGINT ( 0x6d, 0x4b, 0xca ),
+			BIGINT ( 0x67, 0x25, 0xa6 ) );
+	bigint_add_ok ( BIGINT ( 0xdd, 0xc2, 0x20, 0x5f ),
+			BIGINT ( 0x80, 0x32, 0xc4, 0xb0 ),
+			BIGINT ( 0x5d, 0xf4, 0xe5, 0x0f ) );
+	bigint_add_ok ( BIGINT ( 0x01, 0xed, 0x45, 0x4b, 0x41, 0xeb, 0x4c,
+				 0x2e, 0x53, 0x07, 0x15, 0x51, 0x56, 0x47,
+				 0x29, 0xfc, 0x9c, 0xbd, 0xbd, 0xfb, 0x1b,
+				 0xd1, 0x1d ),
+			BIGINT ( 0x73, 0xed, 0xfc, 0x35, 0x31, 0x22, 0xd7,
+				 0xb1, 0xea, 0x91, 0x5a, 0xe4, 0xba, 0xbc,
+				 0xa1, 0x38, 0x72, 0xae, 0x4b, 0x1c, 0xc1,
+				 0x05, 0xb3 ),
+			BIGINT ( 0x75, 0xdb, 0x41, 0x80, 0x73, 0x0e, 0x23,
+				 0xe0, 0x3d, 0x98, 0x70, 0x36, 0x11, 0x03,
+				 0xcb, 0x35, 0x0f, 0x6c, 0x09, 0x17, 0xdc,
+				 0xd6, 0xd0 ) );
+	bigint_add_ok ( BIGINT ( 0x06, 0x8e, 0xd6, 0x18, 0xbb, 0x4b, 0x0c,
+				 0xc5, 0x85, 0xde, 0xee, 0x9b, 0x3f, 0x65,
+				 0x63, 0x86, 0xf5, 0x5a, 0x9f, 0xa2, 0xd7,
+				 0xb2, 0xc7, 0xb6, 0x1d, 0x28, 0x6c, 0x50,
+				 0x47, 0x10, 0x0a, 0x0e, 0x86, 0xcd, 0x2a,
+				 0x64, 0xdc, 0xe6, 0x9d, 0x96, 0xd8, 0xf4,
+				 0x56, 0x46, 0x6f, 0xbb, 0x7b, 0x64, 0x6f,
+				 0xdc, 0x2a, 0xd1, 0x3b, 0xcc, 0x03, 0x85,
+				 0x95, 0xf4, 0xe9, 0x68, 0x1f, 0x5c, 0xc5,
+				 0xbf, 0x97, 0x19, 0x12, 0x88, 0x2e, 0x88,
+				 0xb9, 0x34, 0xac, 0x74, 0x83, 0x2d, 0x8f,
+				 0xb3, 0x97, 0x53, 0x99, 0xf3, 0xb4, 0x8b,
+				 0x2d, 0x98, 0x69, 0x8d, 0x19, 0xf0, 0x40,
+				 0x66, 0x3f, 0x60, 0x78, 0x34, 0x7f, 0x9b,
+				 0xf7, 0x01, 0x74, 0x55, 0xca, 0x63, 0x25,
+				 0x7b, 0x86, 0xe9, 0x73, 0xfd, 0x5d, 0x77,
+				 0x32, 0x5e, 0x9e, 0x42, 0x53, 0xb6, 0x35,
+				 0x92, 0xb9, 0xd7, 0x1b, 0xf7, 0x16, 0x55,
+				 0xf6, 0xe2 ),
+			BIGINT ( 0x3f, 0x8f, 0x62, 0x21, 0x4a, 0x7a, 0xa2,
+				 0xef, 0xa8, 0x79, 0x9b, 0x73, 0xac, 0xde,
+				 0x72, 0xe4, 0xfc, 0x3c, 0xd3, 0xa9, 0x44,
+				 0x1a, 0x6a, 0x02, 0x76, 0xe3, 0x78, 0x4d,
+				 0x2e, 0x07, 0x9b, 0xb6, 0x3d, 0x5d, 0xc5,
+				 0xcd, 0x68, 0x23, 0x4b, 0x5f, 0x89, 0x0e,
+				 0xd7, 0xa7, 0xff, 0x18, 0x80, 0xdc, 0xfb,
+				 0x34, 0x45, 0xca, 0x4b, 0xdb, 0x8a, 0x19,
+				 0xcb, 0xc9, 0xe5, 0xa1, 0x63, 0xa2, 0x0d,
+				 0x56, 0xc4, 0xf9, 0x51, 0x1b, 0x88, 0x4e,
+				 0x36, 0xab, 0x15, 0x4d, 0x8f, 0xdc, 0x08,
+				 0xc4, 0x4d, 0x43, 0xc7, 0x2b, 0xc9, 0x5c,
+				 0x05, 0x26, 0xe3, 0x46, 0xf0, 0x64, 0xaa,
+				 0x02, 0xa4, 0xbe, 0x3a, 0xd1, 0xca, 0x07,
+				 0x6a, 0x6e, 0x62, 0xf4, 0x57, 0x71, 0x96,
+				 0xec, 0xf0, 0x0b, 0xac, 0xa4, 0x4a, 0xa3,
+				 0x6d, 0x01, 0xba, 0xbd, 0x62, 0xc0, 0x10,
+				 0x54, 0x33, 0x8a, 0x71, 0xef, 0xaa, 0x1c,
+				 0x25, 0x25 ),
+			BIGINT ( 0x46, 0x1e, 0x38, 0x3a, 0x05, 0xc5, 0xaf,
+				 0xb5, 0x2e, 0x58, 0x8a, 0x0e, 0xec, 0x43,
+				 0xd6, 0x6b, 0xf1, 0x97, 0x73, 0x4c, 0x1b,
+				 0xcd, 0x31, 0xb8, 0x94, 0x0b, 0xe4, 0x9d,
+				 0x75, 0x17, 0xa5, 0xc4, 0xc4, 0x2a, 0xf0,
+				 0x32, 0x45, 0x09, 0xe8, 0xf6, 0x62, 0x03,
+				 0x2d, 0xee, 0x6e, 0xd3, 0xfc, 0x41, 0x6b,
+				 0x10, 0x70, 0x9b, 0x87, 0xa7, 0x8d, 0x9f,
+				 0x61, 0xbe, 0xcf, 0x09, 0x82, 0xfe, 0xd3,
+				 0x16, 0x5c, 0x12, 0x63, 0xa3, 0xb6, 0xd6,
+				 0xef, 0xdf, 0xc1, 0xc2, 0x13, 0x09, 0x98,
+				 0x77, 0xe4, 0x97, 0x61, 0x1f, 0x7d, 0xe7,
+				 0x32, 0xbf, 0x4c, 0xd4, 0x0a, 0x54, 0xea,
+				 0x68, 0xe4, 0x1e, 0xb3, 0x06, 0x49, 0xa3,
+				 0x61, 0x6f, 0xd7, 0x4a, 0x21, 0xd4, 0xbc,
+				 0x68, 0x76, 0xf5, 0x20, 0xa1, 0xa8, 0x1a,
+				 0x9f, 0x60, 0x58, 0xff, 0xb6, 0x76, 0x45,
+				 0xe6, 0xed, 0x61, 0x8d, 0xe6, 0xc0, 0x72,
+				 0x1c, 0x07 ) );
+	bigint_subtract_ok ( BIGINT ( 0x83 ),
+			     BIGINT ( 0x50 ),
+			     BIGINT ( 0xcd ) );
+	bigint_subtract_ok ( BIGINT ( 0x2c, 0x7c ),
+			     BIGINT ( 0x49, 0x0e ),
+			     BIGINT ( 0x1c, 0x92 ) );
+	bigint_subtract_ok ( BIGINT ( 0x9c, 0x30, 0xbf ),
+			     BIGINT ( 0xde, 0x4e, 0x07 ),
+			     BIGINT ( 0x42, 0x1d, 0x48 ) );
+	bigint_subtract_ok ( BIGINT ( 0xbb, 0x77, 0x32, 0x5a ),
+			     BIGINT ( 0x5a, 0xd5, 0xfe, 0x28 ),
+			     BIGINT ( 0x9f, 0x5e, 0xcb, 0xce ) );
+	bigint_subtract_ok ( BIGINT ( 0x7b, 0xaa, 0x16, 0xcf, 0x15, 0x87,
+				      0xe0, 0x4f, 0x2c, 0xa3, 0xec, 0x2f,
+				      0x46, 0xfb, 0x83, 0xc6, 0xe0, 0xee,
+				      0x57, 0xfa, 0x04, 0xce, 0xa6 ),
+			     BIGINT ( 0x46, 0x55, 0xb6, 0x23, 0x63, 0xd0,
+				      0x55, 0xdb, 0x8f, 0xcc, 0x55, 0xa8,
+				      0x2f, 0x85, 0xc1, 0x9f, 0x2c, 0x13,
+				      0x10, 0x9e, 0x76, 0x3c, 0x11 ),
+			     BIGINT ( 0xca, 0xab, 0x9f, 0x54, 0x4e, 0x48,
+				      0x75, 0x8c, 0x63, 0x28, 0x69, 0x78,
+				      0xe8, 0x8a, 0x3d, 0xd8, 0x4b, 0x24,
+				      0xb8, 0xa4, 0x71, 0x6d, 0x6b ) );
+	bigint_subtract_ok ( BIGINT ( 0x5b, 0x06, 0x77, 0x7b, 0xfd, 0x34,
+				      0x5f, 0x0f, 0xd9, 0xbd, 0x8e, 0x5d,
+				      0xc8, 0x4a, 0x70, 0x95, 0x1b, 0xb6,
+				      0x48, 0xfb, 0x0e, 0x40, 0xce, 0x06,
+				      0x66, 0xcc, 0x29, 0xe9, 0x51, 0x59,
+				      0x59, 0xc9, 0x65, 0x07, 0x75, 0xb8,
+				      0xd4, 0xcb, 0x07, 0x68, 0x14, 0x48,
+				      0xc7, 0x1e, 0xfe, 0xb3, 0x4c, 0xf1,
+				      0x10, 0xf0, 0xc7, 0x82, 0x38, 0x4c,
+				      0xaf, 0x05, 0x6d, 0x91, 0xc5, 0x18,
+				      0xfd, 0x1e, 0x26, 0x1b, 0xef, 0x71,
+				      0x70, 0x2e, 0x06, 0x70, 0x8e, 0x54,
+				      0xfa, 0x2b, 0x4d, 0x96, 0x85, 0x10,
+				      0x03, 0x76, 0xe7, 0x17, 0x59, 0x86,
+				      0x6c, 0x8b, 0x24, 0x6e, 0xd9, 0x30,
+				      0xf3, 0xd2, 0x9b, 0x62, 0xdc, 0x23,
+				      0x54, 0x06, 0x51, 0xb1, 0x95, 0x58,
+				      0xec, 0x27, 0xf6, 0x19, 0xae, 0xf4,
+				      0x31, 0xec, 0x72, 0x53, 0xcd, 0x32,
+				      0xed, 0xf4, 0x25, 0x4a, 0x5b, 0x36,
+				      0xa2, 0xb4, 0xa0, 0x29, 0x0c, 0x6b,
+				      0x3f, 0xc2 ),
+			     BIGINT ( 0x7a, 0xd4, 0x25, 0xf1, 0xb5, 0xf5,
+				      0x00, 0x96, 0x47, 0x5b, 0x4f, 0x9f,
+				      0x1f, 0x61, 0x69, 0xd9, 0x72, 0x47,
+				      0xde, 0xbd, 0x87, 0x5d, 0x50, 0x91,
+				      0x69, 0xd8, 0x35, 0xe0, 0x43, 0xd8,
+				      0xd5, 0x15, 0xf2, 0xcd, 0x01, 0x73,
+				      0x0d, 0x34, 0xf0, 0x34, 0x46, 0x76,
+				      0xc0, 0x55, 0x7b, 0x27, 0xf5, 0x7b,
+				      0x55, 0xe9, 0xd0, 0x29, 0x0b, 0x4b,
+				      0x9f, 0x07, 0xbf, 0x2c, 0x3f, 0xef,
+				      0x36, 0x34, 0xde, 0x29, 0x1d, 0x5d,
+				      0x84, 0x5a, 0x5d, 0xc1, 0x02, 0x4d,
+				      0x56, 0xf1, 0x47, 0x39, 0x37, 0xc9,
+				      0xb5, 0x5f, 0x73, 0xec, 0x7c, 0x3d,
+				      0xbd, 0xc0, 0xfd, 0x38, 0x6c, 0x91,
+				      0x88, 0x4a, 0x0f, 0xee, 0xa1, 0x80,
+				      0xf5, 0x6a, 0x7c, 0x8c, 0x02, 0xc3,
+				      0x5a, 0xb2, 0x15, 0xa6, 0x2f, 0x6b,
+				      0x5b, 0x78, 0xb5, 0xf3, 0xbd, 0xd0,
+				      0xc8, 0xbc, 0xb1, 0xbb, 0xe1, 0xce,
+				      0x22, 0x80, 0x34, 0x5a, 0x2a, 0x27,
+				      0x83, 0xdc ),
+			     BIGINT ( 0x1f, 0xcd, 0xae, 0x75, 0xb8, 0xc0,
+				      0xa1, 0x86, 0x6d, 0x9d, 0xc1, 0x41,
+				      0x57, 0x16, 0xf9, 0x44, 0x56, 0x91,
+				      0x95, 0xc2, 0x79, 0x1c, 0x82, 0x8b,
+				      0x03, 0x0c, 0x0b, 0xf6, 0xf2, 0x7f,
+				      0x7b, 0x4c, 0x8d, 0xc5, 0x8b, 0xba,
+				      0x38, 0x69, 0xe8, 0xcc, 0x32, 0x2d,
+				      0xf9, 0x36, 0x7c, 0x74, 0xa8, 0x8a,
+				      0x44, 0xf9, 0x08, 0xa6, 0xd2, 0xfe,
+				      0xf0, 0x02, 0x51, 0x9a, 0x7a, 0xd6,
+				      0x39, 0x16, 0xb8, 0x0d, 0x2d, 0xec,
+				      0x14, 0x2c, 0x57, 0x50, 0x73, 0xf8,
+				      0x5c, 0xc5, 0xf9, 0xa2, 0xb2, 0xb9,
+				      0xb1, 0xe8, 0x8c, 0xd5, 0x22, 0xb7,
+				      0x51, 0x35, 0xd8, 0xc9, 0x93, 0x60,
+				      0x94, 0x77, 0x74, 0x8b, 0xc5, 0x5d,
+				      0xa1, 0x64, 0x2a, 0xda, 0x6d, 0x6a,
+				      0x6e, 0x8a, 0x1f, 0x8c, 0x80, 0x77,
+				      0x29, 0x8c, 0x43, 0x9f, 0xf0, 0x9d,
+				      0xda, 0xc8, 0x8c, 0x71, 0x86, 0x97,
+				      0x7f, 0xcb, 0x94, 0x31, 0x1d, 0xbc,
+				      0x44, 0x1a ) );
+	bigint_rol_ok ( BIGINT ( 0xe0 ),
+			BIGINT ( 0xc0 ) );
+	bigint_rol_ok ( BIGINT ( 0x43, 0x1d ),
+			BIGINT ( 0x86, 0x3a ) );
+	bigint_rol_ok ( BIGINT ( 0xac, 0xed, 0x9b ),
+			BIGINT ( 0x59, 0xdb, 0x36 ) );
+	bigint_rol_ok ( BIGINT ( 0x2c, 0xe8, 0x3a, 0x22 ),
+			BIGINT ( 0x59, 0xd0, 0x74, 0x44 ) );
+	bigint_rol_ok ( BIGINT ( 0x4e, 0x88, 0x4a, 0x05, 0x5e, 0x10, 0xee,
+				 0x5b, 0xc6, 0x40, 0x0e, 0x03, 0xd7, 0x0d,
+				 0x28, 0xa5, 0x55, 0xb2, 0x50, 0xef, 0x69,
+				 0xd1, 0x1d ),
+			BIGINT ( 0x9d, 0x10, 0x94, 0x0a, 0xbc, 0x21, 0xdc,
+				 0xb7, 0x8c, 0x80, 0x1c, 0x07, 0xae, 0x1a,
+				 0x51, 0x4a, 0xab, 0x64, 0xa1, 0xde, 0xd3,
+				 0xa2, 0x3a ) );
+	bigint_rol_ok ( BIGINT ( 0x07, 0x62, 0x78, 0x70, 0x2e, 0xd4, 0x41,
+				 0xaa, 0x9b, 0x50, 0xb1, 0x9a, 0x71, 0xf5,
+				 0x1c, 0x2f, 0xe7, 0x0d, 0xf1, 0x46, 0x57,
+				 0x04, 0x99, 0x78, 0x4e, 0x84, 0x78, 0xba,
+				 0x57, 0xea, 0xa5, 0x43, 0xf7, 0x02, 0xf0,
+				 0x7a, 0x22, 0x60, 0x65, 0x42, 0xf2, 0x33,
+				 0x7d, 0xe3, 0xa8, 0x1b, 0xc4, 0x14, 0xdb,
+				 0xee, 0x4a, 0xf1, 0xe1, 0x52, 0xd4, 0xda,
+				 0x23, 0xed, 0x13, 0x5d, 0xea, 0xcf, 0xf6,
+				 0x5e, 0x39, 0x84, 0xe2, 0xb3, 0xa2, 0x05,
+				 0xba, 0xd9, 0x49, 0x8e, 0x75, 0x1d, 0xdb,
+				 0xe6, 0xb1, 0x6e, 0xda, 0x0a, 0x83, 0xd0,
+				 0x6e, 0xcf, 0x7a, 0x66, 0xb7, 0x64, 0x84,
+				 0xf5, 0x09, 0x5a, 0xa8, 0x11, 0x93, 0xf3,
+				 0x4f, 0x02, 0x28, 0x00, 0x3a, 0xf0, 0xa9,
+				 0x08, 0x77, 0x04, 0xf5, 0x04, 0xcd, 0x6b,
+				 0x24, 0xbe, 0x0f, 0x6d, 0xe3, 0xb2, 0xd3,
+				 0x07, 0x68, 0xe9, 0x00, 0x59, 0xa0, 0xe4,
+				 0x9e, 0x5e ),
+			BIGINT ( 0x0e, 0xc4, 0xf0, 0xe0, 0x5d, 0xa8, 0x83,
+				 0x55, 0x36, 0xa1, 0x63, 0x34, 0xe3, 0xea,
+				 0x38, 0x5f, 0xce, 0x1b, 0xe2, 0x8c, 0xae,
+				 0x09, 0x32, 0xf0, 0x9d, 0x08, 0xf1, 0x74,
+				 0xaf, 0xd5, 0x4a, 0x87, 0xee, 0x05, 0xe0,
+				 0xf4, 0x44, 0xc0, 0xca, 0x85, 0xe4, 0x66,
+				 0xfb, 0xc7, 0x50, 0x37, 0x88, 0x29, 0xb7,
+				 0xdc, 0x95, 0xe3, 0xc2, 0xa5, 0xa9, 0xb4,
+				 0x47, 0xda, 0x26, 0xbb, 0xd5, 0x9f, 0xec,
+				 0xbc, 0x73, 0x09, 0xc5, 0x67, 0x44, 0x0b,
+				 0x75, 0xb2, 0x93, 0x1c, 0xea, 0x3b, 0xb7,
+				 0xcd, 0x62, 0xdd, 0xb4, 0x15, 0x07, 0xa0,
+				 0xdd, 0x9e, 0xf4, 0xcd, 0x6e, 0xc9, 0x09,
+				 0xea, 0x12, 0xb5, 0x50, 0x23, 0x27, 0xe6,
+				 0x9e, 0x04, 0x50, 0x00, 0x75, 0xe1, 0x52,
+				 0x10, 0xee, 0x09, 0xea, 0x09, 0x9a, 0xd6,
+				 0x49, 0x7c, 0x1e, 0xdb, 0xc7, 0x65, 0xa6,
+				 0x0e, 0xd1, 0xd2, 0x00, 0xb3, 0x41, 0xc9,
+				 0x3c, 0xbc ) );
+	bigint_ror_ok ( BIGINT ( 0x8f ),
+			BIGINT ( 0x47 ) );
+	bigint_ror_ok ( BIGINT ( 0xaa, 0x1d ),
+			BIGINT ( 0x55, 0x0e ) );
+	bigint_ror_ok ( BIGINT ( 0xf0, 0xbd, 0x68 ),
+			BIGINT ( 0x78, 0x5e, 0xb4 ) );
+	bigint_ror_ok ( BIGINT ( 0x33, 0xa0, 0x3d, 0x95 ),
+			BIGINT ( 0x19, 0xd0, 0x1e, 0xca ) );
+	bigint_ror_ok ( BIGINT ( 0xa1, 0xf4, 0xb9, 0x64, 0x91, 0x99, 0xa1,
+				 0xf4, 0xae, 0xeb, 0x71, 0x97, 0x1b, 0x71,
+				 0x09, 0x38, 0x3f, 0x8f, 0xc5, 0x3a, 0xb9,
+				 0x75, 0x94 ),
+			BIGINT ( 0x50, 0xfa, 0x5c, 0xb2, 0x48, 0xcc, 0xd0,
+				 0xfa, 0x57, 0x75, 0xb8, 0xcb, 0x8d, 0xb8,
+				 0x84, 0x9c, 0x1f, 0xc7, 0xe2, 0x9d, 0x5c,
+				 0xba, 0xca ) );
+	bigint_ror_ok ( BIGINT ( 0xc0, 0xb3, 0x78, 0x46, 0x69, 0x6e, 0x35,
+				 0x94, 0xed, 0x28, 0xdc, 0xfd, 0xf6, 0xdb,
+				 0x2d, 0x24, 0xcb, 0xa4, 0x6f, 0x0e, 0x58,
+				 0x89, 0x04, 0xec, 0xc8, 0x0c, 0x2d, 0xb3,
+				 0x58, 0xa7, 0x22, 0x6d, 0x93, 0xe0, 0xb8,
+				 0x48, 0x6a, 0x3f, 0x04, 0x7e, 0xbe, 0xb8,
+				 0xa7, 0x84, 0xf5, 0xc9, 0x2f, 0x60, 0x9e,
+				 0x7c, 0xbc, 0xaf, 0x28, 0x89, 0x2f, 0xaa,
+				 0xd1, 0x82, 0x77, 0xa4, 0xdf, 0xf3, 0x4a,
+				 0xc6, 0xed, 0xa3, 0x07, 0xb4, 0xa9, 0xfd,
+				 0xef, 0xf8, 0x20, 0xb9, 0xb3, 0xff, 0x35,
+				 0x27, 0xed, 0x02, 0xea, 0xec, 0x63, 0xc0,
+				 0x46, 0x97, 0xc0, 0x4c, 0xca, 0x89, 0xca,
+				 0x14, 0xe8, 0xe0, 0x02, 0x14, 0x44, 0x46,
+				 0xf3, 0x2f, 0xbc, 0x6a, 0x28, 0xa2, 0xbe,
+				 0x20, 0xc8, 0xaa, 0x0f, 0xd9, 0x51, 0x8e,
+				 0x8d, 0x51, 0x29, 0x61, 0xef, 0x48, 0xae,
+				 0x3e, 0xe5, 0x10, 0xbf, 0xda, 0x9b, 0x92,
+				 0xb3, 0x77 ),
+			BIGINT ( 0x60, 0x59, 0xbc, 0x23, 0x34, 0xb7, 0x1a,
+				 0xca, 0x76, 0x94, 0x6e, 0x7e, 0xfb, 0x6d,
+				 0x96, 0x92, 0x65, 0xd2, 0x37, 0x87, 0x2c,
+				 0x44, 0x82, 0x76, 0x64, 0x06, 0x16, 0xd9,
+				 0xac, 0x53, 0x91, 0x36, 0xc9, 0xf0, 0x5c,
+				 0x24, 0x35, 0x1f, 0x82, 0x3f, 0x5f, 0x5c,
+				 0x53, 0xc2, 0x7a, 0xe4, 0x97, 0xb0, 0x4f,
+				 0x3e, 0x5e, 0x57, 0x94, 0x44, 0x97, 0xd5,
+				 0x68, 0xc1, 0x3b, 0xd2, 0x6f, 0xf9, 0xa5,
+				 0x63, 0x76, 0xd1, 0x83, 0xda, 0x54, 0xfe,
+				 0xf7, 0xfc, 0x10, 0x5c, 0xd9, 0xff, 0x9a,
+				 0x93, 0xf6, 0x81, 0x75, 0x76, 0x31, 0xe0,
+				 0x23, 0x4b, 0xe0, 0x26, 0x65, 0x44, 0xe5,
+				 0x0a, 0x74, 0x70, 0x01, 0x0a, 0x22, 0x23,
+				 0x79, 0x97, 0xde, 0x35, 0x14, 0x51, 0x5f,
+				 0x10, 0x64, 0x55, 0x07, 0xec, 0xa8, 0xc7,
+				 0x46, 0xa8, 0x94, 0xb0, 0xf7, 0xa4, 0x57,
+				 0x1f, 0x72, 0x88, 0x5f, 0xed, 0x4d, 0xc9,
+				 0x59, 0xbb ) );
+	bigint_is_zero_ok ( BIGINT ( 0x9b ),
+			    0 );
+	bigint_is_zero_ok ( BIGINT ( 0x5a, 0x9d ),
+			    0 );
+	bigint_is_zero_ok ( BIGINT ( 0x5f, 0x80, 0x78 ),
+			    0 );
+	bigint_is_zero_ok ( BIGINT ( 0xa0, 0x52, 0x47, 0x2e ),
+			    0 );
+	bigint_is_zero_ok ( BIGINT ( 0x18, 0x08, 0x49, 0xdb, 0x7b, 0x5c,
+				     0xe7, 0x41, 0x07, 0xdf, 0xed, 0xf9,
+				     0xd3, 0x92, 0x0d, 0x75, 0xa6, 0xb0,
+				     0x14, 0xfa, 0xdd, 0xfd, 0x82 ),
+			    0 );
+	bigint_is_zero_ok ( BIGINT ( 0x04, 0x04, 0xb5, 0xf5, 0x01, 0xae,
+				     0x2b, 0x91, 0xa7, 0xc1, 0x49, 0x97,
+				     0x3f, 0x45, 0x53, 0x52, 0xb8, 0x52,
+				     0xf1, 0x62, 0xa5, 0x21, 0x18, 0xd4,
+				     0xb0, 0xb4, 0x8a, 0x17, 0x0e, 0xe8,
+				     0xeb, 0xaa, 0x28, 0xae, 0x3d, 0x8e,
+				     0xe3, 0x6c, 0xd0, 0x01, 0x0c, 0x54,
+				     0xca, 0x23, 0xbb, 0x06, 0xcd, 0x7a,
+				     0x61, 0x89, 0x38, 0x34, 0x6e, 0xc7,
+				     0xc2, 0xee, 0xb1, 0x80, 0x61, 0x0e,
+				     0xc6, 0x8d, 0x65, 0xa0, 0xeb, 0x34,
+				     0xe9, 0x63, 0x09, 0x4c, 0x20, 0xac,
+				     0x42, 0xe3, 0x35, 0xa2, 0x3e, 0x3b,
+				     0x2e, 0x18, 0x70, 0x45, 0x7c, 0xab,
+				     0x42, 0xcc, 0xe0, 0x9e, 0x7c, 0x42,
+				     0xd1, 0xda, 0x6c, 0x51, 0x10, 0x1e,
+				     0x0e, 0x3f, 0xe5, 0xd6, 0xd8, 0x56,
+				     0x08, 0xb2, 0x3b, 0x15, 0xc4, 0x7c,
+				     0x0c, 0x7e, 0xaf, 0x7b, 0x9d, 0xd6,
+				     0x2b, 0xc0, 0x2f, 0xa2, 0xa3, 0xa3,
+				     0x77, 0x58, 0x1b, 0xe9, 0xa8, 0x9a,
+				     0x23, 0x7f ),
+			    0 );
+	bigint_is_zero_ok ( BIGINT ( 0x00 ),
+			    1 );
+	bigint_is_zero_ok ( BIGINT ( 0x00, 0x00 ),
+			    1 );
+	bigint_is_zero_ok ( BIGINT ( 0x00, 0x00, 0x00 ),
+			    1 );
+	bigint_is_zero_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00 ),
+			    1 );
+	bigint_is_zero_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00 ),
+			    1 );
+	bigint_is_zero_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				     0x00, 0x00 ),
+			    1 );
+	bigint_is_zero_ok ( BIGINT ( 0xff ),
+			    0 );
+	bigint_is_zero_ok ( BIGINT ( 0xff, 0xff ),
+			    0 );
+	bigint_is_zero_ok ( BIGINT ( 0xff, 0xff, 0xff ),
+			    0 );
+	bigint_is_zero_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff ),
+			    0 );
+	bigint_is_zero_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff ),
+			    0 );
+	bigint_is_zero_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				     0xff, 0xff ),
+			    0 );
+	bigint_is_geq_ok ( BIGINT ( 0xa2 ),
+			   BIGINT ( 0x58 ),
+			   1 );
+	bigint_is_geq_ok ( BIGINT ( 0x58 ),
+			   BIGINT ( 0xa2 ),
+			   0 );
+	bigint_is_geq_ok ( BIGINT ( 0xa2 ),
+			   BIGINT ( 0xa2 ),
+			   1 );
+	bigint_is_geq_ok ( BIGINT ( 0x61, 0x29 ),
+			   BIGINT ( 0x87, 0xac ),
+			   0 );
+	bigint_is_geq_ok ( BIGINT ( 0x87, 0xac ),
+			   BIGINT ( 0x61, 0x29 ),
+			   1 );
+	bigint_is_geq_ok ( BIGINT ( 0x61, 0x29 ),
+			   BIGINT ( 0x61, 0x29 ),
+			   1 );
+	bigint_is_geq_ok ( BIGINT ( 0xe6, 0x63, 0x14 ),
+			   BIGINT ( 0xb7, 0x2b, 0x76 ),
+			   1 );
+	bigint_is_geq_ok ( BIGINT ( 0xb7, 0x2b, 0x76 ),
+			   BIGINT ( 0xe6, 0x63, 0x14 ),
+			   0 );
+	bigint_is_geq_ok ( BIGINT ( 0xe6, 0x63, 0x14 ),
+			   BIGINT ( 0xe6, 0x63, 0x14 ),
+			   1 );
+	bigint_is_geq_ok ( BIGINT ( 0xe7, 0x4f, 0xd4, 0x80 ),
+			   BIGINT ( 0xb5, 0xf9, 0x9b, 0x90 ),
+			   1 );
+	bigint_is_geq_ok ( BIGINT ( 0xb5, 0xf9, 0x9b, 0x90 ),
+			   BIGINT ( 0xe7, 0x4f, 0xd4, 0x80 ),
+			   0 );
+	bigint_is_geq_ok ( BIGINT ( 0xe7, 0x4f, 0xd4, 0x80 ),
+			   BIGINT ( 0xe7, 0x4f, 0xd4, 0x80 ),
+			   1 );
+	bigint_is_geq_ok ( BIGINT ( 0xe6, 0x2c, 0x7c, 0x24, 0x78, 0x8f, 0x12,
+				    0x20, 0xde, 0xd3, 0x6b, 0xc9, 0x97, 0x2d,
+				    0x66, 0x74, 0xe5, 0xb6, 0xf7, 0x8f, 0x2b,
+				    0x60, 0x98 ),
+			   BIGINT ( 0x77, 0xbc, 0x3b, 0x1b, 0x57, 0x43, 0x3b,
+				    0x8c, 0x82, 0xda, 0xb5, 0xc7, 0x18, 0x09,
+				    0xb3, 0x59, 0x0e, 0x53, 0x2a, 0xb9, 0xd8,
+				    0xa2, 0xb4 ),
+			   1 );
+	bigint_is_geq_ok ( BIGINT ( 0x77, 0xbc, 0x3b, 0x1b, 0x57, 0x43, 0x3b,
+				    0x8c, 0x82, 0xda, 0xb5, 0xc7, 0x18, 0x09,
+				    0xb3, 0x59, 0x0e, 0x53, 0x2a, 0xb9, 0xd8,
+				    0xa2, 0xb4 ),
+			   BIGINT ( 0xe6, 0x2c, 0x7c, 0x24, 0x78, 0x8f, 0x12,
+				    0x20, 0xde, 0xd3, 0x6b, 0xc9, 0x97, 0x2d,
+				    0x66, 0x74, 0xe5, 0xb6, 0xf7, 0x8f, 0x2b,
+				    0x60, 0x98 ),
+			   0 );
+	bigint_is_geq_ok ( BIGINT ( 0xe6, 0x2c, 0x7c, 0x24, 0x78, 0x8f, 0x12,
+				    0x20, 0xde, 0xd3, 0x6b, 0xc9, 0x97, 0x2d,
+				    0x66, 0x74, 0xe5, 0xb6, 0xf7, 0x8f, 0x2b,
+				    0x60, 0x98 ),
+			   BIGINT ( 0xe6, 0x2c, 0x7c, 0x24, 0x78, 0x8f, 0x12,
+				    0x20, 0xde, 0xd3, 0x6b, 0xc9, 0x97, 0x2d,
+				    0x66, 0x74, 0xe5, 0xb6, 0xf7, 0x8f, 0x2b,
+				    0x60, 0x98 ),
+			   1 );
+	bigint_is_geq_ok ( BIGINT ( 0x2a, 0x98, 0xfd, 0x87, 0x5d, 0x9f, 0xb4,
+				    0x8b, 0x5c, 0xcd, 0x5f, 0xcd, 0x53, 0xb3,
+				    0xd1, 0x81, 0x6a, 0x9c, 0x93, 0x66, 0x40,
+				    0xa7, 0x64, 0xe0, 0x8c, 0xec, 0x96, 0x63,
+				    0x4d, 0x29, 0xfa, 0xb1, 0x5d, 0x93, 0x2f,
+				    0xf9, 0x36, 0xea, 0x3b, 0xc1, 0xaf, 0x85,
+				    0xcb, 0xde, 0x2d, 0xc8, 0x48, 0x33, 0xce,
+				    0x7b, 0xa4, 0xa4, 0xda, 0x0f, 0xaa, 0x1b,
+				    0xcb, 0xed, 0xbe, 0x3a, 0xa5, 0xbb, 0x73,
+				    0x28, 0x04, 0xc6, 0x2a, 0xfb, 0x3a, 0xc3,
+				    0xae, 0x42, 0x1f, 0x53, 0x6c, 0xb2, 0x76,
+				    0xb7, 0xe2, 0x88, 0xcb, 0x88, 0xcf, 0xf0,
+				    0x52, 0x81, 0xd3, 0xb2, 0x1f, 0x56, 0xe1,
+				    0xe1, 0x47, 0x93, 0x6f, 0x2b, 0x49, 0xaa,
+				    0x50, 0x99, 0x7a, 0xc4, 0x56, 0xb7, 0x13,
+				    0x80, 0xf4, 0x73, 0x88, 0xc7, 0x39, 0x83,
+				    0x67, 0xc7, 0xcc, 0xb2, 0x28, 0x7a, 0xd3,
+				    0xdc, 0x48, 0xea, 0x62, 0x0d, 0xf5, 0x5a,
+				    0x27, 0x96 ),
+			   BIGINT ( 0xd4, 0x6b, 0x0a, 0x2e, 0x9f, 0xde, 0x4b,
+				    0x64, 0xfa, 0x6b, 0x37, 0x73, 0x66, 0x06,
+				    0xee, 0x04, 0xef, 0xe6, 0x3c, 0x7d, 0x57,
+				    0x22, 0x7f, 0x1f, 0x62, 0x1c, 0x7e, 0x20,
+				    0xda, 0x97, 0xd0, 0x27, 0x23, 0xf6, 0x77,
+				    0x5b, 0x49, 0x97, 0xe1, 0x65, 0x91, 0x13,
+				    0x93, 0xd6, 0x12, 0xc3, 0x66, 0x91, 0x76,
+				    0xe8, 0x47, 0x4c, 0x6a, 0x1b, 0xa2, 0x02,
+				    0xf8, 0x94, 0xaa, 0xe0, 0x1b, 0x0b, 0x17,
+				    0x86, 0x5e, 0xf5, 0x17, 0x23, 0xf5, 0x17,
+				    0x91, 0x6b, 0xd7, 0x2f, 0x5a, 0xfe, 0x8a,
+				    0x63, 0x28, 0x31, 0x1e, 0x09, 0x60, 0x29,
+				    0x5d, 0x55, 0xd8, 0x79, 0xeb, 0x78, 0x36,
+				    0x44, 0x69, 0xa4, 0x76, 0xa5, 0x35, 0x30,
+				    0xca, 0xc9, 0xf9, 0x62, 0xd7, 0x82, 0x13,
+				    0x56, 0xd0, 0x58, 0xfe, 0x16, 0x4b, 0xfb,
+				    0xa8, 0x4c, 0xb3, 0xd7, 0xcf, 0x5f, 0x93,
+				    0x9d, 0xc4, 0x11, 0xb4, 0xdd, 0xf8, 0x8f,
+				    0xe1, 0x11 ),
+			   0 );
+	bigint_is_geq_ok ( BIGINT ( 0xd4, 0x6b, 0x0a, 0x2e, 0x9f, 0xde, 0x4b,
+				    0x64, 0xfa, 0x6b, 0x37, 0x73, 0x66, 0x06,
+				    0xee, 0x04, 0xef, 0xe6, 0x3c, 0x7d, 0x57,
+				    0x22, 0x7f, 0x1f, 0x62, 0x1c, 0x7e, 0x20,
+				    0xda, 0x97, 0xd0, 0x27, 0x23, 0xf6, 0x77,
+				    0x5b, 0x49, 0x97, 0xe1, 0x65, 0x91, 0x13,
+				    0x93, 0xd6, 0x12, 0xc3, 0x66, 0x91, 0x76,
+				    0xe8, 0x47, 0x4c, 0x6a, 0x1b, 0xa2, 0x02,
+				    0xf8, 0x94, 0xaa, 0xe0, 0x1b, 0x0b, 0x17,
+				    0x86, 0x5e, 0xf5, 0x17, 0x23, 0xf5, 0x17,
+				    0x91, 0x6b, 0xd7, 0x2f, 0x5a, 0xfe, 0x8a,
+				    0x63, 0x28, 0x31, 0x1e, 0x09, 0x60, 0x29,
+				    0x5d, 0x55, 0xd8, 0x79, 0xeb, 0x78, 0x36,
+				    0x44, 0x69, 0xa4, 0x76, 0xa5, 0x35, 0x30,
+				    0xca, 0xc9, 0xf9, 0x62, 0xd7, 0x82, 0x13,
+				    0x56, 0xd0, 0x58, 0xfe, 0x16, 0x4b, 0xfb,
+				    0xa8, 0x4c, 0xb3, 0xd7, 0xcf, 0x5f, 0x93,
+				    0x9d, 0xc4, 0x11, 0xb4, 0xdd, 0xf8, 0x8f,
+				    0xe1, 0x11 ),
+			   BIGINT ( 0x2a, 0x98, 0xfd, 0x87, 0x5d, 0x9f, 0xb4,
+				    0x8b, 0x5c, 0xcd, 0x5f, 0xcd, 0x53, 0xb3,
+				    0xd1, 0x81, 0x6a, 0x9c, 0x93, 0x66, 0x40,
+				    0xa7, 0x64, 0xe0, 0x8c, 0xec, 0x96, 0x63,
+				    0x4d, 0x29, 0xfa, 0xb1, 0x5d, 0x93, 0x2f,
+				    0xf9, 0x36, 0xea, 0x3b, 0xc1, 0xaf, 0x85,
+				    0xcb, 0xde, 0x2d, 0xc8, 0x48, 0x33, 0xce,
+				    0x7b, 0xa4, 0xa4, 0xda, 0x0f, 0xaa, 0x1b,
+				    0xcb, 0xed, 0xbe, 0x3a, 0xa5, 0xbb, 0x73,
+				    0x28, 0x04, 0xc6, 0x2a, 0xfb, 0x3a, 0xc3,
+				    0xae, 0x42, 0x1f, 0x53, 0x6c, 0xb2, 0x76,
+				    0xb7, 0xe2, 0x88, 0xcb, 0x88, 0xcf, 0xf0,
+				    0x52, 0x81, 0xd3, 0xb2, 0x1f, 0x56, 0xe1,
+				    0xe1, 0x47, 0x93, 0x6f, 0x2b, 0x49, 0xaa,
+				    0x50, 0x99, 0x7a, 0xc4, 0x56, 0xb7, 0x13,
+				    0x80, 0xf4, 0x73, 0x88, 0xc7, 0x39, 0x83,
+				    0x67, 0xc7, 0xcc, 0xb2, 0x28, 0x7a, 0xd3,
+				    0xdc, 0x48, 0xea, 0x62, 0x0d, 0xf5, 0x5a,
+				    0x27, 0x96 ),
+			   1 );
+	bigint_is_geq_ok ( BIGINT ( 0x2a, 0x98, 0xfd, 0x87, 0x5d, 0x9f, 0xb4,
+				    0x8b, 0x5c, 0xcd, 0x5f, 0xcd, 0x53, 0xb3,
+				    0xd1, 0x81, 0x6a, 0x9c, 0x93, 0x66, 0x40,
+				    0xa7, 0x64, 0xe0, 0x8c, 0xec, 0x96, 0x63,
+				    0x4d, 0x29, 0xfa, 0xb1, 0x5d, 0x93, 0x2f,
+				    0xf9, 0x36, 0xea, 0x3b, 0xc1, 0xaf, 0x85,
+				    0xcb, 0xde, 0x2d, 0xc8, 0x48, 0x33, 0xce,
+				    0x7b, 0xa4, 0xa4, 0xda, 0x0f, 0xaa, 0x1b,
+				    0xcb, 0xed, 0xbe, 0x3a, 0xa5, 0xbb, 0x73,
+				    0x28, 0x04, 0xc6, 0x2a, 0xfb, 0x3a, 0xc3,
+				    0xae, 0x42, 0x1f, 0x53, 0x6c, 0xb2, 0x76,
+				    0xb7, 0xe2, 0x88, 0xcb, 0x88, 0xcf, 0xf0,
+				    0x52, 0x81, 0xd3, 0xb2, 0x1f, 0x56, 0xe1,
+				    0xe1, 0x47, 0x93, 0x6f, 0x2b, 0x49, 0xaa,
+				    0x50, 0x99, 0x7a, 0xc4, 0x56, 0xb7, 0x13,
+				    0x80, 0xf4, 0x73, 0x88, 0xc7, 0x39, 0x83,
+				    0x67, 0xc7, 0xcc, 0xb2, 0x28, 0x7a, 0xd3,
+				    0xdc, 0x48, 0xea, 0x62, 0x0d, 0xf5, 0x5a,
+				    0x27, 0x96 ),
+			   BIGINT ( 0x2a, 0x98, 0xfd, 0x87, 0x5d, 0x9f, 0xb4,
+				    0x8b, 0x5c, 0xcd, 0x5f, 0xcd, 0x53, 0xb3,
+				    0xd1, 0x81, 0x6a, 0x9c, 0x93, 0x66, 0x40,
+				    0xa7, 0x64, 0xe0, 0x8c, 0xec, 0x96, 0x63,
+				    0x4d, 0x29, 0xfa, 0xb1, 0x5d, 0x93, 0x2f,
+				    0xf9, 0x36, 0xea, 0x3b, 0xc1, 0xaf, 0x85,
+				    0xcb, 0xde, 0x2d, 0xc8, 0x48, 0x33, 0xce,
+				    0x7b, 0xa4, 0xa4, 0xda, 0x0f, 0xaa, 0x1b,
+				    0xcb, 0xed, 0xbe, 0x3a, 0xa5, 0xbb, 0x73,
+				    0x28, 0x04, 0xc6, 0x2a, 0xfb, 0x3a, 0xc3,
+				    0xae, 0x42, 0x1f, 0x53, 0x6c, 0xb2, 0x76,
+				    0xb7, 0xe2, 0x88, 0xcb, 0x88, 0xcf, 0xf0,
+				    0x52, 0x81, 0xd3, 0xb2, 0x1f, 0x56, 0xe1,
+				    0xe1, 0x47, 0x93, 0x6f, 0x2b, 0x49, 0xaa,
+				    0x50, 0x99, 0x7a, 0xc4, 0x56, 0xb7, 0x13,
+				    0x80, 0xf4, 0x73, 0x88, 0xc7, 0x39, 0x83,
+				    0x67, 0xc7, 0xcc, 0xb2, 0x28, 0x7a, 0xd3,
+				    0xdc, 0x48, 0xea, 0x62, 0x0d, 0xf5, 0x5a,
+				    0x27, 0x96 ),
+			   1 );
+	bigint_bit_is_set_ok ( BIGINT ( 0x37 ),
+			       0, 1 );
+	bigint_bit_is_set_ok ( BIGINT ( 0xe6, 0xcb ),
+			       0, 1 );
+	bigint_bit_is_set_ok ( BIGINT ( 0xd9, 0x0c, 0x5b ),
+			       0, 1 );
+	bigint_bit_is_set_ok ( BIGINT ( 0x8b, 0x56, 0x89, 0xaf ),
+			       0, 1 );
+	bigint_bit_is_set_ok ( BIGINT ( 0x25, 0xfc, 0xaf, 0xeb, 0x81, 0xc3,
+					0xb8, 0x2f, 0xbb, 0xe3, 0x07, 0xb2,
+					0xe2, 0x2a, 0xe2, 0x2d, 0xb4, 0x4d,
+					0x6d, 0xec, 0x51, 0xa0, 0x2f ),
+			       0, 1 );
+	bigint_bit_is_set_ok ( BIGINT ( 0x25, 0xfc, 0xaf, 0xeb, 0x81, 0xc3,
+					0xb8, 0x2f, 0xbb, 0xe3, 0x07, 0xb2,
+					0xe2, 0x2a, 0xe2, 0x2d, 0xb4, 0x4d,
+					0x6d, 0xec, 0x51, 0xa0, 0x2f ),
+			       45, 0 );
+	bigint_bit_is_set_ok ( BIGINT ( 0x88, 0x04, 0xec, 0xe6, 0xfb, 0x31,
+					0x87, 0x43, 0xb2, 0x04, 0x9e, 0x09,
+					0xba, 0x3e, 0x6d, 0x64, 0x1a, 0x85,
+					0xb6, 0x46, 0x7d, 0x71, 0x3c, 0x06,
+					0xd6, 0x40, 0x52, 0x39, 0x95, 0xa1,
+					0x06, 0xff, 0x6a, 0x5c, 0xa3, 0x6d,
+					0x4a, 0xc9, 0x77, 0x87, 0x75, 0x25,
+					0x57, 0x65, 0x72, 0x73, 0x64, 0x7e,
+					0xe9, 0x16, 0x17, 0xf3, 0x65, 0x3f,
+					0xd5, 0xcc, 0xd7, 0xa2, 0xee, 0xe7,
+					0x8d, 0x48, 0xd5, 0x7e, 0xdd, 0x59,
+					0x4b, 0xf0, 0x96, 0x8b, 0x21, 0x65,
+					0x04, 0x66, 0xc5, 0xff, 0x3e, 0x60,
+					0xba, 0x28, 0x38, 0x7d, 0x9c, 0x09,
+					0xd1, 0x8e, 0xac, 0x73, 0x8e, 0xf2,
+					0x1e, 0xdf, 0x83, 0x6e, 0x54, 0xd5,
+					0x34, 0xc1, 0xc6, 0xf9, 0x62, 0x2a,
+					0x7d, 0xec, 0x47, 0xf2, 0xfc, 0xa2,
+					0x10, 0x0a, 0x67, 0x1b, 0xc6, 0x11,
+					0x9d, 0x68, 0x25, 0x8b, 0xb5, 0x9b,
+					0x83, 0xf8, 0xa2, 0x11, 0xf5, 0xd4,
+					0xcb, 0xe0 ),
+			       0, 0 );
+	bigint_bit_is_set_ok ( BIGINT ( 0x88, 0x04, 0xec, 0xe6, 0xfb, 0x31,
+					0x87, 0x43, 0xb2, 0x04, 0x9e, 0x09,
+					0xba, 0x3e, 0x6d, 0x64, 0x1a, 0x85,
+					0xb6, 0x46, 0x7d, 0x71, 0x3c, 0x06,
+					0xd6, 0x40, 0x52, 0x39, 0x95, 0xa1,
+					0x06, 0xff, 0x6a, 0x5c, 0xa3, 0x6d,
+					0x4a, 0xc9, 0x77, 0x87, 0x75, 0x25,
+					0x57, 0x65, 0x72, 0x73, 0x64, 0x7e,
+					0xe9, 0x16, 0x17, 0xf3, 0x65, 0x3f,
+					0xd5, 0xcc, 0xd7, 0xa2, 0xee, 0xe7,
+					0x8d, 0x48, 0xd5, 0x7e, 0xdd, 0x59,
+					0x4b, 0xf0, 0x96, 0x8b, 0x21, 0x65,
+					0x04, 0x66, 0xc5, 0xff, 0x3e, 0x60,
+					0xba, 0x28, 0x38, 0x7d, 0x9c, 0x09,
+					0xd1, 0x8e, 0xac, 0x73, 0x8e, 0xf2,
+					0x1e, 0xdf, 0x83, 0x6e, 0x54, 0xd5,
+					0x34, 0xc1, 0xc6, 0xf9, 0x62, 0x2a,
+					0x7d, 0xec, 0x47, 0xf2, 0xfc, 0xa2,
+					0x10, 0x0a, 0x67, 0x1b, 0xc6, 0x11,
+					0x9d, 0x68, 0x25, 0x8b, 0xb5, 0x9b,
+					0x83, 0xf8, 0xa2, 0x11, 0xf5, 0xd4,
+					0xcb, 0xe0 ),
+			       45, 1 );
+	bigint_bit_is_set_ok ( BIGINT ( 0x88, 0x04, 0xec, 0xe6, 0xfb, 0x31,
+					0x87, 0x43, 0xb2, 0x04, 0x9e, 0x09,
+					0xba, 0x3e, 0x6d, 0x64, 0x1a, 0x85,
+					0xb6, 0x46, 0x7d, 0x71, 0x3c, 0x06,
+					0xd6, 0x40, 0x52, 0x39, 0x95, 0xa1,
+					0x06, 0xff, 0x6a, 0x5c, 0xa3, 0x6d,
+					0x4a, 0xc9, 0x77, 0x87, 0x75, 0x25,
+					0x57, 0x65, 0x72, 0x73, 0x64, 0x7e,
+					0xe9, 0x16, 0x17, 0xf3, 0x65, 0x3f,
+					0xd5, 0xcc, 0xd7, 0xa2, 0xee, 0xe7,
+					0x8d, 0x48, 0xd5, 0x7e, 0xdd, 0x59,
+					0x4b, 0xf0, 0x96, 0x8b, 0x21, 0x65,
+					0x04, 0x66, 0xc5, 0xff, 0x3e, 0x60,
+					0xba, 0x28, 0x38, 0x7d, 0x9c, 0x09,
+					0xd1, 0x8e, 0xac, 0x73, 0x8e, 0xf2,
+					0x1e, 0xdf, 0x83, 0x6e, 0x54, 0xd5,
+					0x34, 0xc1, 0xc6, 0xf9, 0x62, 0x2a,
+					0x7d, 0xec, 0x47, 0xf2, 0xfc, 0xa2,
+					0x10, 0x0a, 0x67, 0x1b, 0xc6, 0x11,
+					0x9d, 0x68, 0x25, 0x8b, 0xb5, 0x9b,
+					0x83, 0xf8, 0xa2, 0x11, 0xf5, 0xd4,
+					0xcb, 0xe0 ),
+			       1013, 0 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x3a ),
+				6 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x03 ),
+				2 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x00 ),
+				0 );
+	bigint_max_set_bit_ok ( BIGINT ( 0xff ),
+				8 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x20, 0x30 ),
+				14 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x10 ),
+				5 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00 ),
+				0 );
+	bigint_max_set_bit_ok ( BIGINT ( 0xff, 0xff ),
+				16 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x06, 0xdb, 0x7a ),
+				19 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x00 ),
+				0 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x00 ),
+				0 );
+	bigint_max_set_bit_ok ( BIGINT ( 0xff, 0xff, 0xff ),
+				24 );
+	bigint_max_set_bit_ok ( BIGINT ( 0xee, 0xcb, 0x7b, 0xfd ),
+				32 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x01, 0xdd ),
+				9 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00 ),
+				0 );
+	bigint_max_set_bit_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff ),
+				32 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x32, 0x39, 0x96, 0x52, 0x10, 0x67,
+					 0x7e, 0x32, 0xfc, 0x4e, 0x56, 0xc3,
+					 0x68, 0x18, 0x76, 0x1a, 0xac, 0x0e,
+					 0x93, 0xee, 0x55, 0xc5, 0x6e ),
+				182 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0xc8, 0xe6, 0x59 ),
+				24 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00 ),
+				0 );
+	bigint_max_set_bit_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff ),
+				184 );
+	bigint_max_set_bit_ok ( BIGINT ( 0xcd, 0xb3, 0x22, 0x30, 0xdd, 0xa7,
+					 0xff, 0x37, 0xbf, 0xe3, 0x38, 0xf7,
+					 0xe1, 0x41, 0x73, 0xea, 0x3a, 0xfc,
+					 0x78, 0x9e, 0xfb, 0x4f, 0x85, 0xdc,
+					 0x1c, 0x40, 0x89, 0x6e, 0xda, 0xf9,
+					 0x9d, 0x6d, 0x12, 0x97, 0xb1, 0x80,
+					 0x2a, 0xeb, 0x91, 0xce, 0x3b, 0x83,
+					 0xb8, 0xa5, 0x3d, 0xce, 0x46, 0x56,
+					 0xb7, 0xd1, 0x28, 0xbc, 0x93, 0x4e,
+					 0x8c, 0x29, 0x6d, 0x2c, 0xcc, 0x58,
+					 0x49, 0x2f, 0x37, 0xa0, 0x08, 0x37,
+					 0x86, 0xdd, 0x38, 0x21, 0xa7, 0x57,
+					 0x37, 0xe3, 0xc5, 0xcc, 0x50, 0x11,
+					 0x1a, 0xe4, 0xea, 0xe7, 0x4d, 0x3c,
+					 0x37, 0x65, 0x78, 0xd1, 0xf6, 0xc3,
+					 0x94, 0x46, 0xd4, 0x0e, 0xd3, 0x9a,
+					 0x21, 0x8b, 0xa6, 0x54, 0xc0, 0xd2,
+					 0x88, 0x07, 0x24, 0xbf, 0x7d, 0x31,
+					 0xfd, 0x15, 0xa8, 0x92, 0x65, 0xe1,
+					 0x8d, 0xed, 0x70, 0x7b, 0x68, 0x0f,
+					 0xcc, 0x13, 0xb9, 0xb2, 0xdd, 0x3c,
+					 0x6a, 0x52 ),
+				1024 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x66, 0xd9,
+					 0x91, 0x18, 0x6e, 0xd3, 0xff, 0x9b,
+					 0xdf, 0xf1, 0x9c, 0x7b, 0xf0, 0xa0,
+					 0xb9, 0xf5 ),
+				127 );
+	bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+					 0x00, 0x00 ),
+				0 );
+	bigint_max_set_bit_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+					 0xff, 0xff ),
+				1024 );
+	bigint_multiply_ok ( BIGINT ( 0xf0 ),
+			     BIGINT ( 0xeb ),
+			     BIGINT ( 0xdc, 0x50 ) );
+	bigint_multiply_ok ( BIGINT ( 0xd7, 0x16 ),
+			     BIGINT ( 0x88, 0xfb ),
+			     BIGINT ( 0x73, 0x16, 0x92, 0x92 ) );
+	bigint_multiply_ok ( BIGINT ( 0xfe, 0xed, 0x1d ),
+			     BIGINT ( 0x69, 0x9c, 0x03 ),
+			     BIGINT ( 0x69, 0x2a, 0x9c, 0x5f, 0x73, 0x57 ) );
+	bigint_multiply_ok ( BIGINT ( 0x96, 0xe9, 0x6f, 0x81 ),
+			     BIGINT ( 0x67, 0x3c, 0x5a, 0x16 ),
+			     BIGINT ( 0x3c, 0xdb, 0x7f, 0xae, 0x12, 0x7e,
+				      0xef, 0x16 ) );
+	bigint_multiply_ok ( BIGINT ( 0xe8, 0x08, 0x0b, 0xe9, 0x29, 0x36,
+				      0xea, 0x51, 0x1d, 0x75, 0x1a, 0xd5,
+				      0xba, 0xc6, 0xa0, 0xf3, 0x48, 0x5c,
+				      0xdf, 0x42, 0xdf, 0x28, 0x38 ),
+			     BIGINT ( 0x22, 0x07, 0x41, 0x54, 0x4e, 0xf9,
+				      0x90, 0xa8, 0xaf, 0xba, 0xf6, 0xb0,
+				      0x35, 0x7e, 0x98, 0xef, 0x2c, 0x31,
+				      0xc9, 0xa7, 0x25, 0x74, 0x8d ),
+			     BIGINT ( 0x1e, 0xd7, 0xa5, 0x03, 0xc0, 0x18,
+				      0x2e, 0x29, 0xb1, 0x3e, 0x96, 0x71,
+				      0x90, 0xa5, 0x6d, 0x43, 0x58, 0xf7,
+				      0x22, 0x80, 0x0b, 0x21, 0xc6, 0x70,
+				      0x90, 0x1c, 0xa8, 0x85, 0x87, 0xaf,
+				      0xd7, 0xdd, 0x27, 0x69, 0xaf, 0x20,
+				      0xa0, 0x2d, 0x43, 0x5d, 0xda, 0xba,
+				      0x4b, 0x3a, 0x86, 0xd8 ) );
+	bigint_multiply_ok ( BIGINT ( 0xa2, 0x0f, 0xc6, 0x08, 0x0a, 0x01,
+				      0x19, 0x42, 0x0e, 0xaa, 0x5c, 0xae,
+				      0x4f, 0x4e, 0xb0, 0xad, 0xb2, 0xe8,
+				      0xee, 0xd5, 0x65, 0xec, 0x5a, 0xda,
+				      0xc0, 0xba, 0x78, 0xa8, 0x0f, 0x15,
+				      0x39, 0xd7, 0x7a, 0x10, 0xc2, 0xa7,
+				      0xec, 0x44, 0xac, 0xad, 0x39, 0x04,
+				      0x2e, 0x66, 0x54, 0x70, 0x57, 0xee,
+				      0xf6, 0x97, 0x19, 0x71, 0x16, 0xf9,
+				      0xbb, 0x2e, 0x84, 0x09, 0x6e, 0x9a,
+				      0x3b, 0x16, 0xb2, 0x65, 0x74, 0x50,
+				      0x19, 0xd1, 0xe9, 0x95, 0xa0, 0x7b,
+				      0x33, 0xb5, 0xac, 0x7c, 0x9e, 0xd4,
+				      0x68, 0x0d, 0xc9, 0xe4, 0x03, 0x86,
+				      0x1a, 0xa3, 0x42, 0x33, 0x28, 0x14,
+				      0x12, 0x7d, 0x5a, 0xd9, 0x30, 0x18,
+				      0x0a, 0xf4, 0x0c, 0x96, 0x58, 0xc9,
+				      0xb5, 0x37, 0xdb, 0x49, 0xdc, 0x01,
+				      0x4a, 0xcb, 0x6d, 0x87, 0x52, 0xf6,
+				      0xae, 0xa7, 0x71, 0x31, 0x9a, 0x1a,
+				      0xe2, 0x1c, 0x87, 0x51, 0xc9, 0xeb,
+				      0x70, 0x71 ),
+			     BIGINT ( 0x7c, 0xdd, 0x2f, 0x5d, 0x27, 0xfe,
+				      0xca, 0x70, 0x96, 0xc3, 0xb1, 0x1f,
+				      0xac, 0xa9, 0x3a, 0xdc, 0xcd, 0xbc,
+				      0x58, 0xb4, 0xde, 0xe7, 0xe5, 0x34,
+				      0x1a, 0xc0, 0xb9, 0x46, 0xf7, 0x52,
+				      0x76, 0x23, 0xe8, 0xe9, 0x92, 0xa1,
+				      0x86, 0x3c, 0x6f, 0xf1, 0x22, 0xf4,
+				      0x72, 0xb1, 0xde, 0xd3, 0x8f, 0x11,
+				      0x9e, 0x52, 0xe5, 0x81, 0x54, 0xe9,
+				      0xa7, 0x72, 0x3f, 0x3e, 0xa0, 0x80,
+				      0xbb, 0xae, 0x0e, 0x30, 0x6a, 0x11,
+				      0x91, 0x11, 0x3b, 0x3f, 0x44, 0x1f,
+				      0x8d, 0x4d, 0xea, 0xdd, 0x09, 0x95,
+				      0x9d, 0x02, 0xa6, 0x6d, 0x3b, 0x08,
+				      0x40, 0x8d, 0xb4, 0x4b, 0x05, 0x74,
+				      0x8c, 0x1f, 0xaa, 0x61, 0x6f, 0x0e,
+				      0xcc, 0xcf, 0xe0, 0x81, 0x03, 0xe4,
+				      0x9b, 0x11, 0xd9, 0xab, 0xf3, 0x24,
+				      0xe2, 0x3b, 0xe0, 0x05, 0x60, 0x65,
+				      0x16, 0xc6, 0x2e, 0x83, 0xa0, 0x98,
+				      0x8e, 0x11, 0x05, 0x00, 0xe4, 0x3f,
+				      0x7e, 0x65 ),
+			     BIGINT ( 0x4f, 0x0b, 0xa9, 0x85, 0xb8, 0x31,
+				      0x48, 0xea, 0x11, 0x44, 0xaf, 0x2d,
+				      0xed, 0x1a, 0x76, 0x45, 0xac, 0x87,
+				      0x0c, 0xf3, 0xd7, 0xc4, 0x8e, 0x5c,
+				      0xd7, 0xdf, 0x28, 0x74, 0xa6, 0x40,
+				      0xe4, 0x6b, 0x5b, 0x19, 0x36, 0x37,
+				      0x9c, 0xcd, 0x43, 0x76, 0x15, 0x00,
+				      0x5d, 0x23, 0xa2, 0x8a, 0x53, 0x25,
+				      0xbf, 0x18, 0xda, 0xe6, 0x09, 0xdf,
+				      0xaa, 0xeb, 0x9a, 0x82, 0x01, 0x14,
+				      0x2b, 0x20, 0x2b, 0xb6, 0x22, 0x62,
+				      0x6b, 0xcc, 0xd4, 0xc9, 0x02, 0x67,
+				      0x95, 0x43, 0x75, 0x4e, 0x97, 0x4e,
+				      0xec, 0x04, 0xde, 0x29, 0x0a, 0xef,
+				      0xf7, 0xc1, 0x72, 0x8c, 0x64, 0x38,
+				      0x16, 0x47, 0x9f, 0x16, 0x0c, 0xa5,
+				      0x79, 0x6b, 0xea, 0x2e, 0x4c, 0x3d,
+				      0x0c, 0xe6, 0x57, 0x51, 0x65, 0xa5,
+				      0x3b, 0xca, 0xae, 0x54, 0x0c, 0x67,
+				      0xf8, 0x23, 0x00, 0xc9, 0x8d, 0xe6,
+				      0x16, 0x91, 0x19, 0xb3, 0x5b, 0x68,
+				      0x7b, 0xf2, 0xe2, 0x5d, 0x69, 0x48,
+				      0x3f, 0x2b, 0xa0, 0x4f, 0x7c, 0x3c,
+				      0x26, 0xf9, 0xd9, 0xfd, 0x3d, 0x5d,
+				      0xd6, 0x05, 0x00, 0xd8, 0xdf, 0x5a,
+				      0x56, 0x8f, 0x16, 0x68, 0x4f, 0x15,
+				      0x19, 0x9d, 0xd7, 0x11, 0x51, 0x7d,
+				      0x73, 0x5c, 0xd4, 0xd5, 0xb4, 0xc7,
+				      0x42, 0xe3, 0xee, 0xf1, 0x67, 0xd6,
+				      0x69, 0x72, 0x04, 0x4b, 0x88, 0x3d,
+				      0x05, 0xd8, 0x1e, 0x50, 0xcb, 0xce,
+				      0x39, 0x19, 0x42, 0xb6, 0xa7, 0xf3,
+				      0xba, 0x78, 0x90, 0xd2, 0x09, 0x05,
+				      0x87, 0xf8, 0xc0, 0x9c, 0x47, 0xff,
+				      0xbf, 0xaa, 0x21, 0x8d, 0x81, 0x86,
+				      0xcd, 0x58, 0xdf, 0x30, 0xf1, 0xd1,
+				      0x60, 0x53, 0x85, 0x40, 0xbf, 0x14,
+				      0x3e, 0xdc, 0x9e, 0x9e, 0xc4, 0xc7,
+				      0x48, 0xa0, 0x83, 0xe0, 0x99, 0x8b,
+				      0x43, 0xf8, 0x52, 0x8a, 0x15, 0x88,
+				      0x89, 0x83, 0x7d, 0x71, 0xbb, 0x62,
+				      0x12, 0x7a, 0x23, 0x85, 0x3a, 0xbb,
+				      0xdb, 0x09, 0xfa, 0x95 ) );
+	bigint_multiply_ok ( BIGINT ( 0xff ),
+			     BIGINT ( 0xff ),
+			     BIGINT ( 0xfe, 0x01 ) );
+	bigint_multiply_ok ( BIGINT ( 0xff, 0xff ),
+			     BIGINT ( 0xff, 0xff ),
+			     BIGINT ( 0xff, 0xfe, 0x00, 0x01 ) );
+	bigint_multiply_ok ( BIGINT ( 0xff, 0xff, 0xff ),
+			     BIGINT ( 0xff, 0xff, 0xff ),
+			     BIGINT ( 0xff, 0xff, 0xfe, 0x00, 0x00, 0x01 ) );
+	bigint_multiply_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff ),
+			     BIGINT ( 0xff, 0xff, 0xff, 0xff ),
+			     BIGINT ( 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00,
+				      0x00, 0x01 ) );
+	bigint_multiply_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff ),
+			     BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff ),
+			     BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xfe, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x01 ) );
+	bigint_multiply_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff ),
+			     BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff ),
+			     BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xfe, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				      0x00, 0x00, 0x00, 0x01 ) );
+	bigint_mod_multiply_ok ( BIGINT ( 0x37 ),
+				 BIGINT ( 0x67 ),
+				 BIGINT ( 0x3f ),
+				 BIGINT ( 0x3a ) );
+	bigint_mod_multiply_ok ( BIGINT ( 0x45, 0x94 ),
+				 BIGINT ( 0xbd, 0xd2 ),
+				 BIGINT ( 0xca, 0xc7 ),
+				 BIGINT ( 0xac, 0xc1 ) );
+	bigint_mod_multiply_ok ( BIGINT ( 0x8e, 0xcd, 0x74 ),
+				 BIGINT ( 0xe2, 0xf1, 0xea ),
+				 BIGINT ( 0x59, 0x51, 0x53 ),
+				 BIGINT ( 0x22, 0xdd, 0x1c ) );
+	bigint_mod_multiply_ok ( BIGINT ( 0xc2, 0xa8, 0x40, 0x6f ),
+				 BIGINT ( 0x29, 0xd7, 0xf4, 0x77 ),
+				 BIGINT ( 0xbb, 0xbd, 0xdb, 0x3d ),
+				 BIGINT ( 0x8f, 0x39, 0xd0, 0x47 ) );
+	bigint_mod_multiply_ok ( BIGINT ( 0x2e, 0xcb, 0x74, 0x7c, 0x64, 0x60,
+					  0xb3, 0x44, 0xf3, 0x23, 0x49, 0x4a,
+					  0xc6, 0xb6, 0xbf, 0xea, 0x80, 0xd8,
+					  0x34, 0xc5, 0x54, 0x22, 0x09 ),
+				 BIGINT ( 0x61, 0x2c, 0x5a, 0xc5, 0xde, 0x07,
+					  0x65, 0x8e, 0xab, 0x88, 0x1a, 0x2e,
+					  0x7a, 0x95, 0x17, 0xe3, 0x3b, 0x17,
+					  0xe4, 0x21, 0xb0, 0xb4, 0x57 ),
+				 BIGINT ( 0x8e, 0x46, 0xa5, 0x87, 0x7b, 0x7f,
+					  0xc4, 0xd7, 0x31, 0xb1, 0x94, 0xe7,
+					  0xe7, 0x1c, 0x7e, 0x7a, 0xc2, 0x6c,
+					  0xce, 0xcb, 0xc8, 0x5d, 0x70 ),
+				 BIGINT ( 0x1e, 0xd1, 0x5b, 0x3d, 0x1d, 0x17,
+					  0x7c, 0x31, 0x95, 0x13, 0x1b, 0xd8,
+					  0xee, 0x0a, 0xb0, 0xe1, 0x5b, 0x13,
+					  0xad, 0x83, 0xe9, 0xf8, 0x7f ) );
+	bigint_mod_multiply_ok ( BIGINT ( 0x56, 0x37, 0xab, 0x07, 0x8b, 0x25,
+					  0xa7, 0xc2, 0x50, 0x30, 0x43, 0xfc,
+					  0x63, 0x8b, 0xdf, 0x84, 0x68, 0x85,
+					  0xca, 0xce, 0x44, 0x5c, 0xb1, 0x14,
+					  0xa4, 0xb5, 0xba, 0x43, 0xe0, 0x31,
+					  0x45, 0x6b, 0x82, 0xa9, 0x0b, 0x9e,
+					  0x3a, 0xb0, 0x39, 0x09, 0x2a, 0x68,
+					  0x2e, 0x0f, 0x09, 0x54, 0x47, 0x04,
+					  0xdb, 0xcf, 0x4a, 0x3a, 0x2d, 0x7b,
+					  0x7d, 0x50, 0xa4, 0xc5, 0xeb, 0x13,
+					  0xdd, 0x49, 0x61, 0x7d, 0x18, 0xa1,
+					  0x0d, 0x6b, 0x58, 0xba, 0x9f, 0x7c,
+					  0x81, 0x34, 0x9e, 0xf9, 0x9c, 0x9e,
+					  0x28, 0xa8, 0x1c, 0x15, 0x16, 0x20,
+					  0x3c, 0x0a, 0xb1, 0x11, 0x06, 0x93,
+					  0xbc, 0xd8, 0x4e, 0x49, 0xae, 0x7b,
+					  0xb4, 0x02, 0x8b, 0x1c, 0x5b, 0x18,
+					  0xb4, 0xac, 0x7f, 0xdd, 0x70, 0xef,
+					  0x87, 0xac, 0x1b, 0xac, 0x25, 0xa3,
+					  0xc9, 0xa7, 0x3a, 0xc5, 0x76, 0x68,
+					  0x09, 0x1f, 0xa1, 0x48, 0x53, 0xb6,
+					  0x13, 0xac ),
+				 BIGINT ( 0xef, 0x5c, 0x1f, 0x1a, 0x44, 0x64,
+					  0x66, 0xcf, 0xdd, 0x3f, 0x0b, 0x27,
+					  0x81, 0xa7, 0x91, 0x7a, 0x35, 0x7b,
+					  0x0f, 0x46, 0x5e, 0xca, 0xbf, 0xf8,
+					  0x50, 0x5e, 0x99, 0x7c, 0xc6, 0x64,
+					  0x43, 0x00, 0x9f, 0xb2, 0xda, 0xfa,
+					  0x42, 0x15, 0x9c, 0xa3, 0xd6, 0xc8,
+					  0x64, 0xa7, 0x65, 0x4a, 0x98, 0xf7,
+					  0xb3, 0x96, 0x5f, 0x42, 0xf9, 0x73,
+					  0xe1, 0x75, 0xc3, 0xc4, 0x0b, 0x5d,
+					  0x5f, 0xf3, 0x04, 0x8a, 0xee, 0x59,
+					  0xa6, 0x1b, 0x06, 0x38, 0x0b, 0xa2,
+					  0x9f, 0xb4, 0x4f, 0x6d, 0x50, 0x5e,
+					  0x37, 0x37, 0x21, 0x83, 0x9d, 0xa3,
+					  0x12, 0x16, 0x4d, 0xab, 0x36, 0x51,
+					  0x21, 0xb1, 0x74, 0x66, 0x40, 0x9a,
+					  0xd3, 0x72, 0xcc, 0x18, 0x40, 0x53,
+					  0x89, 0xff, 0xd7, 0x00, 0x8d, 0x7e,
+					  0x93, 0x81, 0xdb, 0x29, 0xb6, 0xd7,
+					  0x23, 0x2b, 0x67, 0x2f, 0x11, 0x98,
+					  0x49, 0x87, 0x2f, 0x46, 0xb7, 0x33,
+					  0x6d, 0x12 ),
+				 BIGINT ( 0x67, 0x7a, 0x17, 0x6a, 0xd2, 0xf8,
+					  0x49, 0xfb, 0x7c, 0x95, 0x25, 0x54,
+					  0xf0, 0xab, 0x5b, 0xb3, 0x0e, 0x01,
+					  0xab, 0xd3, 0x65, 0x6f, 0x7e, 0x18,
+					  0x05, 0xed, 0x9b, 0xc4, 0x90, 0x6c,
+					  0xd0, 0x6d, 0x94, 0x79, 0x28, 0xd6,
+					  0x24, 0x77, 0x9a, 0x08, 0xd2, 0x2f,
+					  0x7c, 0x2d, 0xa0, 0x0c, 0x14, 0xbe,
+					  0x7b, 0xee, 0x9e, 0x48, 0x88, 0x3c,
+					  0x8f, 0x9f, 0xb9, 0x7a, 0xcb, 0x98,
+					  0x76, 0x61, 0x0d, 0xee, 0xa2, 0x42,
+					  0x67, 0x1b, 0x2c, 0x42, 0x8f, 0x41,
+					  0xcc, 0x78, 0xba, 0xba, 0xaa, 0xa2,
+					  0x92, 0xb0, 0x6e, 0x0c, 0x4e, 0xe1,
+					  0xa5, 0x13, 0x7d, 0x8a, 0x8f, 0x81,
+					  0x95, 0x8a, 0xdf, 0x57, 0x93, 0x88,
+					  0x27, 0x4f, 0x1a, 0x59, 0xa4, 0x74,
+					  0x22, 0xa9, 0x78, 0xe5, 0xed, 0xb1,
+					  0x09, 0x26, 0x59, 0xde, 0x88, 0x21,
+					  0x8d, 0xa2, 0xa8, 0x58, 0x10, 0x7b,
+					  0x65, 0x96, 0xbf, 0x69, 0x3b, 0xc5,
+					  0x55, 0xf8 ),
+				 BIGINT ( 0x15, 0xf7, 0x00, 0xeb, 0xc7, 0x5a,
+					  0x6f, 0xf0, 0x50, 0xf3, 0x21, 0x8a,
+					  0x8e, 0xa6, 0xf6, 0x67, 0x56, 0x7d,
+					  0x07, 0x45, 0x89, 0xdb, 0xd7, 0x7e,
+					  0x9e, 0x28, 0x7f, 0xfb, 0xed, 0xca,
+					  0x2c, 0xbf, 0x47, 0x77, 0x99, 0x95,
+					  0xf3, 0xd6, 0x9d, 0xc5, 0x57, 0x81,
+					  0x7f, 0x97, 0xf2, 0x6b, 0x24, 0xee,
+					  0xce, 0xc5, 0x9b, 0xe6, 0x42, 0x2d,
+					  0x37, 0xb7, 0xeb, 0x3d, 0xb5, 0xf7,
+					  0x1e, 0x86, 0xc2, 0x40, 0x44, 0xc9,
+					  0x85, 0x5a, 0x1a, 0xc0, 0xac, 0x9e,
+					  0x78, 0x69, 0x00, 0x7b, 0x93, 0x65,
+					  0xd7, 0x7f, 0x0c, 0xd6, 0xba, 0x4f,
+					  0x06, 0x00, 0x61, 0x05, 0xb2, 0x44,
+					  0xb4, 0xe7, 0xbb, 0x3b, 0x96, 0xb0,
+					  0x6d, 0xe8, 0x43, 0xd2, 0x03, 0xb7,
+					  0x0a, 0xc4, 0x6d, 0x30, 0xd8, 0xd5,
+					  0xe6, 0x54, 0x65, 0xdd, 0xa9, 0x1b,
+					  0x50, 0xc0, 0xb9, 0x95, 0xb0, 0x7d,
+					  0x7c, 0xca, 0x63, 0xf8, 0x72, 0xbe,
+					  0x3b, 0x00 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xcd ),
+			    BIGINT ( 0xbb ),
+			    BIGINT ( 0x25 ),
+			    BIGINT ( 0xab ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xc4 ),
+			    BIGINT ( 0xe9 ),
+			    BIGINT ( 0x02, 0x4c ),
+			    BIGINT ( 0x7e ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xcb ),
+			    BIGINT ( 0xde ),
+			    BIGINT ( 0xbd, 0x73, 0xbf ),
+			    BIGINT ( 0x17 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x17 ),
+			    BIGINT ( 0xb9 ),
+			    BIGINT ( 0x39, 0x68, 0xba, 0x7d ),
+			    BIGINT ( 0x17 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x2e ),
+			    BIGINT ( 0xb7 ),
+			    BIGINT ( 0x39, 0x07, 0x1b, 0x49, 0x5b, 0xea,
+				     0xf2, 0x61, 0x75, 0x94, 0x60, 0x86,
+				     0x73, 0xd0, 0xeb, 0x11, 0x08, 0x19,
+				     0x90, 0x19, 0xe0, 0xed, 0x2a ),
+			    BIGINT ( 0x19 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x59 ),
+			    BIGINT ( 0xce ),
+			    BIGINT ( 0xdf, 0xbc, 0x0d, 0x0c, 0x09, 0xeb,
+				     0xf8, 0xcf, 0xdb, 0xb6, 0x00, 0xa3,
+				     0x9e, 0xc3, 0x6c, 0x8d, 0xf1, 0xc3,
+				     0x03, 0x36, 0xaa, 0xd4, 0x22, 0x7c,
+				     0x20, 0x7b, 0xa9, 0x9a, 0x01, 0xe4,
+				     0xf2, 0x50, 0x42, 0x29, 0x68, 0x7a,
+				     0xa6, 0x2c, 0xdf, 0xb6, 0x51, 0xa9,
+				     0x73, 0x10, 0x98, 0x37, 0x69, 0xb3,
+				     0x21, 0x49, 0x6d, 0xcc, 0x80, 0xfa,
+				     0x7e, 0x12, 0xe4, 0x9c, 0xc2, 0xbb,
+				     0xe3, 0xa3, 0x10, 0x3f, 0xba, 0x99,
+				     0x22, 0x79, 0x71, 0x39, 0x96, 0x7b,
+				     0x1a, 0x89, 0xdc, 0xda, 0x43, 0x52,
+				     0x50, 0x7b, 0xe3, 0x8c, 0xd3, 0xc0,
+				     0xf5, 0x7d, 0xfc, 0x80, 0x71, 0x6e,
+				     0xaf, 0x5c, 0xd0, 0x14, 0xc0, 0x60,
+				     0x24, 0xa8, 0x9a, 0x8a, 0x54, 0x4a,
+				     0x6f, 0x42, 0x7a, 0x14, 0x14, 0x25,
+				     0xd5, 0x22, 0x08, 0x8f, 0xd9, 0xdb,
+				     0xd4, 0x0f, 0x14, 0xf4, 0x3b, 0x26,
+				     0x0e, 0xb6, 0x72, 0xd7, 0x03, 0xd5,
+				     0xf0, 0x0e ),
+			    BIGINT ( 0xa9 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x7f, 0x30 ),
+			    BIGINT ( 0x73, 0x74 ),
+			    BIGINT ( 0x75 ),
+			    BIGINT ( 0x4b, 0xe8 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x04, 0x6c ),
+			    BIGINT ( 0x99, 0x04 ),
+			    BIGINT ( 0x33, 0xd2 ),
+			    BIGINT ( 0x86, 0x74 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xca, 0x88 ),
+			    BIGINT ( 0xdc, 0x60 ),
+			    BIGINT ( 0x7e, 0x76, 0x79 ),
+			    BIGINT ( 0x42, 0x40 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x68, 0x97 ),
+			    BIGINT ( 0x52, 0x8b ),
+			    BIGINT ( 0x4f, 0x7f, 0xe7, 0xda ),
+			    BIGINT ( 0x22, 0x77 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xbd, 0x14 ),
+			    BIGINT ( 0x9e, 0xfc ),
+			    BIGINT ( 0x23, 0xf7, 0xd0, 0xa1, 0x9e, 0x9b,
+				     0x05, 0xd2, 0x44, 0x24, 0x4f, 0x3f,
+				     0x83, 0xcc, 0x49, 0x70, 0xa5, 0x0d,
+				     0xfc, 0xa7, 0x43, 0xf3, 0x3e ),
+			    BIGINT ( 0x1a, 0xc8 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x46, 0x3e ),
+			    BIGINT ( 0xb8, 0xde ),
+			    BIGINT ( 0xa9, 0xc0, 0xdc, 0x45, 0x65, 0x0d,
+				     0xa5, 0x56, 0x70, 0x4c, 0xf1, 0xda,
+				     0xab, 0x64, 0xc2, 0x04, 0xf6, 0x32,
+				     0x20, 0x68, 0x31, 0x5f, 0x9a, 0x00,
+				     0x0f, 0x7b, 0x24, 0x33, 0xdf, 0xaf,
+				     0xfe, 0x03, 0x1e, 0x4a, 0xa1, 0xf8,
+				     0x45, 0x8d, 0x5a, 0x7d, 0x12, 0x58,
+				     0x00, 0x6d, 0xba, 0x79, 0x9f, 0xe1,
+				     0xa1, 0xfc, 0x1f, 0xb9, 0xf3, 0xa7,
+				     0x07, 0xf5, 0xfe, 0xd6, 0xa1, 0xba,
+				     0xda, 0x63, 0xef, 0x39, 0x8e, 0xb7,
+				     0x48, 0xa8, 0x81, 0x86, 0xb1, 0x22,
+				     0x14, 0x9f, 0x9e, 0xac, 0x69, 0xf7,
+				     0xae, 0x1f, 0xf2, 0x99, 0x41, 0xb7,
+				     0x37, 0xa7, 0xbc, 0x42, 0xf2, 0x45,
+				     0x43, 0xf2, 0x2a, 0xef, 0xc2, 0x83,
+				     0xd5, 0x32, 0x6e, 0xfa, 0x49, 0x1c,
+				     0x94, 0x9c, 0xc2, 0xc5, 0xad, 0x28,
+				     0x53, 0x1c, 0x11, 0xc4, 0x1c, 0x78,
+				     0x8f, 0x13, 0xdc, 0xb3, 0x2a, 0x63,
+				     0xfd, 0x1f, 0x89, 0x9b, 0x0c, 0x31,
+				     0x92, 0x73 ),
+			    BIGINT ( 0x7b, 0x8a ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xf3, 0xc3, 0xab ),
+			    BIGINT ( 0xd0, 0x7e, 0xd0 ),
+			    BIGINT ( 0xf6 ),
+			    BIGINT ( 0x1f, 0xb3, 0x09 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x13, 0xec, 0xf6 ),
+			    BIGINT ( 0x87, 0x1a, 0x9a ),
+			    BIGINT ( 0x03, 0xf3 ),
+			    BIGINT ( 0x15, 0xe9, 0x8e ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x5a, 0x96, 0xe5 ),
+			    BIGINT ( 0x56, 0x4a, 0xd1 ),
+			    BIGINT ( 0x89, 0x62, 0x8e ),
+			    BIGINT ( 0x34, 0xb8, 0xaa ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x84, 0x7c, 0xbd ),
+			    BIGINT ( 0x3c, 0x80, 0x0a ),
+			    BIGINT ( 0x5e, 0x52, 0x9d, 0xba ),
+			    BIGINT ( 0x04, 0xcb, 0x4f ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x50, 0x01, 0x51 ),
+			    BIGINT ( 0x02, 0xe6, 0x96 ),
+			    BIGINT ( 0x34, 0x0c, 0x7e, 0xbf, 0x27, 0x23,
+				     0x46, 0x92, 0x1c, 0xca, 0x91, 0xab,
+				     0x50, 0x2c, 0x3a, 0x64, 0xc8, 0x4a,
+				     0x75, 0xd6, 0xe2, 0xde, 0x31 ),
+			    BIGINT ( 0x02, 0x16, 0x05 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x5e, 0x47, 0xd8 ),
+			    BIGINT ( 0x26, 0xd1, 0xb6 ),
+			    BIGINT ( 0x49, 0x61, 0x84, 0x7a, 0xa9, 0xfb,
+				     0x93, 0x45, 0xe4, 0xfa, 0x53, 0x60,
+				     0x73, 0x98, 0x5a, 0x17, 0xe7, 0x77,
+				     0x2d, 0xcd, 0x97, 0xf4, 0xc0, 0x34,
+				     0x46, 0xfa, 0xbd, 0x21, 0xdf, 0xa5,
+				     0xa0, 0x12, 0x38, 0x7c, 0xbd, 0xd9,
+				     0xcd, 0xbc, 0xde, 0x29, 0xa5, 0x13,
+				     0xa8, 0xf0, 0xf6, 0x88, 0xc6, 0x31,
+				     0xed, 0x90, 0x19, 0x11, 0x7d, 0xe1,
+				     0x0e, 0x81, 0x98, 0x8e, 0x98, 0x86,
+				     0xde, 0x2a, 0x4c, 0xad, 0xff, 0x57,
+				     0x12, 0xbc, 0x4b, 0xaf, 0x21, 0xde,
+				     0xca, 0x3a, 0x25, 0xd7, 0x98, 0xe3,
+				     0x25, 0xbc, 0x17, 0x74, 0x0b, 0x9c,
+				     0x53, 0xe1, 0x1a, 0xec, 0x9a, 0x5a,
+				     0xdc, 0x68, 0xdf, 0xad, 0xd6, 0x71,
+				     0x6b, 0x5b, 0x8b, 0x85, 0xbb, 0xe5,
+				     0xd5, 0x14, 0x4c, 0x30, 0x27, 0x68,
+				     0xd1, 0xf7, 0x58, 0x34, 0x4c, 0xe1,
+				     0x71, 0xde, 0x7b, 0x8d, 0xa2, 0xe6,
+				     0x0a, 0x44, 0x22, 0x26, 0x5a, 0x70,
+				     0xbb, 0x68 ),
+			    BIGINT ( 0x18, 0x36, 0x96 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xc7, 0x4a, 0xf0, 0x48 ),
+			    BIGINT ( 0x5d, 0x27, 0x07, 0x54 ),
+			    BIGINT ( 0x4a ),
+			    BIGINT ( 0x48, 0x68, 0x7b, 0xe0 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xb4, 0x89, 0xc9, 0x5b ),
+			    BIGINT ( 0x7c, 0xd7, 0xc7, 0xff ),
+			    BIGINT ( 0xc6, 0x9c ),
+			    BIGINT ( 0x0b, 0x2d, 0xf8, 0xf7 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xea, 0x72, 0x43, 0xfe ),
+			    BIGINT ( 0xfc, 0x57, 0x2d, 0x47 ),
+			    BIGINT ( 0x60, 0x01, 0x2c ),
+			    BIGINT ( 0x12, 0x01, 0xe3, 0xf5 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x81, 0x7f, 0x27, 0x94 ),
+			    BIGINT ( 0x17, 0x21, 0x67, 0xab ),
+			    BIGINT ( 0x50, 0x19, 0x12, 0x52 ),
+			    BIGINT ( 0x05, 0x17, 0x6b, 0x13 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x38, 0xab, 0xd4, 0xec ),
+			    BIGINT ( 0x0c, 0x2a, 0x56, 0x38 ),
+			    BIGINT ( 0x2f, 0x85, 0x85, 0x57, 0xf6, 0xde,
+				     0x24, 0xb4, 0x28, 0x3c, 0x5a, 0x3c,
+				     0x0b, 0x12, 0x85, 0x85, 0x85, 0x98,
+				     0x46, 0x5b, 0x9c, 0x52, 0x3a ),
+			    BIGINT ( 0x02, 0xe6, 0x6a, 0x70 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xa6, 0x35, 0xc0, 0x6f ),
+			    BIGINT ( 0x23, 0xac, 0x78, 0x72 ),
+			    BIGINT ( 0x6a, 0x07, 0x80, 0xbf, 0x1b, 0xa5,
+				     0xf8, 0x0b, 0x90, 0x06, 0xa4, 0xa5,
+				     0x44, 0x13, 0xba, 0x4b, 0xb3, 0xce,
+				     0x9f, 0x55, 0x42, 0x56, 0xc3, 0x30,
+				     0x82, 0x85, 0x5a, 0x3b, 0xae, 0x88,
+				     0x92, 0x4e, 0x3c, 0x37, 0xf6, 0x80,
+				     0x4c, 0x03, 0x3c, 0x1e, 0x2c, 0x17,
+				     0xef, 0x9d, 0xd7, 0x6f, 0xdc, 0xbb,
+				     0x42, 0x42, 0xa1, 0x7f, 0x97, 0x66,
+				     0xcd, 0xc8, 0x8a, 0x7c, 0xc6, 0x70,
+				     0x61, 0x54, 0x82, 0xd0, 0xd0, 0x8b,
+				     0xd5, 0x4f, 0x57, 0x7b, 0x8e, 0xab,
+				     0xdc, 0xbf, 0x8e, 0x85, 0x94, 0x83,
+				     0x8a, 0xb3, 0x72, 0x69, 0x2d, 0x51,
+				     0xdd, 0x86, 0x1e, 0x58, 0xb8, 0x00,
+				     0xe2, 0x5e, 0xa7, 0xef, 0x6a, 0x6a,
+				     0xb0, 0x10, 0x3d, 0x53, 0xfe, 0x23,
+				     0x51, 0xc0, 0x51, 0xed, 0x1f, 0x02,
+				     0x4b, 0x73, 0x17, 0x59, 0xfa, 0xb9,
+				     0xa8, 0x05, 0xa7, 0x79, 0xc3, 0xc9,
+				     0x4c, 0x2d, 0x58, 0x59, 0x10, 0x99,
+				     0x71, 0xe6 ),
+			    BIGINT ( 0x01, 0x63, 0xd0, 0x07 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xff, 0x2a, 0x37, 0x04, 0xd4, 0x08,
+				     0x9f, 0xf5, 0xac, 0x29, 0x7f, 0x4b,
+				     0x93, 0x86, 0x02, 0x26, 0xac, 0x29,
+				     0xa8, 0xf9, 0x77, 0x91, 0x20 ),
+			    BIGINT ( 0x2c, 0xb2, 0xe2, 0x1f, 0x4b, 0x97,
+				     0xaa, 0x3b, 0xd1, 0x36, 0xb0, 0x40,
+				     0x8b, 0x1c, 0x19, 0xa2, 0xea, 0xc8,
+				     0xc6, 0x4e, 0x2a, 0x66, 0x50 ),
+			    BIGINT ( 0x97 ),
+			    BIGINT ( 0x04, 0x22, 0x44, 0xe2, 0x14, 0x54,
+				     0x6c, 0x5a, 0xba, 0x1b, 0x39, 0xb7,
+				     0xaa, 0x06, 0xcf, 0x2b, 0xc8, 0x7e,
+				     0xc0, 0xe0, 0x70, 0xf2, 0x90 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xcd, 0xf3, 0xf7, 0x50, 0x13, 0x39,
+				     0x13, 0x4a, 0x56, 0xc5, 0xb8, 0xa6,
+				     0x42, 0x2d, 0x40, 0x5e, 0x07, 0xf2,
+				     0x92, 0x2a, 0x51, 0x87, 0x20 ),
+			    BIGINT ( 0x93, 0x1a, 0x28, 0xbb, 0x69, 0x4f,
+				     0x31, 0x01, 0xe0, 0x88, 0x8a, 0x4c,
+				     0x4f, 0x9b, 0xda, 0xf6, 0x4e, 0xf3,
+				     0x11, 0xe7, 0x35, 0xa1, 0xfb ),
+			    BIGINT ( 0x66, 0x69 ),
+			    BIGINT ( 0x7a, 0x5a, 0x9b, 0x84, 0x72, 0x8f,
+				     0x57, 0x31, 0xb4, 0x34, 0x70, 0x18,
+				     0x77, 0xa6, 0x43, 0xa9, 0x51, 0x69,
+				     0x07, 0x3e, 0xf6, 0x68, 0x82 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xdd, 0x4c, 0x85, 0xcb, 0x3f, 0x45,
+				     0x61, 0xe0, 0x58, 0x1e, 0xad, 0xd3,
+				     0x6b, 0xef, 0x82, 0x53, 0x4a, 0x16,
+				     0x1a, 0xf0, 0x09, 0x82, 0x74 ),
+			    BIGINT ( 0xd2, 0xa2, 0x73, 0x89, 0x0c, 0x56,
+				     0xe4, 0x31, 0xdf, 0x70, 0x3c, 0x40,
+				     0x0d, 0x36, 0xfc, 0x4a, 0xf3, 0xa2,
+				     0x8f, 0x9a, 0x9d, 0xaa, 0xb0 ),
+			    BIGINT ( 0xbc, 0xca, 0x45 ),
+			    BIGINT ( 0x9f, 0x5f, 0x7c, 0xac, 0x5e, 0xc7,
+				     0xf2, 0xc5, 0x72, 0x3d, 0xff, 0x29,
+				     0xd2, 0x25, 0xa9, 0x64, 0x5b, 0xbe,
+				     0x63, 0x63, 0xc6, 0x84, 0x20 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xf8, 0xc9, 0xb9, 0x3d, 0xe1, 0xff,
+				     0xa6, 0x8e, 0xb0, 0xd2, 0xa9, 0xa9,
+				     0xc1, 0x5c, 0xc5, 0x94, 0x90, 0xb9,
+				     0xca, 0x2f, 0x1a, 0xbd, 0x21 ),
+			    BIGINT ( 0xa7, 0xf4, 0xb0, 0x3c, 0xf4, 0x2b,
+				     0x9d, 0x40, 0x5f, 0xfd, 0x2e, 0x28,
+				     0xa9, 0x23, 0x01, 0xaf, 0x0b, 0x73,
+				     0xaa, 0xcf, 0x14, 0xdc, 0xd8 ),
+			    BIGINT ( 0x31, 0xe2, 0xe8, 0xf0 ),
+			    BIGINT ( 0x53, 0x30, 0xc6, 0x10, 0x12, 0x7c,
+				     0xb3, 0x91, 0x15, 0x5f, 0x01, 0x62,
+				     0xec, 0x1f, 0x15, 0x61, 0x3b, 0x9a,
+				     0x76, 0x22, 0xf8, 0x31, 0xb1 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xff, 0x8c, 0x04, 0x74, 0x3e, 0x93,
+				     0xfd, 0xce, 0xd5, 0x7f, 0xc5, 0x58,
+				     0xce, 0x00, 0x53, 0x44, 0x02, 0xf4,
+				     0xfd, 0x01, 0xc3, 0xb0, 0x3c ),
+			    BIGINT ( 0x2f, 0xbe, 0xb3, 0x2d, 0xd6, 0x59,
+				     0x69, 0x44, 0xc0, 0xd4, 0x27, 0x9c,
+				     0xff, 0x53, 0x9e, 0x66, 0x2c, 0x01,
+				     0x3a, 0x96, 0x5d, 0x75, 0xc1 ),
+			    BIGINT ( 0x47, 0x3e, 0xb2, 0x81, 0x51, 0x9a,
+				     0xdf, 0x75, 0xba, 0xa5, 0x19, 0xc1,
+				     0xc7, 0xcc, 0xae, 0x82, 0x9c, 0x3e,
+				     0xfd, 0x7f, 0xb0, 0xd7, 0x00 ),
+			    BIGINT ( 0x09, 0x9c, 0xd0, 0x49, 0x1d, 0x88,
+				     0xd8, 0x08, 0x45, 0x61, 0x71, 0xa1,
+				     0xb5, 0xab, 0xa9, 0x5b, 0xa8, 0xf1,
+				     0xc6, 0x53, 0x68, 0x8f, 0x3e ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xd8, 0x78, 0xad, 0x80, 0x81, 0xf1,
+				     0x84, 0x23, 0x82, 0x5d, 0x49, 0x46,
+				     0x75, 0xfd, 0xd1, 0x49, 0x53, 0x10,
+				     0x4d, 0x10, 0xab, 0x0f, 0xf0 ),
+			    BIGINT ( 0x78, 0x3d, 0x09, 0x1b, 0xea, 0xa4,
+				     0xb9, 0x13, 0xf8, 0xb5, 0xb5, 0x5e,
+				     0x69, 0xa4, 0xe1, 0xfd, 0x88, 0x58,
+				     0x26, 0xb3, 0x76, 0xa2, 0x38 ),
+			    BIGINT ( 0x3b, 0x12, 0xe0, 0x8e, 0xa2, 0x2f,
+				     0x2a, 0x2b, 0xb1, 0x78, 0xf9, 0xf6,
+				     0x93, 0x4d, 0x52, 0x82, 0x29, 0x2d,
+				     0xe4, 0x36, 0x92, 0x49, 0xc1, 0x25,
+				     0x6e, 0x26, 0xe6, 0x6e, 0xc2, 0x4d,
+				     0xea, 0x13, 0x86, 0x85, 0x71, 0x4d,
+				     0x85, 0x70, 0xf9, 0x2b, 0xa0, 0x0f,
+				     0x96, 0xe5, 0x63, 0x7a, 0xb4, 0x25,
+				     0x53, 0x1a, 0xd8, 0x30, 0x36, 0xba,
+				     0x6e, 0x2e, 0xce, 0x2d, 0x8f, 0x32,
+				     0xe9, 0xdc, 0x91, 0x9e, 0xd4, 0xf1,
+				     0x3b, 0x40, 0xc9, 0xf4, 0x97, 0x74,
+				     0x5e, 0x69, 0xcd, 0x34, 0x4a, 0x18,
+				     0x65, 0xe5, 0x07, 0xb5, 0x9e, 0x2a,
+				     0xc4, 0xeb, 0xb6, 0x96, 0x7b, 0x99,
+				     0x0c, 0xe4, 0xb3, 0x85, 0xff, 0x17,
+				     0x72, 0x5d, 0xf6, 0x30, 0xb4, 0xff,
+				     0x98, 0xe6, 0xf6, 0x31, 0x24, 0x82,
+				     0x91, 0xa6, 0x18, 0x6d, 0x0b, 0x84,
+				     0x6f, 0x5f, 0x64, 0xa3, 0xdf, 0x92,
+				     0x06, 0x16, 0xe3, 0x7c, 0x08, 0x61,
+				     0x77, 0xce ),
+			    BIGINT ( 0x17, 0xc9, 0xc5, 0x38, 0x4c, 0x15,
+				     0x0f, 0x4e, 0xc2, 0x90, 0x3b, 0x46,
+				     0x7b, 0x2f, 0x95, 0x82, 0xfe, 0x51,
+				     0x95, 0x2b, 0xff, 0xd5, 0x28 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x69, 0xa3, 0x7e, 0x24, 0xdf, 0x9e,
+				     0x0b, 0x3e, 0x3f, 0x43, 0x06, 0x0e,
+				     0x1d, 0x57, 0x74, 0xe0, 0xa0, 0x5b,
+				     0x82, 0xca, 0xb0, 0x33, 0x8b, 0xe4,
+				     0x39, 0x27, 0x41, 0xd4, 0x2e, 0x30,
+				     0x3a, 0x0e, 0x62, 0x6f, 0xfa, 0xb4,
+				     0x02, 0x88, 0x70, 0x35, 0xa6, 0xea,
+				     0x7d, 0xb2, 0x87, 0xc3, 0xa5, 0x50,
+				     0x49, 0x38, 0xa4, 0x68, 0xa9, 0xe4,
+				     0xa6, 0xcc, 0xd7, 0x13, 0xb1, 0xd9,
+				     0x1c, 0x6a, 0x9a, 0xb8, 0x6c, 0x9b,
+				     0xff, 0xcd, 0x2c, 0xb3, 0xbd, 0xe2,
+				     0xfd, 0x1f, 0x08, 0xdd, 0xc6, 0xee,
+				     0x18, 0x0c, 0xa5, 0xcd, 0x09, 0x19,
+				     0x51, 0x51, 0xa5, 0x6f, 0x93, 0x1b,
+				     0x34, 0xfd, 0x8f, 0xd9, 0x87, 0xed,
+				     0x15, 0x7e, 0x36, 0x60, 0xdd, 0x1b,
+				     0xf4, 0xcc, 0xc4, 0x4c, 0x19, 0x2b,
+				     0xd6, 0x1e, 0xec, 0x51, 0xe9, 0x27,
+				     0xe9, 0xbd, 0x6a, 0x3f, 0x91, 0x45,
+				     0xc3, 0x6d, 0x40, 0x7e, 0x6c, 0x56,
+				     0x05, 0x5a ),
+			    BIGINT ( 0x5c, 0x96, 0x05, 0x81, 0x94, 0x45,
+				     0xcf, 0x47, 0x5f, 0x1b, 0xb0, 0xf9,
+				     0xef, 0x13, 0x8f, 0xcc, 0x71, 0xfd,
+				     0x50, 0xf1, 0xe7, 0x62, 0x6e, 0xfa,
+				     0x48, 0x66, 0x1c, 0xf7, 0xef, 0x09,
+				     0x12, 0xa2, 0xfd, 0x17, 0xb7, 0x6a,
+				     0x3b, 0xed, 0xf7, 0x86, 0xd2, 0xbe,
+				     0x95, 0x90, 0xc6, 0x00, 0x14, 0x8d,
+				     0xe3, 0x27, 0xbe, 0x03, 0x7c, 0x9e,
+				     0x6b, 0x51, 0x31, 0x8d, 0x18, 0xc4,
+				     0x16, 0xd2, 0x84, 0x63, 0x9b, 0xe9,
+				     0xa4, 0xf8, 0xff, 0x70, 0x4d, 0xeb,
+				     0x6f, 0x4a, 0xb7, 0x5b, 0x54, 0xf1,
+				     0xb5, 0xbe, 0x78, 0xb6, 0xfd, 0x8b,
+				     0xe1, 0x39, 0x62, 0x85, 0x9b, 0xde,
+				     0x30, 0xa8, 0xe4, 0x37, 0x52, 0x57,
+				     0x39, 0x79, 0xdb, 0x0b, 0x19, 0x6b,
+				     0xc9, 0x17, 0xfd, 0x8c, 0x2c, 0xaa,
+				     0xa4, 0xf1, 0x04, 0xd1, 0xd3, 0x2f,
+				     0xbb, 0x3a, 0x36, 0x82, 0x31, 0xa4,
+				     0x40, 0xd4, 0x87, 0x46, 0xe3, 0x6e,
+				     0xd0, 0x17 ),
+			    BIGINT ( 0x93 ),
+			    BIGINT ( 0x0d, 0x39, 0x92, 0x57, 0xaa, 0x6d,
+				     0xfc, 0x3b, 0x10, 0x18, 0x6d, 0x59,
+				     0xbe, 0x31, 0x8f, 0xee, 0xf9, 0x82,
+				     0x84, 0xe0, 0xdf, 0xa5, 0x00, 0x28,
+				     0xd1, 0x64, 0x6b, 0x4b, 0x43, 0x3b,
+				     0x76, 0x3e, 0x6b, 0xc4, 0xe4, 0xf5,
+				     0x0b, 0x59, 0x5a, 0xe4, 0x53, 0x5e,
+				     0x02, 0xd4, 0xde, 0x72, 0xd3, 0xa3,
+				     0x58, 0x66, 0xa7, 0xdd, 0x2b, 0x0b,
+				     0xa4, 0x83, 0xd0, 0xd9, 0xef, 0x29,
+				     0x3d, 0x2f, 0x97, 0xff, 0x9a, 0xc7,
+				     0xf6, 0x8a, 0x8d, 0x59, 0xef, 0x87,
+				     0xd1, 0xe6, 0xba, 0x4d, 0x99, 0xd9,
+				     0x5f, 0x5e, 0x7a, 0x7e, 0x67, 0x22,
+				     0x5b, 0x77, 0x83, 0xa2, 0x02, 0xfd,
+				     0xb2, 0xe4, 0xf6, 0x20, 0x4c, 0x12,
+				     0x20, 0xa7, 0xda, 0x5b, 0x3b, 0x8c,
+				     0xa2, 0xca, 0xda, 0x20, 0xaa, 0x27,
+				     0xe6, 0x54, 0x3e, 0xa8, 0x6f, 0x64,
+				     0x9d, 0xa7, 0x0d, 0x57, 0x1b, 0x21,
+				     0xff, 0xd2, 0xe2, 0xb2, 0x0a, 0x4f,
+				     0xb7, 0x0e ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x06, 0xcf, 0x54, 0xf2, 0x0d, 0x62,
+				     0x33, 0xdd, 0xe7, 0x4d, 0x7f, 0x2f,
+				     0x8e, 0x52, 0x73, 0xf4, 0x73, 0x68,
+				     0x4b, 0x13, 0x6e, 0x58, 0x6b, 0x4a,
+				     0xb8, 0x4c, 0xef, 0x73, 0xfe, 0x5f,
+				     0xf6, 0xd0, 0xbb, 0x82, 0x17, 0x3f,
+				     0x9d, 0x91, 0xf8, 0xa3, 0xb8, 0x79,
+				     0xef, 0x41, 0x38, 0xc1, 0xef, 0xc9,
+				     0xc6, 0xcf, 0x2a, 0xc3, 0xaa, 0x75,
+				     0x17, 0xda, 0xbc, 0x76, 0x29, 0x61,
+				     0x6d, 0x05, 0x79, 0x0b, 0x44, 0xb1,
+				     0x54, 0x75, 0xb7, 0xd9, 0xf6, 0xa8,
+				     0xbd, 0xf7, 0x85, 0xe0, 0xe7, 0x90,
+				     0x62, 0xce, 0x79, 0xfb, 0xc5, 0x23,
+				     0xa5, 0x09, 0xc0, 0xc4, 0x4d, 0xe7,
+				     0x9c, 0x49, 0x8f, 0x82, 0xf1, 0x31,
+				     0x34, 0x85, 0xdd, 0x3b, 0xbe, 0xe9,
+				     0x93, 0x19, 0x03, 0x75, 0x3f, 0xc4,
+				     0xa4, 0x0f, 0x52, 0x53, 0xc1, 0xcd,
+				     0x08, 0xb0, 0x05, 0x0c, 0xa2, 0x0c,
+				     0x3a, 0x72, 0xb2, 0x3c, 0xdb, 0x4f,
+				     0xac, 0xc6 ),
+			    BIGINT ( 0xe4, 0x40, 0xd8, 0x30, 0x00, 0xcf,
+				     0x4c, 0xfd, 0xda, 0xae, 0x90, 0xd3,
+				     0x5b, 0xc7, 0x20, 0xcc, 0x2b, 0xe2,
+				     0x0a, 0x39, 0x1e, 0xde, 0xef, 0x98,
+				     0x16, 0x3b, 0x9d, 0x36, 0x63, 0x0d,
+				     0x46, 0xed, 0x23, 0x6e, 0x38, 0xa8,
+				     0x15, 0xb5, 0xb1, 0xaf, 0x47, 0xb1,
+				     0xec, 0xaa, 0x8b, 0x57, 0xd6, 0xca,
+				     0x39, 0x2f, 0x62, 0xbd, 0xd5, 0xf8,
+				     0x98, 0x98, 0x5d, 0xfe, 0x14, 0xd6,
+				     0xdc, 0xe5, 0x98, 0x60, 0x5b, 0x16,
+				     0x92, 0xcb, 0xed, 0xb6, 0x9c, 0x5c,
+				     0x82, 0x40, 0x6b, 0xaa, 0x48, 0x7a,
+				     0xd4, 0xfe, 0xa3, 0xe7, 0x30, 0xf1,
+				     0x7c, 0xfb, 0x94, 0x2e, 0xeb, 0xb6,
+				     0x71, 0xe4, 0x33, 0x63, 0xc3, 0xb0,
+				     0x94, 0x6d, 0xee, 0xa5, 0x15, 0x3f,
+				     0x28, 0xf1, 0xfa, 0xdc, 0xf2, 0x13,
+				     0x0f, 0xc7, 0xd9, 0xe0, 0xbf, 0x1b,
+				     0x49, 0xee, 0x21, 0x8e, 0x26, 0xc9,
+				     0x28, 0x21, 0x86, 0x1d, 0x46, 0x33,
+				     0xd4, 0x69 ),
+			    BIGINT ( 0xd9, 0x87 ),
+			    BIGINT ( 0xdf, 0xff, 0xcc, 0xb7, 0xfe, 0x19,
+				     0x02, 0x92, 0x9d, 0xab, 0x33, 0xd2,
+				     0x21, 0xbc, 0xd3, 0xc4, 0x31, 0xad,
+				     0x4b, 0xb3, 0x16, 0x50, 0x96, 0xd9,
+				     0xdc, 0x88, 0x74, 0x60, 0xde, 0xdf,
+				     0xb7, 0x83, 0xdb, 0x22, 0xef, 0xcb,
+				     0xcb, 0xdb, 0x4c, 0xfb, 0x94, 0x4c,
+				     0x3f, 0xf5, 0xf5, 0x99, 0x85, 0x21,
+				     0x1a, 0x2b, 0xec, 0x90, 0x2d, 0xb4,
+				     0x20, 0x3c, 0x27, 0x9f, 0xe5, 0xb1,
+				     0x5c, 0x92, 0xfa, 0xb0, 0xa9, 0x8e,
+				     0x2c, 0x21, 0x8e, 0x8d, 0xe5, 0x55,
+				     0x84, 0x02, 0xa5, 0x15, 0x5c, 0x53,
+				     0x1f, 0x40, 0x81, 0x0a, 0x10, 0xde,
+				     0x21, 0x41, 0xa9, 0x97, 0xf8, 0x6f,
+				     0xbf, 0x42, 0x58, 0x9e, 0xc6, 0xdd,
+				     0x10, 0x33, 0x3f, 0xad, 0xe6, 0x8e,
+				     0x57, 0x27, 0x37, 0x20, 0xa4, 0x86,
+				     0xef, 0x39, 0x7b, 0x6f, 0x78, 0x77,
+				     0xab, 0xa0, 0x62, 0xe1, 0xfd, 0x9c,
+				     0xbe, 0xfa, 0x98, 0x2e, 0x29, 0xe3,
+				     0xeb, 0x52 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x00, 0x91, 0xb3, 0x87, 0xe6, 0x01,
+				     0x57, 0xe9, 0x68, 0xa4, 0xf4, 0x9b,
+				     0xea, 0x6a, 0x8a, 0x9e, 0x1a, 0x8b,
+				     0xd3, 0x85, 0x9d, 0xba, 0x85, 0xab,
+				     0xd8, 0xcd, 0x25, 0x56, 0x8e, 0x85,
+				     0x8a, 0x8e, 0x48, 0x9e, 0xb4, 0x90,
+				     0xc8, 0x2e, 0x07, 0x78, 0x80, 0x49,
+				     0xa0, 0xb7, 0x95, 0x6a, 0xd8, 0xad,
+				     0xb5, 0xda, 0x5d, 0xe6, 0x11, 0x87,
+				     0xb8, 0x33, 0x8f, 0xa8, 0x6f, 0x4e,
+				     0xc6, 0xc3, 0x0d, 0xf5, 0xa9, 0x4e,
+				     0xb2, 0x42, 0x53, 0x81, 0xcd, 0x33,
+				     0x83, 0x49, 0xab, 0x0d, 0x0e, 0xf5,
+				     0x2c, 0xcd, 0x84, 0x58, 0xf3, 0x30,
+				     0xa3, 0x6e, 0x3c, 0x3a, 0xc6, 0x77,
+				     0x43, 0xb0, 0xe7, 0x4b, 0x66, 0x30,
+				     0xe9, 0x48, 0x0b, 0x0d, 0x86, 0x3f,
+				     0xd8, 0xe2, 0xb5, 0x88, 0xc1, 0x44,
+				     0xb2, 0x6b, 0xb0, 0x7a, 0x35, 0x3b,
+				     0x56, 0x83, 0xb1, 0xac, 0x9e, 0xeb,
+				     0x9b, 0x08, 0x43, 0xac, 0x0a, 0x3a,
+				     0x31, 0x69 ),
+			    BIGINT ( 0x96, 0x6f, 0xb0, 0xa7, 0x02, 0xb5,
+				     0xd9, 0x19, 0xbe, 0x4b, 0x27, 0x65,
+				     0x5b, 0x96, 0xd4, 0x0b, 0x49, 0x70,
+				     0xf0, 0x09, 0x8e, 0xf2, 0x04, 0x85,
+				     0x93, 0xe9, 0x2e, 0x09, 0x31, 0x76,
+				     0x8b, 0xbb, 0xe9, 0xe1, 0x2b, 0x4f,
+				     0xed, 0x83, 0xa6, 0x87, 0xa3, 0x07,
+				     0x0a, 0x3d, 0x1c, 0x65, 0x14, 0x5a,
+				     0xd5, 0xc0, 0x5d, 0x3c, 0x31, 0x9a,
+				     0x83, 0xad, 0xca, 0x6a, 0x93, 0x0d,
+				     0x1a, 0x67, 0x4e, 0x68, 0x06, 0x64,
+				     0x53, 0x2e, 0x15, 0xd9, 0xdd, 0x5e,
+				     0xcb, 0xb7, 0x2e, 0xef, 0xd3, 0xbb,
+				     0x5f, 0xaf, 0xef, 0x9e, 0xf2, 0x7b,
+				     0x69, 0x15, 0xb0, 0x18, 0x6c, 0x67,
+				     0x10, 0xda, 0x33, 0x07, 0x48, 0x97,
+				     0x31, 0xb3, 0x3d, 0x3d, 0xc9, 0x2e,
+				     0x0b, 0x68, 0x91, 0x3f, 0x6a, 0x3b,
+				     0x1a, 0xdf, 0xa8, 0x69, 0x46, 0x1c,
+				     0xb2, 0x69, 0x08, 0x0b, 0x02, 0x1b,
+				     0x03, 0x64, 0xae, 0xb6, 0x2d, 0xc6,
+				     0xc4, 0x0a ),
+			    BIGINT ( 0x6d, 0x3f, 0xdd ),
+			    BIGINT ( 0x40, 0x6e, 0x9d, 0x3e, 0xeb, 0xa4,
+				     0xb1, 0x8d, 0xb7, 0xb4, 0x0f, 0x5b,
+				     0x12, 0xad, 0x27, 0x9e, 0xbd, 0xe7,
+				     0xe5, 0x9d, 0xec, 0xb4, 0xac, 0x23,
+				     0x5f, 0xa9, 0xec, 0x9c, 0xd1, 0x6a,
+				     0xbe, 0x99, 0xba, 0xb3, 0x66, 0x0e,
+				     0x17, 0xaa, 0x13, 0xa2, 0x2e, 0x01,
+				     0x28, 0xb1, 0x6c, 0xba, 0xad, 0x68,
+				     0x48, 0xf0, 0xf3, 0x4c, 0x08, 0x9f,
+				     0xd1, 0x9c, 0xb7, 0x75, 0xc5, 0xb6,
+				     0x5a, 0x05, 0xb0, 0x14, 0xd4, 0x61,
+				     0xea, 0x18, 0x9f, 0xe6, 0xe5, 0xe3,
+				     0xd4, 0xff, 0x35, 0x43, 0x0b, 0xb8,
+				     0xf6, 0xe9, 0x19, 0x7a, 0x88, 0xa7,
+				     0x4d, 0x01, 0x92, 0x05, 0xd2, 0x6e,
+				     0xa3, 0xc1, 0xb6, 0x66, 0x75, 0xb1,
+				     0x00, 0x0d, 0x42, 0x37, 0xcc, 0xca,
+				     0xc0, 0x8d, 0xc8, 0x7e, 0x5c, 0xc9,
+				     0x53, 0x81, 0x2f, 0xc4, 0x61, 0xb6,
+				     0x96, 0x3b, 0xa5, 0x04, 0x14, 0x1b,
+				     0xa7, 0x77, 0xa1, 0xbc, 0x73, 0x1d,
+				     0xad, 0xed ) );
+	bigint_mod_exp_ok ( BIGINT ( 0x45, 0xfb, 0xf3, 0xdc, 0x31, 0xe5,
+				     0x56, 0x7a, 0xee, 0x15, 0xfb, 0x16,
+				     0xee, 0x6e, 0x90, 0x3e, 0xa3, 0x89,
+				     0xc2, 0x6d, 0x9b, 0x06, 0x65, 0xd0,
+				     0xcd, 0xa2, 0xcc, 0x01, 0x60, 0x0d,
+				     0xd1, 0xdd, 0x68, 0x14, 0xc2, 0xcd,
+				     0xd8, 0x79, 0x75, 0xad, 0x0a, 0x9f,
+				     0x39, 0x5f, 0x52, 0x4b, 0x58, 0x31,
+				     0x48, 0xbb, 0x2a, 0xcc, 0xe0, 0x42,
+				     0x18, 0x32, 0xdc, 0x63, 0x14, 0x11,
+				     0x4e, 0xab, 0x96, 0x29, 0xc5, 0x06,
+				     0x79, 0xe5, 0x06, 0xf7, 0x59, 0xdb,
+				     0x1e, 0x51, 0xfd, 0xc4, 0x48, 0x3a,
+				     0x4c, 0x7f, 0xd0, 0xe2, 0x36, 0x86,
+				     0xc1, 0x8b, 0xc5, 0x86, 0x52, 0xe0,
+				     0xdb, 0x92, 0x5f, 0x0e, 0x19, 0xb1,
+				     0xa3, 0x23, 0xdd, 0xf0, 0x78, 0xcc,
+				     0x81, 0x3f, 0x4a, 0xe6, 0xb0, 0x32,
+				     0xd1, 0x5c, 0x5e, 0x3a, 0xb0, 0xd8,
+				     0xe2, 0x04, 0xc0, 0x30, 0x85, 0x1d,
+				     0x5e, 0x28, 0xee, 0xd9, 0xb3, 0x83,
+				     0x9f, 0xe2 ),
+			    BIGINT ( 0xb3, 0x2c, 0x2e, 0xc5, 0xba, 0xf8,
+				     0x41, 0x98, 0x79, 0x7e, 0xaa, 0x0c,
+				     0x2a, 0x8f, 0xd9, 0x56, 0x55, 0xaa,
+				     0x74, 0x60, 0x74, 0xd1, 0x49, 0x2c,
+				     0x6f, 0x0a, 0x4e, 0xf8, 0x3f, 0x1b,
+				     0x73, 0x4c, 0xe0, 0x17, 0x37, 0x06,
+				     0x76, 0x73, 0xd5, 0x2d, 0x4d, 0x3f,
+				     0xb0, 0x15, 0x7e, 0x98, 0xd0, 0xdf,
+				     0xf0, 0x33, 0x78, 0xe2, 0xe6, 0xec,
+				     0x21, 0x22, 0xad, 0xd5, 0xab, 0x2d,
+				     0x0d, 0x59, 0x95, 0x05, 0x34, 0x1f,
+				     0x51, 0xf5, 0xec, 0x93, 0x05, 0x15,
+				     0x37, 0xcf, 0x93, 0x03, 0xd7, 0xf6,
+				     0x35, 0x23, 0x8f, 0x33, 0xf6, 0xba,
+				     0x42, 0xc8, 0x52, 0x94, 0xd3, 0x33,
+				     0x3e, 0x39, 0x01, 0xd1, 0x55, 0x3f,
+				     0x48, 0x84, 0xe9, 0xbc, 0x0b, 0x0f,
+				     0xc9, 0x69, 0x41, 0x2c, 0x5f, 0x34,
+				     0xd0, 0xe6, 0x15, 0x50, 0x06, 0x64,
+				     0x5b, 0x8b, 0x71, 0x22, 0xb3, 0x3e,
+				     0x09, 0x9c, 0x76, 0x13, 0x9b, 0x29,
+				     0x57, 0x94 ),
+			    BIGINT ( 0xca, 0x94, 0xf7, 0xca ),
+			    BIGINT ( 0x83, 0x68, 0xb9, 0xe7, 0x91, 0xf3,
+				     0x3b, 0x5a, 0x0b, 0xb6, 0x1e, 0x2f,
+				     0x3f, 0x5f, 0xdc, 0x96, 0x5b, 0x7f,
+				     0x8d, 0xc5, 0x8e, 0xda, 0x6e, 0x21,
+				     0xe3, 0x20, 0xea, 0x37, 0x39, 0x3b,
+				     0xb4, 0xd7, 0xf6, 0xba, 0x61, 0xfe,
+				     0xdc, 0x7e, 0x82, 0x9a, 0x38, 0x7b,
+				     0xd5, 0xb1, 0x11, 0x98, 0xc4, 0x88,
+				     0x0b, 0x01, 0x7d, 0x81, 0xc9, 0x64,
+				     0x23, 0xc3, 0x3e, 0xf3, 0x67, 0x95,
+				     0x78, 0xca, 0xda, 0x52, 0xaf, 0x72,
+				     0x25, 0xd9, 0xf0, 0x27, 0xd3, 0x1c,
+				     0xfb, 0xad, 0xa1, 0xa7, 0x06, 0x2f,
+				     0xaa, 0x2f, 0x86, 0x5c, 0x8b, 0x30,
+				     0xe1, 0xda, 0x5a, 0x36, 0xf9, 0xfd,
+				     0xbf, 0xfe, 0x0d, 0x03, 0xf8, 0x9c,
+				     0x6b, 0x9b, 0xe5, 0x70, 0x6d, 0x75,
+				     0xd7, 0x54, 0x28, 0x43, 0x34, 0x69,
+				     0x98, 0x11, 0x29, 0xee, 0x50, 0x06,
+				     0xa4, 0xc4, 0x11, 0x6d, 0x60, 0x8c,
+				     0xcd, 0xd1, 0x88, 0xe9, 0x6b, 0xbb,
+				     0xc1, 0xd4 ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xa1, 0x01, 0x7e, 0xb4, 0x0e, 0x66,
+				     0xa5, 0x07, 0x8b, 0x10, 0x84, 0x0d,
+				     0x30, 0x0a, 0xa4, 0x2d, 0x10, 0x2c,
+				     0xd4, 0x9a, 0x27, 0xf1, 0x02, 0x8c,
+				     0x38, 0x18, 0x7f, 0x7f, 0x95, 0x65,
+				     0xf1, 0xa9, 0x3b, 0x7d, 0x1f, 0x4f,
+				     0x88, 0xb0, 0x65, 0x62, 0x63, 0x63,
+				     0xaa, 0x82, 0xfc, 0x83, 0x3a, 0x3a,
+				     0x46, 0x59, 0x6a, 0x89, 0xec, 0xa9,
+				     0xb0, 0x4c, 0x5e, 0xbe, 0x46, 0x98,
+				     0xd0, 0xd4, 0xb7, 0xe3, 0x1b, 0x30,
+				     0x0b, 0xfb, 0xbb, 0x4f, 0x0b, 0xd3,
+				     0xe4, 0xa0, 0x80, 0x54, 0xcb, 0x52,
+				     0x0a, 0xe8, 0x03, 0x75, 0x8e, 0x96,
+				     0xa4, 0x21, 0xaa, 0xbd, 0x7a, 0xfd,
+				     0xfa, 0xf8, 0xaf, 0x42, 0xf6, 0x61,
+				     0xd2, 0x93, 0xce, 0x66, 0x67, 0xe9,
+				     0x02, 0xda, 0x81, 0x0b, 0xb0, 0x1e,
+				     0x9e, 0x27, 0x57, 0x98, 0x18, 0x88,
+				     0x35, 0x49, 0xc0, 0x88, 0x88, 0x59,
+				     0xae, 0x2f, 0x66, 0x59, 0x31, 0x87,
+				     0x88, 0xda ),
+			    BIGINT ( 0xfe, 0x21, 0x7c, 0xf4, 0xbe, 0xae,
+				     0x65, 0xda, 0x89, 0xd2, 0x26, 0xd6,
+				     0x9c, 0x65, 0xc6, 0xb6, 0xb4, 0x0a,
+				     0x84, 0x11, 0xe1, 0xe8, 0xba, 0xd8,
+				     0x16, 0xcf, 0x60, 0x6c, 0x83, 0xa5,
+				     0x4a, 0xbf, 0xa2, 0x24, 0x0b, 0x66,
+				     0xda, 0xe2, 0x4e, 0x2d, 0xe5, 0x9e,
+				     0xbf, 0xad, 0x5c, 0xa3, 0x1e, 0x5c,
+				     0xbd, 0xe2, 0x5b, 0x46, 0xcf, 0xcc,
+				     0xd5, 0xc9, 0x13, 0x95, 0xc3, 0xdb,
+				     0x64, 0xbf, 0xeb, 0x31, 0xa9, 0x8a,
+				     0x3b, 0xd2, 0x5d, 0x3b, 0x2e, 0xdc,
+				     0x0c, 0xca, 0xab, 0xde, 0x92, 0xae,
+				     0x45, 0x35, 0x96, 0xb0, 0xb7, 0xb9,
+				     0xe6, 0xfe, 0x28, 0x0d, 0x10, 0x72,
+				     0x53, 0x8e, 0x21, 0xc0, 0x33, 0x79,
+				     0x01, 0x43, 0x8d, 0x77, 0xc4, 0xaa,
+				     0xcf, 0x7f, 0xc3, 0xd1, 0xf5, 0xfd,
+				     0x79, 0x81, 0xf6, 0x2e, 0xb7, 0xeb,
+				     0x55, 0x5f, 0x74, 0xf0, 0x3a, 0xb9,
+				     0x57, 0x07, 0x09, 0x97, 0xa5, 0x4c,
+				     0x4a, 0x85 ),
+			    BIGINT ( 0xd9, 0xb7, 0xb2, 0xd6, 0xeb, 0xf3,
+				     0x66, 0xbe, 0x15, 0x64, 0xad, 0x2e,
+				     0x9e, 0xc6, 0xaf, 0x5e, 0xaf, 0x40,
+				     0x1e, 0x90, 0x82, 0x2f, 0x98 ),
+			    BIGINT ( 0x12, 0x48, 0x31, 0x7f, 0x09, 0xbb,
+				     0x8f, 0xd9, 0x02, 0x7e, 0x4a, 0xd0,
+				     0x2f, 0x42, 0x7c, 0x17, 0x6e, 0x83,
+				     0x74, 0x21, 0x95, 0x47, 0x7d, 0x93,
+				     0x4a, 0xce, 0x34, 0x7c, 0xde, 0xc7,
+				     0x8f, 0xf6, 0x28, 0x97, 0xba, 0x81,
+				     0x9b, 0xcc, 0x54, 0x14, 0x7f, 0xd3,
+				     0x93, 0x66, 0x41, 0x8c, 0x0e, 0x47,
+				     0xee, 0xc5, 0x5e, 0xd6, 0x5f, 0x01,
+				     0x62, 0x97, 0xf1, 0x2b, 0xee, 0x60,
+				     0x5e, 0x82, 0x2c, 0x7b, 0x0a, 0xf2,
+				     0xc3, 0x23, 0xbf, 0xb9, 0x83, 0xf7,
+				     0x97, 0xf5, 0xca, 0x58, 0xd7, 0xf0,
+				     0x87, 0x7b, 0xcb, 0x87, 0x69, 0x42,
+				     0xbc, 0x05, 0xc4, 0xad, 0xbd, 0x82,
+				     0xcf, 0x44, 0x16, 0x4f, 0x46, 0xe0,
+				     0xde, 0x2f, 0xfa, 0x77, 0xec, 0xa4,
+				     0x23, 0x7d, 0x47, 0x3e, 0x94, 0x19,
+				     0x8b, 0xb8, 0x84, 0x81, 0x80, 0x6c,
+				     0x1e, 0x31, 0xa3, 0x6d, 0x14, 0x94,
+				     0x57, 0x28, 0x99, 0x08, 0x0a, 0xa7,
+				     0x98, 0x4b ) );
+	bigint_mod_exp_ok ( BIGINT ( 0xda, 0x52, 0xfd, 0x44, 0x5d, 0x11,
+				     0x60, 0x6c, 0xec, 0x87, 0xbf, 0x19,
+				     0xb8, 0x46, 0xaa, 0x41, 0xfc, 0x10,
+				     0xae, 0x47, 0xd6, 0x72, 0x42, 0x57,
+				     0xc3, 0x05, 0xca, 0xe3, 0x59, 0x94,
+				     0x82, 0x7c, 0xa1, 0xe0, 0xd2, 0x6b,
+				     0x77, 0x71, 0x42, 0xa1, 0xf7, 0x84,
+				     0xae, 0xf4, 0x6f, 0x44, 0x0d, 0x88,
+				     0xa2, 0xc5, 0x45, 0x9b, 0x49, 0x36,
+				     0xd4, 0x20, 0x3a, 0x7c, 0x92, 0xdb,
+				     0x65, 0xd9, 0x20, 0xd6, 0x71, 0x22,
+				     0x90, 0x70, 0xbf, 0xf3, 0x17, 0xe8,
+				     0x2c, 0x10, 0xe9, 0x4c, 0x02, 0x69,
+				     0x37, 0xa2, 0x91, 0x04, 0x46, 0x11,
+				     0xdc, 0xab, 0x5b, 0x1e, 0x3e, 0x31,
+				     0xd8, 0x69, 0xf8, 0x48, 0x84, 0x1f,
+				     0x56, 0x46, 0xf1, 0xc0, 0x14, 0x3f,
+				     0xcc, 0x5d, 0xe2, 0xf7, 0x8b, 0xa4,
+				     0x9e, 0x94, 0x32, 0xaa, 0x3c, 0x5e,
+				     0x21, 0x70, 0x00, 0x24, 0x2a, 0x1b,
+				     0xec, 0x25, 0xb1, 0xb6, 0x83, 0x36,
+				     0x5a, 0x95 ),
+			    BIGINT ( 0x5e, 0xdc, 0x71, 0x1f, 0x5b, 0x55,
+				     0xaa, 0xda, 0x56, 0xf5, 0x93, 0x9b,
+				     0xe8, 0xfc, 0x6a, 0x80, 0xe1, 0xe3,
+				     0x93, 0xe4, 0xc0, 0x58, 0x6f, 0x22,
+				     0xce, 0x9d, 0x6f, 0x84, 0x4c, 0xd4,
+				     0x12, 0x44, 0x57, 0x25, 0xca, 0xe5,
+				     0x2b, 0x7c, 0x35, 0x88, 0xc7, 0x38,
+				     0x25, 0x20, 0x9b, 0x57, 0xf2, 0xf2,
+				     0x6c, 0x28, 0x47, 0x9c, 0x3f, 0x91,
+				     0x1e, 0x3f, 0xe9, 0xeb, 0x50, 0xd6,
+				     0xa7, 0x22, 0x88, 0x6c, 0x71, 0xe5,
+				     0x62, 0x2a, 0xb7, 0xce, 0xbe, 0xf7,
+				     0x1a, 0x8c, 0x52, 0xa6, 0xff, 0xb8,
+				     0x34, 0x83, 0x7e, 0x04, 0xa8, 0x9c,
+				     0xa8, 0xa7, 0xd1, 0x05, 0x8e, 0x13,
+				     0x03, 0xe0, 0x49, 0xd8, 0x4a, 0xc4,
+				     0x4d, 0x38, 0x21, 0x5b, 0x62, 0xc2,
+				     0x38, 0x23, 0x7c, 0x9e, 0xf1, 0xe9,
+				     0xb6, 0x9a, 0x75, 0x42, 0x14, 0x99,
+				     0x63, 0x36, 0x13, 0x4c, 0x2d, 0x3a,
+				     0x77, 0xd4, 0x74, 0xb7, 0x30, 0xb2,
+				     0x00, 0x0f ),
+			    BIGINT ( 0xe3, 0xe5, 0x3b, 0xb5, 0x92, 0x5a,
+				     0xc6, 0xfa, 0x8f, 0xe8, 0x00, 0xb9,
+				     0x5c, 0xa0, 0xb6, 0x3e, 0x5e, 0x14,
+				     0x12, 0xa9, 0xdd, 0x2a, 0x3d, 0x4d,
+				     0xa3, 0x91, 0x6a, 0x56, 0x99, 0xc2,
+				     0x6c, 0x8e, 0xda, 0xb0, 0x5a, 0x2a,
+				     0x37, 0x55, 0x8b, 0xd3, 0x9b, 0xb6,
+				     0x1d, 0x49, 0x7d, 0x81, 0x76, 0x1c,
+				     0x2e, 0xb9, 0x92, 0x6d, 0xfa, 0x54,
+				     0x53, 0xfc, 0x74, 0x9b, 0x6b, 0x63,
+				     0x95, 0x1a, 0x89, 0xcc, 0xbd, 0x36,
+				     0xc5, 0x31, 0x7f, 0xf5, 0x31, 0x69,
+				     0x40, 0xd5, 0x7b, 0x94, 0x5d, 0xa9,
+				     0xd1, 0x34, 0x95, 0xa1, 0x8b, 0xa5,
+				     0xb5, 0x83, 0xda, 0xb5, 0x9d, 0x5b,
+				     0x74, 0x41, 0xad, 0x81, 0x45, 0x40,
+				     0x9b, 0xc3, 0xe8, 0xfe, 0x47, 0xdc,
+				     0xb0, 0xc3, 0x34, 0x5d, 0xf6, 0x3c,
+				     0x1d, 0x07, 0x76, 0xd9, 0x25, 0xca,
+				     0xa2, 0x39, 0x6c, 0xa8, 0xae, 0x30,
+				     0x4a, 0xde, 0xfb, 0xeb, 0x19, 0x80,
+				     0x5e, 0x49 ),
+			    BIGINT ( 0x4b, 0x0e, 0x74, 0xb8, 0xa7, 0x92,
+				     0x74, 0xd9, 0x50, 0xf6, 0x1b, 0x67,
+				     0x76, 0x76, 0x56, 0x6c, 0x09, 0x9c,
+				     0x01, 0xda, 0xaf, 0xa3, 0xca, 0xb2,
+				     0x12, 0x85, 0x52, 0x24, 0xe9, 0x7e,
+				     0x2b, 0xf2, 0x6e, 0xe9, 0x1a, 0x10,
+				     0x5d, 0xa0, 0x25, 0x46, 0x8f, 0x2a,
+				     0x95, 0x62, 0x50, 0xb6, 0x66, 0x43,
+				     0x37, 0x8b, 0xcb, 0x05, 0xf8, 0x61,
+				     0x59, 0xf9, 0xdd, 0xd2, 0x68, 0x72,
+				     0xfa, 0x88, 0x13, 0x36, 0xd8, 0x24,
+				     0x73, 0xec, 0x47, 0x44, 0xdd, 0x45,
+				     0x8a, 0x59, 0xd2, 0xbd, 0x43, 0xe3,
+				     0x05, 0x16, 0xd5, 0x9b, 0x1c, 0x8a,
+				     0x4b, 0x07, 0xda, 0x58, 0x0d, 0x4a,
+				     0x4e, 0xe7, 0x15, 0xfc, 0xbd, 0x95,
+				     0xf7, 0x18, 0xa5, 0xa7, 0x93, 0xff,
+				     0xf8, 0x1f, 0xd4, 0x6b, 0x07, 0xc6,
+				     0x5d, 0x90, 0x73, 0x57, 0x57, 0x37,
+				     0xfa, 0x83, 0xd4, 0x7c, 0xe9, 0x77,
+				     0x46, 0x91, 0x3a, 0x50, 0x0d, 0x6a,
+				     0x25, 0xd0 ) );
+}
+
+/** Big integer self-test */
+struct self_test bigint_test __self_test = {
+	.name = "bigint",
+	.exec = bigint_test_exec,
+};
diff --git a/roms/ipxe/src/tests/bofm_test.c b/roms/ipxe/src/tests/bofm_test.c
index 6f2e6c6739d7a40402b60ae1a180..e430d12d49fb3d5f83dbfa72f3d1 100644
--- a/roms/ipxe/src/tests/bofm_test.c
+++ b/roms/ipxe/src/tests/bofm_test.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/tests/byteswap_test.c b/roms/ipxe/src/tests/byteswap_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..a500218be67304ec882eed3bd6712d3409fea14d
--- /dev/null
+++ b/roms/ipxe/src/tests/byteswap_test.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Byte-order swapping test functions
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stdint.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/test.h>
+
+/* Provide global functions to allow inspection of generated assembly code */
+
+uint16_t test_bswap16 ( uint16_t x ) {
+	return __bswap_16 ( x );
+}
+
+uint32_t test_bswap32 ( uint32_t x ) {
+	return __bswap_32 ( x );
+}
+
+uint64_t test_bswap64 ( uint64_t x ) {
+	return __bswap_64 ( x );
+}
+
+void test_bswap16s ( uint16_t *x ) {
+	__bswap_16s ( x );
+}
+
+void test_bswap32s ( uint32_t *x ) {
+	__bswap_32s ( x );
+}
+
+void test_bswap64s ( uint64_t *x ) {
+	__bswap_64s ( x );
+}
+
+/**
+ * Perform byte-order swapping
+ *
+ */
+static void byteswap_test_exec ( void ) {
+	uint16_t test16;
+	uint32_t test32;
+	uint64_t test64;
+
+	ok ( test_bswap16 ( 0x1234 ) == 0x3412 );
+	ok ( test_bswap32 ( 0x12345678UL ) == 0x78563412UL );
+	ok ( test_bswap64 ( 0x123456789abcdef0ULL ) == 0xf0debc9a78563412ULL );
+
+	test16 = 0xabcd;
+	test_bswap16s ( &test16 );
+	ok ( test16 == 0xcdab );
+
+	test32 = 0xabcdef01UL;
+	test_bswap32s ( &test32 );
+	ok ( test32 == 0x01efcdabUL );
+
+	test64 = 0xabcdef0123456789ULL;
+	test_bswap64s ( &test64 );
+	ok ( test64 == 0x8967452301efcdabULL );
+}
+
+/** Byte-order swapping self-test */
+struct self_test byteswap_test __self_test = {
+	.name = "byteswap",
+	.exec = byteswap_test_exec,
+};
diff --git a/roms/ipxe/src/tests/cbc_test.c b/roms/ipxe/src/tests/cbc_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..ada991b219b55fde09ac89ec32522054e57738c3
--- /dev/null
+++ b/roms/ipxe/src/tests/cbc_test.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * CBC self-tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ipxe/crypto.h>
+#include <ipxe/profile.h>
+#include "cbc_test.h"
+
+/**
+ * Test CBC encryption
+ *
+ * @v cipher			Cipher algorithm
+ * @v key			Key
+ * @v key_len			Length of key
+ * @v iv			Initialisation vector
+ * @v plaintext			Plaintext data
+ * @v expected_ciphertext	Expected ciphertext data
+ * @v len			Length of data
+ * @ret ok			Ciphertext is as expected
+ */
+int cbc_test_encrypt ( struct cipher_algorithm *cipher, const void *key,
+		       size_t key_len, const void *iv, const void *plaintext,
+		       const void *expected_ciphertext, size_t len ) {
+	uint8_t ctx[cipher->ctxsize];
+	uint8_t ciphertext[len];
+	int rc;
+
+	/* Initialise cipher */
+	rc = cipher_setkey ( cipher, ctx, key, key_len );
+	assert ( rc == 0 );
+	cipher_setiv ( cipher, ctx, iv );
+
+	/* Perform encryption */
+	cipher_encrypt ( cipher, ctx, plaintext, ciphertext, len );
+
+	/* Verify result */
+	return ( memcmp ( ciphertext, expected_ciphertext, len ) == 0 );
+}
+
+/**
+ * Test CBC decryption
+ *
+ * @v cipher			Cipher algorithm
+ * @v key			Key
+ * @v key_len			Length of key
+ * @v iv			Initialisation vector
+ * @v ciphertext		Ciphertext data
+ * @v expected_plaintext	Expected plaintext data
+ * @v len			Length of data
+ * @ret ok			Plaintext is as expected
+ */
+int cbc_test_decrypt ( struct cipher_algorithm *cipher, const void *key,
+		       size_t key_len, const void *iv, const void *ciphertext,
+		       const void *expected_plaintext, size_t len ) {
+	uint8_t ctx[cipher->ctxsize];
+	uint8_t plaintext[len];
+	int rc;
+
+	/* Initialise cipher */
+	rc = cipher_setkey ( cipher, ctx, key, key_len );
+	assert ( rc == 0 );
+	cipher_setiv ( cipher, ctx, iv );
+
+	/* Perform encryption */
+	cipher_decrypt ( cipher, ctx, ciphertext, plaintext, len );
+
+	/* Verify result */
+	return ( memcmp ( plaintext, expected_plaintext, len ) == 0 );
+}
+
+/**
+ * Calculate CBC encryption or decryption cost
+ *
+ * @v cipher			Cipher algorithm
+ * @v key_len			Length of key
+ * @v op			Encryption or decryption operation
+ * @ret cost			Cost (in cycles per byte)
+ */
+static unsigned long cbc_cost ( struct cipher_algorithm *cipher,
+				size_t key_len,
+				void ( * op ) ( struct cipher_algorithm *cipher,
+						void *ctx, const void *src,
+						void *dst, size_t len ) ) {
+	static uint8_t random[8192]; /* Too large for stack */
+	uint8_t key[key_len];
+	uint8_t iv[cipher->blocksize];
+	uint8_t ctx[cipher->ctxsize];
+	union profiler profiler;
+	unsigned long long elapsed;
+	unsigned long cost;
+	unsigned int i;
+	int rc;
+
+	/* Fill buffer with pseudo-random data */
+	srand ( 0x1234568 );
+	for ( i = 0 ; i < sizeof ( random ) ; i++ )
+		random[i] = rand();
+	for ( i = 0 ; i < sizeof ( key ) ; i++ )
+		key[i] = rand();
+	for ( i = 0 ; i < sizeof ( iv ) ; i++ )
+		iv[i] = rand();
+
+	/* Initialise cipher */
+	rc = cipher_setkey ( cipher, ctx, key, key_len );
+	assert ( rc == 0 );
+	cipher_setiv ( cipher, ctx, iv );
+
+	/* Time operation */
+	profile ( &profiler );
+	op ( cipher, ctx, random, random, sizeof ( random ) );
+	elapsed = profile ( &profiler );
+
+	/* Round to nearest whole number of cycles per byte */
+	cost = ( ( elapsed + ( sizeof ( random ) / 2 ) ) / sizeof ( random ) );
+
+	return cost;
+}
+
+/**
+ * Calculate CBC encryption cost
+ *
+ * @v cipher			Cipher algorithm
+ * @v key_len			Length of key
+ * @ret cost			Cost (in cycles per byte)
+ */
+unsigned long cbc_cost_encrypt ( struct cipher_algorithm *cipher,
+				 size_t key_len ) {
+	return cbc_cost ( cipher, key_len, cipher_encrypt );
+}
+
+/**
+ * Calculate CBC decryption cost
+ *
+ * @v cipher			Cipher algorithm
+ * @v key_len			Length of key
+ * @ret cost			Cost (in cycles per byte)
+ */
+unsigned long cbc_cost_decrypt ( struct cipher_algorithm *cipher,
+				 size_t key_len ) {
+	return cbc_cost ( cipher, key_len, cipher_decrypt );
+}
diff --git a/roms/ipxe/src/tests/cbc_test.h b/roms/ipxe/src/tests/cbc_test.h
new file mode 100644
index 0000000000000000000000000000000000000000..ad9e6f341fad1516e1d5f75807c580f66f5381a7
--- /dev/null
+++ b/roms/ipxe/src/tests/cbc_test.h
@@ -0,0 +1,57 @@
+#ifndef _CBC_TEST_H
+#define _CBC_TEST_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/crypto.h>
+#include <ipxe/test.h>
+
+extern int cbc_test_encrypt ( struct cipher_algorithm *cipher, const void *key,
+			      size_t key_len, const void *iv,
+			      const void *plaintext,
+			      const void *expected_ciphertext, size_t len );
+extern int cbc_test_decrypt ( struct cipher_algorithm *cipher, const void *key,
+			      size_t key_len, const void *iv,
+			      const void *ciphertext,
+			      const void *expected_plaintext, size_t len );
+extern unsigned long cbc_cost_encrypt ( struct cipher_algorithm *cipher,
+					size_t key_len );
+extern unsigned long cbc_cost_decrypt ( struct cipher_algorithm *cipher,
+					size_t key_len );
+
+/**
+ * Report CBC encryption test result
+ *
+ * @v cipher			Cipher algorithm
+ * @v key			Key
+ * @v key_len			Length of key
+ * @v iv			Initialisation vector
+ * @v plaintext			Plaintext data
+ * @v expected_ciphertext	Expected ciphertext data
+ * @v len			Length of data
+ */
+#define cbc_encrypt_ok( cipher, key, key_len, iv, plaintext,		\
+			expected_ciphertext, len ) do {			\
+	ok ( cbc_test_encrypt ( cipher, key, key_len, iv, plaintext,	\
+				expected_ciphertext, len ) );		\
+	} while ( 0 )
+
+/**
+ * Report CBC decryption test result
+ *
+ * @v cipher			Cipher algorithm
+ * @v key			Key
+ * @v key_len			Length of key
+ * @v iv			Initialisation vector
+ * @v ciphertext		Ciphertext data
+ * @v expected_plaintext	Expected plaintext data
+ * @v len			Length of data
+ */
+#define cbc_decrypt_ok( cipher, key, key_len, iv, ciphertext,		\
+			expected_plaintext, len ) do {			\
+	ok ( cbc_test_decrypt ( cipher, key, key_len, iv, ciphertext,	\
+				expected_plaintext, len ) );		\
+	} while ( 0 )
+
+#endif /* _CBC_TEST_H */
diff --git a/roms/ipxe/src/tests/cms_test.c b/roms/ipxe/src/tests/cms_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..9899b06aa33c4f4dca24efec59a113fec017588c
--- /dev/null
+++ b/roms/ipxe/src/tests/cms_test.c
@@ -0,0 +1,1438 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * CMS self-tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stdint.h>
+#include <string.h>
+#include <ipxe/sha256.h>
+#include <ipxe/x509.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/cms.h>
+#include <ipxe/test.h>
+
+/** Fingerprint algorithm used for X.509 test certificates */
+#define cms_test_algorithm sha256_algorithm
+
+/** CMS test code blob */
+struct cms_test_code {
+	/** Data */
+	const void *data;
+	/** Length of data */
+	size_t len;
+};
+
+/** CMS test signature */
+struct cms_test_signature {
+	/** Data */
+	const void *data;
+	/** Length of data */
+	size_t len;
+
+	/** Parsed signature */
+	struct cms_signature *sig;
+};
+
+/** Define inline data */
+#define DATA(...) { __VA_ARGS__ }
+
+/** Define inline fingerprint data */
+#define FINGERPRINT(...) { __VA_ARGS__ }
+
+/** Define a test code blob */
+#define SIGNED_CODE( name, DATA )					\
+	static const uint8_t name ## _data[] = DATA;			\
+	static struct cms_test_code name = {				\
+		.data = name ## _data,					\
+		.len = sizeof ( name ## _data ),			\
+	}
+
+/** Define a test signature */
+#define SIGNATURE( name, DATA )						\
+	static const uint8_t name ## _data[] = DATA;			\
+	static struct cms_test_signature name = {			\
+		.data = name ## _data,					\
+		.len = sizeof ( name ## _data ),			\
+	}
+
+/** Code that has been signed */
+SIGNED_CODE ( test_code,
+	DATA ( 0x23, 0x21, 0x69, 0x70, 0x78, 0x65, 0x0a, 0x0a, 0x65, 0x63,
+	       0x68, 0x6f, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
+	       0x20, 0x61, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20,
+	       0x61, 0x6e, 0x64, 0x20, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65,
+	       0x64, 0x20, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x63, 0x72,
+	       0x69, 0x70, 0x74, 0x2e, 0x20, 0x20, 0x44, 0x6f, 0x20, 0x61,
+	       0x6e, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x79, 0x6f,
+	       0x75, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x21, 0x0a, 0x73, 0x68,
+	       0x65, 0x6c, 0x6c, 0x0a ) );
+
+/** Code that has not been signed */
+SIGNED_CODE ( bad_code,
+	DATA ( 0x23, 0x21, 0x69, 0x70, 0x78, 0x65, 0x0a, 0x0a, 0x65, 0x63,
+	       0x68, 0x6f, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
+	       0x20, 0x61, 0x20, 0x6d, 0x61, 0x6c, 0x69, 0x63, 0x69, 0x6f,
+	       0x75, 0x73, 0x20, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x63,
+	       0x72, 0x69, 0x70, 0x74, 0x2e, 0x20, 0x20, 0x44, 0x6f, 0x20,
+	       0x61, 0x6e, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x79,
+	       0x6f, 0x75, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x21, 0x0a, 0x73,
+	       0x68, 0x65, 0x6c, 0x6c, 0x0a ) );
+
+/** Valid signature */
+SIGNATURE ( codesigned_sig,
+	DATA ( 0x30, 0x82, 0x0c, 0x41, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+	       0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x0c, 0x32, 0x30,
+	       0x82, 0x0c, 0x2e, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07,
+	       0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x30, 0x0b, 0x06,
+	       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+	       0xa0, 0x82, 0x0a, 0xd8, 0x30, 0x82, 0x02, 0xac, 0x30, 0x82,
+	       0x02, 0x15, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x04,
+	       0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+	       0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b,
+	       0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47,
+	       0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08,
+	       0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67,
+	       0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10,
+	       0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d,
+	       0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16,
+	       0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e,
+	       0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c,
+	       0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
+	       0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72,
+	       0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03,
+	       0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c,
+	       0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61,
+	       0x66, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32,
+	       0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x34,
+	       0x5a, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x33, 0x32, 0x32, 0x30,
+	       0x30, 0x30, 0x31, 0x33, 0x34, 0x5a, 0x30, 0x81, 0x88, 0x31,
+	       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+	       0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30,
+	       0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30,
+	       0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65,
+	       0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20,
+	       0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
+	       0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f,
+	       0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04,
+	       0x03, 0x0c, 0x16, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x69, 0x67,
+	       0x6e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78,
+	       0x65, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+	       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+	       0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89,
+	       0x02, 0x81, 0x81, 0x00, 0xc3, 0x3a, 0xdb, 0x7b, 0x17, 0x24,
+	       0x47, 0xb9, 0xb9, 0x17, 0x02, 0x17, 0xa8, 0xce, 0x21, 0x97,
+	       0x92, 0x2f, 0x65, 0x53, 0x3b, 0x7e, 0x5c, 0x7d, 0x13, 0xab,
+	       0x46, 0xe8, 0x4a, 0x44, 0x6c, 0x5d, 0x8f, 0xa2, 0x0c, 0x1d,
+	       0x69, 0xc1, 0x66, 0x48, 0xc4, 0x1a, 0xc9, 0x32, 0xe5, 0x97,
+	       0x92, 0xb7, 0x11, 0xa7, 0x1f, 0x21, 0xac, 0x96, 0xcb, 0x85,
+	       0x10, 0xcc, 0x23, 0x20, 0x51, 0xdd, 0xaf, 0xbe, 0xf5, 0x23,
+	       0x12, 0x0b, 0x03, 0xe9, 0xf9, 0x61, 0x86, 0x64, 0x82, 0xa4,
+	       0xfd, 0x53, 0x24, 0xdf, 0xc2, 0x96, 0x2e, 0x28, 0xbb, 0x94,
+	       0xfb, 0x2c, 0xaf, 0x9e, 0x07, 0x79, 0x96, 0x48, 0x24, 0xf0,
+	       0x9d, 0xb3, 0x11, 0x3d, 0x4c, 0x2e, 0xd8, 0xc9, 0xf9, 0x69,
+	       0xca, 0xdb, 0x16, 0xbd, 0x4c, 0xc5, 0xce, 0x28, 0x18, 0xdc,
+	       0x88, 0x1b, 0x31, 0x0d, 0x10, 0x6b, 0x5b, 0x10, 0xe9, 0xcc,
+	       0xfe, 0xa1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x24, 0x30,
+	       0x22, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04,
+	       0x03, 0x02, 0x07, 0x80, 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d,
+	       0x25, 0x04, 0x0c, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01,
+	       0x05, 0x05, 0x07, 0x03, 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+	       0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+	       0x03, 0x81, 0x81, 0x00, 0x22, 0x20, 0xe4, 0xc5, 0x0a, 0xef,
+	       0xae, 0xab, 0xbd, 0xab, 0x96, 0x56, 0x2c, 0x30, 0xeb, 0x06,
+	       0x84, 0xa0, 0x96, 0x37, 0x1a, 0x29, 0x2b, 0xeb, 0x8c, 0xb5,
+	       0x23, 0x22, 0x10, 0xef, 0x81, 0xe8, 0xdc, 0xa9, 0xdd, 0x8e,
+	       0x1d, 0x2c, 0xfc, 0xf5, 0x07, 0x19, 0xb7, 0x94, 0x91, 0xf7,
+	       0x2e, 0x07, 0xa1, 0xbc, 0xc5, 0x17, 0x34, 0xbe, 0x8a, 0x62,
+	       0x05, 0x5e, 0x9f, 0xe3, 0xce, 0xfd, 0x16, 0x42, 0xca, 0x25,
+	       0x2e, 0x0a, 0x03, 0x54, 0xd5, 0x3a, 0x52, 0x7f, 0x99, 0x94,
+	       0x96, 0xc6, 0xf5, 0xf0, 0xe3, 0x09, 0xd6, 0x00, 0x9b, 0x6f,
+	       0x0b, 0xa4, 0x9a, 0x13, 0x70, 0x9e, 0x67, 0xf9, 0x8c, 0x64,
+	       0xab, 0x22, 0x5d, 0xb3, 0xba, 0x2d, 0xe2, 0x70, 0xb8, 0x0c,
+	       0x6d, 0xd3, 0x12, 0x70, 0x5e, 0x04, 0x80, 0xef, 0x5e, 0x42,
+	       0x0a, 0x77, 0x57, 0x79, 0xa2, 0x1d, 0xe5, 0xbd, 0x20, 0xce,
+	       0x45, 0xc3, 0x30, 0x82, 0x02, 0xb3, 0x30, 0x82, 0x02, 0x1c,
+	       0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x30, 0x0d,
+	       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+	       0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09,
+	       0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31,
+	       0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e,
+	       0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73,
+	       0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
+	       0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72,
+	       0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03,
+	       0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53,
+	       0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64,
+	       0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c,
+	       0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31,
+	       0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16,
+	       0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d,
+	       0x74, 0x65, 0x73, 0x74, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20,
+	       0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33,
+	       0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x17,
+	       0x0d, 0x31, 0x34, 0x31, 0x32, 0x31, 0x37, 0x30, 0x30, 0x30,
+	       0x31, 0x33, 0x33, 0x5a, 0x30, 0x81, 0x90, 0x31, 0x0b, 0x30,
+	       0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42,
+	       0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
+	       0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65,
+	       0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06,
+	       0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62,
+	       0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06,
+	       0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20,
+	       0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74,
+	       0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b,
+	       0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67,
+	       0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+	       0x1e, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66,
+	       0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x65,
+	       0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x43,
+	       0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+	       0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+	       0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
+	       0xc9, 0x3a, 0xee, 0xc6, 0x3c, 0xac, 0x4d, 0x81, 0xc6, 0x98,
+	       0x5e, 0xe1, 0x48, 0x66, 0x1a, 0x1e, 0x60, 0x19, 0x41, 0xae,
+	       0xca, 0x14, 0x97, 0xc8, 0x3a, 0x50, 0xb6, 0x48, 0xf5, 0x42,
+	       0xac, 0x0f, 0xe1, 0xe3, 0x47, 0xf0, 0xbf, 0x7c, 0xd0, 0xee,
+	       0x8f, 0xb7, 0xa6, 0x19, 0xad, 0xbb, 0xc5, 0x1b, 0x34, 0x38,
+	       0xc8, 0xbd, 0x55, 0x84, 0x93, 0x72, 0xaf, 0x84, 0xfc, 0x9b,
+	       0x97, 0x1d, 0xb5, 0x54, 0x24, 0xd6, 0x5d, 0xb7, 0x31, 0xf4,
+	       0xbd, 0x3b, 0x40, 0x97, 0xc0, 0xa9, 0x5a, 0x2a, 0xcb, 0x6b,
+	       0x98, 0x07, 0xdb, 0xb5, 0x9f, 0xe8, 0x31, 0x3f, 0x01, 0x46,
+	       0x46, 0x70, 0x05, 0xa2, 0x0f, 0x8c, 0x7a, 0x61, 0xf3, 0xdf,
+	       0xdb, 0xa1, 0x37, 0x2c, 0x88, 0x6a, 0x81, 0x21, 0x12, 0x4c,
+	       0xf5, 0xcd, 0xaf, 0xc9, 0xd2, 0x36, 0x3d, 0x82, 0xd1, 0xca,
+	       0x19, 0xaf, 0x4e, 0xae, 0x50, 0x71, 0x44, 0xbf, 0x02, 0x03,
+	       0x01, 0x00, 0x01, 0xa3, 0x23, 0x30, 0x21, 0x30, 0x0f, 0x06,
+	       0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+	       0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
+	       0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04,
+	       0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+	       0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x5d,
+	       0x3c, 0xb3, 0x52, 0x19, 0xa6, 0x9e, 0x4a, 0x44, 0x98, 0xbf,
+	       0x51, 0x20, 0x47, 0x0a, 0xf3, 0x26, 0x1a, 0xcc, 0x35, 0x2f,
+	       0xc9, 0xed, 0xe0, 0x9d, 0x46, 0xeb, 0xbc, 0x7e, 0xc9, 0xb9,
+	       0x1d, 0x76, 0xa4, 0x1d, 0xc2, 0xd9, 0x16, 0x29, 0x77, 0x01,
+	       0x40, 0xdd, 0xe5, 0xcb, 0x28, 0x91, 0x3a, 0x0c, 0x13, 0x01,
+	       0x1b, 0x72, 0x62, 0x45, 0x27, 0xfd, 0xd7, 0x00, 0x47, 0x36,
+	       0x09, 0x1e, 0x7b, 0xd2, 0xcb, 0x95, 0x3d, 0x28, 0x82, 0xce,
+	       0x83, 0x59, 0x32, 0xf9, 0xe6, 0xec, 0x89, 0xac, 0x88, 0x45,
+	       0x22, 0x88, 0x6f, 0x5e, 0xa2, 0x79, 0x95, 0xba, 0xb9, 0xc9,
+	       0xb6, 0x4c, 0x7c, 0xb4, 0x29, 0xa1, 0x02, 0xf5, 0xac, 0x5d,
+	       0x8e, 0x52, 0xeb, 0xe8, 0xb1, 0x56, 0x49, 0xb3, 0x77, 0x62,
+	       0x7d, 0x87, 0x4d, 0x17, 0xf2, 0x62, 0x83, 0x08, 0x59, 0x21,
+	       0x60, 0x0d, 0x84, 0x8e, 0x5a, 0x84, 0xf6, 0x30, 0x82, 0x02,
+	       0xb3, 0x30, 0x82, 0x02, 0x1c, 0xa0, 0x03, 0x02, 0x01, 0x02,
+	       0x02, 0x09, 0x00, 0xc6, 0xb8, 0x9c, 0x58, 0xd2, 0xdc, 0xc9,
+	       0x5d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31,
+	       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+	       0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30,
+	       0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30,
+	       0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65,
+	       0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20,
+	       0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
+	       0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f,
+	       0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04,
+	       0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65,
+	       0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x72, 0x6f,
+	       0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+	       0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33,
+	       0x33, 0x5a, 0x17, 0x0d, 0x33, 0x39, 0x30, 0x38, 0x30, 0x38,
+	       0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x30, 0x81, 0x88,
+	       0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+	       0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55,
+	       0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69,
+	       0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12,
+	       0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43,
+	       0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18,
+	       0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46,
+	       0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73,
+	       0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+	       0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e,
+	       0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55,
+	       0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73,
+	       0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x72,
+	       0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x81, 0x9f, 0x30,
+	       0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+	       0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81,
+	       0x89, 0x02, 0x81, 0x81, 0x00, 0xaa, 0x72, 0xb5, 0xc1, 0x73,
+	       0xf4, 0x95, 0x76, 0xa4, 0x27, 0xab, 0x5e, 0xeb, 0x1d, 0x9d,
+	       0xd0, 0x04, 0xb2, 0x93, 0x05, 0xc7, 0xfa, 0x75, 0x84, 0x66,
+	       0xe6, 0x3a, 0x26, 0x1f, 0xbc, 0x2d, 0xfd, 0x8f, 0x59, 0x64,
+	       0xac, 0xcf, 0x65, 0x9d, 0x82, 0x23, 0xc3, 0x72, 0x93, 0xf2,
+	       0x40, 0x68, 0x32, 0xd1, 0xb8, 0xf1, 0x47, 0x61, 0x50, 0xea,
+	       0xbc, 0xcc, 0x3c, 0x6b, 0x74, 0x7a, 0xec, 0x2b, 0x75, 0xa6,
+	       0xc2, 0xa2, 0xb8, 0xbf, 0x23, 0x48, 0x97, 0xd5, 0xaf, 0x77,
+	       0xc1, 0x92, 0x88, 0xd7, 0x38, 0xb7, 0x9e, 0xda, 0xee, 0x72,
+	       0x04, 0xcb, 0x96, 0xe5, 0xdb, 0xfd, 0x9b, 0x5d, 0x99, 0x4e,
+	       0x7a, 0x60, 0x23, 0x34, 0xa4, 0x8d, 0xd7, 0x6c, 0xe7, 0x5d,
+	       0x93, 0x97, 0xe1, 0xab, 0x36, 0x2c, 0x24, 0x16, 0x92, 0x66,
+	       0xf6, 0x6a, 0x14, 0x23, 0x1d, 0x18, 0xb9, 0x44, 0x24, 0x61,
+	       0x6b, 0xd3, 0x75, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x23,
+	       0x30, 0x21, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
+	       0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+	       0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04,
+	       0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+	       0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+	       0x03, 0x81, 0x81, 0x00, 0x94, 0x9e, 0xea, 0x17, 0x8d, 0x27,
+	       0xa9, 0x17, 0xe5, 0xa9, 0x19, 0xbe, 0x82, 0x36, 0xbd, 0xac,
+	       0x74, 0xf3, 0x6e, 0x75, 0x71, 0x30, 0x1c, 0x05, 0x80, 0x6d,
+	       0x1a, 0x69, 0x37, 0x86, 0x9c, 0x77, 0x75, 0x29, 0xa1, 0xc6,
+	       0xb7, 0x11, 0x0a, 0x63, 0x27, 0xee, 0xb1, 0xc8, 0x94, 0xa9,
+	       0x2e, 0x56, 0x8f, 0xca, 0x9d, 0xbe, 0xf4, 0xdb, 0x63, 0x97,
+	       0x68, 0x3b, 0x13, 0xf8, 0x6a, 0xa5, 0xd1, 0x3d, 0xed, 0xbb,
+	       0x86, 0x9d, 0x42, 0xfc, 0x15, 0x0a, 0x04, 0xf8, 0x3c, 0x0e,
+	       0xc4, 0x86, 0x05, 0x57, 0x56, 0x96, 0xf6, 0xc0, 0x18, 0x53,
+	       0xb0, 0xc5, 0xf0, 0xca, 0x72, 0x77, 0x77, 0xc9, 0x8e, 0x90,
+	       0xa5, 0x4b, 0xb6, 0x80, 0x4a, 0x4c, 0x34, 0x6f, 0xc9, 0xe8,
+	       0x6f, 0xc2, 0x28, 0xdf, 0x93, 0xa9, 0xf5, 0x63, 0x18, 0xc0,
+	       0xec, 0x9e, 0xd5, 0x19, 0x36, 0xc5, 0x94, 0x10, 0xd4, 0x72,
+	       0xd2, 0xb8, 0x30, 0x82, 0x02, 0xb6, 0x30, 0x82, 0x02, 0x1f,
+	       0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x30, 0x0d,
+	       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+	       0x05, 0x05, 0x00, 0x30, 0x81, 0x90, 0x31, 0x0b, 0x30, 0x09,
+	       0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31,
+	       0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e,
+	       0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73,
+	       0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
+	       0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72,
+	       0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03,
+	       0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53,
+	       0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64,
+	       0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c,
+	       0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31,
+	       0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1e,
+	       0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d,
+	       0x74, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72,
+	       0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41,
+	       0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32,
+	       0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x31,
+	       0x34, 0x31, 0x32, 0x31, 0x37, 0x30, 0x30, 0x30, 0x31, 0x33,
+	       0x33, 0x5a, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06,
+	       0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17,
+	       0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43,
+	       0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68,
+	       0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
+	       0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69,
+	       0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55,
+	       0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79,
+	       0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31,
+	       0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08,
+	       0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f,
+	       0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69,
+	       0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74,
+	       0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43,
+	       0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+	       0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+	       0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
+	       0xc3, 0x55, 0xad, 0xdf, 0x7b, 0xd1, 0x48, 0xc3, 0xd3, 0x02,
+	       0x54, 0x6c, 0x92, 0x45, 0x22, 0x3d, 0x90, 0xd8, 0xc7, 0x13,
+	       0xcd, 0xc1, 0x59, 0xc6, 0xe0, 0xad, 0x0e, 0xe6, 0xdb, 0x3b,
+	       0xe8, 0x63, 0xea, 0x4e, 0xb6, 0xea, 0x50, 0xea, 0x6e, 0x33,
+	       0x9d, 0x28, 0x25, 0x42, 0x49, 0xd0, 0xf0, 0xed, 0xc5, 0x5b,
+	       0x6b, 0x4a, 0xe7, 0x45, 0xfa, 0xd3, 0x3f, 0xae, 0xde, 0x5a,
+	       0x90, 0xab, 0xf1, 0x61, 0x2f, 0x40, 0x5e, 0xcf, 0x8b, 0x0b,
+	       0x10, 0x59, 0xa9, 0xd0, 0x1e, 0x0f, 0x18, 0x6b, 0x92, 0xd8,
+	       0x9f, 0x58, 0x10, 0x84, 0xb6, 0x15, 0xe8, 0x5b, 0xc4, 0xa0,
+	       0x3e, 0x49, 0x8b, 0xea, 0xdd, 0xa9, 0x7e, 0x32, 0x26, 0x9a,
+	       0x68, 0x44, 0xf0, 0x30, 0xca, 0x2a, 0xd6, 0x19, 0x7a, 0x80,
+	       0xfd, 0xd7, 0xfc, 0xc7, 0x5d, 0xe7, 0x61, 0xd2, 0x3f, 0x1f,
+	       0x2c, 0x40, 0x70, 0x7b, 0x34, 0xcb, 0x08, 0xa9, 0x02, 0x03,
+	       0x01, 0x00, 0x01, 0xa3, 0x26, 0x30, 0x24, 0x30, 0x12, 0x06,
+	       0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30,
+	       0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06,
+	       0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
+	       0x02, 0x02, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+	       0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
+	       0x81, 0x00, 0x40, 0xd2, 0x70, 0x02, 0x08, 0x19, 0xa0, 0xb8,
+	       0x8d, 0x9d, 0x3d, 0x62, 0x41, 0x90, 0x2a, 0x36, 0x4a, 0x8b,
+	       0x21, 0x42, 0x9a, 0xb4, 0xc5, 0xf8, 0x79, 0x17, 0xd7, 0x64,
+	       0x4d, 0xbf, 0x8f, 0x6a, 0x04, 0x54, 0x7a, 0x0b, 0xd4, 0xb5,
+	       0x0e, 0xab, 0xf7, 0xb7, 0x06, 0x2b, 0xf8, 0xde, 0x87, 0xb2,
+	       0x37, 0x3b, 0x95, 0x01, 0xba, 0x9f, 0x8f, 0xec, 0x0a, 0x86,
+	       0xca, 0x51, 0xb6, 0x25, 0x73, 0x2f, 0xa1, 0x66, 0xc8, 0x7a,
+	       0x5e, 0x51, 0xbd, 0x49, 0xb5, 0x75, 0xda, 0xea, 0xe5, 0xeb,
+	       0x5d, 0xe3, 0xb0, 0xad, 0x49, 0x9f, 0x8b, 0xfd, 0x89, 0xb3,
+	       0xb7, 0xb2, 0x4c, 0x7d, 0x8a, 0x29, 0xb2, 0xbe, 0x04, 0xef,
+	       0x9c, 0x73, 0x3c, 0xea, 0xa3, 0x9f, 0x07, 0x66, 0x5a, 0x2f,
+	       0x38, 0xad, 0x1a, 0xeb, 0xe1, 0xb0, 0x62, 0x14, 0x55, 0xdc,
+	       0x8c, 0x83, 0xbb, 0xc7, 0x13, 0x04, 0x41, 0x54, 0xf1, 0x45,
+	       0x31, 0x82, 0x01, 0x33, 0x30, 0x82, 0x01, 0x2f, 0x02, 0x01,
+	       0x01, 0x30, 0x81, 0x8e, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30,
+	       0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42,
+	       0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
+	       0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65,
+	       0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06,
+	       0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62,
+	       0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06,
+	       0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20,
+	       0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74,
+	       0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b,
+	       0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67,
+	       0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+	       0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66,
+	       0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66,
+	       0x20, 0x43, 0x41, 0x02, 0x01, 0x04, 0x30, 0x07, 0x06, 0x05,
+	       0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+	       0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+	       0x04, 0x81, 0x80, 0x1f, 0x95, 0x53, 0x9c, 0x63, 0xcc, 0x9e,
+	       0xe3, 0x41, 0x30, 0xaf, 0x66, 0xac, 0x7c, 0x39, 0x69, 0xa0,
+	       0x02, 0xe3, 0x28, 0xfa, 0xf6, 0x71, 0xf4, 0xcf, 0x97, 0x2a,
+	       0xbb, 0xe0, 0x1d, 0x71, 0x73, 0x4a, 0xa7, 0xea, 0xb0, 0x72,
+	       0xc3, 0xd2, 0xba, 0x52, 0x42, 0x06, 0x88, 0x4a, 0xa6, 0x41,
+	       0x1d, 0x2f, 0x82, 0xb3, 0x7d, 0x32, 0x59, 0x34, 0x4e, 0x47,
+	       0x1b, 0xaa, 0x5e, 0x90, 0xe2, 0x73, 0x62, 0x2d, 0x6f, 0x6c,
+	       0x47, 0x52, 0x05, 0x90, 0xcb, 0xac, 0x30, 0xa8, 0x20, 0x71,
+	       0x14, 0x39, 0x16, 0x85, 0x3d, 0x32, 0x2f, 0x9d, 0x31, 0x97,
+	       0xa8, 0x96, 0xb9, 0xf2, 0x2b, 0xdc, 0xa6, 0x2f, 0x68, 0xc7,
+	       0xac, 0x46, 0xa2, 0xc7, 0x26, 0xd0, 0xde, 0xac, 0x1d, 0x5d,
+	       0x70, 0x65, 0xc6, 0x26, 0xdd, 0x30, 0x3f, 0x3a, 0xbd, 0x5e,
+	       0x8f, 0x87, 0x64, 0xab, 0xe7, 0xf9, 0x71, 0x64, 0x03, 0x05,
+	       0xbf ) );
+
+/** Signature with a broken certificate chain */
+SIGNATURE ( brokenchain_sig,
+	DATA ( 0x30, 0x82, 0x09, 0x8a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+	       0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x09, 0x7b, 0x30,
+	       0x82, 0x09, 0x77, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07,
+	       0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x30, 0x0b, 0x06,
+	       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+	       0xa0, 0x82, 0x08, 0x21, 0x30, 0x82, 0x02, 0xac, 0x30, 0x82,
+	       0x02, 0x15, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x04,
+	       0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+	       0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b,
+	       0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47,
+	       0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08,
+	       0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67,
+	       0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10,
+	       0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d,
+	       0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16,
+	       0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e,
+	       0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c,
+	       0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
+	       0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72,
+	       0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03,
+	       0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c,
+	       0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61,
+	       0x66, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32,
+	       0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x34,
+	       0x5a, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x33, 0x32, 0x32, 0x30,
+	       0x30, 0x30, 0x31, 0x33, 0x34, 0x5a, 0x30, 0x81, 0x88, 0x31,
+	       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+	       0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30,
+	       0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30,
+	       0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65,
+	       0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20,
+	       0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
+	       0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f,
+	       0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04,
+	       0x03, 0x0c, 0x16, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x69, 0x67,
+	       0x6e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78,
+	       0x65, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+	       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+	       0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89,
+	       0x02, 0x81, 0x81, 0x00, 0xc3, 0x3a, 0xdb, 0x7b, 0x17, 0x24,
+	       0x47, 0xb9, 0xb9, 0x17, 0x02, 0x17, 0xa8, 0xce, 0x21, 0x97,
+	       0x92, 0x2f, 0x65, 0x53, 0x3b, 0x7e, 0x5c, 0x7d, 0x13, 0xab,
+	       0x46, 0xe8, 0x4a, 0x44, 0x6c, 0x5d, 0x8f, 0xa2, 0x0c, 0x1d,
+	       0x69, 0xc1, 0x66, 0x48, 0xc4, 0x1a, 0xc9, 0x32, 0xe5, 0x97,
+	       0x92, 0xb7, 0x11, 0xa7, 0x1f, 0x21, 0xac, 0x96, 0xcb, 0x85,
+	       0x10, 0xcc, 0x23, 0x20, 0x51, 0xdd, 0xaf, 0xbe, 0xf5, 0x23,
+	       0x12, 0x0b, 0x03, 0xe9, 0xf9, 0x61, 0x86, 0x64, 0x82, 0xa4,
+	       0xfd, 0x53, 0x24, 0xdf, 0xc2, 0x96, 0x2e, 0x28, 0xbb, 0x94,
+	       0xfb, 0x2c, 0xaf, 0x9e, 0x07, 0x79, 0x96, 0x48, 0x24, 0xf0,
+	       0x9d, 0xb3, 0x11, 0x3d, 0x4c, 0x2e, 0xd8, 0xc9, 0xf9, 0x69,
+	       0xca, 0xdb, 0x16, 0xbd, 0x4c, 0xc5, 0xce, 0x28, 0x18, 0xdc,
+	       0x88, 0x1b, 0x31, 0x0d, 0x10, 0x6b, 0x5b, 0x10, 0xe9, 0xcc,
+	       0xfe, 0xa1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x24, 0x30,
+	       0x22, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04,
+	       0x03, 0x02, 0x07, 0x80, 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d,
+	       0x25, 0x04, 0x0c, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01,
+	       0x05, 0x05, 0x07, 0x03, 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+	       0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+	       0x03, 0x81, 0x81, 0x00, 0x22, 0x20, 0xe4, 0xc5, 0x0a, 0xef,
+	       0xae, 0xab, 0xbd, 0xab, 0x96, 0x56, 0x2c, 0x30, 0xeb, 0x06,
+	       0x84, 0xa0, 0x96, 0x37, 0x1a, 0x29, 0x2b, 0xeb, 0x8c, 0xb5,
+	       0x23, 0x22, 0x10, 0xef, 0x81, 0xe8, 0xdc, 0xa9, 0xdd, 0x8e,
+	       0x1d, 0x2c, 0xfc, 0xf5, 0x07, 0x19, 0xb7, 0x94, 0x91, 0xf7,
+	       0x2e, 0x07, 0xa1, 0xbc, 0xc5, 0x17, 0x34, 0xbe, 0x8a, 0x62,
+	       0x05, 0x5e, 0x9f, 0xe3, 0xce, 0xfd, 0x16, 0x42, 0xca, 0x25,
+	       0x2e, 0x0a, 0x03, 0x54, 0xd5, 0x3a, 0x52, 0x7f, 0x99, 0x94,
+	       0x96, 0xc6, 0xf5, 0xf0, 0xe3, 0x09, 0xd6, 0x00, 0x9b, 0x6f,
+	       0x0b, 0xa4, 0x9a, 0x13, 0x70, 0x9e, 0x67, 0xf9, 0x8c, 0x64,
+	       0xab, 0x22, 0x5d, 0xb3, 0xba, 0x2d, 0xe2, 0x70, 0xb8, 0x0c,
+	       0x6d, 0xd3, 0x12, 0x70, 0x5e, 0x04, 0x80, 0xef, 0x5e, 0x42,
+	       0x0a, 0x77, 0x57, 0x79, 0xa2, 0x1d, 0xe5, 0xbd, 0x20, 0xce,
+	       0x45, 0xc3, 0x30, 0x82, 0x02, 0xb3, 0x30, 0x82, 0x02, 0x1c,
+	       0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xc6, 0xb8,
+	       0x9c, 0x58, 0xd2, 0xdc, 0xc9, 0x5d, 0x30, 0x0d, 0x06, 0x09,
+	       0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
+	       0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+	       0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30,
+	       0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69,
+	       0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
+	       0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04,
+	       0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73,
+	       0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11,
+	       0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69,
+	       0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30,
+	       0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50,
+	       0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65,
+	       0x73, 0x74, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
+	       0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32,
+	       0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x33,
+	       0x39, 0x30, 0x38, 0x30, 0x38, 0x30, 0x30, 0x30, 0x31, 0x33,
+	       0x33, 0x5a, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06,
+	       0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17,
+	       0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43,
+	       0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68,
+	       0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
+	       0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69,
+	       0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55,
+	       0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79,
+	       0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31,
+	       0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08,
+	       0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f,
+	       0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69,
+	       0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74,
+	       0x65, 0x73, 0x74, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43,
+	       0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+	       0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+	       0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
+	       0xaa, 0x72, 0xb5, 0xc1, 0x73, 0xf4, 0x95, 0x76, 0xa4, 0x27,
+	       0xab, 0x5e, 0xeb, 0x1d, 0x9d, 0xd0, 0x04, 0xb2, 0x93, 0x05,
+	       0xc7, 0xfa, 0x75, 0x84, 0x66, 0xe6, 0x3a, 0x26, 0x1f, 0xbc,
+	       0x2d, 0xfd, 0x8f, 0x59, 0x64, 0xac, 0xcf, 0x65, 0x9d, 0x82,
+	       0x23, 0xc3, 0x72, 0x93, 0xf2, 0x40, 0x68, 0x32, 0xd1, 0xb8,
+	       0xf1, 0x47, 0x61, 0x50, 0xea, 0xbc, 0xcc, 0x3c, 0x6b, 0x74,
+	       0x7a, 0xec, 0x2b, 0x75, 0xa6, 0xc2, 0xa2, 0xb8, 0xbf, 0x23,
+	       0x48, 0x97, 0xd5, 0xaf, 0x77, 0xc1, 0x92, 0x88, 0xd7, 0x38,
+	       0xb7, 0x9e, 0xda, 0xee, 0x72, 0x04, 0xcb, 0x96, 0xe5, 0xdb,
+	       0xfd, 0x9b, 0x5d, 0x99, 0x4e, 0x7a, 0x60, 0x23, 0x34, 0xa4,
+	       0x8d, 0xd7, 0x6c, 0xe7, 0x5d, 0x93, 0x97, 0xe1, 0xab, 0x36,
+	       0x2c, 0x24, 0x16, 0x92, 0x66, 0xf6, 0x6a, 0x14, 0x23, 0x1d,
+	       0x18, 0xb9, 0x44, 0x24, 0x61, 0x6b, 0xd3, 0x75, 0x02, 0x03,
+	       0x01, 0x00, 0x01, 0xa3, 0x23, 0x30, 0x21, 0x30, 0x0f, 0x06,
+	       0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
+	       0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
+	       0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04,
+	       0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+	       0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x94,
+	       0x9e, 0xea, 0x17, 0x8d, 0x27, 0xa9, 0x17, 0xe5, 0xa9, 0x19,
+	       0xbe, 0x82, 0x36, 0xbd, 0xac, 0x74, 0xf3, 0x6e, 0x75, 0x71,
+	       0x30, 0x1c, 0x05, 0x80, 0x6d, 0x1a, 0x69, 0x37, 0x86, 0x9c,
+	       0x77, 0x75, 0x29, 0xa1, 0xc6, 0xb7, 0x11, 0x0a, 0x63, 0x27,
+	       0xee, 0xb1, 0xc8, 0x94, 0xa9, 0x2e, 0x56, 0x8f, 0xca, 0x9d,
+	       0xbe, 0xf4, 0xdb, 0x63, 0x97, 0x68, 0x3b, 0x13, 0xf8, 0x6a,
+	       0xa5, 0xd1, 0x3d, 0xed, 0xbb, 0x86, 0x9d, 0x42, 0xfc, 0x15,
+	       0x0a, 0x04, 0xf8, 0x3c, 0x0e, 0xc4, 0x86, 0x05, 0x57, 0x56,
+	       0x96, 0xf6, 0xc0, 0x18, 0x53, 0xb0, 0xc5, 0xf0, 0xca, 0x72,
+	       0x77, 0x77, 0xc9, 0x8e, 0x90, 0xa5, 0x4b, 0xb6, 0x80, 0x4a,
+	       0x4c, 0x34, 0x6f, 0xc9, 0xe8, 0x6f, 0xc2, 0x28, 0xdf, 0x93,
+	       0xa9, 0xf5, 0x63, 0x18, 0xc0, 0xec, 0x9e, 0xd5, 0x19, 0x36,
+	       0xc5, 0x94, 0x10, 0xd4, 0x72, 0xd2, 0xb8, 0x30, 0x82, 0x02,
+	       0xb6, 0x30, 0x82, 0x02, 0x1f, 0xa0, 0x03, 0x02, 0x01, 0x02,
+	       0x02, 0x01, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+	       0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
+	       0x90, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+	       0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
+	       0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72,
+	       0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31,
+	       0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09,
+	       0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31,
+	       0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f,
+	       0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d,
+	       0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06,
+	       0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65,
+	       0x2e, 0x6f, 0x72, 0x67, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03,
+	       0x55, 0x04, 0x03, 0x0c, 0x1e, 0x69, 0x50, 0x58, 0x45, 0x20,
+	       0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20,
+	       0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61,
+	       0x74, 0x65, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+	       0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33,
+	       0x33, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x32, 0x31, 0x37,
+	       0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x30, 0x81, 0x88,
+	       0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+	       0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55,
+	       0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69,
+	       0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12,
+	       0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43,
+	       0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18,
+	       0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46,
+	       0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73,
+	       0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+	       0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e,
+	       0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55,
+	       0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73,
+	       0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c,
+	       0x65, 0x61, 0x66, 0x20, 0x43, 0x41, 0x30, 0x81, 0x9f, 0x30,
+	       0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+	       0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81,
+	       0x89, 0x02, 0x81, 0x81, 0x00, 0xc3, 0x55, 0xad, 0xdf, 0x7b,
+	       0xd1, 0x48, 0xc3, 0xd3, 0x02, 0x54, 0x6c, 0x92, 0x45, 0x22,
+	       0x3d, 0x90, 0xd8, 0xc7, 0x13, 0xcd, 0xc1, 0x59, 0xc6, 0xe0,
+	       0xad, 0x0e, 0xe6, 0xdb, 0x3b, 0xe8, 0x63, 0xea, 0x4e, 0xb6,
+	       0xea, 0x50, 0xea, 0x6e, 0x33, 0x9d, 0x28, 0x25, 0x42, 0x49,
+	       0xd0, 0xf0, 0xed, 0xc5, 0x5b, 0x6b, 0x4a, 0xe7, 0x45, 0xfa,
+	       0xd3, 0x3f, 0xae, 0xde, 0x5a, 0x90, 0xab, 0xf1, 0x61, 0x2f,
+	       0x40, 0x5e, 0xcf, 0x8b, 0x0b, 0x10, 0x59, 0xa9, 0xd0, 0x1e,
+	       0x0f, 0x18, 0x6b, 0x92, 0xd8, 0x9f, 0x58, 0x10, 0x84, 0xb6,
+	       0x15, 0xe8, 0x5b, 0xc4, 0xa0, 0x3e, 0x49, 0x8b, 0xea, 0xdd,
+	       0xa9, 0x7e, 0x32, 0x26, 0x9a, 0x68, 0x44, 0xf0, 0x30, 0xca,
+	       0x2a, 0xd6, 0x19, 0x7a, 0x80, 0xfd, 0xd7, 0xfc, 0xc7, 0x5d,
+	       0xe7, 0x61, 0xd2, 0x3f, 0x1f, 0x2c, 0x40, 0x70, 0x7b, 0x34,
+	       0xcb, 0x08, 0xa9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x26,
+	       0x30, 0x24, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
+	       0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02,
+	       0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+	       0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d,
+	       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+	       0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x40, 0xd2, 0x70,
+	       0x02, 0x08, 0x19, 0xa0, 0xb8, 0x8d, 0x9d, 0x3d, 0x62, 0x41,
+	       0x90, 0x2a, 0x36, 0x4a, 0x8b, 0x21, 0x42, 0x9a, 0xb4, 0xc5,
+	       0xf8, 0x79, 0x17, 0xd7, 0x64, 0x4d, 0xbf, 0x8f, 0x6a, 0x04,
+	       0x54, 0x7a, 0x0b, 0xd4, 0xb5, 0x0e, 0xab, 0xf7, 0xb7, 0x06,
+	       0x2b, 0xf8, 0xde, 0x87, 0xb2, 0x37, 0x3b, 0x95, 0x01, 0xba,
+	       0x9f, 0x8f, 0xec, 0x0a, 0x86, 0xca, 0x51, 0xb6, 0x25, 0x73,
+	       0x2f, 0xa1, 0x66, 0xc8, 0x7a, 0x5e, 0x51, 0xbd, 0x49, 0xb5,
+	       0x75, 0xda, 0xea, 0xe5, 0xeb, 0x5d, 0xe3, 0xb0, 0xad, 0x49,
+	       0x9f, 0x8b, 0xfd, 0x89, 0xb3, 0xb7, 0xb2, 0x4c, 0x7d, 0x8a,
+	       0x29, 0xb2, 0xbe, 0x04, 0xef, 0x9c, 0x73, 0x3c, 0xea, 0xa3,
+	       0x9f, 0x07, 0x66, 0x5a, 0x2f, 0x38, 0xad, 0x1a, 0xeb, 0xe1,
+	       0xb0, 0x62, 0x14, 0x55, 0xdc, 0x8c, 0x83, 0xbb, 0xc7, 0x13,
+	       0x04, 0x41, 0x54, 0xf1, 0x45, 0x31, 0x82, 0x01, 0x33, 0x30,
+	       0x82, 0x01, 0x2f, 0x02, 0x01, 0x01, 0x30, 0x81, 0x8e, 0x30,
+	       0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+	       0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06,
+	       0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62,
+	       0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65,
+	       0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
+	       0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65,
+	       0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
+	       0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65,
+	       0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f,
+	       0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78,
+	       0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06,
+	       0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45,
+	       0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74,
+	       0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, 0x41, 0x02, 0x01,
+	       0x04, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a,
+	       0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+	       0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x81, 0x80, 0x1f, 0x95,
+	       0x53, 0x9c, 0x63, 0xcc, 0x9e, 0xe3, 0x41, 0x30, 0xaf, 0x66,
+	       0xac, 0x7c, 0x39, 0x69, 0xa0, 0x02, 0xe3, 0x28, 0xfa, 0xf6,
+	       0x71, 0xf4, 0xcf, 0x97, 0x2a, 0xbb, 0xe0, 0x1d, 0x71, 0x73,
+	       0x4a, 0xa7, 0xea, 0xb0, 0x72, 0xc3, 0xd2, 0xba, 0x52, 0x42,
+	       0x06, 0x88, 0x4a, 0xa6, 0x41, 0x1d, 0x2f, 0x82, 0xb3, 0x7d,
+	       0x32, 0x59, 0x34, 0x4e, 0x47, 0x1b, 0xaa, 0x5e, 0x90, 0xe2,
+	       0x73, 0x62, 0x2d, 0x6f, 0x6c, 0x47, 0x52, 0x05, 0x90, 0xcb,
+	       0xac, 0x30, 0xa8, 0x20, 0x71, 0x14, 0x39, 0x16, 0x85, 0x3d,
+	       0x32, 0x2f, 0x9d, 0x31, 0x97, 0xa8, 0x96, 0xb9, 0xf2, 0x2b,
+	       0xdc, 0xa6, 0x2f, 0x68, 0xc7, 0xac, 0x46, 0xa2, 0xc7, 0x26,
+	       0xd0, 0xde, 0xac, 0x1d, 0x5d, 0x70, 0x65, 0xc6, 0x26, 0xdd,
+	       0x30, 0x3f, 0x3a, 0xbd, 0x5e, 0x8f, 0x87, 0x64, 0xab, 0xe7,
+	       0xf9, 0x71, 0x64, 0x03, 0x05, 0xbf ) );
+
+/** Signature generated with a non-code-signing certificate */
+SIGNATURE ( genericsigned_sig,
+	DATA ( 0x30, 0x82, 0x0c, 0x2f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+	       0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x0c, 0x20, 0x30,
+	       0x82, 0x0c, 0x1c, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07,
+	       0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x30, 0x0b, 0x06,
+	       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+	       0xa0, 0x82, 0x0a, 0xc6, 0x30, 0x82, 0x02, 0x9a, 0x30, 0x82,
+	       0x02, 0x03, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x05,
+	       0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+	       0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b,
+	       0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47,
+	       0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08,
+	       0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67,
+	       0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10,
+	       0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d,
+	       0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16,
+	       0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e,
+	       0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c,
+	       0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
+	       0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72,
+	       0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03,
+	       0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c,
+	       0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61,
+	       0x66, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32,
+	       0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x35,
+	       0x5a, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x33, 0x32, 0x32, 0x30,
+	       0x30, 0x30, 0x31, 0x33, 0x35, 0x5a, 0x30, 0x81, 0x8b, 0x31,
+	       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+	       0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30,
+	       0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30,
+	       0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65,
+	       0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20,
+	       0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
+	       0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f,
+	       0x72, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04,
+	       0x03, 0x0c, 0x19, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63,
+	       0x73, 0x69, 0x67, 0x6e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e,
+	       0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x81,
+	       0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00,
+	       0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xc6, 0xfc, 0x96,
+	       0x1e, 0x90, 0x32, 0xed, 0xb8, 0x54, 0xb2, 0xc2, 0x39, 0x66,
+	       0x19, 0xca, 0xd8, 0x45, 0x21, 0xb7, 0x5a, 0x8d, 0x8d, 0x71,
+	       0xef, 0x69, 0x37, 0x40, 0xbb, 0xa4, 0xde, 0x09, 0x1b, 0x17,
+	       0x83, 0x3a, 0x7a, 0xf1, 0x7b, 0x02, 0x31, 0x5d, 0x1f, 0x3a,
+	       0xe5, 0x29, 0x28, 0x9b, 0x7e, 0x7b, 0x5a, 0xc4, 0x18, 0x3e,
+	       0x43, 0xe6, 0xe9, 0x6e, 0xd1, 0x8d, 0x86, 0xcf, 0xb5, 0x9f,
+	       0x7f, 0x50, 0x4e, 0x06, 0x13, 0xf7, 0xb2, 0xee, 0xef, 0x0e,
+	       0xab, 0x50, 0x44, 0x42, 0xfd, 0x3a, 0xa9, 0x47, 0x83, 0x34,
+	       0x17, 0xdf, 0xee, 0x3d, 0x84, 0x1f, 0xed, 0x7e, 0xfa, 0x0f,
+	       0xa8, 0xfc, 0x07, 0xf8, 0xd1, 0x49, 0x99, 0x1a, 0xad, 0x39,
+	       0x16, 0xb3, 0x71, 0x15, 0x2e, 0x82, 0x20, 0x7a, 0x92, 0xed,
+	       0x1e, 0x37, 0xf6, 0x46, 0x5e, 0x7d, 0x9b, 0xa1, 0x53, 0x4d,
+	       0x13, 0x91, 0xcd, 0x7a, 0x77, 0x02, 0x03, 0x01, 0x00, 0x01,
+	       0xa3, 0x0f, 0x30, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d,
+	       0x0f, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x0d, 0x06,
+	       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+	       0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0xb2, 0x39, 0x0b, 0x02,
+	       0x33, 0xca, 0x48, 0x96, 0x13, 0x53, 0xe9, 0x1b, 0x28, 0xd6,
+	       0x35, 0x4e, 0x0c, 0x9d, 0xd0, 0xe3, 0x79, 0x65, 0x0a, 0xe7,
+	       0xa6, 0x22, 0x61, 0x26, 0xbe, 0xb4, 0x05, 0xec, 0x5f, 0x83,
+	       0xb7, 0x0e, 0xa4, 0xae, 0x50, 0xb1, 0xa9, 0x45, 0x25, 0xf2,
+	       0x52, 0x1a, 0x63, 0x05, 0x50, 0x75, 0x33, 0xca, 0x8a, 0xb1,
+	       0xf2, 0x19, 0xd3, 0x93, 0x84, 0x67, 0x42, 0xe3, 0xb7, 0xa6,
+	       0xf9, 0x4d, 0x90, 0x7e, 0x13, 0x40, 0xd3, 0x22, 0x9f, 0x83,
+	       0xaf, 0x70, 0xb2, 0x7d, 0x4d, 0xcc, 0xae, 0x18, 0x9e, 0xca,
+	       0xc8, 0xcb, 0x82, 0x93, 0xcb, 0xce, 0xc6, 0x32, 0xcf, 0x4e,
+	       0x04, 0x64, 0x18, 0x5b, 0xc2, 0x1a, 0xb6, 0xd1, 0x8a, 0xc4,
+	       0x99, 0xce, 0xdd, 0xd7, 0x7e, 0xec, 0xf5, 0xa9, 0xa7, 0x00,
+	       0xc2, 0xd3, 0x6a, 0xb9, 0xcd, 0x25, 0x88, 0x08, 0x71, 0xf5,
+	       0x6d, 0x44, 0xe7, 0x93, 0x30, 0x82, 0x02, 0xb3, 0x30, 0x82,
+	       0x02, 0x1c, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02,
+	       0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+	       0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b,
+	       0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47,
+	       0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08,
+	       0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67,
+	       0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10,
+	       0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d,
+	       0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16,
+	       0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e,
+	       0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c,
+	       0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
+	       0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72,
+	       0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03,
+	       0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c,
+	       0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x72, 0x6f, 0x6f,
+	       0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32,
+	       0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33,
+	       0x5a, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x32, 0x31, 0x37, 0x30,
+	       0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x30, 0x81, 0x90, 0x31,
+	       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+	       0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30,
+	       0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30,
+	       0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65,
+	       0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20,
+	       0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
+	       0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f,
+	       0x72, 0x67, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04,
+	       0x03, 0x0c, 0x1e, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65,
+	       0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6e,
+	       0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65,
+	       0x20, 0x43, 0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
+	       0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+	       0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81,
+	       0x81, 0x00, 0xc9, 0x3a, 0xee, 0xc6, 0x3c, 0xac, 0x4d, 0x81,
+	       0xc6, 0x98, 0x5e, 0xe1, 0x48, 0x66, 0x1a, 0x1e, 0x60, 0x19,
+	       0x41, 0xae, 0xca, 0x14, 0x97, 0xc8, 0x3a, 0x50, 0xb6, 0x48,
+	       0xf5, 0x42, 0xac, 0x0f, 0xe1, 0xe3, 0x47, 0xf0, 0xbf, 0x7c,
+	       0xd0, 0xee, 0x8f, 0xb7, 0xa6, 0x19, 0xad, 0xbb, 0xc5, 0x1b,
+	       0x34, 0x38, 0xc8, 0xbd, 0x55, 0x84, 0x93, 0x72, 0xaf, 0x84,
+	       0xfc, 0x9b, 0x97, 0x1d, 0xb5, 0x54, 0x24, 0xd6, 0x5d, 0xb7,
+	       0x31, 0xf4, 0xbd, 0x3b, 0x40, 0x97, 0xc0, 0xa9, 0x5a, 0x2a,
+	       0xcb, 0x6b, 0x98, 0x07, 0xdb, 0xb5, 0x9f, 0xe8, 0x31, 0x3f,
+	       0x01, 0x46, 0x46, 0x70, 0x05, 0xa2, 0x0f, 0x8c, 0x7a, 0x61,
+	       0xf3, 0xdf, 0xdb, 0xa1, 0x37, 0x2c, 0x88, 0x6a, 0x81, 0x21,
+	       0x12, 0x4c, 0xf5, 0xcd, 0xaf, 0xc9, 0xd2, 0x36, 0x3d, 0x82,
+	       0xd1, 0xca, 0x19, 0xaf, 0x4e, 0xae, 0x50, 0x71, 0x44, 0xbf,
+	       0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x23, 0x30, 0x21, 0x30,
+	       0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
+	       0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03,
+	       0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
+	       0x02, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+	       0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81,
+	       0x00, 0x5d, 0x3c, 0xb3, 0x52, 0x19, 0xa6, 0x9e, 0x4a, 0x44,
+	       0x98, 0xbf, 0x51, 0x20, 0x47, 0x0a, 0xf3, 0x26, 0x1a, 0xcc,
+	       0x35, 0x2f, 0xc9, 0xed, 0xe0, 0x9d, 0x46, 0xeb, 0xbc, 0x7e,
+	       0xc9, 0xb9, 0x1d, 0x76, 0xa4, 0x1d, 0xc2, 0xd9, 0x16, 0x29,
+	       0x77, 0x01, 0x40, 0xdd, 0xe5, 0xcb, 0x28, 0x91, 0x3a, 0x0c,
+	       0x13, 0x01, 0x1b, 0x72, 0x62, 0x45, 0x27, 0xfd, 0xd7, 0x00,
+	       0x47, 0x36, 0x09, 0x1e, 0x7b, 0xd2, 0xcb, 0x95, 0x3d, 0x28,
+	       0x82, 0xce, 0x83, 0x59, 0x32, 0xf9, 0xe6, 0xec, 0x89, 0xac,
+	       0x88, 0x45, 0x22, 0x88, 0x6f, 0x5e, 0xa2, 0x79, 0x95, 0xba,
+	       0xb9, 0xc9, 0xb6, 0x4c, 0x7c, 0xb4, 0x29, 0xa1, 0x02, 0xf5,
+	       0xac, 0x5d, 0x8e, 0x52, 0xeb, 0xe8, 0xb1, 0x56, 0x49, 0xb3,
+	       0x77, 0x62, 0x7d, 0x87, 0x4d, 0x17, 0xf2, 0x62, 0x83, 0x08,
+	       0x59, 0x21, 0x60, 0x0d, 0x84, 0x8e, 0x5a, 0x84, 0xf6, 0x30,
+	       0x82, 0x02, 0xb3, 0x30, 0x82, 0x02, 0x1c, 0xa0, 0x03, 0x02,
+	       0x01, 0x02, 0x02, 0x09, 0x00, 0xc6, 0xb8, 0x9c, 0x58, 0xd2,
+	       0xdc, 0xc9, 0x5d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+	       0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
+	       0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+	       0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
+	       0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72,
+	       0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31,
+	       0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09,
+	       0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31,
+	       0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f,
+	       0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d,
+	       0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06,
+	       0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65,
+	       0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03,
+	       0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20,
+	       0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20,
+	       0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17,
+	       0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30,
+	       0x31, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x39, 0x30, 0x38,
+	       0x30, 0x38, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x30,
+	       0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+	       0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06,
+	       0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62,
+	       0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65,
+	       0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
+	       0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65,
+	       0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
+	       0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65,
+	       0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f,
+	       0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78,
+	       0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06,
+	       0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45,
+	       0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74,
+	       0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x81,
+	       0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00,
+	       0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xaa, 0x72, 0xb5,
+	       0xc1, 0x73, 0xf4, 0x95, 0x76, 0xa4, 0x27, 0xab, 0x5e, 0xeb,
+	       0x1d, 0x9d, 0xd0, 0x04, 0xb2, 0x93, 0x05, 0xc7, 0xfa, 0x75,
+	       0x84, 0x66, 0xe6, 0x3a, 0x26, 0x1f, 0xbc, 0x2d, 0xfd, 0x8f,
+	       0x59, 0x64, 0xac, 0xcf, 0x65, 0x9d, 0x82, 0x23, 0xc3, 0x72,
+	       0x93, 0xf2, 0x40, 0x68, 0x32, 0xd1, 0xb8, 0xf1, 0x47, 0x61,
+	       0x50, 0xea, 0xbc, 0xcc, 0x3c, 0x6b, 0x74, 0x7a, 0xec, 0x2b,
+	       0x75, 0xa6, 0xc2, 0xa2, 0xb8, 0xbf, 0x23, 0x48, 0x97, 0xd5,
+	       0xaf, 0x77, 0xc1, 0x92, 0x88, 0xd7, 0x38, 0xb7, 0x9e, 0xda,
+	       0xee, 0x72, 0x04, 0xcb, 0x96, 0xe5, 0xdb, 0xfd, 0x9b, 0x5d,
+	       0x99, 0x4e, 0x7a, 0x60, 0x23, 0x34, 0xa4, 0x8d, 0xd7, 0x6c,
+	       0xe7, 0x5d, 0x93, 0x97, 0xe1, 0xab, 0x36, 0x2c, 0x24, 0x16,
+	       0x92, 0x66, 0xf6, 0x6a, 0x14, 0x23, 0x1d, 0x18, 0xb9, 0x44,
+	       0x24, 0x61, 0x6b, 0xd3, 0x75, 0x02, 0x03, 0x01, 0x00, 0x01,
+	       0xa3, 0x23, 0x30, 0x21, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
+	       0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01,
+	       0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
+	       0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d, 0x06,
+	       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+	       0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x94, 0x9e, 0xea, 0x17,
+	       0x8d, 0x27, 0xa9, 0x17, 0xe5, 0xa9, 0x19, 0xbe, 0x82, 0x36,
+	       0xbd, 0xac, 0x74, 0xf3, 0x6e, 0x75, 0x71, 0x30, 0x1c, 0x05,
+	       0x80, 0x6d, 0x1a, 0x69, 0x37, 0x86, 0x9c, 0x77, 0x75, 0x29,
+	       0xa1, 0xc6, 0xb7, 0x11, 0x0a, 0x63, 0x27, 0xee, 0xb1, 0xc8,
+	       0x94, 0xa9, 0x2e, 0x56, 0x8f, 0xca, 0x9d, 0xbe, 0xf4, 0xdb,
+	       0x63, 0x97, 0x68, 0x3b, 0x13, 0xf8, 0x6a, 0xa5, 0xd1, 0x3d,
+	       0xed, 0xbb, 0x86, 0x9d, 0x42, 0xfc, 0x15, 0x0a, 0x04, 0xf8,
+	       0x3c, 0x0e, 0xc4, 0x86, 0x05, 0x57, 0x56, 0x96, 0xf6, 0xc0,
+	       0x18, 0x53, 0xb0, 0xc5, 0xf0, 0xca, 0x72, 0x77, 0x77, 0xc9,
+	       0x8e, 0x90, 0xa5, 0x4b, 0xb6, 0x80, 0x4a, 0x4c, 0x34, 0x6f,
+	       0xc9, 0xe8, 0x6f, 0xc2, 0x28, 0xdf, 0x93, 0xa9, 0xf5, 0x63,
+	       0x18, 0xc0, 0xec, 0x9e, 0xd5, 0x19, 0x36, 0xc5, 0x94, 0x10,
+	       0xd4, 0x72, 0xd2, 0xb8, 0x30, 0x82, 0x02, 0xb6, 0x30, 0x82,
+	       0x02, 0x1f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02,
+	       0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+	       0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x90, 0x31, 0x0b,
+	       0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47,
+	       0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08,
+	       0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67,
+	       0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10,
+	       0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d,
+	       0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16,
+	       0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e,
+	       0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c,
+	       0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
+	       0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72,
+	       0x67, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03,
+	       0x0c, 0x1e, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c,
+	       0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x74,
+	       0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20,
+	       0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33,
+	       0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x17,
+	       0x0d, 0x31, 0x34, 0x31, 0x32, 0x31, 0x37, 0x30, 0x30, 0x30,
+	       0x31, 0x33, 0x33, 0x5a, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30,
+	       0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42,
+	       0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
+	       0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65,
+	       0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06,
+	       0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62,
+	       0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06,
+	       0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20,
+	       0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74,
+	       0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b,
+	       0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67,
+	       0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
+	       0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66,
+	       0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66,
+	       0x20, 0x43, 0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
+	       0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+	       0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81,
+	       0x81, 0x00, 0xc3, 0x55, 0xad, 0xdf, 0x7b, 0xd1, 0x48, 0xc3,
+	       0xd3, 0x02, 0x54, 0x6c, 0x92, 0x45, 0x22, 0x3d, 0x90, 0xd8,
+	       0xc7, 0x13, 0xcd, 0xc1, 0x59, 0xc6, 0xe0, 0xad, 0x0e, 0xe6,
+	       0xdb, 0x3b, 0xe8, 0x63, 0xea, 0x4e, 0xb6, 0xea, 0x50, 0xea,
+	       0x6e, 0x33, 0x9d, 0x28, 0x25, 0x42, 0x49, 0xd0, 0xf0, 0xed,
+	       0xc5, 0x5b, 0x6b, 0x4a, 0xe7, 0x45, 0xfa, 0xd3, 0x3f, 0xae,
+	       0xde, 0x5a, 0x90, 0xab, 0xf1, 0x61, 0x2f, 0x40, 0x5e, 0xcf,
+	       0x8b, 0x0b, 0x10, 0x59, 0xa9, 0xd0, 0x1e, 0x0f, 0x18, 0x6b,
+	       0x92, 0xd8, 0x9f, 0x58, 0x10, 0x84, 0xb6, 0x15, 0xe8, 0x5b,
+	       0xc4, 0xa0, 0x3e, 0x49, 0x8b, 0xea, 0xdd, 0xa9, 0x7e, 0x32,
+	       0x26, 0x9a, 0x68, 0x44, 0xf0, 0x30, 0xca, 0x2a, 0xd6, 0x19,
+	       0x7a, 0x80, 0xfd, 0xd7, 0xfc, 0xc7, 0x5d, 0xe7, 0x61, 0xd2,
+	       0x3f, 0x1f, 0x2c, 0x40, 0x70, 0x7b, 0x34, 0xcb, 0x08, 0xa9,
+	       0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x26, 0x30, 0x24, 0x30,
+	       0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
+	       0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30,
+	       0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04,
+	       0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+	       0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+	       0x03, 0x81, 0x81, 0x00, 0x40, 0xd2, 0x70, 0x02, 0x08, 0x19,
+	       0xa0, 0xb8, 0x8d, 0x9d, 0x3d, 0x62, 0x41, 0x90, 0x2a, 0x36,
+	       0x4a, 0x8b, 0x21, 0x42, 0x9a, 0xb4, 0xc5, 0xf8, 0x79, 0x17,
+	       0xd7, 0x64, 0x4d, 0xbf, 0x8f, 0x6a, 0x04, 0x54, 0x7a, 0x0b,
+	       0xd4, 0xb5, 0x0e, 0xab, 0xf7, 0xb7, 0x06, 0x2b, 0xf8, 0xde,
+	       0x87, 0xb2, 0x37, 0x3b, 0x95, 0x01, 0xba, 0x9f, 0x8f, 0xec,
+	       0x0a, 0x86, 0xca, 0x51, 0xb6, 0x25, 0x73, 0x2f, 0xa1, 0x66,
+	       0xc8, 0x7a, 0x5e, 0x51, 0xbd, 0x49, 0xb5, 0x75, 0xda, 0xea,
+	       0xe5, 0xeb, 0x5d, 0xe3, 0xb0, 0xad, 0x49, 0x9f, 0x8b, 0xfd,
+	       0x89, 0xb3, 0xb7, 0xb2, 0x4c, 0x7d, 0x8a, 0x29, 0xb2, 0xbe,
+	       0x04, 0xef, 0x9c, 0x73, 0x3c, 0xea, 0xa3, 0x9f, 0x07, 0x66,
+	       0x5a, 0x2f, 0x38, 0xad, 0x1a, 0xeb, 0xe1, 0xb0, 0x62, 0x14,
+	       0x55, 0xdc, 0x8c, 0x83, 0xbb, 0xc7, 0x13, 0x04, 0x41, 0x54,
+	       0xf1, 0x45, 0x31, 0x82, 0x01, 0x33, 0x30, 0x82, 0x01, 0x2f,
+	       0x02, 0x01, 0x01, 0x30, 0x81, 0x8e, 0x30, 0x81, 0x88, 0x31,
+	       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+	       0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30,
+	       0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30,
+	       0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65,
+	       0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20,
+	       0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
+	       0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f,
+	       0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04,
+	       0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65,
+	       0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65,
+	       0x61, 0x66, 0x20, 0x43, 0x41, 0x02, 0x01, 0x05, 0x30, 0x07,
+	       0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x30, 0x0d, 0x06,
+	       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+	       0x05, 0x00, 0x04, 0x81, 0x80, 0xc5, 0x08, 0x17, 0x23, 0xb9,
+	       0x8d, 0x45, 0x0b, 0x1a, 0x9a, 0x10, 0xa7, 0x16, 0x57, 0x05,
+	       0x86, 0x0c, 0x9a, 0xfd, 0x2d, 0x9c, 0x87, 0x15, 0xb3, 0x0f,
+	       0xd5, 0x3b, 0x7b, 0xa8, 0xce, 0xa2, 0xcc, 0x2a, 0x2a, 0x6a,
+	       0xa0, 0xab, 0x2f, 0x57, 0x8c, 0xb7, 0xc7, 0x4e, 0x2a, 0xbd,
+	       0x72, 0xc5, 0xef, 0x2a, 0xd8, 0xb8, 0xf2, 0x9d, 0xbe, 0xd4,
+	       0xa7, 0x55, 0x3e, 0x06, 0x3b, 0x3f, 0xfa, 0x92, 0x4f, 0x1f,
+	       0x84, 0x84, 0x16, 0xcf, 0x9b, 0x26, 0x71, 0xf7, 0x57, 0x6a,
+	       0x6d, 0xdd, 0x34, 0x6b, 0x12, 0xc4, 0x70, 0x78, 0x59, 0x9b,
+	       0xf7, 0x45, 0xf4, 0xae, 0x30, 0xb0, 0x8c, 0x21, 0xb7, 0xb1,
+	       0x96, 0xda, 0x91, 0x0e, 0x57, 0x7e, 0x1b, 0xe2, 0xef, 0x82,
+	       0xd5, 0xa3, 0xd1, 0xeb, 0x47, 0x5c, 0x33, 0x91, 0xf8, 0x90,
+	       0xf9, 0x99, 0x0c, 0x69, 0x05, 0xee, 0xa1, 0x1a, 0x2d, 0x44,
+	       0x7e, 0x7c, 0x99 ) );
+
+/** Signature generated with a non-signing certificate */
+SIGNATURE ( nonsigned_sig,
+	DATA ( 0x30, 0x82, 0x0c, 0x12, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+	       0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x0c, 0x03, 0x30,
+	       0x82, 0x0b, 0xff, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07,
+	       0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x30, 0x0b, 0x06,
+	       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01,
+	       0xa0, 0x82, 0x0a, 0xa9, 0x30, 0x82, 0x02, 0x7d, 0x30, 0x82,
+	       0x01, 0xe6, 0x02, 0x01, 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+	       0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+	       0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+	       0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15,
+	       0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d,
+	       0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72,
+	       0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07,
+	       0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67,
+	       0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a,
+	       0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74,
+	       0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30,
+	       0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70,
+	       0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d,
+	       0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58,
+	       0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73,
+	       0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, 0x41, 0x30,
+	       0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, 0x30,
+	       0x30, 0x30, 0x31, 0x33, 0x34, 0x5a, 0x17, 0x0d, 0x31, 0x33,
+	       0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x34,
+	       0x5a, 0x30, 0x81, 0x84, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+	       0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30,
+	       0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69,
+	       0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
+	       0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04,
+	       0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73,
+	       0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11,
+	       0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69,
+	       0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1b, 0x30,
+	       0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x12, 0x62, 0x6f,
+	       0x6f, 0x74, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70,
+	       0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x81, 0x9f, 0x30,
+	       0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+	       0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81,
+	       0x89, 0x02, 0x81, 0x81, 0x00, 0xbd, 0x43, 0x97, 0x45, 0xa2,
+	       0xe0, 0x1d, 0x38, 0x41, 0xb0, 0xd9, 0x91, 0xf9, 0x77, 0xa9,
+	       0xcb, 0x9c, 0x9c, 0x93, 0xfe, 0x5a, 0xee, 0xbc, 0xd9, 0x0f,
+	       0x39, 0xf6, 0x42, 0xe4, 0x55, 0x21, 0xbb, 0x11, 0xfd, 0xfd,
+	       0xba, 0x25, 0x58, 0xc8, 0xc6, 0xa5, 0x3b, 0x6f, 0x80, 0xba,
+	       0x5b, 0xbc, 0x89, 0xca, 0x7a, 0xdf, 0x6e, 0xb9, 0x81, 0xb6,
+	       0x25, 0x67, 0x0a, 0x38, 0x10, 0xf8, 0x26, 0x43, 0x0c, 0x51,
+	       0x02, 0x14, 0xd6, 0xf2, 0x9d, 0x7c, 0xf5, 0x25, 0x1c, 0x78,
+	       0x4d, 0x47, 0xaf, 0x87, 0x2e, 0x38, 0x49, 0x87, 0xb5, 0x8a,
+	       0xf3, 0xb5, 0xd4, 0x15, 0x69, 0x2a, 0x52, 0xc9, 0x46, 0x97,
+	       0x34, 0x8e, 0x50, 0x4b, 0xc4, 0xf2, 0xfb, 0x39, 0xfd, 0x16,
+	       0x68, 0xdb, 0xa8, 0x17, 0xe2, 0x71, 0x4b, 0xe0, 0xdf, 0x3d,
+	       0xfc, 0xc3, 0x9b, 0x9d, 0x22, 0xc9, 0xd3, 0xf6, 0x02, 0xa6,
+	       0x60, 0xef, 0xf7, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d,
+	       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+	       0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x7d, 0xff, 0x73,
+	       0xf3, 0x68, 0xe3, 0x75, 0xf1, 0xcf, 0xac, 0x2e, 0x23, 0x73,
+	       0xea, 0xd1, 0x26, 0x33, 0xbf, 0xf9, 0x56, 0xdf, 0xbf, 0x98,
+	       0x20, 0x84, 0x08, 0x78, 0x6b, 0xe6, 0x71, 0x7e, 0x22, 0x68,
+	       0x4d, 0x6c, 0xbb, 0xd5, 0xcc, 0xb4, 0x28, 0x33, 0x5e, 0xbe,
+	       0x4d, 0x10, 0x16, 0x9f, 0x65, 0x3b, 0x68, 0x90, 0xa7, 0xf7,
+	       0x9d, 0x57, 0x71, 0x45, 0x39, 0x86, 0x4c, 0xc0, 0x97, 0x34,
+	       0x03, 0x9c, 0x2b, 0x25, 0x05, 0xb1, 0x5c, 0x0c, 0x4e, 0xf2,
+	       0x14, 0xbf, 0xcf, 0xf0, 0x9a, 0x2d, 0xcf, 0x02, 0x47, 0x60,
+	       0xd2, 0xe9, 0xed, 0xbf, 0x71, 0x5d, 0x07, 0x09, 0x01, 0x87,
+	       0xeb, 0xf7, 0xa8, 0x26, 0x86, 0x24, 0x59, 0xf0, 0x31, 0x3b,
+	       0x42, 0xd1, 0xf1, 0xfd, 0x7c, 0x49, 0x5f, 0x1a, 0xf0, 0x41,
+	       0x67, 0xf0, 0x16, 0x3a, 0xfd, 0xb6, 0xb5, 0xf6, 0x2e, 0x0c,
+	       0x18, 0x1f, 0x09, 0x8e, 0x4d, 0x30, 0x82, 0x02, 0xb3, 0x30,
+	       0x82, 0x02, 0x1c, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01,
+	       0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31,
+	       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+	       0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30,
+	       0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30,
+	       0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65,
+	       0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20,
+	       0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
+	       0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f,
+	       0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04,
+	       0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65,
+	       0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x72, 0x6f,
+	       0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+	       0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33,
+	       0x33, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x32, 0x31, 0x37,
+	       0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x30, 0x81, 0x90,
+	       0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+	       0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55,
+	       0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69,
+	       0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12,
+	       0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43,
+	       0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18,
+	       0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46,
+	       0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73,
+	       0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+	       0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e,
+	       0x6f, 0x72, 0x67, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55,
+	       0x04, 0x03, 0x0c, 0x1e, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73,
+	       0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x69,
+	       0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74,
+	       0x65, 0x20, 0x43, 0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06,
+	       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+	       0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02,
+	       0x81, 0x81, 0x00, 0xc9, 0x3a, 0xee, 0xc6, 0x3c, 0xac, 0x4d,
+	       0x81, 0xc6, 0x98, 0x5e, 0xe1, 0x48, 0x66, 0x1a, 0x1e, 0x60,
+	       0x19, 0x41, 0xae, 0xca, 0x14, 0x97, 0xc8, 0x3a, 0x50, 0xb6,
+	       0x48, 0xf5, 0x42, 0xac, 0x0f, 0xe1, 0xe3, 0x47, 0xf0, 0xbf,
+	       0x7c, 0xd0, 0xee, 0x8f, 0xb7, 0xa6, 0x19, 0xad, 0xbb, 0xc5,
+	       0x1b, 0x34, 0x38, 0xc8, 0xbd, 0x55, 0x84, 0x93, 0x72, 0xaf,
+	       0x84, 0xfc, 0x9b, 0x97, 0x1d, 0xb5, 0x54, 0x24, 0xd6, 0x5d,
+	       0xb7, 0x31, 0xf4, 0xbd, 0x3b, 0x40, 0x97, 0xc0, 0xa9, 0x5a,
+	       0x2a, 0xcb, 0x6b, 0x98, 0x07, 0xdb, 0xb5, 0x9f, 0xe8, 0x31,
+	       0x3f, 0x01, 0x46, 0x46, 0x70, 0x05, 0xa2, 0x0f, 0x8c, 0x7a,
+	       0x61, 0xf3, 0xdf, 0xdb, 0xa1, 0x37, 0x2c, 0x88, 0x6a, 0x81,
+	       0x21, 0x12, 0x4c, 0xf5, 0xcd, 0xaf, 0xc9, 0xd2, 0x36, 0x3d,
+	       0x82, 0xd1, 0xca, 0x19, 0xaf, 0x4e, 0xae, 0x50, 0x71, 0x44,
+	       0xbf, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x23, 0x30, 0x21,
+	       0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+	       0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06,
+	       0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
+	       0x02, 0x02, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+	       0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
+	       0x81, 0x00, 0x5d, 0x3c, 0xb3, 0x52, 0x19, 0xa6, 0x9e, 0x4a,
+	       0x44, 0x98, 0xbf, 0x51, 0x20, 0x47, 0x0a, 0xf3, 0x26, 0x1a,
+	       0xcc, 0x35, 0x2f, 0xc9, 0xed, 0xe0, 0x9d, 0x46, 0xeb, 0xbc,
+	       0x7e, 0xc9, 0xb9, 0x1d, 0x76, 0xa4, 0x1d, 0xc2, 0xd9, 0x16,
+	       0x29, 0x77, 0x01, 0x40, 0xdd, 0xe5, 0xcb, 0x28, 0x91, 0x3a,
+	       0x0c, 0x13, 0x01, 0x1b, 0x72, 0x62, 0x45, 0x27, 0xfd, 0xd7,
+	       0x00, 0x47, 0x36, 0x09, 0x1e, 0x7b, 0xd2, 0xcb, 0x95, 0x3d,
+	       0x28, 0x82, 0xce, 0x83, 0x59, 0x32, 0xf9, 0xe6, 0xec, 0x89,
+	       0xac, 0x88, 0x45, 0x22, 0x88, 0x6f, 0x5e, 0xa2, 0x79, 0x95,
+	       0xba, 0xb9, 0xc9, 0xb6, 0x4c, 0x7c, 0xb4, 0x29, 0xa1, 0x02,
+	       0xf5, 0xac, 0x5d, 0x8e, 0x52, 0xeb, 0xe8, 0xb1, 0x56, 0x49,
+	       0xb3, 0x77, 0x62, 0x7d, 0x87, 0x4d, 0x17, 0xf2, 0x62, 0x83,
+	       0x08, 0x59, 0x21, 0x60, 0x0d, 0x84, 0x8e, 0x5a, 0x84, 0xf6,
+	       0x30, 0x82, 0x02, 0xb3, 0x30, 0x82, 0x02, 0x1c, 0xa0, 0x03,
+	       0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xc6, 0xb8, 0x9c, 0x58,
+	       0xd2, 0xdc, 0xc9, 0x5d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+	       0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
+	       0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+	       0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06,
+	       0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62,
+	       0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65,
+	       0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
+	       0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65,
+	       0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
+	       0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65,
+	       0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f,
+	       0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78,
+	       0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06,
+	       0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45,
+	       0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74,
+	       0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e,
+	       0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30,
+	       0x30, 0x31, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x39, 0x30,
+	       0x38, 0x30, 0x38, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a,
+	       0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+	       0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15,
+	       0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d,
+	       0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72,
+	       0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07,
+	       0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67,
+	       0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a,
+	       0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74,
+	       0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30,
+	       0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70,
+	       0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d,
+	       0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58,
+	       0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73,
+	       0x74, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30,
+	       0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+	       0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+	       0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xaa, 0x72,
+	       0xb5, 0xc1, 0x73, 0xf4, 0x95, 0x76, 0xa4, 0x27, 0xab, 0x5e,
+	       0xeb, 0x1d, 0x9d, 0xd0, 0x04, 0xb2, 0x93, 0x05, 0xc7, 0xfa,
+	       0x75, 0x84, 0x66, 0xe6, 0x3a, 0x26, 0x1f, 0xbc, 0x2d, 0xfd,
+	       0x8f, 0x59, 0x64, 0xac, 0xcf, 0x65, 0x9d, 0x82, 0x23, 0xc3,
+	       0x72, 0x93, 0xf2, 0x40, 0x68, 0x32, 0xd1, 0xb8, 0xf1, 0x47,
+	       0x61, 0x50, 0xea, 0xbc, 0xcc, 0x3c, 0x6b, 0x74, 0x7a, 0xec,
+	       0x2b, 0x75, 0xa6, 0xc2, 0xa2, 0xb8, 0xbf, 0x23, 0x48, 0x97,
+	       0xd5, 0xaf, 0x77, 0xc1, 0x92, 0x88, 0xd7, 0x38, 0xb7, 0x9e,
+	       0xda, 0xee, 0x72, 0x04, 0xcb, 0x96, 0xe5, 0xdb, 0xfd, 0x9b,
+	       0x5d, 0x99, 0x4e, 0x7a, 0x60, 0x23, 0x34, 0xa4, 0x8d, 0xd7,
+	       0x6c, 0xe7, 0x5d, 0x93, 0x97, 0xe1, 0xab, 0x36, 0x2c, 0x24,
+	       0x16, 0x92, 0x66, 0xf6, 0x6a, 0x14, 0x23, 0x1d, 0x18, 0xb9,
+	       0x44, 0x24, 0x61, 0x6b, 0xd3, 0x75, 0x02, 0x03, 0x01, 0x00,
+	       0x01, 0xa3, 0x23, 0x30, 0x21, 0x30, 0x0f, 0x06, 0x03, 0x55,
+	       0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+	       0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+	       0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d,
+	       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+	       0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x94, 0x9e, 0xea,
+	       0x17, 0x8d, 0x27, 0xa9, 0x17, 0xe5, 0xa9, 0x19, 0xbe, 0x82,
+	       0x36, 0xbd, 0xac, 0x74, 0xf3, 0x6e, 0x75, 0x71, 0x30, 0x1c,
+	       0x05, 0x80, 0x6d, 0x1a, 0x69, 0x37, 0x86, 0x9c, 0x77, 0x75,
+	       0x29, 0xa1, 0xc6, 0xb7, 0x11, 0x0a, 0x63, 0x27, 0xee, 0xb1,
+	       0xc8, 0x94, 0xa9, 0x2e, 0x56, 0x8f, 0xca, 0x9d, 0xbe, 0xf4,
+	       0xdb, 0x63, 0x97, 0x68, 0x3b, 0x13, 0xf8, 0x6a, 0xa5, 0xd1,
+	       0x3d, 0xed, 0xbb, 0x86, 0x9d, 0x42, 0xfc, 0x15, 0x0a, 0x04,
+	       0xf8, 0x3c, 0x0e, 0xc4, 0x86, 0x05, 0x57, 0x56, 0x96, 0xf6,
+	       0xc0, 0x18, 0x53, 0xb0, 0xc5, 0xf0, 0xca, 0x72, 0x77, 0x77,
+	       0xc9, 0x8e, 0x90, 0xa5, 0x4b, 0xb6, 0x80, 0x4a, 0x4c, 0x34,
+	       0x6f, 0xc9, 0xe8, 0x6f, 0xc2, 0x28, 0xdf, 0x93, 0xa9, 0xf5,
+	       0x63, 0x18, 0xc0, 0xec, 0x9e, 0xd5, 0x19, 0x36, 0xc5, 0x94,
+	       0x10, 0xd4, 0x72, 0xd2, 0xb8, 0x30, 0x82, 0x02, 0xb6, 0x30,
+	       0x82, 0x02, 0x1f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01,
+	       0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x90, 0x31,
+	       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+	       0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30,
+	       0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30,
+	       0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65,
+	       0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20,
+	       0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
+	       0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f,
+	       0x72, 0x67, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04,
+	       0x03, 0x0c, 0x1e, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65,
+	       0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6e,
+	       0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65,
+	       0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30,
+	       0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a,
+	       0x17, 0x0d, 0x31, 0x34, 0x31, 0x32, 0x31, 0x37, 0x30, 0x30,
+	       0x30, 0x31, 0x33, 0x33, 0x5a, 0x30, 0x81, 0x88, 0x31, 0x0b,
+	       0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47,
+	       0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08,
+	       0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67,
+	       0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10,
+	       0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d,
+	       0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16,
+	       0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e,
+	       0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c,
+	       0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
+	       0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72,
+	       0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03,
+	       0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c,
+	       0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61,
+	       0x66, 0x20, 0x43, 0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06,
+	       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+	       0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02,
+	       0x81, 0x81, 0x00, 0xc3, 0x55, 0xad, 0xdf, 0x7b, 0xd1, 0x48,
+	       0xc3, 0xd3, 0x02, 0x54, 0x6c, 0x92, 0x45, 0x22, 0x3d, 0x90,
+	       0xd8, 0xc7, 0x13, 0xcd, 0xc1, 0x59, 0xc6, 0xe0, 0xad, 0x0e,
+	       0xe6, 0xdb, 0x3b, 0xe8, 0x63, 0xea, 0x4e, 0xb6, 0xea, 0x50,
+	       0xea, 0x6e, 0x33, 0x9d, 0x28, 0x25, 0x42, 0x49, 0xd0, 0xf0,
+	       0xed, 0xc5, 0x5b, 0x6b, 0x4a, 0xe7, 0x45, 0xfa, 0xd3, 0x3f,
+	       0xae, 0xde, 0x5a, 0x90, 0xab, 0xf1, 0x61, 0x2f, 0x40, 0x5e,
+	       0xcf, 0x8b, 0x0b, 0x10, 0x59, 0xa9, 0xd0, 0x1e, 0x0f, 0x18,
+	       0x6b, 0x92, 0xd8, 0x9f, 0x58, 0x10, 0x84, 0xb6, 0x15, 0xe8,
+	       0x5b, 0xc4, 0xa0, 0x3e, 0x49, 0x8b, 0xea, 0xdd, 0xa9, 0x7e,
+	       0x32, 0x26, 0x9a, 0x68, 0x44, 0xf0, 0x30, 0xca, 0x2a, 0xd6,
+	       0x19, 0x7a, 0x80, 0xfd, 0xd7, 0xfc, 0xc7, 0x5d, 0xe7, 0x61,
+	       0xd2, 0x3f, 0x1f, 0x2c, 0x40, 0x70, 0x7b, 0x34, 0xcb, 0x08,
+	       0xa9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x26, 0x30, 0x24,
+	       0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+	       0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00,
+	       0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
+	       0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d, 0x06, 0x09,
+	       0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
+	       0x00, 0x03, 0x81, 0x81, 0x00, 0x40, 0xd2, 0x70, 0x02, 0x08,
+	       0x19, 0xa0, 0xb8, 0x8d, 0x9d, 0x3d, 0x62, 0x41, 0x90, 0x2a,
+	       0x36, 0x4a, 0x8b, 0x21, 0x42, 0x9a, 0xb4, 0xc5, 0xf8, 0x79,
+	       0x17, 0xd7, 0x64, 0x4d, 0xbf, 0x8f, 0x6a, 0x04, 0x54, 0x7a,
+	       0x0b, 0xd4, 0xb5, 0x0e, 0xab, 0xf7, 0xb7, 0x06, 0x2b, 0xf8,
+	       0xde, 0x87, 0xb2, 0x37, 0x3b, 0x95, 0x01, 0xba, 0x9f, 0x8f,
+	       0xec, 0x0a, 0x86, 0xca, 0x51, 0xb6, 0x25, 0x73, 0x2f, 0xa1,
+	       0x66, 0xc8, 0x7a, 0x5e, 0x51, 0xbd, 0x49, 0xb5, 0x75, 0xda,
+	       0xea, 0xe5, 0xeb, 0x5d, 0xe3, 0xb0, 0xad, 0x49, 0x9f, 0x8b,
+	       0xfd, 0x89, 0xb3, 0xb7, 0xb2, 0x4c, 0x7d, 0x8a, 0x29, 0xb2,
+	       0xbe, 0x04, 0xef, 0x9c, 0x73, 0x3c, 0xea, 0xa3, 0x9f, 0x07,
+	       0x66, 0x5a, 0x2f, 0x38, 0xad, 0x1a, 0xeb, 0xe1, 0xb0, 0x62,
+	       0x14, 0x55, 0xdc, 0x8c, 0x83, 0xbb, 0xc7, 0x13, 0x04, 0x41,
+	       0x54, 0xf1, 0x45, 0x31, 0x82, 0x01, 0x33, 0x30, 0x82, 0x01,
+	       0x2f, 0x02, 0x01, 0x01, 0x30, 0x81, 0x8e, 0x30, 0x81, 0x88,
+	       0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+	       0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55,
+	       0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69,
+	       0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12,
+	       0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43,
+	       0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18,
+	       0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46,
+	       0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73,
+	       0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+	       0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e,
+	       0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55,
+	       0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73,
+	       0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c,
+	       0x65, 0x61, 0x66, 0x20, 0x43, 0x41, 0x02, 0x01, 0x03, 0x30,
+	       0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x30, 0x0d,
+	       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+	       0x01, 0x05, 0x00, 0x04, 0x81, 0x80, 0x33, 0x5c, 0xf8, 0xb4,
+	       0xa5, 0x70, 0xb9, 0x0f, 0x05, 0x50, 0x72, 0xdb, 0xa3, 0xba,
+	       0x8e, 0x0d, 0x6d, 0x8a, 0x2a, 0x91, 0x65, 0xb8, 0x76, 0xd0,
+	       0xfc, 0x9e, 0x1a, 0xdb, 0x2b, 0xd2, 0xfc, 0x03, 0xef, 0x8d,
+	       0xef, 0xfe, 0x32, 0x16, 0xad, 0xf8, 0xcb, 0x28, 0xb0, 0x61,
+	       0x15, 0xb8, 0x38, 0x72, 0xfc, 0x5d, 0xa1, 0xd2, 0xae, 0x9d,
+	       0x6a, 0xb0, 0x5e, 0xbb, 0x78, 0xd3, 0x39, 0x24, 0xa3, 0x71,
+	       0xa6, 0x90, 0x64, 0xa5, 0x82, 0xba, 0x3b, 0x85, 0x2d, 0x16,
+	       0x78, 0xf4, 0xcc, 0x9f, 0xfa, 0xc5, 0x68, 0x44, 0x2c, 0x22,
+	       0xb9, 0x4c, 0x07, 0x5c, 0xb4, 0x79, 0x1a, 0x48, 0xc2, 0x66,
+	       0x71, 0x57, 0x6d, 0xdf, 0x33, 0xa2, 0x26, 0x99, 0xdd, 0xe9,
+	       0xb9, 0x1b, 0xe1, 0xa6, 0x4d, 0x53, 0x8e, 0x71, 0x81, 0xa9,
+	       0x5d, 0x70, 0x47, 0x54, 0xbc, 0x15, 0xad, 0x9c, 0xe8, 0x90,
+	       0x52, 0x3e, 0x49, 0x86 ) );
+
+/** iPXE self-test root CA certificate */
+static uint8_t root_crt_fingerprint[] =
+	FINGERPRINT ( 0x71, 0x5d, 0x51, 0x37, 0x5e, 0x18, 0xb3, 0xbc,
+		      0xbb, 0x30, 0x0e, 0x8f, 0x50, 0xc7, 0x55, 0xf5,
+		      0x96, 0xe7, 0xa8, 0x6d, 0x63, 0x2d, 0x32, 0x38,
+		      0xaf, 0x00, 0xc4, 0x1a, 0xfc, 0xd8, 0xac, 0xc3 );
+
+/** Certificate store containing the iPXE self-test root CA */
+static struct x509_root test_root = {
+	.digest = &cms_test_algorithm,
+	.count = 1,
+	.fingerprints = root_crt_fingerprint,
+};
+
+/** Dummy fingerprint (not matching any certificates) */
+static uint8_t dummy_fingerprint[] =
+	FINGERPRINT ( 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+		      0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+		      0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+		      0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff );
+
+/** Certificate store containing a dummy fingerprint */
+static struct x509_root dummy_root = {
+	.digest = &cms_test_algorithm,
+	.count = 1,
+	.fingerprints = dummy_fingerprint,
+};
+
+/** Time at which all test certificates are valid */
+static time_t test_time = 1332374737ULL; /* Thu Mar 22 00:05:37 2012 */
+
+/** Time at which end-entity test certificates are invalid */
+static time_t test_expired = 1375573111ULL; /* Sat Aug  3 23:38:31 2013 */
+
+/**
+ * Report signature parsing test result
+ *
+ * @v sgn		Test signature
+ */
+#define cms_signature_ok( sgn ) do {					\
+	ok ( cms_signature ( (sgn)->data, (sgn)->len,			\
+			     &(sgn)->sig ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Report signature verification test result
+ *
+ * @v sgn		Test signature
+ * @v code		Test signed code
+ * @v name		Test verification name
+ * @v time		Test verification time
+ * @v root		Test root certificate store
+ */
+#define cms_verify_ok( sgn, code, name, time, root ) do {		\
+	x509_invalidate_chain ( (sgn)->sig->certificates );		\
+	ok ( cms_verify ( (sgn)->sig, virt_to_user ( (code)->data ),	\
+			  (code)->len, name, time, root ) == 0 );	\
+	} while ( 0 )
+
+/**
+ * Report signature verification failure test result
+ *
+ * @v sgn		Test signature
+ * @v code		Test signed code
+ * @v name		Test verification name
+ * @v time		Test verification time
+ * @v root		Test root certificate store
+ */
+#define cms_verify_fail_ok( sgn, code, name, time, root ) do {		\
+	x509_invalidate_chain ( (sgn)->sig->certificates );		\
+	ok ( cms_verify ( (sgn)->sig, virt_to_user ( (code)->data ),	\
+			  (code)->len, name, time, root ) != 0 );	\
+	} while ( 0 )
+
+/**
+ * Perform CMS self-tests
+ *
+ */
+static void cms_test_exec ( void ) {
+
+	/* Check that all signatures can be parsed */
+	cms_signature_ok ( &codesigned_sig );
+	cms_signature_ok ( &brokenchain_sig );
+	cms_signature_ok ( &genericsigned_sig );
+	cms_signature_ok ( &nonsigned_sig );
+
+	/* Check good signature */
+	cms_verify_ok ( &codesigned_sig, &test_code,
+			"codesign.test.ipxe.org", test_time, &test_root );
+	cms_verify_ok ( &codesigned_sig, &test_code,
+			NULL, test_time, &test_root );
+
+	/* Check incorrect signer name */
+	cms_verify_fail_ok ( &codesigned_sig, &test_code,
+			     "wrongname.test.ipxe.org", test_time, &test_root );
+
+	/* Check non-code-signing certificate */
+	cms_verify_fail_ok ( &genericsigned_sig, &test_code,
+			     NULL, test_time, &test_root );
+
+	/* Check non-signing certificate */
+	cms_verify_fail_ok ( &nonsigned_sig, &test_code,
+			     NULL, test_time, &test_root );
+
+	/* Check broken chain */
+	cms_verify_fail_ok ( &brokenchain_sig, &test_code,
+			     NULL, test_time, &test_root );
+
+	/* Check untrusted signature */
+	cms_verify_fail_ok ( &codesigned_sig, &test_code,
+			     NULL, test_time, &dummy_root );
+
+	/* Check incorrect signed content */
+	cms_verify_fail_ok ( &codesigned_sig, &bad_code,
+			     NULL, test_time, &test_root );
+
+	/* Check expired signature */
+	cms_verify_fail_ok ( &codesigned_sig, &test_code,
+			     NULL, test_expired, &test_root );
+
+	/* Drop signature references */
+	cms_put ( nonsigned_sig.sig );
+	cms_put ( genericsigned_sig.sig );
+	cms_put ( brokenchain_sig.sig );
+	cms_put ( codesigned_sig.sig );
+}
+
+/** CMS self-test */
+struct self_test cms_test __self_test = {
+	.name = "cms",
+	.exec = cms_test_exec,
+};
+
+/* Drag in algorithms required for tests */
+REQUIRE_OBJECT ( rsa );
+REQUIRE_OBJECT ( md5 );
+REQUIRE_OBJECT ( sha1 );
+REQUIRE_OBJECT ( sha256 );
diff --git a/roms/ipxe/src/tests/crc32_test.c b/roms/ipxe/src/tests/crc32_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..873f633a5502ac3adde59b65b03d2ca7b78989f3
--- /dev/null
+++ b/roms/ipxe/src/tests/crc32_test.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * CRC32 tests
+ *
+ *
+ * Test vectors generated using Perl's Digest::CRC:
+ *
+ *    use Digest::CRC qw ( crc );
+ *
+ *    printf "%#08x", crc ( $data, 32, $seed, 0, 1, 0x04c11db7, 1 );
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stdint.h>
+#include <ipxe/crc32.h>
+#include <ipxe/test.h>
+
+/** Define inline data */
+#define DATA(...) { __VA_ARGS__ }
+
+/** A CRC32 test */
+struct crc32_test {
+	/** Test data */
+	const void *data;
+	/** Length of test data */
+	size_t len;
+	/** Seed */
+	uint32_t seed;
+	/** Expected CRC32 */
+	uint32_t crc32;
+};
+
+/**
+ * Define a CRC32 test
+ *
+ * @v name		Test name
+ * @v DATA		Test data
+ * @v SEED		Seed
+ * @v CRC32		Expected CRC32
+ * @ret test		CRC32 test
+ */
+#define CRC32_TEST( name, DATA, SEED, CRC32 )				\
+	static const uint8_t name ## _data[] = DATA;			\
+	static struct crc32_test name = {				\
+		.data = name ## _data,					\
+		.len = sizeof ( name ## _data ),			\
+		.seed = SEED,						\
+		.crc32 = CRC32,						\
+	};
+
+/**
+ * Report a CRC32 test result
+ *
+ * @v test		CRC32 test
+ */
+#define crc32_ok( test ) do {						\
+	uint32_t crc32;							\
+	crc32 = crc32_le ( (test)->seed, (test)->data, (test)->len );	\
+	ok ( crc32 == (test)->crc32 );					\
+	} while ( 0 )
+
+/* CRC32 tests */
+CRC32_TEST ( empty_test,
+	     DATA ( ),
+	     0x12345678UL, 0x12345678UL );
+CRC32_TEST ( hw_test,
+	     DATA ( 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' ),
+	     0xffffffffUL, 0xf2b5ee7aUL );
+CRC32_TEST ( hw_split_part1_test,
+	     DATA ( 'h', 'e', 'l', 'l', 'o' ),
+	     0xffffffffUL, 0xc9ef5979UL );
+CRC32_TEST ( hw_split_part2_test,
+	     DATA ( ' ', 'w', 'o', 'r', 'l', 'd' ),
+	     0xc9ef5979UL, 0xf2b5ee7aUL );
+
+/**
+ * Perform CRC32 self-tests
+ *
+ */
+static void crc32_test_exec ( void ) {
+
+	crc32_ok ( &empty_test );
+	crc32_ok ( &hw_test );
+	crc32_ok ( &hw_split_part1_test );
+	crc32_ok ( &hw_split_part2_test );
+}
+
+/** CRC32 self-test */
+struct self_test crc32_test __self_test = {
+	.name = "crc32",
+	.exec = crc32_test_exec,
+};
diff --git a/roms/ipxe/src/tests/digest_test.c b/roms/ipxe/src/tests/digest_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..6428cc72820f0037b6965f76135d8e331e185d4a
--- /dev/null
+++ b/roms/ipxe/src/tests/digest_test.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Digest self-tests
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ipxe/crypto.h>
+#include <ipxe/profile.h>
+#include "digest_test.h"
+
+/**
+ * Test digest algorithm
+ *
+ * @v digest		Digest algorithm
+ * @v fragments		Digest test fragment list, or NULL
+ * @v data		Test data
+ * @v len		Length of test data
+ * @v expected		Expected digest value
+ * @ret ok		Digest value is as expected
+ */
+int digest_test ( struct digest_algorithm *digest,
+		  struct digest_test_fragments *fragments,
+		  void *data, size_t len, void *expected ) {
+	uint8_t ctx[digest->ctxsize];
+	uint8_t out[digest->digestsize];
+	size_t frag_len = 0;
+	unsigned int i;
+
+	/* Initialise digest */
+	digest_init ( digest, ctx );
+
+	/* Update digest fragment-by-fragment */
+	for ( i = 0 ; len && ( i < ( sizeof ( fragments->len ) /
+				     sizeof ( fragments->len[0] ) ) ) ; i++ ) {
+		if ( fragments )
+			frag_len = fragments->len[i];
+		if ( ( frag_len == 0 ) || ( frag_len < len ) )
+			frag_len = len;
+		digest_update ( digest, ctx, data, frag_len );
+		data += frag_len;
+		len -= frag_len;
+	}
+
+	/* Finalise digest */
+	digest_final ( digest, ctx, out );
+
+	/* Compare against expected output */
+	return ( memcmp ( expected, out, sizeof ( out ) ) == 0 );
+}
+
+/**
+ * Calculate digest algorithm cost
+ *
+ * @v digest		Digest algorithm
+ * @ret cost		Cost (in cycles per byte)
+ */
+unsigned long digest_cost ( struct digest_algorithm *digest ) {
+	static uint8_t random[8192]; /* Too large for stack */
+	uint8_t ctx[digest->ctxsize];
+	uint8_t out[digest->digestsize];
+	union profiler profiler;
+	unsigned long long elapsed;
+	unsigned long cost;
+	unsigned int i;
+
+	/* Fill buffer with pseudo-random data */
+	srand ( 0x1234568 );
+	for ( i = 0 ; i < sizeof ( random ) ; i++ )
+		random[i] = rand();
+
+	/* Time digest calculation */
+	profile ( &profiler );
+	digest_init ( digest, ctx );
+	digest_update ( digest, ctx, random, sizeof ( random ) );
+	digest_final ( digest, ctx, out );
+	elapsed = profile ( &profiler );
+
+	/* Round to nearest whole number of cycles per byte */
+	cost = ( ( elapsed + ( sizeof ( random ) / 2 ) ) / sizeof ( random ) );
+
+	return cost;
+}
diff --git a/roms/ipxe/src/tests/digest_test.h b/roms/ipxe/src/tests/digest_test.h
new file mode 100644
index 0000000000000000000000000000000000000000..49e06d1cbc237a720ea6ca299471cef4c72924bb
--- /dev/null
+++ b/roms/ipxe/src/tests/digest_test.h
@@ -0,0 +1,37 @@
+#ifndef _DIGEST_TEST_H
+#define _DIGEST_TEST_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/crypto.h>
+#include <ipxe/test.h>
+
+/** Maximum number of digest test fragments */
+#define NUM_DIGEST_TEST_FRAG 8
+
+/** A digest test fragment list */
+struct digest_test_fragments {
+	/** Fragment lengths */
+	size_t len[NUM_DIGEST_TEST_FRAG];
+};
+
+extern int digest_test ( struct digest_algorithm *digest,
+			 struct digest_test_fragments *fragments,
+			 void *data, size_t len, void *expected );
+extern unsigned long digest_cost ( struct digest_algorithm *digest );
+
+/**
+ * Report digest test result
+ *
+ * @v digest		Digest algorithm
+ * @v fragments		Digest test fragment list, or NULL
+ * @v data		Test data
+ * @v len		Length of test data
+ * @v expected		Expected digest value
+ */
+#define digest_ok( digest, fragments, data, len, expected ) do {	\
+	ok ( digest_test ( digest, fragments, data, len, expected ) );	\
+	} while ( 0 )
+
+#endif /* _DIGEST_TEST_H */
diff --git a/roms/ipxe/src/tests/entropy_sample.c b/roms/ipxe/src/tests/entropy_sample.c
new file mode 100644
index 0000000000000000000000000000000000000000..95a662e3ec0b1d453969ecf7d0108122f35e6c8a
--- /dev/null
+++ b/roms/ipxe/src/tests/entropy_sample.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Entropy sampling
+ *
+ */
+
+#include <stdio.h>
+#include <ipxe/entropy.h>
+#include <ipxe/test.h>
+
+/** Total number of test samples */
+#define SAMPLE_COUNT 65536
+
+/** Number of samples per block */
+#define SAMPLE_BLOCKSIZE 256
+
+/**
+ * Generate entropy samples for external testing
+ *
+ */
+static void entropy_sample_test_exec ( void ) {
+	static noise_sample_t samples[SAMPLE_BLOCKSIZE];
+	unsigned int i;
+	unsigned int j;
+	int rc;
+
+	/* Collect and print blocks of samples */
+	for ( i = 0 ; i < ( SAMPLE_COUNT / SAMPLE_BLOCKSIZE ) ; i++ ) {
+
+		/* Collect one block of samples */
+		rc = entropy_enable();
+		ok ( rc == 0 );
+		for ( j = 0 ; j < SAMPLE_BLOCKSIZE ; j++ ) {
+			rc = get_noise ( &samples[j] );
+			ok ( rc == 0 );
+		}
+		entropy_disable();
+
+		/* Print out sample values */
+		for ( j = 0 ; j < SAMPLE_BLOCKSIZE ; j++ ) {
+			printf ( "SAMPLE %d %d\n", ( i * SAMPLE_BLOCKSIZE + j ),
+				 samples[j] );
+		}
+	}
+}
+
+/** Entropy sampling self-test */
+struct self_test entropy_sample_test __self_test = {
+	.name = "entropy_sample",
+	.exec = entropy_sample_test_exec,
+};
diff --git a/roms/ipxe/src/tests/hash_df_test.c b/roms/ipxe/src/tests/hash_df_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..74c8d0f4dbdf3bd09054b92f13239b670e58e99d
--- /dev/null
+++ b/roms/ipxe/src/tests/hash_df_test.c
@@ -0,0 +1,898 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Hash-based derivation function (Hash_df) tests
+ *
+ * These test vectors are provided by NIST as part of the
+ * Cryptographic Toolkit Examples, downloadable from:
+ *
+ *    http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/Hash_DRBG.pdf
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <assert.h>
+#include <string.h>
+#include <ipxe/hash_df.h>
+#include <ipxe/sha1.h>
+#include <ipxe/sha256.h>
+#include <ipxe/test.h>
+
+/** Define inline input data */
+#define INPUT(...) { __VA_ARGS__ }
+
+/** Define inline expected data */
+#define EXPECT(...) { __VA_ARGS__ }
+
+/** A Hash_df test */
+struct hash_df_test {
+	/** Underlying hash algorithm */
+	struct digest_algorithm *hash;
+	/** Input data */
+	const void *input;
+	/** Length of input data */
+	size_t input_len;
+	/** Expected output data */
+	const void *expected;
+	/** Length of expected output data */
+	size_t expected_len;
+};
+
+/**
+ * Define a Hash_df test
+ *
+ * @v name		Test name
+ * @v hash_algorithm	Underlying hash algorithm
+ * @v input_array	Input data
+ * @v expected_array	Expected output data
+ * @ret test		Hash_df test
+ */
+#define HASH_DF_TEST( name, hash_algorithm, input_array, expected_array ) \
+	static const uint8_t name ## _input [] = input_array;		  \
+	static const uint8_t name ## _expected [] = expected_array;	  \
+	static struct hash_df_test name = {				  \
+		.hash = &(hash_algorithm),				  \
+		.input = name ## _input,				  \
+		.input_len = sizeof ( name ## _input ),			  \
+		.expected = name ## _expected,				  \
+		.expected_len = sizeof ( name ## _expected ),		  \
+	}
+
+/** SHA-1 Test 1 */
+HASH_DF_TEST ( test_sha1_1, sha1_algorithm,
+	INPUT ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+		0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+		0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+		0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+		0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31,
+		0x32, 0x33, 0x34, 0x35, 0x36, 0x20, 0x21, 0x22, 0x23, 0x24 ),
+	EXPECT ( 0xd0, 0x8f, 0xb4, 0x41, 0xf2, 0xf4, 0xcb, 0x37, 0xcf, 0x6c,
+		 0x24, 0x20, 0xa8, 0x2c, 0x74, 0x27, 0xac, 0xf7, 0xfc, 0xfd,
+		 0x79, 0x90, 0x14, 0x38, 0x34, 0xa5, 0xc2, 0x56, 0xab, 0x28,
+		 0x39, 0x36, 0x6d, 0x96, 0x34, 0x8c, 0xfe, 0x8c, 0x97, 0xab,
+		 0x67, 0x67, 0xb0, 0x5e, 0x83, 0xa9, 0x80, 0x40, 0x6d, 0x94,
+		 0xbe, 0xe3, 0x3c, 0xbb, 0x89 ) );
+
+/** SHA-1 Test 2 */
+HASH_DF_TEST ( test_sha1_2, sha1_algorithm,
+	INPUT ( 0x00, 0xd0, 0x8f, 0xb4, 0x41, 0xf2, 0xf4, 0xcb, 0x37, 0xcf,
+		0x6c, 0x24, 0x20, 0xa8, 0x2c, 0x74, 0x27, 0xac, 0xf7, 0xfc,
+		0xfd, 0x79, 0x90, 0x14, 0x38, 0x34, 0xa5, 0xc2, 0x56, 0xab,
+		0x28, 0x39, 0x36, 0x6d, 0x96, 0x34, 0x8c, 0xfe, 0x8c, 0x97,
+		0xab, 0x67, 0x67, 0xb0, 0x5e, 0x83, 0xa9, 0x80, 0x40, 0x6d,
+		0x94, 0xbe, 0xe3, 0x3c, 0xbb, 0x89 ),
+	EXPECT ( 0x54, 0xc5, 0x21, 0x7b, 0x51, 0x02, 0xd8, 0xda, 0x8b, 0xf1,
+		 0x68, 0x6e, 0xdb, 0xab, 0x2b, 0xbc, 0x0c, 0x11, 0xb0, 0xcc,
+		 0xb0, 0xf0, 0xaf, 0x23, 0x4c, 0x24, 0xcf, 0x15, 0xec, 0xc8,
+		 0xcb, 0x39, 0xc2, 0x33, 0xaa, 0xca, 0x48, 0xfc, 0xce, 0xee,
+		 0x86, 0x3d, 0xa8, 0x81, 0xff, 0xcb, 0xb4, 0x34, 0xa6, 0xcc,
+		 0xb7, 0xda, 0x2f, 0xb2, 0x10 ) );
+
+/** SHA-1 Test 3 */
+HASH_DF_TEST ( test_sha1_3, sha1_algorithm,
+	INPUT ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+		0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+		0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+		0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+		0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31,
+		0x32, 0x33, 0x34, 0x35, 0x36, 0x20, 0x21, 0x22, 0x23, 0x24,
+		0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+		0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
+		0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d,
+		0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+		0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71,
+		0x72, 0x73, 0x74, 0x75, 0x76 ),
+	EXPECT ( 0x99, 0xb9, 0x53, 0x7b, 0x84, 0x27, 0xb8, 0xce, 0x23, 0x21,
+		 0x9a, 0x61, 0x1c, 0xbe, 0x61, 0x06, 0x44, 0xcf, 0x85, 0x03,
+		 0xee, 0xc5, 0xba, 0x22, 0xde, 0x1a, 0xb2, 0x12, 0xc3, 0xd0,
+		 0x85, 0x8e, 0x9e, 0x3b, 0x90, 0x26, 0xd4, 0xe7, 0x7d, 0x58,
+		 0xe0, 0x2e, 0x85, 0xa2, 0x31, 0x4c, 0xe3, 0xd7, 0x4a, 0x93,
+		 0x32, 0x4b, 0x27, 0xbd, 0xe8 ) );
+
+/** SHA-1 Test 4 */
+HASH_DF_TEST ( test_sha1_4, sha1_algorithm,
+	INPUT ( 0x00, 0x99, 0xb9, 0x53, 0x7b, 0x84, 0x27, 0xb8, 0xce, 0x23,
+		0x21, 0x9a, 0x61, 0x1c, 0xbe, 0x61, 0x06, 0x44, 0xcf, 0x85,
+		0x03, 0xee, 0xc5, 0xba, 0x22, 0xde, 0x1a, 0xb2, 0x12, 0xc3,
+		0xd0, 0x85, 0x8e, 0x9e, 0x3b, 0x90, 0x26, 0xd4, 0xe7, 0x7d,
+		0x58, 0xe0, 0x2e, 0x85, 0xa2, 0x31, 0x4c, 0xe3, 0xd7, 0x4a,
+		0x93, 0x32, 0x4b, 0x27, 0xbd, 0xe8 ),
+	EXPECT ( 0xa7, 0x02, 0x66, 0xf7, 0xf9, 0x1e, 0xc4, 0xd2, 0x88, 0x73,
+		 0x14, 0x79, 0x34, 0xce, 0xaf, 0x2a, 0x2c, 0xc3, 0x5a, 0x0f,
+		 0xd5, 0xe0, 0x0a, 0xba, 0xe7, 0x9d, 0xc6, 0x60, 0x5f, 0xab,
+		 0xd6, 0xf5, 0xf9, 0x28, 0xe1, 0x8c, 0x63, 0x26, 0x8e, 0x1a,
+		 0xf4, 0x85, 0xda, 0x6c, 0xbf, 0x04, 0x16, 0xdc, 0xdc, 0x5f,
+		 0xb8, 0xbc, 0x9c, 0x94, 0xb6 ) );
+
+/** SHA-1 Test 5 */
+HASH_DF_TEST ( test_sha1_5, sha1_algorithm,
+	INPUT ( 0x01, 0xd0, 0x8f, 0xb4, 0x41, 0xf2, 0xf4, 0xcb, 0x37, 0xcf,
+		0x6c, 0x24, 0x20, 0xa8, 0x2c, 0x74, 0x27, 0xac, 0xf7, 0xfc,
+		0xfd, 0x79, 0x90, 0x14, 0x38, 0x34, 0xa5, 0xc2, 0x56, 0xab,
+		0x28, 0x39, 0x36, 0x6d, 0x96, 0x34, 0x8c, 0xfe, 0x8c, 0x97,
+		0xab, 0x67, 0x67, 0xb0, 0x5e, 0x83, 0xa9, 0x80, 0x40, 0x6d,
+		0x94, 0xbe, 0xe3, 0x3c, 0xbb, 0x89, 0x80, 0x81, 0x82, 0x83,
+		0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
+		0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+		0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1,
+		0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab,
+		0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
+		0xb6 ),
+	EXPECT ( 0x0a, 0x04, 0x41, 0xa5, 0x2b, 0xed, 0xf7, 0x94, 0xf5, 0xaa,
+		 0x62, 0x7b, 0xcb, 0xd8, 0x1f, 0x93, 0xe0, 0x11, 0xd5, 0x1f,
+		 0x34, 0x74, 0x80, 0x2c, 0x37, 0x50, 0x76, 0x75, 0x51, 0xb4,
+		 0x5b, 0x69, 0xf3, 0xd3, 0x59, 0x39, 0xc9, 0x32, 0xae, 0x1c,
+		 0xb7, 0xc9, 0x89, 0x4f, 0xb8, 0x84, 0x65, 0xe0, 0xcf, 0xd1,
+		 0xcc, 0x26, 0x1e, 0x22, 0xc5 ) );
+
+/** SHA-1 Test 6 */
+HASH_DF_TEST ( test_sha1_6, sha1_algorithm,
+	INPUT ( 0x00, 0x0a, 0x04, 0x41, 0xa5, 0x2b, 0xed, 0xf7, 0x94, 0xf5,
+		0xaa, 0x62, 0x7b, 0xcb, 0xd8, 0x1f, 0x93, 0xe0, 0x11, 0xd5,
+		0x1f, 0x34, 0x74, 0x80, 0x2c, 0x37, 0x50, 0x76, 0x75, 0x51,
+		0xb4, 0x5b, 0x69, 0xf3, 0xd3, 0x59, 0x39, 0xc9, 0x32, 0xae,
+		0x1c, 0xb7, 0xc9, 0x89, 0x4f, 0xb8, 0x84, 0x65, 0xe0, 0xcf,
+		0xd1, 0xcc, 0x26, 0x1e, 0x22, 0xc5 ),
+	EXPECT ( 0x04, 0x11, 0xc8, 0xb0, 0xdb, 0xa7, 0x56, 0xe8, 0x84, 0x2b,
+		 0x3f, 0xb0, 0x2d, 0x2f, 0xeb, 0x7c, 0xee, 0xa5, 0x67, 0x42,
+		 0xee, 0x93, 0x79, 0xc9, 0x0e, 0x6d, 0x3b, 0x2f, 0x10, 0x10,
+		 0xd4, 0x0f, 0x4f, 0x4d, 0xca, 0xda, 0x61, 0xcf, 0xdf, 0xb4,
+		 0x8a, 0xf8, 0x47, 0xca, 0xcc, 0x4c, 0x92, 0xc6, 0x14, 0x44,
+		 0x85, 0xc2, 0x27, 0xca, 0x05 ) );
+
+/** SHA-1 Test 7 */
+HASH_DF_TEST ( test_sha1_7, sha1_algorithm,
+	INPUT ( 0x01, 0x0e, 0x16, 0x0a, 0x56, 0x07, 0x95, 0x4e, 0x7d, 0x79,
+		0xd5, 0xa2, 0x2b, 0xf9, 0x08, 0x0b, 0x10, 0xce, 0xb7, 0x3c,
+		0x62, 0x23, 0x07, 0xf9, 0xf5, 0x45, 0xbd, 0xb1, 0xa4, 0x61,
+		0xc5, 0x2f, 0x79, 0x43, 0x21, 0x24, 0x3a, 0xac, 0xe2, 0x3f,
+		0x36, 0x3f, 0xef, 0xb3, 0x5d, 0xc5, 0xbe, 0xa7, 0xe7, 0x31,
+		0x44, 0x14, 0xcf, 0x78, 0xb3, 0xf9, 0xc0, 0xc1, 0xc2, 0xc3,
+		0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd,
+		0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+		0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1,
+		0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
+		0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
+		0xf6 ),
+	EXPECT ( 0xdc, 0x24, 0xdf, 0x10, 0x2f, 0xa9, 0xf9, 0x6c, 0xc1, 0xcf,
+		 0xf8, 0xc1, 0x16, 0xc7, 0x9d, 0x14, 0x97, 0xd7, 0xc2, 0x7b,
+		 0xba, 0x5b, 0xa8, 0x01, 0xe1, 0x56, 0x21, 0x93, 0x35, 0x3f,
+		 0x31, 0xe3, 0x22, 0x39, 0x57, 0x84, 0x69, 0xb8, 0x0f, 0x2f,
+		 0x51, 0x64, 0x54, 0x37, 0x28, 0x71, 0x7f, 0x17, 0x1f, 0xdb,
+		 0x02, 0xb2, 0xad, 0x57, 0x95 ) );
+
+/** SHA-1 Test 8 */
+HASH_DF_TEST ( test_sha1_8, sha1_algorithm,
+	INPUT ( 0x00, 0xdc, 0x24, 0xdf, 0x10, 0x2f, 0xa9, 0xf9, 0x6c, 0xc1,
+		0xcf, 0xf8, 0xc1, 0x16, 0xc7, 0x9d, 0x14, 0x97, 0xd7, 0xc2,
+		0x7b, 0xba, 0x5b, 0xa8, 0x01, 0xe1, 0x56, 0x21, 0x93, 0x35,
+		0x3f, 0x31, 0xe3, 0x22, 0x39, 0x57, 0x84, 0x69, 0xb8, 0x0f,
+		0x2f, 0x51, 0x64, 0x54, 0x37, 0x28, 0x71, 0x7f, 0x17, 0x1f,
+		0xdb, 0x02, 0xb2, 0xad, 0x57, 0x95 ),
+	EXPECT ( 0xff, 0xaf, 0x45, 0x66, 0x5b, 0x11, 0x0c, 0xa1, 0x33, 0x5a,
+		 0x3f, 0xce, 0x73, 0xa7, 0x98, 0x1d, 0x0f, 0xd5, 0xc8, 0xd9,
+		 0x03, 0xf6, 0x5f, 0xaa, 0x46, 0xa3, 0xd5, 0x97, 0xbf, 0x34,
+		 0xc4, 0xe0, 0xcc, 0x16, 0x75, 0x60, 0xab, 0x94, 0xec, 0x10,
+		 0xd6, 0x41, 0x5f, 0x37, 0x83, 0xb0, 0x15, 0x67, 0x89, 0x1b,
+		 0x57, 0x66, 0x2a, 0xbb, 0x39 ) );
+
+/** SHA-1 Test 9 */
+HASH_DF_TEST ( test_sha1_9, sha1_algorithm,
+	INPUT ( 0x01, 0xd0, 0x8f, 0xb4, 0x41, 0xf2, 0xf4, 0xcb, 0x37, 0xcf,
+		0x6c, 0x24, 0x20, 0xa8, 0x2c, 0x74, 0x27, 0xac, 0xf7, 0xfc,
+		0xfd, 0x79, 0x90, 0x14, 0x38, 0x34, 0xa5, 0xc2, 0x56, 0xab,
+		0x28, 0x39, 0x36, 0x6d, 0x96, 0x34, 0x8c, 0xfe, 0x8c, 0x97,
+		0xab, 0x67, 0x67, 0xb0, 0x5e, 0x83, 0xa9, 0x80, 0x40, 0x6d,
+		0x94, 0xbe, 0xe3, 0x3c, 0xbb, 0x89, 0x80, 0x81, 0x82, 0x83,
+		0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
+		0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+		0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1,
+		0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab,
+		0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
+		0xb6, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+		0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
+		0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c,
+		0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
+		0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
+		0x91, 0x92, 0x93, 0x94, 0x95, 0x96 ),
+	EXPECT ( 0x8f, 0xde, 0xc9, 0xe6, 0x18, 0x96, 0x36, 0xf0, 0xa5, 0xce,
+		 0x53, 0xe8, 0x1c, 0x13, 0xac, 0x93, 0x84, 0xfa, 0xfb, 0xa0,
+		 0xee, 0x50, 0xc1, 0xe2, 0xc8, 0xa0, 0x99, 0xde, 0x41, 0xd8,
+		 0xcc, 0x7a, 0x31, 0x42, 0x9e, 0x8c, 0x8c, 0x88, 0x80, 0xe3,
+		 0xb4, 0x5d, 0x89, 0xdb, 0x61, 0x2c, 0xd9, 0xd2, 0x8a, 0x55,
+		 0xc0, 0xf0, 0xd1, 0xf8, 0xf9 ) );
+
+/** SHA-1 Test 10 */
+HASH_DF_TEST ( test_sha1_10, sha1_algorithm,
+	INPUT ( 0x00, 0x8f, 0xde, 0xc9, 0xe6, 0x18, 0x96, 0x36, 0xf0, 0xa5,
+		0xce, 0x53, 0xe8, 0x1c, 0x13, 0xac, 0x93, 0x84, 0xfa, 0xfb,
+		0xa0, 0xee, 0x50, 0xc1, 0xe2, 0xc8, 0xa0, 0x99, 0xde, 0x41,
+		0xd8, 0xcc, 0x7a, 0x31, 0x42, 0x9e, 0x8c, 0x8c, 0x88, 0x80,
+		0xe3, 0xb4, 0x5d, 0x89, 0xdb, 0x61, 0x2c, 0xd9, 0xd2, 0x8a,
+		0x55, 0xc0, 0xf0, 0xd1, 0xf8, 0xf9 ),
+	EXPECT ( 0x97, 0xd0, 0x76, 0x31, 0xb2, 0x2f, 0x7c, 0x95, 0x7f, 0x19,
+		 0xf8, 0x44, 0xf4, 0xdc, 0x2a, 0xfa, 0x6f, 0xf9, 0x7c, 0x35,
+		 0x66, 0x18, 0x98, 0x21, 0x69, 0x91, 0xd1, 0x5b, 0xda, 0x75,
+		 0xbb, 0xd0, 0x5e, 0xdf, 0x8a, 0x0f, 0xa8, 0x0c, 0xca, 0xb9,
+		 0x51, 0x95, 0xf4, 0x79, 0xcd, 0x76, 0x20, 0x22, 0x35, 0x10,
+		 0x2e, 0xf6, 0x27, 0x29, 0x19 ) );
+
+/** SHA-1 Test 11 */
+HASH_DF_TEST ( test_sha1_11, sha1_algorithm,
+	INPUT ( 0x01, 0x27, 0xaf, 0x40, 0x17, 0xca, 0xc5, 0xb3, 0x86, 0x24,
+		0xe8, 0x4c, 0x2d, 0x10, 0xef, 0xd7, 0x8d, 0xf4, 0xf4, 0x77,
+		0xd6, 0x54, 0x69, 0x5a, 0x04, 0x32, 0x32, 0x6b, 0x3a, 0x1c,
+		0x4e, 0x88, 0x4a, 0x90, 0x22, 0x28, 0xe8, 0x9e, 0xaa, 0x90,
+		0x36, 0xcd, 0x2a, 0xf7, 0x05, 0x66, 0x81, 0x26, 0x23, 0x72,
+		0xc7, 0x13, 0x71, 0xd4, 0x53, 0x3d, 0xc0, 0xc1, 0xc2, 0xc3,
+		0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd,
+		0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+		0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1,
+		0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
+		0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
+		0xf6, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
+		0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2,
+		0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc,
+		0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
+		0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
+		0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6 ),
+	EXPECT ( 0x2c, 0x9c, 0x0d, 0x80, 0x03, 0xe3, 0x40, 0x23, 0xbe, 0x5b,
+		 0x63, 0xfd, 0xb9, 0xd2, 0x24, 0xb4, 0x25, 0x0c, 0xc8, 0x15,
+		 0x5b, 0xd1, 0xee, 0xd8, 0xe5, 0x5d, 0x91, 0x06, 0x2f, 0xdd,
+		 0x27, 0x64, 0xb8, 0xae, 0xa9, 0xc8, 0x2f, 0x84, 0x7e, 0x09,
+		 0xa3, 0xfe, 0xa1, 0xc7, 0x11, 0x7d, 0x6f, 0x7d, 0xd2, 0xef,
+		 0x77, 0x7d, 0x7c, 0xf3, 0xeb ) );
+
+/** SHA-1 Test 12 */
+HASH_DF_TEST ( test_sha1_12, sha1_algorithm,
+	INPUT ( 0x00, 0x2c, 0x9c, 0x0d, 0x80, 0x03, 0xe3, 0x40, 0x23, 0xbe,
+		0x5b, 0x63, 0xfd, 0xb9, 0xd2, 0x24, 0xb4, 0x25, 0x0c, 0xc8,
+		0x15, 0x5b, 0xd1, 0xee, 0xd8, 0xe5, 0x5d, 0x91, 0x06, 0x2f,
+		0xdd, 0x27, 0x64, 0xb8, 0xae, 0xa9, 0xc8, 0x2f, 0x84, 0x7e,
+		0x09, 0xa3, 0xfe, 0xa1, 0xc7, 0x11, 0x7d, 0x6f, 0x7d, 0xd2,
+		0xef, 0x77, 0x7d, 0x7c, 0xf3, 0xeb ),
+	EXPECT ( 0x7e, 0x8a, 0xa4, 0x93, 0x42, 0x72, 0xf2, 0xa2, 0x8b, 0xbf,
+		 0xd7, 0xaf, 0xcc, 0x88, 0xce, 0x1c, 0x80, 0x6a, 0x38, 0xea,
+		 0x7b, 0x89, 0x45, 0xc8, 0xd1, 0xb6, 0xf1, 0x75, 0x03, 0x78,
+		 0x54, 0x6a, 0xb1, 0xa2, 0x96, 0x00, 0xd6, 0x44, 0xec, 0x52,
+		 0x0e, 0x8b, 0xff, 0xf6, 0x0c, 0xb7, 0x7f, 0xa5, 0x4b, 0xb1,
+		 0x1a, 0x83, 0x31, 0xcb, 0x24 ) );
+
+/** SHA-1 Test 13 */
+HASH_DF_TEST ( test_sha1_13, sha1_algorithm,
+	INPUT ( 0x01, 0x99, 0xb9, 0x53, 0x7b, 0x84, 0x27, 0xb8, 0xce, 0x23,
+		0x21, 0x9a, 0x61, 0x1c, 0xbe, 0x61, 0x06, 0x44, 0xcf, 0x85,
+		0x03, 0xee, 0xc5, 0xba, 0x22, 0xde, 0x1a, 0xb2, 0x12, 0xc3,
+		0xd0, 0x85, 0x8e, 0x9e, 0x3b, 0x90, 0x26, 0xd4, 0xe7, 0x7d,
+		0x58, 0xe0, 0x2e, 0x85, 0xa2, 0x31, 0x4c, 0xe3, 0xd7, 0x4a,
+		0x93, 0x32, 0x4b, 0x27, 0xbd, 0xe8, 0x80, 0x81, 0x82, 0x83,
+		0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
+		0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+		0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1,
+		0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab,
+		0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
+		0xb6 ),
+	EXPECT ( 0xe5, 0x04, 0x3d, 0x1b, 0x95, 0x4b, 0x34, 0xba, 0x60, 0xd2,
+		 0x48, 0xe8, 0x83, 0xef, 0x49, 0x8c, 0x5c, 0x52, 0x36, 0xb8,
+		 0x26, 0x0e, 0x23, 0x8e, 0x02, 0xc8, 0xd4, 0xfc, 0x5f, 0xfe,
+		 0x90, 0xfa, 0x40, 0x13, 0x44, 0x70, 0x75, 0xbb, 0x54, 0x3e,
+		 0xf0, 0x0c, 0x3b, 0xda, 0x59, 0x6b, 0x10, 0x88, 0x61, 0xf0,
+		 0x6b, 0xf9, 0x1b, 0x45, 0xd6 ) );
+
+/** SHA-1 Test 14 */
+HASH_DF_TEST ( test_sha1_14, sha1_algorithm,
+	INPUT ( 0x00, 0xe5, 0x04, 0x3d, 0x1b, 0x95, 0x4b, 0x34, 0xba, 0x60,
+		0xd2, 0x48, 0xe8, 0x83, 0xef, 0x49, 0x8c, 0x5c, 0x52, 0x36,
+		0xb8, 0x26, 0x0e, 0x23, 0x8e, 0x02, 0xc8, 0xd4, 0xfc, 0x5f,
+		0xfe, 0x90, 0xfa, 0x40, 0x13, 0x44, 0x70, 0x75, 0xbb, 0x54,
+		0x3e, 0xf0, 0x0c, 0x3b, 0xda, 0x59, 0x6b, 0x10, 0x88, 0x61,
+		0xf0, 0x6b, 0xf9, 0x1b, 0x45, 0xd6 ),
+	EXPECT ( 0x1f, 0x3f, 0x63, 0x10, 0xed, 0x10, 0xfc, 0x9f, 0x93, 0x8c,
+		 0x43, 0x22, 0x61, 0xaf, 0x42, 0xe9, 0xe9, 0x17, 0x5f, 0x08,
+		 0x0f, 0x32, 0x22, 0xdc, 0x11, 0x8b, 0xa7, 0xcf, 0x88, 0x8c,
+		 0xdc, 0x3f, 0x36, 0x0d, 0xd2, 0x8f, 0x5e, 0xcb, 0x7c, 0x80,
+		 0xa6, 0xbc, 0xfc, 0xfc, 0x0f, 0x51, 0xfe, 0x2f, 0x77, 0xc1,
+		 0xc9, 0x9d, 0xf0, 0xa2, 0x09 ) );
+
+/** SHA-1 Test 15 */
+HASH_DF_TEST ( test_sha1_15, sha1_algorithm,
+	INPUT ( 0x01, 0x04, 0x43, 0xa0, 0x2c, 0x82, 0x5c, 0x31, 0x59, 0xf4,
+		0x5e, 0x8c, 0x0a, 0xe5, 0x9e, 0x8c, 0x76, 0x45, 0x69, 0x95,
+		0xc0, 0x35, 0x40, 0x46, 0x6a, 0x14, 0x54, 0x7c, 0xcb, 0xe8,
+		0x8b, 0x6d, 0x39, 0x76, 0x21, 0x17, 0x32, 0x84, 0x72, 0xf5,
+		0x2b, 0x84, 0x57, 0x5a, 0xaf, 0xe8, 0x8b, 0x2d, 0x1e, 0x50,
+		0x4f, 0x21, 0xec, 0x4e, 0x31, 0x35, 0xc0, 0xc1, 0xc2, 0xc3,
+		0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd,
+		0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+		0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1,
+		0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
+		0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
+		0xf6 ),
+	EXPECT ( 0x9d, 0xc3, 0x52, 0x08, 0xee, 0x2b, 0x8c, 0x58, 0x1e, 0xa3,
+		 0x0b, 0xaa, 0xcb, 0x5d, 0x74, 0x31, 0x7a, 0x87, 0x94, 0x54,
+		 0x10, 0x71, 0x7e, 0x58, 0xd3, 0x70, 0x5f, 0xbd, 0xc7, 0x60,
+		 0xbe, 0x0c, 0xc9, 0x0e, 0xd1, 0xcc, 0xbb, 0x89, 0x7d, 0x47,
+		 0xd2, 0x7e, 0x2b, 0x2e, 0x42, 0x2b, 0x32, 0xb9, 0x7f, 0x05,
+		 0x0d, 0x1b, 0xd2, 0xb4, 0x90 ) );
+
+/** SHA-1 Test 16 */
+HASH_DF_TEST ( test_sha1_16, sha1_algorithm,
+	INPUT ( 0x00, 0x9d, 0xc3, 0x52, 0x08, 0xee, 0x2b, 0x8c, 0x58, 0x1e,
+		0xa3, 0x0b, 0xaa, 0xcb, 0x5d, 0x74, 0x31, 0x7a, 0x87, 0x94,
+		0x54, 0x10, 0x71, 0x7e, 0x58, 0xd3, 0x70, 0x5f, 0xbd, 0xc7,
+		0x60, 0xbe, 0x0c, 0xc9, 0x0e, 0xd1, 0xcc, 0xbb, 0x89, 0x7d,
+		0x47, 0xd2, 0x7e, 0x2b, 0x2e, 0x42, 0x2b, 0x32, 0xb9, 0x7f,
+		0x05, 0x0d, 0x1b, 0xd2, 0xb4, 0x90 ),
+	EXPECT ( 0x1a, 0x5a, 0xd6, 0xce, 0xa3, 0xd1, 0x5d, 0xa5, 0xfb, 0x47,
+		 0x42, 0x13, 0x13, 0x09, 0xf0, 0xed, 0x88, 0xcf, 0x4c, 0x90,
+		 0xa6, 0xc1, 0xcc, 0xee, 0x35, 0xa8, 0x76, 0xeb, 0xfc, 0xcc,
+		 0x82, 0x67, 0x29, 0xb6, 0x63, 0x9f, 0x81, 0x19, 0x65, 0xb0,
+		 0xef, 0x85, 0x76, 0xe7, 0x5c, 0xb3, 0xcf, 0xe8, 0x22, 0x07,
+		 0x68, 0xb2, 0x6c, 0xe7, 0x7a ) );
+
+/** SHA-1 Test 17 */
+HASH_DF_TEST ( test_sha1_17, sha1_algorithm,
+	INPUT ( 0x01, 0x99, 0xb9, 0x53, 0x7b, 0x84, 0x27, 0xb8, 0xce, 0x23,
+		0x21, 0x9a, 0x61, 0x1c, 0xbe, 0x61, 0x06, 0x44, 0xcf, 0x85,
+		0x03, 0xee, 0xc5, 0xba, 0x22, 0xde, 0x1a, 0xb2, 0x12, 0xc3,
+		0xd0, 0x85, 0x8e, 0x9e, 0x3b, 0x90, 0x26, 0xd4, 0xe7, 0x7d,
+		0x58, 0xe0, 0x2e, 0x85, 0xa2, 0x31, 0x4c, 0xe3, 0xd7, 0x4a,
+		0x93, 0x32, 0x4b, 0x27, 0xbd, 0xe8, 0x80, 0x81, 0x82, 0x83,
+		0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
+		0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+		0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1,
+		0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab,
+		0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
+		0xb6, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+		0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
+		0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c,
+		0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
+		0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
+		0x91, 0x92, 0x93, 0x94, 0x95, 0x96 ),
+	EXPECT ( 0x56, 0x3a, 0x5d, 0x20, 0x7d, 0x37, 0x70, 0x7b, 0xf5, 0xf2,
+		 0x4d, 0x0b, 0xd4, 0x93, 0x5d, 0xc3, 0x8d, 0xbe, 0x04, 0x36,
+		 0x37, 0xb3, 0xff, 0x8a, 0xb6, 0x8c, 0xfc, 0xe2, 0xf2, 0x90,
+		 0xd1, 0x69, 0x95, 0x20, 0x55, 0x24, 0x19, 0x0f, 0xd2, 0x91,
+		 0xaa, 0x8a, 0x6e, 0x6b, 0x8e, 0x6d, 0x56, 0xa4, 0x31, 0x33,
+		 0x3b, 0x40, 0x8e, 0x6f, 0xa8 ) );
+
+/** SHA-1 Test 18 */
+HASH_DF_TEST ( test_sha1_18, sha1_algorithm,
+	INPUT ( 0x00, 0x56, 0x3a, 0x5d, 0x20, 0x7d, 0x37, 0x70, 0x7b, 0xf5,
+		0xf2, 0x4d, 0x0b, 0xd4, 0x93, 0x5d, 0xc3, 0x8d, 0xbe, 0x04,
+		0x36, 0x37, 0xb3, 0xff, 0x8a, 0xb6, 0x8c, 0xfc, 0xe2, 0xf2,
+		0x90, 0xd1, 0x69, 0x95, 0x20, 0x55, 0x24, 0x19, 0x0f, 0xd2,
+		0x91, 0xaa, 0x8a, 0x6e, 0x6b, 0x8e, 0x6d, 0x56, 0xa4, 0x31,
+		0x33, 0x3b, 0x40, 0x8e, 0x6f, 0xa8 ),
+	EXPECT ( 0xc5, 0xd3, 0xe9, 0x55, 0x1e, 0x00, 0xe4, 0xee, 0x32, 0xb2,
+		 0x11, 0x6f, 0xaf, 0x4d, 0xef, 0xf4, 0xd4, 0xcf, 0xad, 0x2b,
+		 0xdc, 0x2d, 0xba, 0xa2, 0xe0, 0xe7, 0xf9, 0xdd, 0xb9, 0xd8,
+		 0x1e, 0xed, 0x45, 0xe0, 0xa5, 0x0d, 0xa5, 0xaf, 0xd5, 0xc1,
+		 0xf6, 0xbc, 0xda, 0xf8, 0x1d, 0x28, 0x9c, 0xf4, 0xbd, 0x3c,
+		 0x91, 0xb7, 0x00, 0x5c, 0x18 ) );
+
+/** SHA-1 Test 19 */
+HASH_DF_TEST ( test_sha1_19, sha1_algorithm,
+	INPUT ( 0x01, 0x1c, 0x0e, 0x46, 0x75, 0x9b, 0x38, 0x55, 0x6a, 0x28,
+		0xa4, 0x5e, 0x7b, 0x83, 0xe1, 0x4d, 0xb8, 0x62, 0x8d, 0xb1,
+		0x62, 0x13, 0xe1, 0xba, 0x2d, 0x97, 0x74, 0xf6, 0xc0, 0xac,
+		0x68, 0xf0, 0x56, 0xdb, 0x00, 0xfb, 0x12, 0xe1, 0x5b, 0xf4,
+		0xde, 0x95, 0x50, 0xb7, 0x33, 0x1e, 0x2d, 0xbd, 0x66, 0x4c,
+		0x3a, 0xb7, 0x76, 0xe8, 0x25, 0x51, 0xc0, 0xc1, 0xc2, 0xc3,
+		0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd,
+		0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+		0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1,
+		0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
+		0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
+		0xf6, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
+		0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2,
+		0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc,
+		0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
+		0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
+		0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6 ),
+	EXPECT ( 0x60, 0x01, 0x93, 0xc8, 0xf6, 0x03, 0x1a, 0x2d, 0x49, 0x37,
+		 0x2a, 0x8b, 0x0f, 0x60, 0xf6, 0x8c, 0x1d, 0xfd, 0xac, 0xd4,
+		 0xf8, 0xea, 0x01, 0x37, 0x47, 0xd7, 0x14, 0x82, 0x33, 0x3d,
+		 0xf5, 0x25, 0x2e, 0x95, 0xb8, 0x22, 0x57, 0x39, 0x1b, 0xf1,
+		 0x0a, 0xb0, 0x7d, 0x12, 0x08, 0xb6, 0xbd, 0x66, 0x5b, 0x30,
+		 0x0a, 0xa4, 0xdb, 0x9c, 0x3e ) );
+
+/** SHA-1 Test 20 */
+HASH_DF_TEST ( test_sha1_20, sha1_algorithm,
+	INPUT ( 0x00, 0x60, 0x01, 0x93, 0xc8, 0xf6, 0x03, 0x1a, 0x2d, 0x49,
+		0x37, 0x2a, 0x8b, 0x0f, 0x60, 0xf6, 0x8c, 0x1d, 0xfd, 0xac,
+		0xd4, 0xf8, 0xea, 0x01, 0x37, 0x47, 0xd7, 0x14, 0x82, 0x33,
+		0x3d, 0xf5, 0x25, 0x2e, 0x95, 0xb8, 0x22, 0x57, 0x39, 0x1b,
+		0xf1, 0x0a, 0xb0, 0x7d, 0x12, 0x08, 0xb6, 0xbd, 0x66, 0x5b,
+		0x30, 0x0a, 0xa4, 0xdb, 0x9c, 0x3e ),
+	EXPECT ( 0x6b, 0x71, 0x82, 0x3b, 0x18, 0x20, 0x07, 0x71, 0xca, 0xae,
+		 0x5d, 0x12, 0x55, 0xc1, 0x40, 0x3e, 0xdf, 0xe3, 0x8b, 0x4d,
+		 0x18, 0xc7, 0x87, 0xbb, 0x44, 0xcd, 0x17, 0x18, 0x61, 0x52,
+		 0xef, 0xea, 0xd6, 0xfd, 0xc4, 0xb8, 0x94, 0xf9, 0x20, 0x02,
+		 0xc0, 0x72, 0x09, 0x55, 0x5d, 0x7e, 0x35, 0x54, 0xf9, 0xd1,
+		 0x2f, 0xc5, 0x59, 0x7f, 0x22 ) );
+
+/** SHA-256 Test 1 */
+HASH_DF_TEST ( test_sha256_1, sha256_algorithm,
+	INPUT ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+		0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+		0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+		0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+		0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31,
+		0x32, 0x33, 0x34, 0x35, 0x36, 0x20, 0x21, 0x22, 0x23, 0x24,
+		0x25, 0x26, 0x27 ),
+	EXPECT ( 0xab, 0x41, 0xcd, 0xe4, 0x37, 0xab, 0x8b, 0x09, 0x1c, 0xa7,
+		 0xc5, 0x75, 0x5d, 0x10, 0xf0, 0x11, 0x0c, 0x1d, 0xbd, 0x46,
+		 0x2f, 0x22, 0x6c, 0xfd, 0xab, 0xfb, 0xb0, 0x4a, 0x8b, 0xcd,
+		 0xef, 0x95, 0x16, 0x7d, 0x84, 0xaf, 0x64, 0x12, 0x8c, 0x0d,
+		 0x71, 0xf4, 0xd5, 0xb8, 0xc0, 0xed, 0xfb, 0xbe, 0x3d, 0xf4,
+		 0x04, 0x48, 0xd2, 0xd8, 0xe1 ) );
+
+/** SHA-256 Test 2 */
+HASH_DF_TEST ( test_sha256_2, sha256_algorithm,
+	INPUT ( 0x00, 0xab, 0x41, 0xcd, 0xe4, 0x37, 0xab, 0x8b, 0x09, 0x1c,
+		0xa7, 0xc5, 0x75, 0x5d, 0x10, 0xf0, 0x11, 0x0c, 0x1d, 0xbd,
+		0x46, 0x2f, 0x22, 0x6c, 0xfd, 0xab, 0xfb, 0xb0, 0x4a, 0x8b,
+		0xcd, 0xef, 0x95, 0x16, 0x7d, 0x84, 0xaf, 0x64, 0x12, 0x8c,
+		0x0d, 0x71, 0xf4, 0xd5, 0xb8, 0xc0, 0xed, 0xfb, 0xbe, 0x3d,
+		0xf4, 0x04, 0x48, 0xd2, 0xd8, 0xe1 ),
+	EXPECT ( 0xe1, 0x5d, 0xe4, 0xa8, 0xe3, 0xb1, 0x41, 0x9b, 0x61, 0xd5,
+		 0x34, 0xf1, 0x5d, 0xbd, 0x31, 0xee, 0x19, 0xec, 0x59, 0x5f,
+		 0x8b, 0x98, 0x11, 0x1a, 0x94, 0xf5, 0x22, 0x37, 0xad, 0x5d,
+		 0x66, 0xf0, 0xcf, 0xaa, 0xfd, 0xdc, 0x90, 0x19, 0x59, 0x02,
+		 0xe9, 0x79, 0xf7, 0x9b, 0x65, 0x35, 0x7f, 0xea, 0x85, 0x99,
+		 0x8e, 0x4e, 0x37, 0xd2, 0xc1 ) );
+
+/** SHA-256 Test 3 */
+HASH_DF_TEST ( test_sha256_3, sha256_algorithm,
+	INPUT ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+		0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+		0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+		0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+		0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31,
+		0x32, 0x33, 0x34, 0x35, 0x36, 0x20, 0x21, 0x22, 0x23, 0x24,
+		0x25, 0x26, 0x27, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
+		0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
+		0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
+		0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64,
+		0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+		0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76 ),
+	EXPECT ( 0xa3, 0xe9, 0x4e, 0x39, 0x26, 0xfd, 0xa1, 0x69, 0xc3, 0x03,
+		 0xd6, 0x64, 0x38, 0x39, 0x05, 0xe0, 0xd7, 0x99, 0x62, 0xd1,
+		 0x65, 0x44, 0x6d, 0x63, 0xbd, 0xa6, 0x54, 0xd1, 0x32, 0xf7,
+		 0x2d, 0xb4, 0x71, 0x56, 0x4b, 0x45, 0x6f, 0xf2, 0xee, 0xc8,
+		 0x36, 0x42, 0x2a, 0xcc, 0x5a, 0x02, 0x99, 0x35, 0xa7, 0x99,
+		 0x29, 0x90, 0x94, 0xa1, 0xca ) );
+
+/** SHA-256 Test 4 */
+HASH_DF_TEST ( test_sha256_4, sha256_algorithm,
+	INPUT ( 0x00, 0xa3, 0xe9, 0x4e, 0x39, 0x26, 0xfd, 0xa1, 0x69, 0xc3,
+		0x03, 0xd6, 0x64, 0x38, 0x39, 0x05, 0xe0, 0xd7, 0x99, 0x62,
+		0xd1, 0x65, 0x44, 0x6d, 0x63, 0xbd, 0xa6, 0x54, 0xd1, 0x32,
+		0xf7, 0x2d, 0xb4, 0x71, 0x56, 0x4b, 0x45, 0x6f, 0xf2, 0xee,
+		0xc8, 0x36, 0x42, 0x2a, 0xcc, 0x5a, 0x02, 0x99, 0x35, 0xa7,
+		0x99, 0x29, 0x90, 0x94, 0xa1, 0xca ),
+	EXPECT ( 0x44, 0x74, 0x8a, 0x78, 0xb1, 0x6e, 0x75, 0x55, 0x9f, 0x88,
+		 0x1d, 0x51, 0xc1, 0x5d, 0xfe, 0x6c, 0x52, 0xcf, 0xb0, 0xbb,
+		 0x71, 0x62, 0x01, 0x69, 0xc7, 0x93, 0x34, 0x27, 0x67, 0xe7,
+		 0xf8, 0x87, 0x5f, 0x42, 0xcb, 0x6a, 0x20, 0xc8, 0x9d, 0x7c,
+		 0x6e, 0xf3, 0xdc, 0x61, 0x0d, 0x8f, 0xf2, 0x03, 0xd6, 0x76,
+		 0x6c, 0xed, 0x19, 0x19, 0xd0 ) );
+
+/** SHA-256 Test 5 */
+HASH_DF_TEST ( test_sha256_5, sha256_algorithm,
+	INPUT ( 0x01, 0xab, 0x41, 0xcd, 0xe4, 0x37, 0xab, 0x8b, 0x09, 0x1c,
+		0xa7, 0xc5, 0x75, 0x5d, 0x10, 0xf0, 0x11, 0x0c, 0x1d, 0xbd,
+		0x46, 0x2f, 0x22, 0x6c, 0xfd, 0xab, 0xfb, 0xb0, 0x4a, 0x8b,
+		0xcd, 0xef, 0x95, 0x16, 0x7d, 0x84, 0xaf, 0x64, 0x12, 0x8c,
+		0x0d, 0x71, 0xf4, 0xd5, 0xb8, 0xc0, 0xed, 0xfb, 0xbe, 0x3d,
+		0xf4, 0x04, 0x48, 0xd2, 0xd8, 0xe1, 0x80, 0x81, 0x82, 0x83,
+		0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
+		0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+		0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1,
+		0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab,
+		0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
+		0xb6 ),
+	EXPECT ( 0x3c, 0x40, 0xe8, 0xdc, 0x71, 0x72, 0xfd, 0xa2, 0x32, 0x55,
+		 0x0a, 0x1d, 0x8e, 0x14, 0x47, 0xc1, 0x1f, 0x47, 0x48, 0x88,
+		 0xf9, 0x6c, 0xd8, 0x5c, 0x38, 0x63, 0xd5, 0xe4, 0x84, 0x26,
+		 0x67, 0x56, 0x28, 0xd0, 0x88, 0x85, 0x34, 0x7c, 0x3e, 0xfd,
+		 0x62, 0x92, 0xfd, 0xdc, 0xd1, 0xa1, 0x42, 0x1e, 0xed, 0x51,
+		 0xb7, 0x13, 0xab, 0x09, 0x0f ) );
+
+/** SHA-256 Test 6 */
+HASH_DF_TEST ( test_sha256_6, sha256_algorithm,
+	INPUT ( 0x00, 0x3c, 0x40, 0xe8, 0xdc, 0x71, 0x72, 0xfd, 0xa2, 0x32,
+		0x55, 0x0a, 0x1d, 0x8e, 0x14, 0x47, 0xc1, 0x1f, 0x47, 0x48,
+		0x88, 0xf9, 0x6c, 0xd8, 0x5c, 0x38, 0x63, 0xd5, 0xe4, 0x84,
+		0x26, 0x67, 0x56, 0x28, 0xd0, 0x88, 0x85, 0x34, 0x7c, 0x3e,
+		0xfd, 0x62, 0x92, 0xfd, 0xdc, 0xd1, 0xa1, 0x42, 0x1e, 0xed,
+		0x51, 0xb7, 0x13, 0xab, 0x09, 0x0f ),
+	EXPECT ( 0xe7, 0x56, 0x83, 0x84, 0xf2, 0x64, 0xe4, 0xa7, 0xe7, 0xae,
+		 0x85, 0x0d, 0x9d, 0x50, 0x1f, 0xd6, 0x31, 0x83, 0x56, 0x4f,
+		 0xd7, 0xd3, 0x90, 0x44, 0x6f, 0x5b, 0xe5, 0xf6, 0x7b, 0x50,
+		 0x19, 0x5b, 0x52, 0x84, 0x69, 0x2a, 0xd4, 0xb7, 0x6d, 0xfd,
+		 0x4f, 0x52, 0x4b, 0xcf, 0xcc, 0xab, 0x62, 0xc1, 0x30, 0x9f,
+		 0x25, 0x15, 0x17, 0xdf, 0xfd ) );
+
+/** SHA-256 Test 7 */
+HASH_DF_TEST ( test_sha256_7, sha256_algorithm,
+	INPUT ( 0x01, 0x23, 0x97, 0x6c, 0x61, 0x63, 0xd7, 0xe2, 0x4a, 0x1a,
+		0x03, 0x8f, 0x2b, 0x2b, 0x64, 0x67, 0x97, 0x50, 0xca, 0x9e,
+		0xd8, 0xd1, 0x40, 0x69, 0x8d, 0x64, 0x22, 0x39, 0x7b, 0x02,
+		0x96, 0x9e, 0x6e, 0xcd, 0xd2, 0x9d, 0xac, 0xc5, 0x76, 0x7e,
+		0x2c, 0xc2, 0xd0, 0xa1, 0x56, 0xc8, 0x7a, 0xd0, 0xb3, 0x57,
+		0x89, 0x05, 0x07, 0xe0, 0x37, 0x77, 0xc0, 0xc1, 0xc2, 0xc3,
+		0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd,
+		0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+		0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1,
+		0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
+		0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
+		0xf6 ),
+	EXPECT ( 0xe9, 0x83, 0xb1, 0x66, 0xa9, 0x2a, 0x99, 0x7e, 0xab, 0xcc,
+		 0x96, 0x6c, 0x6a, 0xa3, 0xd3, 0xb3, 0xa1, 0x68, 0x1f, 0xc5,
+		 0x8f, 0x58, 0x29, 0x40, 0x3b, 0x48, 0x60, 0x1e, 0xc1, 0x77,
+		 0x54, 0x94, 0x2e, 0x11, 0xc1, 0xcd, 0x46, 0x5b, 0x7d, 0xbe,
+		 0x2a, 0x78, 0xca, 0x04, 0x2c, 0xf9, 0xb3, 0x05, 0x71, 0xff,
+		 0x12, 0xe3, 0xb9, 0xf6, 0xc9 ) );
+
+/** SHA-256 Test 8 */
+HASH_DF_TEST ( test_sha256_8, sha256_algorithm,
+	INPUT ( 0x00, 0xe9, 0x83, 0xb1, 0x66, 0xa9, 0x2a, 0x99, 0x7e, 0xab,
+		0xcc, 0x96, 0x6c, 0x6a, 0xa3, 0xd3, 0xb3, 0xa1, 0x68, 0x1f,
+		0xc5, 0x8f, 0x58, 0x29, 0x40, 0x3b, 0x48, 0x60, 0x1e, 0xc1,
+		0x77, 0x54, 0x94, 0x2e, 0x11, 0xc1, 0xcd, 0x46, 0x5b, 0x7d,
+		0xbe, 0x2a, 0x78, 0xca, 0x04, 0x2c, 0xf9, 0xb3, 0x05, 0x71,
+		0xff, 0x12, 0xe3, 0xb9, 0xf6, 0xc9 ),
+	EXPECT ( 0xa9, 0x77, 0x5c, 0xe1, 0x65, 0x5b, 0xff, 0x95, 0x1b, 0xe0,
+		 0xaf, 0x5b, 0x79, 0x59, 0x72, 0x5c, 0x76, 0x7d, 0x86, 0xf1,
+		 0xe1, 0x9b, 0x11, 0xb8, 0x90, 0x04, 0xf6, 0x97, 0x4d, 0xbf,
+		 0xa0, 0x46, 0x04, 0x45, 0x8e, 0x5c, 0x52, 0x8e, 0x7e, 0x1d,
+		 0xfa, 0xb3, 0x88, 0x7b, 0xa4, 0xaa, 0xdb, 0xd6, 0xfb, 0xde,
+		 0x0b, 0x31, 0x6f, 0x1d, 0x91 ) );
+
+/** SHA-256 Test 9 */
+HASH_DF_TEST ( test_sha256_9, sha256_algorithm,
+	INPUT ( 0x01, 0xab, 0x41, 0xcd, 0xe4, 0x37, 0xab, 0x8b, 0x09, 0x1c,
+		0xa7, 0xc5, 0x75, 0x5d, 0x10, 0xf0, 0x11, 0x0c, 0x1d, 0xbd,
+		0x46, 0x2f, 0x22, 0x6c, 0xfd, 0xab, 0xfb, 0xb0, 0x4a, 0x8b,
+		0xcd, 0xef, 0x95, 0x16, 0x7d, 0x84, 0xaf, 0x64, 0x12, 0x8c,
+		0x0d, 0x71, 0xf4, 0xd5, 0xb8, 0xc0, 0xed, 0xfb, 0xbe, 0x3d,
+		0xf4, 0x04, 0x48, 0xd2, 0xd8, 0xe1, 0x80, 0x81, 0x82, 0x83,
+		0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
+		0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+		0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1,
+		0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab,
+		0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
+		0xb6, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+		0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
+		0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c,
+		0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
+		0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
+		0x91, 0x92, 0x93, 0x94, 0x95, 0x96 ),
+	EXPECT ( 0x57, 0xb2, 0xcf, 0x00, 0xb5, 0x42, 0x97, 0x46, 0x0b, 0x08,
+		 0x7e, 0x52, 0x75, 0xd7, 0xdd, 0x74, 0x23, 0xb6, 0xe3, 0xb6,
+		 0x5e, 0x35, 0x16, 0xd2, 0x48, 0x11, 0x99, 0xa0, 0x17, 0xb5,
+		 0x3a, 0x22, 0x20, 0x33, 0xfe, 0x68, 0xa6, 0x0b, 0xd0, 0xbd,
+		 0x70, 0x40, 0x26, 0xcd, 0x5a, 0x3e, 0x79, 0x55, 0xdb, 0x01,
+		 0xdc, 0xb2, 0x84, 0x48, 0xd1 ) );
+
+/** SHA-256 Test 10 */
+HASH_DF_TEST ( test_sha256_10, sha256_algorithm,
+	INPUT ( 0x00, 0x57, 0xb2, 0xcf, 0x00, 0xb5, 0x42, 0x97, 0x46, 0x0b,
+		0x08, 0x7e, 0x52, 0x75, 0xd7, 0xdd, 0x74, 0x23, 0xb6, 0xe3,
+		0xb6, 0x5e, 0x35, 0x16, 0xd2, 0x48, 0x11, 0x99, 0xa0, 0x17,
+		0xb5, 0x3a, 0x22, 0x20, 0x33, 0xfe, 0x68, 0xa6, 0x0b, 0xd0,
+		0xbd, 0x70, 0x40, 0x26, 0xcd, 0x5a, 0x3e, 0x79, 0x55, 0xdb,
+		0x01, 0xdc, 0xb2, 0x84, 0x48, 0xd1 ),
+	EXPECT ( 0x5b, 0xc1, 0xc6, 0x45, 0xcc, 0x8d, 0x32, 0x15, 0x82, 0xaf,
+		 0xbb, 0x00, 0x16, 0x99, 0x2b, 0x0f, 0x3a, 0xfe, 0x0f, 0x54,
+		 0x7a, 0xe7, 0xa7, 0x4c, 0x9c, 0x05, 0xa1, 0x44, 0x02, 0xfb,
+		 0xb1, 0xd5, 0x40, 0xe6, 0x80, 0x9d, 0x8b, 0xee, 0xf5, 0x99,
+		 0xed, 0x4c, 0x39, 0x16, 0x47, 0x40, 0xed, 0xa0, 0xd9, 0xc3,
+		 0x79, 0x5d, 0xe5, 0x52, 0xc5 ) );
+
+/** SHA-256 Test 11 */
+HASH_DF_TEST ( test_sha256_11, sha256_algorithm,
+	INPUT ( 0x01, 0xb3, 0x74, 0x95, 0x46, 0x81, 0xcf, 0xc9, 0x5b, 0x8d,
+		0xb8, 0x39, 0x52, 0x8c, 0x71, 0x08, 0x83, 0x5e, 0xb4, 0xf3,
+		0x0a, 0xd9, 0x1c, 0xbe, 0x9e, 0xa0, 0xd5, 0x45, 0xcc, 0xfd,
+		0x18, 0x13, 0x2a, 0xf1, 0xd3, 0x76, 0x8f, 0x47, 0x02, 0x77,
+		0x2b, 0x69, 0x15, 0x9f, 0x2c, 0xc0, 0x7f, 0x48, 0x74, 0x1e,
+		0xb5, 0xb2, 0xb1, 0x22, 0x11, 0x25, 0xc0, 0xc1, 0xc2, 0xc3,
+		0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd,
+		0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+		0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1,
+		0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
+		0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
+		0xf6, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
+		0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2,
+		0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc,
+		0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
+		0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
+		0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6 ),
+	EXPECT ( 0x5d, 0xc1, 0xc5, 0xf4, 0xb4, 0x11, 0x50, 0xce, 0xe0, 0xef,
+		 0xc1, 0x29, 0xb8, 0x37, 0xb3, 0x1c, 0x84, 0xd7, 0x91, 0xff,
+		 0x2e, 0x7e, 0xda, 0xc2, 0x9c, 0x2c, 0x50, 0xcf, 0x8a, 0x40,
+		 0x70, 0x9b, 0x98, 0x64, 0x0f, 0x7b, 0xbd, 0x32, 0xbc, 0xf0,
+		 0xfc, 0xb6, 0x13, 0xf9, 0x6d, 0x55, 0xd1, 0x60, 0x56, 0xbb,
+		 0x3c, 0xa6, 0xa7, 0x74, 0x05 ) );
+
+/** SHA-256 Test 12 */
+HASH_DF_TEST ( test_sha256_12, sha256_algorithm,
+	INPUT ( 0x00, 0x5d, 0xc1, 0xc5, 0xf4, 0xb4, 0x11, 0x50, 0xce, 0xe0,
+		0xef, 0xc1, 0x29, 0xb8, 0x37, 0xb3, 0x1c, 0x84, 0xd7, 0x91,
+		0xff, 0x2e, 0x7e, 0xda, 0xc2, 0x9c, 0x2c, 0x50, 0xcf, 0x8a,
+		0x40, 0x70, 0x9b, 0x98, 0x64, 0x0f, 0x7b, 0xbd, 0x32, 0xbc,
+		0xf0, 0xfc, 0xb6, 0x13, 0xf9, 0x6d, 0x55, 0xd1, 0x60, 0x56,
+		0xbb, 0x3c, 0xa6, 0xa7, 0x74, 0x05 ),
+	EXPECT ( 0x62, 0x22, 0x10, 0x8c, 0xed, 0xfe, 0x6d, 0x6a, 0x22, 0x9f,
+		 0x8c, 0x3c, 0xbf, 0x44, 0x68, 0xc8, 0xf5, 0x17, 0x22, 0x86,
+		 0x4c, 0xc4, 0x16, 0xa4, 0x29, 0x26, 0xd9, 0x9b, 0xa6, 0xf0,
+		 0x45, 0xc1, 0xf6, 0x21, 0x11, 0x56, 0x94, 0x6c, 0x6e, 0x79,
+		 0x37, 0x29, 0x97, 0x4e, 0xb4, 0xc5, 0xa6, 0x07, 0x8f, 0x9a,
+		 0x1d, 0x4d, 0x1c, 0xd7, 0x49 ) );
+
+/** SHA-256 Test 13 */
+HASH_DF_TEST ( test_sha256_13, sha256_algorithm,
+	INPUT ( 0x01, 0xa3, 0xe9, 0x4e, 0x39, 0x26, 0xfd, 0xa1, 0x69, 0xc3,
+		0x03, 0xd6, 0x64, 0x38, 0x39, 0x05, 0xe0, 0xd7, 0x99, 0x62,
+		0xd1, 0x65, 0x44, 0x6d, 0x63, 0xbd, 0xa6, 0x54, 0xd1, 0x32,
+		0xf7, 0x2d, 0xb4, 0x71, 0x56, 0x4b, 0x45, 0x6f, 0xf2, 0xee,
+		0xc8, 0x36, 0x42, 0x2a, 0xcc, 0x5a, 0x02, 0x99, 0x35, 0xa7,
+		0x99, 0x29, 0x90, 0x94, 0xa1, 0xca, 0x80, 0x81, 0x82, 0x83,
+		0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
+		0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+		0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1,
+		0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab,
+		0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
+		0xb6 ),
+	EXPECT ( 0xe0, 0x26, 0xa5, 0xc2, 0xe7, 0x62, 0x3e, 0x62, 0xb7, 0x1a,
+		 0x2e, 0x04, 0xc2, 0x5f, 0x0b, 0x08, 0x58, 0x2b, 0xe2, 0x16,
+		 0x36, 0x34, 0xc0, 0x49, 0x6d, 0x2b, 0x65, 0xda, 0x7e, 0xaa,
+		 0x03, 0xb5, 0xc3, 0xb6, 0xb5, 0x10, 0xbb, 0x3f, 0xe4, 0x74,
+		 0x34, 0x07, 0x1f, 0x70, 0x7a, 0xc7, 0xfe, 0x4c, 0x39, 0x6a,
+		 0xaa, 0xee, 0x76, 0x4c, 0x90 ) );
+
+/** SHA-256 Test 14 */
+HASH_DF_TEST ( test_sha256_14, sha256_algorithm,
+	INPUT ( 0x00, 0xe0, 0x26, 0xa5, 0xc2, 0xe7, 0x62, 0x3e, 0x62, 0xb7,
+		0x1a, 0x2e, 0x04, 0xc2, 0x5f, 0x0b, 0x08, 0x58, 0x2b, 0xe2,
+		0x16, 0x36, 0x34, 0xc0, 0x49, 0x6d, 0x2b, 0x65, 0xda, 0x7e,
+		0xaa, 0x03, 0xb5, 0xc3, 0xb6, 0xb5, 0x10, 0xbb, 0x3f, 0xe4,
+		0x74, 0x34, 0x07, 0x1f, 0x70, 0x7a, 0xc7, 0xfe, 0x4c, 0x39,
+		0x6a, 0xaa, 0xee, 0x76, 0x4c, 0x90 ),
+	EXPECT ( 0xc9, 0xea, 0x75, 0x4b, 0xee, 0x0a, 0xb6, 0x44, 0x15, 0xca,
+		 0x7f, 0xe3, 0x2e, 0xbb, 0xfb, 0x07, 0xed, 0x93, 0x2e, 0x7c,
+		 0x95, 0x7e, 0xce, 0xae, 0xf0, 0xcd, 0x2f, 0xa7, 0x7a, 0x46,
+		 0xf9, 0xe8, 0x59, 0x62, 0x78, 0x97, 0x54, 0xc6, 0xd2, 0x98,
+		 0xf9, 0xb5, 0xe4, 0x59, 0x6b, 0x4e, 0x0e, 0x6d, 0xf4, 0xf4,
+		 0xb8, 0x23, 0x60, 0xda, 0x33 ) );
+
+/** SHA-256 Test 15 */
+HASH_DF_TEST ( test_sha256_15, sha256_algorithm,
+	INPUT ( 0x01, 0xaa, 0x11, 0x1b, 0x0e, 0xd5, 0x6c, 0xf4, 0xa6, 0xcc,
+		0xe4, 0xad, 0xe7, 0xf1, 0x1b, 0x06, 0x10, 0x45, 0xbf, 0x10,
+		0x92, 0xcb, 0xb3, 0x8f, 0xf3, 0x23, 0x95, 0xea, 0x62, 0xd2,
+		0x6b, 0x27, 0xc8, 0x86, 0x89, 0x45, 0xc5, 0x93, 0xba, 0x70,
+		0xc3, 0x84, 0xad, 0xad, 0x45, 0x77, 0x1c, 0x93, 0xb0, 0x9c,
+		0x27, 0x69, 0x07, 0x52, 0xd1, 0xd8, 0xc0, 0xc1, 0xc2, 0xc3,
+		0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd,
+		0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+		0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1,
+		0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
+		0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
+		0xf6 ),
+	EXPECT ( 0xfc, 0x5f, 0x56, 0x48, 0xed, 0xc4, 0xfc, 0x30, 0x7b, 0x5c,
+		 0x5a, 0x53, 0xd5, 0x12, 0x89, 0xb5, 0x0e, 0x73, 0xdc, 0xec,
+		 0x4a, 0xa1, 0xcb, 0x47, 0xa3, 0xba, 0xd8, 0x46, 0xbb, 0x57,
+		 0xc3, 0xc4, 0x80, 0x49, 0x1d, 0xf5, 0x21, 0xc4, 0x66, 0x9b,
+		 0xff, 0xf3, 0x7a, 0x41, 0x8b, 0xaf, 0x6e, 0x9b, 0xea, 0xec,
+		 0x34, 0x96, 0xd0, 0xf1, 0xa6 ) );
+
+/** SHA-256 Test 16 */
+HASH_DF_TEST ( test_sha256_16, sha256_algorithm,
+	INPUT ( 0x00, 0xfc, 0x5f, 0x56, 0x48, 0xed, 0xc4, 0xfc, 0x30, 0x7b,
+		0x5c, 0x5a, 0x53, 0xd5, 0x12, 0x89, 0xb5, 0x0e, 0x73, 0xdc,
+		0xec, 0x4a, 0xa1, 0xcb, 0x47, 0xa3, 0xba, 0xd8, 0x46, 0xbb,
+		0x57, 0xc3, 0xc4, 0x80, 0x49, 0x1d, 0xf5, 0x21, 0xc4, 0x66,
+		0x9b, 0xff, 0xf3, 0x7a, 0x41, 0x8b, 0xaf, 0x6e, 0x9b, 0xea,
+		0xec, 0x34, 0x96, 0xd0, 0xf1, 0xa6 ),
+	EXPECT ( 0x62, 0xb0, 0x7d, 0xc3, 0x9e, 0xbd, 0xf3, 0x10, 0x87, 0xb8,
+		 0x5d, 0xdc, 0xec, 0xfd, 0x43, 0x35, 0x62, 0xe5, 0x3b, 0xae,
+		 0x9f, 0x72, 0x1c, 0x5a, 0xfa, 0xb8, 0xf1, 0xcf, 0x01, 0x61,
+		 0xc8, 0x8e, 0x45, 0x50, 0x3e, 0x15, 0xb2, 0x6e, 0x7b, 0x80,
+		 0xd5, 0x1d, 0xb0, 0xb9, 0x24, 0x52, 0x36, 0x2d, 0xc3, 0xdc,
+		 0x57, 0x0d, 0xfe, 0x6e, 0x17 ) );
+
+/** SHA-256 Test 17 */
+HASH_DF_TEST ( test_sha256_17, sha256_algorithm,
+	INPUT ( 0x01, 0xa3, 0xe9, 0x4e, 0x39, 0x26, 0xfd, 0xa1, 0x69, 0xc3,
+		0x03, 0xd6, 0x64, 0x38, 0x39, 0x05, 0xe0, 0xd7, 0x99, 0x62,
+		0xd1, 0x65, 0x44, 0x6d, 0x63, 0xbd, 0xa6, 0x54, 0xd1, 0x32,
+		0xf7, 0x2d, 0xb4, 0x71, 0x56, 0x4b, 0x45, 0x6f, 0xf2, 0xee,
+		0xc8, 0x36, 0x42, 0x2a, 0xcc, 0x5a, 0x02, 0x99, 0x35, 0xa7,
+		0x99, 0x29, 0x90, 0x94, 0xa1, 0xca, 0x80, 0x81, 0x82, 0x83,
+		0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
+		0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+		0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1,
+		0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab,
+		0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
+		0xb6, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+		0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
+		0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c,
+		0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
+		0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
+		0x91, 0x92, 0x93, 0x94, 0x95, 0x96 ),
+	EXPECT ( 0x98, 0x75, 0xbb, 0x7c, 0x7a, 0x0b, 0x23, 0x6b, 0xf4, 0x6f,
+		 0x4e, 0xa6, 0x6f, 0x67, 0xc7, 0xb4, 0x4f, 0x80, 0xef, 0x70,
+		 0x61, 0x4b, 0xef, 0xe8, 0xb0, 0x85, 0xcc, 0xaf, 0x55, 0x89,
+		 0xa7, 0x6f, 0x85, 0xfd, 0x96, 0x69, 0x53, 0xe2, 0x0a, 0x55,
+		 0xd2, 0xf3, 0x5b, 0xa5, 0x81, 0xef, 0x51, 0x11, 0xbf, 0xbf,
+		 0x05, 0x65, 0x3a, 0xf7, 0xe7 ) );
+
+/** SHA-256 Test 18 */
+HASH_DF_TEST ( test_sha256_18, sha256_algorithm,
+	INPUT ( 0x00, 0x98, 0x75, 0xbb, 0x7c, 0x7a, 0x0b, 0x23, 0x6b, 0xf4,
+		0x6f, 0x4e, 0xa6, 0x6f, 0x67, 0xc7, 0xb4, 0x4f, 0x80, 0xef,
+		0x70, 0x61, 0x4b, 0xef, 0xe8, 0xb0, 0x85, 0xcc, 0xaf, 0x55,
+		0x89, 0xa7, 0x6f, 0x85, 0xfd, 0x96, 0x69, 0x53, 0xe2, 0x0a,
+		0x55, 0xd2, 0xf3, 0x5b, 0xa5, 0x81, 0xef, 0x51, 0x11, 0xbf,
+		0xbf, 0x05, 0x65, 0x3a, 0xf7, 0xe7 ),
+	EXPECT ( 0x12, 0x80, 0xfe, 0x1f, 0x05, 0x79, 0x8c, 0xca, 0xed, 0x5d,
+		 0x6d, 0xf6, 0xe7, 0xd2, 0x6f, 0x04, 0x6e, 0x53, 0x8c, 0xc5,
+		 0x2a, 0x6a, 0x03, 0x0d, 0xa8, 0x26, 0xb2, 0xb4, 0x79, 0x82,
+		 0xd6, 0xee, 0x8a, 0x68, 0x67, 0x58, 0x07, 0x06, 0x93, 0x9e,
+		 0xcc, 0x03, 0xfc, 0x11, 0xb0, 0x05, 0x9f, 0xe2, 0xae, 0xad,
+		 0xea, 0x0a, 0x46, 0x98, 0x5c ) );
+
+/** SHA-256 Test 19 */
+HASH_DF_TEST ( test_sha256_19, sha256_algorithm,
+	INPUT ( 0x01, 0xaa, 0xf6, 0xb9, 0x9b, 0x7f, 0x84, 0xb0, 0x36, 0xe1,
+		0xcc, 0xbc, 0x9d, 0x57, 0x3a, 0x36, 0xb8, 0xbd, 0xd4, 0x7c,
+		0x35, 0x8b, 0xb5, 0xf3, 0xc1, 0xd6, 0xe7, 0x90, 0x3a, 0xaa,
+		0x29, 0xf1, 0xc8, 0x7a, 0xe6, 0x66, 0xb8, 0x86, 0x93, 0xbe,
+		0xf4, 0x6c, 0x51, 0xc2, 0x4c, 0x47, 0xbe, 0xfe, 0x4b, 0x35,
+		0x75, 0x4d, 0xcb, 0xfa, 0x1e, 0x7d, 0xc0, 0xc1, 0xc2, 0xc3,
+		0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd,
+		0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+		0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1,
+		0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
+		0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
+		0xf6, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
+		0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2,
+		0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc,
+		0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
+		0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
+		0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6 ),
+	EXPECT ( 0xb0, 0x6d, 0xbf, 0xb1, 0x4e, 0x7f, 0x4e, 0x01, 0x25, 0x62,
+		 0x94, 0x2f, 0xe4, 0xf2, 0xa9, 0x60, 0x17, 0x07, 0x55, 0x9d,
+		 0x7d, 0xd1, 0x90, 0x89, 0x8b, 0xc8, 0x06, 0x24, 0xe5, 0xc8,
+		 0xc1, 0xbb, 0x9b, 0x90, 0xfb, 0x2e, 0xef, 0x12, 0xed, 0x24,
+		 0xbe, 0xbd, 0x8d, 0xf7, 0x1e, 0xf6, 0x5c, 0x70, 0xfa, 0x4e,
+		 0x91, 0x86, 0x3a, 0x31, 0xbe ) );
+
+/** SHA-256 Test 20 */
+HASH_DF_TEST ( test_sha256_20, sha256_algorithm,
+	INPUT ( 0x00, 0xb0, 0x6d, 0xbf, 0xb1, 0x4e, 0x7f, 0x4e, 0x01, 0x25,
+		0x62, 0x94, 0x2f, 0xe4, 0xf2, 0xa9, 0x60, 0x17, 0x07, 0x55,
+		0x9d, 0x7d, 0xd1, 0x90, 0x89, 0x8b, 0xc8, 0x06, 0x24, 0xe5,
+		0xc8, 0xc1, 0xbb, 0x9b, 0x90, 0xfb, 0x2e, 0xef, 0x12, 0xed,
+		0x24, 0xbe, 0xbd, 0x8d, 0xf7, 0x1e, 0xf6, 0x5c, 0x70, 0xfa,
+		0x4e, 0x91, 0x86, 0x3a, 0x31, 0xbe ),
+	EXPECT ( 0x5c, 0x07, 0xb7, 0x9c, 0x12, 0x83, 0x1b, 0xac, 0x36, 0x52,
+		 0x17, 0x8b, 0x2f, 0x90, 0x7a, 0x69, 0x61, 0x98, 0x39, 0xd8,
+		 0xa7, 0xfa, 0xa2, 0xb6, 0x95, 0xef, 0xb3, 0x10, 0x82, 0x38,
+		 0x01, 0x35, 0x85, 0x19, 0x1f, 0x59, 0x9c, 0x99, 0x07, 0xc7,
+		 0x21, 0x92, 0xed, 0x25, 0x7e, 0x9f, 0x6c, 0xd3, 0x77, 0xdd,
+		 0x6b, 0xac, 0x33, 0x7c, 0x19 ) );
+
+/**
+ * Report Hash_df test result
+ *
+ * @v test		Hash_df test
+ */
+#define hash_df_ok( test ) do {						\
+	uint8_t output[ (test)->expected_len ];				\
+	hash_df ( (test)->hash, (test)->input, (test)->input_len,	\
+		  output, sizeof ( output ) );				\
+	ok ( memcmp ( (test)->expected, output,				\
+		      sizeof ( output ) ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Perform Hash_df self-test
+ *
+ */
+static void hash_df_test_exec ( void ) {
+
+	hash_df_ok ( &test_sha1_1 );
+	hash_df_ok ( &test_sha1_2 );
+	hash_df_ok ( &test_sha1_3 );
+	hash_df_ok ( &test_sha1_4 );
+	hash_df_ok ( &test_sha1_5 );
+	hash_df_ok ( &test_sha1_6 );
+	hash_df_ok ( &test_sha1_7 );
+	hash_df_ok ( &test_sha1_8 );
+	hash_df_ok ( &test_sha1_9 );
+	hash_df_ok ( &test_sha1_10 );
+	hash_df_ok ( &test_sha1_11 );
+	hash_df_ok ( &test_sha1_12 );
+	hash_df_ok ( &test_sha1_13 );
+	hash_df_ok ( &test_sha1_14 );
+	hash_df_ok ( &test_sha1_15 );
+	hash_df_ok ( &test_sha1_16 );
+	hash_df_ok ( &test_sha1_17 );
+	hash_df_ok ( &test_sha1_18 );
+	hash_df_ok ( &test_sha1_19 );
+	hash_df_ok ( &test_sha1_20 );
+
+	hash_df_ok ( &test_sha256_1 );
+	hash_df_ok ( &test_sha256_2 );
+	hash_df_ok ( &test_sha256_3 );
+	hash_df_ok ( &test_sha256_4 );
+	hash_df_ok ( &test_sha256_5 );
+	hash_df_ok ( &test_sha256_6 );
+	hash_df_ok ( &test_sha256_7 );
+	hash_df_ok ( &test_sha256_8 );
+	hash_df_ok ( &test_sha256_9 );
+	hash_df_ok ( &test_sha256_10 );
+	hash_df_ok ( &test_sha256_11 );
+	hash_df_ok ( &test_sha256_12 );
+	hash_df_ok ( &test_sha256_13 );
+	hash_df_ok ( &test_sha256_14 );
+	hash_df_ok ( &test_sha256_15 );
+	hash_df_ok ( &test_sha256_16 );
+	hash_df_ok ( &test_sha256_17 );
+	hash_df_ok ( &test_sha256_18 );
+	hash_df_ok ( &test_sha256_19 );
+	hash_df_ok ( &test_sha256_20 );
+}
+
+/** Hash_df self-test */
+struct self_test hash_df_test __self_test = {
+	.name = "hash_df",
+	.exec = hash_df_test_exec,
+};
diff --git a/roms/ipxe/src/tests/hmac_drbg_test.c b/roms/ipxe/src/tests/hmac_drbg_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..8cbf1cc8bdeae9642873e39b17e393935b7ae934
--- /dev/null
+++ b/roms/ipxe/src/tests/hmac_drbg_test.c
@@ -0,0 +1,1386 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * HMAC_DRBG tests
+ *
+ * These test vectors are provided by NIST as part of the
+ * Cryptographic Toolkit Examples, downloadable from:
+ *
+ *    http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/HMAC_DRBG.pdf
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <assert.h>
+#include <string.h>
+#include <ipxe/hmac_drbg.h>
+#include <ipxe/sha1.h>
+#include <ipxe/sha256.h>
+#include <ipxe/test.h>
+
+/** Define inline expected data */
+#define EXPECT(...) { __VA_ARGS__ }
+
+/** An HMAC_DRBG instantiation test */
+struct hmac_drbg_test_instantiate {
+	/** Underlying hash algorithm */
+	struct digest_algorithm *hash;
+	/** Output block length */
+	size_t out_len;
+	/** Entropy */
+	const void *entropy;
+	/** Length of entropy */
+	size_t entropy_len;
+	/** Nonce */
+	const void *nonce;
+	/** Length of nonce */
+	size_t nonce_len;
+	/** Personalisation string */
+	const void *personal;
+	/** Length of personalisation string */
+	size_t personal_len;
+	/** Expected key */
+	const void *expected_key;
+	/** Length of expected key */
+	size_t expected_key_len;
+	/** Expected value */
+	const void *expected_value;
+	/** Length of expected value */
+	size_t expected_value_len;
+};
+
+/**
+ * Define an HMAC_DRBG instantiation test
+ *
+ * @v name		Test name
+ * @v hmac_drbg		HMAC_DRBG algorithm
+ * @v entropy_array	Entropy input
+ * @v nonce_array	Nonce
+ * @v personal_array	Personalisation string
+ * @v key		Expected key
+ * @v value		Expected value
+ * @ret test		Instantiation test
+ */
+#define HMAC_DRBG_TEST_INSTANTIATE( name, hmac_drbg, entropy_array,	\
+				    nonce_array, personal_array,	\
+				    key, value )			\
+	static const uint8_t name ## _key [] = key;			\
+	static const uint8_t name ## _value [] = value;			\
+	static struct hmac_drbg_test_instantiate name = {		\
+		.hash = HMAC_DRBG_HASH ( hmac_drbg ),			\
+		.out_len = HMAC_DRBG_OUTLEN_BYTES ( hmac_drbg ),	\
+		.entropy = entropy_array,				\
+		.entropy_len = sizeof ( entropy_array ),		\
+		.nonce = nonce_array,					\
+		.nonce_len = sizeof ( nonce_array ),			\
+		.personal = personal_array,				\
+		.personal_len = sizeof ( personal_array ),		\
+		.expected_key = name ## _key,				\
+		.expected_key_len = sizeof ( name ## _key ),		\
+		.expected_value = name ## _value,			\
+		.expected_value_len = sizeof ( name ## _value ),	\
+	}
+
+/**
+ * Report instantiation test result
+ *
+ * @v state		HMAC_DRBG internal state
+ * @v test		Instantiation test
+ */
+#define instantiate_ok( state, test ) do {				\
+	struct {							\
+		uint8_t entropy[(test)->entropy_len];			\
+		uint8_t nonce[(test)->nonce_len];			\
+	} __attribute__ (( packed )) entropy_nonce;			\
+									\
+	assert ( (test)->expected_key_len == (test)->out_len );		\
+	assert ( (test)->expected_value_len == (test)->out_len );	\
+	memcpy ( entropy_nonce.entropy, (test)->entropy,		\
+		 sizeof ( entropy_nonce.entropy ) );			\
+	memcpy ( entropy_nonce.nonce, (test)->nonce,			\
+		 sizeof ( entropy_nonce.nonce ) );			\
+	hmac_drbg_instantiate ( (test)->hash, (state), &entropy_nonce,	\
+				sizeof ( entropy_nonce ),		\
+				(test)->personal,			\
+				(test)->personal_len );			\
+	ok ( memcmp ( (state)->key, (test)->expected_key,		\
+		      (test)->expected_key_len ) == 0 );		\
+	ok ( memcmp ( (state)->value, (test)->expected_value,		\
+		      (test)->expected_value_len ) == 0 );		\
+	} while ( 0 )
+
+/** An HMAC_DRBG reseed test */
+struct hmac_drbg_test_reseed {
+	/** Underlying hash algorithm */
+	struct digest_algorithm *hash;
+	/** Output block length */
+	size_t out_len;
+	/** Entropy */
+	const void *entropy;
+	/** Length of entropy */
+	size_t entropy_len;
+	/** Additional input */
+	const void *additional;
+	/** Length of additional_input */
+	size_t additional_len;
+	/** Expected key */
+	const void *expected_key;
+	/** Length of expected key */
+	size_t expected_key_len;
+	/** Expected value */
+	const void *expected_value;
+	/** Length of expected value */
+	size_t expected_value_len;
+};
+
+/**
+ * Define an HMAC_DRBG reseed test
+ *
+ * @v name		Test name
+ * @v hmac_drbg		HMAC_DRBG algorithm
+ * @v entropy_array	Entropy input
+ * @v additional_array	Additional input
+ * @v key		Expected key
+ * @v value		Expected value
+ * @ret test		Reseed test
+ */
+#define HMAC_DRBG_TEST_RESEED( name, hmac_drbg, entropy_array,		\
+			       additional_array, key, value )		\
+	static const uint8_t name ## _key [] = key;			\
+	static const uint8_t name ## _value [] = value;			\
+	static struct hmac_drbg_test_reseed name = {			\
+		.hash = HMAC_DRBG_HASH ( hmac_drbg ),			\
+		.out_len = HMAC_DRBG_OUTLEN_BYTES ( hmac_drbg ),	\
+		.entropy = entropy_array,				\
+		.entropy_len = sizeof ( entropy_array ),		\
+		.additional = additional_array,				\
+		.additional_len = sizeof ( additional_array ),		\
+		.expected_key = name ## _key,				\
+		.expected_key_len = sizeof ( name ## _key ),		\
+		.expected_value = name ## _value,			\
+		.expected_value_len = sizeof ( name ## _value ),	\
+	}
+
+/**
+ * Report reseed test result
+ *
+ * @v state		HMAC_DRBG internal state
+ * @v test		Reseed test
+ */
+#define reseed_ok( state, test ) do {					\
+	assert ( (test)->expected_key_len == (test)->out_len );		\
+	assert ( (test)->expected_value_len == (test)->out_len );	\
+	hmac_drbg_reseed ( (test)->hash, (state), (test)->entropy,	\
+			   (test)->entropy_len, (test)->additional,	\
+			   (test)->additional_len );			\
+	ok ( memcmp ( (state)->key, (test)->expected_key,		\
+		      (test)->expected_key_len ) == 0 );		\
+	ok ( memcmp ( (state)->value, (test)->expected_value,		\
+		      (test)->expected_value_len ) == 0 );		\
+	} while ( 0 )
+
+/** An HMAC_DRBG generation test */
+struct hmac_drbg_test_generate {
+	/** Underlying hash algorithm */
+	struct digest_algorithm *hash;
+	/** Output block length */
+	size_t out_len;
+	/** Additional input */
+	const void *additional;
+	/** Length of additional_input */
+	size_t additional_len;
+	/** Expected key */
+	const void *expected_key;
+	/** Length of expected key */
+	size_t expected_key_len;
+	/** Expected value */
+	const void *expected_value;
+	/** Length of expected value */
+	size_t expected_value_len;
+	/** Expected pseudorandom data */
+	const void *expected_data;
+	/** Length of data */
+	size_t expected_data_len;
+};
+
+/**
+ * Define an HMAC_DRBG generation test
+ *
+ * @v name		Test name
+ * @v hmac_drbg		HMAC_DRBG algorithm
+ * @v additional_array	Additional input
+ * @v key		Expected key
+ * @v value		Expected value
+ * @v data		Expected pseudorandom data
+ * @ret test		Generation test
+ */
+#define HMAC_DRBG_TEST_GENERATE( name, hmac_drbg, additional_array,	\
+				 key, value, data )			\
+	static const uint8_t name ## _key [] = key;			\
+	static const uint8_t name ## _value [] = value;			\
+	static const uint8_t name ## _data [] = data;			\
+	static struct hmac_drbg_test_generate name = {			\
+		.hash = HMAC_DRBG_HASH ( hmac_drbg ),			\
+		.out_len = HMAC_DRBG_OUTLEN_BYTES ( hmac_drbg ),	\
+		.additional = additional_array,				\
+		.additional_len = sizeof ( additional_array ),		\
+		.expected_key = name ## _key,				\
+		.expected_key_len = sizeof ( name ## _key ),		\
+		.expected_value = name ## _value,			\
+		.expected_value_len = sizeof ( name ## _value ),	\
+		.expected_data = name ## _data,				\
+		.expected_data_len = sizeof ( name ## _data ),		\
+	}
+
+/**
+ * Report generation test result
+ *
+ * @v state		HMAC_DRBG internal state
+ * @v test		Generation test
+ */
+#define generate_ok( state, test ) do {					\
+	uint8_t data[ (test)->expected_data_len ];			\
+	int rc;								\
+									\
+	assert ( (test)->expected_key_len == (test)->out_len );		\
+	assert ( (test)->expected_value_len == (test)->out_len );	\
+	rc = hmac_drbg_generate ( (test)->hash, (state),		\
+				  (test)->additional,			\
+				  (test)->additional_len,		\
+				  data, sizeof ( data ) );		\
+	ok ( rc == 0 );							\
+	ok ( memcmp ( (state)->key, (test)->expected_key,		\
+		      (test)->expected_key_len ) == 0 );		\
+	ok ( memcmp ( (state)->value, (test)->expected_value,		\
+		      (test)->expected_value_len ) == 0 );		\
+	ok ( memcmp ( data, (test)->expected_data,			\
+		      (test)->expected_data_len ) == 0 );		\
+	} while ( 0 )
+
+/** An HMAC_DRBG generation failure test */
+struct hmac_drbg_test_generate_fail {
+	/** Underlying hash algorithm */
+	struct digest_algorithm *hash;
+	/** Additional input */
+	const void *additional;
+	/** Length of additional_input */
+	size_t additional_len;
+	/** Length of requested data */
+	size_t requested_len;
+};
+
+/**
+ * Define an HMAC_DRBG generation failure test
+ *
+ * @v name		Test name
+ * @v hmac_drbg		HMAC_DRBG algorithm
+ * @v additional_array	Additional input
+ * @ret test		Generation failure test
+ */
+#define HMAC_DRBG_TEST_GENERATE_FAIL( name, hmac_drbg,			\
+				      additional_array, len )		\
+	static struct hmac_drbg_test_generate_fail name = {		\
+		.hash = HMAC_DRBG_HASH ( hmac_drbg ),			\
+		.additional = additional_array,				\
+		.additional_len = sizeof ( additional_array ),		\
+		.requested_len = len,					\
+	}
+
+/**
+ * Report generation failure test result
+ *
+ * @v state		HMAC_DRBG internal state
+ * @v test		Generation failure test
+ */
+#define generate_fail_ok( state, test ) do {				\
+	uint8_t data[ (test)->requested_len ];				\
+	int rc;								\
+									\
+	rc = hmac_drbg_generate ( (test)->hash, (state),		\
+				  (test)->additional,			\
+				  (test)->additional_len, data,		\
+				  sizeof ( data ) );			\
+	ok ( rc != 0 );							\
+	} while ( 0 )
+
+/** "EntropyInput" */
+static const uint8_t entropy_input[] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+	0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+	0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36
+};
+
+/** "Nonce" for SHA-1 */
+static const uint8_t nonce_sha1[] = {
+	0x20, 0x21, 0x22, 0x23, 0x24
+};
+
+/** "Nonce" for SHA-256 */
+static const uint8_t nonce_sha256[] = {
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
+};
+
+/** "EntropyInput1 (for Reseed1) */
+static const uint8_t entropy_input_1[] = {
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b,
+	0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3,
+	0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6
+};
+
+/** "EntropyInput2 (for Reseed2) */
+static const uint8_t entropy_input_2[] = {
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
+	0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
+	0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6
+};
+
+/** "PersonalizationString = <empty>" */
+static const uint8_t personalisation_string_empty[] = {};
+
+/** "PersonalizationString" */
+static const uint8_t personalisation_string[] = {
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
+	0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63,
+	0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76
+};
+
+/** "AdditionalInput = <empty>" */
+static const uint8_t additional_input_empty[] = {};
+
+/** "AdditionalInput1" */
+static const uint8_t additional_input_1[] = {
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
+	0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
+	0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96
+};
+
+/** "AdditionalInput2" */
+static const uint8_t additional_input_2[] = {
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab,
+	0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3,
+	0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6
+};
+
+/** SHA-1 Test 1 : Instantiation */
+HMAC_DRBG_TEST_INSTANTIATE ( sha1_instantiate_1, HMAC_DRBG_SHA1,
+	entropy_input, nonce_sha1, personalisation_string_empty,
+	EXPECT ( 0xab, 0x16, 0x0d, 0xd2, 0x1c, 0x30, 0x98, 0x0c, 0xa3, 0xca,
+		 0x5a, 0x9c, 0x77, 0xb7, 0xbd, 0xf0, 0x50, 0xe6, 0x4e, 0xe9 ),
+	EXPECT ( 0x61, 0x44, 0x99, 0xea, 0x98, 0x0c, 0xfb, 0x3d, 0xaa, 0x2c,
+		 0xa8, 0x6d, 0x65, 0xa4, 0x6b, 0xf4, 0x48, 0x8d, 0x8c, 0xc5 ) );
+
+/** SHA-1 Test 1.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_1_1, HMAC_DRBG_SHA1,
+	additional_input_empty,
+	EXPECT ( 0x7b, 0xb1, 0x80, 0x28, 0xe0, 0x1d, 0x03, 0x42, 0xdf, 0x4f,
+		 0x54, 0xda, 0x51, 0x22, 0xfa, 0x5f, 0x2c, 0x3a, 0x05, 0xe4 ),
+	EXPECT ( 0x2f, 0x89, 0x4f, 0x28, 0xcc, 0x2f, 0x53, 0x82, 0x96, 0x40,
+		 0x64, 0x3a, 0xd1, 0x7b, 0x84, 0xb0, 0xcd, 0x3c, 0x79, 0x79 ),
+	EXPECT ( 0x5a, 0x7d, 0x3b, 0x44, 0x9f, 0x48, 0x1c, 0xb3, 0x8d, 0xf7,
+		 0x9a, 0xd2, 0xb1, 0xfc, 0xc0, 0x1e, 0x57, 0xf8, 0x13, 0x5e,
+		 0x8c, 0x0b, 0x22, 0xcd, 0x06, 0x30, 0xbf, 0xb0, 0x12, 0x7f,
+		 0xb5, 0x40, 0x8c, 0x8e, 0xfc, 0x17, 0xa9, 0x29, 0x89, 0x6e ) );
+
+/** SHA-1 Test 1.2 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_1_2, HMAC_DRBG_SHA1,
+	additional_input_empty,
+	EXPECT ( 0x3d, 0x4d, 0x73, 0x77, 0xe9, 0x17, 0x2a, 0xaf, 0xa7, 0x76,
+		 0xb0, 0xdd, 0xcb, 0x89, 0x42, 0x00, 0x4a, 0x44, 0xb7, 0xfd ),
+	EXPECT ( 0x1a, 0x26, 0xbd, 0x9b, 0xfc, 0x97, 0x44, 0xbd, 0x29, 0xf6,
+		 0xae, 0xbe, 0x24, 0x37, 0xe2, 0x09, 0xf1, 0xf7, 0x16, 0x25 ),
+	EXPECT ( 0x82, 0xcf, 0x77, 0x2e, 0xc3, 0xe8, 0x4b, 0x00, 0xfc, 0x74,
+		 0xf5, 0xdf, 0x10, 0x4e, 0xfb, 0xfb, 0x24, 0x28, 0x55, 0x4e,
+		 0x9c, 0xe3, 0x67, 0xd0, 0x3a, 0xea, 0xde, 0x37, 0x82, 0x7f,
+		 0xa8, 0xe9, 0xcb, 0x6a, 0x08, 0x19, 0x61, 0x15, 0xd9, 0x48 ) );
+
+/** SHA-1 Test 2 : Instantiation */
+#define sha1_instantiate_2 sha1_instantiate_1
+
+/** SHA-1 Test 2.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_2_1, HMAC_DRBG_SHA1,
+	additional_input_1,
+	EXPECT ( 0x3a, 0x06, 0x2e, 0x6b, 0x79, 0xfe, 0x70, 0xdb, 0xff, 0xeb,
+		 0x3a, 0x2b, 0x6b, 0xe8, 0x03, 0x23, 0xf7, 0xd6, 0x74, 0xc5 ),
+	EXPECT ( 0xbd, 0x36, 0x31, 0x28, 0xbf, 0x58, 0x0d, 0x7a, 0x54, 0x42,
+		 0x9d, 0xdd, 0x58, 0xe8, 0x19, 0x3b, 0x98, 0x43, 0xbd, 0x2b ),
+	EXPECT ( 0xc7, 0xaa, 0xac, 0x58, 0x3c, 0x6e, 0xf6, 0x30, 0x07, 0x14,
+		 0xc2, 0xcc, 0x5d, 0x06, 0xc1, 0x48, 0xcf, 0xfb, 0x40, 0x44,
+		 0x9a, 0xd0, 0xbb, 0x26, 0xfa, 0xc0, 0x49, 0x7b, 0x5c, 0x57,
+		 0xe1, 0x61, 0xe3, 0x66, 0x81, 0xbc, 0xc9, 0x30, 0xce, 0x80 ) );
+
+/** SHA-1 Test 2.2 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_2_2, HMAC_DRBG_SHA1,
+	additional_input_2,
+	EXPECT ( 0x8a, 0xd7, 0xe3, 0x47, 0x72, 0xb5, 0xfc, 0x7c, 0x3b, 0x3b,
+		 0x27, 0x62, 0x4f, 0x0b, 0x91, 0x77, 0x6a, 0x8a, 0x71, 0x12 ),
+	EXPECT ( 0xd7, 0x13, 0x76, 0xa4, 0x6d, 0x76, 0x4b, 0x17, 0xc3, 0xb7,
+		 0x39, 0x34, 0x7b, 0x38, 0x4e, 0x51, 0x51, 0xe8, 0x7e, 0x88 ),
+	EXPECT ( 0x6e, 0xbd, 0x2b, 0x7b, 0x5e, 0x0a, 0x2a, 0xd7, 0xa2, 0x4b,
+		 0x1b, 0xf9, 0xa1, 0xdb, 0xa4, 0x7d, 0x43, 0x27, 0x17, 0x19,
+		 0xb9, 0xc3, 0x7b, 0x7f, 0xe8, 0x1b, 0xa9, 0x40, 0x45, 0xa1,
+		 0x4a, 0x7c, 0xb5, 0x14, 0xb4, 0x46, 0x66, 0x6e, 0xa5, 0xa7 ) );
+
+/** SHA-1 Test 3 : Instantiation */
+HMAC_DRBG_TEST_INSTANTIATE ( sha1_instantiate_3, HMAC_DRBG_SHA1,
+	entropy_input, nonce_sha1, personalisation_string,
+	EXPECT ( 0xb7, 0xd9, 0x66, 0xd7, 0x0d, 0x4e, 0x27, 0xa7, 0xfa, 0x83,
+		 0x8f, 0x7d, 0x61, 0x12, 0x6c, 0x0e, 0xdc, 0x84, 0x76, 0x1c ),
+	EXPECT ( 0xda, 0xb2, 0xa7, 0x18, 0x83, 0xf1, 0x00, 0x5c, 0x5d, 0xd0,
+		 0x39, 0x32, 0x4d, 0x3c, 0x36, 0x4d, 0x6e, 0x18, 0xf9, 0x54 ) );
+
+/** SHA-1 Test 3.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_3_1, HMAC_DRBG_SHA1,
+	additional_input_empty,
+	EXPECT ( 0x87, 0xd3, 0x82, 0x8b, 0xe0, 0x3a, 0x80, 0x7d, 0xd3, 0x40,
+		 0x29, 0x41, 0xbe, 0xd6, 0xde, 0x98, 0x6e, 0xe7, 0xa2, 0x86 ),
+	EXPECT ( 0x6a, 0xe1, 0xd0, 0x08, 0x6f, 0x53, 0xb1, 0xb7, 0x63, 0xa4,
+		 0x51, 0x5b, 0x19, 0x06, 0xfe, 0xe4, 0x76, 0x61, 0xfd, 0x47 ),
+	EXPECT ( 0xb3, 0xbd, 0x05, 0x24, 0x6c, 0xba, 0x12, 0xa6, 0x47, 0x35,
+		 0xa4, 0xe3, 0xfd, 0xe5, 0x99, 0xbc, 0x1b, 0xe3, 0x0f, 0x43,
+		 0x9b, 0xd0, 0x60, 0x20, 0x8e, 0xea, 0x7d, 0x71, 0xf9, 0xd1,
+		 0x23, 0xdf, 0x47, 0xb3, 0xce, 0x06, 0x9d, 0x98, 0xed, 0xe6 ) );
+
+/** SHA-1 Test 3.2 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_3_2, HMAC_DRBG_SHA1,
+	additional_input_empty,
+	EXPECT ( 0x26, 0xab, 0xbf, 0x54, 0xb2, 0x8b, 0x93, 0xff, 0x90, 0x08,
+		 0x67, 0x0e, 0xbf, 0xee, 0x86, 0xcd, 0xd7, 0x22, 0x8e, 0xd5 ),
+	EXPECT ( 0xe9, 0x25, 0x47, 0x29, 0xe0, 0x02, 0x04, 0xa1, 0xb6, 0xc0,
+		 0x21, 0x58, 0xa6, 0xc7, 0x27, 0x86, 0x47, 0x14, 0xf1, 0xf7 ),
+	EXPECT ( 0xb5, 0xda, 0xda, 0x38, 0x0e, 0x28, 0x72, 0xdf, 0x93, 0x5b,
+		 0xca, 0x55, 0xb8, 0x82, 0xc8, 0xc9, 0x37, 0x69, 0x02, 0xab,
+		 0x63, 0x97, 0x65, 0x47, 0x2b, 0x71, 0xac, 0xeb, 0xe2, 0xea,
+		 0x8b, 0x1b, 0x6b, 0x49, 0x62, 0x9c, 0xb6, 0x73, 0x17, 0xe0 ) );
+
+/** SHA-1 Test 4 : Instantiation */
+#define sha1_instantiate_4 sha1_instantiate_3
+
+/** SHA-1 Test 4.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_4_1, HMAC_DRBG_SHA1,
+	additional_input_1,
+	EXPECT ( 0x17, 0xa5, 0xd7, 0x9f, 0x07, 0x67, 0x87, 0x6f, 0x3a, 0x45,
+		 0xe0, 0xc9, 0xc3, 0x3e, 0xc8, 0x8b, 0x03, 0xce, 0xea, 0x13 ),
+	EXPECT ( 0x4d, 0x2f, 0x3b, 0xc7, 0x77, 0x50, 0x5c, 0x45, 0xf7, 0xe1,
+		 0x7d, 0xcd, 0x3d, 0x86, 0xbf, 0x37, 0x9c, 0xb6, 0x02, 0x5e ),
+	EXPECT ( 0x1f, 0x8f, 0xec, 0x7b, 0xc7, 0xcf, 0xa9, 0xa8, 0x80, 0x34,
+		 0x5d, 0x28, 0x0b, 0x13, 0xc6, 0x32, 0xb8, 0x52, 0x77, 0x0a,
+		 0x6d, 0xfc, 0x30, 0x2e, 0xad, 0x4c, 0xe3, 0xf5, 0x54, 0xc7,
+		 0x9b, 0x0d, 0x44, 0x23, 0x9e, 0xba, 0x56, 0xa7, 0xea, 0x2d ) );
+
+/** SHA-1 Test 4.2 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_4_2, HMAC_DRBG_SHA1,
+	additional_input_2,
+	EXPECT ( 0x07, 0x9b, 0x57, 0xd9, 0x40, 0x6e, 0x11, 0xc2, 0xf8, 0x7c,
+		 0x8c, 0x82, 0x8c, 0x8c, 0x6f, 0xa7, 0x6e, 0x40, 0xea, 0x01 ),
+	EXPECT ( 0xa6, 0x54, 0xfe, 0x72, 0xf8, 0xa7, 0x7b, 0xb8, 0xf0, 0x3d,
+		 0xff, 0x07, 0xc7, 0x9a, 0x51, 0x53, 0x00, 0x9e, 0xdd, 0xda ),
+	EXPECT ( 0xaf, 0x97, 0xcd, 0xe1, 0xe8, 0xab, 0x32, 0x2a, 0x2e, 0xac,
+		 0xa8, 0xe6, 0xf4, 0xe5, 0xbf, 0x78, 0xa1, 0x1b, 0xde, 0xf7,
+		 0xdc, 0x91, 0x21, 0x5d, 0x44, 0xb1, 0x07, 0xb4, 0xd5, 0xa7,
+		 0x79, 0x01, 0x59, 0x25, 0x09, 0x76, 0x52, 0x80, 0xf9, 0x69 ) );
+
+/** SHA-1 Test 5 : Instantiation */
+#define sha1_instantiate_5 sha1_instantiate_1
+
+/** SHA-1 Test 5.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_5_1, HMAC_DRBG_SHA1,
+	additional_input_empty, ( 320 / 8 ) );
+
+/** SHA-1 Test 5.2 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha1_reseed_5_2, HMAC_DRBG_SHA1,
+	entropy_input_1, additional_input_empty,
+	EXPECT ( 0xcd, 0x4c, 0xab, 0x38, 0xc8, 0xad, 0x65, 0x71, 0x22, 0xbf,
+		 0x5d, 0x3d, 0x00, 0xd0, 0xac, 0x9b, 0x13, 0xd6, 0x29, 0xbb ),
+	EXPECT ( 0xf6, 0x60, 0xe2, 0x3e, 0x91, 0x00, 0x6b, 0x62, 0xc6, 0x54,
+		 0x3a, 0xb1, 0x34, 0x4d, 0x23, 0xa3, 0x1a, 0xb4, 0xcf, 0x2c ) );
+
+/** SHA-1 Test 5.3 : Retried first call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_5_3, HMAC_DRBG_SHA1,
+	additional_input_empty,
+	EXPECT ( 0x58, 0x7f, 0xd8, 0x21, 0xef, 0x6c, 0x9d, 0xa4, 0xa8, 0x3c,
+		 0x19, 0x21, 0x1f, 0x10, 0x56, 0xca, 0xcd, 0x23, 0xfc, 0x1a ),
+	EXPECT ( 0x84, 0x8f, 0xd1, 0x4c, 0x13, 0xb7, 0xea, 0x93, 0x72, 0x0c,
+		 0xcf, 0xde, 0x71, 0xf2, 0xf6, 0x44, 0x39, 0xdb, 0x79, 0x5d ),
+	EXPECT ( 0xfe, 0xc4, 0x59, 0x7f, 0x06, 0xa3, 0xa8, 0xcc, 0x85, 0x29,
+		 0xd5, 0x95, 0x57, 0xb9, 0xe6, 0x61, 0x05, 0x38, 0x09, 0xc0,
+		 0xbc, 0x0e, 0xfc, 0x28, 0x2a, 0xbd, 0x87, 0x60, 0x5c, 0xc9,
+		 0x0c, 0xba, 0x9b, 0x86, 0x33, 0xdc, 0xb1, 0xda, 0xe0, 0x2e ) );
+
+/** SHA-1 Test 5.4 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_5_4, HMAC_DRBG_SHA1,
+	additional_input_empty, ( 320 / 8 ) );
+
+/** SHA-1 Test 5.5 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha1_reseed_5_5, HMAC_DRBG_SHA1,
+	entropy_input_2, additional_input_empty,
+	EXPECT ( 0xdb, 0xa1, 0xcf, 0xf4, 0x87, 0x95, 0x46, 0xa0, 0x38, 0xa5,
+		 0x59, 0xb2, 0xa2, 0x4d, 0xf2, 0xc0, 0x30, 0x08, 0x9a, 0x41 ),
+	EXPECT ( 0x2f, 0x88, 0x3c, 0x46, 0x48, 0xe1, 0x31, 0xe8, 0x6d, 0xdf,
+		 0x9d, 0xca, 0x0d, 0x74, 0xf3, 0x0c, 0xa1, 0xce, 0x6e, 0xfb ) );
+
+/** SHA-1 Test 5.6 : Retried second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_5_6, HMAC_DRBG_SHA1,
+	additional_input_empty,
+	EXPECT ( 0xf9, 0x39, 0xa5, 0xab, 0x08, 0xa3, 0x9f, 0x23, 0x10, 0x70,
+		 0xb0, 0xd4, 0xc9, 0x6d, 0xc2, 0x37, 0x90, 0xba, 0x01, 0x53 ),
+	EXPECT ( 0xce, 0x6d, 0x08, 0xb4, 0xae, 0x2c, 0xe3, 0x83, 0xfd, 0xab,
+		 0xb0, 0x1e, 0xaa, 0xfc, 0x9c, 0x8e, 0x76, 0xa0, 0xd4, 0x72 ),
+	EXPECT ( 0x84, 0xad, 0xd5, 0xe2, 0xd2, 0x04, 0x1c, 0x01, 0x72, 0x3a,
+		 0x4d, 0xe4, 0x33, 0x5b, 0x13, 0xef, 0xdf, 0x16, 0xb0, 0xe5,
+		 0x1a, 0x0a, 0xd3, 0x9b, 0xd1, 0x5e, 0x86, 0x2e, 0x64, 0x4f,
+		 0x31, 0xe4, 0xa2, 0xd7, 0xd8, 0x43, 0xe5, 0x7c, 0x59, 0x68 ) );
+
+/** SHA-1 Test 6 : Instantiate */
+#define sha1_instantiate_6 sha1_instantiate_1
+
+/** SHA-1 Test 6.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_6_1, HMAC_DRBG_SHA1,
+	additional_input_1, ( 320 / 8 ) );
+
+/** SHA-1 Test 6.2 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha1_reseed_6_2, HMAC_DRBG_SHA1,
+	entropy_input_1, additional_input_1,
+	EXPECT ( 0x52, 0x28, 0xa4, 0xb6, 0xa4, 0x46, 0x92, 0x90, 0x5e, 0xc0,
+		 0x44, 0xbf, 0xf0, 0xbb, 0x4e, 0x25, 0xa3, 0x87, 0xca, 0xc1 ),
+	EXPECT ( 0x24, 0x77, 0x32, 0xd0, 0x4c, 0xb8, 0x4e, 0xd4, 0x1a, 0xdd,
+		 0x95, 0xa4, 0xb7, 0x8b, 0x50, 0xcd, 0x9b, 0x3d, 0x3f, 0x32 ) );
+
+/** SHA-1 Test 6.3 : Retried first call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_6_3, HMAC_DRBG_SHA1,
+	additional_input_empty,
+	EXPECT ( 0xab, 0x3d, 0xd4, 0x89, 0x5b, 0xc8, 0xcd, 0x22, 0x71, 0xde,
+		 0xba, 0x5f, 0x3c, 0x13, 0x63, 0x52, 0x6b, 0x8b, 0x74, 0x52 ),
+	EXPECT ( 0xa8, 0x66, 0xc5, 0xef, 0xf2, 0xaf, 0x04, 0x2b, 0x11, 0x86,
+		 0x44, 0x94, 0x45, 0x23, 0x7f, 0x9c, 0x02, 0x44, 0x98, 0x64 ),
+	EXPECT ( 0xa1, 0xba, 0x8f, 0xa5, 0x8b, 0xb5, 0x01, 0x3f, 0x43, 0xf7,
+		 0xb6, 0xed, 0x52, 0xb4, 0x53, 0x9f, 0xa1, 0x6d, 0xc7, 0x79,
+		 0x57, 0xae, 0xe8, 0x15, 0xb9, 0xc0, 0x70, 0x04, 0xc7, 0xe9,
+		 0x92, 0xeb, 0x8c, 0x7e, 0x59, 0x19, 0x64, 0xaf, 0xee, 0xa2 ) );
+
+/** SHA-1 Test 6.4 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_6_4, HMAC_DRBG_SHA1,
+	additional_input_2, ( 320 / 8 ) );
+
+/** SHA-1 Test 6.5 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha1_reseed_6_5, HMAC_DRBG_SHA1,
+	entropy_input_2, additional_input_2,
+	EXPECT ( 0xe5, 0x73, 0x9f, 0x9c, 0xf7, 0xff, 0x43, 0x84, 0xd1, 0x27,
+		 0x3e, 0x02, 0x6b, 0x45, 0x31, 0x21, 0x36, 0x49, 0x4f, 0x41 ),
+	EXPECT ( 0x30, 0xc3, 0x43, 0x05, 0xc2, 0xc6, 0x48, 0xb0, 0x57, 0xa6,
+		 0x40, 0x22, 0x1b, 0x5c, 0x56, 0x57, 0x26, 0xcd, 0x32, 0xb2 ) );
+
+/** SHA-1 Test 6.6 : Retried second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_6_6, HMAC_DRBG_SHA1,
+	additional_input_empty,
+	EXPECT ( 0x61, 0x91, 0xca, 0x9b, 0xf0, 0x00, 0xd1, 0x0a, 0x71, 0x69,
+		 0x0a, 0xc1, 0x0e, 0x09, 0xff, 0xc8, 0x92, 0xab, 0xde, 0x9a ),
+	EXPECT ( 0x1e, 0xc0, 0x49, 0x0f, 0xa0, 0xb7, 0x65, 0x52, 0x7e, 0x5e,
+		 0xa1, 0x8b, 0x53, 0x22, 0xb2, 0x8b, 0xdd, 0x0e, 0x7b, 0xc0 ),
+	EXPECT ( 0x84, 0x26, 0x4a, 0x73, 0xa8, 0x18, 0xc9, 0x5c, 0x2f, 0x42,
+		 0x4b, 0x37, 0xd3, 0xcc, 0x99, 0x0b, 0x04, 0x6f, 0xb5, 0x0c,
+		 0x2d, 0xc6, 0x4a, 0x16, 0x42, 0x11, 0x88, 0x9a, 0x01, 0x0f,
+		 0x24, 0x71, 0xa0, 0x91, 0x2f, 0xfe, 0xa1, 0xbf, 0x01, 0x95 ) );
+
+/** SHA-1 Test 7 : Instantiation */
+#define sha1_instantiate_7 sha1_instantiate_3
+
+/** SHA-1 Test 7.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_7_1, HMAC_DRBG_SHA1,
+	additional_input_empty, ( 320 / 8 ) );
+
+/** SHA-1 Test 7.2 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha1_reseed_7_2, HMAC_DRBG_SHA1,
+	entropy_input_1, additional_input_empty,
+	EXPECT ( 0xb9, 0x25, 0x4d, 0x8a, 0xac, 0xba, 0x43, 0xfb, 0xda, 0xe6,
+		 0x39, 0x4f, 0x2b, 0x3a, 0xfc, 0x5d, 0x58, 0x08, 0x00, 0xbf ),
+	EXPECT ( 0x28, 0x40, 0x3b, 0x60, 0x36, 0x38, 0xd0, 0x7d, 0x79, 0x66,
+		 0x66, 0x1e, 0xf6, 0x7b, 0x9d, 0x39, 0x05, 0xf4, 0x6d, 0xb9 ) );
+
+/** SHA-1 Test 7.3 : Retried first call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_7_3, HMAC_DRBG_SHA1,
+	additional_input_empty,
+	EXPECT ( 0x64, 0xfe, 0x07, 0x4a, 0x6e, 0x77, 0x97, 0xd1, 0xa4, 0x35,
+		 0xda, 0x89, 0x64, 0x48, 0x4d, 0x6c, 0xf8, 0xbd, 0xc0, 0x1b ),
+	EXPECT ( 0x43, 0xe0, 0xc0, 0x52, 0x15, 0x86, 0xe9, 0x47, 0x3b, 0x06,
+		 0x0d, 0x87, 0xd0, 0x8a, 0x23, 0x25, 0xfa, 0xe1, 0x49, 0xd1 ),
+	EXPECT ( 0x6c, 0x37, 0xfd, 0xd7, 0x29, 0xaa, 0x40, 0xf8, 0x0b, 0xc6,
+		 0xab, 0x08, 0xca, 0x7c, 0xc6, 0x49, 0x79, 0x4f, 0x69, 0x98,
+		 0xb5, 0x70, 0x81, 0xe4, 0x22, 0x0f, 0x22, 0xc5, 0xc2, 0x83,
+		 0xe2, 0xc9, 0x1b, 0x8e, 0x30, 0x5a, 0xb8, 0x69, 0xc6, 0x25 ) );
+
+/** SHA-1 Test 7.4 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_7_4, HMAC_DRBG_SHA1,
+	additional_input_empty, ( 320 / 8 ) );
+
+/** SHA-1 Test 7.5 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha1_reseed_7_5, HMAC_DRBG_SHA1,
+	entropy_input_2, additional_input_empty,
+	EXPECT ( 0x02, 0xbc, 0x57, 0x7f, 0xd1, 0x0e, 0xf7, 0x19, 0x3c, 0x1d,
+		 0xb0, 0x98, 0xbd, 0x5b, 0x75, 0xc7, 0xc4, 0xb6, 0x79, 0x59 ),
+	EXPECT ( 0xbc, 0xbd, 0xf0, 0x52, 0xe0, 0xe0, 0x2a, 0xe8, 0x9a, 0x77,
+		 0x67, 0x94, 0x3f, 0x98, 0x65, 0xb8, 0xb7, 0x22, 0x90, 0x2d ) );
+
+/** SHA-1 Test 7.6 : Retried second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_7_6, HMAC_DRBG_SHA1,
+	additional_input_empty,
+	EXPECT ( 0x1a, 0xa4, 0x24, 0x1c, 0x69, 0x5e, 0x29, 0xc0, 0xa5, 0x9a,
+		 0xd1, 0x8a, 0x60, 0x70, 0xe3, 0x38, 0xa5, 0x48, 0xbe, 0x92 ),
+	EXPECT ( 0x03, 0x47, 0x35, 0x9b, 0xc9, 0xc7, 0xf8, 0x8c, 0xc8, 0x33,
+		 0x0d, 0x4f, 0x59, 0xfb, 0xc7, 0x70, 0xb0, 0xb7, 0x7b, 0x03 ),
+	EXPECT ( 0xca, 0xf5, 0x7d, 0xcf, 0xea, 0x39, 0x3b, 0x92, 0x36, 0xbf,
+		 0x69, 0x1f, 0xa4, 0x56, 0xfe, 0xa7, 0xfd, 0xf1, 0xdf, 0x83,
+		 0x61, 0x48, 0x2c, 0xa5, 0x4d, 0x5f, 0xa7, 0x23, 0xf4, 0xc8,
+		 0x8b, 0x4f, 0xa5, 0x04, 0xbf, 0x03, 0x27, 0x7f, 0xa7, 0x83 ) );
+
+/** SHA-1 Test 8 : Instantiate */
+#define sha1_instantiate_8 sha1_instantiate_3
+
+/** SHA-1 Test 8.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_8_1, HMAC_DRBG_SHA1,
+	additional_input_1, ( 320 / 8 ) );
+
+/** SHA-1 Test 8.2 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha1_reseed_8_2, HMAC_DRBG_SHA1,
+	entropy_input_1, additional_input_1,
+	EXPECT ( 0xc0, 0x95, 0x48, 0xc0, 0xd3, 0xc8, 0x61, 0xd7, 0x40, 0xf2,
+		 0x83, 0x7d, 0x72, 0xb5, 0x07, 0x23, 0x5c, 0x26, 0xdb, 0x82 ),
+	EXPECT ( 0x17, 0x4b, 0x3f, 0x84, 0xc3, 0x53, 0x1f, 0x7c, 0x0a, 0x2e,
+		 0x54, 0x21, 0x23, 0x4e, 0xa1, 0x6b, 0x70, 0x8d, 0xdf, 0x0d ) );
+
+/** SHA-1 Test 8.3 : Retried first call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_8_3, HMAC_DRBG_SHA1,
+	additional_input_empty,
+	EXPECT ( 0x60, 0x3f, 0x09, 0x49, 0x27, 0x9c, 0x70, 0xe8, 0xc6, 0x6c,
+		 0x0f, 0x56, 0x37, 0xc0, 0xf3, 0x75, 0x60, 0x07, 0xe5, 0xac ),
+	EXPECT ( 0xf2, 0xb3, 0x3b, 0x21, 0x15, 0x1f, 0xaf, 0x61, 0x20, 0x01,
+		 0x83, 0x10, 0xf4, 0x4e, 0x4c, 0xd0, 0xbf, 0xe3, 0x68, 0xea ),
+	EXPECT ( 0xbd, 0x07, 0xc2, 0x5c, 0xfd, 0x7c, 0x5e, 0x3a, 0x4e, 0xaa,
+		 0x6e, 0x2e, 0xdc, 0x5a, 0xb7, 0xea, 0x49, 0x42, 0xa0, 0x91,
+		 0x34, 0x71, 0xfd, 0xa5, 0x5c, 0x6d, 0xdd, 0x2c, 0x03, 0xef,
+		 0xa3, 0xb9, 0x64, 0x3a, 0xb3, 0xbb, 0x22, 0xf6, 0xc9, 0xf2 ) );
+
+/** SHA-1 Test 8.4 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_8_4, HMAC_DRBG_SHA1,
+	additional_input_2, ( 320 / 8 ) );
+
+/** SHA-1 Test 8.5 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha1_reseed_8_5, HMAC_DRBG_SHA1,
+	entropy_input_2, additional_input_2,
+	EXPECT ( 0x89, 0x42, 0xa5, 0x4f, 0x34, 0x9e, 0x28, 0x1b, 0x84, 0xaa,
+		 0x46, 0x95, 0x87, 0xfb, 0xdd, 0xaf, 0x9d, 0x11, 0x40, 0x82 ),
+	EXPECT ( 0x07, 0x73, 0x0e, 0x3c, 0xbf, 0xfd, 0x3c, 0xaf, 0xd7, 0xa8,
+		 0xaa, 0xe2, 0xbf, 0x01, 0xd6, 0x01, 0x43, 0x01, 0xe2, 0x4d ) );
+
+/** SHA-1 Test 8.6 : Retried second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha1_generate_8_6, HMAC_DRBG_SHA1,
+	additional_input_empty,
+	EXPECT ( 0xbd, 0xe1, 0xb4, 0x6c, 0xdc, 0x54, 0x13, 0xb3, 0xd9, 0xf7,
+		 0x35, 0xac, 0xdb, 0x80, 0xb1, 0x3c, 0x57, 0xbf, 0xe4, 0x73 ),
+	EXPECT ( 0x72, 0x5a, 0x3c, 0x78, 0x20, 0xde, 0x1a, 0x06, 0xd0, 0x95,
+		 0x81, 0x9c, 0xcf, 0x6f, 0x2c, 0x9b, 0x3a, 0x67, 0xf2, 0xce ),
+	EXPECT ( 0xd1, 0xa9, 0xc1, 0xa2, 0x2c, 0x84, 0xfc, 0x23, 0xff, 0x22,
+		 0x27, 0xef, 0x98, 0xec, 0x8b, 0xa9, 0xdf, 0x2a, 0x20, 0x9b,
+		 0xa1, 0xdb, 0x09, 0x80, 0x9f, 0x57, 0xbf, 0xea, 0xe5, 0xb3,
+		 0xe5, 0xf1, 0x46, 0xc7, 0x5f, 0x2d, 0x8d, 0xbb, 0x5e, 0x4a ) );
+
+/** SHA-256 Test 1 : Instantiation */
+HMAC_DRBG_TEST_INSTANTIATE ( sha256_instantiate_1, HMAC_DRBG_SHA256,
+	entropy_input, nonce_sha256, personalisation_string_empty,
+	EXPECT ( 0x3d, 0xda, 0x54, 0x3e, 0x7e, 0xef, 0x14, 0xf9, 0x36, 0x23,
+		 0x7b, 0xe6, 0x5d, 0x09, 0x4b, 0x4d, 0xdc, 0x96, 0x9c, 0x0b,
+		 0x2b, 0x5e, 0xaf, 0xb5, 0xd8, 0x05, 0xe8, 0x6c, 0xfa, 0x64,
+		 0xd7, 0x41 ),
+	EXPECT ( 0x2d, 0x02, 0xc2, 0xf8, 0x22, 0x51, 0x7d, 0x54, 0xb8, 0x17,
+		 0x27, 0x9a, 0x59, 0x49, 0x1c, 0x41, 0xa1, 0x98, 0x9b, 0x3e,
+		 0x38, 0x2d, 0xeb, 0xe8, 0x0d, 0x2c, 0x7f, 0x66, 0x0f, 0x44,
+		 0x76, 0xc4 ) );
+
+/** SHA-256 Test 1.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_1_1, HMAC_DRBG_SHA256,
+	additional_input_empty,
+	EXPECT ( 0xdd, 0x30, 0x95, 0x79, 0x35, 0x38, 0x02, 0xcc, 0xdd, 0x43,
+		 0x99, 0xc3, 0x69, 0x1c, 0x9d, 0xd9, 0x09, 0xdd, 0x3b, 0x2d,
+		 0xd0, 0x03, 0xcc, 0xd5, 0x9d, 0x6f, 0x08, 0xd8, 0x5f, 0x2e,
+		 0x35, 0x09 ),
+	EXPECT ( 0xa1, 0xc2, 0x0f, 0xf2, 0x70, 0xa3, 0x9d, 0x2b, 0x8d, 0x03,
+		 0xd6, 0x59, 0xb9, 0xdd, 0xd0, 0x11, 0xc2, 0xcc, 0xdf, 0x24,
+		 0x48, 0x55, 0x7e, 0xf6, 0xa1, 0xa9, 0x15, 0xd1, 0x89, 0x40,
+		 0xa6, 0x88 ),
+	EXPECT ( 0xd6, 0x7b, 0x8c, 0x17, 0x34, 0xf4, 0x6f, 0xa3, 0xf7, 0x63,
+		 0xcf, 0x57, 0xc6, 0xf9, 0xf4, 0xf2, 0xdc, 0x10, 0x89, 0xbd,
+		 0x8b, 0xc1, 0xf6, 0xf0, 0x23, 0x95, 0x0b, 0xfc, 0x56, 0x17,
+		 0x63, 0x52, 0x08, 0xc8, 0x50, 0x12, 0x38, 0xad, 0x7a, 0x44,
+		 0x00, 0xde, 0xfe, 0xe4, 0x6c, 0x64, 0x0b, 0x61, 0xaf, 0x77,
+		 0xc2, 0xd1, 0xa3, 0xbf, 0xaa, 0x90, 0xed, 0xe5, 0xd2, 0x07,
+		 0x40, 0x6e, 0x54, 0x03 ) );
+
+/** SHA-256 Test 1.2 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_1_2, HMAC_DRBG_SHA256,
+	additional_input_empty,
+	EXPECT ( 0x5c, 0xd5, 0xe5, 0x0a, 0x3e, 0x44, 0x8a, 0x07, 0xc3, 0xd2,
+		 0xf2, 0xa3, 0xf9, 0xde, 0xbc, 0xc0, 0x46, 0x5f, 0x9c, 0xf1,
+		 0x1c, 0xa1, 0x36, 0xe9, 0xb5, 0x04, 0xb4, 0xd3, 0x1c, 0x7f,
+		 0xf1, 0xb8 ),
+	EXPECT ( 0x33, 0xb3, 0x09, 0xf2, 0xff, 0x01, 0xce, 0x10, 0x4b, 0x44,
+		 0x29, 0xb6, 0x75, 0xfa, 0xfa, 0x19, 0x01, 0x1e, 0x34, 0x8b,
+		 0x28, 0x12, 0x71, 0x5a, 0x76, 0x37, 0xf6, 0xa6, 0xe6, 0x3b,
+		 0x5d, 0x57 ),
+	EXPECT ( 0x8f, 0xda, 0xec, 0x20, 0xf8, 0xb4, 0x21, 0x40, 0x70, 0x59,
+		 0xe3, 0x58, 0x89, 0x20, 0xda, 0x7e, 0xda, 0x9d, 0xce, 0x3c,
+		 0xf8, 0x27, 0x4d, 0xfa, 0x1c, 0x59, 0xc1, 0x08, 0xc1, 0xd0,
+		 0xaa, 0x9b, 0x0f, 0xa3, 0x8d, 0xa5, 0xc7, 0x92, 0x03, 0x7c,
+		 0x4d, 0x33, 0xcd, 0x07, 0x0c, 0xa7, 0xcd, 0x0c, 0x56, 0x08,
+		 0xdb, 0xa8, 0xb8, 0x85, 0x65, 0x46, 0x39, 0xde, 0x21, 0x87,
+		 0xb7, 0x4c, 0xb2, 0x63 ) );
+
+/** SHA-256 Test 2 : Instantiation */
+#define sha256_instantiate_2 sha256_instantiate_1
+
+/** SHA-256 Test 2.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_2_1, HMAC_DRBG_SHA256,
+	additional_input_1,
+	EXPECT ( 0x79, 0x1d, 0x31, 0x44, 0xb3, 0x02, 0xad, 0x6c, 0xe4, 0x32,
+		 0x41, 0x34, 0x42, 0x10, 0xaa, 0xd0, 0xd3, 0x99, 0xed, 0xb7,
+		 0xb5, 0x90, 0x6f, 0xb2, 0x51, 0xdb, 0x1c, 0xb6, 0x00, 0x04,
+		 0xea, 0x51 ),
+	EXPECT ( 0x58, 0xfd, 0x96, 0x5f, 0x4f, 0x99, 0x89, 0x3c, 0x17, 0xe6,
+		 0xa3, 0x3c, 0xb8, 0xe9, 0x04, 0x15, 0xb5, 0x16, 0xd0, 0x06,
+		 0x14, 0xa4, 0x49, 0xd4, 0x06, 0xe0, 0x3c, 0x68, 0x5b, 0xd8,
+		 0x59, 0xbd ),
+	EXPECT ( 0x41, 0x87, 0x87, 0x35, 0x81, 0x35, 0x41, 0x9b, 0x93, 0x81,
+		 0x33, 0x53, 0x53, 0x06, 0x17, 0x6a, 0xfb, 0x25, 0x1c, 0xdd,
+		 0x2b, 0xa3, 0x79, 0x88, 0x59, 0xb5, 0x66, 0xa0, 0x5c, 0xfb,
+		 0x1d, 0x68, 0x0e, 0xa9, 0x25, 0x85, 0x6d, 0x5b, 0x84, 0xd5,
+		 0x6a, 0xda, 0xe8, 0x70, 0x45, 0xa6, 0xba, 0x28, 0xd2, 0xc9,
+		 0x08, 0xab, 0x75, 0xb7, 0xcc, 0x41, 0x43, 0x1f, 0xac, 0x59,
+		 0xf3, 0x89, 0x18, 0xa3 ) );
+
+/** SHA-256 Test 2.2 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_2_2, HMAC_DRBG_SHA256,
+	additional_input_2,
+	EXPECT ( 0xe7, 0x45, 0x8f, 0xb4, 0x4a, 0x36, 0x9a, 0x65, 0x3f, 0x2f,
+		 0x8f, 0x57, 0x7b, 0xf9, 0x75, 0xc4, 0xb3, 0x62, 0xc4, 0xfe,
+		 0x61, 0x8b, 0x2f, 0x1f, 0xf6, 0x76, 0x9b, 0x13, 0xc9, 0x4d,
+		 0xec, 0xf4 ),
+	EXPECT ( 0x19, 0x33, 0x4b, 0x8c, 0x31, 0xb7, 0x49, 0x32, 0xdd, 0xd7,
+		 0xb2, 0xa4, 0x68, 0xf6, 0x43, 0x6d, 0xf9, 0x2e, 0x10, 0x0d,
+		 0x39, 0xd3, 0xac, 0xb3, 0x68, 0xc7, 0x02, 0x9c, 0xb8, 0x83,
+		 0xec, 0x89 ),
+	EXPECT ( 0x7c, 0x06, 0x7b, 0xdd, 0xca, 0x81, 0x72, 0x48, 0x23, 0xd6,
+		 0x4c, 0x69, 0x82, 0x92, 0x85, 0xbd, 0xbf, 0xf5, 0x37, 0x71,
+		 0x61, 0x02, 0xc1, 0x88, 0x2e, 0x20, 0x22, 0x50, 0xe0, 0xfa,
+		 0x5e, 0xf3, 0xa3, 0x84, 0xcd, 0x34, 0xa2, 0x0f, 0xfd, 0x1f,
+		 0xbc, 0x91, 0xe0, 0xc5, 0x32, 0xa8, 0xa4, 0x21, 0xbc, 0x4a,
+		 0xfe, 0x3c, 0xd4, 0x7f, 0x22, 0x32, 0x3e, 0xb4, 0xba, 0xe1,
+		 0xa0, 0x07, 0x89, 0x81 ) );
+
+/** SHA-256 Test 3 : Instantiation */
+HMAC_DRBG_TEST_INSTANTIATE ( sha256_instantiate_3, HMAC_DRBG_SHA256,
+	entropy_input, nonce_sha256, personalisation_string,
+	EXPECT ( 0x65, 0x67, 0x3c, 0x34, 0x8e, 0x51, 0xcf, 0xac, 0xc4, 0x10,
+		 0xbd, 0x20, 0x02, 0x49, 0xa5, 0x9a, 0x9d, 0x6b, 0xae, 0x77,
+		 0x69, 0x04, 0x27, 0x1b, 0xb1, 0xf7, 0x18, 0xda, 0x1d, 0x18,
+		 0x20, 0x42 ),
+	EXPECT ( 0xe0, 0xf9, 0x1a, 0xc9, 0x96, 0x30, 0xee, 0xe6, 0x7c, 0xf8,
+		 0x30, 0xcf, 0xd5, 0x04, 0x4f, 0xeb, 0xf5, 0x5c, 0x0c, 0x11,
+		 0x50, 0x07, 0x99, 0x7a, 0xda, 0x11, 0x29, 0x6f, 0xc4, 0x16,
+		 0x4a, 0x9a ) );
+
+/** SHA-256 Test 3.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_3_1, HMAC_DRBG_SHA256,
+	additional_input_empty,
+	EXPECT ( 0xf0, 0xb2, 0xf2, 0x42, 0xca, 0xd9, 0x92, 0xa7, 0x24, 0xf7,
+		 0xe5, 0x59, 0x1d, 0x2f, 0x3b, 0x0c, 0x21, 0x57, 0xae, 0x70,
+		 0xd5, 0x32, 0x78, 0x99, 0x40, 0xf1, 0x64, 0x45, 0x9b, 0x00,
+		 0xc7, 0x49 ),
+	EXPECT ( 0x1a, 0x03, 0xf9, 0x1c, 0x51, 0x20, 0xba, 0xca, 0x2b, 0xf6,
+		 0xc6, 0x4d, 0xd7, 0x3a, 0xb1, 0x1d, 0xf6, 0xfd, 0x3f, 0xf1,
+		 0xac, 0x3b, 0x57, 0x20, 0xa3, 0xf7, 0xfb, 0xe3, 0x9e, 0x7e,
+		 0x7f, 0xe9 ),
+	EXPECT ( 0x0d, 0xd9, 0xc8, 0x55, 0x89, 0xf3, 0x57, 0xc3, 0x89, 0xd6,
+		 0xaf, 0x8d, 0xe9, 0xd7, 0x34, 0xa9, 0x17, 0xc7, 0x71, 0xef,
+		 0x2d, 0x88, 0x16, 0xb9, 0x82, 0x59, 0x6e, 0xd1, 0x2d, 0xb4,
+		 0x5d, 0x73, 0x4a, 0x62, 0x68, 0x08, 0x35, 0xc0, 0x2f, 0xda,
+		 0x66, 0xb0, 0x8e, 0x1a, 0x36, 0x9a, 0xe2, 0x18, 0xf2, 0x6d,
+		 0x52, 0x10, 0xad, 0x56, 0x42, 0x48, 0x87, 0x2d, 0x7a, 0x28,
+		 0x78, 0x41, 0x59, 0xc3 ) );
+
+/** SHA-256 Test 3.2 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_3_2, HMAC_DRBG_SHA256,
+	additional_input_empty,
+	EXPECT ( 0x5c, 0x0d, 0xec, 0x09, 0x37, 0x08, 0xc1, 0x7c, 0xa7, 0x6b,
+		 0x57, 0xc0, 0xcb, 0x60, 0xcf, 0x88, 0x9d, 0xcc, 0x47, 0xad,
+		 0x10, 0xbd, 0x64, 0xbc, 0x6a, 0x14, 0xb2, 0x3f, 0x20, 0x26,
+		 0x07, 0x8a ),
+	EXPECT ( 0x45, 0x67, 0x52, 0xa5, 0x11, 0xb8, 0x48, 0xbd, 0x05, 0xf1,
+		 0x81, 0x9b, 0x9f, 0x6b, 0x15, 0x42, 0xc7, 0xd5, 0xec, 0xf9,
+		 0x32, 0x73, 0x39, 0x26, 0x7a, 0x0c, 0x77, 0x23, 0x5b, 0x87,
+		 0xdc, 0x5a ),
+	EXPECT ( 0x46, 0xb4, 0xf4, 0x75, 0x6a, 0xe7, 0x15, 0xe0, 0xe5, 0x16,
+		 0x81, 0xab, 0x29, 0x32, 0xde, 0x15, 0x23, 0xbe, 0x5d, 0x13,
+		 0xba, 0xf0, 0xf4, 0x58, 0x8b, 0x11, 0xfe, 0x37, 0x2f, 0xda,
+		 0x37, 0xab, 0xe3, 0x68, 0x31, 0x73, 0x41, 0xbc, 0x8b, 0xa9,
+		 0x1f, 0xc5, 0xd8, 0x5b, 0x7f, 0xb8, 0xca, 0x8f, 0xbc, 0x30,
+		 0x9a, 0x75, 0x8f, 0xd6, 0xfc, 0xa9, 0xdf, 0x43, 0xc7, 0x66,
+		 0x0b, 0x22, 0x13, 0x22 ) );
+
+/** SHA-256 Test 4 : Instantiation */
+#define sha256_instantiate_4 sha256_instantiate_3
+
+/** SHA-256 Test 4.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_4_1, HMAC_DRBG_SHA256,
+	additional_input_1,
+	EXPECT ( 0x57, 0x2c, 0x03, 0x74, 0xc1, 0xa1, 0x01, 0x25, 0xbf, 0xa6,
+		 0xae, 0xcd, 0x7c, 0xeb, 0xfe, 0x32, 0xf7, 0x52, 0xc3, 0xfb,
+		 0x31, 0x67, 0x31, 0xb7, 0xcf, 0xdb, 0xde, 0xc2, 0x63, 0x56,
+		 0x93, 0x2b ),
+	EXPECT ( 0xd6, 0x8b, 0xf0, 0x41, 0xf3, 0xeb, 0x50, 0x88, 0x08, 0x8d,
+		 0x8b, 0x8e, 0x71, 0x2c, 0x36, 0xae, 0x95, 0x83, 0xbb, 0x08,
+		 0xfd, 0x1f, 0x90, 0x34, 0xa4, 0xe9, 0x42, 0xe9, 0xa6, 0x74,
+		 0x7c, 0xe7 ),
+	EXPECT ( 0x14, 0x78, 0xf2, 0x9e, 0x94, 0xb0, 0x2c, 0xb4, 0x0d, 0x3a,
+		 0xab, 0x86, 0x24, 0x55, 0x57, 0xce, 0x13, 0xa8, 0xca, 0x2f,
+		 0xdb, 0x65, 0x7d, 0x98, 0xef, 0xc1, 0x92, 0x34, 0x6b, 0x9f,
+		 0xac, 0x33, 0xea, 0x58, 0xad, 0xa2, 0xcc, 0xa4, 0x32, 0xcc,
+		 0xde, 0xfb, 0xcd, 0xaa, 0x8b, 0x82, 0xf5, 0x53, 0xef, 0x96,
+		 0x61, 0x34, 0xe2, 0xcd, 0x13, 0x9f, 0x15, 0xf0, 0x1c, 0xad,
+		 0x56, 0x85, 0x65, 0xa8 ) );
+
+/** SHA-256 Test 4.2 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_4_2, HMAC_DRBG_SHA256,
+	additional_input_2,
+	EXPECT ( 0x28, 0x2e, 0x07, 0x34, 0x80, 0x80, 0x93, 0x75, 0x58, 0xb1,
+		 0x39, 0x2e, 0x95, 0xab, 0x91, 0xe7, 0xc1, 0xf6, 0x22, 0xb2,
+		 0x4f, 0xfb, 0x87, 0x20, 0xa5, 0xf0, 0xa5, 0xe0, 0x75, 0x50,
+		 0xc7, 0xc2 ),
+	EXPECT ( 0xdf, 0xc3, 0xbd, 0xb5, 0xf3, 0xbc, 0xf1, 0xaa, 0x68, 0x29,
+		 0x8e, 0x79, 0x0d, 0x72, 0x0a, 0x67, 0xa7, 0x6e, 0x31, 0xb9,
+		 0x2b, 0x9b, 0x35, 0xa8, 0xe5, 0x47, 0x1b, 0xb1, 0x7e, 0x30,
+		 0x3c, 0x6b ),
+	EXPECT ( 0x49, 0x7c, 0x7a, 0x16, 0xe8, 0x8a, 0x64, 0x11, 0xf8, 0xfc,
+		 0xe1, 0x0e, 0xf5, 0x67, 0x63, 0xc6, 0x10, 0x25, 0x80, 0x1d,
+		 0x8f, 0x51, 0xa7, 0x43, 0x52, 0xd6, 0x82, 0xcc, 0x23, 0xa0,
+		 0xa8, 0xe6, 0x73, 0xca, 0xe0, 0x32, 0x28, 0x93, 0x90, 0x64,
+		 0x7d, 0xc6, 0x83, 0xb7, 0x34, 0x28, 0x85, 0xd6, 0xb7, 0x6a,
+		 0xb1, 0xda, 0x69, 0x6d, 0x3e, 0x97, 0xe2, 0x2d, 0xff, 0xdd,
+		 0xff, 0xfd, 0x8d, 0xf0 ) );
+
+/** SHA-256 Test 5 : Instantiation */
+#define sha256_instantiate_5 sha256_instantiate_1
+
+/** SHA-256 Test 5.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_5_1, HMAC_DRBG_SHA256,
+	additional_input_empty, ( 512 / 8 ) );
+
+/** SHA-256 Test 5.2 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha256_reseed_5_2, HMAC_DRBG_SHA256,
+	entropy_input_1, additional_input_empty,
+	EXPECT ( 0xb8, 0x40, 0x07, 0xe3, 0xe2, 0x7f, 0x34, 0xf9, 0xa7, 0x82,
+		 0x0b, 0x7a, 0xb5, 0x9b, 0xbe, 0xfc, 0xd0, 0xc4, 0xac, 0xae,
+		 0xde, 0x4b, 0x0b, 0x36, 0xb1, 0x47, 0xb8, 0x97, 0x79, 0xfd,
+		 0x74, 0x9d ),
+	EXPECT ( 0xa7, 0x2b, 0x8f, 0xee, 0x92, 0x39, 0x2f, 0x0a, 0x9d, 0x2d,
+		 0x61, 0xbf, 0x09, 0xa4, 0xdf, 0xcc, 0x9d, 0xe6, 0x9a, 0x16,
+		 0xa5, 0xf1, 0x50, 0x22, 0x4c, 0x3e, 0xf6, 0x04, 0x2d, 0x15,
+		 0x21, 0xfc ) );
+
+/** SHA-256 Test 5.3 : Retried first call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_5_3, HMAC_DRBG_SHA256,
+	additional_input_empty,
+	EXPECT ( 0x43, 0x48, 0xaf, 0x84, 0x20, 0x84, 0x2f, 0xa0, 0x77, 0xb9,
+		 0xd3, 0xdb, 0xa8, 0xdc, 0xe9, 0xb3, 0xe1, 0xdf, 0x73, 0x4f,
+		 0xfc, 0xe1, 0xbe, 0xa5, 0xb9, 0xe2, 0xb1, 0x54, 0xdc, 0x5e,
+		 0xc6, 0x15 ),
+	EXPECT ( 0xd2, 0xc1, 0xac, 0x27, 0x88, 0x5d, 0x43, 0x32, 0x76, 0x71,
+		 0x31, 0x46, 0x32, 0xea, 0x60, 0x43, 0x3c, 0xca, 0x72, 0x73,
+		 0x04, 0x56, 0x9e, 0xa7, 0xd4, 0x71, 0xfe, 0xa7, 0xdb, 0x7d,
+		 0x31, 0x5d ),
+	EXPECT ( 0xfa, 0xbd, 0x0a, 0xe2, 0x5c, 0x69, 0xdc, 0x2e, 0xfd, 0xef,
+		 0xb7, 0xf2, 0x0c, 0x5a, 0x31, 0xb5, 0x7a, 0xc9, 0x38, 0xab,
+		 0x77, 0x1a, 0xa1, 0x9b, 0xf8, 0xf5, 0xf1, 0x46, 0x8f, 0x66,
+		 0x5c, 0x93, 0x8c, 0x9a, 0x1a, 0x5d, 0xf0, 0x62, 0x8a, 0x56,
+		 0x90, 0xf1, 0x5a, 0x1a, 0xd8, 0xa6, 0x13, 0xf3, 0x1b, 0xbd,
+		 0x65, 0xee, 0xad, 0x54, 0x57, 0xd5, 0xd2, 0x69, 0x47, 0xf2,
+		 0x9f, 0xe9, 0x1a, 0xa7 ) );
+
+/** SHA-256 Test 5.4 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_5_4, HMAC_DRBG_SHA256,
+	additional_input_empty, ( 512 / 8 ) );
+
+/** SHA-256 Test 5.5 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha256_reseed_5_5, HMAC_DRBG_SHA256,
+	entropy_input_2, additional_input_empty,
+	EXPECT ( 0xbf, 0xa0, 0x2c, 0xe7, 0xe9, 0x2d, 0xe9, 0x2b, 0x18, 0x24,
+		 0x28, 0x86, 0x89, 0x0e, 0x58, 0x6f, 0x83, 0x69, 0x06, 0xac,
+		 0xe9, 0xe5, 0x54, 0xf1, 0xb0, 0xed, 0x63, 0x57, 0x3c, 0xb8,
+		 0xb5, 0x03 ),
+	EXPECT ( 0xd3, 0x24, 0x03, 0xee, 0xa9, 0xdc, 0xe1, 0x61, 0x6e, 0x4e,
+		 0x11, 0x55, 0xb9, 0x23, 0xd8, 0x84, 0x2c, 0xc6, 0xe7, 0x84,
+		 0xc6, 0x7a, 0x93, 0x85, 0xb2, 0xa6, 0x37, 0xf1, 0x02, 0xfa,
+		 0x45, 0xd5 ) );
+
+/** SHA-256 Test 5.6 : Retried second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_5_6, HMAC_DRBG_SHA256,
+	additional_input_empty,
+	EXPECT ( 0x81, 0x21, 0xf7, 0x76, 0x4c, 0x08, 0x1e, 0xe9, 0xd1, 0x17,
+		 0x1e, 0xd1, 0x87, 0xba, 0xe0, 0x88, 0x95, 0xca, 0xe2, 0x30,
+		 0xd0, 0xa2, 0x5e, 0x37, 0x39, 0xc5, 0x7d, 0x54, 0x16, 0x10,
+		 0x9b, 0x82 ),
+	EXPECT ( 0x37, 0x84, 0x97, 0x7c, 0xc0, 0xe5, 0x9f, 0xbc, 0x9c, 0xda,
+		 0x4e, 0x11, 0x92, 0x47, 0x5c, 0x6e, 0xfa, 0xf8, 0x07, 0x20,
+		 0x19, 0x86, 0x21, 0x22, 0xcb, 0x6b, 0xce, 0xaa, 0xcc, 0x4a,
+		 0x17, 0x5e ),
+	EXPECT ( 0x6b, 0xd9, 0x25, 0xb0, 0xe1, 0xc2, 0x32, 0xef, 0xd6, 0x7c,
+		 0xcd, 0x84, 0xf7, 0x22, 0xe9, 0x27, 0xec, 0xb4, 0x6a, 0xb2,
+		 0xb7, 0x40, 0x01, 0x47, 0x77, 0xaf, 0x14, 0xba, 0x0b, 0xbf,
+		 0x53, 0xa4, 0x5b, 0xdb, 0xb6, 0x2b, 0x3f, 0x7d, 0x0b, 0x9c,
+		 0x8e, 0xea, 0xd0, 0x57, 0xc0, 0xec, 0x75, 0x4e, 0xf8, 0xb5,
+		 0x3e, 0x60, 0xa1, 0xf4, 0x34, 0xf0, 0x59, 0x46, 0xa8, 0xb6,
+		 0x86, 0xaf, 0xbc, 0x7a ) );
+
+/** SHA-256 Test 6 : Instantiate */
+#define sha256_instantiate_6 sha256_instantiate_1
+
+/** SHA-256 Test 6.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_6_1, HMAC_DRBG_SHA256,
+	additional_input_1, ( 512 / 8 ) );
+
+/** SHA-256 Test 6.2 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha256_reseed_6_2, HMAC_DRBG_SHA256,
+	entropy_input_1, additional_input_1,
+	EXPECT ( 0xc1, 0x25, 0xea, 0x99, 0x75, 0x8e, 0xbb, 0x9a, 0x6f, 0x69,
+		 0xae, 0x31, 0x2a, 0xc2, 0x04, 0xb5, 0x94, 0xc0, 0x0a, 0xb6,
+		 0x8b, 0x81, 0x6e, 0x3a, 0x52, 0x12, 0x8e, 0x02, 0x78, 0xa5,
+		 0x84, 0xac ),
+	EXPECT ( 0xb2, 0xcb, 0x2b, 0x89, 0x12, 0x3f, 0x5b, 0x4a, 0xf5, 0x87,
+		 0xb8, 0xf6, 0xbd, 0xc5, 0x42, 0x7a, 0x99, 0x14, 0x19, 0xd3,
+		 0x53, 0x07, 0x7c, 0x68, 0x5e, 0x70, 0x7a, 0xcd, 0xf8, 0xe9,
+		 0xfd, 0xa9 ) );
+
+/** SHA-256 Test 6.3 : Retried first call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_6_3, HMAC_DRBG_SHA256,
+	additional_input_empty,
+	EXPECT ( 0xc6, 0xed, 0x8f, 0xed, 0x71, 0x57, 0xa4, 0xd0, 0x9e, 0xa1,
+		 0xdd, 0xe8, 0x94, 0x6b, 0x54, 0x43, 0x3e, 0xcc, 0x54, 0x49,
+		 0xa4, 0xa3, 0x52, 0xaf, 0x45, 0x76, 0x4e, 0xe6, 0x73, 0x4b,
+		 0xbb, 0x04 ),
+	EXPECT ( 0xeb, 0xc7, 0x75, 0x25, 0x6b, 0xb7, 0x81, 0x24, 0x1e, 0x9c,
+		 0x70, 0xbb, 0xcf, 0x73, 0x2b, 0xdc, 0x90, 0xad, 0x10, 0xd9,
+		 0xdd, 0x3a, 0x89, 0x6e, 0xcc, 0x12, 0xb9, 0x2f, 0xfb, 0x63,
+		 0x45, 0xab ),
+	EXPECT ( 0x08, 0x5d, 0x57, 0xaf, 0x6b, 0xab, 0xcf, 0x2b, 0x9a, 0xee,
+		 0xf3, 0x87, 0xd5, 0x31, 0x65, 0x0e, 0x6a, 0x50, 0x5c, 0x54,
+		 0x40, 0x6a, 0xb3, 0x7a, 0x52, 0x89, 0x9e, 0x0e, 0xca, 0xb3,
+		 0x63, 0x2b, 0x7a, 0x06, 0x8a, 0x28, 0x14, 0xc6, 0xdf, 0x6a,
+		 0xe5, 0x32, 0xb6, 0x58, 0xd0, 0xd9, 0x74, 0x1c, 0x84, 0x77,
+		 0x5f, 0xee, 0x45, 0xb6, 0x84, 0xcd, 0xbd, 0xc2, 0x5f, 0xbc,
+		 0xb4, 0xd8, 0xf3, 0x10 ) );
+
+/** SHA-256 Test 6.4 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_6_4, HMAC_DRBG_SHA256,
+	additional_input_2, ( 512 / 8 ) );
+
+/** SHA-256 Test 6.5 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha256_reseed_6_5, HMAC_DRBG_SHA256,
+	entropy_input_2, additional_input_2,
+	EXPECT ( 0xfc, 0x51, 0xda, 0x84, 0xf9, 0x69, 0x6b, 0xcc, 0x84, 0xc8,
+		 0xf2, 0xac, 0xb9, 0x24, 0xbc, 0xdf, 0x72, 0xf8, 0x2e, 0xa2,
+		 0xca, 0x64, 0x3f, 0x08, 0x3b, 0x0c, 0x16, 0xc3, 0x63, 0x4e,
+		 0xfc, 0x62 ),
+	EXPECT ( 0xb9, 0x74, 0xe4, 0x37, 0x0a, 0xd5, 0x76, 0xbb, 0x99, 0xc4,
+		 0xe4, 0x9e, 0xa6, 0x80, 0xbf, 0xf9, 0x8d, 0xe9, 0xe1, 0x2f,
+		 0xec, 0xd0, 0x13, 0xde, 0xd4, 0x3c, 0x80, 0xf6, 0x9a, 0x7a,
+		 0xde, 0x8a ) );
+
+/** SHA-256 Test 6.6 : Retried second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_6_6, HMAC_DRBG_SHA256,
+	additional_input_empty,
+	EXPECT ( 0x56, 0xa2, 0xb4, 0x46, 0x32, 0xcb, 0x8f, 0xc3, 0xa6, 0x40,
+		 0x09, 0xbf, 0xd6, 0xec, 0x95, 0xe5, 0x6c, 0xef, 0x8e, 0x7c,
+		 0x91, 0x2a, 0xa8, 0x2b, 0x16, 0xf6, 0x14, 0x91, 0x5d, 0x9c,
+		 0xd6, 0xe3 ),
+	EXPECT ( 0xb5, 0xb3, 0x96, 0xa0, 0x15, 0x76, 0xb0, 0xfe, 0x42, 0xf4,
+		 0x08, 0x44, 0x55, 0x6c, 0x4c, 0xf4, 0xb6, 0x80, 0x4c, 0x94,
+		 0xde, 0x9d, 0x62, 0x38, 0xf1, 0xf7, 0xe7, 0xaf, 0x5c, 0x72,
+		 0x57, 0xf3 ),
+	EXPECT ( 0x9b, 0x21, 0x9f, 0xd9, 0x0d, 0xe2, 0xa0, 0x8e, 0x49, 0x34,
+		 0x05, 0xcf, 0x87, 0x44, 0x17, 0xb5, 0x82, 0x67, 0x70, 0xf3,
+		 0x94, 0x48, 0x15, 0x55, 0xdc, 0x66, 0x8a, 0xcd, 0x96, 0xb9,
+		 0xa3, 0xe5, 0x6f, 0x9d, 0x2c, 0x32, 0x5e, 0x26, 0xd4, 0x7c,
+		 0x1d, 0xfc, 0xfc, 0x8f, 0xbf, 0x86, 0x12, 0x6f, 0x40, 0xa1,
+		 0xe6, 0x39, 0x60, 0xf6, 0x27, 0x49, 0x34, 0x2e, 0xcd, 0xb7,
+		 0x1b, 0x24, 0x0d, 0xc6 ) );
+
+/** SHA-256 Test 7 : Instantiation */
+#define sha256_instantiate_7 sha256_instantiate_3
+
+/** SHA-256 Test 7.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_7_1, HMAC_DRBG_SHA256,
+	additional_input_empty, ( 512 / 8 ) );
+
+/** SHA-256 Test 7.2 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha256_reseed_7_2, HMAC_DRBG_SHA256,
+	entropy_input_1, additional_input_empty,
+	EXPECT ( 0x44, 0x76, 0xc6, 0xd1, 0x1f, 0xc3, 0x5d, 0x44, 0x09, 0xd9,
+		 0x03, 0x2e, 0x45, 0x3b, 0x0f, 0x0d, 0xc3, 0x31, 0x4d, 0xb8,
+		 0x62, 0xcb, 0xdb, 0x60, 0x9c, 0x56, 0x02, 0x20, 0x8d, 0x4c,
+		 0x88, 0xd8 ),
+	EXPECT ( 0x95, 0xef, 0x78, 0x5a, 0x61, 0xc2, 0xf7, 0xb3, 0x6b, 0xc5,
+		 0x96, 0xba, 0x4b, 0xa2, 0x08, 0xa5, 0x2c, 0x6d, 0xc2, 0x03,
+		 0x63, 0x6d, 0x8f, 0x17, 0x87, 0x45, 0x3b, 0x85, 0x2b, 0x7e,
+		 0x49, 0xec ) );
+
+/** SHA-256 Test 7.3 : Retried first call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_7_3, HMAC_DRBG_SHA256,
+	additional_input_empty,
+	EXPECT ( 0x0d, 0xf9, 0x11, 0x0e, 0x2f, 0x22, 0x58, 0x98, 0x24, 0xa9,
+		 0x47, 0x6c, 0x8e, 0x32, 0x08, 0x8e, 0x51, 0xa0, 0xda, 0x36,
+		 0x63, 0x3f, 0x8c, 0xd1, 0xf7, 0x54, 0x7d, 0xff, 0x69, 0x6e,
+		 0x4b, 0x29 ),
+	EXPECT ( 0xc0, 0xe3, 0xc8, 0xed, 0x5a, 0x8b, 0x57, 0x9e, 0x3f, 0xef,
+		 0x9d, 0xf3, 0xb7, 0xc2, 0xc2, 0x12, 0x98, 0x07, 0x17, 0xcc,
+		 0x91, 0xae, 0x18, 0x66, 0x45, 0xfa, 0xbb, 0x2c, 0xc7, 0x84,
+		 0xd5, 0xd7 ),
+	EXPECT ( 0xd8, 0xb6, 0x71, 0x30, 0x71, 0x41, 0x94, 0xff, 0xe5, 0xb2,
+		 0xa3, 0x5d, 0xbc, 0xd5, 0xe1, 0xa2, 0x99, 0x42, 0xad, 0x5c,
+		 0x68, 0xf3, 0xde, 0xb9, 0x4a, 0xdd, 0x9e, 0x9e, 0xba, 0xd8,
+		 0x60, 0x67, 0xed, 0xf0, 0x49, 0x15, 0xfb, 0x40, 0xc3, 0x91,
+		 0xea, 0xe7, 0x0c, 0x65, 0x9e, 0xaa, 0xe7, 0xef, 0x11, 0xa3,
+		 0xd4, 0x6a, 0x5b, 0x08, 0x5e, 0xdd, 0x90, 0xcc, 0x72, 0xce,
+		 0xa9, 0x89, 0x21, 0x0b ) );
+
+/** SHA-256 Test 7.4 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_7_4, HMAC_DRBG_SHA256,
+	additional_input_empty, ( 512 / 8 ) );
+
+/** SHA-256 Test 7.5 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha256_reseed_7_5, HMAC_DRBG_SHA256,
+	entropy_input_2, additional_input_empty,
+	EXPECT ( 0x3d, 0x77, 0x63, 0xe5, 0x30, 0x3d, 0xb5, 0x4b, 0xe2, 0x05,
+		 0x44, 0xa8, 0x1e, 0x9f, 0x00, 0xca, 0xdc, 0xfc, 0x1c, 0xb2,
+		 0x8d, 0xec, 0xb9, 0xcf, 0xc6, 0x99, 0xf6, 0x1d, 0xba, 0xf8,
+		 0x80, 0x21 ),
+	EXPECT ( 0xfe, 0xbc, 0x02, 0x79, 0xb7, 0x71, 0x0d, 0xec, 0x5c, 0x06,
+		 0x7e, 0xbe, 0xfa, 0x06, 0x8e, 0x4b, 0x59, 0x67, 0x49, 0x1b,
+		 0x7e, 0xef, 0x94, 0x75, 0x83, 0x50, 0x6d, 0x04, 0x97, 0xce,
+		 0x67, 0xba ) );
+
+/** SHA-256 Test 7.6 : Retried second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_7_6, HMAC_DRBG_SHA256,
+	additional_input_empty,
+	EXPECT ( 0x2d, 0x21, 0xac, 0x94, 0x99, 0x2f, 0xd8, 0x2b, 0x09, 0x80,
+		 0xd3, 0xd5, 0x95, 0x51, 0xb9, 0xd0, 0x7c, 0x8d, 0x54, 0xb2,
+		 0x52, 0xb6, 0x16, 0x28, 0x93, 0x44, 0xf8, 0xac, 0x86, 0x9e,
+		 0xd3, 0x5b ),
+	EXPECT ( 0x61, 0x0c, 0x34, 0xcd, 0xbf, 0x6f, 0x75, 0x33, 0x54, 0x7f,
+		 0x23, 0x32, 0xea, 0xc5, 0x7e, 0xe3, 0x1e, 0x72, 0x4f, 0xb2,
+		 0x92, 0x55, 0x56, 0x6b, 0x59, 0x78, 0x33, 0x16, 0x6c, 0xd0,
+		 0x39, 0x9f ),
+	EXPECT ( 0x8b, 0xba, 0x71, 0xc2, 0x58, 0x3f, 0x25, 0x30, 0xc2, 0x59,
+		 0xc9, 0x07, 0x84, 0xa5, 0x9a, 0xc4, 0x4d, 0x1c, 0x80, 0x56,
+		 0x91, 0x7c, 0xcf, 0x38, 0x87, 0x88, 0x10, 0x2d, 0x73, 0x82,
+		 0x4c, 0x6c, 0x11, 0xd5, 0xd6, 0x3b, 0xe1, 0xf0, 0x10, 0x17,
+		 0xd8, 0x84, 0xcd, 0x69, 0xd9, 0x33, 0x4b, 0x9e, 0xbc, 0x01,
+		 0xe7, 0xbd, 0x8f, 0xdf, 0x2a, 0x8e, 0x52, 0x57, 0x22, 0x93,
+		 0xdc, 0x21, 0xc0, 0xe1 ) );
+
+/** SHA-256 Test 8 : Instantiate */
+#define sha256_instantiate_8 sha256_instantiate_3
+
+/** SHA-256 Test 8.1 : First call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_8_1, HMAC_DRBG_SHA256,
+	additional_input_1, ( 512 / 8 ) );
+
+/** SHA-256 Test 8.2 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha256_reseed_8_2, HMAC_DRBG_SHA256,
+	entropy_input_1, additional_input_1,
+	EXPECT ( 0xb3, 0x81, 0x38, 0x8c, 0x1d, 0x7c, 0xfd, 0x56, 0x59, 0x30,
+		 0x99, 0x3b, 0xd9, 0x26, 0x90, 0x66, 0x50, 0x88, 0xd9, 0xb8,
+		 0x39, 0x96, 0x9b, 0x87, 0xf1, 0x6d, 0xb6, 0xdf, 0x4e, 0x43,
+		 0x00, 0xd7 ),
+	EXPECT ( 0xfa, 0x04, 0x25, 0x64, 0x00, 0xe3, 0x42, 0xe6, 0x55, 0xf4,
+		 0x33, 0x26, 0x94, 0xe3, 0xb2, 0x4c, 0x04, 0xfb, 0x85, 0xbf,
+		 0x87, 0x80, 0x21, 0xe4, 0x52, 0xe7, 0x3b, 0x8f, 0x46, 0xd4,
+		 0xbd, 0xc6 ) );
+
+/** SHA-256 Test 8.3 : Retried first call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_8_3, HMAC_DRBG_SHA256,
+	additional_input_empty,
+	EXPECT ( 0xd4, 0x1f, 0x6f, 0x33, 0x65, 0x82, 0x21, 0x70, 0x50, 0xb1,
+		 0xf6, 0x59, 0x28, 0xfd, 0x6e, 0x94, 0xcb, 0xc9, 0x45, 0x68,
+		 0xfe, 0x3b, 0x6b, 0x53, 0x38, 0x9e, 0x1e, 0x3a, 0x5b, 0x49,
+		 0xe1, 0x01 ),
+	EXPECT ( 0xa6, 0x55, 0xc9, 0xe7, 0xd1, 0x33, 0xf1, 0xcd, 0x8b, 0x11,
+		 0x61, 0xf2, 0x7d, 0x54, 0xe7, 0x5a, 0x7e, 0x7c, 0x80, 0x42,
+		 0xbf, 0x74, 0xd4, 0x7f, 0x9f, 0xfd, 0x60, 0xe2, 0x45, 0xeb,
+		 0xa5, 0x7e ),
+	EXPECT ( 0x44, 0xd7, 0x8b, 0xbc, 0x3e, 0xb6, 0x7c, 0x59, 0xc2, 0x2f,
+		 0x6c, 0x31, 0x00, 0x3d, 0x21, 0x2a, 0x78, 0x37, 0xcc, 0xd8,
+		 0x4c, 0x43, 0x8b, 0x55, 0x15, 0x0f, 0xd0, 0x13, 0xa8, 0xa7,
+		 0x8f, 0xe8, 0xed, 0xea, 0x81, 0xc6, 0x72, 0xe4, 0xb8, 0xdd,
+		 0xc8, 0x18, 0x38, 0x86, 0xe6, 0x9c, 0x2e, 0x17, 0x7d, 0xf5,
+		 0x74, 0xc1, 0xf1, 0x90, 0xdf, 0x27, 0x18, 0x50, 0xf8, 0xce,
+		 0x55, 0xef, 0x20, 0xb8 ) );
+
+/** SHA-256 Test 8.4 : Second call to Generate */
+HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_8_4, HMAC_DRBG_SHA256,
+	additional_input_2, ( 512 / 8 ) );
+
+/** SHA-256 Test 8.5 : Reseed */
+HMAC_DRBG_TEST_RESEED ( sha256_reseed_8_5, HMAC_DRBG_SHA256,
+	entropy_input_2, additional_input_2,
+	EXPECT ( 0xfb, 0xa8, 0x05, 0x45, 0x3e, 0x3c, 0x9a, 0x73, 0x64, 0x58,
+		 0x5c, 0xed, 0xbc, 0xd2, 0x92, 0x30, 0xfb, 0xc9, 0x3d, 0x6f,
+		 0x12, 0x9d, 0x21, 0xed, 0xdd, 0xf6, 0x61, 0x3b, 0x3a, 0x8f,
+		 0xf2, 0x83 ),
+	EXPECT ( 0x83, 0x64, 0x7a, 0x33, 0x8c, 0x15, 0x3c, 0xba, 0xf0, 0xe4,
+		 0x9a, 0x54, 0xa4, 0x4f, 0xea, 0x66, 0x70, 0xcf, 0xd7, 0xc1,
+		 0x71, 0x4d, 0x4a, 0xb3, 0x5f, 0x11, 0x12, 0x3d, 0xf2, 0x7b,
+		 0x69, 0xcf ) );
+
+/** SHA-256 Test 8.6 : Retried second call to Generate */
+HMAC_DRBG_TEST_GENERATE ( sha256_generate_8_6, HMAC_DRBG_SHA256,
+	additional_input_empty,
+	EXPECT ( 0xae, 0x59, 0xc7, 0x0a, 0x7c, 0x60, 0xed, 0x49, 0x83, 0x78,
+		 0xea, 0x84, 0x5b, 0xe9, 0x7d, 0x8f, 0xf8, 0x81, 0xe0, 0xea,
+		 0x37, 0x2e, 0x26, 0x5f, 0xa6, 0x72, 0x84, 0x29, 0x3e, 0x1a,
+		 0x46, 0xac ),
+	EXPECT ( 0xe2, 0xf0, 0x4d, 0xe3, 0xce, 0x21, 0x79, 0x61, 0xae, 0x2b,
+		 0x2d, 0x20, 0xa7, 0xba, 0x7c, 0x6c, 0x82, 0x0b, 0x5b, 0x14,
+		 0x92, 0x6e, 0x59, 0x56, 0xae, 0x6d, 0xfa, 0x2e, 0xd1, 0xd6,
+		 0x39, 0x93 ),
+	EXPECT ( 0x91, 0x77, 0x80, 0xdc, 0x0c, 0xe9, 0x98, 0x9f, 0xee, 0x6c,
+		 0x08, 0x06, 0xd6, 0xda, 0x12, 0x3a, 0x18, 0x25, 0x29, 0x47,
+		 0x58, 0xd4, 0xe1, 0xb5, 0x82, 0x68, 0x72, 0x31, 0x78, 0x0a,
+		 0x2a, 0x9c, 0x33, 0xf1, 0xd1, 0x56, 0xcc, 0xad, 0x32, 0x77,
+		 0x64, 0xb2, 0x9a, 0x4c, 0xb2, 0x69, 0x01, 0x77, 0xae, 0x96,
+		 0xef, 0x9e, 0xe9, 0x2a, 0xd0, 0xc3, 0x40, 0xba, 0x0f, 0xd1,
+		 0x20, 0x3c, 0x02, 0xc6 ) );
+
+/**
+ * Force a "reseed required" state
+ *
+ * @v state		HMAC_DRBG internal state
+ */
+static inline void force_reseed_required ( struct hmac_drbg_state *state ) {
+	state->reseed_counter = ( HMAC_DRBG_RESEED_INTERVAL + 1 );
+}
+
+/**
+ * Perform HMAC_DRBG self-test
+ *
+ */
+static void hmac_drbg_test_exec ( void ) {
+	struct hmac_drbg_state state;
+
+	/*
+	 * IMPORTANT NOTE
+	 *
+	 * The NIST test vector set includes several calls to
+	 * HMAC_DRBG_Generate() that are expected to fail with a
+	 * status of "Reseed required".  The pattern seems to be that
+	 * when prediction resistance is requested, any call to
+	 * HMAC_DRBG_Generate() is at first expected to fail.  After
+	 * an explicit reseeding, the call to HMAC_DRBG_Generate() is
+	 * retried, and on this second time it is expected to succeed.
+	 *
+	 * This pattern does not match the specifications for
+	 * HMAC_DRBG_Generate(): neither HMAC_DRBG_Generate_algorithm
+	 * (defined in ANS X9.82 Part 3-2007 Section 10.2.2.2.5 (NIST
+	 * SP 800-90 Section 10.1.2.5)) nor the higher-level wrapper
+	 * Generate_function defined in ANS X9.82 Part 3-2007 Section
+	 * 9.4 (NIST SP 800-90 Section 9.3)) can possibly exhibit this
+	 * behaviour:
+	 *
+	 * a) HMAC_DRBG_Generate_algorithm can return a "reseed
+	 *    required" status only as a result of the test
+	 *
+	 *      "1. If reseed_counter > reseed_interval, then return
+	 *       an indication that a reseed is required."
+	 *
+	 *    Since the reseed interval is independent of any request
+	 *    for prediction resistance, and since the reseed interval
+	 *    is not specified as part of the NIST test vector set,
+	 *    then this cannot be the source of the "Reseed required"
+	 *    failure expected by the NIST test vector set.
+	 *
+	 * b) Generate_function cannot return a "reseed required"
+	 *    status under any circumstances.  If the underlying
+	 *    HMAC_DRBG_Generate_algorithm call returns "reseed
+	 *    required", then Generate_function will automatically
+	 *    reseed and try again.
+	 *
+	 * To produce the behaviour expected by the NIST test vector
+	 * set, we therefore contrive to produce a "reseed required"
+	 * state where necessary by setting the reseed_counter to
+	 * greater than the reseed_interval.
+	 */
+
+	/* SHA-1 Test 1 */
+	instantiate_ok ( &state, &sha1_instantiate_1 );
+	generate_ok ( &state, &sha1_generate_1_1 );
+	generate_ok ( &state, &sha1_generate_1_2 );
+
+	/* SHA-1 Test 2 */
+	instantiate_ok ( &state, &sha1_instantiate_2 );
+	generate_ok ( &state, &sha1_generate_2_1 );
+	generate_ok ( &state, &sha1_generate_2_2 );
+
+	/* SHA-1 Test 3 */
+	instantiate_ok ( &state, &sha1_instantiate_3 );
+	generate_ok ( &state, &sha1_generate_3_1 );
+	generate_ok ( &state, &sha1_generate_3_2 );
+
+	/* SHA-1 Test 4 */
+	instantiate_ok ( &state, &sha1_instantiate_4 );
+	generate_ok ( &state, &sha1_generate_4_1 );
+	generate_ok ( &state, &sha1_generate_4_2 );
+
+	/* SHA-1 Test 5 */
+	instantiate_ok ( &state, &sha1_instantiate_5 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha1_generate_fail_5_1 );
+	reseed_ok ( &state, &sha1_reseed_5_2 );
+	generate_ok ( &state, &sha1_generate_5_3 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha1_generate_fail_5_4 );
+	reseed_ok ( &state, &sha1_reseed_5_5 );
+	generate_ok ( &state, &sha1_generate_5_6 );
+
+	/* SHA-1 Test 6 */
+	instantiate_ok ( &state, &sha1_instantiate_6 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha1_generate_fail_6_1 );
+	reseed_ok ( &state, &sha1_reseed_6_2 );
+	generate_ok ( &state, &sha1_generate_6_3 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha1_generate_fail_6_4 );
+	reseed_ok ( &state, &sha1_reseed_6_5 );
+	generate_ok ( &state, &sha1_generate_6_6 );
+
+	/* SHA-1 Test 7 */
+	instantiate_ok ( &state, &sha1_instantiate_7 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha1_generate_fail_7_1 );
+	reseed_ok ( &state, &sha1_reseed_7_2 );
+	generate_ok ( &state, &sha1_generate_7_3 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha1_generate_fail_7_4 );
+	reseed_ok ( &state, &sha1_reseed_7_5 );
+	generate_ok ( &state, &sha1_generate_7_6 );
+
+	/* SHA-1 Test 8 */
+	instantiate_ok ( &state, &sha1_instantiate_8 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha1_generate_fail_8_1 );
+	reseed_ok ( &state, &sha1_reseed_8_2 );
+	generate_ok ( &state, &sha1_generate_8_3 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha1_generate_fail_8_4 );
+	reseed_ok ( &state, &sha1_reseed_8_5 );
+	generate_ok ( &state, &sha1_generate_8_6 );
+
+	/* SHA-256 Test 1 */
+	instantiate_ok ( &state, &sha256_instantiate_1 );
+	generate_ok ( &state, &sha256_generate_1_1 );
+	generate_ok ( &state, &sha256_generate_1_2 );
+
+	/* SHA-256 Test 2 */
+	instantiate_ok ( &state, &sha256_instantiate_2 );
+	generate_ok ( &state, &sha256_generate_2_1 );
+	generate_ok ( &state, &sha256_generate_2_2 );
+
+	/* SHA-256 Test 3 */
+	instantiate_ok ( &state, &sha256_instantiate_3 );
+	generate_ok ( &state, &sha256_generate_3_1 );
+	generate_ok ( &state, &sha256_generate_3_2 );
+
+	/* SHA-256 Test 4 */
+	instantiate_ok ( &state, &sha256_instantiate_4 );
+	generate_ok ( &state, &sha256_generate_4_1 );
+	generate_ok ( &state, &sha256_generate_4_2 );
+
+	/* SHA-256 Test 5 */
+	instantiate_ok ( &state, &sha256_instantiate_5 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha256_generate_fail_5_1 );
+	reseed_ok ( &state, &sha256_reseed_5_2 );
+	generate_ok ( &state, &sha256_generate_5_3 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha256_generate_fail_5_4 );
+	reseed_ok ( &state, &sha256_reseed_5_5 );
+	generate_ok ( &state, &sha256_generate_5_6 );
+
+	/* SHA-256 Test 6 */
+	instantiate_ok ( &state, &sha256_instantiate_6 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha256_generate_fail_6_1 );
+	reseed_ok ( &state, &sha256_reseed_6_2 );
+	generate_ok ( &state, &sha256_generate_6_3 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha256_generate_fail_6_4 );
+	reseed_ok ( &state, &sha256_reseed_6_5 );
+	generate_ok ( &state, &sha256_generate_6_6 );
+
+	/* SHA-256 Test 7 */
+	instantiate_ok ( &state, &sha256_instantiate_7 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha256_generate_fail_7_1 );
+	reseed_ok ( &state, &sha256_reseed_7_2 );
+	generate_ok ( &state, &sha256_generate_7_3 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha256_generate_fail_7_4 );
+	reseed_ok ( &state, &sha256_reseed_7_5 );
+	generate_ok ( &state, &sha256_generate_7_6 );
+
+	/* SHA-256 Test 8 */
+	instantiate_ok ( &state, &sha256_instantiate_8 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha256_generate_fail_8_1 );
+	reseed_ok ( &state, &sha256_reseed_8_2 );
+	generate_ok ( &state, &sha256_generate_8_3 );
+	force_reseed_required ( &state ); /* See above comments */
+	generate_fail_ok ( &state, &sha256_generate_fail_8_4 );
+	reseed_ok ( &state, &sha256_reseed_8_5 );
+	generate_ok ( &state, &sha256_generate_8_6 );
+}
+
+/** HMAC_DRBG self-test */
+struct self_test hmac_drbg_test __self_test = {
+	.name = "hmac_drbg",
+	.exec = hmac_drbg_test_exec,
+};
diff --git a/roms/ipxe/src/tests/list_test.c b/roms/ipxe/src/tests/list_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..35cbd5e5fb26334cf23ea482d34cee5087bf9673
--- /dev/null
+++ b/roms/ipxe/src/tests/list_test.c
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2011 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * List function tests
+ *
+ */
+
+/* Forcibly enable assertions for list_check() */
+#undef NDEBUG
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <ipxe/list.h>
+#include <ipxe/test.h>
+
+/** A list test structure */
+struct list_test {
+	/** List element */
+	struct list_head list;
+	/** Label */
+	char label;
+};
+
+/** List test elements */
+static struct list_test list_tests[] = {
+	{ .label = '0' },
+	{ .label = '1' },
+	{ .label = '2' },
+	{ .label = '3' },
+	{ .label = '4' },
+	{ .label = '5' },
+	{ .label = '6' },
+	{ .label = '7' },
+	{ .label = '8' },
+	{ .label = '9' },
+};
+
+/** Test list */
+static LIST_HEAD ( test_list );
+
+/**
+ * Check list contents are as expected
+ *
+ * @v list		Test list
+ * @v expected		Expected contents
+ * @v ok		List contents are as expected
+ */
+static int list_check_contents ( struct list_head *list,
+				 const char *expected ) {
+	struct list_test *entry;
+	size_t num_entries = 0;
+
+	/* Determine size of list */
+	list_for_each_entry ( entry, list, list )
+		num_entries++;
+
+	{
+		char found[ num_entries + 1 ];
+		char found_rev[ num_entries + 1 ];
+		char *tmp;
+
+		/* Build up list content string */
+		tmp = found;
+		list_for_each_entry ( entry, list, list )
+			*(tmp++) = entry->label;
+		*tmp = '\0';
+
+		/* Sanity check reversed list */
+		tmp = &found_rev[ sizeof ( found_rev ) - 1 ];
+		*tmp = '\0';
+		list_for_each_entry_reverse ( entry, list, list )
+			*(--tmp) = entry->label;
+		if ( strcmp ( found, found_rev ) != 0 ) {
+			printf ( "FAILURE: list reversal mismatch (forward "
+				 "\"%s\", reverse \"%s\")\n",
+				 found, found_rev  );
+			return 0;
+		}
+
+		/* Compare against expected content */
+		if ( strcmp ( found, expected ) == 0 ) {
+			return 1;
+		} else {
+			printf ( "FAILURE: expected \"%s\", got \"%s\"\n",
+			 expected, found );
+			return 0;
+		}
+	}
+}
+
+/**
+ * Report list test result
+ *
+ * @v list		Test list
+ * @v expected		Expected contents
+ */
+#define list_contents_ok( list, expected ) do {			\
+	ok ( list_check_contents ( (list), (expected) ) );	\
+	} while ( 0 )
+
+/**
+ * Report list iteration test result
+ *
+ * @v macro		Iterator macro
+ * @v expected		Expected contents
+ * @v pos		Iterator
+ * @v ...		Arguments to iterator macro
+ */
+#define list_iterate_ok( macro, expected, pos, ... ) do {	\
+	const char *check = expected;				\
+	macro ( pos, __VA_ARGS__ ) {				\
+		struct list_test *entry =			\
+			list_entry ( pos, struct list_test,	\
+				     list );			\
+		ok ( entry->label == *(check++) );		\
+	}							\
+	ok ( *check == '\0' );					\
+	} while ( 0 )
+
+/**
+ * Report list entry iteration test result
+ *
+ * @v macro		Iterator macro
+ * @v expected		Expected contents
+ * @v pos		Iterator
+ * @v ...		Arguments to iterator macro
+ */
+#define list_iterate_entry_ok( macro, expected, pos, ... ) do {	\
+	const char *check = expected;				\
+	macro ( pos, __VA_ARGS__ ) {				\
+		ok ( (pos)->label == *(check++) );		\
+	}							\
+	ok ( *check == '\0' );					\
+	} while ( 0 )
+
+/**
+ * Perform list self-test
+ *
+ */
+static void list_test_exec ( void ) {
+	struct list_head *list = &test_list;
+	struct list_head target_list;
+	struct list_head *target = &target_list;
+	struct list_head *raw_pos;
+	struct list_test *pos;
+	struct list_test *tmp;
+
+	/* Test initialiser and list_empty() */
+	ok ( list_empty ( list ) );
+	list_contents_ok ( list, "" );
+
+	/* Test list_add(), list_add_tail() and list_del() */
+	INIT_LIST_HEAD ( list );
+	list_contents_ok ( list, "" );
+	list_add ( &list_tests[4].list, list ); /* prepend */
+	list_contents_ok ( list, "4" );
+	list_add ( &list_tests[2].list, list ); /* prepend */
+	list_contents_ok ( list, "24" );
+	list_add_tail ( &list_tests[7].list, list ); /* append */
+	list_contents_ok ( list, "247" );
+	list_add ( &list_tests[1].list, &list_tests[4].list ); /* after */
+	list_contents_ok ( list, "2417" );
+	list_add_tail ( &list_tests[8].list, &list_tests[7].list ); /* before */
+	list_contents_ok ( list, "24187" );
+	list_del ( &list_tests[4].list ); /* delete middle */
+	list_contents_ok ( list, "2187" );
+	list_del ( &list_tests[2].list ); /* delete first */
+	list_contents_ok ( list, "187" );
+	list_del ( &list_tests[7].list ); /* delete last */
+	list_contents_ok ( list, "18" );
+	list_del ( &list_tests[1].list ); /* delete all */
+	list_del ( &list_tests[8].list ); /* delete all */
+	list_contents_ok ( list, "" );
+	ok ( list_empty ( list ) );
+
+	/* Test list_is_singular() */
+	INIT_LIST_HEAD ( list );
+	ok ( ! list_is_singular ( list ) );
+	list_add ( &list_tests[1].list, list );
+	ok ( list_is_singular ( list ) );
+	list_add ( &list_tests[3].list, list );
+	ok ( ! list_is_singular ( list ) );
+	list_del ( &list_tests[1].list );
+	ok ( list_is_singular ( list ) );
+
+	/* Test list_is_last() */
+	INIT_LIST_HEAD ( list );
+	list_add_tail ( &list_tests[6].list, list );
+	ok ( list_is_last ( &list_tests[6].list, list ) );
+	list_add_tail ( &list_tests[4].list, list );
+	ok ( list_is_last ( &list_tests[4].list, list ) );
+	ok ( ! list_is_last ( &list_tests[6].list, list ) );
+
+	/* Test list_cut_position() - empty list */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_cut_position ( target, list, list );
+	list_contents_ok ( list, "" );
+	list_contents_ok ( target, "" );
+
+	/* Test list_cut_position() - singular list, move nothing */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_add_tail ( &list_tests[4].list, list );
+	list_cut_position ( target, list, list );
+	list_contents_ok ( list, "4" );
+	list_contents_ok ( target, "" );
+
+	/* Test list_cut_position() - singular list, move singular entry */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_add_tail ( &list_tests[9].list, list );
+	list_cut_position ( target, list, &list_tests[9].list );
+	list_contents_ok ( list, "" );
+	list_contents_ok ( target, "9" );
+
+	/* Test list_cut_position() - multi-entry list, move nothing */
+	INIT_LIST_HEAD ( list );
+	list_add_tail ( &list_tests[3].list, list );
+	list_add_tail ( &list_tests[2].list, list );
+	list_add_tail ( &list_tests[7].list, list );
+	INIT_LIST_HEAD ( target );
+	list_cut_position ( target, list, list );
+	list_contents_ok ( list, "327" );
+	list_contents_ok ( target, "" );
+
+	/* Test list_cut_position() - multi-entry list, move some */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_add_tail ( &list_tests[8].list, list );
+	list_add_tail ( &list_tests[0].list, list );
+	list_add_tail ( &list_tests[9].list, list );
+	list_add_tail ( &list_tests[3].list, list );
+	list_add_tail ( &list_tests[2].list, list );
+	list_cut_position ( target, list, &list_tests[0].list );
+	list_contents_ok ( list, "932" );
+	list_contents_ok ( target, "80" );
+
+	/* Test list_cut_position() - multi-entry list, move everything */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_add_tail ( &list_tests[3].list, list );
+	list_add_tail ( &list_tests[5].list, list );
+	list_add_tail ( &list_tests[4].list, list );
+	list_add_tail ( &list_tests[7].list, list );
+	list_add_tail ( &list_tests[1].list, list );
+	list_cut_position ( target, list, &list_tests[1].list );
+	list_contents_ok ( list, "" );
+	list_contents_ok ( target, "35471" );
+
+	/* Test list_splice() - empty list */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_splice ( list, target );
+	list_contents_ok ( list, "" );
+	list_contents_ok ( target, "" );
+
+	/* Test list_splice() - both lists empty */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_splice ( list, target );
+	list_contents_ok ( target, "" );
+
+	/* Test list_splice() - source list empty */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_add_tail ( &list_tests[1].list, target );
+	list_add_tail ( &list_tests[3].list, target );
+	list_splice ( list, &list_tests[1].list );
+	list_contents_ok ( target, "13" );
+
+	/* Test list_splice() - destination list empty */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_add_tail ( &list_tests[6].list, list );
+	list_add_tail ( &list_tests[5].list, list );
+	list_add_tail ( &list_tests[2].list, list );
+	list_splice ( list, target );
+	list_contents_ok ( target, "652" );
+
+	/* Test list_splice() - both lists non-empty */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_add_tail ( &list_tests[8].list, list );
+	list_add_tail ( &list_tests[4].list, list );
+	list_add_tail ( &list_tests[5].list, list );
+	list_add_tail ( &list_tests[1].list, target );
+	list_add_tail ( &list_tests[9].list, target );
+	list_splice ( list, &list_tests[1].list );
+	list_contents_ok ( target, "18459" );
+
+	/* Test list_splice_tail() - both lists empty */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_splice_tail ( list, target );
+	list_contents_ok ( target, "" );
+
+	/* Test list_splice_tail() - source list empty */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_add_tail ( &list_tests[5].list, target );
+	list_splice_tail ( list, &list_tests[5].list );
+	list_contents_ok ( target, "5" );
+
+	/* Test list_splice_tail() - destination list empty */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_add_tail ( &list_tests[2].list, list );
+	list_add_tail ( &list_tests[1].list, list );
+	list_add_tail ( &list_tests[0].list, list );
+	list_splice_tail ( list, target );
+	list_contents_ok ( target, "210" );
+
+	/* Test list_splice_tail() - both lists non-empty */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_add_tail ( &list_tests[9].list, list );
+	list_add_tail ( &list_tests[5].list, list );
+	list_add_tail ( &list_tests[7].list, list );
+	list_add_tail ( &list_tests[2].list, target );
+	list_add_tail ( &list_tests[4].list, target );
+	list_splice_tail ( list, &list_tests[2].list );
+	list_contents_ok ( target, "95724" );
+
+	/* Test list_splice_init() */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_add_tail ( &list_tests[4].list, list );
+	list_add_tail ( &list_tests[1].list, target );
+	list_splice_init ( list, target );
+	ok ( list_empty ( list ) );
+	list_contents_ok ( list, "" );
+	list_contents_ok ( target, "41" );
+
+	/* Test list_splice_tail_init() */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( target );
+	list_add_tail ( &list_tests[3].list, list );
+	list_add_tail ( &list_tests[2].list, list );
+	list_add_tail ( &list_tests[5].list, target );
+	list_splice_tail_init ( list, &list_tests[5].list );
+	ok ( list_empty ( list ) );
+	list_contents_ok ( list, "" );
+	list_contents_ok ( target, "325" );
+
+	/* Test list_entry() */
+	INIT_LIST_HEAD ( &list_tests[3].list );  // for list_check()
+	ok ( list_entry ( &list_tests[3].list, struct list_test, list )
+	     == &list_tests[3] );
+
+	/* Test list_first_entry() and list_last_entry() */
+	INIT_LIST_HEAD ( list );
+	list_add_tail ( &list_tests[9].list, list );
+	list_add_tail ( &list_tests[5].list, list );
+	list_add_tail ( &list_tests[6].list, list );
+	ok ( list_first_entry ( list, struct list_test, list )
+	     == &list_tests[9] );
+	ok ( list_last_entry ( list, struct list_test, list )
+	     == &list_tests[6] );
+	list_del ( &list_tests[9].list );
+	ok ( list_first_entry ( list, struct list_test, list )
+	     == &list_tests[5] );
+	ok ( list_last_entry ( list, struct list_test, list )
+	     == &list_tests[6] );
+	list_del ( &list_tests[6].list );
+	ok ( list_first_entry ( list, struct list_test, list )
+	     == &list_tests[5] );
+	ok ( list_last_entry ( list, struct list_test, list )
+	     == &list_tests[5] );
+	list_del ( &list_tests[5].list );
+	ok ( list_first_entry ( list, struct list_test, list ) == NULL );
+	ok ( list_last_entry ( list, struct list_test, list ) == NULL );
+
+	/* Test list_for_each() */
+	INIT_LIST_HEAD ( list );
+	list_add_tail ( &list_tests[6].list, list );
+	list_add_tail ( &list_tests[7].list, list );
+	list_add_tail ( &list_tests[3].list, list );
+	list_iterate_ok ( list_for_each, "673", raw_pos, list );
+
+	/* Test list_for_each_entry() and list_for_each_entry_reverse() */
+	INIT_LIST_HEAD ( list );
+	list_add_tail ( &list_tests[3].list, list );
+	list_add_tail ( &list_tests[2].list, list );
+	list_add_tail ( &list_tests[6].list, list );
+	list_add_tail ( &list_tests[9].list, list );
+	list_iterate_entry_ok ( list_for_each_entry, "3269",
+				pos, list, list );
+	list_iterate_entry_ok ( list_for_each_entry_reverse, "9623",
+				pos, list, list );
+
+	/* Test list_for_each_entry_safe() */
+	INIT_LIST_HEAD ( list );
+	list_add_tail ( &list_tests[2].list, list );
+	list_add_tail ( &list_tests[4].list, list );
+	list_add_tail ( &list_tests[1].list, list );
+	{
+		char *expected = "241";
+		list_for_each_entry_safe ( pos, tmp, list, list ) {
+			list_contents_ok ( list, expected );
+			list_del ( &pos->list );
+			expected++;
+			list_contents_ok ( list, expected );
+		}
+	}
+	ok ( list_empty ( list ) );
+
+	/* Test list_for_each_entry_continue() and
+	 * list_for_each_entry_continue_reverse()
+	 */
+	INIT_LIST_HEAD ( list );
+	list_add_tail ( &list_tests[4].list, list );
+	list_add_tail ( &list_tests[7].list, list );
+	list_add_tail ( &list_tests[2].list, list );
+	list_add_tail ( &list_tests[9].list, list );
+	list_add_tail ( &list_tests[3].list, list );
+	pos = &list_tests[7];
+	list_iterate_entry_ok ( list_for_each_entry_continue, "293",
+				pos, list, list );
+	ok ( pos == list_entry ( list, struct list_test, list ) );
+	list_iterate_entry_ok ( list_for_each_entry_continue, "47293",
+				pos, list, list );
+	pos = &list_tests[3];
+	list_iterate_entry_ok ( list_for_each_entry_continue, "",
+				pos, list, list );
+	pos = &list_tests[2];
+	list_iterate_entry_ok ( list_for_each_entry_continue_reverse, "74",
+				pos, list, list );
+	ok ( pos == list_entry ( list, struct list_test, list ) );
+	list_iterate_entry_ok ( list_for_each_entry_continue_reverse, "39274",
+				pos, list, list );
+	pos = &list_tests[4];
+	list_iterate_entry_ok ( list_for_each_entry_continue_reverse, "",
+				pos, list, list );
+
+	/* Test list_contains() and list_contains_entry() */
+	INIT_LIST_HEAD ( list );
+	INIT_LIST_HEAD ( &list_tests[3].list );
+	list_add ( &list_tests[8].list, list );
+	list_add ( &list_tests[5].list, list );
+	ok ( list_contains ( &list_tests[8].list, list ) );
+	ok ( list_contains_entry ( &list_tests[8], list, list ) );
+	ok ( list_contains ( &list_tests[5].list, list ) );
+	ok ( list_contains_entry ( &list_tests[5], list, list ) );
+	ok ( ! list_contains ( &list_tests[3].list, list ) );
+	ok ( ! list_contains_entry ( &list_tests[3], list, list ) );
+
+	/* Test list_check_contains_entry() */
+	INIT_LIST_HEAD ( list );
+	list_add ( &list_tests[4].list, list );
+	list_add ( &list_tests[0].list, list );
+	list_add ( &list_tests[3].list, list );
+	list_check_contains_entry ( &list_tests[4], list, list );
+	list_check_contains_entry ( &list_tests[0], list, list );
+	list_check_contains_entry ( &list_tests[3], list, list );
+}
+
+/** List self-test */
+struct self_test list_test __self_test = {
+	.name = "list",
+	.exec = list_test_exec,
+};
diff --git a/roms/ipxe/src/tests/md5_test.c b/roms/ipxe/src/tests/md5_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..ba5f24c3ec80ecbd690bd169011436d0e5000e8e
--- /dev/null
+++ b/roms/ipxe/src/tests/md5_test.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * MD5 tests
+ *
+ */
+
+#include <stdint.h>
+#include <ipxe/md5.h>
+#include <ipxe/test.h>
+#include "digest_test.h"
+
+/** An MD5 test vector */
+struct md5_test_vector {
+	/** Test data */
+	void *data;
+	/** Test data length */
+	size_t len;
+	/** Expected digest */
+	uint8_t digest[MD5_DIGEST_SIZE];
+};
+
+/** MD5 test vectors */
+static struct md5_test_vector md5_test_vectors[] = {
+	/* Test inputs borrowed from SHA-1 tests, with results
+	 * calculated using md5sum.
+	 */
+	{ NULL, 0,
+	  { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
+	    0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } },
+	{ "abc", 3,
+	  { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0,
+	    0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } },
+	{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56,
+	  { 0x82, 0x15, 0xef, 0x07, 0x96, 0xa2, 0x0b, 0xca,
+	    0xaa, 0xe1, 0x16, 0xd3, 0x87, 0x6c, 0x66, 0x4a } },
+};
+
+/** MD5 test fragment lists */
+static struct digest_test_fragments md5_test_fragments[] = {
+	{ { 0, -1UL, } },
+	{ { 1, 1, 1, 1, 1, 1, 1, 1 } },
+	{ { 2, 0, 23, 4, 6, 1, 0 } },
+};
+
+/**
+ * Perform MD5 self-test
+ *
+ */
+static void md5_test_exec ( void ) {
+	struct digest_algorithm *digest = &md5_algorithm;
+	struct md5_test_vector *test;
+	unsigned long cost;
+	unsigned int i;
+	unsigned int j;
+
+	/* Correctness test */
+	for ( i = 0 ; i < ( sizeof ( md5_test_vectors ) /
+			    sizeof ( md5_test_vectors[0] ) ) ; i++ ) {
+		test = &md5_test_vectors[i];
+		/* Test with a single pass */
+		digest_ok ( digest, NULL, test->data, test->len, test->digest );
+		/* Test with fragment lists */
+		for ( j = 0 ; j < ( sizeof ( md5_test_fragments ) /
+				    sizeof ( md5_test_fragments[0] ) ) ; j++ ){
+			digest_ok ( digest, &md5_test_fragments[j],
+				    test->data, test->len, test->digest );
+		}
+	}
+
+	/* Speed test */
+	cost = digest_cost ( digest );
+	DBG ( "MD5 required %ld cycles per byte\n", cost );
+}
+
+/** MD5 self-test */
+struct self_test md5_test __self_test = {
+	.name = "md5",
+	.exec = md5_test_exec,
+};
diff --git a/roms/ipxe/src/tests/memcpy_test.c b/roms/ipxe/src/tests/memcpy_test.c
index 7626e6398e453e802cbcc71dfad6..b405a9f2fa05c1f99f6f901ce833 100644
--- a/roms/ipxe/src/tests/memcpy_test.c
+++ b/roms/ipxe/src/tests/memcpy_test.c
@@ -1,39 +1,261 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * memcpy() self-tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
+#include <ipxe/test.h>
+#include <ipxe/profile.h>
 
-/*
- * This file exists for testing the compilation of memcpy() with the
- * various constant-length optimisations.
+/* Provide global functions to allow inspection of generated code */
+
+void memcpy_0 ( void *dest, void *src ) { memcpy ( dest, src, 0 ); }
+void memcpy_1 ( void *dest, void *src ) { memcpy ( dest, src, 1 ); }
+void memcpy_2 ( void *dest, void *src ) { memcpy ( dest, src, 2 ); }
+void memcpy_3 ( void *dest, void *src ) { memcpy ( dest, src, 3 ); }
+void memcpy_4 ( void *dest, void *src ) { memcpy ( dest, src, 4 ); }
+void memcpy_5 ( void *dest, void *src ) { memcpy ( dest, src, 5 ); }
+void memcpy_6 ( void *dest, void *src ) { memcpy ( dest, src, 6 ); }
+void memcpy_7 ( void *dest, void *src ) { memcpy ( dest, src, 7 ); }
+void memcpy_8 ( void *dest, void *src ) { memcpy ( dest, src, 8 ); }
+void memcpy_9 ( void *dest, void *src ) { memcpy ( dest, src, 9 ); }
+void memcpy_10 ( void *dest, void *src ) { memcpy ( dest, src, 10 ); }
+void memcpy_11 ( void *dest, void *src ) { memcpy ( dest, src, 11 ); }
+void memcpy_12 ( void *dest, void *src ) { memcpy ( dest, src, 12 ); }
+void memcpy_13 ( void *dest, void *src ) { memcpy ( dest, src, 13 ); }
+void memcpy_14 ( void *dest, void *src ) { memcpy ( dest, src, 14 ); }
+void memcpy_15 ( void *dest, void *src ) { memcpy ( dest, src, 15 ); }
+void memcpy_16 ( void *dest, void *src ) { memcpy ( dest, src, 16 ); }
+void memcpy_17 ( void *dest, void *src ) { memcpy ( dest, src, 17 ); }
+void memcpy_18 ( void *dest, void *src ) { memcpy ( dest, src, 18 ); }
+void memcpy_19 ( void *dest, void *src ) { memcpy ( dest, src, 19 ); }
+void memcpy_20 ( void *dest, void *src ) { memcpy ( dest, src, 20 ); }
+void memcpy_21 ( void *dest, void *src ) { memcpy ( dest, src, 21 ); }
+void memcpy_22 ( void *dest, void *src ) { memcpy ( dest, src, 22 ); }
+void memcpy_23 ( void *dest, void *src ) { memcpy ( dest, src, 23 ); }
+void memcpy_24 ( void *dest, void *src ) { memcpy ( dest, src, 24 ); }
+void memcpy_25 ( void *dest, void *src ) { memcpy ( dest, src, 25 ); }
+void memcpy_26 ( void *dest, void *src ) { memcpy ( dest, src, 26 ); }
+void memcpy_27 ( void *dest, void *src ) { memcpy ( dest, src, 27 ); }
+void memcpy_28 ( void *dest, void *src ) { memcpy ( dest, src, 28 ); }
+void memcpy_29 ( void *dest, void *src ) { memcpy ( dest, src, 29 ); }
+void memcpy_30 ( void *dest, void *src ) { memcpy ( dest, src, 30 ); }
+void memcpy_31 ( void *dest, void *src ) { memcpy ( dest, src, 31 ); }
+
+/**
+ * Force a call to the variable-length implementation of memcpy()
+ *
+ * @v dest		Destination address
+ * @v src		Source address
+ * @v len		Length of data
+ * @ret dest		Destination address
+ */
+__attribute__ (( noinline )) void * memcpy_var ( void *dest, const void *src,
+						 size_t len ) {
+	return memcpy ( dest, src, len );
+}
+
+/**
+ * Perform a constant-length memcpy() test
+ *
+ * ...			Data to copy
+ */
+#define MEMCPY_TEST_CONSTANT( ... ) do {				\
+		static const uint8_t src[] = { __VA_ARGS__ };		\
+		uint8_t dest_const[ 1 + sizeof ( src ) + 1 ];		\
+		uint8_t dest_var[ 1 + sizeof ( src ) + 1 ];		\
+									\
+		dest_const[0] = 0x33;					\
+		dest_const[ sizeof ( dest_const ) - 1 ] = 0x44;		\
+		memcpy ( ( dest_const + 1 ), src,			\
+			 ( sizeof ( dest_const ) - 2 ) );		\
+		ok ( dest_const[0] == 0x33 );				\
+		ok ( dest_const[ sizeof ( dest_const ) - 1 ] == 0x44 );	\
+		ok ( memcmp ( ( dest_const + 1 ), src,			\
+			      ( sizeof ( dest_const ) - 2 ) ) == 0 );	\
+									\
+		dest_var[0] = 0x55;					\
+		dest_var[ sizeof ( dest_var ) - 1 ] = 0x66;		\
+		memcpy_var ( ( dest_var + 1 ), src,			\
+			     ( sizeof ( dest_var ) - 2 ) );		\
+		ok ( dest_var[0] == 0x55 );				\
+		ok ( dest_var[ sizeof ( dest_var ) - 1 ] == 0x66 );	\
+		ok ( memcmp ( ( dest_var + 1 ), src,			\
+			      ( sizeof ( dest_var ) - 2 ) ) == 0 );	\
+	} while ( 0 )
+
+/**
+ * Test memcpy() speed
+ *
+ * @v dest_offset	Destination alignment offset
+ * @v src_offset	Source alignment offset
+ * @v len		Length of data to copy
+ */
+static void memcpy_test_speed ( unsigned int dest_offset,
+				unsigned int src_offset, size_t len ) {
+	uint8_t *dest;
+	uint8_t *src;
+	unsigned int i;
+	unsigned long elapsed;
+
+	/* Allocate blocks */
+	dest = malloc ( len + dest_offset );
+	assert ( dest != NULL );
+	src = malloc ( len + src_offset );
+	assert ( src != NULL );
+
+	/* Generate random source data */
+	for ( i = 0 ; i < len ; i++ )
+		src[ src_offset + i ] = random();
+
+	/* Perform memcpy() */
+	simple_profile();
+	memcpy ( ( dest + dest_offset ), ( src + src_offset ), len );
+	elapsed = simple_profile();
+
+	/* Check copied data */
+	ok ( memcmp ( ( dest + dest_offset ), ( src + src_offset ),
+		      len ) == 0 );
+
+	/* Free blocks */
+	free ( dest );
+	free ( src );
+
+	DBG ( "MEMCPY copied %zd bytes (+%d => +%d) in %ld ticks\n",
+	      len, src_offset, dest_offset, elapsed );
+}
+
+/**
+ * Perform memcpy() self-tests
  *
  */
+static void memcpy_test_exec ( void ) {
+	unsigned int dest_offset;
+	unsigned int src_offset;
+
+	/* Constant-length tests */
+	MEMCPY_TEST_CONSTANT ( );
+	MEMCPY_TEST_CONSTANT ( 0x86 );
+	MEMCPY_TEST_CONSTANT ( 0x8c, 0xd3 );
+	MEMCPY_TEST_CONSTANT ( 0x4e, 0x08, 0xed );
+	MEMCPY_TEST_CONSTANT ( 0xcc, 0x61, 0x8f, 0x70 );
+	MEMCPY_TEST_CONSTANT ( 0x6d, 0x28, 0xe0, 0x9e, 0x6d );
+	MEMCPY_TEST_CONSTANT ( 0x7d, 0x13, 0x4f, 0xef, 0x17, 0xb3 );
+	MEMCPY_TEST_CONSTANT ( 0x38, 0xa7, 0xd4, 0x8d, 0x44, 0x01, 0xfd );
+	MEMCPY_TEST_CONSTANT ( 0x45, 0x9f, 0xf4, 0xf9, 0xf3, 0x0f, 0x99, 0x43 );
+	MEMCPY_TEST_CONSTANT ( 0x69, 0x8c, 0xf6, 0x12, 0x79, 0x70, 0xd8, 0x1e,
+			       0x9d );
+	MEMCPY_TEST_CONSTANT ( 0xbe, 0x53, 0xb4, 0xb7, 0xdd, 0xe6, 0x35, 0x10,
+			       0x3c, 0xe7 );
+	MEMCPY_TEST_CONSTANT ( 0xaf, 0x41, 0x8a, 0x88, 0xb1, 0x4e, 0x52, 0xd4,
+			       0xe6, 0xc3, 0x76 );
+	MEMCPY_TEST_CONSTANT ( 0xdf, 0x43, 0xe4, 0x5d, 0xad, 0x17, 0x35, 0x38,
+			       0x1a, 0x1d, 0x57, 0x58 );
+	MEMCPY_TEST_CONSTANT ( 0x20, 0x52, 0x83, 0x92, 0xb9, 0x85, 0xa4, 0x06,
+			       0x94, 0xe0, 0x3d, 0x57, 0xd4 );
+	MEMCPY_TEST_CONSTANT ( 0xf1, 0x67, 0x31, 0x9e, 0x32, 0x98, 0x27, 0xe9,
+			       0x8e, 0x62, 0xb4, 0x82, 0x7e, 0x02 );
+	MEMCPY_TEST_CONSTANT ( 0x93, 0xc1, 0x55, 0xe3, 0x60, 0xce, 0xac, 0x1e,
+			       0xae, 0x9d, 0xca, 0xec, 0x92, 0xb3, 0x38 );
+	MEMCPY_TEST_CONSTANT ( 0xb3, 0xc1, 0xfa, 0xe7, 0x8a, 0x1c, 0xe4, 0xce,
+			       0x85, 0xe6, 0x3c, 0xab, 0x1c, 0xa2, 0xaf, 0x7a );
+	MEMCPY_TEST_CONSTANT ( 0x9b, 0x6e, 0x1c, 0x48, 0x82, 0xd3, 0x6e, 0x58,
+			       0xa7, 0xb0, 0xe6, 0xea, 0x6d, 0xee, 0xc8, 0xf8,
+			       0xaf );
+	MEMCPY_TEST_CONSTANT ( 0x86, 0x6d, 0xb0, 0xf5, 0xf2, 0xc9, 0xcd, 0xfe,
+			       0xfb, 0x38, 0x67, 0xbc, 0x51, 0x9d, 0x25, 0xbc,
+			       0x09, 0x88 );
+	MEMCPY_TEST_CONSTANT ( 0x58, 0xa4, 0x96, 0x9e, 0x98, 0x36, 0xdb, 0xae,
+			       0x8a, 0x08, 0x7c, 0x64, 0xf9, 0xfb, 0x25, 0xb4,
+			       0x8e, 0xf3, 0xed );
+	MEMCPY_TEST_CONSTANT ( 0xc6, 0x3b, 0x84, 0x3c, 0x76, 0x24, 0x8e, 0x42,
+			       0x11, 0x1f, 0x09, 0x2e, 0x24, 0xbb, 0x67, 0x71,
+			       0x3a, 0xca, 0x60, 0xdd );
+	MEMCPY_TEST_CONSTANT ( 0x8e, 0x2d, 0xa9, 0x58, 0x87, 0xe2, 0xac, 0x4b,
+			       0xc8, 0xbf, 0xa2, 0x4e, 0xee, 0x3a, 0xa6, 0x71,
+			       0x76, 0xee, 0x42, 0x05, 0x6e );
+	MEMCPY_TEST_CONSTANT ( 0x8a, 0xda, 0xdf, 0x7b, 0x55, 0x41, 0x8c, 0xcd,
+			       0x42, 0x40, 0x18, 0xe2, 0x60, 0xc4, 0x7d, 0x64,
+			       0x00, 0xd5, 0xef, 0xa1, 0x7b, 0x31 );
+	MEMCPY_TEST_CONSTANT ( 0xd9, 0x25, 0xcb, 0xbb, 0x9c, 0x1d, 0xdd, 0xcd,
+			       0xde, 0x96, 0xd9, 0x74, 0x13, 0x95, 0xfe, 0x68,
+			       0x0b, 0x3d, 0x30, 0x8d, 0x0c, 0x1e, 0x6d );
+	MEMCPY_TEST_CONSTANT ( 0x2d, 0x0d, 0x02, 0x33, 0xd6, 0xbe, 0x6c, 0xa6,
+			       0x0a, 0xab, 0xe5, 0xda, 0xe2, 0xab, 0x78, 0x3c,
+			       0xd3, 0xdd, 0xea, 0xfa, 0x1a, 0xe4, 0xf4, 0xb3 );
+	MEMCPY_TEST_CONSTANT ( 0x6a, 0x34, 0x39, 0xea, 0x29, 0x5f, 0xa6, 0x18,
+			       0xc1, 0x53, 0x39, 0x78, 0xdb, 0x40, 0xf2, 0x98,
+			       0x78, 0xcf, 0xee, 0xfd, 0xcd, 0xf8, 0x56, 0xf8,
+			       0x30 );
+	MEMCPY_TEST_CONSTANT ( 0xe4, 0xe5, 0x5a, 0x8d, 0xcf, 0x04, 0x29, 0x7c,
+			       0xa7, 0xd8, 0x43, 0xbf, 0x0b, 0xbf, 0xe7, 0x68,
+			       0xf7, 0x8c, 0x81, 0xf9, 0x3f, 0xad, 0xa4, 0x40,
+			       0x38, 0x82 );
+	MEMCPY_TEST_CONSTANT ( 0x71, 0xcd, 0x3d, 0x26, 0xde, 0x11, 0x23, 0xd5,
+			       0x42, 0x6e, 0x63, 0x72, 0x53, 0xfc, 0x28, 0x06,
+			       0x4b, 0xe0, 0x2c, 0x07, 0x6b, 0xe8, 0xd9, 0x5f,
+			       0xf8, 0x74, 0xed );
+	MEMCPY_TEST_CONSTANT ( 0x05, 0xb2, 0xae, 0x81, 0x91, 0xc9, 0xa2, 0x5f,
+			       0xa9, 0x1b, 0x25, 0x7f, 0x32, 0x0c, 0x04, 0x00,
+			       0xf1, 0x46, 0xab, 0x77, 0x1e, 0x12, 0x27, 0xe7,
+			       0xf6, 0x1e, 0x0c, 0x29 );
+	MEMCPY_TEST_CONSTANT ( 0x0e, 0xca, 0xa5, 0x56, 0x3d, 0x99, 0x99, 0xf9,
+			       0x6e, 0xdd, 0x93, 0x98, 0xec, 0x8b, 0x5c, 0x71,
+			       0x0c, 0xb0, 0xe6, 0x12, 0xf2, 0x10, 0x1a, 0xbe,
+			       0x4a, 0xe0, 0xe3, 0x00, 0xf8 );
+	MEMCPY_TEST_CONSTANT ( 0x40, 0xa8, 0x28, 0x5b, 0x12, 0x0d, 0x80, 0x8e,
+			       0x8a, 0xd9, 0x92, 0x7a, 0x6e, 0x48, 0x8d, 0x14,
+			       0x4b, 0xc6, 0xce, 0x21, 0x2f, 0x0e, 0x47, 0xbd,
+			       0xf1, 0xca, 0x0e, 0x1f, 0x65, 0xc4 );
+	MEMCPY_TEST_CONSTANT ( 0x84, 0x83, 0x44, 0xe8, 0x1c, 0xbf, 0x23, 0x05,
+			       0xdf, 0xed, 0x3b, 0xb7, 0x0b, 0x4a, 0x05, 0xec,
+			       0xb7, 0x6f, 0x1c, 0xfe, 0x05, 0x05, 0x4e, 0xd1,
+			       0x50, 0x88, 0x81, 0x87, 0x68, 0xf6, 0x66 );
+	MEMCPY_TEST_CONSTANT ( 0x0d, 0x1d, 0xcf, 0x3e, 0x7c, 0xf8, 0x12, 0x1b,
+			       0x96, 0x7f, 0xff, 0x27, 0xca, 0xfe, 0xd3, 0x8b,
+			       0x10, 0xb9, 0x5d, 0x05, 0xad, 0x50, 0xed, 0x35,
+			       0x32, 0x9c, 0xe6, 0x3b, 0x73, 0xe0, 0x7d );
+
+	/* Speed tests */
+	memcpy_test_speed ( 0, 0, 64 );
+	memcpy_test_speed ( 0, 0, 128 );
+	memcpy_test_speed ( 0, 0, 256 );
+	for ( dest_offset = 0 ; dest_offset < 4 ; dest_offset++ ) {
+		for ( src_offset = 0 ; src_offset < 4 ; src_offset++ ) {
+			memcpy_test_speed ( dest_offset, src_offset, 4096 );
+		}
+	}
+}
 
-#define __regparm __attribute__ (( regparm(3) ))
-
-void __regparm memcpy_0 ( void *dest, void *src ) { memcpy ( dest, src, 0 ); }
-void __regparm memcpy_1 ( void *dest, void *src ) { memcpy ( dest, src, 1 ); }
-void __regparm memcpy_2 ( void *dest, void *src ) { memcpy ( dest, src, 2 ); }
-void __regparm memcpy_3 ( void *dest, void *src ) { memcpy ( dest, src, 3 ); }
-void __regparm memcpy_4 ( void *dest, void *src ) { memcpy ( dest, src, 4 ); }
-void __regparm memcpy_5 ( void *dest, void *src ) { memcpy ( dest, src, 5 ); }
-void __regparm memcpy_6 ( void *dest, void *src ) { memcpy ( dest, src, 6 ); }
-void __regparm memcpy_7 ( void *dest, void *src ) { memcpy ( dest, src, 7 ); }
-void __regparm memcpy_8 ( void *dest, void *src ) { memcpy ( dest, src, 8 ); }
-void __regparm memcpy_9 ( void *dest, void *src ) { memcpy ( dest, src, 9 ); }
-void __regparm memcpy_10 ( void *dest, void *src ) { memcpy ( dest, src, 10 ); }
-void __regparm memcpy_11 ( void *dest, void *src ) { memcpy ( dest, src, 11 ); }
-void __regparm memcpy_12 ( void *dest, void *src ) { memcpy ( dest, src, 12 ); }
-void __regparm memcpy_13 ( void *dest, void *src ) { memcpy ( dest, src, 13 ); }
-void __regparm memcpy_14 ( void *dest, void *src ) { memcpy ( dest, src, 14 ); }
-void __regparm memcpy_15 ( void *dest, void *src ) { memcpy ( dest, src, 15 ); }
-void __regparm memcpy_16 ( void *dest, void *src ) { memcpy ( dest, src, 16 ); }
-void __regparm memcpy_17 ( void *dest, void *src ) { memcpy ( dest, src, 17 ); }
-void __regparm memcpy_18 ( void *dest, void *src ) { memcpy ( dest, src, 18 ); }
-void __regparm memcpy_19 ( void *dest, void *src ) { memcpy ( dest, src, 19 ); }
-void __regparm memcpy_20 ( void *dest, void *src ) { memcpy ( dest, src, 20 ); }
-void __regparm memcpy_21 ( void *dest, void *src ) { memcpy ( dest, src, 21 ); }
-void __regparm memcpy_22 ( void *dest, void *src ) { memcpy ( dest, src, 22 ); }
-void __regparm memcpy_23 ( void *dest, void *src ) { memcpy ( dest, src, 23 ); }
-void __regparm memcpy_24 ( void *dest, void *src ) { memcpy ( dest, src, 24 ); }
-void __regparm memcpy_25 ( void *dest, void *src ) { memcpy ( dest, src, 25 ); }
-void __regparm memcpy_26 ( void *dest, void *src ) { memcpy ( dest, src, 26 ); }
-void __regparm memcpy_27 ( void *dest, void *src ) { memcpy ( dest, src, 27 ); }
-void __regparm memcpy_28 ( void *dest, void *src ) { memcpy ( dest, src, 28 ); }
+/** memcpy() self-test */
+struct self_test memcpy_test __self_test = {
+	.name = "memcpy",
+	.exec = memcpy_test_exec,
+};
diff --git a/roms/ipxe/src/tests/ocsp_test.c b/roms/ipxe/src/tests/ocsp_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..24405db80c66145b578d9b36376863a996f59aea
--- /dev/null
+++ b/roms/ipxe/src/tests/ocsp_test.c
@@ -0,0 +1,1450 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * OCSP tests
+ *
+ *
+ * Test vectors generated using OpenSSL:
+ *
+ *     openssl ocsp -no_nonce -issuer issuer.crt -cert cert.crt \
+ *		    -url http://ocsp.server.address \
+ *		    -reqout request.der -respout response.der
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ipxe/x509.h>
+#include <ipxe/ocsp.h>
+#include <ipxe/test.h>
+
+/** An OCSP test certificate */
+struct ocsp_test_certificate {
+	/** Data */
+	const void *data;
+	/** Length of data */
+	size_t len;
+	/** Parsed certificate */
+	struct x509_certificate *cert;
+};
+
+/** An OCSP test */
+struct ocsp_test {
+	/** Certificate */
+	struct ocsp_test_certificate *cert;
+	/** Issuing certificate */
+	struct ocsp_test_certificate *issuer;
+	/** Request */
+	const void *request;
+	/** Length of request */
+	size_t request_len;
+	/** Response */
+	const void *response;
+	/** Length of response */
+	size_t response_len;
+	/* OCSP check */
+	struct ocsp_check *ocsp;
+};
+
+/** Define inline data */
+#define DATA(...) { __VA_ARGS__ }
+
+/** Define a test certificate */
+#define CERTIFICATE( name, DATA, FINGERPRINT )				\
+	static const uint8_t name ## _data[] = DATA;			\
+	static struct ocsp_test_certificate name = {			\
+		.data = name ## _data,					\
+		.len = sizeof ( name ## _data ),			\
+	}
+
+/** Define an OCSP test */
+#define OCSP( name, CERT, ISSUER, REQUEST, RESPONSE )			\
+	static const uint8_t name ## _request[] = REQUEST;		\
+	static const uint8_t name ## _response[] = RESPONSE;		\
+	static struct ocsp_test name = {				\
+		.cert = CERT,						\
+		.issuer = ISSUER,					\
+		.request = name ## _request,				\
+		.request_len = sizeof ( name ## _request ),		\
+		.response = name ## _response,				\
+		.response_len = sizeof ( name ## _response ),		\
+	 }
+
+/**
+ * Prepare an OCSP test
+ *
+ * @v test		OCSP test
+ */
+static void ocsp_prepare_test ( struct ocsp_test *test ) {
+	struct x509_certificate *cert = test->cert->cert;
+	struct x509_certificate *issuer = test->issuer->cert;
+
+	/* Invalidate certificate being checked */
+	x509_invalidate ( cert );
+
+	/* Force-validate issuer certificate */
+	issuer->valid = 1;
+	issuer->path_remaining = ( issuer->extensions.basic.path_len + 1 );
+}
+
+/*
+ * subject	bank.barclays.co.uk
+ * issuer	VeriSign Class 3 International Server CA - G3
+ */
+CERTIFICATE ( barclays_crt,
+	DATA ( 0x30, 0x82, 0x05, 0x7b, 0x30, 0x82, 0x04, 0x63, 0xa0, 0x03,
+	       0x02, 0x01, 0x02, 0x02, 0x10, 0x49, 0x83, 0xfc, 0x05, 0x76,
+	       0xdf, 0x36, 0x91, 0x7c, 0x64, 0x2a, 0x27, 0xc1, 0xf1, 0x48,
+	       0xe3, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0xbc, 0x31,
+	       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+	       0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67,
+	       0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30,
+	       0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, 0x65,
+	       0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75,
+	       0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
+	       0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
+	       0x32, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x20, 0x6f, 0x66, 0x20,
+	       0x75, 0x73, 0x65, 0x20, 0x61, 0x74, 0x20, 0x68, 0x74, 0x74,
+	       0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76,
+	       0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f,
+	       0x6d, 0x2f, 0x72, 0x70, 0x61, 0x20, 0x28, 0x63, 0x29, 0x31,
+	       0x30, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03,
+	       0x13, 0x2d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e,
+	       0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x49,
+	       0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	       0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
+	       0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x1e, 0x17,
+	       0x0d, 0x31, 0x31, 0x31, 0x32, 0x30, 0x35, 0x30, 0x30, 0x30,
+	       0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x32, 0x31, 0x32,
+	       0x30, 0x34, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30,
+	       0x7f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+	       0x13, 0x02, 0x47, 0x42, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03,
+	       0x55, 0x04, 0x08, 0x13, 0x07, 0x45, 0x6e, 0x67, 0x6c, 0x61,
+	       0x6e, 0x64, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
+	       0x07, 0x14, 0x0a, 0x47, 0x6c, 0x6f, 0x75, 0x63, 0x65, 0x73,
+	       0x74, 0x65, 0x72, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55,
+	       0x04, 0x0a, 0x14, 0x11, 0x42, 0x61, 0x72, 0x63, 0x6c, 0x61,
+	       0x79, 0x73, 0x20, 0x42, 0x61, 0x6e, 0x6b, 0x20, 0x50, 0x6c,
+	       0x63, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0b,
+	       0x14, 0x06, 0x47, 0x4c, 0x4f, 0x2d, 0x4c, 0x32, 0x31, 0x1c,
+	       0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x14, 0x13, 0x62,
+	       0x61, 0x6e, 0x6b, 0x2e, 0x62, 0x61, 0x72, 0x63, 0x6c, 0x61,
+	       0x79, 0x73, 0x2e, 0x63, 0x6f, 0x2e, 0x75, 0x6b, 0x30, 0x82,
+	       0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+	       0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
+	       0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
+	       0x00, 0x99, 0x4c, 0x2e, 0x00, 0xa0, 0xaf, 0xe2, 0xbc, 0x52,
+	       0x43, 0x83, 0x34, 0x03, 0x58, 0xdf, 0xd3, 0xea, 0x43, 0xa2,
+	       0xfd, 0x2c, 0x4c, 0x3c, 0x32, 0x9c, 0x60, 0x40, 0xe5, 0xa1,
+	       0x07, 0x8d, 0x32, 0x21, 0xc1, 0xbd, 0xf1, 0x04, 0x2e, 0x90,
+	       0xf3, 0x05, 0x30, 0xd4, 0x6f, 0x81, 0x3e, 0x08, 0xb6, 0xc3,
+	       0xc1, 0xcf, 0xc4, 0x59, 0x7c, 0x56, 0x27, 0xea, 0x74, 0xe7,
+	       0x8f, 0x50, 0xd1, 0xa9, 0x13, 0x57, 0x3a, 0x05, 0x5a, 0xd7,
+	       0x7f, 0xfc, 0xc5, 0xc6, 0x66, 0xec, 0xa4, 0x03, 0xec, 0x97,
+	       0x1a, 0x4b, 0x28, 0xf9, 0xc9, 0xf4, 0xea, 0xc6, 0x89, 0x68,
+	       0xc1, 0x42, 0xcd, 0x80, 0xfc, 0xeb, 0x86, 0x6d, 0x1c, 0xd6,
+	       0xa1, 0x05, 0x16, 0xa4, 0xcf, 0x82, 0x1d, 0x07, 0x67, 0x7c,
+	       0xeb, 0xa1, 0x69, 0xf3, 0xf2, 0x21, 0xa7, 0x79, 0xf5, 0xf2,
+	       0xdc, 0xb6, 0x0b, 0x6e, 0x19, 0xcc, 0x50, 0x53, 0xf3, 0xbd,
+	       0xb9, 0x71, 0xdc, 0x2b, 0x15, 0x78, 0x6d, 0xd4, 0xd3, 0x82,
+	       0xce, 0x37, 0x0c, 0xb5, 0x5e, 0x24, 0x8d, 0x80, 0x40, 0x71,
+	       0x4e, 0x7b, 0x0a, 0x6e, 0x30, 0x4b, 0xb6, 0x2c, 0x23, 0x9e,
+	       0xd5, 0x08, 0x7d, 0x8a, 0x72, 0x46, 0xf6, 0x52, 0x98, 0xcb,
+	       0x03, 0x79, 0x61, 0xfe, 0xc1, 0x97, 0x15, 0x4b, 0x05, 0x36,
+	       0x0c, 0x11, 0xe9, 0x95, 0x4b, 0xef, 0xf3, 0x2d, 0xf3, 0xef,
+	       0x33, 0x6c, 0xc6, 0x98, 0xb9, 0x65, 0xe3, 0x3c, 0x26, 0x86,
+	       0xb5, 0x87, 0x9e, 0x20, 0x92, 0x7b, 0x8f, 0x13, 0x66, 0x5e,
+	       0x26, 0x09, 0xd6, 0x83, 0xee, 0x56, 0x72, 0x08, 0x6c, 0x2a,
+	       0x4c, 0xf2, 0x5b, 0xf1, 0x08, 0x4b, 0x91, 0x9e, 0x67, 0x37,
+	       0x2f, 0xc5, 0xcf, 0x1a, 0xa8, 0xa1, 0x1c, 0xb6, 0x2d, 0xd0,
+	       0x81, 0xf4, 0xf7, 0x37, 0xb9, 0xa3, 0x37, 0x3f, 0x6b, 0x2f,
+	       0x62, 0x82, 0xa7, 0x17, 0xc1, 0x8c, 0x69, 0x02, 0x03, 0x01,
+	       0x00, 0x01, 0xa3, 0x82, 0x01, 0xb3, 0x30, 0x82, 0x01, 0xaf,
+	       0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30,
+	       0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04,
+	       0x03, 0x02, 0x05, 0xa0, 0x30, 0x41, 0x06, 0x03, 0x55, 0x1d,
+	       0x1f, 0x04, 0x3a, 0x30, 0x38, 0x30, 0x36, 0xa0, 0x34, 0xa0,
+	       0x32, 0x86, 0x30, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
+	       0x53, 0x56, 0x52, 0x49, 0x6e, 0x74, 0x6c, 0x2d, 0x47, 0x33,
+	       0x2d, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73,
+	       0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x56,
+	       0x52, 0x49, 0x6e, 0x74, 0x6c, 0x47, 0x33, 0x2e, 0x63, 0x72,
+	       0x6c, 0x30, 0x44, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3d,
+	       0x30, 0x3b, 0x30, 0x39, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01,
+	       0x86, 0xf8, 0x45, 0x01, 0x07, 0x17, 0x03, 0x30, 0x2a, 0x30,
+	       0x28, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02,
+	       0x01, 0x16, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f,
+	       0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73,
+	       0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x70,
+	       0x61, 0x30, 0x28, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x21,
+	       0x30, 0x1f, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8,
+	       0x42, 0x04, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
+	       0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
+	       0x07, 0x03, 0x02, 0x30, 0x72, 0x06, 0x08, 0x2b, 0x06, 0x01,
+	       0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x66, 0x30, 0x64, 0x30,
+	       0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30,
+	       0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
+	       0x6f, 0x63, 0x73, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73,
+	       0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x3c, 0x06,
+	       0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86,
+	       0x30, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x53, 0x56,
+	       0x52, 0x49, 0x6e, 0x74, 0x6c, 0x2d, 0x47, 0x33, 0x2d, 0x61,
+	       0x69, 0x61, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67,
+	       0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x56, 0x52, 0x49,
+	       0x6e, 0x74, 0x6c, 0x47, 0x33, 0x2e, 0x63, 0x65, 0x72, 0x30,
+	       0x6e, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01,
+	       0x0c, 0x04, 0x62, 0x30, 0x60, 0xa1, 0x5e, 0xa0, 0x5c, 0x30,
+	       0x5a, 0x30, 0x58, 0x30, 0x56, 0x16, 0x09, 0x69, 0x6d, 0x61,
+	       0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x30, 0x21, 0x30, 0x1f,
+	       0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04,
+	       0x14, 0x4b, 0x6b, 0xb9, 0x28, 0x96, 0x06, 0x0c, 0xbb, 0xd0,
+	       0x52, 0x38, 0x9b, 0x29, 0xac, 0x4b, 0x07, 0x8b, 0x21, 0x05,
+	       0x18, 0x30, 0x26, 0x16, 0x24, 0x68, 0x74, 0x74, 0x70, 0x3a,
+	       0x2f, 0x2f, 0x6c, 0x6f, 0x67, 0x6f, 0x2e, 0x76, 0x65, 0x72,
+	       0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+	       0x76, 0x73, 0x6c, 0x6f, 0x67, 0x6f, 0x31, 0x2e, 0x67, 0x69,
+	       0x66, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
+	       0x00, 0x49, 0xf3, 0x7c, 0x15, 0xb0, 0x50, 0x97, 0xb7, 0xcd,
+	       0x87, 0x75, 0x85, 0xcc, 0x55, 0x7c, 0x62, 0x97, 0x97, 0x04,
+	       0xbd, 0xc2, 0x22, 0xfc, 0xf5, 0x2c, 0x75, 0xdc, 0x25, 0x6d,
+	       0xed, 0xcd, 0x22, 0x2e, 0xa4, 0xcd, 0x88, 0x95, 0xe8, 0x52,
+	       0x45, 0x7a, 0xa0, 0x85, 0xcc, 0x6d, 0x1c, 0xcb, 0xd8, 0xc3,
+	       0x26, 0x2c, 0xee, 0xb5, 0xe1, 0x38, 0x3f, 0xb6, 0x96, 0x10,
+	       0xa3, 0xb3, 0x1e, 0x2d, 0xdc, 0xe8, 0x07, 0x2f, 0xc2, 0xb7,
+	       0x50, 0xd5, 0x60, 0x73, 0x0d, 0x43, 0xb1, 0xaf, 0xd9, 0xcb,
+	       0x39, 0x00, 0xc7, 0x00, 0xb3, 0x1f, 0xa4, 0xaf, 0xf8, 0xed,
+	       0x9b, 0x6a, 0x7a, 0x10, 0xcc, 0x81, 0x92, 0xc2, 0x58, 0x7e,
+	       0x42, 0xe4, 0xbf, 0xcf, 0x8c, 0x91, 0x7f, 0xde, 0xe6, 0xac,
+	       0x37, 0x31, 0x58, 0x90, 0xee, 0x51, 0xf5, 0x0e, 0xe5, 0x84,
+	       0xd8, 0x51, 0x89, 0x50, 0xfe, 0xfa, 0xad, 0xc9, 0xbb, 0x19,
+	       0xb3, 0x4a, 0xc8, 0x6b, 0x26, 0x98, 0x4b, 0x63, 0x41, 0x81,
+	       0xe1, 0x12, 0xab, 0xcc, 0x89, 0xbe, 0xdf, 0xa8, 0x7e, 0xf5,
+	       0x0e, 0x07, 0xf6, 0x92, 0x89, 0x64, 0x3b, 0xc2, 0x64, 0xa2,
+	       0x4b, 0xd1, 0x6b, 0x9b, 0x4e, 0x6a, 0xf2, 0x63, 0xf7, 0xc3,
+	       0xe0, 0x9f, 0xc5, 0x4e, 0xb6, 0x77, 0x0a, 0xad, 0x6d, 0x0f,
+	       0x30, 0x87, 0x6b, 0xfb, 0x66, 0xb3, 0x90, 0x87, 0xa3, 0x48,
+	       0xbe, 0xa4, 0x34, 0x9c, 0x5a, 0x93, 0xa3, 0x74, 0x0e, 0x36,
+	       0x8e, 0xf6, 0x3b, 0x6c, 0xae, 0xa0, 0x6a, 0xa1, 0x1a, 0x12,
+	       0x78, 0x99, 0x75, 0x50, 0xb1, 0x72, 0xed, 0x22, 0x34, 0x0f,
+	       0xe1, 0x89, 0xfe, 0x81, 0x0a, 0xcc, 0x2a, 0xd0, 0xf3, 0x25,
+	       0xe6, 0xd9, 0x19, 0x06, 0x20, 0x2d, 0x29, 0x8b, 0xdd, 0xb5,
+	       0x60, 0xf4, 0x0d, 0x08, 0x97, 0x7b, 0x81, 0x4a, 0xfb, 0x20,
+	       0xfb, 0x83, 0xa3, 0xc8, 0x1d, 0x79, 0xb9 ),
+	FINGERPRINT ( 0x7e, 0x54, 0x41, 0x60, 0x21, 0xca, 0x3e, 0x63,
+		      0xce, 0x5a, 0x41, 0x6c, 0xbe, 0x52, 0x01, 0x88,
+		      0xcf, 0x41, 0x36, 0x48, 0xdb, 0xe3, 0xdf, 0x8e,
+		      0x79, 0x73, 0x5f, 0xcf, 0x8e, 0x8e, 0xac, 0xd8 ) );
+
+/*
+ * subject	www.google.com
+ * issuer	Thawte SGC CA
+ */
+CERTIFICATE ( google_crt,
+	DATA ( 0x30, 0x82, 0x03, 0x21, 0x30, 0x82, 0x02, 0x8a, 0xa0, 0x03,
+	       0x02, 0x01, 0x02, 0x02, 0x10, 0x4f, 0x9d, 0x96, 0xd9, 0x66,
+	       0xb0, 0x99, 0x2b, 0x54, 0xc2, 0x95, 0x7c, 0xb4, 0x15, 0x7d,
+	       0x4d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x4c, 0x31, 0x0b,
+	       0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x5a,
+	       0x41, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a,
+	       0x13, 0x1c, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x43,
+	       0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x20,
+	       0x28, 0x50, 0x74, 0x79, 0x29, 0x20, 0x4c, 0x74, 0x64, 0x2e,
+	       0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+	       0x0d, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x53, 0x47,
+	       0x43, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31,
+	       0x31, 0x30, 0x32, 0x36, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+	       0x5a, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x39, 0x33, 0x30, 0x32,
+	       0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x68, 0x31, 0x0b,
+	       0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+	       0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
+	       0x13, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
+	       0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04,
+	       0x07, 0x14, 0x0d, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69,
+	       0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11,
+	       0x06, 0x03, 0x55, 0x04, 0x0a, 0x14, 0x0a, 0x47, 0x6f, 0x6f,
+	       0x67, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x17, 0x30,
+	       0x15, 0x06, 0x03, 0x55, 0x04, 0x03, 0x14, 0x0e, 0x77, 0x77,
+	       0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63,
+	       0x6f, 0x6d, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+	       0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+	       0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81,
+	       0x00, 0xde, 0xb7, 0x26, 0x43, 0xa6, 0x99, 0x85, 0xcd, 0x38,
+	       0xa7, 0x15, 0x09, 0xb9, 0xcf, 0x0f, 0xc9, 0xc3, 0x55, 0x8c,
+	       0x88, 0xee, 0x8c, 0x8d, 0x28, 0x27, 0x24, 0x4b, 0x2a, 0x5e,
+	       0xa0, 0xd8, 0x16, 0xfa, 0x61, 0x18, 0x4b, 0xcf, 0x6d, 0x60,
+	       0x80, 0xd3, 0x35, 0x40, 0x32, 0x72, 0xc0, 0x8f, 0x12, 0xd8,
+	       0xe5, 0x4e, 0x8f, 0xb9, 0xb2, 0xf6, 0xd9, 0x15, 0x5e, 0x5a,
+	       0x86, 0x31, 0xa3, 0xba, 0x86, 0xaa, 0x6b, 0xc8, 0xd9, 0x71,
+	       0x8c, 0xcc, 0xcd, 0x27, 0x13, 0x1e, 0x9d, 0x42, 0x5d, 0x38,
+	       0xf6, 0xa7, 0xac, 0xef, 0xfa, 0x62, 0xf3, 0x18, 0x81, 0xd4,
+	       0x24, 0x46, 0x7f, 0x01, 0x77, 0x7c, 0xc6, 0x2a, 0x89, 0x14,
+	       0x99, 0xbb, 0x98, 0x39, 0x1d, 0xa8, 0x19, 0xfb, 0x39, 0x00,
+	       0x44, 0x7d, 0x1b, 0x94, 0x6a, 0x78, 0x2d, 0x69, 0xad, 0xc0,
+	       0x7a, 0x2c, 0xfa, 0xd0, 0xda, 0x20, 0x12, 0x98, 0xd3, 0x02,
+	       0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xe7, 0x30, 0x81, 0xe4,
+	       0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+	       0x04, 0x02, 0x30, 0x00, 0x30, 0x36, 0x06, 0x03, 0x55, 0x1d,
+	       0x1f, 0x04, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0xa0, 0x29, 0xa0,
+	       0x27, 0x86, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
+	       0x63, 0x72, 0x6c, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65,
+	       0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x54, 0x68, 0x61, 0x77, 0x74,
+	       0x65, 0x53, 0x47, 0x43, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x6c,
+	       0x30, 0x28, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x21, 0x30,
+	       0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
+	       0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
+	       0x02, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42,
+	       0x04, 0x01, 0x30, 0x72, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
+	       0x05, 0x07, 0x01, 0x01, 0x04, 0x66, 0x30, 0x64, 0x30, 0x22,
+	       0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01,
+	       0x86, 0x16, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f,
+	       0x63, 0x73, 0x70, 0x2e, 0x74, 0x68, 0x61, 0x77, 0x74, 0x65,
+	       0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x3e, 0x06, 0x08, 0x2b, 0x06,
+	       0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x32, 0x68, 0x74,
+	       0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x74,
+	       0x68, 0x61, 0x77, 0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+	       0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79,
+	       0x2f, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x5f, 0x53, 0x47,
+	       0x43, 0x5f, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x0d,
+	       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+	       0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x21, 0xac, 0xd5,
+	       0xae, 0xca, 0x34, 0x89, 0x5a, 0xc2, 0xab, 0x52, 0xd2, 0xb2,
+	       0x34, 0x66, 0x9d, 0x7a, 0xab, 0xee, 0xe6, 0x7c, 0xd5, 0x7e,
+	       0xc2, 0x5c, 0x28, 0xbb, 0x74, 0x00, 0xc9, 0x10, 0x1f, 0x42,
+	       0x13, 0xfc, 0x69, 0x8a, 0x1e, 0x24, 0xa0, 0x02, 0x00, 0xe9,
+	       0xba, 0x5b, 0xca, 0x19, 0x04, 0xb2, 0xd3, 0xaf, 0x01, 0xb2,
+	       0x7e, 0x5f, 0x14, 0xdb, 0xa6, 0xdb, 0x52, 0xb9, 0x9a, 0xf3,
+	       0x12, 0x7f, 0x7c, 0xa2, 0x9c, 0x3b, 0x6f, 0x99, 0x7d, 0xea,
+	       0x50, 0x0d, 0x76, 0x23, 0x12, 0xff, 0xf7, 0x66, 0x73, 0x29,
+	       0xb7, 0x95, 0x0a, 0xad, 0xd8, 0x8b, 0xb2, 0xde, 0x20, 0xe9,
+	       0x0a, 0x70, 0x64, 0x11, 0x08, 0xc8, 0x5a, 0xf1, 0x7d, 0x9e,
+	       0xec, 0x69, 0xa5, 0xa5, 0xd5, 0x82, 0xd7, 0x27, 0x1e, 0x9e,
+	       0x56, 0xcd, 0xd2, 0x76, 0xd5, 0x79, 0x2b, 0xf7, 0x25, 0x43,
+	       0x1c, 0x69, 0xf0, 0xb8, 0xf9 ),
+	FINGERPRINT ( 0xec, 0x6a, 0x6b, 0x15, 0x6b, 0x30, 0x62, 0xfa,
+		      0x99, 0x49, 0x9d, 0x1e, 0x15, 0x15, 0xcf, 0x6c,
+		      0x50, 0x48, 0xaf, 0x17, 0x94, 0x57, 0x48, 0x39,
+		      0x6b, 0xd2, 0xec, 0xf1, 0x2b, 0x8d, 0xe2, 0x2c ) );
+
+/*
+ * subject	VeriSign Class 3 International Server CA - G3
+ * issuer	VeriSign Class 3 Public Primary Certification Authority - G5
+ */
+CERTIFICATE ( verisign_crt,
+	DATA ( 0x30, 0x82, 0x06, 0x29, 0x30, 0x82, 0x05, 0x11, 0xa0, 0x03,
+	       0x02, 0x01, 0x02, 0x02, 0x10, 0x64, 0x1b, 0xe8, 0x20, 0xce,
+	       0x02, 0x08, 0x13, 0xf3, 0x2d, 0x4d, 0x2d, 0x95, 0xd6, 0x7e,
+	       0x67, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0xca, 0x31,
+	       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+	       0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67,
+	       0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30,
+	       0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, 0x65,
+	       0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75,
+	       0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
+	       0x31, 0x3a, 0x30, 0x38, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
+	       0x31, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 0x20,
+	       0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20,
+	       0x49, 0x6e, 0x63, 0x2e, 0x20, 0x2d, 0x20, 0x46, 0x6f, 0x72,
+	       0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65,
+	       0x64, 0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79,
+	       0x31, 0x45, 0x30, 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+	       0x3c, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20,
+	       0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x50, 0x75,
+	       0x62, 0x6c, 0x69, 0x63, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61,
+	       0x72, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+	       0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74,
+	       0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x2d, 0x20, 0x47,
+	       0x35, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x32, 0x30,
+	       0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d,
+	       0x32, 0x30, 0x30, 0x32, 0x30, 0x37, 0x32, 0x33, 0x35, 0x39,
+	       0x35, 0x39, 0x5a, 0x30, 0x81, 0xbc, 0x31, 0x0b, 0x30, 0x09,
+	       0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+	       0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e,
+	       0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20,
+	       0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03,
+	       0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, 0x65, 0x72, 0x69, 0x53,
+	       0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20,
+	       0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3b, 0x30,
+	       0x39, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x32, 0x54, 0x65,
+	       0x72, 0x6d, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x65,
+	       0x20, 0x61, 0x74, 0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a,
+	       0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, 0x69,
+	       0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72,
+	       0x70, 0x61, 0x20, 0x28, 0x63, 0x29, 0x31, 0x30, 0x31, 0x36,
+	       0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x2d, 0x56,
+	       0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x43, 0x6c,
+	       0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x49, 0x6e, 0x74, 0x65,
+	       0x72, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x20,
+	       0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x20,
+	       0x2d, 0x20, 0x47, 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
+	       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+	       0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
+	       0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x99, 0xd6, 0x9c,
+	       0x62, 0xf0, 0x15, 0xf4, 0x81, 0x9a, 0x41, 0x08, 0x59, 0x8f,
+	       0x13, 0x9d, 0x17, 0xc9, 0x9f, 0x51, 0xdc, 0xda, 0xb1, 0x52,
+	       0xef, 0xff, 0xe3, 0x41, 0xdd, 0xe0, 0xdf, 0xc4, 0x28, 0xc6,
+	       0xe3, 0xad, 0x79, 0x1f, 0x27, 0x10, 0x98, 0xb8, 0xbb, 0x20,
+	       0x97, 0xc1, 0x28, 0x44, 0x41, 0x0f, 0xea, 0xa9, 0xa8, 0x52,
+	       0xcf, 0x4d, 0x4e, 0x1b, 0x8b, 0xbb, 0xb5, 0xc4, 0x76, 0xd9,
+	       0xcc, 0x56, 0x06, 0xee, 0xb3, 0x55, 0x20, 0x2a, 0xde, 0x15,
+	       0x8d, 0x71, 0xcb, 0x54, 0xc8, 0x6f, 0x17, 0xcd, 0x89, 0x00,
+	       0xe4, 0xdc, 0xff, 0xe1, 0xc0, 0x1f, 0x68, 0x71, 0xe9, 0xc7,
+	       0x29, 0x2e, 0x7e, 0xbc, 0x3b, 0xfc, 0xe5, 0xbb, 0xab, 0x26,
+	       0x54, 0x8b, 0x66, 0x90, 0xcd, 0xf6, 0x92, 0xb9, 0x31, 0x24,
+	       0x80, 0xbc, 0x9e, 0x6c, 0xd5, 0xfc, 0x7e, 0xd2, 0xe1, 0x4b,
+	       0x8c, 0xdc, 0x42, 0xfa, 0x44, 0x4b, 0x5f, 0xf8, 0x18, 0xb5,
+	       0x2e, 0x30, 0xf4, 0x3d, 0x12, 0x98, 0xd3, 0x62, 0x05, 0x73,
+	       0x54, 0xa6, 0x9c, 0xa2, 0x1d, 0xbe, 0x52, 0x83, 0x3a, 0x07,
+	       0x46, 0xc4, 0x3b, 0x02, 0x56, 0x21, 0xbf, 0xf2, 0x51, 0x4f,
+	       0xd0, 0xa6, 0x99, 0x39, 0xe9, 0xae, 0xa5, 0x3f, 0x89, 0x9b,
+	       0x9c, 0x7d, 0xfe, 0x4d, 0x60, 0x07, 0x25, 0x20, 0xf7, 0xbb,
+	       0xd7, 0x69, 0x83, 0x2b, 0x82, 0x93, 0x43, 0x37, 0xd9, 0x83,
+	       0x41, 0x1b, 0x6b, 0x0b, 0xab, 0x4a, 0x66, 0x84, 0x4f, 0x4a,
+	       0x8e, 0xde, 0x7e, 0x34, 0x99, 0x8e, 0x68, 0xd6, 0xca, 0x39,
+	       0x06, 0x9b, 0x4c, 0xb3, 0x9a, 0x48, 0x4d, 0x13, 0x46, 0xb4,
+	       0x58, 0x21, 0x04, 0xc4, 0xfb, 0xa0, 0x4d, 0xac, 0x2e, 0x4b,
+	       0x62, 0x12, 0xe3, 0xfb, 0x4d, 0xf6, 0xc9, 0x51, 0x00, 0x01,
+	       0x1f, 0xfc, 0x1e, 0x6a, 0x81, 0x2a, 0x38, 0xe0, 0xb9, 0x4f,
+	       0xd6, 0x2d, 0x45, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82,
+	       0x02, 0x15, 0x30, 0x82, 0x02, 0x11, 0x30, 0x12, 0x06, 0x03,
+	       0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06,
+	       0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x70, 0x06, 0x03,
+	       0x55, 0x1d, 0x20, 0x04, 0x69, 0x30, 0x67, 0x30, 0x65, 0x06,
+	       0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x07,
+	       0x17, 0x03, 0x30, 0x56, 0x30, 0x28, 0x06, 0x08, 0x2b, 0x06,
+	       0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74,
+	       0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e,
+	       0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63,
+	       0x6f, 0x6d, 0x2f, 0x63, 0x70, 0x73, 0x30, 0x2a, 0x06, 0x08,
+	       0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30, 0x1e,
+	       0x1a, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f,
+	       0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69,
+	       0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x70, 0x61,
+	       0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
+	       0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x6d, 0x06, 0x08,
+	       0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0c, 0x04, 0x61,
+	       0x30, 0x5f, 0xa1, 0x5d, 0xa0, 0x5b, 0x30, 0x59, 0x30, 0x57,
+	       0x30, 0x55, 0x16, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f,
+	       0x67, 0x69, 0x66, 0x30, 0x21, 0x30, 0x1f, 0x30, 0x07, 0x06,
+	       0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, 0x8f, 0xe5,
+	       0xd3, 0x1a, 0x86, 0xac, 0x8d, 0x8e, 0x6b, 0xc3, 0xcf, 0x80,
+	       0x6a, 0xd4, 0x48, 0x18, 0x2c, 0x7b, 0x19, 0x2e, 0x30, 0x25,
+	       0x16, 0x23, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6c,
+	       0x6f, 0x67, 0x6f, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69,
+	       0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x73, 0x6c,
+	       0x6f, 0x67, 0x6f, 0x2e, 0x67, 0x69, 0x66, 0x30, 0x34, 0x06,
+	       0x03, 0x55, 0x1d, 0x25, 0x04, 0x2d, 0x30, 0x2b, 0x06, 0x08,
+	       0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08,
+	       0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x09,
+	       0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01, 0x06,
+	       0x0a, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x08,
+	       0x01, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
+	       0x07, 0x01, 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, 0x06,
+	       0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86,
+	       0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63,
+	       0x73, 0x70, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67,
+	       0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x34, 0x06, 0x03, 0x55,
+	       0x1d, 0x1f, 0x04, 0x2d, 0x30, 0x2b, 0x30, 0x29, 0xa0, 0x27,
+	       0xa0, 0x25, 0x86, 0x23, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+	       0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73,
+	       0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x63,
+	       0x61, 0x33, 0x2d, 0x67, 0x35, 0x2e, 0x63, 0x72, 0x6c, 0x30,
+	       0x28, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x21, 0x30, 0x1f,
+	       0xa4, 0x1d, 0x30, 0x1b, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03,
+	       0x55, 0x04, 0x03, 0x13, 0x10, 0x56, 0x65, 0x72, 0x69, 0x53,
+	       0x69, 0x67, 0x6e, 0x4d, 0x50, 0x4b, 0x49, 0x2d, 0x32, 0x2d,
+	       0x37, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
+	       0x04, 0x14, 0xd7, 0x9b, 0x7c, 0xd8, 0x22, 0xa0, 0x15, 0xf7,
+	       0xdd, 0xad, 0x5f, 0xce, 0x29, 0x9b, 0x58, 0xc3, 0xbc, 0x46,
+	       0x00, 0xb5, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
+	       0x18, 0x30, 0x16, 0x80, 0x14, 0x7f, 0xd3, 0x65, 0xa7, 0xc2,
+	       0xdd, 0xec, 0xbb, 0xf0, 0x30, 0x09, 0xf3, 0x43, 0x39, 0xfa,
+	       0x02, 0xaf, 0x33, 0x31, 0x33, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+	       0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+	       0x03, 0x82, 0x01, 0x01, 0x00, 0x71, 0xb5, 0x7d, 0x73, 0x52,
+	       0x4a, 0xdd, 0xd7, 0x4d, 0x34, 0x2b, 0x2e, 0xaf, 0x94, 0x46,
+	       0xa5, 0x49, 0x50, 0x02, 0x4f, 0xf8, 0x2f, 0x17, 0x70, 0xf2,
+	       0x13, 0xdc, 0x1f, 0x21, 0x86, 0xaa, 0xc2, 0x4f, 0x7c, 0x37,
+	       0x3c, 0xd4, 0x46, 0x78, 0xae, 0x5d, 0x78, 0x6f, 0xd1, 0xba,
+	       0x5a, 0xbc, 0x10, 0xab, 0x58, 0x36, 0xc5, 0x8c, 0x62, 0x15,
+	       0x45, 0x60, 0x17, 0x21, 0xe2, 0xd5, 0x42, 0xa8, 0x77, 0xa1,
+	       0x55, 0xd8, 0x43, 0x04, 0x51, 0xf6, 0x6e, 0xba, 0x48, 0xe6,
+	       0x5d, 0x4c, 0xb7, 0x44, 0xd3, 0x3e, 0xa4, 0xd5, 0xd6, 0x33,
+	       0x9a, 0x9f, 0x0d, 0xe6, 0xd7, 0x4e, 0x96, 0x44, 0x95, 0x5a,
+	       0x6c, 0xd6, 0xa3, 0x16, 0x53, 0x0e, 0x98, 0x43, 0xce, 0xa4,
+	       0xb8, 0xc3, 0x66, 0x7a, 0x05, 0x5c, 0x62, 0x10, 0xe8, 0x1b,
+	       0x12, 0xdb, 0x7d, 0x2e, 0x76, 0x50, 0xff, 0xdf, 0xd7, 0x6b,
+	       0x1b, 0xcc, 0x8a, 0xcc, 0x71, 0xfa, 0xb3, 0x40, 0x56, 0x7c,
+	       0x33, 0x7a, 0x77, 0x94, 0x5b, 0xf5, 0x0b, 0x53, 0xfb, 0x0e,
+	       0x5f, 0xbc, 0x68, 0xfb, 0xaf, 0x2a, 0xee, 0x30, 0x37, 0x79,
+	       0x16, 0x93, 0x25, 0x7f, 0x4d, 0x10, 0xff, 0x57, 0xfb, 0xbf,
+	       0x6e, 0x3b, 0x33, 0x21, 0xde, 0x79, 0xdc, 0x86, 0x17, 0x59,
+	       0x2d, 0x43, 0x64, 0xb7, 0xa6, 0x66, 0x87, 0xea, 0xbc, 0x96,
+	       0x46, 0x19, 0x1a, 0x86, 0x8b, 0x6f, 0xd7, 0xb7, 0x49, 0x00,
+	       0x5b, 0xdb, 0xa3, 0xbf, 0x29, 0x9a, 0xee, 0xf7, 0xd3, 0x33,
+	       0xae, 0xa3, 0xf4, 0x9e, 0x4c, 0xca, 0x5e, 0x69, 0xd4, 0x1b,
+	       0xad, 0xb7, 0x90, 0x77, 0x6a, 0xd8, 0x59, 0x6f, 0x79, 0xab,
+	       0x01, 0xfa, 0x55, 0xf0, 0x8a, 0x21, 0x66, 0xe5, 0x65, 0x6e,
+	       0xfd, 0x7c, 0xd3, 0xdf, 0x1e, 0xeb, 0x7e, 0x3f, 0x06, 0x90,
+	       0xfb, 0x19, 0x0b, 0xd3, 0x06, 0x02, 0x1b, 0x78, 0x43, 0x99,
+	       0xa8 ),
+	FINGERPRINT ( 0x6e, 0x21, 0x87, 0x6c, 0xf1, 0x63, 0x47, 0x20,
+		      0x1f, 0x63, 0x7a, 0x17, 0x8c, 0xb4, 0x2b, 0x17,
+		      0x1d, 0x52, 0x37, 0x9a, 0xf7, 0xe5, 0xf5, 0xb6,
+		      0xf6, 0x75, 0x5b, 0x3e, 0xe9, 0xbb, 0x2e, 0xd4 ) );
+
+/*
+ * subject	Thawte SGC CA
+issuer= /C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
+ */
+CERTIFICATE ( thawte_crt,
+	DATA ( 0x30, 0x82, 0x03, 0x23, 0x30, 0x82, 0x02, 0x8c, 0xa0, 0x03,
+	       0x02, 0x01, 0x02, 0x02, 0x04, 0x30, 0x00, 0x00, 0x02, 0x30,
+	       0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+	       0x01, 0x05, 0x05, 0x00, 0x30, 0x5f, 0x31, 0x0b, 0x30, 0x09,
+	       0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+	       0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e,
+	       0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20,
+	       0x49, 0x6e, 0x63, 0x2e, 0x31, 0x37, 0x30, 0x35, 0x06, 0x03,
+	       0x55, 0x04, 0x0b, 0x13, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73,
+	       0x20, 0x33, 0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
+	       0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20, 0x43, 0x65,
+	       0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+	       0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+	       0x79, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x34, 0x30, 0x35, 0x31,
+	       0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d,
+	       0x31, 0x34, 0x30, 0x35, 0x31, 0x32, 0x32, 0x33, 0x35, 0x39,
+	       0x35, 0x39, 0x5a, 0x30, 0x4c, 0x31, 0x0b, 0x30, 0x09, 0x06,
+	       0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x5a, 0x41, 0x31, 0x25,
+	       0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c, 0x54,
+	       0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x73,
+	       0x75, 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x28, 0x50, 0x74,
+	       0x79, 0x29, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x16, 0x30,
+	       0x14, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0d, 0x54, 0x68,
+	       0x61, 0x77, 0x74, 0x65, 0x20, 0x53, 0x47, 0x43, 0x20, 0x43,
+	       0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+	       0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
+	       0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
+	       0xd4, 0xd3, 0x67, 0xd0, 0x8d, 0x15, 0x7f, 0xae, 0xcd, 0x31,
+	       0xfe, 0x7d, 0x1d, 0x91, 0xa1, 0x3f, 0x0b, 0x71, 0x3c, 0xac,
+	       0xcc, 0xc8, 0x64, 0xfb, 0x63, 0xfc, 0x32, 0x4b, 0x07, 0x94,
+	       0xbd, 0x6f, 0x80, 0xba, 0x2f, 0xe1, 0x04, 0x93, 0xc0, 0x33,
+	       0xfc, 0x09, 0x33, 0x23, 0xe9, 0x0b, 0x74, 0x2b, 0x71, 0xc4,
+	       0x03, 0xc6, 0xd2, 0xcd, 0xe2, 0x2f, 0xf5, 0x09, 0x63, 0xcd,
+	       0xff, 0x48, 0xa5, 0x00, 0xbf, 0xe0, 0xe7, 0xf3, 0x88, 0xb7,
+	       0x2d, 0x32, 0xde, 0x98, 0x36, 0xe6, 0x0a, 0xad, 0x00, 0x7b,
+	       0xc4, 0x64, 0x4a, 0x3b, 0x84, 0x75, 0x03, 0xf2, 0x70, 0x92,
+	       0x7d, 0x0e, 0x62, 0xf5, 0x21, 0xab, 0x69, 0x36, 0x84, 0x31,
+	       0x75, 0x90, 0xf8, 0xbf, 0xc7, 0x6c, 0x88, 0x1b, 0x06, 0x95,
+	       0x7c, 0xc9, 0xe5, 0xa8, 0xde, 0x75, 0xa1, 0x2c, 0x7a, 0x68,
+	       0xdf, 0xd5, 0xca, 0x1c, 0x87, 0x58, 0x60, 0x19, 0x02, 0x03,
+	       0x01, 0x00, 0x01, 0xa3, 0x81, 0xfe, 0x30, 0x81, 0xfb, 0x30,
+	       0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
+	       0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30,
+	       0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02,
+	       0x01, 0x06, 0x30, 0x11, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
+	       0x86, 0xf8, 0x42, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x01,
+	       0x06, 0x30, 0x28, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x21,
+	       0x30, 0x1f, 0xa4, 0x1d, 0x30, 0x1b, 0x31, 0x19, 0x30, 0x17,
+	       0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x50, 0x72, 0x69,
+	       0x76, 0x61, 0x74, 0x65, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x33,
+	       0x2d, 0x31, 0x35, 0x30, 0x31, 0x06, 0x03, 0x55, 0x1d, 0x1f,
+	       0x04, 0x2a, 0x30, 0x28, 0x30, 0x26, 0xa0, 0x24, 0xa0, 0x22,
+	       0x86, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63,
+	       0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67,
+	       0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x63, 0x61, 0x33,
+	       0x2e, 0x63, 0x72, 0x6c, 0x30, 0x32, 0x06, 0x08, 0x2b, 0x06,
+	       0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x26, 0x30, 0x24,
+	       0x30, 0x22, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
+	       0x30, 0x01, 0x86, 0x16, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+	       0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x74, 0x68, 0x61, 0x77,
+	       0x74, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x34, 0x06, 0x03,
+	       0x55, 0x1d, 0x25, 0x04, 0x2d, 0x30, 0x2b, 0x06, 0x08, 0x2b,
+	       0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b,
+	       0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x09, 0x60,
+	       0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01, 0x06, 0x0a,
+	       0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45, 0x01, 0x08, 0x01,
+	       0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+	       0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x55,
+	       0xac, 0x63, 0xea, 0xde, 0xa1, 0xdd, 0xd2, 0x90, 0x5f, 0x9f,
+	       0x0b, 0xce, 0x76, 0xbe, 0x13, 0x51, 0x8f, 0x93, 0xd9, 0x05,
+	       0x2b, 0xc8, 0x1b, 0x77, 0x4b, 0xad, 0x69, 0x50, 0xa1, 0xee,
+	       0xde, 0xdc, 0xfd, 0xdb, 0x07, 0xe9, 0xe8, 0x39, 0x94, 0xdc,
+	       0xab, 0x72, 0x79, 0x2f, 0x06, 0xbf, 0xab, 0x81, 0x70, 0xc4,
+	       0xa8, 0xed, 0xea, 0x53, 0x34, 0xed, 0xef, 0x1e, 0x53, 0xd9,
+	       0x06, 0xc7, 0x56, 0x2b, 0xd1, 0x5c, 0xf4, 0xd1, 0x8a, 0x8e,
+	       0xb4, 0x2b, 0xb1, 0x37, 0x90, 0x48, 0x08, 0x42, 0x25, 0xc5,
+	       0x3e, 0x8a, 0xcb, 0x7f, 0xeb, 0x6f, 0x04, 0xd1, 0x6d, 0xc5,
+	       0x74, 0xa2, 0xf7, 0xa2, 0x7c, 0x7b, 0x60, 0x3c, 0x77, 0xcd,
+	       0x0e, 0xce, 0x48, 0x02, 0x7f, 0x01, 0x2f, 0xb6, 0x9b, 0x37,
+	       0xe0, 0x2a, 0x2a, 0x36, 0xdc, 0xd5, 0x85, 0xd6, 0xac, 0xe5,
+	       0x3f, 0x54, 0x6f, 0x96, 0x1e, 0x05, 0xaf ),
+	FINGERPRINT ( 0x10, 0x85, 0xa6, 0xf4, 0x54, 0xd0, 0xc9, 0x11,
+		      0x98, 0xfd, 0xda, 0xb1, 0x1a, 0x31, 0xc7, 0x16,
+		      0xd5, 0xdc, 0xd6, 0x8d, 0xf9, 0x1c, 0x03, 0x9c,
+		      0xe1, 0x8d, 0xca, 0x9b, 0xeb, 0x3c, 0xde, 0x3d ) );
+
+/*
+ * subject	StartCom Class 2 Primary Intermediate Server CA
+ * issuer	StartCom Certification Authority
+ */
+CERTIFICATE ( startssl_crt,
+	DATA ( 0x30, 0x82, 0x07, 0xe3, 0x30, 0x82, 0x05, 0xcb, 0xa0, 0x03,
+	       0x02, 0x01, 0x02, 0x02, 0x01, 0x0b, 0x30, 0x0d, 0x06, 0x09,
+	       0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
+	       0x00, 0x30, 0x7d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+	       0x04, 0x06, 0x13, 0x02, 0x49, 0x4c, 0x31, 0x16, 0x30, 0x14,
+	       0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x53, 0x74, 0x61,
+	       0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, 0x2e,
+	       0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
+	       0x22, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x44, 0x69,
+	       0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72, 0x74,
+	       0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x69,
+	       0x67, 0x6e, 0x69, 0x6e, 0x67, 0x31, 0x29, 0x30, 0x27, 0x06,
+	       0x03, 0x55, 0x04, 0x03, 0x13, 0x20, 0x53, 0x74, 0x61, 0x72,
+	       0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
+	       0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41,
+	       0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x1e,
+	       0x17, 0x0d, 0x30, 0x37, 0x31, 0x30, 0x32, 0x34, 0x32, 0x30,
+	       0x35, 0x37, 0x30, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x32, 0x31,
+	       0x30, 0x32, 0x32, 0x32, 0x30, 0x35, 0x37, 0x30, 0x38, 0x5a,
+	       0x30, 0x81, 0x8c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+	       0x04, 0x06, 0x13, 0x02, 0x49, 0x4c, 0x31, 0x16, 0x30, 0x14,
+	       0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x53, 0x74, 0x61,
+	       0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, 0x2e,
+	       0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
+	       0x22, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x44, 0x69,
+	       0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72, 0x74,
+	       0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x69,
+	       0x67, 0x6e, 0x69, 0x6e, 0x67, 0x31, 0x38, 0x30, 0x36, 0x06,
+	       0x03, 0x55, 0x04, 0x03, 0x13, 0x2f, 0x53, 0x74, 0x61, 0x72,
+	       0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73,
+	       0x20, 0x32, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79,
+	       0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69,
+	       0x61, 0x74, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
+	       0x20, 0x43, 0x41, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06,
+	       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+	       0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01,
+	       0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xe2, 0x4f, 0x39, 0x2f,
+	       0xa1, 0x8c, 0x9a, 0x85, 0xad, 0x08, 0x0e, 0x08, 0x3e, 0x57,
+	       0xf2, 0x88, 0x01, 0x21, 0x1b, 0x94, 0xa9, 0x6c, 0xe2, 0xb8,
+	       0xdb, 0xaa, 0x19, 0x18, 0x46, 0x3a, 0x52, 0xa1, 0xf5, 0x0f,
+	       0xf4, 0x6e, 0x8c, 0xea, 0x96, 0x8c, 0x96, 0x87, 0x79, 0x13,
+	       0x40, 0x51, 0x2f, 0x22, 0xf2, 0x0c, 0x8b, 0x87, 0x0f, 0x65,
+	       0xdf, 0x71, 0x74, 0x34, 0x43, 0x55, 0xb1, 0x35, 0x09, 0x9b,
+	       0xd9, 0xbc, 0x1f, 0xfa, 0xeb, 0x42, 0xd0, 0x97, 0x40, 0x72,
+	       0xb7, 0x43, 0x96, 0x3d, 0xba, 0x96, 0x9d, 0x5d, 0x50, 0x02,
+	       0x1c, 0x9b, 0x91, 0x8d, 0x9c, 0xc0, 0xac, 0xd7, 0xbb, 0x2f,
+	       0x17, 0xd7, 0xcb, 0x3e, 0x82, 0x9d, 0x73, 0xeb, 0x07, 0x42,
+	       0x92, 0xb2, 0xcd, 0x64, 0xb3, 0x74, 0x55, 0x1b, 0xb4, 0x4b,
+	       0x86, 0x21, 0x2c, 0xf7, 0x78, 0x87, 0x32, 0xe0, 0x16, 0xe4,
+	       0xda, 0xbd, 0x4c, 0x95, 0xea, 0xa4, 0x0a, 0x7e, 0xb6, 0x0a,
+	       0x0d, 0x2e, 0x8a, 0xcf, 0x55, 0xab, 0xc3, 0xe5, 0xdd, 0x41,
+	       0x8a, 0x4e, 0xe6, 0x6f, 0x65, 0x6c, 0xb2, 0x40, 0xcf, 0x17,
+	       0x5d, 0xb9, 0xc3, 0x6a, 0x0b, 0x27, 0x11, 0x84, 0x77, 0x61,
+	       0xf6, 0xc2, 0x7c, 0xed, 0xc0, 0x8d, 0x78, 0x14, 0x18, 0x99,
+	       0x81, 0x99, 0x75, 0x63, 0xb7, 0xe8, 0x53, 0xd3, 0xba, 0x61,
+	       0xe9, 0x0e, 0xfa, 0xa2, 0x30, 0xf3, 0x46, 0xa2, 0xb9, 0xc9,
+	       0x1f, 0x6c, 0x80, 0x5a, 0x40, 0xac, 0x27, 0xed, 0x48, 0x47,
+	       0x33, 0xb0, 0x54, 0xc6, 0x46, 0x1a, 0xf3, 0x35, 0x61, 0xc1,
+	       0x02, 0x29, 0x90, 0x54, 0x7e, 0x64, 0x4d, 0xc4, 0x30, 0x52,
+	       0x02, 0x82, 0xd7, 0xdf, 0xce, 0x21, 0x6e, 0x18, 0x91, 0xd7,
+	       0xb8, 0xab, 0x8c, 0x27, 0x17, 0xb5, 0xf0, 0xa3, 0x01, 0x2f,
+	       0x8e, 0xd2, 0x2e, 0x87, 0x3a, 0x3d, 0xb4, 0x29, 0x67, 0x8a,
+	       0xc4, 0x03, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x03,
+	       0x5c, 0x30, 0x82, 0x03, 0x58, 0x30, 0x0c, 0x06, 0x03, 0x55,
+	       0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+	       0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02,
+	       0x01, 0xa6, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
+	       0x16, 0x04, 0x14, 0x11, 0xdb, 0x23, 0x45, 0xfd, 0x54, 0xcc,
+	       0x6a, 0x71, 0x6f, 0x84, 0x8a, 0x03, 0xd7, 0xbe, 0xf7, 0x01,
+	       0x2f, 0x26, 0x86, 0x30, 0x81, 0xa8, 0x06, 0x03, 0x55, 0x1d,
+	       0x23, 0x04, 0x81, 0xa0, 0x30, 0x81, 0x9d, 0x80, 0x14, 0x4e,
+	       0x0b, 0xef, 0x1a, 0xa4, 0x40, 0x5b, 0xa5, 0x17, 0x69, 0x87,
+	       0x30, 0xca, 0x34, 0x68, 0x43, 0xd0, 0x41, 0xae, 0xf2, 0xa1,
+	       0x81, 0x81, 0xa4, 0x7f, 0x30, 0x7d, 0x31, 0x0b, 0x30, 0x09,
+	       0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x4c, 0x31,
+	       0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d,
+	       0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x4c,
+	       0x74, 0x64, 0x2e, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55,
+	       0x04, 0x0b, 0x13, 0x22, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65,
+	       0x20, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x43,
+	       0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
+	       0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x31, 0x29,
+	       0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x20, 0x53,
+	       0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x65,
+	       0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
+	       0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
+	       0x79, 0x82, 0x01, 0x01, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d,
+	       0x12, 0x04, 0x02, 0x30, 0x00, 0x30, 0x3d, 0x06, 0x08, 0x2b,
+	       0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x31, 0x30,
+	       0x2f, 0x30, 0x2d, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
+	       0x07, 0x30, 0x02, 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a,
+	       0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x73, 0x74, 0x61, 0x72,
+	       0x74, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73,
+	       0x66, 0x73, 0x63, 0x61, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x60,
+	       0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x59, 0x30, 0x57, 0x30,
+	       0x2c, 0xa0, 0x2a, 0xa0, 0x28, 0x86, 0x26, 0x68, 0x74, 0x74,
+	       0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x73,
+	       0x74, 0x61, 0x72, 0x74, 0x63, 0x6f, 0x6d, 0x2e, 0x6f, 0x72,
+	       0x67, 0x2f, 0x73, 0x66, 0x73, 0x63, 0x61, 0x2d, 0x63, 0x72,
+	       0x6c, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x27, 0xa0, 0x25, 0xa0,
+	       0x23, 0x86, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
+	       0x63, 0x72, 0x6c, 0x2e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73,
+	       0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x66, 0x73,
+	       0x63, 0x61, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x82, 0x01, 0x5d,
+	       0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x82, 0x01, 0x54, 0x30,
+	       0x82, 0x01, 0x50, 0x30, 0x82, 0x01, 0x4c, 0x06, 0x0b, 0x2b,
+	       0x06, 0x01, 0x04, 0x01, 0x81, 0xb5, 0x37, 0x01, 0x01, 0x04,
+	       0x30, 0x82, 0x01, 0x3b, 0x30, 0x2f, 0x06, 0x08, 0x2b, 0x06,
+	       0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x23, 0x68, 0x74,
+	       0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x2e,
+	       0x73, 0x74, 0x61, 0x72, 0x74, 0x63, 0x6f, 0x6d, 0x2e, 0x6f,
+	       0x72, 0x67, 0x2f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e,
+	       0x70, 0x64, 0x66, 0x30, 0x35, 0x06, 0x08, 0x2b, 0x06, 0x01,
+	       0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x29, 0x68, 0x74, 0x74,
+	       0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x73,
+	       0x74, 0x61, 0x72, 0x74, 0x63, 0x6f, 0x6d, 0x2e, 0x6f, 0x72,
+	       0x67, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64,
+	       0x69, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x64, 0x66, 0x30, 0x81,
+	       0xd0, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02,
+	       0x02, 0x30, 0x81, 0xc3, 0x30, 0x27, 0x16, 0x20, 0x53, 0x74,
+	       0x61, 0x72, 0x74, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72,
+	       0x63, 0x69, 0x61, 0x6c, 0x20, 0x28, 0x53, 0x74, 0x61, 0x72,
+	       0x74, 0x43, 0x6f, 0x6d, 0x29, 0x20, 0x4c, 0x74, 0x64, 0x2e,
+	       0x30, 0x03, 0x02, 0x01, 0x01, 0x1a, 0x81, 0x97, 0x4c, 0x69,
+	       0x6d, 0x69, 0x74, 0x65, 0x64, 0x20, 0x4c, 0x69, 0x61, 0x62,
+	       0x69, 0x6c, 0x69, 0x74, 0x79, 0x2c, 0x20, 0x72, 0x65, 0x61,
+	       0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x74,
+	       0x69, 0x6f, 0x6e, 0x20, 0x2a, 0x4c, 0x65, 0x67, 0x61, 0x6c,
+	       0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f,
+	       0x6e, 0x73, 0x2a, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65,
+	       0x20, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20,
+	       0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+	       0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
+	       0x69, 0x74, 0x79, 0x20, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79,
+	       0x20, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65,
+	       0x20, 0x61, 0x74, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
+	       0x2f, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x73, 0x74, 0x61, 0x72,
+	       0x74, 0x63, 0x6f, 0x6d, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x70,
+	       0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70, 0x64, 0x66, 0x30,
+	       0x11, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42,
+	       0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x00, 0x07, 0x30, 0x51,
+	       0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01,
+	       0x0d, 0x04, 0x44, 0x16, 0x42, 0x53, 0x74, 0x61, 0x72, 0x74,
+	       0x43, 0x6f, 0x6d, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20,
+	       0x32, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x20,
+	       0x49, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61,
+	       0x74, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20, 0x53, 0x53,
+	       0x4c, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43,
+	       0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
+	       0x73, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01,
+	       0x00, 0x64, 0x82, 0x4c, 0x59, 0x5c, 0x0c, 0x6c, 0x16, 0xb6,
+	       0xa2, 0x39, 0x45, 0x11, 0x87, 0x98, 0xdf, 0x10, 0x33, 0xae,
+	       0x42, 0x9e, 0x25, 0xd1, 0xfd, 0x70, 0x53, 0x45, 0x5e, 0xf4,
+	       0x35, 0xc0, 0xe4, 0x30, 0x77, 0xe0, 0x9c, 0xf7, 0xef, 0x27,
+	       0xe5, 0x6e, 0x28, 0xef, 0xac, 0xd7, 0xf3, 0x16, 0xcc, 0xc1,
+	       0x6c, 0x53, 0x9c, 0x8f, 0x2d, 0x82, 0x6f, 0x94, 0xf7, 0x14,
+	       0x36, 0x17, 0xae, 0xb2, 0xe5, 0xa2, 0x3f, 0xa2, 0x83, 0x73,
+	       0xa4, 0xdf, 0xa8, 0xbb, 0xca, 0x01, 0x31, 0x6c, 0x9a, 0x43,
+	       0x08, 0xdd, 0x1a, 0x5d, 0xad, 0x4b, 0x6d, 0x7f, 0xf4, 0x7e,
+	       0xf0, 0x12, 0x3a, 0x05, 0xbf, 0xa7, 0x44, 0x10, 0x07, 0x17,
+	       0x44, 0x93, 0x50, 0xe3, 0x95, 0x29, 0xb3, 0xf4, 0x13, 0xd2,
+	       0x40, 0xe0, 0x3e, 0xdf, 0x3d, 0x3d, 0x39, 0x5e, 0x81, 0x48,
+	       0x0f, 0x32, 0xba, 0x48, 0xd5, 0x03, 0x1b, 0xf5, 0xf7, 0x4e,
+	       0x0a, 0x8e, 0x03, 0x8d, 0xfc, 0xca, 0x87, 0xe6, 0xc9, 0xdf,
+	       0x26, 0xdf, 0x84, 0x3a, 0x49, 0xb1, 0x99, 0x55, 0x3f, 0xd4,
+	       0x2c, 0xab, 0x78, 0x0d, 0x62, 0x03, 0x15, 0x9f, 0xb1, 0x45,
+	       0x4b, 0x23, 0x78, 0x62, 0x2a, 0xee, 0xeb, 0x7b, 0x60, 0x2d,
+	       0x77, 0x72, 0x1e, 0x61, 0x24, 0x69, 0x62, 0xe8, 0xe1, 0x35,
+	       0x3c, 0x82, 0x02, 0x40, 0x15, 0x32, 0x4b, 0x57, 0xcd, 0x97,
+	       0xb9, 0x29, 0x8f, 0xa4, 0xd7, 0x84, 0xdb, 0x09, 0xe5, 0x35,
+	       0x5b, 0x2f, 0x60, 0x59, 0x49, 0xe9, 0xd6, 0x59, 0xf5, 0xfa,
+	       0x5d, 0xc8, 0xcd, 0x4d, 0x94, 0x70, 0xc4, 0xe8, 0x3c, 0x35,
+	       0x01, 0x06, 0x75, 0xe8, 0x71, 0x9b, 0x7f, 0x2b, 0x10, 0xca,
+	       0x6b, 0x3f, 0xc0, 0xb3, 0x97, 0x72, 0xda, 0xff, 0x74, 0x16,
+	       0x8e, 0xfb, 0xfb, 0x9b, 0xe4, 0x05, 0xf0, 0x98, 0xe7, 0x15,
+	       0xac, 0xca, 0x24, 0xa2, 0xe7, 0x8a, 0xb4, 0xcf, 0x72, 0x31,
+	       0x2b, 0xe3, 0x31, 0x0e, 0x30, 0x5f, 0xd5, 0xcb, 0x94, 0xb3,
+	       0xee, 0x35, 0x04, 0xd3, 0x45, 0x07, 0x09, 0x14, 0x51, 0x8a,
+	       0xf5, 0x07, 0x31, 0x5e, 0x13, 0x2f, 0x5d, 0x0c, 0xd9, 0xd7,
+	       0x36, 0xa8, 0xb0, 0x52, 0x37, 0x94, 0xc2, 0x75, 0x9c, 0x5a,
+	       0x2e, 0xa8, 0xd1, 0xb0, 0x73, 0x6b, 0x69, 0xda, 0x0c, 0x3a,
+	       0xd6, 0x11, 0x6b, 0xac, 0x9d, 0xbc, 0x45, 0x32, 0x05, 0xe8,
+	       0x89, 0x77, 0xd5, 0xb7, 0xbe, 0xc0, 0xed, 0xcd, 0xcd, 0x4e,
+	       0x6d, 0x28, 0x58, 0x0a, 0xf0, 0xb4, 0x51, 0xc8, 0xcd, 0x86,
+	       0xd1, 0x89, 0x23, 0xc5, 0x23, 0xed, 0xcf, 0x10, 0xf9, 0x0e,
+	       0x6e, 0xd8, 0xc1, 0xd7, 0x3f, 0x80, 0xfa, 0xa6, 0x2a, 0x47,
+	       0xc4, 0xdb, 0x07, 0x16, 0xe7, 0x0b, 0x8b, 0x53, 0x97, 0x11,
+	       0x2e, 0xa3, 0x61, 0x27, 0xb3, 0xbb, 0x4a, 0xd7, 0x01, 0x6d,
+	       0xb1, 0x71, 0xa5, 0xe5, 0x23, 0xd6, 0xda, 0xa1, 0xa8, 0x55,
+	       0x26, 0xaf, 0xb7, 0xba, 0x5e, 0x56, 0x2d, 0x3d, 0x10, 0xa3,
+	       0x71, 0x4a, 0x93, 0x45, 0x1c, 0x7a, 0x3c, 0x92, 0x2a, 0x69,
+	       0x3f, 0x4f, 0x1e, 0x96, 0x99, 0x90, 0x09, 0xc8, 0x01, 0xbf,
+	       0x28, 0x34, 0xb2, 0x7d, 0x11, 0x50, 0x59, 0xd0, 0x9b, 0xe3,
+	       0x33, 0x56, 0x65, 0xee, 0x98, 0x97, 0x3f, 0x3e, 0x54, 0x69,
+	       0x2d, 0x26, 0x2e, 0x03, 0x2b, 0xa0, 0xbe, 0xab, 0x6b, 0x80,
+	       0x20, 0xe1, 0x3a, 0x4b, 0xbb, 0x26, 0xbe, 0xab, 0xab, 0xa5,
+	       0x39, 0xb1, 0x9a, 0x49, 0xa6, 0xb4, 0x5b, 0x96, 0x66, 0xe2,
+	       0x49, 0x0b, 0x70, 0x02, 0xaa, 0x49, 0x49, 0x61, 0x0e, 0xfe,
+	       0xae, 0xf5, 0xa5, 0x96, 0xe7, 0xf6, 0xba, 0x6c, 0x89, 0x9f,
+	       0x0e, 0x72, 0xec, 0xfb, 0x45, 0x00, 0x87, 0x8f, 0x2c, 0xe7,
+	       0x7f, 0xb2, 0xc5, 0xa5, 0x52, 0xbe, 0x03, 0xfa, 0x31, 0x2a,
+	       0x02, 0x6a, 0xf8 ),
+	FINGERPRINT ( 0x9f, 0xd1, 0x93, 0xd3, 0x8f, 0x95, 0x30, 0xab,
+		      0x55, 0xa5, 0xc1, 0xb3, 0x51, 0x4a, 0x1d, 0x64,
+		      0x1c, 0xec, 0xc2, 0x1c, 0xc5, 0xc2, 0xf5, 0x67,
+		      0x48, 0xa7, 0x11, 0x01, 0x69, 0x83, 0xfd, 0x8e ) );
+
+OCSP ( barclays_ocsp, &barclays_crt, &verisign_crt,
+	DATA ( 0x30, 0x51, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x4b, 0x30, 0x49,
+	       0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
+	       0x00, 0x04, 0x14, 0xd4, 0xb4, 0x3b, 0x8e, 0x3d, 0x02, 0x49,
+	       0x1a, 0x65, 0x50, 0x6f, 0x96, 0x73, 0x14, 0xdd, 0xe8, 0x59,
+	       0x44, 0x52, 0xe4, 0x04, 0x14, 0xd7, 0x9b, 0x7c, 0xd8, 0x22,
+	       0xa0, 0x15, 0xf7, 0xdd, 0xad, 0x5f, 0xce, 0x29, 0x9b, 0x58,
+	       0xc3, 0xbc, 0x46, 0x00, 0xb5, 0x02, 0x10, 0x49, 0x83, 0xfc,
+	       0x05, 0x76, 0xdf, 0x36, 0x91, 0x7c, 0x64, 0x2a, 0x27, 0xc1,
+	       0xf1, 0x48, 0xe3 ),
+	DATA ( 0x30, 0x82, 0x06, 0x4d, 0x0a, 0x01, 0x00, 0xa0, 0x82, 0x06,
+	       0x46, 0x30, 0x82, 0x06, 0x42, 0x06, 0x09, 0x2b, 0x06, 0x01,
+	       0x05, 0x05, 0x07, 0x30, 0x01, 0x01, 0x04, 0x82, 0x06, 0x33,
+	       0x30, 0x82, 0x06, 0x2f, 0x30, 0x82, 0x01, 0x1f, 0xa0, 0x03,
+	       0x02, 0x01, 0x00, 0xa1, 0x81, 0x91, 0x30, 0x81, 0x8e, 0x31,
+	       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+	       0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67,
+	       0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30,
+	       0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, 0x65,
+	       0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75,
+	       0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
+	       0x31, 0x45, 0x30, 0x43, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+	       0x3c, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20,
+	       0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x49, 0x6e,
+	       0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61,
+	       0x6c, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x43,
+	       0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x20, 0x4f, 0x43, 0x53,
+	       0x50, 0x20, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65,
+	       0x72, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x32, 0x30, 0x35, 0x31,
+	       0x34, 0x31, 0x34, 0x30, 0x31, 0x34, 0x31, 0x5a, 0x30, 0x73,
+	       0x30, 0x71, 0x30, 0x49, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
+	       0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0xd4, 0xb4, 0x3b,
+	       0x8e, 0x3d, 0x02, 0x49, 0x1a, 0x65, 0x50, 0x6f, 0x96, 0x73,
+	       0x14, 0xdd, 0xe8, 0x59, 0x44, 0x52, 0xe4, 0x04, 0x14, 0xd7,
+	       0x9b, 0x7c, 0xd8, 0x22, 0xa0, 0x15, 0xf7, 0xdd, 0xad, 0x5f,
+	       0xce, 0x29, 0x9b, 0x58, 0xc3, 0xbc, 0x46, 0x00, 0xb5, 0x02,
+	       0x10, 0x49, 0x83, 0xfc, 0x05, 0x76, 0xdf, 0x36, 0x91, 0x7c,
+	       0x64, 0x2a, 0x27, 0xc1, 0xf1, 0x48, 0xe3, 0x80, 0x00, 0x18,
+	       0x0f, 0x32, 0x30, 0x31, 0x32, 0x30, 0x35, 0x31, 0x34, 0x31,
+	       0x34, 0x30, 0x31, 0x34, 0x31, 0x5a, 0xa0, 0x11, 0x18, 0x0f,
+	       0x32, 0x30, 0x31, 0x32, 0x30, 0x35, 0x32, 0x31, 0x31, 0x34,
+	       0x30, 0x31, 0x34, 0x31, 0x5a, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+	       0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+	       0x03, 0x81, 0x81, 0x00, 0x78, 0xa8, 0xe7, 0xdc, 0xaf, 0xf2,
+	       0x8b, 0xc2, 0x9f, 0x99, 0xf9, 0x44, 0x84, 0xa8, 0x8a, 0x2c,
+	       0x35, 0xd7, 0x91, 0xd8, 0x44, 0x3e, 0xd6, 0xe0, 0xc6, 0x3f,
+	       0xbf, 0xe3, 0x71, 0x22, 0x45, 0x5a, 0x73, 0xf4, 0x59, 0x1b,
+	       0x4c, 0xa5, 0x51, 0x21, 0x5c, 0xfa, 0xbe, 0x10, 0xcb, 0x5f,
+	       0xb0, 0x2f, 0xef, 0x22, 0x89, 0xf6, 0xc7, 0x0f, 0x7c, 0x6d,
+	       0x26, 0xbe, 0x83, 0x99, 0xe2, 0x02, 0xf5, 0x95, 0x6e, 0xca,
+	       0xd9, 0x6d, 0xdd, 0xc2, 0xf0, 0xf2, 0x4f, 0x99, 0x66, 0x93,
+	       0x6e, 0x2e, 0xcf, 0xc5, 0xab, 0x68, 0x5f, 0xde, 0x52, 0x3d,
+	       0xf2, 0x23, 0x9d, 0xe8, 0x99, 0xd5, 0xf4, 0x4f, 0x8a, 0xf3,
+	       0xfd, 0x99, 0xa3, 0xe3, 0x12, 0x56, 0xd1, 0x54, 0xf1, 0xe1,
+	       0x24, 0xa0, 0xce, 0xeb, 0x80, 0xb6, 0xde, 0x44, 0xa8, 0xef,
+	       0xb1, 0xfc, 0x9c, 0x76, 0xbb, 0x1f, 0x17, 0x40, 0xbe, 0x2a,
+	       0xc8, 0x12, 0xa0, 0x82, 0x04, 0x75, 0x30, 0x82, 0x04, 0x71,
+	       0x30, 0x82, 0x04, 0x6d, 0x30, 0x82, 0x03, 0x55, 0xa0, 0x03,
+	       0x02, 0x01, 0x02, 0x02, 0x10, 0x68, 0x8e, 0x69, 0x1f, 0x05,
+	       0x02, 0x11, 0x40, 0x45, 0x8e, 0xf0, 0x39, 0x24, 0x07, 0xcf,
+	       0xd6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0xbc, 0x31,
+	       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+	       0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67,
+	       0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x1f, 0x30,
+	       0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, 0x65,
+	       0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75,
+	       0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
+	       0x31, 0x3b, 0x30, 0x39, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
+	       0x32, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x20, 0x6f, 0x66, 0x20,
+	       0x75, 0x73, 0x65, 0x20, 0x61, 0x74, 0x20, 0x68, 0x74, 0x74,
+	       0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76,
+	       0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f,
+	       0x6d, 0x2f, 0x72, 0x70, 0x61, 0x20, 0x28, 0x63, 0x29, 0x31,
+	       0x30, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03,
+	       0x13, 0x2d, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e,
+	       0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x49,
+	       0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	       0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
+	       0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x30, 0x1e, 0x17,
+	       0x0d, 0x31, 0x32, 0x30, 0x33, 0x31, 0x33, 0x30, 0x30, 0x30,
+	       0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x36,
+	       0x31, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30,
+	       0x81, 0x8e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+	       0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x17, 0x30, 0x15, 0x06,
+	       0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72, 0x69,
+	       0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+	       0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
+	       0x16, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20,
+	       0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77,
+	       0x6f, 0x72, 0x6b, 0x31, 0x45, 0x30, 0x43, 0x06, 0x03, 0x55,
+	       0x04, 0x03, 0x13, 0x3c, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69,
+	       0x67, 0x6e, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33,
+	       0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69,
+	       0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65,
+	       0x72, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x47, 0x33, 0x20,
+	       0x4f, 0x43, 0x53, 0x50, 0x20, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	       0x6e, 0x64, 0x65, 0x72, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06,
+	       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+	       0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02,
+	       0x81, 0x81, 0x00, 0xa4, 0x3c, 0x3c, 0x43, 0xd3, 0x33, 0x14,
+	       0x0a, 0xb4, 0x5e, 0x25, 0x03, 0x6d, 0x60, 0x6c, 0x2f, 0xc9,
+	       0x33, 0x11, 0xe6, 0x79, 0xd9, 0x8c, 0x4a, 0x05, 0x60, 0xad,
+	       0x16, 0x8b, 0x23, 0x67, 0x8b, 0x1a, 0xaf, 0x84, 0xc3, 0xbb,
+	       0x6b, 0xcf, 0x9e, 0xf7, 0x65, 0x6d, 0x04, 0x97, 0xca, 0x12,
+	       0x96, 0x0b, 0x30, 0x7f, 0x0d, 0x6e, 0x7f, 0x81, 0x49, 0x53,
+	       0xf3, 0xcb, 0x5c, 0x00, 0xd8, 0x6d, 0xf9, 0x03, 0xf4, 0x23,
+	       0xd6, 0xd2, 0x9e, 0x8c, 0xca, 0x41, 0xfd, 0xa1, 0x02, 0x20,
+	       0xc8, 0x70, 0xb0, 0xfb, 0xaa, 0x1b, 0x33, 0x1e, 0x64, 0x30,
+	       0x70, 0x36, 0xed, 0x7b, 0xac, 0xe8, 0x64, 0xd9, 0x79, 0xa8,
+	       0x48, 0x20, 0x02, 0xdd, 0x8c, 0x02, 0x6f, 0x87, 0x2f, 0xad,
+	       0x29, 0x99, 0x8e, 0x15, 0x2c, 0xd1, 0xe0, 0x64, 0x82, 0x24,
+	       0x77, 0x31, 0xee, 0xb8, 0x68, 0xd1, 0x02, 0x32, 0xfb, 0xf0,
+	       0xcd, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x19,
+	       0x30, 0x82, 0x01, 0x15, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d,
+	       0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x81, 0xac, 0x06, 0x03,
+	       0x55, 0x1d, 0x20, 0x04, 0x81, 0xa4, 0x30, 0x81, 0xa1, 0x30,
+	       0x81, 0x9e, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8,
+	       0x45, 0x01, 0x07, 0x17, 0x03, 0x30, 0x81, 0x8e, 0x30, 0x28,
+	       0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01,
+	       0x16, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f,
+	       0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73, 0x69,
+	       0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53,
+	       0x30, 0x62, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
+	       0x02, 0x02, 0x30, 0x56, 0x30, 0x15, 0x16, 0x0e, 0x56, 0x65,
+	       0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e,
+	       0x63, 0x2e, 0x30, 0x03, 0x02, 0x01, 0x01, 0x1a, 0x3d, 0x56,
+	       0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x27, 0x73, 0x20,
+	       0x43, 0x50, 0x53, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x72, 0x70,
+	       0x2e, 0x20, 0x62, 0x79, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72,
+	       0x65, 0x6e, 0x63, 0x65, 0x20, 0x6c, 0x69, 0x61, 0x62, 0x2e,
+	       0x20, 0x6c, 0x74, 0x64, 0x2e, 0x20, 0x28, 0x63, 0x29, 0x39,
+	       0x37, 0x20, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e,
+	       0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x0c, 0x30,
+	       0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
+	       0x09, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04,
+	       0x03, 0x02, 0x07, 0x80, 0x30, 0x0f, 0x06, 0x09, 0x2b, 0x06,
+	       0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x05, 0x04, 0x02, 0x05,
+	       0x00, 0x30, 0x26, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x1f,
+	       0x30, 0x1d, 0xa4, 0x1b, 0x30, 0x19, 0x31, 0x17, 0x30, 0x15,
+	       0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0e, 0x4f, 0x43, 0x53,
+	       0x50, 0x38, 0x2d, 0x54, 0x47, 0x56, 0x37, 0x2d, 0x32, 0x38,
+	       0x35, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01,
+	       0x00, 0x3b, 0xce, 0xd6, 0xa6, 0x61, 0x41, 0x3d, 0xb2, 0xc4,
+	       0x75, 0x00, 0x45, 0xf9, 0x3c, 0x2f, 0x2e, 0x4a, 0x8b, 0xfb,
+	       0x9c, 0xff, 0x15, 0xcb, 0x28, 0x65, 0xde, 0xc6, 0x97, 0xd8,
+	       0x85, 0x32, 0xa2, 0xfe, 0x74, 0x2d, 0xed, 0x34, 0xf8, 0x3c,
+	       0x15, 0xac, 0xfe, 0x72, 0x7f, 0x8c, 0x0e, 0x24, 0xdd, 0xb2,
+	       0x80, 0x55, 0xbd, 0x10, 0x0d, 0xa8, 0xb6, 0xf3, 0xe0, 0x98,
+	       0x8f, 0x24, 0x0b, 0xa0, 0x9d, 0x2c, 0x05, 0x20, 0x13, 0x4d,
+	       0x0b, 0x15, 0x2d, 0x1a, 0x02, 0x76, 0x0a, 0x5a, 0xb2, 0xb9,
+	       0xce, 0x6f, 0xb8, 0xc1, 0xec, 0xc4, 0xde, 0x46, 0xe4, 0xec,
+	       0x32, 0x05, 0x2d, 0xca, 0xb1, 0x4c, 0x59, 0x41, 0x13, 0x47,
+	       0x44, 0x9a, 0x55, 0x20, 0x26, 0xcc, 0x0d, 0x66, 0xb2, 0xd1,
+	       0x76, 0x87, 0x74, 0x73, 0xea, 0x5e, 0xe9, 0x49, 0xaf, 0x57,
+	       0x9c, 0xa6, 0x3d, 0xe5, 0x2c, 0x28, 0x21, 0xe5, 0x0a, 0x80,
+	       0xae, 0x99, 0x44, 0xe9, 0x83, 0x78, 0x7e, 0x24, 0xb5, 0xfa,
+	       0x50, 0x9d, 0x32, 0x55, 0x70, 0x73, 0xaf, 0x10, 0x92, 0xd3,
+	       0x14, 0xd3, 0x69, 0xfa, 0xa6, 0x81, 0x5c, 0xba, 0x9d, 0x18,
+	       0x25, 0xda, 0x78, 0x47, 0x33, 0x83, 0xd1, 0xc3, 0x96, 0x12,
+	       0x6f, 0x8b, 0xc9, 0x98, 0x32, 0x79, 0x59, 0x76, 0xcb, 0x56,
+	       0x7f, 0x5e, 0x6d, 0x1e, 0x78, 0xb2, 0xd0, 0x39, 0x3c, 0x41,
+	       0xd7, 0xab, 0x77, 0x2a, 0x0e, 0xbb, 0xc8, 0x69, 0xae, 0xfd,
+	       0x9c, 0x20, 0x11, 0xba, 0x0a, 0x5d, 0x00, 0x58, 0xf8, 0x74,
+	       0xb0, 0x77, 0x36, 0x9b, 0x8e, 0xd5, 0x4d, 0x85, 0xb1, 0xbb,
+	       0xcd, 0xcb, 0x1d, 0xee, 0x08, 0xb9, 0x53, 0x9a, 0x5f, 0xe3,
+	       0x88, 0xb1, 0x1a, 0xc3, 0x41, 0x41, 0x3e, 0x06, 0xf7, 0x70,
+	       0x58, 0xe8, 0x22, 0x22, 0xd7, 0x0e, 0xbb, 0x88, 0xce, 0x73,
+	       0x0e, 0xd0, 0x04, 0x81, 0x50, 0xd2, 0x33 ) );
+
+OCSP ( google_ocsp, &google_crt, &thawte_crt,
+	DATA ( 0x30, 0x51, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x4b, 0x30, 0x49,
+	       0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
+	       0x00, 0x04, 0x14, 0x1e, 0x92, 0x09, 0xaa, 0x71, 0x3c, 0x79,
+	       0x4b, 0xca, 0x1e, 0x93, 0x1a, 0x0a, 0x61, 0xad, 0x3f, 0xd0,
+	       0xba, 0x60, 0x83, 0x04, 0x14, 0x3b, 0x34, 0x9a, 0x70, 0x91,
+	       0x73, 0xb2, 0x8a, 0x1b, 0x0c, 0xf4, 0xe9, 0x37, 0xcd, 0xb3,
+	       0x70, 0x32, 0x9e, 0x18, 0x54, 0x02, 0x10, 0x4f, 0x9d, 0x96,
+	       0xd9, 0x66, 0xb0, 0x99, 0x2b, 0x54, 0xc2, 0x95, 0x7c, 0xb4,
+	       0x15, 0x7d, 0x4d ),
+	DATA ( 0x30, 0x82, 0x04, 0x38, 0x0a, 0x01, 0x00, 0xa0, 0x82, 0x04,
+	       0x31, 0x30, 0x82, 0x04, 0x2d, 0x06, 0x09, 0x2b, 0x06, 0x01,
+	       0x05, 0x05, 0x07, 0x30, 0x01, 0x01, 0x04, 0x82, 0x04, 0x1e,
+	       0x30, 0x82, 0x04, 0x1a, 0x30, 0x81, 0xe7, 0xa0, 0x03, 0x02,
+	       0x01, 0x00, 0xa1, 0x5a, 0x30, 0x58, 0x31, 0x0b, 0x30, 0x09,
+	       0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x5a, 0x41, 0x31,
+	       0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x1c,
+	       0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x43, 0x6f, 0x6e,
+	       0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x28, 0x50,
+	       0x74, 0x79, 0x29, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x22,
+	       0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x54,
+	       0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x53, 0x47, 0x43, 0x20,
+	       0x4f, 0x43, 0x53, 0x50, 0x20, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	       0x6e, 0x64, 0x65, 0x72, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x32,
+	       0x30, 0x35, 0x31, 0x32, 0x31, 0x39, 0x33, 0x31, 0x34, 0x33,
+	       0x5a, 0x30, 0x73, 0x30, 0x71, 0x30, 0x49, 0x30, 0x09, 0x06,
+	       0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14,
+	       0x1e, 0x92, 0x09, 0xaa, 0x71, 0x3c, 0x79, 0x4b, 0xca, 0x1e,
+	       0x93, 0x1a, 0x0a, 0x61, 0xad, 0x3f, 0xd0, 0xba, 0x60, 0x83,
+	       0x04, 0x14, 0x3b, 0x34, 0x9a, 0x70, 0x91, 0x73, 0xb2, 0x8a,
+	       0x1b, 0x0c, 0xf4, 0xe9, 0x37, 0xcd, 0xb3, 0x70, 0x32, 0x9e,
+	       0x18, 0x54, 0x02, 0x10, 0x4f, 0x9d, 0x96, 0xd9, 0x66, 0xb0,
+	       0x99, 0x2b, 0x54, 0xc2, 0x95, 0x7c, 0xb4, 0x15, 0x7d, 0x4d,
+	       0x80, 0x00, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x32, 0x30, 0x35,
+	       0x31, 0x32, 0x31, 0x39, 0x33, 0x31, 0x34, 0x33, 0x5a, 0xa0,
+	       0x11, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x32, 0x30, 0x35, 0x31,
+	       0x39, 0x31, 0x39, 0x33, 0x31, 0x34, 0x33, 0x5a, 0x30, 0x0d,
+	       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+	       0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x57, 0xf9, 0xf8,
+	       0x26, 0x0f, 0xda, 0x0c, 0xc2, 0xf0, 0xe4, 0x80, 0xd0, 0x29,
+	       0xd6, 0x04, 0x77, 0xab, 0x0c, 0xf6, 0x7e, 0x77, 0xc9, 0xac,
+	       0x53, 0xa4, 0x4d, 0x6b, 0x75, 0x58, 0xb9, 0xc7, 0x7a, 0x9a,
+	       0x39, 0x5d, 0x4c, 0xfd, 0x15, 0x1b, 0x47, 0x55, 0x8e, 0x39,
+	       0x05, 0x2b, 0x06, 0x2f, 0x3e, 0x1d, 0x3a, 0x7c, 0x2c, 0xf4,
+	       0x4c, 0x70, 0x6a, 0x58, 0x7a, 0x4b, 0x8f, 0x77, 0xaf, 0x9e,
+	       0xcf, 0xc6, 0xb1, 0x66, 0x8d, 0xed, 0xbf, 0xc1, 0xd9, 0xe1,
+	       0x78, 0x5a, 0x18, 0x61, 0xca, 0xa8, 0xf5, 0x2b, 0xe3, 0x9b,
+	       0x50, 0x25, 0x60, 0x7d, 0x8d, 0xd1, 0xe0, 0x76, 0xbb, 0x5c,
+	       0x7b, 0xc1, 0x5d, 0xe1, 0x27, 0x3f, 0x7f, 0x9b, 0xb3, 0xb0,
+	       0xb2, 0x79, 0x37, 0xd4, 0x53, 0x29, 0x62, 0x46, 0x8f, 0xe6,
+	       0x34, 0x9e, 0xe5, 0x6e, 0x63, 0x5d, 0xcc, 0xb3, 0xb2, 0xe2,
+	       0x73, 0x7e, 0xa6, 0xad, 0xa0, 0xa0, 0x82, 0x02, 0x99, 0x30,
+	       0x82, 0x02, 0x95, 0x30, 0x82, 0x02, 0x91, 0x30, 0x82, 0x01,
+	       0xfa, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x67, 0x4d,
+	       0x9b, 0x61, 0x8f, 0x57, 0xcd, 0x51, 0xfb, 0x58, 0x07, 0x66,
+	       0x1d, 0x24, 0xf5, 0xa5, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+	       0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
+	       0x4c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+	       0x13, 0x02, 0x5a, 0x41, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03,
+	       0x55, 0x04, 0x0a, 0x13, 0x1c, 0x54, 0x68, 0x61, 0x77, 0x74,
+	       0x65, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74, 0x69,
+	       0x6e, 0x67, 0x20, 0x28, 0x50, 0x74, 0x79, 0x29, 0x20, 0x4c,
+	       0x74, 0x64, 0x2e, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55,
+	       0x04, 0x03, 0x13, 0x0d, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65,
+	       0x20, 0x53, 0x47, 0x43, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17,
+	       0x0d, 0x31, 0x32, 0x30, 0x33, 0x30, 0x34, 0x30, 0x30, 0x30,
+	       0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x36,
+	       0x30, 0x32, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30,
+	       0x58, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+	       0x13, 0x02, 0x5a, 0x41, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03,
+	       0x55, 0x04, 0x0a, 0x13, 0x1c, 0x54, 0x68, 0x61, 0x77, 0x74,
+	       0x65, 0x20, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74, 0x69,
+	       0x6e, 0x67, 0x20, 0x28, 0x50, 0x74, 0x79, 0x29, 0x20, 0x4c,
+	       0x74, 0x64, 0x2e, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55,
+	       0x04, 0x03, 0x13, 0x19, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65,
+	       0x20, 0x53, 0x47, 0x43, 0x20, 0x4f, 0x43, 0x53, 0x50, 0x20,
+	       0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x30,
+	       0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+	       0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+	       0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xc2, 0x21,
+	       0x52, 0xe2, 0x10, 0x44, 0xe3, 0xc7, 0xe3, 0x72, 0x19, 0x01,
+	       0xa8, 0x0c, 0x5a, 0x8b, 0x63, 0x0b, 0x30, 0x4c, 0x4f, 0xa2,
+	       0xe2, 0xdf, 0x62, 0x2e, 0xdf, 0xe2, 0x77, 0xb9, 0x27, 0x3b,
+	       0x8d, 0x45, 0xe2, 0xa1, 0x21, 0x95, 0x13, 0x5a, 0xf2, 0x7d,
+	       0x58, 0x2c, 0x6d, 0x53, 0xb2, 0x42, 0x52, 0x8f, 0x8e, 0xf4,
+	       0x17, 0xc5, 0xcb, 0xfa, 0x2f, 0x2d, 0x9b, 0x02, 0xd0, 0x1a,
+	       0xf1, 0x32, 0xc5, 0xb9, 0xd3, 0x5a, 0xc0, 0xd6, 0x20, 0xb8,
+	       0x3f, 0xa3, 0x93, 0x8b, 0xe5, 0x22, 0x91, 0x1a, 0x7e, 0x7c,
+	       0x8b, 0x35, 0xeb, 0x94, 0xee, 0xe6, 0xcc, 0x58, 0xe4, 0x3c,
+	       0xcd, 0x00, 0x86, 0xaa, 0xc3, 0x2e, 0x8b, 0xb4, 0x3c, 0x29,
+	       0x11, 0x21, 0x5d, 0x71, 0x4a, 0xb6, 0x7a, 0x22, 0xa9, 0xf2,
+	       0xf8, 0x90, 0xed, 0x5c, 0x73, 0x8c, 0xe0, 0x70, 0x56, 0xde,
+	       0x70, 0xc5, 0x0d, 0x81, 0xb4, 0x5b, 0x02, 0x03, 0x01, 0x00,
+	       0x01, 0xa3, 0x68, 0x30, 0x66, 0x30, 0x09, 0x06, 0x03, 0x55,
+	       0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x13, 0x06, 0x03,
+	       0x55, 0x1d, 0x25, 0x04, 0x0c, 0x30, 0x0a, 0x06, 0x08, 0x2b,
+	       0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x09, 0x30, 0x0b, 0x06,
+	       0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80,
+	       0x30, 0x0f, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
+	       0x30, 0x01, 0x05, 0x04, 0x02, 0x05, 0x00, 0x30, 0x26, 0x06,
+	       0x03, 0x55, 0x1d, 0x11, 0x04, 0x1f, 0x30, 0x1d, 0xa4, 0x1b,
+	       0x30, 0x19, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x03, 0x13, 0x0e, 0x4f, 0x43, 0x53, 0x50, 0x38, 0x2d, 0x54,
+	       0x47, 0x56, 0x37, 0x2d, 0x32, 0x37, 0x35, 0x30, 0x0d, 0x06,
+	       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+	       0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x98, 0x50, 0x14, 0xbe,
+	       0x31, 0x44, 0x01, 0x97, 0xee, 0x21, 0xf9, 0xcf, 0xa4, 0x32,
+	       0xc2, 0x91, 0x6a, 0x4b, 0x02, 0x61, 0x62, 0xa9, 0xe4, 0xad,
+	       0x8a, 0xac, 0xe4, 0x12, 0x12, 0xbe, 0x9b, 0xba, 0x4c, 0xe2,
+	       0x92, 0xdb, 0x8b, 0x92, 0x11, 0xe6, 0x9e, 0x25, 0x2e, 0xd5,
+	       0x4b, 0xe8, 0x5d, 0xc8, 0x63, 0xd2, 0xff, 0xfa, 0x80, 0x89,
+	       0x83, 0x0f, 0xe4, 0xe2, 0x91, 0xcc, 0x0a, 0x85, 0x74, 0x38,
+	       0xb7, 0xdf, 0xb9, 0x1c, 0xf6, 0x35, 0xfe, 0x6f, 0xf3, 0x29,
+	       0xc0, 0xc5, 0x0a, 0x2c, 0x04, 0xd7, 0x69, 0xff, 0x02, 0x45,
+	       0x1c, 0x29, 0x7a, 0x27, 0xf8, 0xb2, 0xe3, 0x58, 0x09, 0x34,
+	       0xc4, 0xd7, 0x77, 0x74, 0xbd, 0xe4, 0x7c, 0xda, 0x99, 0x09,
+	       0x83, 0x03, 0x6c, 0x36, 0x0d, 0xb2, 0x91, 0x71, 0x40, 0xc7,
+	       0x97, 0x85, 0xfb, 0x2a, 0xa3, 0x92, 0x65, 0x0b, 0x02, 0x58,
+	       0x14, 0x89, 0x8f, 0x3b ) );
+
+OCSP ( unauthorized_ocsp, &barclays_crt, &thawte_crt,
+	DATA ( 0x30, 0x51, 0x30, 0x4f, 0x30, 0x4d, 0x30, 0x4b, 0x30, 0x49,
+	       0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
+	       0x00, 0x04, 0x14, 0xd4, 0xb4, 0x3b, 0x8e, 0x3d, 0x02, 0x49,
+	       0x1a, 0x65, 0x50, 0x6f, 0x96, 0x73, 0x14, 0xdd, 0xe8, 0x59,
+	       0x44, 0x52, 0xe4, 0x04, 0x14, 0x3b, 0x34, 0x9a, 0x70, 0x91,
+	       0x73, 0xb2, 0x8a, 0x1b, 0x0c, 0xf4, 0xe9, 0x37, 0xcd, 0xb3,
+	       0x70, 0x32, 0x9e, 0x18, 0x54, 0x02, 0x10, 0x49, 0x83, 0xfc,
+	       0x05, 0x76, 0xdf, 0x36, 0x91, 0x7c, 0x64, 0x2a, 0x27, 0xc1,
+	       0xf1, 0x48, 0xe3 ),
+	DATA ( 0x30, 0x03, 0x0a, 0x01, 0x06 ) );
+
+OCSP ( unknown_ocsp, &thawte_crt, &startssl_crt,
+	DATA ( 0x30, 0x45, 0x30, 0x43, 0x30, 0x41, 0x30, 0x3f, 0x30, 0x3d,
+	       0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
+	       0x00, 0x04, 0x14, 0x48, 0xb7, 0x64, 0x49, 0xf3, 0xd5, 0xfe,
+	       0xfa, 0x11, 0x33, 0xaa, 0x80, 0x5e, 0x42, 0x0f, 0x0f, 0xca,
+	       0x64, 0x36, 0x51, 0x04, 0x14, 0x11, 0xdb, 0x23, 0x45, 0xfd,
+	       0x54, 0xcc, 0x6a, 0x71, 0x6f, 0x84, 0x8a, 0x03, 0xd7, 0xbe,
+	       0xf7, 0x01, 0x2f, 0x26, 0x86, 0x02, 0x04, 0x30, 0x00, 0x00,
+	       0x02 ),
+	DATA ( 0x30, 0x82, 0x06, 0x46, 0x0a, 0x01, 0x00, 0xa0, 0x82, 0x06,
+	       0x3f, 0x30, 0x82, 0x06, 0x3b, 0x06, 0x09, 0x2b, 0x06, 0x01,
+	       0x05, 0x05, 0x07, 0x30, 0x01, 0x01, 0x04, 0x82, 0x06, 0x2c,
+	       0x30, 0x82, 0x06, 0x28, 0x30, 0x81, 0xec, 0xa1, 0x70, 0x30,
+	       0x6e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+	       0x13, 0x02, 0x49, 0x4c, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03,
+	       0x55, 0x04, 0x0a, 0x13, 0x28, 0x53, 0x74, 0x61, 0x72, 0x74,
+	       0x43, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x20, 0x28,
+	       0x53, 0x74, 0x61, 0x72, 0x74, 0x20, 0x43, 0x6f, 0x6d, 0x6d,
+	       0x65, 0x72, 0x63, 0x69, 0x61, 0x6c, 0x20, 0x4c, 0x69, 0x6d,
+	       0x69, 0x74, 0x65, 0x64, 0x29, 0x31, 0x2c, 0x30, 0x2a, 0x06,
+	       0x03, 0x55, 0x04, 0x03, 0x13, 0x23, 0x53, 0x74, 0x61, 0x72,
+	       0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73,
+	       0x20, 0x32, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
+	       0x4f, 0x43, 0x53, 0x50, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x65,
+	       0x72, 0x18, 0x0f, 0x32, 0x30, 0x31, 0x32, 0x30, 0x35, 0x31,
+	       0x35, 0x31, 0x31, 0x35, 0x34, 0x30, 0x38, 0x5a, 0x30, 0x67,
+	       0x30, 0x65, 0x30, 0x3d, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
+	       0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x48, 0xb7, 0x64,
+	       0x49, 0xf3, 0xd5, 0xfe, 0xfa, 0x11, 0x33, 0xaa, 0x80, 0x5e,
+	       0x42, 0x0f, 0x0f, 0xca, 0x64, 0x36, 0x51, 0x04, 0x14, 0x11,
+	       0xdb, 0x23, 0x45, 0xfd, 0x54, 0xcc, 0x6a, 0x71, 0x6f, 0x84,
+	       0x8a, 0x03, 0xd7, 0xbe, 0xf7, 0x01, 0x2f, 0x26, 0x86, 0x02,
+	       0x04, 0x30, 0x00, 0x00, 0x02, 0x82, 0x00, 0x18, 0x0f, 0x32,
+	       0x30, 0x31, 0x32, 0x30, 0x35, 0x31, 0x35, 0x31, 0x31, 0x35,
+	       0x34, 0x30, 0x38, 0x5a, 0xa0, 0x11, 0x18, 0x0f, 0x32, 0x30,
+	       0x31, 0x32, 0x30, 0x35, 0x31, 0x36, 0x31, 0x31, 0x35, 0x34,
+	       0x30, 0x38, 0x5a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+	       0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82,
+	       0x01, 0x01, 0x00, 0xbe, 0x1b, 0xa7, 0xa7, 0xba, 0x17, 0xd9,
+	       0x94, 0x16, 0xdf, 0xd2, 0x86, 0x1e, 0x39, 0x38, 0x2f, 0x0e,
+	       0x0e, 0xb0, 0x19, 0x74, 0x9d, 0x64, 0x61, 0xfb, 0x34, 0x15,
+	       0x64, 0xe6, 0x7a, 0x44, 0xfc, 0x24, 0xaf, 0x63, 0xe3, 0xe5,
+	       0x01, 0x3f, 0xeb, 0x62, 0xc4, 0x2f, 0xd7, 0x56, 0xac, 0x9e,
+	       0x39, 0x8c, 0x54, 0x20, 0x24, 0x9f, 0xe0, 0x9a, 0x2c, 0x9a,
+	       0xfb, 0xbe, 0x13, 0x8d, 0x18, 0xf1, 0x95, 0x37, 0xf7, 0x6a,
+	       0x93, 0x28, 0x2a, 0xf6, 0x10, 0xc0, 0x5e, 0xa0, 0xfc, 0xf7,
+	       0x66, 0x97, 0xe4, 0x76, 0x04, 0x90, 0xd3, 0x45, 0x59, 0x26,
+	       0xfd, 0xe9, 0xb4, 0xe5, 0xd6, 0x30, 0x2f, 0xe0, 0xfb, 0xda,
+	       0xcc, 0x4b, 0xc4, 0x11, 0xbf, 0x20, 0x50, 0x18, 0xd5, 0x18,
+	       0xfc, 0xe7, 0x86, 0xb8, 0x80, 0x2b, 0x2e, 0x35, 0x50, 0xcd,
+	       0x73, 0x0d, 0x70, 0xbe, 0x55, 0xa2, 0xef, 0x2c, 0x62, 0x96,
+	       0xe3, 0x6a, 0xec, 0x69, 0xa6, 0x8f, 0x9d, 0x37, 0xb6, 0xbe,
+	       0x6b, 0x72, 0x02, 0x99, 0x02, 0xea, 0x0b, 0x18, 0x01, 0x26,
+	       0x82, 0x3b, 0x7b, 0x44, 0x8a, 0x84, 0xe4, 0x78, 0x6c, 0xb3,
+	       0x5b, 0x83, 0x87, 0x7c, 0xab, 0x80, 0x17, 0xfd, 0x00, 0xfd,
+	       0x56, 0x87, 0x85, 0x2b, 0x49, 0x42, 0xa2, 0x63, 0x84, 0x4f,
+	       0x4a, 0xaa, 0x5e, 0x7d, 0x64, 0x29, 0x09, 0x81, 0xac, 0xea,
+	       0x53, 0x00, 0x36, 0xbf, 0x19, 0x33, 0x5c, 0x0e, 0xee, 0xa9,
+	       0x6a, 0x9e, 0x2e, 0x44, 0x9b, 0x3e, 0xc9, 0x27, 0xb7, 0x49,
+	       0x15, 0x76, 0xa8, 0x42, 0x79, 0x2d, 0x4a, 0x42, 0x1f, 0xf1,
+	       0x32, 0x35, 0x31, 0x4c, 0xcb, 0xa2, 0xee, 0x50, 0xae, 0x1f,
+	       0x5e, 0x4d, 0x5d, 0xc1, 0x9e, 0x28, 0x17, 0x59, 0x6d, 0x1d,
+	       0x2a, 0x0a, 0x3d, 0xeb, 0x88, 0x10, 0xb5, 0xe6, 0x3b, 0xa7,
+	       0x81, 0x1f, 0xc7, 0xa0, 0xc8, 0x4a, 0xfe, 0x6c, 0x8f, 0xa0,
+	       0x82, 0x04, 0x21, 0x30, 0x82, 0x04, 0x1d, 0x30, 0x82, 0x04,
+	       0x19, 0x30, 0x82, 0x03, 0x01, 0xa0, 0x03, 0x02, 0x01, 0x02,
+	       0x02, 0x03, 0x00, 0xca, 0x67, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+	       0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+	       0x30, 0x81, 0x8c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+	       0x04, 0x06, 0x13, 0x02, 0x49, 0x4c, 0x31, 0x16, 0x30, 0x14,
+	       0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x53, 0x74, 0x61,
+	       0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20, 0x4c, 0x74, 0x64, 0x2e,
+	       0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
+	       0x22, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x44, 0x69,
+	       0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 0x43, 0x65, 0x72, 0x74,
+	       0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x69,
+	       0x67, 0x6e, 0x69, 0x6e, 0x67, 0x31, 0x38, 0x30, 0x36, 0x06,
+	       0x03, 0x55, 0x04, 0x03, 0x13, 0x2f, 0x53, 0x74, 0x61, 0x72,
+	       0x74, 0x43, 0x6f, 0x6d, 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73,
+	       0x20, 0x32, 0x20, 0x50, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79,
+	       0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69,
+	       0x61, 0x74, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
+	       0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30,
+	       0x34, 0x32, 0x32, 0x30, 0x35, 0x33, 0x30, 0x35, 0x39, 0x5a,
+	       0x17, 0x0d, 0x31, 0x32, 0x30, 0x36, 0x30, 0x32, 0x30, 0x36,
+	       0x32, 0x39, 0x32, 0x37, 0x5a, 0x30, 0x6e, 0x31, 0x0b, 0x30,
+	       0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x49, 0x4c,
+	       0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
+	       0x28, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d, 0x20,
+	       0x4c, 0x74, 0x64, 0x2e, 0x20, 0x28, 0x53, 0x74, 0x61, 0x72,
+	       0x74, 0x20, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69,
+	       0x61, 0x6c, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64,
+	       0x29, 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, 0x03,
+	       0x13, 0x23, 0x53, 0x74, 0x61, 0x72, 0x74, 0x43, 0x6f, 0x6d,
+	       0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x32, 0x20, 0x53,
+	       0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x4f, 0x43, 0x53, 0x50,
+	       0x20, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x30, 0x82, 0x01,
+	       0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
+	       0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00,
+	       0xd0, 0xd5, 0xf5, 0x70, 0x9a, 0x2b, 0x41, 0x35, 0xf7, 0xf8,
+	       0xcf, 0xb5, 0x6b, 0xb3, 0xdf, 0xe0, 0xb9, 0x12, 0x0d, 0x3d,
+	       0xd3, 0x99, 0x9f, 0x32, 0x73, 0x01, 0x1f, 0xbc, 0x7d, 0x4f,
+	       0x3e, 0x66, 0xf7, 0xfd, 0x60, 0x57, 0x92, 0x30, 0xb4, 0xdb,
+	       0x9a, 0xf5, 0xd3, 0x49, 0x19, 0xd6, 0xad, 0x37, 0x43, 0x78,
+	       0x69, 0x8c, 0x0d, 0x23, 0x0e, 0x7a, 0xd1, 0x65, 0x08, 0xeb,
+	       0x71, 0x8c, 0x37, 0x36, 0xd3, 0x4d, 0xa6, 0xcb, 0x11, 0xb2,
+	       0xfa, 0xb4, 0x38, 0x3e, 0x2b, 0x70, 0x8c, 0xf7, 0xf1, 0xd9,
+	       0x64, 0x62, 0x26, 0xf4, 0xa7, 0x2c, 0x24, 0x25, 0x4e, 0x4d,
+	       0x3e, 0x7a, 0x54, 0x57, 0x0f, 0xc1, 0x89, 0x9e, 0xb6, 0x55,
+	       0x0b, 0x7c, 0xbe, 0x38, 0xda, 0x8b, 0x62, 0xe9, 0xf1, 0xfa,
+	       0x8c, 0xd9, 0x32, 0x1f, 0xbe, 0x6d, 0x2e, 0x3d, 0x48, 0xa7,
+	       0x4f, 0x48, 0xd4, 0xff, 0x6b, 0xf6, 0x17, 0xf8, 0x31, 0xb2,
+	       0x37, 0xeb, 0x89, 0x71, 0x19, 0x0f, 0xe7, 0x86, 0x06, 0x66,
+	       0xfb, 0xc5, 0xad, 0x7b, 0x75, 0x0b, 0xcc, 0x2e, 0x3c, 0x4d,
+	       0x1c, 0x99, 0x40, 0x32, 0x72, 0xd4, 0x5c, 0xc9, 0x06, 0xaa,
+	       0x98, 0xe9, 0x01, 0x92, 0xdb, 0x25, 0x48, 0x1a, 0xae, 0x3f,
+	       0x01, 0x4d, 0x8a, 0xb0, 0x78, 0xb1, 0x28, 0xe0, 0x09, 0x9b,
+	       0x23, 0xe2, 0x28, 0x46, 0x6f, 0x50, 0x52, 0x71, 0x1c, 0xf1,
+	       0x09, 0xa0, 0x87, 0x3b, 0xdb, 0x84, 0xa3, 0xb1, 0x57, 0x6f,
+	       0xbf, 0x52, 0xd2, 0x30, 0x83, 0x30, 0x26, 0xc0, 0x27, 0x8e,
+	       0x6d, 0x03, 0x43, 0x14, 0x42, 0x31, 0x29, 0xf2, 0x7e, 0x52,
+	       0xcb, 0x84, 0x20, 0x2e, 0x87, 0x19, 0xe5, 0x48, 0xad, 0x06,
+	       0xce, 0x2e, 0x0f, 0xed, 0x78, 0x2a, 0x3d, 0x79, 0xc4, 0xb0,
+	       0xdb, 0xfa, 0x4e, 0x95, 0x88, 0x46, 0x75, 0x12, 0xb0, 0x7a,
+	       0x55, 0x6a, 0x38, 0xae, 0xea, 0x59, 0x02, 0x03, 0x01, 0x00,
+	       0x01, 0xa3, 0x81, 0xa0, 0x30, 0x81, 0x9d, 0x30, 0x09, 0x06,
+	       0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b,
+	       0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x03,
+	       0xa8, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x17,
+	       0x30, 0x15, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
+	       0x03, 0x09, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
+	       0x30, 0x01, 0x05, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
+	       0x04, 0x16, 0x04, 0x14, 0xbd, 0x4c, 0xef, 0x0e, 0xf7, 0x08,
+	       0xac, 0xc9, 0xbd, 0x39, 0x0f, 0xd9, 0xa0, 0xd3, 0xce, 0xcf,
+	       0x26, 0x48, 0xb8, 0x19, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
+	       0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x11, 0xdb, 0x23,
+	       0x45, 0xfd, 0x54, 0xcc, 0x6a, 0x71, 0x6f, 0x84, 0x8a, 0x03,
+	       0xd7, 0xbe, 0xf7, 0x01, 0x2f, 0x26, 0x86, 0x30, 0x23, 0x06,
+	       0x03, 0x55, 0x1d, 0x12, 0x04, 0x1c, 0x30, 0x1a, 0x86, 0x18,
+	       0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
+	       0x2e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x73, 0x6c, 0x2e,
+	       0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+	       0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03,
+	       0x82, 0x01, 0x01, 0x00, 0x56, 0x1f, 0xef, 0xa5, 0x1a, 0x07,
+	       0xbe, 0xb1, 0xd1, 0xd0, 0x17, 0xeb, 0x72, 0x5b, 0x17, 0x11,
+	       0xe5, 0x96, 0xc3, 0x96, 0xe7, 0x9a, 0xdb, 0xbf, 0x64, 0x1c,
+	       0x99, 0x11, 0x2f, 0x18, 0x07, 0xb2, 0x45, 0x48, 0xf3, 0x58,
+	       0xcd, 0x38, 0x69, 0x33, 0xf4, 0x58, 0x5b, 0x16, 0xed, 0xfb,
+	       0xce, 0xb3, 0xc3, 0x14, 0x27, 0xa6, 0x16, 0xff, 0xd0, 0x70,
+	       0x9e, 0xe1, 0x9d, 0x4b, 0xd1, 0x26, 0x6c, 0x61, 0x25, 0xf1,
+	       0x39, 0x9c, 0xbe, 0x69, 0x75, 0x58, 0xcd, 0xbd, 0x8e, 0x36,
+	       0xfd, 0x46, 0xd1, 0xe3, 0xb9, 0x1a, 0x8a, 0xc1, 0xd7, 0x3e,
+	       0x6e, 0x82, 0xb8, 0xb0, 0x3f, 0xcf, 0x14, 0x3f, 0xc6, 0xf6,
+	       0x3a, 0x86, 0xce, 0x03, 0x76, 0x1f, 0xdb, 0x0b, 0x12, 0xac,
+	       0x99, 0x79, 0x53, 0xf0, 0x3d, 0x70, 0xd3, 0x5a, 0x05, 0xf6,
+	       0xba, 0x6e, 0x35, 0x31, 0x1e, 0x08, 0x30, 0xc1, 0xa4, 0xd4,
+	       0x45, 0x43, 0x5a, 0x01, 0xd9, 0x3d, 0xa5, 0xdb, 0xd2, 0xd7,
+	       0x73, 0x97, 0xe9, 0xab, 0xe4, 0x60, 0xf1, 0xfc, 0xf0, 0x9b,
+	       0xe2, 0x5a, 0x1e, 0x31, 0xe0, 0x1b, 0x47, 0x3f, 0x5a, 0x78,
+	       0xf3, 0x6e, 0xf0, 0x94, 0x6c, 0x2c, 0xfb, 0x67, 0x6e, 0xcb,
+	       0x8c, 0xb6, 0x8d, 0xcc, 0xcf, 0x1e, 0x9f, 0xd2, 0x10, 0x52,
+	       0xc2, 0xe7, 0xc8, 0x05, 0x2c, 0xa0, 0x18, 0xf5, 0x53, 0x4a,
+	       0xd2, 0xb0, 0x57, 0x5e, 0x5f, 0x63, 0xd7, 0x7b, 0x8e, 0xfa,
+	       0x22, 0xa0, 0x69, 0x17, 0xd2, 0xa0, 0xc7, 0x70, 0x01, 0x79,
+	       0x8b, 0x69, 0x1f, 0x0f, 0xdb, 0xe5, 0xf9, 0x83, 0x2b, 0x26,
+	       0x05, 0x05, 0x87, 0x80, 0x0d, 0xf9, 0x20, 0x0e, 0x16, 0x39,
+	       0xc5, 0x9b, 0x14, 0x2e, 0xf2, 0x06, 0x57, 0x46, 0x3d, 0x0b,
+	       0x8c, 0x3e, 0xb4, 0x66, 0x76, 0x67, 0x34, 0x70, 0x00, 0x63,
+	       0xcf, 0x9e, 0xc8, 0xc5, 0x5f, 0x48, 0x06, 0x53, 0x26, 0x55 ) );
+
+/** Time at which OCSP responses are valid */
+static time_t test_time = 1337062083ULL; /* Tue 15 May 2012 06:08:03 */
+
+/** Time at which OCSP responses are not valid */
+static time_t test_stale = 1375573111ULL; /* Sat Aug  3 23:38:31 2013 */
+
+/**
+ * Report certificate parsing test result
+ *
+ * @v crt		Test certificate
+ */
+#define ocsp_certificate_ok( crt ) do {					\
+	ok ( x509_certificate ( (crt)->data, (crt)->len,		\
+				&(crt)->cert ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Report OCSP check creation test result
+ *
+ * @v test		OCSP test
+ */
+#define ocsp_check_ok( test ) do {					\
+	ocsp_prepare_test ( (test) );					\
+	ok ( ocsp_check ( (test)->cert->cert, (test)->issuer->cert,	\
+			  &(test)->ocsp ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Report OCSP request construction test result
+ *
+ * @v test		OCSP test
+ */
+#define ocsp_request_ok( test ) do {					\
+	DBGC ( (test), "OCSPTEST %p expected request:\n", (test) );	\
+	DBGC_HDA ( (test), 0, (test)->request, (test)->request_len );	\
+	ok ( (test)->ocsp->request.builder.len == (test)->request_len );\
+	ok ( memcmp ( (test)->ocsp->request.builder.data,		\
+		      (test)->request, (test)->request_len ) == 0 );	\
+	DBGC ( (test), "OCSPTEST %p generated request:\n", (test) );	\
+	DBGC_HDA ( (test), 0, (test)->ocsp->request.builder.data,	\
+		   (test)->ocsp->request.builder.len );			\
+	} while ( 0 )
+
+/**
+ * Report OCSP response test result
+ *
+ * @v test		OCSP test
+ */
+#define ocsp_response_ok( test ) do {					\
+	ok ( ocsp_response ( (test)->ocsp, (test)->response,		\
+			     (test)->response_len ) == 0 );		\
+	} while ( 0 )
+
+/**
+ * Report OCSP response failure test result
+ *
+ * @v test		OCSP test
+ */
+#define ocsp_response_fail_ok( test ) do {				\
+	ok ( ocsp_response ( (test)->ocsp, (test)->response,		\
+			     (test)->response_len ) != 0 );		\
+	} while ( 0 )
+
+/**
+ * Report OCSP validation test result
+ *
+ * @v test		OCSP test
+ * @v time		Test time
+ */
+#define ocsp_validate_ok( test, time ) do {				\
+	ocsp_prepare_test ( (test) );					\
+	ok ( ocsp_validate ( (test)->ocsp, time ) == 0 );		\
+	} while ( 0 )
+
+/**
+ * Report OCSP validation failure test result
+ *
+ * @v test		OCSP test
+ * @v time		Test time
+ */
+#define ocsp_validate_fail_ok( test, time ) do {			\
+	ocsp_prepare_test ( (test) );					\
+	ok ( ocsp_validate ( (test)->ocsp, time ) != 0 );		\
+	} while ( 0 )
+
+/**
+ * Perform OCSP self-tests
+ *
+ */
+static void ocsp_test_exec ( void ) {
+
+	/* Parse certificates */
+	ocsp_certificate_ok ( &barclays_crt );
+	ocsp_certificate_ok ( &google_crt );
+	ocsp_certificate_ok ( &verisign_crt );
+	ocsp_certificate_ok ( &thawte_crt );
+	ocsp_certificate_ok ( &startssl_crt );
+
+	/* Parse OCSP checks */
+	ocsp_check_ok ( &barclays_ocsp );
+	ocsp_check_ok ( &google_ocsp );
+	ocsp_check_ok ( &unauthorized_ocsp );
+	ocsp_check_ok ( &unknown_ocsp );
+
+	/* "barclays" test */
+	ocsp_request_ok ( &barclays_ocsp );
+	ocsp_response_ok ( &barclays_ocsp );
+	ocsp_validate_ok ( &barclays_ocsp, test_time );
+	ocsp_validate_fail_ok ( &barclays_ocsp, test_stale );
+
+	/* "google" test */
+	ocsp_request_ok ( &google_ocsp );
+	ocsp_response_ok ( &google_ocsp );
+	ocsp_validate_ok ( &google_ocsp, test_time );
+	ocsp_validate_fail_ok ( &google_ocsp, test_stale );
+
+	/* "unauthorized" test */
+	ocsp_request_ok ( &unauthorized_ocsp );
+	ocsp_response_fail_ok ( &unauthorized_ocsp );
+
+	/* "unknown" test */
+	ocsp_request_ok ( &unknown_ocsp );
+	ocsp_response_fail_ok ( &unknown_ocsp );
+
+	/* Drop OCSP check references */
+	ocsp_put ( unknown_ocsp.ocsp );
+	ocsp_put ( unauthorized_ocsp.ocsp );
+	ocsp_put ( google_ocsp.ocsp );
+	ocsp_put ( barclays_ocsp.ocsp );
+
+	/* Drop certificate references */
+	x509_put ( startssl_crt.cert );
+	x509_put ( thawte_crt.cert );
+	x509_put ( verisign_crt.cert );
+	x509_put ( google_crt.cert );
+	x509_put ( barclays_crt.cert );
+}
+
+/** OCSP self-test */
+struct self_test ocsp_test __self_test = {
+	.name = "ocsp",
+	.exec = ocsp_test_exec,
+};
+
+/* Drag in algorithms required for tests */
+REQUIRE_OBJECT ( rsa );
+REQUIRE_OBJECT ( sha1 );
diff --git a/roms/ipxe/src/tests/pubkey_test.h b/roms/ipxe/src/tests/pubkey_test.h
new file mode 100644
index 0000000000000000000000000000000000000000..7678453a94673dd69b37c19c4695cb91e55fd7ef
--- /dev/null
+++ b/roms/ipxe/src/tests/pubkey_test.h
@@ -0,0 +1,175 @@
+#ifndef _PUBKEY_TEST_H
+#define _PUBKEY_TEST_H
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/crypto.h>
+#include <ipxe/test.h>
+
+/**
+ * Report public key decryption test result
+ *
+ * @v pubkey		Public key algorithm
+ * @v key		Key
+ * @v key_len		Key length
+ * @v ciphertext	Ciphertext
+ * @v ciphertext_len	Ciphertext length
+ * @v expected		Expected plaintext
+ * @v expected_len	Expected plaintext length
+ */
+#define pubkey_decrypt_ok( pubkey, key, key_len, ciphertext,		\
+			   ciphertext_len, expected, expected_len ) do {\
+	uint8_t ctx[ (pubkey)->ctxsize ];				\
+									\
+	ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 );	\
+	{								\
+		size_t max_len = pubkey_max_len ( (pubkey), ctx );	\
+		uint8_t decrypted[ max_len ];				\
+		int decrypted_len;					\
+									\
+		decrypted_len = pubkey_decrypt ( (pubkey), ctx,		\
+						 (ciphertext),		\
+						 (ciphertext_len),	\
+						 decrypted );		\
+		ok ( decrypted_len == ( ( int ) (expected_len) ) );	\
+		ok ( memcmp ( decrypted, (expected),			\
+			      (expected_len) ) == 0 );			\
+	}								\
+	pubkey_final ( (pubkey), ctx );					\
+	} while ( 0 )
+
+/**
+ * Report public key encryption and decryption test result
+ *
+ * @v pubkey		Public key algorithm
+ * @v encrypt_key	Encryption key
+ * @v encrypt_key_len	Encryption key length
+ * @v decrypt_key	Decryption key
+ * @v decrypt_key_len	Decryption key length
+ * @v plaintext		Plaintext
+ * @v plaintext_len	Plaintext length
+ */
+#define pubkey_encrypt_ok( pubkey, encrypt_key, encrypt_key_len,	\
+			   decrypt_key, decrypt_key_len, plaintext,	\
+			   plaintext_len ) do {				\
+	uint8_t ctx[ (pubkey)->ctxsize ];				\
+									\
+	ok ( pubkey_init ( (pubkey), ctx, (encrypt_key),		\
+			   (encrypt_key_len) ) == 0 );			\
+	{								\
+		size_t max_len = pubkey_max_len ( (pubkey), ctx );	\
+		uint8_t encrypted[ max_len ];				\
+		int encrypted_len;					\
+									\
+		encrypted_len = pubkey_encrypt ( (pubkey), ctx,		\
+						 (plaintext),		\
+						 (plaintext_len),	\
+						 encrypted );		\
+		ok ( encrypted_len >= 0 );				\
+		pubkey_decrypt_ok ( (pubkey), (decrypt_key),		\
+				    (decrypt_key_len), encrypted,	\
+				    encrypted_len, (plaintext),		\
+				    (plaintext_len) );			\
+	}								\
+	pubkey_final ( (pubkey), ctx );					\
+	} while ( 0 )
+
+/**
+ * Report public key signature test result
+ *
+ * @v pubkey		Public key algorithm
+ * @v key		Key
+ * @v key_len		Key length
+ * @v digest		Digest algorithm
+ * @v plaintext		Plaintext
+ * @v plaintext_len	Plaintext length
+ * @v expected		Expected signature
+ * @v expected_len	Expected signature length
+ */
+#define pubkey_sign_ok( pubkey, key, key_len, digest, plaintext,	\
+			plaintext_len, expected, expected_len ) do {	\
+	uint8_t ctx[ (pubkey)->ctxsize ];				\
+	uint8_t digestctx[ (digest)->ctxsize ];				\
+	uint8_t digestout[ (digest)->digestsize ];			\
+									\
+	digest_init ( (digest), digestctx );				\
+	digest_update ( (digest), digestctx, (plaintext),		\
+			(plaintext_len) );				\
+	digest_final ( (digest), digestctx, digestout );		\
+									\
+	ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 );	\
+	{								\
+		size_t max_len = pubkey_max_len ( (pubkey), ctx );	\
+		uint8_t signature[ max_len ];				\
+		int signature_len;					\
+									\
+		signature_len = pubkey_sign ( (pubkey), ctx, (digest),	\
+					      digestout, signature );	\
+		ok ( signature_len == ( ( int ) (expected_len) ) );	\
+		ok ( memcmp ( signature, (expected),			\
+			      (expected_len) ) == 0 );			\
+	}								\
+	pubkey_final ( (pubkey), ctx );					\
+	} while ( 0 )
+
+/**
+ * Report public key verification test result
+ *
+ * @v pubkey		Public key algorithm
+ * @v key		Key
+ * @v key_len		Key length
+ * @v digest		Digest algorithm
+ * @v plaintext		Plaintext
+ * @v plaintext_len	Plaintext length
+ * @v signature		Signature
+ * @v signature_len	Signature length
+ */
+#define pubkey_verify_ok( pubkey, key, key_len, digest, plaintext,	\
+			  plaintext_len, signature, signature_len ) do {\
+	uint8_t ctx[ (pubkey)->ctxsize ];				\
+	uint8_t digestctx[ (digest)->ctxsize ];				\
+	uint8_t digestout[ (digest)->digestsize ];			\
+									\
+	digest_init ( (digest), digestctx );				\
+	digest_update ( (digest), digestctx, (plaintext),		\
+			(plaintext_len) );				\
+	digest_final ( (digest), digestctx, digestout );		\
+									\
+	ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 );	\
+	ok ( pubkey_verify ( (pubkey), ctx, (digest), digestout,	\
+			     (signature), (signature_len) ) == 0 );	\
+	pubkey_final ( (pubkey), ctx );					\
+	} while ( 0 )
+
+/**
+ * Report public key verification test result
+ *
+ * @v pubkey		Public key algorithm
+ * @v key		Key
+ * @v key_len		Key length
+ * @v digest		Digest algorithm
+ * @v plaintext		Plaintext
+ * @v plaintext_len	Plaintext length
+ * @v signature		Signature
+ * @v signature_len	Signature length
+ */
+#define pubkey_verify_fail_ok( pubkey, key, key_len, digest, plaintext,	\
+			       plaintext_len, signature,		\
+			       signature_len ) do {			\
+	uint8_t ctx[ (pubkey)->ctxsize ];				\
+	uint8_t digestctx[ (digest)->ctxsize ];				\
+	uint8_t digestout[ (digest)->digestsize ];			\
+									\
+	digest_init ( (digest), digestctx );				\
+	digest_update ( (digest), digestctx, (plaintext),		\
+			(plaintext_len) );				\
+	digest_final ( (digest), digestctx, digestout );		\
+									\
+	ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 );	\
+	ok ( pubkey_verify ( (pubkey), ctx, (digest), digestout,	\
+			     (signature), (signature_len) ) != 0 );	\
+	pubkey_final ( (pubkey), ctx );					\
+	} while ( 0 )
+
+#endif /* _PUBKEY_TEST_H */
diff --git a/roms/ipxe/src/tests/rsa_test.c b/roms/ipxe/src/tests/rsa_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..3b32c74bcb8264abcab5dc259e919667c3ad9148
--- /dev/null
+++ b/roms/ipxe/src/tests/rsa_test.c
@@ -0,0 +1,492 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * RSA self-tests
+ *
+ * These test vectors are generated using openssl's genrsa, rsa,
+ * rsautl, and dgst tools.
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <ipxe/crypto.h>
+#include <ipxe/rsa.h>
+#include <ipxe/md5.h>
+#include <ipxe/sha1.h>
+#include <ipxe/sha256.h>
+#include <ipxe/test.h>
+#include "pubkey_test.h"
+
+/** Define inline private key data */
+#define PRIVATE(...) { __VA_ARGS__ }
+
+/** Define inline public key data */
+#define PUBLIC(...) { __VA_ARGS__ }
+
+/** Define inline plaintext data */
+#define PLAINTEXT(...) { __VA_ARGS__ }
+
+/** Define inline ciphertext data */
+#define CIPHERTEXT(...) { __VA_ARGS__ }
+
+/** Define inline signature data */
+#define SIGNATURE(...) { __VA_ARGS__ }
+
+/** An RSA encryption and decryption self-test */
+struct rsa_encrypt_decrypt_test {
+	/** Private key */
+	const void *private;
+	/** Private key length */
+	size_t private_len;
+	/** Public key */
+	const void *public;
+	/** Public key length */
+	size_t public_len;
+	/** Plaintext */
+	const void *plaintext;
+	/** Plaintext length */
+	size_t plaintext_len;
+	/** Ciphertext
+	 *
+	 * Note that the encryption process includes some random
+	 * padding, so a given plaintext will encrypt to multiple
+	 * different ciphertexts.
+	 */
+	const void *ciphertext;
+	/** Ciphertext length */
+	size_t ciphertext_len;
+};
+
+/**
+ * Define an RSA encryption and decryption test
+ *
+ * @v name		Test name
+ * @v PRIVATE		Private key
+ * @v PUBLIC		Public key
+ * @v PLAINTEXT		Plaintext
+ * @v CIPHERTEXT	Ciphertext
+ * @ret test		Encryption and decryption test
+ */
+#define RSA_ENCRYPT_DECRYPT_TEST( name, PRIVATE, PUBLIC, PLAINTEXT,	\
+				  CIPHERTEXT )				\
+	static const uint8_t name ## _private[] = PRIVATE;		\
+	static const uint8_t name ## _public[] = PUBLIC;		\
+	static const uint8_t name ## _plaintext[] = PLAINTEXT;		\
+	static const uint8_t name ## _ciphertext[] = CIPHERTEXT;	\
+	static struct rsa_encrypt_decrypt_test name = {			\
+		.private = name ## _private,				\
+		.private_len = sizeof ( name ## _private ),		\
+		.public = name ## _public,				\
+		.public_len = sizeof ( name ## _public ),		\
+		.plaintext = name ## _plaintext,			\
+		.plaintext_len = sizeof ( name ## _plaintext ),		\
+		.ciphertext = name ## _ciphertext,			\
+		.ciphertext_len = sizeof ( name ## _ciphertext ),	\
+	}
+
+/** An RSA signature self-test */
+struct rsa_signature_test {
+	/** Private key */
+	const void *private;
+	/** Private key length */
+	size_t private_len;
+	/** Public key */
+	const void *public;
+	/** Public key length */
+	size_t public_len;
+	/** Plaintext */
+	const void *plaintext;
+	/** Plaintext length */
+	size_t plaintext_len;
+	/** Digest algorithm */
+	struct digest_algorithm *digest;
+	/** Signature */
+	const void *signature;
+	/** Signature length */
+	size_t signature_len;
+};
+
+/**
+ * Define an RSA signature test
+ *
+ * @v name		Test name
+ * @v PRIVATE		Private key
+ * @v PUBLIC		Public key
+ * @v PLAINTEXT		Plaintext
+ * @v DIGEST		Digest algorithm
+ * @v SIGNATURE		Signature
+ * @ret test		Signature test
+ */
+#define RSA_SIGNATURE_TEST( name, PRIVATE, PUBLIC, PLAINTEXT, DIGEST,	\
+			    SIGNATURE )					\
+	static const uint8_t name ## _private[] = PRIVATE;		\
+	static const uint8_t name ## _public[] = PUBLIC;		\
+	static const uint8_t name ## _plaintext[] = PLAINTEXT;		\
+	static const uint8_t name ## _signature[] = SIGNATURE;		\
+	static struct rsa_signature_test name = {			\
+		.private = name ## _private,				\
+		.private_len = sizeof ( name ## _private ),		\
+		.public = name ## _public,				\
+		.public_len = sizeof ( name ## _public ),		\
+		.plaintext = name ## _plaintext,			\
+		.plaintext_len = sizeof ( name ## _plaintext ),		\
+		.digest = DIGEST,					\
+		.signature = name ## _signature,			\
+		.signature_len = sizeof ( name ## _signature ),		\
+	}
+
+/**
+ * Report RSA encryption and decryption test result
+ *
+ * @v test		RSA encryption and decryption test
+ */
+#define rsa_encrypt_decrypt_ok( test ) do {				\
+	pubkey_decrypt_ok ( &rsa_algorithm, (test)->private,		\
+			    (test)->private_len, (test)->ciphertext,	\
+			    (test)->ciphertext_len, (test)->plaintext,	\
+			    (test)->plaintext_len );			\
+	pubkey_encrypt_ok ( &rsa_algorithm, (test)->private,		\
+			    (test)->private_len, (test)->public,	\
+			    (test)->public_len, (test)->plaintext,	\
+			    (test)->plaintext_len );			\
+	pubkey_encrypt_ok ( &rsa_algorithm, (test)->public,		\
+			    (test)->public_len, (test)->private,	\
+			    (test)->private_len, (test)->plaintext,	\
+			    (test)->plaintext_len );			\
+	} while ( 0 )
+
+
+/**
+ * Report RSA signature test result
+ *
+ * @v test		RSA signature test
+ */
+#define rsa_signature_ok( test ) do {					\
+	uint8_t bad_signature[ (test)->signature_len ];			\
+	pubkey_sign_ok ( &rsa_algorithm, (test)->private,		\
+			 (test)->private_len, (test)->digest,		\
+			 (test)->plaintext, (test)->plaintext_len,	\
+			 (test)->signature, (test)->signature_len );	\
+	pubkey_verify_ok ( &rsa_algorithm, (test)->public,		\
+			   (test)->public_len, (test)->digest,		\
+			   (test)->plaintext, (test)->plaintext_len,	\
+			   (test)->signature, (test)->signature_len );	\
+	memset ( bad_signature, 0, sizeof ( bad_signature ) );		\
+	pubkey_verify_fail_ok ( &rsa_algorithm, (test)->public,		\
+				(test)->public_len, (test)->digest,	\
+				(test)->plaintext,			\
+				(test)->plaintext_len, bad_signature,	\
+				sizeof ( bad_signature ) );		\
+	} while ( 0 )
+
+/** "Hello world" encryption and decryption test */
+RSA_ENCRYPT_DECRYPT_TEST ( hw_test,
+	PRIVATE ( 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00,
+		  0xd2, 0xf1, 0x04, 0x67, 0xf6, 0x2c, 0x96, 0x07, 0xa6, 0xbd,
+		  0x85, 0xac, 0xc1, 0x17, 0x5d, 0xe8, 0xf0, 0x93, 0x94, 0x0c,
+		  0x45, 0x67, 0x26, 0x67, 0xde, 0x7e, 0xfb, 0xa8, 0xda, 0xbd,
+		  0x07, 0xdf, 0xcf, 0x45, 0x04, 0x6d, 0xbd, 0x69, 0x8b, 0xfb,
+		  0xc1, 0x72, 0xc0, 0xfc, 0x03, 0x04, 0xf2, 0x82, 0xc4, 0x7b,
+		  0x6a, 0x3e, 0xec, 0x53, 0x7a, 0xe3, 0x4e, 0xa8, 0xc9, 0xf9,
+		  0x1f, 0x2a, 0x13, 0x0d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
+		  0x40, 0x49, 0xb8, 0x61, 0xc9, 0xd3, 0x87, 0x11, 0x87, 0xeb,
+		  0x06, 0x21, 0x49, 0x96, 0xd2, 0x0b, 0xc7, 0xf5, 0x0c, 0x1e,
+		  0x99, 0x8b, 0x47, 0xd9, 0x6c, 0x43, 0x9e, 0x2d, 0x65, 0x7d,
+		  0xcc, 0xc2, 0x8b, 0x1a, 0x6f, 0x2b, 0x55, 0xbe, 0xb3, 0x9f,
+		  0xd1, 0xe2, 0x9a, 0xde, 0x1d, 0xac, 0xec, 0x67, 0xec, 0xa5,
+		  0xbf, 0x9c, 0x30, 0xd6, 0xf9, 0x0a, 0x1a, 0x48, 0xf3, 0xc2,
+		  0x93, 0x3a, 0x17, 0x27, 0x21, 0x02, 0x21, 0x00, 0xfc, 0x8d,
+		  0xfb, 0xee, 0x8a, 0xaa, 0x45, 0x19, 0x4b, 0xf0, 0x68, 0xb0,
+		  0x02, 0x38, 0x3e, 0x03, 0x6b, 0x24, 0x77, 0x20, 0xbd, 0x5e,
+		  0x6c, 0x76, 0xdb, 0xc9, 0xe1, 0x43, 0xa3, 0x40, 0x62, 0x6f,
+		  0x02, 0x21, 0x00, 0xd5, 0xd1, 0xb4, 0x4d, 0x03, 0x40, 0x69,
+		  0x3f, 0x9a, 0xa7, 0x44, 0x15, 0x28, 0x1e, 0xa5, 0x5f, 0xcf,
+		  0x97, 0x21, 0x12, 0xb3, 0xe6, 0x1c, 0x9a, 0x8d, 0xb7, 0xb4,
+		  0x80, 0x3a, 0x9c, 0xb0, 0x43, 0x02, 0x20, 0x71, 0xf0, 0xa0,
+		  0xab, 0x82, 0xf5, 0xc4, 0x8c, 0xe0, 0x1c, 0xcb, 0x2e, 0x35,
+		  0x22, 0x28, 0xa0, 0x24, 0x33, 0x64, 0x67, 0x69, 0xe7, 0xf2,
+		  0xa9, 0x41, 0x09, 0x78, 0x4e, 0xaa, 0x95, 0x3e, 0x93, 0x02,
+		  0x21, 0x00, 0x85, 0xcc, 0x4d, 0xd9, 0x0b, 0x39, 0xd9, 0x22,
+		  0x75, 0xf2, 0x49, 0x46, 0x3b, 0xee, 0xc1, 0x69, 0x6d, 0x0b,
+		  0x93, 0x24, 0x92, 0xf2, 0x61, 0xdf, 0xcc, 0xe2, 0xb1, 0xce,
+		  0xb3, 0xde, 0xac, 0xe5, 0x02, 0x21, 0x00, 0x9c, 0x23, 0x6a,
+		  0x95, 0xa6, 0xfe, 0x1e, 0xd8, 0x0c, 0x3f, 0x6e, 0xe6, 0x0a,
+		  0xeb, 0x97, 0xd6, 0x36, 0x1c, 0x80, 0xc1, 0x02, 0x87, 0x0d,
+		  0x4d, 0xfe, 0x28, 0x02, 0x1e, 0xde, 0xe1, 0xcc, 0x72 ),
+	PUBLIC ( 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+		 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00,
+		 0x30, 0x48, 0x02, 0x41, 0x00, 0xd2, 0xf1, 0x04, 0x67, 0xf6,
+		 0x2c, 0x96, 0x07, 0xa6, 0xbd, 0x85, 0xac, 0xc1, 0x17, 0x5d,
+		 0xe8, 0xf0, 0x93, 0x94, 0x0c, 0x45, 0x67, 0x26, 0x67, 0xde,
+		 0x7e, 0xfb, 0xa8, 0xda, 0xbd, 0x07, 0xdf, 0xcf, 0x45, 0x04,
+		 0x6d, 0xbd, 0x69, 0x8b, 0xfb, 0xc1, 0x72, 0xc0, 0xfc, 0x03,
+		 0x04, 0xf2, 0x82, 0xc4, 0x7b, 0x6a, 0x3e, 0xec, 0x53, 0x7a,
+		 0xe3, 0x4e, 0xa8, 0xc9, 0xf9, 0x1f, 0x2a, 0x13, 0x0d, 0x02,
+		 0x03, 0x01, 0x00, 0x01 ),
+	PLAINTEXT ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c,
+		    0x64, 0x0a ),
+	CIPHERTEXT ( 0x39, 0xff, 0x5c, 0x54, 0x65, 0x3e, 0x6a, 0xab, 0xc0, 0x62,
+		     0x91, 0xb2, 0xbf, 0x1d, 0x73, 0x5b, 0xd5, 0x4c, 0xbd, 0x16,
+		     0x0f, 0x24, 0xc9, 0xf5, 0xa7, 0xdd, 0x94, 0xd6, 0xf8, 0xae,
+		     0xd3, 0xa0, 0x9f, 0x4d, 0xff, 0x8d, 0x81, 0x34, 0x47, 0xff,
+		     0x2a, 0x87, 0x96, 0xd3, 0x17, 0x5d, 0x93, 0x4d, 0x7b, 0x27,
+		     0x88, 0x4f, 0xec, 0x43, 0x9c, 0xed, 0xb3, 0xf2, 0x19, 0x89,
+		     0x38, 0x43, 0xf9, 0x41 ) );
+
+/** Random message MD5 signature test */
+RSA_SIGNATURE_TEST ( md5_test,
+	PRIVATE ( 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00,
+		  0xf9, 0x3f, 0x78, 0x44, 0xe2, 0x0e, 0x25, 0xf1, 0x0e, 0x94,
+		  0xcd, 0xca, 0x6f, 0x9e, 0xea, 0x6d, 0xdf, 0xcd, 0xa0, 0x7c,
+		  0xe2, 0x21, 0xeb, 0xde, 0xa6, 0x01, 0x4b, 0xb0, 0x76, 0x4b,
+		  0xd8, 0x8b, 0x19, 0x83, 0xb4, 0xbe, 0x45, 0xde, 0x3d, 0x46,
+		  0x61, 0x0f, 0x11, 0xe2, 0x2c, 0xf5, 0xb0, 0x63, 0xa0, 0x84,
+		  0xc0, 0xaf, 0x4e, 0xbe, 0x6a, 0xd3, 0x84, 0x3f, 0xec, 0x42,
+		  0x17, 0xe9, 0x25, 0xe1, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
+		  0x40, 0x62, 0x7d, 0x93, 0x1f, 0xdd, 0x17, 0xec, 0x24, 0x42,
+		  0x37, 0xc8, 0xce, 0x0a, 0xa7, 0x88, 0x49, 0x5c, 0x9b, 0x9b,
+		  0xa4, 0x5d, 0x93, 0x3b, 0xea, 0x62, 0x3c, 0xb6, 0xd5, 0x07,
+		  0x19, 0xd7, 0x79, 0xf0, 0x3b, 0xab, 0xa3, 0xa5, 0x43, 0x35,
+		  0x8d, 0x58, 0x40, 0xa0, 0x95, 0xc5, 0x63, 0x28, 0x28, 0xda,
+		  0x13, 0x28, 0xdf, 0xc9, 0x05, 0xdc, 0x69, 0x46, 0xff, 0x2a,
+		  0xfb, 0xe4, 0xd1, 0x23, 0xa5, 0x02, 0x21, 0x00, 0xfc, 0xef,
+		  0x3b, 0x9d, 0x9d, 0x69, 0xf3, 0x66, 0x0a, 0x2b, 0x52, 0xd6,
+		  0x61, 0x14, 0x90, 0x6e, 0x7d, 0x3c, 0x08, 0x4b, 0x98, 0x44,
+		  0x00, 0xf2, 0xa4, 0x16, 0x2d, 0xd1, 0xf9, 0xa0, 0x1e, 0x37,
+		  0x02, 0x21, 0x00, 0xfc, 0x44, 0xcc, 0x7c, 0xc0, 0x26, 0x9a,
+		  0x0a, 0x6e, 0xda, 0x17, 0x05, 0x7d, 0x66, 0x8d, 0x29, 0x1a,
+		  0x44, 0xbf, 0x33, 0x76, 0xae, 0x8d, 0xe8, 0xb5, 0xed, 0xb8,
+		  0x6f, 0xdc, 0xfe, 0x10, 0xa7, 0x02, 0x20, 0x76, 0x48, 0x8a,
+		  0x60, 0x93, 0x14, 0xd1, 0x36, 0x8e, 0xda, 0xe3, 0xca, 0x4d,
+		  0x6c, 0x08, 0x7f, 0x23, 0x21, 0xc7, 0xdf, 0x52, 0x3d, 0xbb,
+		  0x13, 0xbd, 0x98, 0x81, 0xa5, 0x08, 0x4f, 0xd0, 0xd1, 0x02,
+		  0x21, 0x00, 0xd9, 0xa3, 0x11, 0x37, 0xdf, 0x1e, 0x6e, 0x6e,
+		  0xe9, 0xcb, 0xc5, 0x68, 0xbb, 0x13, 0x2a, 0x5d, 0x77, 0x88,
+		  0x2f, 0xdc, 0x5a, 0x5b, 0xa5, 0x9a, 0x4a, 0xba, 0x58, 0x10,
+		  0x49, 0xfb, 0xf6, 0xa9, 0x02, 0x21, 0x00, 0x89, 0xe8, 0x47,
+		  0x5b, 0x20, 0x04, 0x3b, 0x0f, 0xb9, 0xe0, 0x1d, 0xab, 0xcf,
+		  0xe8, 0x72, 0xfd, 0x7d, 0x17, 0x85, 0xc8, 0xd8, 0xbd, 0x1a,
+		  0x92, 0xe0, 0xbc, 0x7a, 0xc7, 0x31, 0xbe, 0xef, 0xf4 ),
+	PUBLIC ( 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+		 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00,
+		 0x30, 0x48, 0x02, 0x41, 0x00, 0xf9, 0x3f, 0x78, 0x44, 0xe2,
+		 0x0e, 0x25, 0xf1, 0x0e, 0x94, 0xcd, 0xca, 0x6f, 0x9e, 0xea,
+		 0x6d, 0xdf, 0xcd, 0xa0, 0x7c, 0xe2, 0x21, 0xeb, 0xde, 0xa6,
+		 0x01, 0x4b, 0xb0, 0x76, 0x4b, 0xd8, 0x8b, 0x19, 0x83, 0xb4,
+		 0xbe, 0x45, 0xde, 0x3d, 0x46, 0x61, 0x0f, 0x11, 0xe2, 0x2c,
+		 0xf5, 0xb0, 0x63, 0xa0, 0x84, 0xc0, 0xaf, 0x4e, 0xbe, 0x6a,
+		 0xd3, 0x84, 0x3f, 0xec, 0x42, 0x17, 0xe9, 0x25, 0xe1, 0x02,
+		 0x03, 0x01, 0x00, 0x01 ),
+	PLAINTEXT ( 0x9d, 0x5b, 0x46, 0x42, 0x27, 0xc0, 0xf1, 0x4b, 0xe5, 0x9e,
+		    0xd3, 0x10, 0xa1, 0xeb, 0x16, 0xc3, 0xc6, 0x8f, 0x1a, 0x18,
+		    0x86, 0xc3, 0x92, 0x15, 0x2d, 0x65, 0xa0, 0x40, 0xe1, 0x3e,
+		    0x29, 0x79, 0x7c, 0xd4, 0x08, 0xef, 0x53, 0xeb, 0x08, 0x07,
+		    0x39, 0x21, 0xb3, 0x40, 0xff, 0x4b, 0xc7, 0x76, 0xb9, 0x12,
+		    0x32, 0x41, 0xcc, 0x5a, 0x86, 0x5c, 0x2e, 0x0b, 0x05, 0xd8,
+		    0x56, 0xd4, 0xdf, 0x6f, 0x2c, 0xf0, 0xbf, 0x4b, 0x6f, 0x68,
+		    0xde, 0x39, 0x4a, 0x3e, 0xae, 0x44, 0xb9, 0xc6, 0x24, 0xb3,
+		    0x83, 0x2e, 0x9f, 0xf5, 0x6d, 0x61, 0xc3, 0x8e, 0xe8, 0x8f,
+		    0xa6, 0x87, 0x58, 0x3f, 0x36, 0x13, 0xf4, 0x7e, 0xf0, 0x20,
+		    0x47, 0x87, 0x3f, 0x21, 0x6e, 0x51, 0x3c, 0xf1, 0xef, 0xca,
+		    0x9f, 0x77, 0x9c, 0x91, 0x4f, 0xd4, 0x56, 0xc0, 0x39, 0x11,
+		    0xab, 0x15, 0x2c, 0x5e, 0xad, 0x40, 0x09, 0xe6, 0xde, 0xe5,
+		    0x77, 0x60, 0x19, 0xd4, 0x0d, 0x77, 0x76, 0x24, 0x8b, 0xe6,
+		    0xdd, 0xa5, 0x8d, 0x4a, 0x55, 0x3a, 0xdf, 0xf8, 0x29, 0xfb,
+		    0x47, 0x8a, 0xfe, 0x98, 0x34, 0xf6, 0x30, 0x7f, 0x09, 0x03,
+		    0x26, 0x05, 0xd5, 0x46, 0x18, 0x96, 0xca, 0x96, 0x5b, 0x66,
+		    0xf2, 0x8d, 0xfc, 0xfc, 0x37, 0xf7, 0xc7, 0x6d, 0x6c, 0xd8,
+		    0x24, 0x0c, 0x6a, 0xec, 0x82, 0x5c, 0x72, 0xf1, 0xfc, 0x05,
+		    0xed, 0x8e, 0xe8, 0xd9, 0x8b, 0x8b, 0x67, 0x02, 0x95 ),
+	&md5_algorithm,
+	SIGNATURE ( 0xdb, 0x56, 0x3d, 0xea, 0xae, 0x81, 0x4b, 0x3b, 0x2e, 0x8e,
+		    0xb8, 0xee, 0x13, 0x61, 0xc6, 0xe7, 0xd7, 0x50, 0xcd, 0x0d,
+		    0x34, 0x3a, 0xfe, 0x9a, 0x8d, 0xf8, 0xfb, 0xd6, 0x7e, 0xbd,
+		    0xdd, 0xb3, 0xf9, 0xfb, 0xe0, 0xf8, 0xe7, 0x71, 0x03, 0xe6,
+		    0x55, 0xd5, 0xf4, 0x02, 0x3c, 0xb5, 0xbc, 0x95, 0x2b, 0x66,
+		    0x56, 0xec, 0x2f, 0x8e, 0xa7, 0xae, 0xd9, 0x80, 0xb3, 0xaa,
+		    0xac, 0x45, 0x00, 0xa8 ) );
+
+/** Random message SHA-1 signature test */
+RSA_SIGNATURE_TEST ( sha1_test,
+	PRIVATE ( 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00,
+		  0xe0, 0x3a, 0x8d, 0x35, 0xe1, 0x92, 0x2f, 0xea, 0x0d, 0x82,
+		  0x60, 0x2e, 0xb6, 0x0b, 0x02, 0xd3, 0xf4, 0x39, 0xfb, 0x06,
+		  0x43, 0x8e, 0xa1, 0x7c, 0xc5, 0xae, 0x0d, 0xc7, 0xee, 0x83,
+		  0xb3, 0x63, 0x20, 0x92, 0x34, 0xe2, 0x94, 0x3d, 0xdd, 0xbb,
+		  0x6c, 0x64, 0x69, 0x68, 0x25, 0x24, 0x81, 0x4b, 0x4d, 0x48,
+		  0x5a, 0xd2, 0x29, 0x14, 0xeb, 0x38, 0xdd, 0x3e, 0xb5, 0x57,
+		  0x45, 0x9b, 0xed, 0x33, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
+		  0x40, 0x3d, 0xa9, 0x1c, 0x47, 0xe2, 0xdd, 0xf6, 0x7b, 0x20,
+		  0x77, 0xe7, 0xc7, 0x30, 0x9c, 0x5a, 0x8c, 0xba, 0xae, 0x6f,
+		  0x0f, 0x4b, 0xe8, 0x9f, 0x13, 0xd6, 0xb0, 0x84, 0x6d, 0xa4,
+		  0x73, 0x67, 0x12, 0xa9, 0x7c, 0x75, 0xaf, 0x62, 0x92, 0x7b,
+		  0x80, 0xaf, 0x39, 0x7d, 0x01, 0xb3, 0x43, 0xc8, 0x0d, 0x17,
+		  0x7f, 0x82, 0x59, 0x46, 0xb8, 0xe5, 0x4e, 0xba, 0x5e, 0x71,
+		  0x5c, 0xba, 0x62, 0x06, 0x91, 0x02, 0x21, 0x00, 0xf7, 0xaa,
+		  0xb6, 0x9c, 0xc8, 0xad, 0x68, 0xa8, 0xd7, 0x25, 0xb1, 0xb5,
+		  0x91, 0xd4, 0xc7, 0xd6, 0x69, 0x51, 0x5d, 0x04, 0xed, 0xd8,
+		  0xc6, 0xea, 0x69, 0xd2, 0x24, 0xbe, 0x5e, 0x7c, 0x89, 0xa5,
+		  0x02, 0x21, 0x00, 0xe7, 0xc5, 0xf4, 0x01, 0x35, 0xe0, 0x16,
+		  0xb5, 0x13, 0x86, 0x14, 0x5a, 0x6a, 0x8d, 0x03, 0x90, 0xae,
+		  0x7d, 0x3a, 0xc1, 0xfe, 0x8c, 0xa0, 0x4a, 0xb4, 0x94, 0x50,
+		  0x58, 0xa4, 0xc6, 0x73, 0xf7, 0x02, 0x21, 0x00, 0xe2, 0xda,
+		  0x16, 0x6c, 0x63, 0x90, 0x1a, 0xc6, 0x54, 0x53, 0x2d, 0x84,
+		  0x8f, 0x70, 0x24, 0x1f, 0x6b, 0xd6, 0x5f, 0xea, 0x8c, 0xe5,
+		  0xbb, 0xc5, 0xa9, 0x6a, 0x17, 0xc7, 0xdb, 0x8a, 0x1d, 0x15,
+		  0x02, 0x21, 0x00, 0xe4, 0x2a, 0x7e, 0xe4, 0x76, 0x2a, 0x2d,
+		  0x90, 0x83, 0x30, 0xda, 0x76, 0x8c, 0x30, 0x58, 0x13, 0x25,
+		  0x83, 0x88, 0xc5, 0x93, 0x96, 0xd2, 0xf1, 0xd8, 0x45, 0xad,
+		  0xb7, 0x26, 0x37, 0x6b, 0xcf, 0x02, 0x20, 0x73, 0x58, 0x1f,
+		  0x0a, 0xcd, 0x0c, 0x83, 0x27, 0xcc, 0x15, 0xa2, 0x1e, 0x07,
+		  0x32, 0x1b, 0xa3, 0xc6, 0xa6, 0xb8, 0x83, 0x97, 0x48, 0x45,
+		  0x50, 0x6c, 0x37, 0x45, 0xa5, 0x54, 0x2a, 0x59, 0x3c ),
+	PUBLIC ( 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+		 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00,
+		 0x30, 0x48, 0x02, 0x41, 0x00, 0xe0, 0x3a, 0x8d, 0x35, 0xe1,
+		 0x92, 0x2f, 0xea, 0x0d, 0x82, 0x60, 0x2e, 0xb6, 0x0b, 0x02,
+		 0xd3, 0xf4, 0x39, 0xfb, 0x06, 0x43, 0x8e, 0xa1, 0x7c, 0xc5,
+		 0xae, 0x0d, 0xc7, 0xee, 0x83, 0xb3, 0x63, 0x20, 0x92, 0x34,
+		 0xe2, 0x94, 0x3d, 0xdd, 0xbb, 0x6c, 0x64, 0x69, 0x68, 0x25,
+		 0x24, 0x81, 0x4b, 0x4d, 0x48, 0x5a, 0xd2, 0x29, 0x14, 0xeb,
+		 0x38, 0xdd, 0x3e, 0xb5, 0x57, 0x45, 0x9b, 0xed, 0x33, 0x02,
+		 0x03, 0x01, 0x00, 0x01 ),
+	PLAINTEXT ( 0xf7, 0x42, 0x01, 0x57, 0x6b, 0x70, 0xcc, 0x4a, 0xdc, 0xed,
+		    0x12, 0x83, 0x3f, 0xef, 0x27, 0xc1, 0x3c, 0x85, 0xdd, 0x5e,
+		    0x0a, 0x34, 0x98, 0xf9, 0x21, 0xd3, 0x24, 0x2a, 0x5a, 0xb2,
+		    0xdf, 0x60, 0x21, 0x28, 0x7c, 0x5b, 0x7a, 0xbe, 0xcb, 0xea,
+		    0xbc, 0xd6, 0x0e, 0xae, 0x94, 0x64, 0x21, 0xda, 0x28, 0x66,
+		    0x2f, 0x71, 0x48, 0xe5, 0xea, 0x59, 0x38, 0x28, 0x3e, 0xed,
+		    0x3b, 0x95, 0x4f, 0x3d, 0x72, 0x2a, 0x00, 0xf3, 0x95, 0x4d,
+		    0xf0, 0x02, 0x71, 0x63, 0x5a, 0xbc, 0x84, 0xd1, 0x81, 0x3f,
+		    0x16, 0xcd, 0x28, 0x3d, 0x47, 0xa2, 0xee, 0xa1, 0x2f, 0x84,
+		    0x8a, 0x22, 0x02, 0x88, 0xd7, 0x83, 0x06, 0x4a, 0x9f, 0xea,
+		    0x0f, 0x15, 0x48, 0x43, 0x58, 0x6d, 0x39, 0x78, 0x5a, 0x43,
+		    0x3f, 0xed, 0x6f, 0x68, 0xde, 0x9c, 0xfe, 0xd3, 0x67, 0x74,
+		    0x08, 0x46, 0x7d, 0x20, 0x22, 0x60, 0x8c, 0x37, 0x35, 0x46,
+		    0x56, 0x19, 0x3c, 0xfa, 0xa5, 0x40, 0xac, 0x44, 0x90, 0x8a,
+		    0xa5, 0x80, 0xb2, 0x32, 0xbc, 0xb4, 0x3f, 0x3e, 0x5e, 0xd4,
+		    0x51, 0xa9, 0x2e, 0xd9, 0x7f, 0x5e, 0x32, 0xb1, 0x24, 0x35,
+		    0x88, 0x71, 0x3a, 0x01, 0x86, 0x5c, 0xa2, 0xe2, 0x2d, 0x02,
+		    0x30, 0x91, 0x1c, 0xaa, 0x6c, 0x24, 0x42, 0x1b, 0x1a, 0xba,
+		    0x30, 0x40, 0x49, 0x83, 0xd9, 0xd7, 0x66, 0x7e, 0x5c, 0x1a,
+		    0x4b, 0x7f, 0xa6, 0x8e, 0x8a, 0xd6, 0x0c, 0x65, 0x75 ),
+	&sha1_algorithm,
+	SIGNATURE ( 0xa5, 0x5a, 0x8a, 0x67, 0x81, 0x76, 0x7e, 0xad, 0x99, 0x22,
+		    0xf1, 0x47, 0x64, 0xd2, 0xfb, 0x81, 0x45, 0xeb, 0x85, 0x56,
+		    0xf8, 0x7d, 0xb8, 0xec, 0x41, 0x17, 0x84, 0xf7, 0x2b, 0xbb,
+		    0x2b, 0x8f, 0xb6, 0xb8, 0x8f, 0xc6, 0xab, 0x39, 0xbc, 0xa3,
+		    0x72, 0xb3, 0x63, 0x45, 0x5a, 0xe0, 0xac, 0xf8, 0x1c, 0x83,
+		    0x48, 0x84, 0x89, 0x8a, 0x6b, 0xdf, 0x93, 0xa0, 0xc3, 0x0b,
+		    0x0e, 0x3d, 0x80, 0x80 ) );
+
+/** Random message SHA-256 signature test */
+RSA_SIGNATURE_TEST ( sha256_test,
+	PRIVATE ( 0x30, 0x82, 0x01, 0x3a, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00,
+		  0xa5, 0xe9, 0xdb, 0xa9, 0x1a, 0x6e, 0xd6, 0x4c, 0x25, 0x50,
+		  0xfe, 0x61, 0x77, 0x08, 0x7a, 0x80, 0x36, 0xcb, 0x88, 0x49,
+		  0x5c, 0xe8, 0xaa, 0x15, 0xf8, 0xb3, 0xd6, 0x78, 0x51, 0x46,
+		  0x86, 0x3a, 0x5f, 0xd5, 0x9f, 0xab, 0xfe, 0x74, 0x8c, 0x53,
+		  0x0d, 0xb5, 0x3c, 0x7d, 0x2c, 0x35, 0x88, 0x3f, 0xde, 0xa2,
+		  0xce, 0x46, 0x94, 0x30, 0xa9, 0x76, 0xee, 0x25, 0xc5, 0x5d,
+		  0xa6, 0xa6, 0x3a, 0xa5, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
+		  0x40, 0x14, 0x4b, 0xbc, 0x4c, 0x3e, 0x68, 0x8a, 0x9c, 0x7c,
+		  0x00, 0x21, 0x6e, 0x28, 0xd2, 0x87, 0xb1, 0xc1, 0x82, 0x3a,
+		  0x64, 0xc7, 0x11, 0xcb, 0x24, 0xae, 0xec, 0xc8, 0xf2, 0xa4,
+		  0xf6, 0x9c, 0x9a, 0xbb, 0x05, 0x94, 0x80, 0x9b, 0xc1, 0x21,
+		  0x83, 0x36, 0x23, 0xba, 0x04, 0x20, 0x23, 0x06, 0x48, 0xa7,
+		  0xa4, 0xe6, 0x31, 0x8e, 0xa1, 0x73, 0xe5, 0x6b, 0x83, 0x4c,
+		  0x3a, 0xb8, 0xd8, 0x22, 0x61, 0x02, 0x21, 0x00, 0xd4, 0xdf,
+		  0xcb, 0x21, 0x4a, 0x9a, 0x35, 0x52, 0x02, 0x99, 0xcc, 0x40,
+		  0x83, 0x65, 0x30, 0x1f, 0x9d, 0x13, 0xd6, 0xd1, 0x79, 0x10,
+		  0xce, 0x5b, 0xeb, 0x25, 0xa2, 0x39, 0x4e, 0xdf, 0x1c, 0x29,
+		  0x02, 0x21, 0x00, 0xc7, 0x86, 0x8f, 0xd9, 0x88, 0xe9, 0x98,
+		  0x4b, 0x5c, 0x50, 0x06, 0x94, 0x05, 0x59, 0x31, 0x25, 0xa7,
+		  0xa8, 0xe6, 0x95, 0x2b, 0xe3, 0x74, 0x93, 0x51, 0xa8, 0x8e,
+		  0x3d, 0xe2, 0xe0, 0xfa, 0x1d, 0x02, 0x20, 0x6e, 0xe3, 0x81,
+		  0x31, 0xff, 0x65, 0xa3, 0x1e, 0xec, 0x61, 0xe7, 0x67, 0x37,
+		  0xcb, 0x0f, 0x2d, 0x78, 0xaa, 0xab, 0xfd, 0x84, 0x5e, 0x3f,
+		  0xd0, 0xdc, 0x06, 0x47, 0xa2, 0x28, 0xb6, 0xca, 0x39, 0x02,
+		  0x20, 0x13, 0x7d, 0x9f, 0x9b, 0xbe, 0x76, 0x23, 0x3c, 0x69,
+		  0x5e, 0x1f, 0xe6, 0x61, 0xc7, 0x5e, 0xb7, 0xb0, 0xf3, 0x1c,
+		  0xe3, 0x41, 0x90, 0x4c, 0x98, 0xff, 0x87, 0x19, 0xae, 0x0d,
+		  0xf5, 0xb0, 0x39, 0x02, 0x21, 0x00, 0xb7, 0xeb, 0xcd, 0x01,
+		  0x2e, 0x23, 0x42, 0x4f, 0x0c, 0x6f, 0xde, 0xc8, 0x4f, 0xa7,
+		  0x69, 0x09, 0x12, 0x34, 0xb6, 0x95, 0x4d, 0xb8, 0x7f, 0x16,
+		  0xd0, 0x48, 0x17, 0x4a, 0x9e, 0x6e, 0x5e, 0xe2 ),
+	PUBLIC ( 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+		 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00,
+		 0x30, 0x48, 0x02, 0x41, 0x00, 0xa5, 0xe9, 0xdb, 0xa9, 0x1a,
+		 0x6e, 0xd6, 0x4c, 0x25, 0x50, 0xfe, 0x61, 0x77, 0x08, 0x7a,
+		 0x80, 0x36, 0xcb, 0x88, 0x49, 0x5c, 0xe8, 0xaa, 0x15, 0xf8,
+		 0xb3, 0xd6, 0x78, 0x51, 0x46, 0x86, 0x3a, 0x5f, 0xd5, 0x9f,
+		 0xab, 0xfe, 0x74, 0x8c, 0x53, 0x0d, 0xb5, 0x3c, 0x7d, 0x2c,
+		 0x35, 0x88, 0x3f, 0xde, 0xa2, 0xce, 0x46, 0x94, 0x30, 0xa9,
+		 0x76, 0xee, 0x25, 0xc5, 0x5d, 0xa6, 0xa6, 0x3a, 0xa5, 0x02,
+		 0x03, 0x01, 0x00, 0x01 ),
+	PLAINTEXT ( 0x60, 0xe7, 0xba, 0x9d, 0x5a, 0xe3, 0x2d, 0xfa, 0x5f, 0x47,
+		    0xdb, 0x93, 0x24, 0x2c, 0xc4, 0xe2, 0x61, 0xf3, 0x89, 0x4d,
+		    0x67, 0xad, 0xc8, 0xae, 0xf8, 0xe2, 0xfb, 0x52, 0x0f, 0x8d,
+		    0x18, 0x7e, 0x30, 0xd8, 0x8d, 0x94, 0x07, 0x92, 0x70, 0x91,
+		    0xaf, 0x3b, 0x92, 0xa6, 0x0f, 0x7a, 0x9b, 0x46, 0x85, 0x8c,
+		    0x2a, 0x5a, 0x78, 0x5d, 0x1e, 0x13, 0xbf, 0xe6, 0x12, 0xbd,
+		    0xb1, 0xbb, 0x92, 0x6d, 0x11, 0xed, 0xe1, 0xe4, 0x6e, 0x88,
+		    0x4d, 0x0b, 0x51, 0xd6, 0xfd, 0x6a, 0xb2, 0x9b, 0xd3, 0xfd,
+		    0x56, 0xec, 0xd9, 0xd6, 0xb8, 0xc5, 0xfd, 0x0c, 0xf7, 0x55,
+		    0x5f, 0xc5, 0x6f, 0xbc, 0xbb, 0x78, 0x2f, 0x50, 0x08, 0x65,
+		    0x0f, 0x12, 0xca, 0x5a, 0xea, 0x52, 0xd0, 0x94, 0x76, 0x17,
+		    0xe4, 0xba, 0x97, 0xba, 0x11, 0xbf, 0x05, 0x7e, 0xa1, 0xfd,
+		    0x7d, 0xb5, 0xf1, 0x3a, 0x7e, 0x6f, 0xa1, 0xaa, 0x97, 0x66,
+		    0x5d, 0x72, 0x76, 0x45, 0x40, 0xb5, 0x22, 0x71, 0x43, 0xe8,
+		    0x77, 0x76, 0xc8, 0x1b, 0xd2, 0xd1, 0x33, 0x05, 0x64, 0xa9,
+		    0xc2, 0xa8, 0x40, 0x40, 0x21, 0xdd, 0xcf, 0x07, 0x7e, 0xf2,
+		    0x4b, 0x80, 0x3d, 0x0f, 0x67, 0xf6, 0xbd, 0xc2, 0xc7, 0xe3,
+		    0x91, 0x71, 0xd6, 0x2d, 0xa1, 0xae, 0x81, 0x0c, 0xed, 0x54,
+		    0x48, 0x79, 0x8a, 0x78, 0x05, 0x74, 0x4d, 0x4f, 0xf0, 0xe0,
+		    0x3c, 0x41, 0x5c, 0x04, 0x0b, 0x68, 0x57, 0xc5, 0xd6 ),
+	&sha256_algorithm,
+	SIGNATURE ( 0x02, 0x2e, 0xc5, 0x2a, 0x2b, 0x7f, 0xb4, 0x80, 0xca, 0x9d,
+		    0x96, 0x5b, 0xaf, 0x1f, 0x72, 0x5b, 0x6e, 0xf1, 0x69, 0x7f,
+		    0x4d, 0x41, 0xd5, 0x9f, 0x00, 0xdc, 0x47, 0xf4, 0x68, 0x8f,
+		    0xda, 0xfc, 0xd1, 0x23, 0x96, 0x11, 0x1d, 0xc0, 0x1b, 0x1d,
+		    0x36, 0x66, 0x2a, 0xf9, 0x21, 0x51, 0xcb, 0xb9, 0x7d, 0x24,
+		    0x7d, 0x38, 0x37, 0xc4, 0xea, 0xdd, 0x3a, 0x6f, 0xa8, 0x65,
+		    0x60, 0x73, 0x77, 0x3c ) );
+
+/**
+ * Perform RSA self-tests
+ *
+ */
+static void rsa_test_exec ( void ) {
+
+	rsa_encrypt_decrypt_ok ( &hw_test );
+	rsa_signature_ok ( &md5_test );
+	rsa_signature_ok ( &sha1_test );
+	rsa_signature_ok ( &sha256_test );
+}
+
+/** RSA self-test */
+struct self_test rsa_test __self_test = {
+	.name = "rsa",
+	.exec = rsa_test_exec,
+};
diff --git a/roms/ipxe/src/tests/settings_test.c b/roms/ipxe/src/tests/settings_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..028f8163b1502bbbd158eab48e3124c88c86ac22
--- /dev/null
+++ b/roms/ipxe/src/tests/settings_test.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Settings self-tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <string.h>
+#include <ipxe/settings.h>
+#include <ipxe/test.h>
+
+/** Define inline raw data */
+#define RAW(...) { __VA_ARGS__ }
+
+/**
+ * Report a formatted-store test result
+ *
+ * @v settings		Settings block
+ * @v setting		Setting
+ * @v formatted		Formatted value
+ * @v raw_array		Expected raw value
+ */
+#define storef_ok( settings, setting, formatted, raw_array ) do {	\
+	const uint8_t expected[] = raw_array;				\
+	uint8_t actual[ sizeof ( expected ) ];				\
+	int len;							\
+									\
+	ok ( storef_setting ( settings, setting, formatted ) == 0 );	\
+	len = fetch_setting ( settings, setting, actual,		\
+			      sizeof ( actual ) );			\
+	DBGC ( settings, "Stored %s \"%s\", got:\n",			\
+	       (setting)->type->name, formatted );			\
+	DBGC_HDA ( settings, 0, actual, len );				\
+	ok ( len == ( int ) sizeof ( actual ) );			\
+	ok ( memcmp ( actual, expected, sizeof ( actual ) ) == 0 );	\
+	} while ( 0 )
+
+/**
+ * Report a formatted-fetch test result
+ *
+ * @v settings		Settings block
+ * @v setting		Setting
+ * @v raw_array		Raw value
+ * @v formatted		Expected formatted value
+ */
+#define fetchf_ok( settings, setting, raw_array, formatted ) do {	\
+	const uint8_t raw[] = raw_array;				\
+	char actual[ strlen ( formatted ) + 1 ];			\
+	int len;							\
+									\
+	ok ( store_setting ( settings, setting, raw,			\
+			     sizeof ( raw ) ) == 0 );			\
+	len = fetchf_setting ( settings, setting, actual,		\
+			       sizeof ( actual ) );			\
+	DBGC ( settings, "Fetched %s \"%s\" from:\n",			\
+	       (setting)->type->name, formatted );			\
+	DBGC_HDA ( settings, 0, raw, sizeof ( raw ) );			\
+	ok ( len == ( int ) ( sizeof ( actual ) - 1 ) );		\
+	ok ( strcmp ( actual, formatted ) == 0 );			\
+	} while ( 0 )
+
+/** Test generic settings block */
+struct generic_settings test_generic_settings = {
+	.settings = {
+		.refcnt = NULL,
+		.siblings =
+		    LIST_HEAD_INIT ( test_generic_settings.settings.siblings ),
+		.children =
+		    LIST_HEAD_INIT ( test_generic_settings.settings.children ),
+		.op = &generic_settings_operations,
+	},
+	.list = LIST_HEAD_INIT ( test_generic_settings.list ),
+};
+
+/** Test settings block */
+#define test_settings test_generic_settings.settings
+
+/** Test string setting */
+static struct setting test_string_setting = {
+	.name = "test_string",
+	.type = &setting_type_string,
+};
+
+/** Test URI-encoded string setting */
+static struct setting test_uristring_setting = {
+	.name = "test_uristring",
+	.type = &setting_type_uristring,
+};
+
+/** Test IPv4 address setting type */
+static struct setting test_ipv4_setting = {
+	.name = "test_ipv4",
+	.type = &setting_type_ipv4,
+};
+
+/** Test signed 8-bit integer setting type */
+static struct setting test_int8_setting = {
+	.name = "test_int8",
+	.type = &setting_type_int8,
+};
+
+/** Test signed 16-bit integer setting type */
+static struct setting test_int16_setting = {
+	.name = "test_int16",
+	.type = &setting_type_int16,
+};
+
+/** Test signed 32-bit integer setting type */
+static struct setting test_int32_setting = {
+	.name = "test_int32",
+	.type = &setting_type_int32,
+};
+
+/** Test unsigned 8-bit integer setting type */
+static struct setting test_uint8_setting = {
+	.name = "test_uint8",
+	.type = &setting_type_uint8,
+};
+
+/** Test unsigned 16-bit integer setting type */
+static struct setting test_uint16_setting = {
+	.name = "test_uint16",
+	.type = &setting_type_uint16,
+};
+
+/** Test unsigned 32-bit integer setting type */
+static struct setting test_uint32_setting = {
+	.name = "test_uint32",
+	.type = &setting_type_uint32,
+};
+
+/** Test colon-separated hex string setting type */
+static struct setting test_hex_setting = {
+	.name = "test_hex",
+	.type = &setting_type_hex,
+};
+
+/** Test hyphen-separated hex string setting type */
+static struct setting test_hexhyp_setting = {
+	.name = "test_hexhyp",
+	.type = &setting_type_hexhyp,
+};
+
+/** Test UUID setting type */
+static struct setting test_uuid_setting = {
+	.name = "test_uuid",
+	.type = &setting_type_uuid,
+};
+
+/**
+ * Perform settings self-tests
+ *
+ */
+static void settings_test_exec ( void ) {
+
+	/* Register test settings block */
+	ok ( register_settings ( &test_settings, NULL, "test" ) == 0 );
+
+	/* "string" setting type */
+	storef_ok ( &test_settings, &test_string_setting, "hello",
+		    RAW ( 'h', 'e', 'l', 'l', 'o' ) );
+	fetchf_ok ( &test_settings, &test_string_setting,
+		    RAW ( 'w', 'o', 'r', 'l', 'd' ), "world" );
+
+	/* "uristring" setting type */
+	storef_ok ( &test_settings, &test_uristring_setting, "hello%20world",
+		    RAW ( 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l',
+			  'd' ) );
+	fetchf_ok ( &test_settings, &test_uristring_setting,
+		    RAW ( 1, 2, 3, 4, 5 ), "%01%02%03%04%05" );
+
+	/* "ipv4" setting type */
+	storef_ok ( &test_settings, &test_ipv4_setting, "192.168.0.1",
+		    RAW ( 192, 168, 0, 1 ) );
+	fetchf_ok ( &test_settings, &test_ipv4_setting,
+		    RAW ( 212, 13, 204, 60 ), "212.13.204.60" );
+
+	/* Integer setting types */
+	storef_ok ( &test_settings, &test_int8_setting,
+		    "54", RAW ( 54 ) );
+	storef_ok ( &test_settings, &test_int8_setting,
+		    "0x7f", RAW ( 0x7f ) );
+	storef_ok ( &test_settings, &test_int8_setting,
+		    "0x1234", RAW ( 0x34 ) );
+	storef_ok ( &test_settings, &test_int8_setting,
+		    "-32", RAW ( -32 ) );
+	fetchf_ok ( &test_settings, &test_int8_setting,
+		    RAW ( -9 ), "-9" );
+	fetchf_ok ( &test_settings, &test_int8_setting,
+		    RAW ( 106 ), "106" );
+	storef_ok ( &test_settings, &test_uint8_setting,
+		    "129", RAW ( 129 ) );
+	storef_ok ( &test_settings, &test_uint8_setting,
+		    "0x3421", RAW ( 0x21 ) );
+	fetchf_ok ( &test_settings, &test_uint8_setting,
+		    RAW ( 0x54 ), "0x54" );
+	storef_ok ( &test_settings, &test_int16_setting,
+		    "29483", RAW ( 0x73, 0x2b ) );
+	fetchf_ok ( &test_settings, &test_int16_setting,
+		    RAW ( 0x82, 0x14 ), "-32236" );
+	fetchf_ok ( &test_settings, &test_int16_setting,
+		    RAW ( 0x12, 0x78 ), "4728" );
+	storef_ok ( &test_settings, &test_uint16_setting,
+		    "48727", RAW ( 0xbe, 0x57 ) );
+	fetchf_ok ( &test_settings, &test_uint16_setting,
+		    RAW ( 0x9a, 0x24 ), "0x9a24" );
+	storef_ok ( &test_settings, &test_int32_setting,
+		    "2901274", RAW ( 0x00, 0x2c, 0x45, 0x1a ) );
+	fetchf_ok ( &test_settings, &test_int32_setting,
+		    RAW ( 0xff, 0x34, 0x2d, 0xaf ), "-13357649" );
+	fetchf_ok ( &test_settings, &test_int32_setting,
+		    RAW ( 0x01, 0x00, 0x34, 0xab ), "16790699" );
+	storef_ok ( &test_settings, &test_uint32_setting,
+		    "0xb598d21", RAW ( 0x0b, 0x59, 0x8d, 0x21 ) );
+	fetchf_ok ( &test_settings, &test_uint32_setting,
+		    RAW ( 0xf2, 0x37, 0xb2, 0x18 ), "0xf237b218" );
+
+	/* "hex" setting type */
+	storef_ok ( &test_settings, &test_hex_setting,
+		    ":", RAW ( 0x00, 0x00 ) );
+	storef_ok ( &test_settings, &test_hex_setting,
+		    "1:2:", RAW ( 0x01, 0x02, 0x00 ) );
+	storef_ok ( &test_settings, &test_hex_setting,
+		    "08:12:f5:22:90:1b:4b:47:a8:30:cb:4d:67:4c:d6:76",
+		    RAW ( 0x08, 0x12, 0xf5, 0x22, 0x90, 0x1b, 0x4b, 0x47, 0xa8,
+			  0x30, 0xcb, 0x4d, 0x67, 0x4c, 0xd6, 0x76 ) );
+	fetchf_ok ( &test_settings, &test_hex_setting,
+		    RAW ( 0x62, 0xd9, 0xd4, 0xc4, 0x7e, 0x3b, 0x41, 0x46, 0x91,
+			  0xc6, 0xfd, 0x0c, 0xbf ),
+		    "62:d9:d4:c4:7e:3b:41:46:91:c6:fd:0c:bf" );
+
+	/* "hexhyp" setting type */
+	storef_ok ( &test_settings, &test_hexhyp_setting,
+		    "11-33-22", RAW ( 0x11, 0x33, 0x22 ) );
+	fetchf_ok ( &test_settings, &test_hexhyp_setting,
+		    RAW ( 0x9f, 0xe5, 0x6d, 0xfb, 0x24, 0x3a, 0x4c, 0xbb, 0xa9,
+			  0x09, 0x6c, 0x66, 0x13, 0xc1, 0xa8, 0xec, 0x27 ),
+		    "9f-e5-6d-fb-24-3a-4c-bb-a9-09-6c-66-13-c1-a8-ec-27" );
+
+	/* "uuid" setting type (no store capability) */
+	fetchf_ok ( &test_settings, &test_uuid_setting,
+		    RAW ( 0x1a, 0x6a, 0x74, 0x9d, 0x0e, 0xda, 0x46, 0x1a,0xa8,
+			  0x7a, 0x7c, 0xfe, 0x4f, 0xca, 0x4a, 0x57 ),
+		    "1a6a749d-0eda-461a-a87a-7cfe4fca4a57" );
+
+	/* Clear and unregister test settings block */
+	clear_settings ( &test_settings );
+	unregister_settings ( &test_settings );
+}
+
+/** Settings self-test */
+struct self_test settings_test __self_test = {
+	.name = "settings",
+	.exec = settings_test_exec,
+};
diff --git a/roms/ipxe/src/tests/sha1_test.c b/roms/ipxe/src/tests/sha1_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..bcf761bdd14f85bc6c667c949264a9ed0e7e139f
--- /dev/null
+++ b/roms/ipxe/src/tests/sha1_test.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * SHA-1 tests
+ *
+ */
+
+#include <stdint.h>
+#include <ipxe/sha1.h>
+#include <ipxe/test.h>
+#include "digest_test.h"
+
+/** An SHA-1 test vector */
+struct sha1_test_vector {
+	/** Test data */
+	void *data;
+	/** Test data length */
+	size_t len;
+	/** Expected digest */
+	uint8_t digest[SHA1_DIGEST_SIZE];
+};
+
+/** SHA-1 test vectors */
+static struct sha1_test_vector sha1_test_vectors[] = {
+	/* Empty test data
+	 *
+	 * Expected digest value obtained from "sha1sum /dev/null"
+	 */
+	{ NULL, 0,
+	  { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
+	    0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 } },
+	/* Test data and expected digests taken from the NIST
+	 * Cryptographic Toolkit Algorithm Examples at
+	 * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA1.pdf
+	 */
+	{ "abc", 3,
+	  { 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e,
+	    0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d } },
+	{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56,
+	  { 0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, 0x6e, 0xba, 0xae,
+	    0x4a, 0xa1, 0xf9, 0x51, 0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1 } },
+};
+
+/** SHA-1 test fragment lists */
+static struct digest_test_fragments sha1_test_fragments[] = {
+	{ { 0, -1UL, } },
+	{ { 1, 1, 1, 1, 1, 1, 1, 1 } },
+	{ { 2, 0, 23, 4, 6, 1, 0 } },
+};
+
+/**
+ * Perform SHA-1 self-test
+ *
+ */
+static void sha1_test_exec ( void ) {
+	struct digest_algorithm *digest = &sha1_algorithm;
+	struct sha1_test_vector *test;
+	unsigned long cost;
+	unsigned int i;
+	unsigned int j;
+
+	/* Correctness test */
+	for ( i = 0 ; i < ( sizeof ( sha1_test_vectors ) /
+			    sizeof ( sha1_test_vectors[0] ) ) ; i++ ) {
+		test = &sha1_test_vectors[i];
+		/* Test with a single pass */
+		digest_ok ( digest, NULL, test->data, test->len, test->digest );
+		/* Test with fragment lists */
+		for ( j = 0 ; j < ( sizeof ( sha1_test_fragments ) /
+				    sizeof ( sha1_test_fragments[0] ) ) ; j++ ){
+			digest_ok ( digest, &sha1_test_fragments[j],
+				    test->data, test->len, test->digest );
+		}
+	}
+
+	/* Speed test */
+	cost = digest_cost ( digest );
+	DBG ( "SHA1 required %ld cycles per byte\n", cost );
+}
+
+/** SHA-1 self-test */
+struct self_test sha1_test __self_test = {
+	.name = "sha1",
+	.exec = sha1_test_exec,
+};
diff --git a/roms/ipxe/src/tests/sha256_test.c b/roms/ipxe/src/tests/sha256_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..06a8cae25e62014e041c90eb5ebcecb2b10f9ecf
--- /dev/null
+++ b/roms/ipxe/src/tests/sha256_test.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * SHA-256 tests
+ *
+ */
+
+#include <stdint.h>
+#include <ipxe/sha256.h>
+#include <ipxe/test.h>
+#include "digest_test.h"
+
+/** An SHA-256 test vector */
+struct sha256_test_vector {
+	/** Test data */
+	void *data;
+	/** Test data length */
+	size_t len;
+	/** Expected digest */
+	uint8_t digest[SHA256_DIGEST_SIZE];
+};
+
+/** SHA-256 test vectors */
+static struct sha256_test_vector sha256_test_vectors[] = {
+	/* Empty test data
+	 *
+	 * Expected digest value obtained from "sha256sum /dev/null"
+	 */
+	{ NULL, 0,
+	  { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4,
+	    0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
+	    0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 } },
+	/* Test data and expected digests taken from the NIST
+	 * Cryptographic Toolkit Algorithm Examples at
+	 * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA256.pdf
+	 */
+	{ "abc", 3,
+	  { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40,
+	    0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17,
+	    0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad } },
+	{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56,
+	  { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26,
+	    0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff,
+	    0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 } },
+};
+
+/** SHA-256 test fragment lists */
+static struct digest_test_fragments sha256_test_fragments[] = {
+	{ { 0, -1UL, } },
+	{ { 1, 1, 1, 1, 1, 1, 1, 1 } },
+	{ { 2, 0, 23, 4, 6, 1, 0 } },
+};
+
+/**
+ * Perform SHA-256 self-test
+ *
+ */
+static void sha256_test_exec ( void ) {
+	struct digest_algorithm *digest = &sha256_algorithm;
+	struct sha256_test_vector *test;
+	unsigned long cost;
+	unsigned int i;
+	unsigned int j;
+
+	/* Correctness test */
+	for ( i = 0 ; i < ( sizeof ( sha256_test_vectors ) /
+			    sizeof ( sha256_test_vectors[0] ) ) ; i++ ) {
+		test = &sha256_test_vectors[i];
+		/* Test with a single pass */
+		digest_ok ( digest, NULL, test->data, test->len, test->digest );
+		/* Test with fragment lists */
+		for ( j = 0 ; j < ( sizeof ( sha256_test_fragments ) /
+				    sizeof ( sha256_test_fragments[0] )); j++ ){
+			digest_ok ( digest, &sha256_test_fragments[j],
+				    test->data, test->len, test->digest );
+		}
+	}
+
+	/* Speed test */
+	cost = digest_cost ( digest );
+	DBG ( "SHA256 required %ld cycles per byte\n", cost );
+}
+
+/** SHA-256 self-test */
+struct self_test sha256_test __self_test = {
+	.name = "sha256",
+	.exec = sha256_test_exec,
+};
diff --git a/roms/ipxe/src/tests/string_test.c b/roms/ipxe/src/tests/string_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..88181cc21796db40473f561a76e57c06481cf1a1
--- /dev/null
+++ b/roms/ipxe/src/tests/string_test.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * String self-tests
+ *
+ * memcpy() tests are handled separately
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ipxe/test.h>
+
+/**
+ * Perform string self-tests
+ *
+ */
+static void string_test_exec ( void ) {
+
+	/* Test strlen() */
+	ok ( strlen ( "" ) == 0 );
+	ok ( strlen ( "Hello" ) == 5 );
+	ok ( strlen ( "Hello world!" ) == 12 );
+	ok ( strlen ( "Hello\0world!" ) == 5 );
+
+	/* Test strnlen() */
+	ok ( strnlen ( "", 0 ) == 0 );
+	ok ( strnlen ( "", 10 ) == 0 );
+	ok ( strnlen ( "Hello", 0 ) == 0 );
+	ok ( strnlen ( "Hello", 3 ) == 3 );
+	ok ( strnlen ( "Hello", 5 ) == 5 );
+	ok ( strnlen ( "Hello", 16 ) == 5 );
+	ok ( strnlen ( "Hello world!", 5 ) == 5 );
+	ok ( strnlen ( "Hello world!", 11 ) == 11 );
+	ok ( strnlen ( "Hello world!", 16 ) == 12 );
+
+	/* Test strchr() */
+	ok ( strchr ( "", 'a' ) == NULL );
+	ok ( *(strchr ( "Testing", 'e' )) == 'e' );
+	ok ( *(strchr ( "Testing", 'g' )) == 'g' );
+	ok ( strchr ( "Testing", 'x' ) == NULL );
+
+	/* Test strcmp() */
+	ok ( strcmp ( "", "" ) == 0 );
+	ok ( strcmp ( "Hello", "Hello" ) == 0 );
+	ok ( strcmp ( "Hello", "hello" ) != 0 );
+	ok ( strcmp ( "Hello", "Hello world!" ) != 0 );
+	ok ( strcmp ( "Hello world!", "Hello" ) != 0 );
+
+	/* Test strncmp() */
+	ok ( strncmp ( "", "", 0 ) == 0 );
+	ok ( strncmp ( "", "", 15 ) == 0 );
+	ok ( strncmp ( "Goodbye", "Goodbye", 16 ) == 0 );
+	ok ( strncmp ( "Goodbye", "Hello", 16 ) != 0 );
+	ok ( strncmp ( "Goodbye", "Goodbye world", 32 ) != 0 );
+	ok ( strncmp ( "Goodbye", "Goodbye world", 7 ) == 0 );
+
+	/* Test memcmp() */
+	ok ( memcmp ( "", "", 0 ) == 0 );
+	ok ( memcmp ( "Foo", "Foo", 3 ) == 0 );
+	ok ( memcmp ( "Foo", "Bar", 3 ) != 0 );
+
+	/* Test memset() */
+	{
+		static uint8_t test[7] = { '>', 1, 1, 1, 1, 1, '<' };
+		static const uint8_t expected[7] = { '>', 0, 0, 0, 0, 0, '<' };
+		memset ( ( test + 1 ), 0, ( sizeof ( test ) - 2 ) );
+		ok ( memcmp ( test, expected, sizeof ( test ) ) == 0 );
+	}
+	{
+		static uint8_t test[4] = { '>', 0, 0, '<' };
+		static const uint8_t expected[4] = { '>', 0xeb, 0xeb, '<' };
+		memset ( ( test + 1 ), 0xeb, ( sizeof ( test ) - 2 ) );
+		ok ( memcmp ( test, expected, sizeof ( test ) ) == 0 );
+	}
+
+	/* Test memmove() */
+	{
+		static uint8_t test[11] =
+			{ '>', 1, 2, 3, 4, 5, 6, 7, 8, 9, '<' };
+		static const uint8_t expected[11] =
+			{ '>', 3, 4, 5, 6, 7, 8, 7, 8, 9, '<' };
+		memmove ( ( test + 1 ), ( test + 3 ), 6 );
+		ok ( memcmp ( test, expected, sizeof ( test ) ) == 0 );
+	}
+	{
+		static uint8_t test[12] =
+			{ '>', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, '<' };
+		static const uint8_t expected[12] =
+			{ '>', 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, '<' };
+		memmove ( ( test + 6 ), ( test + 1 ), 5 );
+		ok ( memcmp ( test, expected, sizeof ( test ) ) == 0 );
+	}
+
+	/* Test memswap() */
+	{
+		static uint8_t test[8] =
+			{ '>', 1, 2, 3, 7, 8, 9, '<' };
+		static const uint8_t expected[8] =
+			{ '>', 7, 8, 9, 1, 2, 3, '<' };
+		memswap ( ( test + 1 ), ( test + 4 ), 3 );
+		ok ( memcmp ( test, expected, sizeof ( test ) ) == 0 );
+	}
+}
+
+/** String self-test */
+struct self_test string_test __self_test = {
+	.name = "string",
+	.exec = string_test_exec,
+};
diff --git a/roms/ipxe/src/tests/tcpip_test.c b/roms/ipxe/src/tests/tcpip_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..13423c397cf60eb6faa14aa15ac5d1770ed39f32
--- /dev/null
+++ b/roms/ipxe/src/tests/tcpip_test.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2012 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 (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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * TCP/IP self-tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ipxe/test.h>
+#include <ipxe/profile.h>
+#include <ipxe/tcpip.h>
+
+/** A TCP/IP fixed-data test */
+struct tcpip_test {
+	/** Data */
+	const void *data;
+	/** Length of data */
+	size_t len;
+};
+
+/** A TCP/IP pseudorandom-data test */
+struct tcpip_random_test {
+	/** Seed */
+	unsigned int seed;
+	/** Length of data */
+	size_t len;
+	/** Alignment offset */
+	size_t offset;
+};
+
+/** Define inline data */
+#define DATA(...) { __VA_ARGS__ }
+
+/** Define a TCP/IP fixed-data test */
+#define TCPIP_TEST( name, DATA )					\
+	static const uint8_t __attribute__ (( aligned ( 16 ) ))		\
+		name ## _data[] = DATA;					\
+	static struct tcpip_test name = {				\
+		.data = name ## _data,					\
+		.len = sizeof ( name ## _data ),			\
+	}
+
+/** Define a TCP/IP pseudorandom-data test */
+#define TCPIP_RANDOM_TEST( name, SEED, LEN, OFFSET )			\
+	static struct tcpip_random_test name = {			\
+		.seed = SEED,						\
+		.len = LEN,						\
+		.offset = OFFSET,					\
+	}
+
+/** Buffer for pseudorandom-data tests */
+static uint8_t __attribute__ (( aligned ( 16 ) ))
+	tcpip_data[ 4096 + 7 /* offset */ ];
+
+/** Empty data */
+TCPIP_TEST ( empty, DATA() );
+
+/** Single byte */
+TCPIP_TEST ( one_byte, DATA ( 0xeb ) );
+
+/** Double byte */
+TCPIP_TEST ( two_bytes, DATA ( 0xba, 0xbe ) );
+
+/** Final wrap-around carry (big-endian) */
+TCPIP_TEST ( final_carry_big,
+	     DATA ( 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ) );
+
+/** Final wrap-around carry (little-endian) */
+TCPIP_TEST ( final_carry_little,
+	     DATA ( 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 ) );
+
+/** Random data (aligned) */
+TCPIP_RANDOM_TEST ( random_aligned, 0x12345678UL, 4096, 0 );
+
+/** Random data (unaligned, +1) */
+TCPIP_RANDOM_TEST ( random_unaligned_1, 0x12345678UL, 4096, 1 );
+
+/** Random data (unaligned, +2) */
+TCPIP_RANDOM_TEST ( random_unaligned_2, 0x12345678UL, 4096, 2 );
+
+/** Random data (aligned, truncated) */
+TCPIP_RANDOM_TEST ( random_aligned_truncated, 0x12345678UL, 4095, 0 );
+
+/** Random data (unaligned start and finish) */
+TCPIP_RANDOM_TEST ( partial, 0xcafebabe, 121, 5 );
+
+/**
+ * Calculate TCP/IP checksum
+ *
+ * @v data		Data to sum
+ * @v len		Length of data
+ * @ret cksum		Checksum
+ *
+ * This is a reference implementation taken from RFC1071 (and modified
+ * to fix compilation without warnings under gcc).
+ */
+static uint16_t rfc_tcpip_chksum ( const void *data, size_t len ) {
+	unsigned long sum = 0;
+
+        while ( len > 1 )  {
+		sum += *( ( uint16_t * ) data );
+		data += 2;
+		len -= 2;
+	}
+
+	if ( len > 0 )
+		sum += *( ( uint8_t * ) data );
+
+	while ( sum >> 16 )
+		sum = ( ( sum & 0xffff ) + ( sum >> 16 ) );
+
+	return ~sum;
+}
+
+/**
+ * Report TCP/IP fixed-data test result
+ *
+ * @v test		TCP/IP test
+ */
+#define tcpip_ok( test ) do {						\
+	uint16_t expected;						\
+	uint16_t generic_sum;						\
+	uint16_t sum;							\
+	expected = rfc_tcpip_chksum ( (test)->data, (test)->len );	\
+	generic_sum = generic_tcpip_continue_chksum ( TCPIP_EMPTY_CSUM,	\
+						      (test)->data,	\
+						      (test)->len );	\
+	ok ( generic_sum == expected );					\
+	sum = tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, (test)->data,	\
+				      (test)->len );			\
+	ok ( sum == expected );						\
+	} while ( 0 )
+
+/**
+ * Report TCP/IP pseudorandom-data test result
+ *
+ * @v test		TCP/IP test
+ */
+#define tcpip_random_ok( test ) do {					\
+	uint8_t *data = ( tcpip_data + (test)->offset );		\
+	uint16_t expected;						\
+	uint16_t generic_sum;						\
+	uint16_t sum;							\
+	unsigned long elapsed;						\
+	unsigned int i;							\
+	assert ( ( (test)->len + (test)->offset ) <=			\
+		 sizeof ( tcpip_data ) );				\
+	srandom ( (test)->seed );					\
+	for ( i = 0 ; i < (test)->len ; i++ )				\
+		data[i] = random();					\
+	expected = rfc_tcpip_chksum ( data, (test)->len );		\
+	generic_sum = generic_tcpip_continue_chksum ( TCPIP_EMPTY_CSUM,	\
+						      data,		\
+						      (test)->len );	\
+	ok ( generic_sum == expected );					\
+	simple_profile();						\
+	sum = tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, data,		\
+				      (test)->len );			\
+	elapsed = simple_profile();					\
+	ok ( sum == expected );						\
+	DBG ( "TCPIP checksummed %zd bytes (+%zd) in %ld ticks\n",	\
+	      (test)->len, (test)->offset, elapsed );			\
+	} while ( 0 )
+
+/**
+ * Perform TCP/IP self-tests
+ *
+ */
+static void tcpip_test_exec ( void ) {
+
+	tcpip_ok ( &empty );
+	tcpip_ok ( &one_byte );
+	tcpip_ok ( &two_bytes );
+	tcpip_ok ( &final_carry_big );
+	tcpip_ok ( &final_carry_little );
+	tcpip_random_ok ( &random_aligned );
+	tcpip_random_ok ( &random_unaligned_1 );
+	tcpip_random_ok ( &random_unaligned_2 );
+	tcpip_random_ok ( &random_aligned_truncated );
+	tcpip_random_ok ( &partial );
+}
+
+/** TCP/IP self-test */
+struct self_test tcpip_test __self_test = {
+	.name = "tcpip",
+	.exec = tcpip_test_exec,
+};
diff --git a/roms/ipxe/src/tests/test.c b/roms/ipxe/src/tests/test.c
new file mode 100644
index 0000000000000000000000000000000000000000..62f7c97d99b948c089ac200fce5cbe89a30a8aa7
--- /dev/null
+++ b/roms/ipxe/src/tests/test.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2011 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Self-test infrastructure
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/test.h>
+#include <ipxe/init.h>
+#include <ipxe/image.h>
+
+/** Current self-test set */
+static struct self_test *current_tests;
+
+/**
+ * Report test result
+ *
+ * @v success		Test succeeded
+ * @v file		Test code file
+ * @v line		Test code line
+ */
+void test_ok ( int success, const char *file, unsigned int line ) {
+
+	/* Sanity check */
+	assert ( current_tests != NULL );
+
+	/* Increment test counter */
+	current_tests->total++;
+
+	/* Report failure if applicable */
+	if ( ! success ) {
+		current_tests->failures++;
+		printf ( "FAILURE: \"%s\" test failed at %s line %d\n",
+			 current_tests->name, file, line );
+	}
+}
+
+/**
+ * Run self-test set
+ *
+ */
+static void run_tests ( struct self_test *tests ) {
+	unsigned int old_assertion_failures = assertion_failures;
+
+	/* Sanity check */
+	assert ( current_tests == NULL );
+
+	/* Record current test set */
+	current_tests = tests;
+
+	/* Run tests */
+	tests->exec();
+
+	/* Clear current test set */
+	current_tests = NULL;
+
+	/* Record number of assertion failures */
+	tests->assertion_failures =
+		( assertion_failures - old_assertion_failures );
+
+	/* Print test set summary */
+	if ( tests->failures || tests->assertion_failures ) {
+		printf ( "FAILURE: \"%s\" %d of %d tests failed",
+			 tests->name, tests->failures, tests->total );
+		if ( tests->assertion_failures ) {
+			printf ( " with %d assertion failures",
+				 tests->assertion_failures );
+		}
+		printf ( "\n" );
+	} else {
+		printf ( "OK: \"%s\" %d tests passed\n",
+			 tests->name, tests->total );
+	}
+}
+
+/**
+ * Run all self-tests
+ *
+ * @ret rc		Return status code
+ */
+static int run_all_tests ( void ) {
+	struct self_test *tests;
+	unsigned int failures = 0;
+	unsigned int assertions = 0;
+	unsigned int total = 0;
+
+	/* Run all compiled-in self-tests */
+	printf ( "Starting self-tests\n" );
+	for_each_table_entry ( tests, SELF_TESTS )
+		run_tests ( tests );
+
+	/* Print overall summary */
+	for_each_table_entry ( tests, SELF_TESTS ) {
+		total += tests->total;
+		failures += tests->failures;
+		assertions += tests->assertion_failures;
+	}
+	if ( failures || assertions ) {
+		printf ( "FAILURE: %d of %d tests failed",
+			 failures, total );
+		if ( assertions ) {
+			printf ( " with %d assertion failures", assertions );
+		}
+		printf ( "\n" );
+		return -EINPROGRESS;
+	} else {
+		printf ( "OK: all %d tests passed\n", total );
+		return 0;
+	}
+}
+
+static int test_image_probe ( struct image *image __unused ) {
+	return -ENOTTY;
+}
+
+static int test_image_exec ( struct image *image __unused ) {
+	return run_all_tests();
+}
+
+static struct image_type test_image_type = {
+	.name = "self-tests",
+	.probe = test_image_probe,
+	.exec = test_image_exec,
+};
+
+static struct image test_image = {
+	.refcnt = REF_INIT ( ref_no_free ),
+	.name = "<TESTS>",
+	.type = &test_image_type,
+};
+
+static void test_init ( void ) {
+	int rc;
+
+	/* Register self-tests image */
+	if ( ( rc = register_image ( &test_image ) ) != 0 ) {
+		DBG ( "Could not register self-test image: %s\n",
+		      strerror ( rc ) );
+		/* No way to report failure */
+		return;
+	}
+}
+
+/** Self-test initialisation function */
+struct init_fn test_init_fn __init_fn ( INIT_EARLY ) = {
+	.initialise = test_init,
+};
diff --git a/roms/ipxe/src/tests/tests.c b/roms/ipxe/src/tests/tests.c
new file mode 100644
index 0000000000000000000000000000000000000000..af969ec8faf00c307127ad759d27e117b933dd90
--- /dev/null
+++ b/roms/ipxe/src/tests/tests.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Self-test collection
+ *
+ */
+
+/* Drag in all applicable self-tests */
+REQUIRE_OBJECT ( memcpy_test );
+REQUIRE_OBJECT ( string_test );
+REQUIRE_OBJECT ( list_test );
+REQUIRE_OBJECT ( byteswap_test );
+REQUIRE_OBJECT ( base64_test );
+REQUIRE_OBJECT ( settings_test );
+REQUIRE_OBJECT ( time_test );
+REQUIRE_OBJECT ( tcpip_test );
+REQUIRE_OBJECT ( crc32_test );
+REQUIRE_OBJECT ( md5_test );
+REQUIRE_OBJECT ( sha1_test );
+REQUIRE_OBJECT ( sha256_test );
+REQUIRE_OBJECT ( aes_cbc_test );
+REQUIRE_OBJECT ( hmac_drbg_test );
+REQUIRE_OBJECT ( hash_df_test );
+REQUIRE_OBJECT ( bigint_test );
+REQUIRE_OBJECT ( rsa_test );
+REQUIRE_OBJECT ( x509_test );
+REQUIRE_OBJECT ( ocsp_test );
+REQUIRE_OBJECT ( cms_test );
diff --git a/roms/ipxe/src/tests/time_test.c b/roms/ipxe/src/tests/time_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..28acebee60a03a201e95cb042e35b89242541772
--- /dev/null
+++ b/roms/ipxe/src/tests/time_test.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Date and time self-tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <time.h>
+#include <ipxe/test.h>
+
+/** A mktime() test */
+struct mktime_test {
+	/** Broken-down time */
+	struct tm tm;
+	/** Day of the week */
+	int wday;
+	/** Day of the year */
+	int yday;
+	/** Seconds since the Epoch */
+	time_t time;
+};
+
+/**
+ * Define a mktime() test
+ *
+ * @v name		Test name
+ * @v SEC		Seconds [0,60]
+ * @v MIN		Minutes [0,59]
+ * @v HOUR		Hour [0,23]
+ * @v MDAY		Day of month [1,31]
+ * @v MON		Month of year [0,11]
+ * @v YEAR		Years since 1900
+ * @v WDAY		Day of week [0,6] (Sunday=0)
+ * @v YDAY		Day of year [0,365]
+ * @v ISDST		Daylight savings flag (ignored)
+ * @v TIME		Seconds since the Epoch
+ * @ret test		mktime() test
+ *
+ * This macro is designed to make it easy to generate test vectors in
+ * Perl using
+ *
+ *    print join ", ", gmtime ( $time ), $time."ULL";
+ *
+ */
+#define MKTIME_TEST( name, SEC, MIN, HOUR, MDAY, MON, YEAR, WDAY,	\
+		     YDAY, ISDST, TIME )				\
+	static struct mktime_test name = {				\
+		.tm = {							\
+			.tm_sec = SEC,					\
+			.tm_min = MIN,					\
+			.tm_hour = HOUR,				\
+			.tm_mday = MDAY,				\
+			.tm_mon = MON,					\
+			.tm_year = YEAR,				\
+			.tm_isdst = ISDST,				\
+		},							\
+		.wday = WDAY,						\
+		.yday = YDAY,						\
+		.time = TIME,						\
+	}
+
+/**
+ * Report mktime() test result
+ *
+ * @v test		mktime() test
+ */
+#define mktime_ok( test ) do {						\
+	time_t time = mktime ( &(test)->tm );				\
+	ok ( time == (test)->time );					\
+	ok ( (test)->tm.tm_wday == (test)->wday );			\
+	ok ( (test)->tm.tm_yday == (test)->yday );			\
+	} while ( 0 )
+
+/* Start of the Epoch */
+MKTIME_TEST ( mktime_epoch, 00, 00, 00, 01, 00, 70, 4, 0, 0, 0 );
+
+/* Birth of iPXE as a new project */
+MKTIME_TEST ( mktime_ipxe, 01, 15, 20, 19, 03, 110, 1, 108, 0, 1271708101ULL );
+
+/* Random test vectors generated using Perl's gmtime() */
+MKTIME_TEST ( mktime_0, 4, 17, 20, 1, 0, 150, 6, 0, 0, 2524681024ULL );
+MKTIME_TEST ( mktime_1, 22, 47, 21, 27, 11, 77, 2, 360, 0, 252107242ULL );
+MKTIME_TEST ( mktime_2, 26, 10, 0, 7, 2, 196, 3, 66, 0, 3981917426ULL );
+MKTIME_TEST ( mktime_3, 44, 44, 23, 15, 9, 261, 4, 287, 0, 6052319084ULL );
+MKTIME_TEST ( mktime_4, 3, 22, 18, 8, 9, 296, 6, 281, 0, 7156232523ULL );
+MKTIME_TEST ( mktime_5, 27, 26, 16, 18, 11, 338, 2, 351, 0, 8487649587ULL );
+MKTIME_TEST ( mktime_6, 31, 36, 22, 3, 3, 293, 3, 92, 0, 7045310191ULL );
+MKTIME_TEST ( mktime_7, 2, 0, 6, 25, 5, 289, 4, 175, 0, 6926191202ULL );
+MKTIME_TEST ( mktime_8, 43, 50, 1, 8, 0, 210, 3, 7, 0, 4418589043ULL );
+MKTIME_TEST ( mktime_9, 48, 14, 20, 23, 3, 86, 3, 112, 0, 514671288ULL );
+MKTIME_TEST ( mktime_10, 4, 43, 5, 29, 11, 173, 5, 362, 0, 3281751784ULL );
+MKTIME_TEST ( mktime_11, 47, 26, 21, 12, 7, 177, 4, 223, 0, 3396029207ULL );
+MKTIME_TEST ( mktime_12, 18, 55, 20, 26, 11, 88, 1, 360, 0, 599172918ULL );
+MKTIME_TEST ( mktime_13, 8, 32, 13, 15, 7, 314, 1, 226, 0, 7719456728ULL );
+MKTIME_TEST ( mktime_14, 0, 16, 11, 20, 6, 138, 2, 200, 0, 2163237360ULL );
+MKTIME_TEST ( mktime_15, 48, 0, 9, 31, 2, 202, 5, 89, 0, 4173238848ULL );
+MKTIME_TEST ( mktime_16, 51, 55, 0, 15, 1, 323, 6, 45, 0, 7987769751ULL );
+MKTIME_TEST ( mktime_17, 36, 10, 7, 11, 5, 301, 4, 161, 0, 7303590636ULL );
+MKTIME_TEST ( mktime_18, 22, 39, 11, 21, 9, 233, 3, 293, 0, 5169181162ULL );
+MKTIME_TEST ( mktime_19, 48, 29, 8, 31, 7, 207, 3, 242, 0, 4344222588ULL );
+MKTIME_TEST ( mktime_20, 4, 53, 22, 8, 8, 165, 2, 250, 0, 3019675984ULL );
+MKTIME_TEST ( mktime_21, 14, 16, 8, 10, 5, 298, 0, 160, 0, 7208900174ULL );
+MKTIME_TEST ( mktime_22, 10, 35, 3, 12, 3, 188, 1, 102, 0, 3732579310ULL );
+MKTIME_TEST ( mktime_23, 47, 12, 18, 22, 2, 103, 6, 80, 0, 1048356767ULL );
+MKTIME_TEST ( mktime_24, 23, 29, 17, 23, 10, 201, 3, 326, 0, 4162210163ULL );
+MKTIME_TEST ( mktime_25, 58, 35, 23, 24, 3, 111, 0, 113, 0, 1303688158ULL );
+MKTIME_TEST ( mktime_26, 34, 56, 15, 24, 11, 154, 4, 357, 0, 2681740594ULL );
+MKTIME_TEST ( mktime_27, 7, 11, 22, 28, 1, 243, 4, 58, 0, 5464447867ULL );
+MKTIME_TEST ( mktime_28, 25, 45, 23, 29, 11, 90, 6, 362, 0, 662514325ULL );
+MKTIME_TEST ( mktime_29, 31, 20, 12, 24, 1, 146, 6, 54, 0, 2403087631ULL );
+MKTIME_TEST ( mktime_30, 49, 7, 18, 16, 10, 271, 6, 319, 0, 6370596469ULL );
+MKTIME_TEST ( mktime_31, 31, 55, 2, 25, 5, 141, 2, 175, 0, 2255741731ULL );
+
+/**
+ * Perform date and time self-tests
+ *
+ */
+static void time_test_exec ( void ) {
+
+	mktime_ok ( &mktime_epoch );
+	mktime_ok ( &mktime_ipxe );
+	mktime_ok ( &mktime_0 );
+	mktime_ok ( &mktime_1 );
+	mktime_ok ( &mktime_2 );
+	mktime_ok ( &mktime_3 );
+	mktime_ok ( &mktime_4 );
+	mktime_ok ( &mktime_5 );
+	mktime_ok ( &mktime_6 );
+	mktime_ok ( &mktime_7 );
+	mktime_ok ( &mktime_8 );
+	mktime_ok ( &mktime_9 );
+	mktime_ok ( &mktime_10 );
+	mktime_ok ( &mktime_11 );
+	mktime_ok ( &mktime_12 );
+	mktime_ok ( &mktime_13 );
+	mktime_ok ( &mktime_14 );
+	mktime_ok ( &mktime_15 );
+	mktime_ok ( &mktime_16 );
+	mktime_ok ( &mktime_17 );
+	mktime_ok ( &mktime_18 );
+	mktime_ok ( &mktime_19 );
+	mktime_ok ( &mktime_20 );
+	mktime_ok ( &mktime_21 );
+	mktime_ok ( &mktime_22 );
+	mktime_ok ( &mktime_23 );
+	mktime_ok ( &mktime_24 );
+	mktime_ok ( &mktime_25 );
+	mktime_ok ( &mktime_26 );
+	mktime_ok ( &mktime_27 );
+	mktime_ok ( &mktime_28 );
+	mktime_ok ( &mktime_29 );
+	mktime_ok ( &mktime_30 );
+	mktime_ok ( &mktime_31 );
+}
+
+/** Date and time self-test */
+struct self_test time_test __self_test = {
+	.name = "time",
+	.exec = time_test_exec,
+};
diff --git a/roms/ipxe/src/tests/x509_test.c b/roms/ipxe/src/tests/x509_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..c014bd2e01aba170d679abebf2a6bf1ce41c069b
--- /dev/null
+++ b/roms/ipxe/src/tests/x509_test.c
@@ -0,0 +1,948 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * X.509 self-tests
+ *
+ */
+
+/* Forcibly enable assertions */
+#undef NDEBUG
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/x509.h>
+#include <ipxe/asn1.h>
+#include <ipxe/sha256.h>
+#include <ipxe/test.h>
+
+/** Fingerprint algorithm used for X.509 test certificates */
+#define x509_test_algorithm sha256_algorithm
+
+/** An X.509 test certificate */
+struct x509_test_certificate {
+	/** Data */
+	const void *data;
+	/** Length of data */
+	size_t len;
+	/** Fingerprint */
+	const void *fingerprint;
+
+	/** Parsed certificate */
+	struct x509_certificate *cert;
+};
+
+/** An X.509 test certificate chain */
+struct x509_test_chain {
+	/** Test certificates */
+	struct x509_test_certificate **certs;
+	/** Number of certificates */
+	unsigned int count;
+
+	/** Parsed certificate chain */
+	struct x509_chain *chain;
+};
+
+/** Define inline certificate data */
+#define DATA(...) { __VA_ARGS__ }
+
+/** Define inline fingerprint data */
+#define FINGERPRINT(...) { __VA_ARGS__ }
+
+/** Define a test certificate */
+#define CERTIFICATE( name, DATA, FINGERPRINT )				\
+	static const uint8_t name ## _data[] = DATA;			\
+	static const uint8_t name ## _fingerprint[] = FINGERPRINT;	\
+	static struct x509_test_certificate name = {			\
+		.data = name ## _data,					\
+		.len = sizeof ( name ## _data ),			\
+		.fingerprint = name ## _fingerprint,			\
+	}
+
+/** Define a test certificate chain */
+#define CHAIN( name, ... )						\
+	static struct x509_test_certificate * name ## _certs[] =	\
+		{ __VA_ARGS__ };					\
+	static struct x509_test_chain name = {				\
+		.certs = name ## _certs,				\
+		.count = ( sizeof ( name ## _certs ) /			\
+			   sizeof ( name ## _certs[0] ) ),		\
+	}
+
+/*
+ * subject	iPXE self-test root CA
+ * issuer	iPXE self-test root CA
+ */
+CERTIFICATE ( root_crt,
+	DATA ( 0x30, 0x82, 0x02, 0xb3, 0x30, 0x82, 0x02, 0x1c, 0xa0, 0x03,
+	       0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xc6, 0xb8, 0x9c, 0x58,
+	       0xd2, 0xdc, 0xc9, 0x5d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+	       0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
+	       0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+	       0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06,
+	       0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62,
+	       0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65,
+	       0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
+	       0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65,
+	       0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
+	       0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65,
+	       0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f,
+	       0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78,
+	       0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06,
+	       0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45,
+	       0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74,
+	       0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e,
+	       0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30,
+	       0x30, 0x31, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x39, 0x30,
+	       0x38, 0x30, 0x38, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a,
+	       0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+	       0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15,
+	       0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d,
+	       0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72,
+	       0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07,
+	       0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67,
+	       0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a,
+	       0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74,
+	       0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30,
+	       0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70,
+	       0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d,
+	       0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58,
+	       0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73,
+	       0x74, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30,
+	       0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+	       0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+	       0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xaa, 0x72,
+	       0xb5, 0xc1, 0x73, 0xf4, 0x95, 0x76, 0xa4, 0x27, 0xab, 0x5e,
+	       0xeb, 0x1d, 0x9d, 0xd0, 0x04, 0xb2, 0x93, 0x05, 0xc7, 0xfa,
+	       0x75, 0x84, 0x66, 0xe6, 0x3a, 0x26, 0x1f, 0xbc, 0x2d, 0xfd,
+	       0x8f, 0x59, 0x64, 0xac, 0xcf, 0x65, 0x9d, 0x82, 0x23, 0xc3,
+	       0x72, 0x93, 0xf2, 0x40, 0x68, 0x32, 0xd1, 0xb8, 0xf1, 0x47,
+	       0x61, 0x50, 0xea, 0xbc, 0xcc, 0x3c, 0x6b, 0x74, 0x7a, 0xec,
+	       0x2b, 0x75, 0xa6, 0xc2, 0xa2, 0xb8, 0xbf, 0x23, 0x48, 0x97,
+	       0xd5, 0xaf, 0x77, 0xc1, 0x92, 0x88, 0xd7, 0x38, 0xb7, 0x9e,
+	       0xda, 0xee, 0x72, 0x04, 0xcb, 0x96, 0xe5, 0xdb, 0xfd, 0x9b,
+	       0x5d, 0x99, 0x4e, 0x7a, 0x60, 0x23, 0x34, 0xa4, 0x8d, 0xd7,
+	       0x6c, 0xe7, 0x5d, 0x93, 0x97, 0xe1, 0xab, 0x36, 0x2c, 0x24,
+	       0x16, 0x92, 0x66, 0xf6, 0x6a, 0x14, 0x23, 0x1d, 0x18, 0xb9,
+	       0x44, 0x24, 0x61, 0x6b, 0xd3, 0x75, 0x02, 0x03, 0x01, 0x00,
+	       0x01, 0xa3, 0x23, 0x30, 0x21, 0x30, 0x0f, 0x06, 0x03, 0x55,
+	       0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+	       0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+	       0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d,
+	       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+	       0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x94, 0x9e, 0xea,
+	       0x17, 0x8d, 0x27, 0xa9, 0x17, 0xe5, 0xa9, 0x19, 0xbe, 0x82,
+	       0x36, 0xbd, 0xac, 0x74, 0xf3, 0x6e, 0x75, 0x71, 0x30, 0x1c,
+	       0x05, 0x80, 0x6d, 0x1a, 0x69, 0x37, 0x86, 0x9c, 0x77, 0x75,
+	       0x29, 0xa1, 0xc6, 0xb7, 0x11, 0x0a, 0x63, 0x27, 0xee, 0xb1,
+	       0xc8, 0x94, 0xa9, 0x2e, 0x56, 0x8f, 0xca, 0x9d, 0xbe, 0xf4,
+	       0xdb, 0x63, 0x97, 0x68, 0x3b, 0x13, 0xf8, 0x6a, 0xa5, 0xd1,
+	       0x3d, 0xed, 0xbb, 0x86, 0x9d, 0x42, 0xfc, 0x15, 0x0a, 0x04,
+	       0xf8, 0x3c, 0x0e, 0xc4, 0x86, 0x05, 0x57, 0x56, 0x96, 0xf6,
+	       0xc0, 0x18, 0x53, 0xb0, 0xc5, 0xf0, 0xca, 0x72, 0x77, 0x77,
+	       0xc9, 0x8e, 0x90, 0xa5, 0x4b, 0xb6, 0x80, 0x4a, 0x4c, 0x34,
+	       0x6f, 0xc9, 0xe8, 0x6f, 0xc2, 0x28, 0xdf, 0x93, 0xa9, 0xf5,
+	       0x63, 0x18, 0xc0, 0xec, 0x9e, 0xd5, 0x19, 0x36, 0xc5, 0x94,
+	       0x10, 0xd4, 0x72, 0xd2, 0xb8 ),
+	FINGERPRINT ( 0x71, 0x5d, 0x51, 0x37, 0x5e, 0x18, 0xb3, 0xbc,
+		      0xbb, 0x30, 0x0e, 0x8f, 0x50, 0xc7, 0x55, 0xf5,
+		      0x96, 0xe7, 0xa8, 0x6d, 0x63, 0x2d, 0x32, 0x38,
+		      0xaf, 0x00, 0xc4, 0x1a, 0xfc, 0xd8, 0xac, 0xc3 ) );
+
+/*
+ * subject	iPXE self-test intermediate CA
+ * issuer	iPXE self-test root CA
+ */
+CERTIFICATE ( intermediate_crt,
+	DATA ( 0x30, 0x82, 0x02, 0xb3, 0x30, 0x82, 0x02, 0x1c, 0xa0, 0x03,
+	       0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x30, 0x0d, 0x06, 0x09,
+	       0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
+	       0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+	       0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30,
+	       0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69,
+	       0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
+	       0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04,
+	       0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73,
+	       0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11,
+	       0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69,
+	       0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30,
+	       0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50,
+	       0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65,
+	       0x73, 0x74, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
+	       0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32,
+	       0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x31,
+	       0x34, 0x31, 0x32, 0x31, 0x37, 0x30, 0x30, 0x30, 0x31, 0x33,
+	       0x33, 0x5a, 0x30, 0x81, 0x90, 0x31, 0x0b, 0x30, 0x09, 0x06,
+	       0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17,
+	       0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43,
+	       0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68,
+	       0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
+	       0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69,
+	       0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55,
+	       0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79,
+	       0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31,
+	       0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08,
+	       0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x27,
+	       0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1e, 0x69,
+	       0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74,
+	       0x65, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d,
+	       0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x30,
+	       0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+	       0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+	       0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xc9, 0x3a,
+	       0xee, 0xc6, 0x3c, 0xac, 0x4d, 0x81, 0xc6, 0x98, 0x5e, 0xe1,
+	       0x48, 0x66, 0x1a, 0x1e, 0x60, 0x19, 0x41, 0xae, 0xca, 0x14,
+	       0x97, 0xc8, 0x3a, 0x50, 0xb6, 0x48, 0xf5, 0x42, 0xac, 0x0f,
+	       0xe1, 0xe3, 0x47, 0xf0, 0xbf, 0x7c, 0xd0, 0xee, 0x8f, 0xb7,
+	       0xa6, 0x19, 0xad, 0xbb, 0xc5, 0x1b, 0x34, 0x38, 0xc8, 0xbd,
+	       0x55, 0x84, 0x93, 0x72, 0xaf, 0x84, 0xfc, 0x9b, 0x97, 0x1d,
+	       0xb5, 0x54, 0x24, 0xd6, 0x5d, 0xb7, 0x31, 0xf4, 0xbd, 0x3b,
+	       0x40, 0x97, 0xc0, 0xa9, 0x5a, 0x2a, 0xcb, 0x6b, 0x98, 0x07,
+	       0xdb, 0xb5, 0x9f, 0xe8, 0x31, 0x3f, 0x01, 0x46, 0x46, 0x70,
+	       0x05, 0xa2, 0x0f, 0x8c, 0x7a, 0x61, 0xf3, 0xdf, 0xdb, 0xa1,
+	       0x37, 0x2c, 0x88, 0x6a, 0x81, 0x21, 0x12, 0x4c, 0xf5, 0xcd,
+	       0xaf, 0xc9, 0xd2, 0x36, 0x3d, 0x82, 0xd1, 0xca, 0x19, 0xaf,
+	       0x4e, 0xae, 0x50, 0x71, 0x44, 0xbf, 0x02, 0x03, 0x01, 0x00,
+	       0x01, 0xa3, 0x23, 0x30, 0x21, 0x30, 0x0f, 0x06, 0x03, 0x55,
+	       0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
+	       0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
+	       0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d,
+	       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+	       0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x5d, 0x3c, 0xb3,
+	       0x52, 0x19, 0xa6, 0x9e, 0x4a, 0x44, 0x98, 0xbf, 0x51, 0x20,
+	       0x47, 0x0a, 0xf3, 0x26, 0x1a, 0xcc, 0x35, 0x2f, 0xc9, 0xed,
+	       0xe0, 0x9d, 0x46, 0xeb, 0xbc, 0x7e, 0xc9, 0xb9, 0x1d, 0x76,
+	       0xa4, 0x1d, 0xc2, 0xd9, 0x16, 0x29, 0x77, 0x01, 0x40, 0xdd,
+	       0xe5, 0xcb, 0x28, 0x91, 0x3a, 0x0c, 0x13, 0x01, 0x1b, 0x72,
+	       0x62, 0x45, 0x27, 0xfd, 0xd7, 0x00, 0x47, 0x36, 0x09, 0x1e,
+	       0x7b, 0xd2, 0xcb, 0x95, 0x3d, 0x28, 0x82, 0xce, 0x83, 0x59,
+	       0x32, 0xf9, 0xe6, 0xec, 0x89, 0xac, 0x88, 0x45, 0x22, 0x88,
+	       0x6f, 0x5e, 0xa2, 0x79, 0x95, 0xba, 0xb9, 0xc9, 0xb6, 0x4c,
+	       0x7c, 0xb4, 0x29, 0xa1, 0x02, 0xf5, 0xac, 0x5d, 0x8e, 0x52,
+	       0xeb, 0xe8, 0xb1, 0x56, 0x49, 0xb3, 0x77, 0x62, 0x7d, 0x87,
+	       0x4d, 0x17, 0xf2, 0x62, 0x83, 0x08, 0x59, 0x21, 0x60, 0x0d,
+	       0x84, 0x8e, 0x5a, 0x84, 0xf6 ),
+	FINGERPRINT ( 0x88, 0x70, 0xbf, 0xf0, 0xd6, 0x09, 0x03, 0x3a,
+		      0xe1, 0x80, 0xa7, 0xa5, 0x5c, 0x3e, 0xe1, 0x05,
+		      0x38, 0x97, 0xde, 0xe1, 0xe9, 0x74, 0x55, 0xb1,
+		      0x1e, 0x59, 0x69, 0x44, 0x42, 0x1b, 0xc8, 0xff ) );
+
+/*
+ * subject	iPXE self-test leaf CA
+ * issuer	iPXE self-test intermediate CA
+ */
+CERTIFICATE ( leaf_crt,
+	DATA ( 0x30, 0x82, 0x02, 0xb6, 0x30, 0x82, 0x02, 0x1f, 0xa0, 0x03,
+	       0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x30, 0x0d, 0x06, 0x09,
+	       0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
+	       0x00, 0x30, 0x81, 0x90, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+	       0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30,
+	       0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69,
+	       0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
+	       0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04,
+	       0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73,
+	       0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11,
+	       0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69,
+	       0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x27, 0x30,
+	       0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1e, 0x69, 0x50,
+	       0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65,
+	       0x73, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65,
+	       0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x30, 0x1e,
+	       0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30,
+	       0x30, 0x31, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x31,
+	       0x32, 0x31, 0x37, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a,
+	       0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+	       0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15,
+	       0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d,
+	       0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72,
+	       0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07,
+	       0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67,
+	       0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a,
+	       0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74,
+	       0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30,
+	       0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70,
+	       0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d,
+	       0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58,
+	       0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73,
+	       0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, 0x41, 0x30,
+	       0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+	       0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+	       0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xc3, 0x55,
+	       0xad, 0xdf, 0x7b, 0xd1, 0x48, 0xc3, 0xd3, 0x02, 0x54, 0x6c,
+	       0x92, 0x45, 0x22, 0x3d, 0x90, 0xd8, 0xc7, 0x13, 0xcd, 0xc1,
+	       0x59, 0xc6, 0xe0, 0xad, 0x0e, 0xe6, 0xdb, 0x3b, 0xe8, 0x63,
+	       0xea, 0x4e, 0xb6, 0xea, 0x50, 0xea, 0x6e, 0x33, 0x9d, 0x28,
+	       0x25, 0x42, 0x49, 0xd0, 0xf0, 0xed, 0xc5, 0x5b, 0x6b, 0x4a,
+	       0xe7, 0x45, 0xfa, 0xd3, 0x3f, 0xae, 0xde, 0x5a, 0x90, 0xab,
+	       0xf1, 0x61, 0x2f, 0x40, 0x5e, 0xcf, 0x8b, 0x0b, 0x10, 0x59,
+	       0xa9, 0xd0, 0x1e, 0x0f, 0x18, 0x6b, 0x92, 0xd8, 0x9f, 0x58,
+	       0x10, 0x84, 0xb6, 0x15, 0xe8, 0x5b, 0xc4, 0xa0, 0x3e, 0x49,
+	       0x8b, 0xea, 0xdd, 0xa9, 0x7e, 0x32, 0x26, 0x9a, 0x68, 0x44,
+	       0xf0, 0x30, 0xca, 0x2a, 0xd6, 0x19, 0x7a, 0x80, 0xfd, 0xd7,
+	       0xfc, 0xc7, 0x5d, 0xe7, 0x61, 0xd2, 0x3f, 0x1f, 0x2c, 0x40,
+	       0x70, 0x7b, 0x34, 0xcb, 0x08, 0xa9, 0x02, 0x03, 0x01, 0x00,
+	       0x01, 0xa3, 0x26, 0x30, 0x24, 0x30, 0x12, 0x06, 0x03, 0x55,
+	       0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01,
+	       0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55,
+	       0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02,
+	       0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00,
+	       0x40, 0xd2, 0x70, 0x02, 0x08, 0x19, 0xa0, 0xb8, 0x8d, 0x9d,
+	       0x3d, 0x62, 0x41, 0x90, 0x2a, 0x36, 0x4a, 0x8b, 0x21, 0x42,
+	       0x9a, 0xb4, 0xc5, 0xf8, 0x79, 0x17, 0xd7, 0x64, 0x4d, 0xbf,
+	       0x8f, 0x6a, 0x04, 0x54, 0x7a, 0x0b, 0xd4, 0xb5, 0x0e, 0xab,
+	       0xf7, 0xb7, 0x06, 0x2b, 0xf8, 0xde, 0x87, 0xb2, 0x37, 0x3b,
+	       0x95, 0x01, 0xba, 0x9f, 0x8f, 0xec, 0x0a, 0x86, 0xca, 0x51,
+	       0xb6, 0x25, 0x73, 0x2f, 0xa1, 0x66, 0xc8, 0x7a, 0x5e, 0x51,
+	       0xbd, 0x49, 0xb5, 0x75, 0xda, 0xea, 0xe5, 0xeb, 0x5d, 0xe3,
+	       0xb0, 0xad, 0x49, 0x9f, 0x8b, 0xfd, 0x89, 0xb3, 0xb7, 0xb2,
+	       0x4c, 0x7d, 0x8a, 0x29, 0xb2, 0xbe, 0x04, 0xef, 0x9c, 0x73,
+	       0x3c, 0xea, 0xa3, 0x9f, 0x07, 0x66, 0x5a, 0x2f, 0x38, 0xad,
+	       0x1a, 0xeb, 0xe1, 0xb0, 0x62, 0x14, 0x55, 0xdc, 0x8c, 0x83,
+	       0xbb, 0xc7, 0x13, 0x04, 0x41, 0x54, 0xf1, 0x45 ),
+	FINGERPRINT ( 0xca, 0xcf, 0xea, 0x98, 0x3d, 0x71, 0xb6, 0x9d,
+		      0x4f, 0x5b, 0x84, 0x5e, 0xaa, 0x8e, 0xae, 0x63,
+		      0x0e, 0xad, 0x52, 0xe8, 0xc7, 0x51, 0x81, 0x07,
+		      0xd1, 0xa1, 0x66, 0xdb, 0xd5, 0x62, 0xe1, 0xe6 ) );
+
+/*
+ * subject	iPXE self-test useless CA
+ * issuer	iPXE self-test leaf CA
+ */
+CERTIFICATE ( useless_crt,
+	DATA ( 0x30, 0x82, 0x02, 0xae, 0x30, 0x82, 0x02, 0x17, 0xa0, 0x03,
+	       0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x30, 0x0d, 0x06, 0x09,
+	       0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
+	       0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+	       0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30,
+	       0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69,
+	       0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
+	       0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04,
+	       0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73,
+	       0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11,
+	       0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69,
+	       0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30,
+	       0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50,
+	       0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65,
+	       0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, 0x41,
+	       0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32,
+	       0x30, 0x30, 0x30, 0x31, 0x33, 0x34, 0x5a, 0x17, 0x0d, 0x31,
+	       0x34, 0x31, 0x32, 0x31, 0x37, 0x30, 0x30, 0x30, 0x31, 0x33,
+	       0x34, 0x5a, 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06,
+	       0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17,
+	       0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43,
+	       0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68,
+	       0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55,
+	       0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69,
+	       0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55,
+	       0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79,
+	       0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31,
+	       0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08,
+	       0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x22,
+	       0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x69,
+	       0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74,
+	       0x65, 0x73, 0x74, 0x20, 0x75, 0x73, 0x65, 0x6c, 0x65, 0x73,
+	       0x73, 0x20, 0x43, 0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06,
+	       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+	       0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02,
+	       0x81, 0x81, 0x00, 0xbe, 0x7f, 0x5a, 0x07, 0x7c, 0x61, 0xc2,
+	       0x3a, 0x7e, 0xe3, 0x94, 0xcb, 0xe9, 0xc3, 0x4c, 0x6f, 0x8d,
+	       0x5c, 0x4a, 0xf0, 0xc2, 0x13, 0x54, 0x09, 0x39, 0xa8, 0xf9,
+	       0xc2, 0xc3, 0xdd, 0xbe, 0x42, 0x99, 0xa6, 0xe1, 0x58, 0x0a,
+	       0xd5, 0x89, 0x12, 0xa6, 0xd6, 0x4e, 0xfb, 0x6c, 0xe5, 0xab,
+	       0xff, 0x40, 0x52, 0xcc, 0x1e, 0x63, 0x10, 0xd7, 0xfe, 0x49,
+	       0xf3, 0x86, 0x29, 0x58, 0x6a, 0x90, 0xe4, 0xe2, 0x56, 0x85,
+	       0x14, 0x7d, 0xa5, 0xf8, 0xe0, 0x7e, 0x96, 0x88, 0xd9, 0x23,
+	       0xe5, 0x44, 0x72, 0xa9, 0x5a, 0xbb, 0x76, 0x6b, 0x59, 0x3e,
+	       0x85, 0xd4, 0xe7, 0xb2, 0x31, 0x32, 0xea, 0x40, 0x1f, 0xce,
+	       0xfb, 0xb1, 0x91, 0xee, 0x86, 0x91, 0x3e, 0xa4, 0x86, 0xa4,
+	       0xe9, 0x74, 0xd7, 0x14, 0x8c, 0xb6, 0xb4, 0xc0, 0x08, 0xbb,
+	       0xc8, 0x38, 0xc3, 0x96, 0x3d, 0x85, 0xcf, 0xef, 0x94, 0x52,
+	       0x29, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x23, 0x30, 0x21,
+	       0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+	       0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06,
+	       0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
+	       0x02, 0x02, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+	       0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
+	       0x81, 0x00, 0x50, 0x59, 0xfb, 0x9d, 0x4d, 0xfe, 0x0e, 0x5b,
+	       0xc4, 0x51, 0xe9, 0xe8, 0xa4, 0xf5, 0x2f, 0x32, 0x8b, 0x06,
+	       0x78, 0xbe, 0xf1, 0x18, 0xc5, 0x6f, 0xd9, 0x20, 0xee, 0xb7,
+	       0x51, 0x40, 0xaf, 0xf3, 0x3c, 0xe4, 0x74, 0x00, 0xa4, 0x63,
+	       0x3b, 0x37, 0xe1, 0xef, 0x80, 0xdc, 0xd5, 0x90, 0xed, 0xba,
+	       0x91, 0x86, 0x7f, 0x97, 0x5d, 0x3e, 0x8f, 0x29, 0xcc, 0x57,
+	       0xee, 0x79, 0x15, 0x6b, 0xe3, 0xd1, 0x25, 0x14, 0x24, 0xdf,
+	       0xbf, 0x38, 0xee, 0xe3, 0x8a, 0x88, 0x19, 0x0f, 0xc8, 0x10,
+	       0xae, 0x27, 0x99, 0xa8, 0x35, 0x47, 0xc9, 0xfb, 0x92, 0x47,
+	       0xa2, 0x36, 0x2a, 0x8c, 0x26, 0x12, 0xb1, 0x0d, 0x46, 0xe2,
+	       0xdc, 0x33, 0x29, 0x0c, 0x32, 0xcf, 0x22, 0x49, 0xde, 0xc3,
+	       0x55, 0x2a, 0xba, 0xdd, 0xe3, 0x98, 0xc0, 0xe4, 0x9a, 0xa2,
+	       0xe5, 0x43, 0x04, 0x32, 0xd3, 0x50, 0x7d, 0x9c, 0x71, 0x23 ),
+	FINGERPRINT ( 0xda, 0xbf, 0xd3, 0x5e, 0x2e, 0x29, 0xa9, 0xfd,
+		      0x4d, 0x40, 0xba, 0xb8, 0xdd, 0x66, 0x93, 0x4c,
+		      0x10, 0xea, 0x5b, 0x07, 0xa6, 0xe2, 0x27, 0x63,
+		      0x2e, 0xfe, 0x01, 0x63, 0x7c, 0xea, 0xc6, 0xd0 ) );
+
+/*
+ * subject	boot.test.ipxe.org
+ * issuer	iPXE self-test leaf CA
+ */
+CERTIFICATE ( server_crt,
+	DATA ( 0x30, 0x82, 0x02, 0x7d, 0x30, 0x82, 0x01, 0xe6, 0x02, 0x01,
+	       0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31,
+	       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+	       0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30,
+	       0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30,
+	       0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65,
+	       0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20,
+	       0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
+	       0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f,
+	       0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04,
+	       0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65,
+	       0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65,
+	       0x61, 0x66, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31,
+	       0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33,
+	       0x34, 0x5a, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x33, 0x32, 0x32,
+	       0x30, 0x30, 0x30, 0x31, 0x33, 0x34, 0x5a, 0x30, 0x81, 0x84,
+	       0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+	       0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55,
+	       0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69,
+	       0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12,
+	       0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43,
+	       0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18,
+	       0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46,
+	       0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73,
+	       0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
+	       0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e,
+	       0x6f, 0x72, 0x67, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55,
+	       0x04, 0x03, 0x0c, 0x12, 0x62, 0x6f, 0x6f, 0x74, 0x2e, 0x74,
+	       0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f,
+	       0x72, 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+	       0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+	       0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81,
+	       0x00, 0xbd, 0x43, 0x97, 0x45, 0xa2, 0xe0, 0x1d, 0x38, 0x41,
+	       0xb0, 0xd9, 0x91, 0xf9, 0x77, 0xa9, 0xcb, 0x9c, 0x9c, 0x93,
+	       0xfe, 0x5a, 0xee, 0xbc, 0xd9, 0x0f, 0x39, 0xf6, 0x42, 0xe4,
+	       0x55, 0x21, 0xbb, 0x11, 0xfd, 0xfd, 0xba, 0x25, 0x58, 0xc8,
+	       0xc6, 0xa5, 0x3b, 0x6f, 0x80, 0xba, 0x5b, 0xbc, 0x89, 0xca,
+	       0x7a, 0xdf, 0x6e, 0xb9, 0x81, 0xb6, 0x25, 0x67, 0x0a, 0x38,
+	       0x10, 0xf8, 0x26, 0x43, 0x0c, 0x51, 0x02, 0x14, 0xd6, 0xf2,
+	       0x9d, 0x7c, 0xf5, 0x25, 0x1c, 0x78, 0x4d, 0x47, 0xaf, 0x87,
+	       0x2e, 0x38, 0x49, 0x87, 0xb5, 0x8a, 0xf3, 0xb5, 0xd4, 0x15,
+	       0x69, 0x2a, 0x52, 0xc9, 0x46, 0x97, 0x34, 0x8e, 0x50, 0x4b,
+	       0xc4, 0xf2, 0xfb, 0x39, 0xfd, 0x16, 0x68, 0xdb, 0xa8, 0x17,
+	       0xe2, 0x71, 0x4b, 0xe0, 0xdf, 0x3d, 0xfc, 0xc3, 0x9b, 0x9d,
+	       0x22, 0xc9, 0xd3, 0xf6, 0x02, 0xa6, 0x60, 0xef, 0xf7, 0x02,
+	       0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+	       0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03,
+	       0x81, 0x81, 0x00, 0x7d, 0xff, 0x73, 0xf3, 0x68, 0xe3, 0x75,
+	       0xf1, 0xcf, 0xac, 0x2e, 0x23, 0x73, 0xea, 0xd1, 0x26, 0x33,
+	       0xbf, 0xf9, 0x56, 0xdf, 0xbf, 0x98, 0x20, 0x84, 0x08, 0x78,
+	       0x6b, 0xe6, 0x71, 0x7e, 0x22, 0x68, 0x4d, 0x6c, 0xbb, 0xd5,
+	       0xcc, 0xb4, 0x28, 0x33, 0x5e, 0xbe, 0x4d, 0x10, 0x16, 0x9f,
+	       0x65, 0x3b, 0x68, 0x90, 0xa7, 0xf7, 0x9d, 0x57, 0x71, 0x45,
+	       0x39, 0x86, 0x4c, 0xc0, 0x97, 0x34, 0x03, 0x9c, 0x2b, 0x25,
+	       0x05, 0xb1, 0x5c, 0x0c, 0x4e, 0xf2, 0x14, 0xbf, 0xcf, 0xf0,
+	       0x9a, 0x2d, 0xcf, 0x02, 0x47, 0x60, 0xd2, 0xe9, 0xed, 0xbf,
+	       0x71, 0x5d, 0x07, 0x09, 0x01, 0x87, 0xeb, 0xf7, 0xa8, 0x26,
+	       0x86, 0x24, 0x59, 0xf0, 0x31, 0x3b, 0x42, 0xd1, 0xf1, 0xfd,
+	       0x7c, 0x49, 0x5f, 0x1a, 0xf0, 0x41, 0x67, 0xf0, 0x16, 0x3a,
+	       0xfd, 0xb6, 0xb5, 0xf6, 0x2e, 0x0c, 0x18, 0x1f, 0x09, 0x8e,
+	       0x4d ),
+	FINGERPRINT ( 0xe0, 0xdb, 0x60, 0x53, 0x7c, 0xf6, 0x25, 0x8f,
+		      0xa7, 0xba, 0xdf, 0xe2, 0x1a, 0xfc, 0x27, 0x49,
+		      0xf6, 0x83, 0x15, 0xbd, 0x1b, 0x4c, 0x3f, 0x36,
+		      0x6f, 0x33, 0xf2, 0x47, 0x8e, 0x8b, 0x38, 0xa8 ) );
+
+/*
+ * subject	not.a.ca.test.ipxe.org
+ * issuer	boot.test.ipxe.org
+ */
+CERTIFICATE ( not_ca_crt,
+	DATA ( 0x30, 0x82, 0x02, 0x7d, 0x30, 0x82, 0x01, 0xe6, 0x02, 0x01,
+	       0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x84, 0x31,
+	       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+	       0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30,
+	       0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30,
+	       0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65,
+	       0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20,
+	       0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
+	       0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f,
+	       0x72, 0x67, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04,
+	       0x03, 0x0c, 0x12, 0x62, 0x6f, 0x6f, 0x74, 0x2e, 0x74, 0x65,
+	       0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72,
+	       0x67, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32,
+	       0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x34, 0x5a, 0x17, 0x0d,
+	       0x31, 0x33, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31,
+	       0x33, 0x34, 0x5a, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09,
+	       0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31,
+	       0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e,
+	       0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73,
+	       0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
+	       0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72,
+	       0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03,
+	       0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53,
+	       0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64,
+	       0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c,
+	       0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31,
+	       0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16,
+	       0x6e, 0x6f, 0x74, 0x2e, 0x61, 0x2e, 0x63, 0x61, 0x2e, 0x74,
+	       0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f,
+	       0x72, 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+	       0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+	       0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81,
+	       0x00, 0xc3, 0x5b, 0x6d, 0xb3, 0x8d, 0x74, 0x9c, 0x1d, 0xbd,
+	       0x94, 0x41, 0xa2, 0x42, 0x96, 0x3c, 0x41, 0x82, 0xc0, 0xf1,
+	       0x95, 0xbf, 0xc5, 0x34, 0x92, 0x92, 0xa3, 0xed, 0xed, 0x5c,
+	       0x07, 0xaa, 0xb4, 0xc1, 0x66, 0xbb, 0xa6, 0xd1, 0xd9, 0x78,
+	       0x93, 0xf1, 0x9c, 0x3e, 0x13, 0x3a, 0xee, 0x74, 0x31, 0xeb,
+	       0x55, 0x86, 0xa5, 0x43, 0x8a, 0x5d, 0x0c, 0x2c, 0x0d, 0xfb,
+	       0x91, 0x9e, 0x31, 0x22, 0xbe, 0x96, 0xb5, 0x0e, 0x44, 0xc8,
+	       0x5b, 0x65, 0xb2, 0xf5, 0xec, 0x2a, 0x51, 0xed, 0x8f, 0x28,
+	       0xd8, 0xb2, 0x4b, 0x45, 0x39, 0x31, 0x1f, 0x11, 0xb7, 0x12,
+	       0xe3, 0xc6, 0xb2, 0xd2, 0x8d, 0x50, 0xd5, 0xf4, 0xd2, 0x71,
+	       0x77, 0xc9, 0x4c, 0x67, 0xee, 0xf7, 0xdc, 0xdb, 0x68, 0xa6,
+	       0xac, 0x33, 0xd4, 0xb2, 0x12, 0x61, 0x5c, 0xae, 0x4c, 0x2e,
+	       0x26, 0xe8, 0xdf, 0x46, 0x3a, 0x05, 0xaf, 0xeb, 0x0d, 0x02,
+	       0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+	       0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03,
+	       0x81, 0x81, 0x00, 0x90, 0x3e, 0x16, 0x27, 0x2f, 0x4e, 0x4b,
+	       0x31, 0x0e, 0xae, 0x31, 0x9d, 0x64, 0x88, 0x9f, 0xce, 0xd8,
+	       0x22, 0x51, 0x9d, 0xd9, 0x2b, 0xfe, 0xed, 0x75, 0xbe, 0xec,
+	       0x5a, 0x73, 0xaf, 0x6c, 0xa5, 0x5e, 0xd1, 0x15, 0x9a, 0x08,
+	       0xcf, 0x4d, 0x41, 0x78, 0x48, 0xb4, 0x29, 0xf1, 0xf7, 0x63,
+	       0x9b, 0x11, 0x91, 0x16, 0x94, 0x55, 0xff, 0xeb, 0xe9, 0x6f,
+	       0x0a, 0x34, 0x89, 0xed, 0xf2, 0xd1, 0x79, 0x91, 0x9d, 0xe5,
+	       0x73, 0x48, 0x68, 0x7f, 0x9b, 0xf4, 0x94, 0x80, 0x29, 0xbb,
+	       0x2f, 0xac, 0x6c, 0xf7, 0x6a, 0x43, 0xcc, 0x40, 0x34, 0x85,
+	       0xc8, 0xa1, 0x6d, 0x16, 0x36, 0x65, 0x3f, 0x93, 0x60, 0xc1,
+	       0x64, 0x33, 0x91, 0xa1, 0x8f, 0x86, 0x8c, 0xce, 0x14, 0x19,
+	       0x72, 0x28, 0xef, 0x94, 0x3d, 0x09, 0xb8, 0x3b, 0x39, 0xe8,
+	       0xd1, 0x66, 0x2b, 0x38, 0xb4, 0x46, 0x50, 0xf4, 0xcd, 0xc4,
+	       0x9a ),
+	FINGERPRINT ( 0x37, 0x6b, 0xc2, 0x20, 0xa9, 0xbc, 0xe2, 0x83,
+		      0x99, 0x60, 0x06, 0x2e, 0xaf, 0x94, 0xfe, 0xb0,
+		      0x1a, 0x2c, 0x17, 0x47, 0x1e, 0xc0, 0xd1, 0x66,
+		      0xb6, 0x76, 0xeb, 0x1c, 0x07, 0xae, 0x72, 0xf2 ) );
+
+/*
+ * subject	bad.path.len.test.ipxe.org
+ * issuer	iPXE self-test useless CA
+ */
+CERTIFICATE ( bad_path_len_crt,
+	DATA ( 0x30, 0x82, 0x02, 0x88, 0x30, 0x82, 0x01, 0xf1, 0x02, 0x01,
+	       0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+	       0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x8b, 0x31,
+	       0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+	       0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
+	       0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64,
+	       0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30,
+	       0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61,
+	       0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30,
+	       0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65,
+	       0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20,
+	       0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
+	       0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f,
+	       0x72, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04,
+	       0x03, 0x0c, 0x19, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65,
+	       0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, 0x73,
+	       0x65, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x43, 0x41, 0x30, 0x1e,
+	       0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30,
+	       0x30, 0x31, 0x33, 0x34, 0x5a, 0x17, 0x0d, 0x31, 0x33, 0x30,
+	       0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x34, 0x5a,
+	       0x30, 0x81, 0x8c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+	       0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15,
+	       0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d,
+	       0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72,
+	       0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07,
+	       0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67,
+	       0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a,
+	       0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74,
+	       0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30,
+	       0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70,
+	       0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x23, 0x30, 0x21,
+	       0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x62, 0x61, 0x64,
+	       0x2e, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x6c, 0x65, 0x6e, 0x2e,
+	       0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, 0x65, 0x2e,
+	       0x6f, 0x72, 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09,
+	       0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+	       0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81,
+	       0x81, 0x00, 0xed, 0xf1, 0xe3, 0xb2, 0x61, 0x68, 0xa0, 0xd5,
+	       0x43, 0xfe, 0xad, 0xee, 0xfb, 0x8e, 0x2c, 0xf0, 0x44, 0xaf,
+	       0x0a, 0x3c, 0x87, 0xc2, 0x56, 0x9b, 0x66, 0x15, 0xc6, 0xbc,
+	       0x5b, 0x96, 0xef, 0xa1, 0x49, 0xd6, 0xe7, 0xeb, 0xb8, 0xf6,
+	       0x3d, 0x62, 0xf5, 0x51, 0xfd, 0xb1, 0xa5, 0x4e, 0x92, 0x7c,
+	       0x7a, 0x31, 0x1b, 0xb8, 0x21, 0x5c, 0xfe, 0x0b, 0x4e, 0x58,
+	       0xd6, 0xd0, 0x8b, 0x81, 0x00, 0x4a, 0xf8, 0xf7, 0x2a, 0xc9,
+	       0xea, 0xfa, 0x9c, 0xc9, 0x33, 0x0b, 0xc4, 0xce, 0x96, 0x4c,
+	       0x30, 0x6e, 0xf0, 0x07, 0xfa, 0x1b, 0x94, 0x1f, 0xe3, 0x3b,
+	       0xb2, 0x7d, 0x31, 0x1a, 0x37, 0x64, 0xe2, 0xc3, 0xf1, 0xe5,
+	       0xb9, 0xcc, 0xd1, 0x02, 0xae, 0x16, 0x39, 0x9b, 0xfc, 0x55,
+	       0xca, 0xdd, 0x33, 0x92, 0xe3, 0x12, 0x40, 0xc5, 0x32, 0x51,
+	       0x62, 0xac, 0x3a, 0xc0, 0x17, 0x36, 0xd0, 0x27, 0x3d, 0xbb,
+	       0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+	       0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
+	       0x03, 0x81, 0x81, 0x00, 0x07, 0x53, 0x2a, 0x80, 0xd6, 0x25,
+	       0x10, 0x37, 0xce, 0x3b, 0x87, 0x87, 0xfc, 0xae, 0xe2, 0x2a,
+	       0x28, 0x3f, 0xf7, 0xa6, 0x32, 0x5b, 0x06, 0xbd, 0x4f, 0x34,
+	       0x6b, 0x47, 0x8a, 0x4b, 0x47, 0x51, 0xe8, 0x45, 0x69, 0xe3,
+	       0xf3, 0xdf, 0xa4, 0x25, 0x8f, 0x34, 0xbe, 0xe5, 0x2c, 0xa4,
+	       0x6c, 0x8c, 0x6e, 0x02, 0x74, 0x23, 0x43, 0x21, 0x4d, 0xe3,
+	       0x75, 0x93, 0x8e, 0xa8, 0x2c, 0x54, 0xba, 0x35, 0xe7, 0xab,
+	       0x44, 0xfa, 0x07, 0x7a, 0x18, 0xb4, 0xa7, 0xce, 0xfa, 0xa6,
+	       0x74, 0x5a, 0x45, 0x2c, 0x6f, 0x86, 0x34, 0x8f, 0x4a, 0x09,
+	       0xe0, 0xf3, 0x4f, 0x37, 0xbb, 0xa3, 0xa0, 0xcb, 0xad, 0x6b,
+	       0xc1, 0x16, 0x06, 0xdf, 0x83, 0x98, 0xaf, 0xa8, 0xc3, 0xa0,
+	       0x5f, 0x33, 0x09, 0x01, 0x12, 0xbd, 0xd3, 0x45, 0x9f, 0x5f,
+	       0x96, 0x93, 0xe9, 0x69, 0xe9, 0xb1, 0x8a, 0xe4, 0x94, 0xce,
+	       0xe4, 0x8d ),
+	FINGERPRINT ( 0xb6, 0x80, 0x84, 0xf1, 0x45, 0x55, 0x1f, 0xbc,
+		      0x15, 0xa6, 0xd8, 0x4b, 0xf3, 0x19, 0x65, 0xef,
+		      0x53, 0x5a, 0xc8, 0x99, 0xe5, 0xdf, 0x79, 0x07,
+		      0x00, 0x2c, 0x9f, 0x49, 0x91, 0x21, 0xeb, 0xfc ) );
+
+/** Valid certificate chain up to boot.test.ipxe.org */
+CHAIN ( server_chain, &server_crt, &leaf_crt, &intermediate_crt, &root_crt );
+
+/** Broken certificate chain up to boot.test.ipxe.org */
+CHAIN ( broken_server_chain, &server_crt, &leaf_crt, &root_crt );
+
+/** Incomplete certificate chain up to boot.test.ipxe.org */
+CHAIN ( incomplete_server_chain, &server_crt, &leaf_crt, &intermediate_crt );
+
+/** Non-functional certificate chain up to not_ca.test.ipxe.org */
+CHAIN ( not_ca_chain,
+	&not_ca_crt, &server_crt, &leaf_crt, &intermediate_crt, &root_crt );
+
+/** Valid certificate chain up to iPXE self-test useless CA */
+CHAIN ( useless_chain, &useless_crt, &leaf_crt,	&intermediate_crt, &root_crt );
+
+/** Non-functional certificate chain up to bad.path.len.test.ipxe.org */
+CHAIN ( bad_path_len_chain, &bad_path_len_crt, &useless_crt, &leaf_crt,
+	&intermediate_crt, &root_crt );
+
+/** Certificate store containing the iPXE self-test root CA */
+static struct x509_root test_root = {
+	.digest = &x509_test_algorithm,
+	.count = 1,
+	.fingerprints = root_crt_fingerprint,
+};
+
+/** Certificate store containing the iPXE self-test intermediate CA */
+static struct x509_root intermediate_root = {
+	.digest = &x509_test_algorithm,
+	.count = 1,
+	.fingerprints = intermediate_crt_fingerprint,
+};
+
+/** Dummy fingerprint (not matching any certificates) */
+static uint8_t dummy_fingerprint[] =
+	FINGERPRINT ( 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+		      0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+		      0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+		      0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff );
+
+/** Certificate store containing a dummy fingerprint */
+static struct x509_root dummy_root = {
+	.digest = &x509_test_algorithm,
+	.count = 1,
+	.fingerprints = dummy_fingerprint,
+};
+
+/** Time at which all test certificates are valid */
+static time_t test_time = 1332374737ULL; /* Thu Mar 22 00:05:37 2012 */
+
+/** Time at which end-entity test certificates are invalid */
+static time_t test_expired = 1375573111ULL; /* Sat Aug  3 23:38:31 2013 */
+
+/** Time at which CA test certificates are invalid */
+static time_t test_ca_expired = 2205014905ULL; /* Wed Nov 16 00:08:25 2039 */
+
+/**
+ * Report certificate parsing test result
+ *
+ * @v crt		Test certificate
+ */
+#define x509_certificate_ok( crt ) do {					\
+	ok ( x509_certificate ( (crt)->data, (crt)->len,		\
+				&(crt)->cert ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Report cached certificate parsing test result
+ *
+ * @v crt		Test certificate
+ */
+#define x509_cached_ok( crt ) do {					\
+	struct x509_certificate *temp;					\
+	ok ( x509_certificate ( (crt)->data, (crt)->len,		\
+				&temp ) == 0 );				\
+	ok ( temp == (crt)->cert );					\
+	x509_put ( temp );						\
+	} while ( 0 )
+
+/**
+ * Report certificate fingerprint test result
+ *
+ * @v crt		Test certificate
+ */
+#define x509_fingerprint_ok( crt ) do {					\
+	uint8_t fingerprint[ x509_test_algorithm.digestsize ];		\
+	x509_fingerprint ( (crt)->cert, &x509_test_algorithm,		\
+			   fingerprint );				\
+	ok ( memcmp ( fingerprint, (crt)->fingerprint,			\
+		      sizeof ( fingerprint ) ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Report certificate issuer validation test result
+ *
+ * @v crt		Test certificate
+ * @v issuer		Test issuer
+ */
+#define x509_check_issuer_ok( crt, issuer ) do {			\
+	ok ( x509_check_issuer ( (crt)->cert, (issuer)->cert ) == 0 );	\
+	} while ( 0 )
+
+/**
+ * Report certificate issuer validation failure test result
+ *
+ * @v crt		Test certificate
+ * @v issuer		Test issuer
+ */
+#define x509_check_issuer_fail_ok( crt, issuer ) do {			\
+	ok ( x509_check_issuer ( (crt)->cert, (issuer)->cert ) != 0 );	\
+	} while ( 0 )
+
+/**
+ * Report certificate root validation test result
+ *
+ * @v crt		Test certificate
+ * @v root		Test root certificate store
+ */
+#define x509_check_root_ok( crt, root ) do {				\
+	ok ( x509_check_root ( (crt)->cert, root ) == 0 );		\
+	} while ( 0 )
+
+/**
+ * Report certificate root validation failure test result
+ *
+ * @v crt		Test certificate
+ * @v root		Test root certificate store
+ */
+#define x509_check_root_fail_ok( crt, root ) do {			\
+	ok ( x509_check_root ( (crt)->cert, root ) != 0 );		\
+	} while ( 0 )
+
+/**
+ * Report certificate time validation test result
+ *
+ * @v crt		Test certificate
+ * @v time		Test time
+ */
+#define x509_check_time_ok( crt, time ) do {				\
+	ok ( x509_check_time ( (crt)->cert, time ) == 0 );		\
+	} while ( 0 )
+
+/**
+ * Report certificate time validation failure test result
+ *
+ * @v crt		Test certificate
+ * @v time		Test time
+ */
+#define x509_check_time_fail_ok( crt, time ) do {			\
+	ok ( x509_check_time ( (crt)->cert, time ) != 0 );		\
+	} while ( 0 )
+
+/**
+ * Report certificate chain parsing test result
+ *
+ * @v chn		Test certificate chain
+ */
+#define x509_chain_ok( chn ) do {					\
+	unsigned int i;							\
+	struct x509_certificate *first;					\
+	(chn)->chain = x509_alloc_chain();				\
+	ok ( (chn)->chain != NULL );					\
+	for ( i = 0 ; i < (chn)->count ; i++ ) {			\
+		ok ( x509_append ( (chn)->chain,			\
+				   (chn)->certs[i]->cert ) == 0 );	\
+	}								\
+	first = x509_first ( (chn)->chain );				\
+	ok ( first != NULL );						\
+	ok ( first->raw.len == (chn)->certs[0]->len );			\
+	ok ( memcmp ( first->raw.data, (chn)->certs[0]->data,		\
+		      first->raw.len ) == 0 );				\
+	} while ( 0 )
+
+/**
+ * Report certificate chain validation test result
+ *
+ * @v chn		Test certificate chain
+ * @v time		Test certificate validation time
+ * @v root		Test root certificate store
+ */
+#define x509_validate_chain_ok( chn, time, root ) do {			\
+	x509_invalidate_chain ( (chn)->chain );				\
+	ok ( x509_validate_chain ( (chn)->chain, (time),		\
+				   (root) ) == 0 );			\
+	} while ( 0 )
+
+/**
+ * Report certificate chain validation failure test result
+ *
+ * @v chn		Test certificate chain
+ * @v time		Test certificate validation time
+ * @v root		Test root certificate store
+ */
+#define x509_validate_chain_fail_ok( chn, time, root ) do {		\
+	x509_invalidate_chain ( (chn)->chain );				\
+	ok ( x509_validate_chain ( (chn)->chain, (time),		\
+				   (root) ) != 0 );			\
+	} while ( 0 )
+
+/**
+ * Perform X.509 self-tests
+ *
+ */
+static void x509_test_exec ( void ) {
+
+	/* Parse all certificates */
+	x509_certificate_ok ( &root_crt );
+	x509_certificate_ok ( &intermediate_crt );
+	x509_certificate_ok ( &leaf_crt );
+	x509_certificate_ok ( &useless_crt );
+	x509_certificate_ok ( &server_crt );
+	x509_certificate_ok ( &not_ca_crt );
+	x509_certificate_ok ( &bad_path_len_crt );
+
+	/* Check cache functionality */
+	x509_cached_ok ( &root_crt );
+	x509_cached_ok ( &intermediate_crt );
+	x509_cached_ok ( &leaf_crt );
+	x509_cached_ok ( &useless_crt );
+	x509_cached_ok ( &server_crt );
+	x509_cached_ok ( &not_ca_crt );
+	x509_cached_ok ( &bad_path_len_crt );
+
+	/* Check all certificate fingerprints */
+	x509_fingerprint_ok ( &root_crt );
+	x509_fingerprint_ok ( &intermediate_crt );
+	x509_fingerprint_ok ( &leaf_crt );
+	x509_fingerprint_ok ( &useless_crt );
+	x509_fingerprint_ok ( &server_crt );
+	x509_fingerprint_ok ( &not_ca_crt );
+	x509_fingerprint_ok ( &bad_path_len_crt );
+
+	/* Check pairwise issuing */
+	x509_check_issuer_ok ( &intermediate_crt, &root_crt );
+	x509_check_issuer_ok ( &leaf_crt, &intermediate_crt );
+	x509_check_issuer_ok ( &useless_crt, &leaf_crt );
+	x509_check_issuer_ok ( &server_crt, &leaf_crt );
+	x509_check_issuer_fail_ok ( &not_ca_crt, &server_crt );
+	x509_check_issuer_ok ( &bad_path_len_crt, &useless_crt );
+
+	/* Check root certificate stores */
+	x509_check_root_ok ( &root_crt, &test_root );
+	x509_check_root_fail_ok ( &intermediate_crt, &test_root );
+	x509_check_root_ok ( &intermediate_crt, &intermediate_root );
+	x509_check_root_fail_ok ( &root_crt, &intermediate_root );
+	x509_check_root_fail_ok ( &root_crt, &dummy_root );
+
+	/* Check certificate validity periods */
+	x509_check_time_ok ( &server_crt, test_time );
+	x509_check_time_fail_ok ( &server_crt, test_expired );
+	x509_check_time_ok ( &root_crt, test_time );
+	x509_check_time_ok ( &root_crt, test_expired );
+	x509_check_time_fail_ok ( &root_crt, test_ca_expired );
+
+	/* Parse all certificate chains */
+	x509_chain_ok ( &server_chain );
+	x509_chain_ok ( &broken_server_chain );
+	x509_chain_ok ( &incomplete_server_chain );
+	x509_chain_ok ( &not_ca_chain );
+	x509_chain_ok ( &useless_chain );
+	x509_chain_ok ( &bad_path_len_chain );
+
+	/* Check certificate chains */
+	x509_validate_chain_ok ( &server_chain, test_time, &test_root );
+	x509_validate_chain_ok ( &server_chain, test_time, &intermediate_root );
+	x509_validate_chain_fail_ok ( &server_chain, test_time, &dummy_root );
+	x509_validate_chain_fail_ok ( &broken_server_chain, test_time,
+				      &test_root );
+	x509_validate_chain_fail_ok ( &incomplete_server_chain, test_time,
+				      &test_root );
+	x509_validate_chain_ok ( &incomplete_server_chain, test_time,
+				 &intermediate_root );
+	x509_validate_chain_fail_ok ( &not_ca_chain, test_time, &test_root );
+	x509_validate_chain_ok ( &useless_chain, test_time, &test_root );
+	x509_validate_chain_fail_ok ( &bad_path_len_chain, test_time,
+				      &test_root );
+
+	/* Check certificate chain expiry times */
+	x509_validate_chain_fail_ok ( &server_chain, test_expired, &test_root );
+	x509_validate_chain_ok ( &useless_chain, test_expired, &test_root );
+	x509_validate_chain_fail_ok ( &useless_chain, test_ca_expired,
+				      &test_root );
+
+	/* Drop chain references */
+	x509_chain_put ( bad_path_len_chain.chain );
+	x509_chain_put ( useless_chain.chain );
+	x509_chain_put ( not_ca_chain.chain );
+	x509_chain_put ( incomplete_server_chain.chain );
+	x509_chain_put ( broken_server_chain.chain );
+	x509_chain_put ( server_chain.chain );
+
+	/* Drop certificate references */
+	x509_put ( bad_path_len_crt.cert );
+	x509_put ( not_ca_crt.cert );
+	x509_put ( server_crt.cert );
+	x509_put ( useless_crt.cert );
+	x509_put ( leaf_crt.cert );
+	x509_put ( intermediate_crt.cert );
+	x509_put ( root_crt.cert );
+}
+
+/** X.509 self-test */
+struct self_test x509_test __self_test = {
+	.name = "x509",
+	.exec = x509_test_exec,
+};
+
+/* Drag in algorithms required for tests */
+REQUIRE_OBJECT ( rsa );
+REQUIRE_OBJECT ( sha1 );
+REQUIRE_OBJECT ( sha256 );
diff --git a/roms/ipxe/src/usr/autoboot.c b/roms/ipxe/src/usr/autoboot.c
index c5c5f3e78d0da45b137ac3bd9930..b2d288eade759162b6f827dc12b2 100644
--- a/roms/ipxe/src/usr/autoboot.c
+++ b/roms/ipxe/src/usr/autoboot.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -29,11 +30,18 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <ipxe/uri.h>
 #include <ipxe/open.h>
 #include <ipxe/init.h>
+#include <ipxe/keys.h>
+#include <ipxe/version.h>
+#include <ipxe/shell.h>
+#include <ipxe/features.h>
+#include <ipxe/image.h>
 #include <usr/ifmgmt.h>
 #include <usr/route.h>
 #include <usr/dhcpmgmt.h>
 #include <usr/imgmgmt.h>
+#include <usr/prompt.h>
 #include <usr/autoboot.h>
+#include <config/general.h>
 
 /** @file
  *
@@ -46,6 +54,18 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define EINFO_ENOENT_BOOT \
 	__einfo_uniqify ( EINFO_ENOENT, 0x01, "Nothing to boot" )
 
+#define NORMAL	"\033[0m"
+#define BOLD	"\033[1m"
+#define CYAN	"\033[36m"
+
+/** The "scriptlet" setting */
+struct setting scriptlet_setting __setting ( SETTING_MISC ) = {
+	.name = "scriptlet",
+	.description = "Boot scriptlet",
+	.tag = DHCP_EB_SCRIPTLET,
+	.type = &setting_type_string,
+};
+
 /**
  * Perform PXE menu boot when PXE stack is not available
  */
@@ -119,54 +139,38 @@ struct setting skip_san_boot_setting __setting ( SETTING_SANBOOT_EXTRA ) = {
  *
  * @v filename		Filename
  * @v root_path		Root path
+ * @v drive		SAN drive (if applicable)
+ * @v flags		Boot action flags
  * @ret rc		Return status code
+ *
+ * The somewhat tortuous flow of control in this function exists in
+ * order to ensure that the "sanboot" command remains identical in
+ * function to a SAN boot via a DHCP-specified root path, and to
+ * provide backwards compatibility for the "keep-san" and
+ * "skip-san-boot" options.
  */
-int uriboot ( struct uri *filename, struct uri *root_path ) {
-	int drive;
+int uriboot ( struct uri *filename, struct uri *root_path, int drive,
+	      unsigned int flags ) {
+	struct image *image;
 	int rc;
 
-	/* Treat empty URIs as absent */
-	if ( filename && ( ! uri_has_path ( filename ) ) )
-		filename = NULL;
-	if ( root_path && ( ! uri_is_absolute ( root_path ) ) )
-		root_path = NULL;
-
-	/* If we have both a filename and a root path, ignore an
-	 * unsupported URI scheme in the root path, since it may
-	 * represent an NFS root.
-	 */
-	if ( filename && root_path &&
-	     ( xfer_uri_opener ( root_path->scheme ) == NULL ) ) {
-		printf ( "Ignoring unsupported root path\n" );
-		root_path = NULL;
-	}
-
-	/* Check that we have something to boot */
-	if ( ! ( filename || root_path ) ) {
-		rc = -ENOENT_BOOT;
-		printf ( "Nothing to boot: %s\n", strerror ( rc ) );
-		goto err_no_boot;
-	}
-
 	/* Hook SAN device, if applicable */
 	if ( root_path ) {
-		drive = san_hook ( root_path, 0 );
-		if ( drive < 0 ) {
-			rc = drive;
+		if ( ( rc = san_hook ( root_path, drive ) ) != 0 ) {
 			printf ( "Could not open SAN device: %s\n",
 				 strerror ( rc ) );
 			goto err_san_hook;
 		}
-		printf ( "Registered as SAN device %#02x\n", drive );
-	} else {
-		drive = -ENODEV;
+		printf ( "Registered SAN device %#02x\n", drive );
 	}
 
 	/* Describe SAN device, if applicable */
-	if ( ( drive >= 0 ) && ( ( rc = san_describe ( drive ) ) != 0 ) ) {
-		printf ( "Could not describe SAN device %#02x: %s\n",
-			 drive, strerror ( rc ) );
-		goto err_san_describe;
+	if ( ( drive >= 0 ) && ! ( flags & URIBOOT_NO_SAN_DESCRIBE ) ) {
+		if ( ( rc = san_describe ( drive ) ) != 0 ) {
+			printf ( "Could not describe SAN device %#02x: %s\n",
+				 drive, strerror ( rc ) );
+			goto err_san_describe;
+		}
 	}
 
 	/* Allow a root-path-only boot with skip-san enabled to succeed */
@@ -174,9 +178,11 @@ int uriboot ( struct uri *filename, struct uri *root_path ) {
 
 	/* Attempt filename boot if applicable */
 	if ( filename ) {
-		if ( ( rc = imgdownload ( filename, NULL, NULL,
-					  register_and_boot_image ) ) != 0 ) {
-			printf ( "\nCould not chain image: %s\n",
+		if ( ( rc = imgdownload ( filename, &image ) ) != 0 )
+			goto err_download;
+		image->flags |= IMAGE_AUTO_UNREGISTER;
+		if ( ( rc = image_exec ( image ) ) != 0 ) {
+			printf ( "Could not boot image: %s\n",
 				 strerror ( rc ) );
 			/* Fall through to (possibly) attempt a SAN boot
 			 * as a fallback.  If no SAN boot is attempted,
@@ -192,7 +198,7 @@ int uriboot ( struct uri *filename, struct uri *root_path ) {
 	}
 
 	/* Attempt SAN boot if applicable */
-	if ( root_path ) {
+	if ( ( drive >= 0 ) && ! ( flags & URIBOOT_NO_SAN_BOOT ) ) {
 		if ( fetch_intz_setting ( NULL, &skip_san_boot_setting) == 0 ) {
 			printf ( "Booting from SAN device %#02x\n", drive );
 			rc = san_boot ( drive );
@@ -207,19 +213,18 @@ int uriboot ( struct uri *filename, struct uri *root_path ) {
 		}
 	}
 
+ err_download:
  err_san_describe:
 	/* Unhook SAN device, if applicable */
-	if ( drive >= 0 ) {
+	if ( ( drive >= 0 ) && ! ( flags & URIBOOT_NO_SAN_UNHOOK ) ) {
 		if ( fetch_intz_setting ( NULL, &keep_san_setting ) == 0 ) {
-			printf ( "Unregistering SAN device %#02x\n", drive );
 			san_unhook ( drive );
+			printf ( "Unregistered SAN device %#02x\n", drive );
 		} else {
-			printf ( "Preserving connection to SAN device %#02x\n",
-				 drive );
+			printf ( "Preserving SAN device %#02x\n", drive );
 		}
 	}
  err_san_hook:
- err_no_boot:
 	return rc;
 }
 
@@ -360,19 +365,51 @@ int netboot ( struct net_device *netdev ) {
 		goto err_pxe_menu_boot;
 	}
 
-	/* Fetch next server, filename and root path */
+	/* Fetch next server and filename */
 	filename = fetch_next_server_and_filename ( NULL );
 	if ( ! filename )
 		goto err_filename;
+	if ( ! uri_has_path ( filename ) ) {
+		/* Ignore empty filename */
+		uri_put ( filename );
+		filename = NULL;
+	}
+
+	/* Fetch root path */
 	root_path = fetch_root_path ( NULL );
 	if ( ! root_path )
 		goto err_root_path;
+	if ( ! uri_is_absolute ( root_path ) ) {
+		/* Ignore empty root path */
+		uri_put ( root_path );
+		root_path = NULL;
+	}
+
+	/* If we have both a filename and a root path, ignore an
+	 * unsupported URI scheme in the root path, since it may
+	 * represent an NFS root.
+	 */
+	if ( filename && root_path &&
+	     ( xfer_uri_opener ( root_path->scheme ) == NULL ) ) {
+		printf ( "Ignoring unsupported root path\n" );
+		uri_put ( root_path );
+		root_path = NULL;
+	}
+
+	/* Check that we have something to boot */
+	if ( ! ( filename || root_path ) ) {
+		rc = -ENOENT_BOOT;
+		printf ( "Nothing to boot: %s\n", strerror ( rc ) );
+		goto err_no_boot;
+	}
 
 	/* Boot using next server, filename and root path */
-	if ( ( rc = uriboot ( filename, root_path ) ) != 0 )
+	if ( ( rc = uriboot ( filename, root_path, san_default_drive(),
+			      ( root_path ? 0 : URIBOOT_NO_SAN ) ) ) != 0 )
 		goto err_uriboot;
 
  err_uriboot:
+ err_no_boot:
 	uri_put ( root_path );
  err_root_path:
 	uri_put ( filename );
@@ -405,3 +442,79 @@ int autoboot ( void ) {
 	printf ( "No more network devices\n" );
 	return rc;
 }
+
+/**
+ * Prompt for shell entry
+ *
+ * @ret	enter_shell	User wants to enter shell
+ */
+static int shell_banner ( void ) {
+
+	/* Skip prompt if timeout is zero */
+	if ( BANNER_TIMEOUT <= 0 )
+		return 0;
+
+	/* Prompt user */
+	printf ( "\n" );
+	return ( prompt ( "Press Ctrl-B for the iPXE command line...",
+			  ( BANNER_TIMEOUT * 100 ), CTRL_B ) == 0 );
+}
+
+/**
+ * Main iPXE flow of execution
+ *
+ * @v netdev		Network device, or NULL
+ */
+void ipxe ( struct net_device *netdev ) {
+	struct feature *feature;
+	struct image *image;
+	char *scriptlet;
+
+	/*
+	 * Print welcome banner
+	 *
+	 *
+	 * If you wish to brand this build of iPXE, 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 iPXE or http://ipxe.org, we prefer you not to
+	 * do so.
+	 *
+	 */
+	printf ( NORMAL "\n\n" PRODUCT_NAME "\n" BOLD "iPXE %s"
+		 NORMAL " -- Open Source Network Boot Firmware -- "
+		 CYAN "http://ipxe.org" NORMAL "\n"
+		 "Features:", product_version );
+	for_each_table_entry ( feature, FEATURES )
+		printf ( " %s", feature->name );
+	printf ( "\n" );
+
+	/* Boot system */
+	if ( ( image = first_image() ) != NULL ) {
+		/* We have an embedded image; execute it */
+		image_exec ( image );
+	} else if ( shell_banner() ) {
+		/* User wants shell; just give them a shell */
+		shell();
+	} else {
+		fetch_string_setting_copy ( NULL, &scriptlet_setting,
+					    &scriptlet );
+		if ( scriptlet ) {
+			/* User has defined a scriptlet; execute it */
+			system ( scriptlet );
+			free ( scriptlet );
+		} else {
+			/* Try booting.  If booting fails, offer the
+			 * user another chance to enter the shell.
+			 */
+			if ( netdev ) {
+				netboot ( netdev );
+			} else {
+				autoboot();
+			}
+			if ( shell_banner() )
+				shell();
+		}
+	}
+}
diff --git a/roms/ipxe/src/usr/dhcpmgmt.c b/roms/ipxe/src/usr/dhcpmgmt.c
index e651dfda1059d06f67d57bc50f8b..b61c01aa30d4d318ac842853947e 100644
--- a/roms/ipxe/src/usr/dhcpmgmt.c
+++ b/roms/ipxe/src/usr/dhcpmgmt.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -37,10 +38,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
  */
 
 int dhcp ( struct net_device *netdev ) {
-	struct dhcphdr *dhcphdr;
-	typeof ( dhcphdr->chaddr ) chaddr;
-	unsigned int hlen;
-	unsigned int i;
 	int rc;
 
 	/* Check we can open the interface first */
@@ -52,12 +49,8 @@ int dhcp ( struct net_device *netdev ) {
 		return rc;
 
 	/* Perform DHCP */
-	printf ( "DHCP (%s", netdev->name );
-	hlen = dhcp_chaddr ( netdev, chaddr, NULL );
-	for ( i = 0 ; i < hlen ; i++ )
-		printf ( "%c%02x", ( i ? ':' : ' ' ), chaddr[i] );
-	printf ( ")" );
-
+	printf ( "DHCP (%s %s)", netdev->name,
+		 netdev->ll_protocol->ntoa ( netdev->ll_addr ) );
 	if ( ( rc = start_dhcp ( &monojob, netdev ) ) == 0 ) {
 		rc = monojob_wait ( "" );
 	} else if ( rc > 0 ) {
diff --git a/roms/ipxe/src/usr/fcmgmt.c b/roms/ipxe/src/usr/fcmgmt.c
index 1af723d1313bd36dbc0583cf158d..2657ba0cfbad4a742824ba3638c0 100644
--- a/roms/ipxe/src/usr/fcmgmt.c
+++ b/roms/ipxe/src/usr/fcmgmt.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -74,8 +75,7 @@ void fcpeerstat ( struct fc_peer *peer ) {
 	}
 
 	list_for_each_entry ( ulp, &peer->ulps, list ) {
-		printf ( "  [Type %02x usage %d link:",
-			 ulp->type, ulp->usage );
+		printf ( "  [Type %02x link:", ulp->type );
 		if ( fc_link_ok ( &ulp->link ) ) {
 			printf ( " up, params" );
 			param = ulp->param;
diff --git a/roms/ipxe/src/usr/ifmgmt.c b/roms/ipxe/src/usr/ifmgmt.c
index 049851596da0514d1a8cd9077d3d..94e6e87546442857a628ed060919 100644
--- a/roms/ipxe/src/usr/ifmgmt.c
+++ b/roms/ipxe/src/usr/ifmgmt.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -113,6 +114,9 @@ int iflinkwait ( struct net_device *netdev, unsigned int max_wait_ms ) {
 	int key;
 	int rc;
 
+	/* Allow link state to be updated */
+	netdev_poll ( netdev );
+
 	if ( netdev_link_ok ( netdev ) )
 		return 0;
 
diff --git a/roms/ipxe/src/usr/imgmgmt.c b/roms/ipxe/src/usr/imgmgmt.c
index dbf792b75c9083252b9b427976ae..ef4e2c3664421cd51289123164f7 100644
--- a/roms/ipxe/src/usr/imgmgmt.c
+++ b/roms/ipxe/src/usr/imgmgmt.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -36,132 +37,24 @@ FILE_LICENCE ( GPL2_OR_LATER );
  */
 
 /**
- * Register an image and leave it registered
- *
- * @v image		Executable image
- * @ret rc		Return status code
- *
- * This function assumes an ownership of the passed image.
- */
-int register_and_put_image ( struct image *image ) {
-	int rc;
-
-	rc = register_image ( image );
-	image_put ( image );
-	return rc;
-}
-
-/**
- * Register and probe an image
- *
- * @v image		Executable image
- * @ret rc		Return status code
- *
- * This function assumes an ownership of the passed image.
- */
-int register_and_probe_image ( struct image *image ) {
-	int rc;
-
-	if ( ( rc = register_and_put_image ( image ) ) != 0 )
-		return rc;
-
-	if ( ( rc = image_probe ( image ) ) != 0 )
-		return rc;
-
-	return 0;
-}
-
-/**
- * Register and select an image
- *
- * @v image		Executable image
- * @ret rc		Return status code
- *
- * This function assumes an ownership of the passed image.
- */
-int register_and_select_image ( struct image *image ) {
-	int rc;
-
-	if ( ( rc = register_and_probe_image ( image ) ) != 0 )
-		return rc;
-
-	if ( ( rc = image_select ( image ) ) != 0 )
-		return rc;
-
-	return 0;
-}
-
-/**
- * Register and boot an image
- *
- * @v image		Image
- * @ret rc		Return status code
- *
- * This function assumes an ownership of the passed image.
- */
-int register_and_boot_image ( struct image *image ) {
-	int rc;
-
-	if ( ( rc = register_and_select_image ( image ) ) != 0 )
-		return rc;
-
-	if ( ( rc = image_exec ( image ) ) != 0 )
-		return rc;
-
-	return 0;
-}
-
-/**
- * Register and replace image
- *
- * @v image		Image
- * @ret rc		Return status code
- *
- * This function assumes an ownership of the passed image.
- */
-int register_and_replace_image ( struct image *image ) {
-	int rc;
-
-	if ( ( rc = register_and_probe_image ( image ) ) != 0 )
-		return rc;
-
-	if ( ( rc = image_replace ( image ) ) != 0 )
-		return rc;
-
-	return 0;
-}
-
-/**
- * Download an image
+ * Download a new image
  *
  * @v uri		URI
- * @v name		Image name, or NULL to use default
- * @v cmdline		Command line, or NULL for no command line
- * @v action		Action to take upon a successful download
+ * @v image		Image to fill in
  * @ret rc		Return status code
  */
-int imgdownload ( struct uri *uri, const char *name, const char *cmdline,
-		  int ( * action ) ( struct image *image ) ) {
-	struct image *image;
+int imgdownload ( struct uri *uri, struct image **image ) {
 	size_t len = ( unparse_uri ( NULL, 0, uri, URI_ALL ) + 1 );
 	char uri_string_redacted[len];
 	const char *password;
 	int rc;
 
 	/* Allocate image */
-	image = alloc_image();
-	if ( ! image )
-		return -ENOMEM;
-
-	/* Set image name */
-	if ( name )
-		image_set_name ( image, name );
-
-	/* Set image URI */
-	image_set_uri ( image, uri );
-
-	/* Set image command line */
-	image_set_cmdline ( image, cmdline );
+	*image = alloc_image ( uri );
+	if ( ! *image ) {
+		rc = -ENOMEM;
+		goto err_alloc_image;
+	}
 
 	/* Redact password portion of URI, if necessary */
 	password = uri->password;
@@ -172,51 +65,75 @@ int imgdownload ( struct uri *uri, const char *name, const char *cmdline,
 	uri->password = password;
 
 	/* Create downloader */
-	if ( ( rc = create_downloader ( &monojob, image, LOCATION_URI,
+	if ( ( rc = create_downloader ( &monojob, *image, LOCATION_URI,
 					uri ) ) != 0 ) {
-		image_put ( image );
-		return rc;
+		printf ( "Could not start download: %s\n", strerror ( rc ) );
+		goto err_create_downloader;
 	}
 
 	/* Wait for download to complete */
-	if ( ( rc = monojob_wait ( uri_string_redacted ) ) != 0 ) {
-		image_put ( image );
-		return rc;
+	if ( ( rc = monojob_wait ( uri_string_redacted ) ) != 0 )
+		goto err_monojob_wait;
+
+	/* Register image */
+	if ( ( rc = register_image ( *image ) ) != 0 ) {
+		printf ( "Could not register image: %s\n", strerror ( rc ) );
+		goto err_register_image;
 	}
 
-	/* Act upon downloaded image.  This action assumes our
-	 * ownership of the image.
+	/* Drop local reference to image.  Image is guaranteed to
+	 * remain in scope since it is registered.
 	 */
-	if ( ( rc = action ( image ) ) != 0 )
-		return rc;
+	image_put ( *image );
 
 	return 0;
+
+ err_register_image:
+ err_monojob_wait:
+ err_create_downloader:
+	image_put ( *image );
+ err_alloc_image:
+	return rc;
 }
 
 /**
- * Download an image
+ * Download a new image
  *
- * @v uri_string	URI as a string (e.g. "http://www.nowhere.com/vmlinuz")
- * @v name		Image name, or NULL to use default
- * @v cmdline		Command line, or NULL for no command line
- * @v action		Action to take upon a successful download
+ * @v uri_string	URI string
+ * @v image		Image to fill in
  * @ret rc		Return status code
  */
-int imgdownload_string ( const char *uri_string, const char *name,
-			 const char *cmdline,
-			 int ( * action ) ( struct image *image ) ) {
+int imgdownload_string ( const char *uri_string, struct image **image ) {
 	struct uri *uri;
 	int rc;
 
 	if ( ! ( uri = parse_uri ( uri_string ) ) )
 		return -ENOMEM;
 
-	rc = imgdownload ( uri, name, cmdline, action );
+	rc = imgdownload ( uri, image );
 
 	uri_put ( uri );
 	return rc;
 }
 
+/**
+ * Acquire an image
+ *
+ * @v name_uri		Name or URI string
+ * @v image		Image to fill in
+ * @ret rc		Return status code
+ */
+int imgacquire ( const char *name_uri, struct image **image ) {
+
+	/* If we already have an image with the specified name, use it */
+	*image = find_image ( name_uri );
+	if ( *image )
+		return 0;
+
+	/* Otherwise, download a new image */
+	return imgdownload_string ( name_uri, image );
+}
+
 /**
  * Display status of an image
  *
@@ -226,18 +143,13 @@ void imgstat ( struct image *image ) {
 	printf ( "%s : %zd bytes", image->name, image->len );
 	if ( image->type )
 		printf ( " [%s]", image->type->name );
+	if ( image->flags & IMAGE_TRUSTED )
+		printf ( " [TRUSTED]" );
 	if ( image->flags & IMAGE_SELECTED )
 		printf ( " [SELECTED]" );
+	if ( image->flags & IMAGE_AUTO_UNREGISTER )
+		printf ( " [AUTOFREE]" );
 	if ( image->cmdline )
 		printf ( " \"%s\"", image->cmdline );
 	printf ( "\n" );
 }
-
-/**
- * Free an image
- *
- * @v image		Executable/loadable image
- */
-void imgfree ( struct image *image ) {
-	unregister_image ( image );
-}
diff --git a/roms/ipxe/src/usr/imgtrust.c b/roms/ipxe/src/usr/imgtrust.c
new file mode 100644
index 0000000000000000000000000000000000000000..afb41529f00a90e645d4414e41fa56150b34d2e8
--- /dev/null
+++ b/roms/ipxe/src/usr/imgtrust.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <syslog.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/image.h>
+#include <ipxe/cms.h>
+#include <ipxe/validator.h>
+#include <ipxe/monojob.h>
+#include <usr/imgtrust.h>
+
+/** @file
+ *
+ * Image trust management
+ *
+ */
+
+/**
+ * Verify image using downloaded signature
+ *
+ * @v image		Image to verify
+ * @v signature		Image containing signature
+ * @v name		Required common name, or NULL to allow any name
+ * @ret rc		Return status code
+ */
+int imgverify ( struct image *image, struct image *signature,
+		const char *name ) {
+	size_t len;
+	void *data;
+	struct cms_signature *sig;
+	struct cms_signer_info *info;
+	time_t now;
+	int rc;
+
+	/* Mark image as untrusted */
+	image_untrust ( image );
+
+	/* Copy signature to internal memory */
+	len = signature->len;
+	data = malloc ( len );
+	if ( ! data ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	copy_from_user ( data, signature->data, 0, len );
+
+	/* Parse signature */
+	if ( ( rc = cms_signature ( data, len, &sig ) ) != 0 )
+		goto err_parse;
+
+	/* Free internal copy of signature */
+	free ( data );
+	data = NULL;
+
+	/* Complete all certificate chains */
+	list_for_each_entry ( info, &sig->info, list ) {
+		if ( ( rc = create_validator ( &monojob, info->chain ) ) != 0 )
+			goto err_create_validator;
+		if ( ( rc = monojob_wait ( NULL ) ) != 0 )
+			goto err_validator_wait;
+	}
+
+	/* Use signature to verify image */
+	now = time ( NULL );
+	if ( ( rc = cms_verify ( sig, image->data, image->len,
+				 name, now, NULL ) ) != 0 )
+		goto err_verify;
+
+	/* Drop reference to signature */
+	cms_put ( sig );
+	sig = NULL;
+
+	/* Mark image as trusted */
+	image_trust ( image );
+	syslog ( LOG_NOTICE, "Image \"%s\" signature OK\n", image->name );
+
+	return 0;
+
+ err_verify:
+ err_validator_wait:
+ err_create_validator:
+	cms_put ( sig );
+ err_parse:
+	free ( data );
+ err_alloc:
+	syslog ( LOG_ERR, "Image \"%s\" signature bad: %s\n",
+		 image->name, strerror ( rc ) );
+	return rc;
+}
diff --git a/roms/ipxe/src/usr/iwmgmt.c b/roms/ipxe/src/usr/iwmgmt.c
index 29f623c3797997206257bbf51cb4..a486bceb33696a8315e8f6ea6b20 100644
--- a/roms/ipxe/src/usr/iwmgmt.c
+++ b/roms/ipxe/src/usr/iwmgmt.c
@@ -13,13 +13,13 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
 
 #include <stdio.h>
-#include <ipxe/console.h>
 #include <string.h>
 #include <errno.h>
 #include <ipxe/net80211.h>
diff --git a/roms/ipxe/src/usr/lotest.c b/roms/ipxe/src/usr/lotest.c
index 7f9f2fd0780f9e64833e7cc208f2..c4b0b4413f9bd94a6daa39809080 100644
--- a/roms/ipxe/src/usr/lotest.c
+++ b/roms/ipxe/src/usr/lotest.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -47,12 +48,14 @@ FILE_LICENCE ( GPL2_OR_LATER );
  * @v netdev		Network device
  * @v ll_dest		Link-layer destination address
  * @v ll_source		Link-layer source address
+ * @v flags		Packet flags
  * @ret rc		Return status code
  */
 static int lotest_rx ( struct io_buffer *iobuf,
 		       struct net_device *netdev __unused,
 		       const void *ll_dest __unused,
-		       const void *ll_source __unused ) {
+		       const void *ll_source __unused,
+		       unsigned int flags __unused ) {
 	free_iob ( iobuf );
 	return -ENOTSUP;
 }
@@ -82,6 +85,86 @@ static struct net_protocol lotest_protocol __net_protocol = {
 	.net_addr_len = 0,
 };
 
+/**
+ * Wait for packet to be received
+ *
+ * @v receiver		Receiving network device*
+ * @v data		Expected data
+ * @v len		Expected data length
+ * @ret rc		Return status code
+ */
+static int loopback_wait ( struct net_device *receiver, void *data,
+			   size_t len ) {
+	struct ll_protocol *ll_protocol = receiver->ll_protocol;
+	struct io_buffer *iobuf;
+	const void *ll_dest;
+	const void *ll_source;
+	uint16_t net_proto;
+	unsigned int flags;
+	int rc;
+
+	/* Poll until packet arrives */
+	while ( 1 ) {
+
+		/* Check for cancellation */
+		if ( iskey() && ( getchar() == CTRL_C ) )
+			return -ECANCELED;
+
+		/* Poll network devices */
+		net_poll();
+
+		/* Dequeue packet, if available */
+		iobuf = netdev_rx_dequeue ( receiver );
+		if ( ! iobuf )
+			continue;
+
+		/* Strip link-layer header */
+		if ( ( rc = ll_protocol->pull ( receiver, iobuf, &ll_dest,
+						&ll_source, &net_proto,
+						&flags ) ) != 0 ) {
+			printf ( "\nFailed to strip link-layer header: %s",
+				 strerror ( rc ) );
+			free_iob ( iob_disown ( iobuf ) );
+			return rc;
+		}
+
+		/* Ignore non-loopback packets */
+		if ( net_proto != lotest_protocol.net_proto ) {
+			printf ( "\nReceived spurious packet type %04x\n",
+				 ntohs ( net_proto ) );
+			free_iob ( iob_disown ( iobuf ) );
+			continue;
+		}
+
+		/* Check packet length */
+		if ( iob_len ( iobuf ) != len ) {
+			printf ( "\nLength mismatch: sent %zd, received %zd",
+				 len, iob_len ( iobuf ) );
+			DBG ( "\nSent:\n" );
+			DBG_HDA ( 0, data, len );
+			DBG ( "Received:\n" );
+			DBG_HDA ( 0, iobuf->data, iob_len ( iobuf ) );
+			free_iob ( iob_disown ( iobuf ) );
+			return -EINVAL;
+		}
+
+		/* Check packet content */
+		if ( memcmp ( iobuf->data, data, len ) != 0 ) {
+			printf ( "\nContent mismatch" );
+			DBG ( "\nSent:\n" );
+			DBG_HDA ( 0, data, len );
+			DBG ( "Received:\n" );
+			DBG_HDA ( 0, iobuf->data, iob_len ( iobuf ) );
+			free_iob ( iob_disown ( iobuf ) );
+			return -EINVAL;
+		}
+
+		/* Discard packet and return */
+		free_iob ( iob_disown ( iobuf ) );
+		return 0;
+	}
+}
+
 /**
  * Perform loopback test between two network devices
  *
@@ -94,9 +177,6 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver,
 		    size_t mtu ) {
 	uint8_t buf[mtu];
 	struct io_buffer *iobuf;
-	const void *ll_dest;
-	const void *ll_source;
-	uint16_t net_proto;
 	unsigned int i;
 	unsigned int successes;
 	int rc;
@@ -137,7 +217,7 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver,
 		if ( ! iobuf ) {
 			printf ( "\nFailed to allocate I/O buffer" );
 			rc = -ENOMEM;
-			goto done;
+			break;
 		}
 		iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
 		memcpy ( iob_put ( iobuf, sizeof ( buf ) ),
@@ -149,64 +229,17 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver,
 				     sender->ll_addr ) ) != 0 ) {
 			printf ( "\nFailed to transmit packet: %s",
 				 strerror ( rc ) );
-			goto done;
+			break;
 		}
 
-		/* Poll until packet arrives */
-		do {
-			/* Check for cancellation */
-			if ( iskey() && ( getchar() == CTRL_C ) ) {
-				rc = -ECANCELED;
-				goto done;
-			}
-			/* Poll network devices */
-			net_poll();
-		} while ( ( iobuf = netdev_rx_dequeue ( receiver ) ) == NULL );
-
-		/* Check received packet */
-		if ( ( rc = receiver->ll_protocol->pull ( receiver, iobuf,
-							  &ll_dest, &ll_source,
-							  &net_proto ) ) != 0 ){
-			printf ( "\nFailed to strip link-layer header: %s",
-				 strerror ( rc ) );
-			goto done;
-		}
-		if ( net_proto == lotest_protocol.net_proto ) {
-			if ( iob_len ( iobuf ) != sizeof ( buf ) ) {
-				printf ( "\nLength mismatch: sent %zd, "
-					 "received %zd",
-					 sizeof ( buf ), iob_len ( iobuf ) );
-				DBG ( "\nSent:\n" );
-				DBG_HDA ( 0, buf, sizeof ( buf ) );
-				DBG ( "Received:\n" );
-				DBG_HDA ( 0, iobuf->data, iob_len ( iobuf ) );
-				rc = -EINVAL;
-				goto done;
-			}
-			if ( memcmp ( iobuf->data, buf, sizeof ( buf ) ) != 0){
-				printf ( "\nContent mismatch" );
-				DBG ( "\nSent:\n" );
-				DBG_HDA ( 0, buf, sizeof ( buf ) );
-				DBG ( "Received:\n" );
-				DBG_HDA ( 0, iobuf->data, iob_len ( iobuf ) );
-				rc = -EINVAL;
-				goto done;
-			}
-		} else {
-			printf ( "\nReceived spurious packet type %04x\n",
-				 ntohs ( net_proto ) );
-			/* Continue; this allows for the fact that
-			 * there may have been packets outstanding on
-			 * the wire when we started the test.
-			 */
+		/* Wait for received packet */
+		if ( ( rc = loopback_wait ( receiver, buf,
+					    sizeof ( buf ) ) ) != 0 ) {
+			break;
 		}
-
-		free_iob ( iob_disown ( iobuf ) );
 	}
 
- done:
 	printf ( "\n");
-	free_iob ( iobuf );
 	netdev_rx_unfreeze ( receiver );
 
 	/* Dump final statistics */
diff --git a/roms/ipxe/src/usr/nslookup.c b/roms/ipxe/src/usr/nslookup.c
new file mode 100644
index 0000000000000000000000000000000000000000..c931ec5a1e31d7c323265f5854f2f1c5d0acfe95
--- /dev/null
+++ b/roms/ipxe/src/usr/nslookup.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2012 Patrick Plenefisch <phplenefisch@wpi.edu>.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/resolv.h>
+#include <ipxe/tcpip.h>
+#include <ipxe/monojob.h>
+#include <ipxe/settings.h>
+#include <usr/nslookup.h>
+
+/** @file
+ *
+ * Standalone name resolution
+ *
+ */
+
+/** A name resolution request */
+struct nslookup {
+	/** Reference count for this object */
+	struct refcnt refcnt;
+
+	/** Job control interface */
+	struct interface job;
+	/** Data transfer interface */
+	struct interface resolver;
+
+	/** Setting name */
+	const char *setting_name;
+};
+
+/**
+ * Terminate name resolution
+ *
+ * @v nslookup		Name resolution request
+ * @v rc		Reason for termination
+ */
+static void nslookup_close ( struct nslookup *nslookup, int rc ) {
+
+	/* Shut down interfaces */
+	intf_shutdown ( &nslookup->resolver, rc );
+	intf_shutdown ( &nslookup->job, rc );
+}
+
+/**
+ * Handle resolved name
+ *
+ * @v nslookup		Name resolution request
+ * @v sa		Completed socket address
+ */
+static void nslookup_resolv_done ( struct nslookup *nslookup,
+				   struct sockaddr *sa ) {
+	struct sockaddr_in *sin;
+	struct setting_type *type;
+	void *data;
+	size_t len;
+	int rc;
+
+	/* Extract address */
+	switch ( sa->sa_family ) {
+	case AF_INET:
+		sin = ( ( struct sockaddr_in * ) sa );
+		data = &sin->sin_addr;
+		len = sizeof ( sin->sin_addr );
+		type = &setting_type_ipv4;
+		break;
+	default:
+		rc = -ENOTSUP;
+		goto err;
+	}
+
+	/* Save in specified setting */
+	if ( ( rc = store_named_setting ( nslookup->setting_name, type,
+					  data, len ) ) != 0 )
+		goto err;
+
+ err:
+	/* Terminate name resolution */
+	nslookup_close ( nslookup, rc );
+}
+
+/** Name resolution resolver interface operations */
+static struct interface_operation nslookup_resolver_operations[] = {
+	INTF_OP ( resolv_done, struct nslookup *, nslookup_resolv_done ),
+	INTF_OP ( intf_close, struct nslookup *, nslookup_close ),
+};
+
+/** Name resolution resolver interface descriptor */
+static struct interface_descriptor nslookup_resolver_desc =
+	INTF_DESC_PASSTHRU ( struct nslookup, resolver,
+			     nslookup_resolver_operations, job );
+
+/** Name resolution job control interface operations */
+static struct interface_operation nslookup_job_operations[] = {
+	INTF_OP ( intf_close, struct nslookup *, nslookup_close ),
+};
+
+/** Name resolution job control interface descriptor */
+static struct interface_descriptor nslookup_job_desc =
+	INTF_DESC_PASSTHRU ( struct nslookup, job,
+			     nslookup_job_operations, resolver );
+
+/**
+ * Initiate standalone name resolution
+ *
+ * @v job		Parent interface
+ * @v name		Name to resolve
+ * @v setting_name	Setting name
+ * @ret rc		Return status code
+ */
+static int resolv_setting ( struct interface *job, const char *name,
+			    const char *setting_name ) {
+	struct nslookup *nslookup;
+	struct sockaddr sa;
+	char *setting_name_copy;
+	int rc;
+
+	/* Allocate and initialise structure */
+	nslookup = zalloc ( sizeof ( *nslookup ) + strlen ( setting_name )
+			    + 1 /* NUL */ );
+	if ( ! nslookup )
+		return -ENOMEM;
+	ref_init ( &nslookup->refcnt, NULL );
+	intf_init ( &nslookup->job, &nslookup_job_desc, &nslookup->refcnt );
+	intf_init ( &nslookup->resolver, &nslookup_resolver_desc,
+		    &nslookup->refcnt );
+	setting_name_copy = ( ( void * ) ( nslookup + 1 ) );
+	strcpy ( setting_name_copy, setting_name );
+	nslookup->setting_name = setting_name_copy;
+
+	/* Start name resolution */
+	memset ( &sa, 0, sizeof ( sa ) );
+	if ( ( rc = resolv ( &nslookup->resolver, name, &sa ) ) != 0 )
+		goto err_resolv;
+
+	/* Attach parent interface, mortalise self, and return */
+	intf_plug_plug ( &nslookup->job, job );
+	ref_put ( &nslookup->refcnt );
+	return 0;
+
+ err_resolv:
+	ref_put ( &nslookup->refcnt );
+	return rc;
+}
+
+/**
+ * Perform (blocking) standalone name resolution
+ *
+ * @v name		Name to resolve
+ * @v setting_name	Setting name
+ * @ret rc		Return status code
+ */
+int nslookup ( const char *name, const char *setting_name ) {
+	int rc;
+
+	/* Perform name resolution */
+	if ( ( rc = resolv_setting ( &monojob, name, setting_name ) ) == 0 )
+		rc = monojob_wait ( NULL );
+	if ( rc != 0 ) {
+		printf ( "Could not resolve %s: %s\n", name, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
diff --git a/roms/ipxe/src/usr/prompt.c b/roms/ipxe/src/usr/prompt.c
index 3c353a686a5fa8d1ea8bfe388c3d..ede037457185f0039d450bdb41f5 100644
--- a/roms/ipxe/src/usr/prompt.c
+++ b/roms/ipxe/src/usr/prompt.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/usr/pxemenu.c b/roms/ipxe/src/usr/pxemenu.c
index 75789e2dcde52bf389bf4bfc1214..d50ee6ba917870ae10fc8e479a52 100644
--- a/roms/ipxe/src/usr/pxemenu.c
+++ b/roms/ipxe/src/usr/pxemenu.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
@@ -377,7 +378,7 @@ int pxe_menu_boot ( struct net_device *netdev ) {
 		return -ENOMEM;
 
 	/* Attempt boot */
-	rc = uriboot ( uri, NULL );
+	rc = uriboot ( uri, NULL, 0, URIBOOT_NO_SAN );
 	uri_put ( uri );
 	return rc;
 }
diff --git a/roms/ipxe/src/usr/route.c b/roms/ipxe/src/usr/route.c
index 1da7135bc5150ec8d951516bda13..e393e38d4fade20f9a746d3cfc36 100644
--- a/roms/ipxe/src/usr/route.c
+++ b/roms/ipxe/src/usr/route.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 FILE_LICENCE ( GPL2_OR_LATER );
diff --git a/roms/ipxe/src/util/Makefile b/roms/ipxe/src/util/Makefile
index d72661e21c04b4218acc84435d3f..4a6a7c7c6e3a58d0e271044b686a 100644
--- a/roms/ipxe/src/util/Makefile
+++ b/roms/ipxe/src/util/Makefile
@@ -1,17 +1,11 @@
 BLIB = ../bin/blib.a
 CFLAGS = -Os
 
-all : hijack prototester mucurses_test
+all : hijack mucurses_test
 
 hijack : hijack.c
 	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wall -lpcap -o $@ $<
 
-prototester.o : prototester.c
-	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wall -o $@ -c $< -idirafter ../include
-
-prototester : prototester.o $(BLIB)
-	$(CC) -o $@ $< -lc $(BLIB)
-
 mucurses_test.o : mucurses_test.c
 	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wall -o $@ -c $<
 
@@ -19,4 +13,4 @@ mucurses_test : mucurses_test.o $(BLIB)
 	$(CC) -o $@ $< -lc $(BLIB)
 
 clean :
-	rm -f hijack prototester mucurses_test *.o
+	rm -f hijack mucurses_test *.o
diff --git a/roms/ipxe/src/util/Option/ROM.pm b/roms/ipxe/src/util/Option/ROM.pm
index 9fea4d344eab786d31985045985a..fb37ce4b0cc4e27528afc4044143 100644
--- a/roms/ipxe/src/util/Option/ROM.pm
+++ b/roms/ipxe/src/util/Option/ROM.pm
@@ -14,7 +14,8 @@ package Option::ROM;
 #
 # 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.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
 
 =head1 NAME
 
@@ -169,13 +170,17 @@ use Exporter 'import';
 
 use constant ROM_SIGNATURE => 0xaa55;
 use constant PCI_SIGNATURE => 'PCIR';
+use constant PCI_LAST_IMAGE => 0x80;
 use constant PNP_SIGNATURE => '$PnP';
+use constant IPXE_SIGNATURE => 'iPXE';
 
-our @EXPORT_OK = qw ( ROM_SIGNATURE PCI_SIGNATURE PNP_SIGNATURE );
+our @EXPORT_OK = qw ( ROM_SIGNATURE PCI_SIGNATURE PCI_LAST_IMAGE
+		      PNP_SIGNATURE IPXE_SIGNATURE );
 our %EXPORT_TAGS = ( all => [ @EXPORT_OK ] );
 
 use constant JMP_SHORT => 0xeb;
 use constant JMP_NEAR => 0xe9;
+use constant CALL_NEAR => 0xe8;
 
 sub pack_init {
   my $dest = shift;
@@ -199,6 +204,9 @@ sub unpack_init {
   } elsif ( $jump == JMP_NEAR ) {
     my $offset = unpack ( "xS", $instr );
     return ( $offset + 6 );
+  } elsif ( $jump == CALL_NEAR ) {
+    my $offset = unpack ( "xS", $instr );
+    return ( $offset + 6 );
   } elsif ( $jump == 0 ) {
     return 0;
   } else {
@@ -229,6 +237,7 @@ sub new {
       init =>		{ offset => 0x03, length => 0x03,
 			  pack => \&pack_init, unpack => \&unpack_init },
       checksum =>	{ offset => 0x06, length => 0x01, pack => "C" },
+      ipxe_header =>	{ offset => 0x10, length => 0x02, pack => "S" },
       bofm_header =>	{ offset => 0x14, length => 0x02, pack => "S" },
       undi_header =>	{ offset => 0x16, length => 0x02, pack => "S" },
       pci_header =>	{ offset => 0x18, length => 0x02, pack => "S" },
@@ -241,6 +250,53 @@ sub new {
 
 =pod
 
+=item C<< set ( $data ) >>
+
+Set option ROM contents.
+
+=cut
+
+sub set {
+  my $hash = shift;
+  my $self = tied(%$hash);
+  my $data = shift;
+
+  # Store data
+  $self->{data} = \$data;
+
+  # Split out any data belonging to the next image
+  delete $self->{next_image};
+  my $length = ( $hash->{length} * 512 );
+  my $pci_header = $hash->pci_header();
+  if ( ( $length < length $data ) &&
+       ( defined $pci_header ) &&
+       ( ! ( $pci_header->{last_image} & PCI_LAST_IMAGE ) ) ) {
+    my $remainder = substr ( $data, $length );
+    $data = substr ( $data, 0, $length );
+    $self->{next_image} = new Option::ROM;
+    $self->{next_image}->set ( $remainder );
+  }
+}
+
+=pod
+
+=item C<< get () >>
+
+Get option ROM contents.
+
+=cut
+
+sub get {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  my $data = ${$self->{data}};
+  $data .= $self->{next_image}->get() if $self->{next_image};
+  return $data;
+}
+
+=pod
+
 =item C<< load ( $filename ) >>
 
 Load option ROM contents from the file C<$filename>.
@@ -256,8 +312,8 @@ sub load {
 
   open my $fh, "<$filename"
       or croak "Cannot open $filename for reading: $!";
-  read $fh, my $data, ( 128 * 1024 ); # 128kB is theoretical max size
-  $self->{data} = \$data;
+  read $fh, my $data, -s $fh;
+  $hash->set ( $data );
   close $fh;
 }
 
@@ -279,7 +335,8 @@ sub save {
 
   open my $fh, ">$filename"
       or croak "Cannot open $filename for writing: $!";
-  print $fh ${$self->{data}};
+  my $data = $hash->get();
+  print $fh $data;
   close $fh;
 }
 
@@ -339,6 +396,60 @@ sub pnp_header {
 
 =pod
 
+=item C<< undi_header () >>
+
+Return a C<Option::ROM::UNDI> object representing the ROM's UNDI header,
+if present.
+
+=cut
+
+sub undi_header {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  my $offset = $hash->{undi_header};
+  return undef unless $offset != 0;
+
+  return Option::ROM::UNDI->new ( $self->{data}, $offset );
+}
+
+=pod
+
+=item C<< ipxe_header () >>
+
+Return a C<Option::ROM::iPXE> object representing the ROM's iPXE
+header, if present.
+
+=cut
+
+sub ipxe_header {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  my $offset = $hash->{ipxe_header};
+  return undef unless $offset != 0;
+
+  return Option::ROM::iPXE->new ( $self->{data}, $offset );
+}
+
+=pod
+
+=item C<< next_image () >>
+
+Return a C<Option::ROM> object representing the next image within the
+ROM, if present.
+
+=cut
+
+sub next_image {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  return $self->{next_image};
+}
+
+=pod
+
 =item C<< checksum () >>
 
 Calculate the byte checksum of the ROM.
@@ -499,4 +610,119 @@ sub product {
   return unpack ( "Z*", $raw );
 }
 
+##############################################################################
+#
+# Option::ROM::UNDI
+#
+##############################################################################
+
+package Option::ROM::UNDI;
+
+use strict;
+use warnings;
+use Carp;
+use bytes;
+
+sub new {
+  my $class = shift;
+  my $data = shift;
+  my $offset = shift;
+
+  my $hash = {};
+  tie %$hash, "Option::ROM::Fields", {
+    data => $data,
+    offset => $offset,
+    length => 0x16,
+    fields => {
+      signature =>	{ offset => 0x00, length => 0x04, pack => "a4" },
+      struct_length =>	{ offset => 0x04, length => 0x01, pack => "C" },
+      checksum =>	{ offset => 0x05, length => 0x01, pack => "C" },
+      struct_revision =>{ offset => 0x06, length => 0x01, pack => "C" },
+      version_revision =>{ offset => 0x07, length => 0x01, pack => "C" },
+      version_minor =>	{ offset => 0x08, length => 0x01, pack => "C" },
+      version_major =>	{ offset => 0x09, length => 0x01, pack => "C" },
+      loader_entry =>	{ offset => 0x0a, length => 0x02, pack => "S" },
+      stack_size =>	{ offset => 0x0c, length => 0x02, pack => "S" },
+      data_size =>	{ offset => 0x0e, length => 0x02, pack => "S" },
+      code_size =>	{ offset => 0x10, length => 0x02, pack => "S" },
+      bus_type =>	{ offset => 0x12, length => 0x04, pack => "a4" },
+    },
+  };
+  bless $hash, $class;
+
+  # Retrieve true length of structure
+  my $self = tied ( %$hash );
+  $self->{length} = $hash->{struct_length};
+
+  return $hash;
+}
+
+sub checksum {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  return $self->checksum();
+}
+
+sub fix_checksum {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  $hash->{checksum} = ( ( $hash->{checksum} - $hash->checksum() ) & 0xff );
+}
+
+##############################################################################
+#
+# Option::ROM::iPXE
+#
+##############################################################################
+
+package Option::ROM::iPXE;
+
+use strict;
+use warnings;
+use Carp;
+use bytes;
+
+sub new {
+  my $class = shift;
+  my $data = shift;
+  my $offset = shift;
+
+  my $hash = {};
+  tie %$hash, "Option::ROM::Fields", {
+    data => $data,
+    offset => $offset,
+    length => 0x06,
+    fields => {
+      signature =>	{ offset => 0x00, length => 0x04, pack => "a4" },
+      struct_length =>	{ offset => 0x04, length => 0x01, pack => "C" },
+      checksum =>	{ offset => 0x05, length => 0x01, pack => "C" },
+      shrunk_length =>	{ offset => 0x06, length => 0x01, pack => "C" },
+      build_id =>	{ offset => 0x08, length => 0x04, pack => "L" },
+    },
+  };
+  bless $hash, $class;
+
+  # Retrieve true length of structure
+  my $self = tied ( %$hash );
+  $self->{length} = $hash->{struct_length};
+
+  return $hash;
+}
+
+sub checksum {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  return $self->checksum();
+}
+
+sub fix_checksum {
+  my $hash = shift;
+  my $self = tied(%$hash);
+
+  $hash->{checksum} = ( ( $hash->{checksum} - $hash->checksum() ) & 0xff );
+}
+
 1;
diff --git a/roms/ipxe/src/util/catrom.pl b/roms/ipxe/src/util/catrom.pl
index fe37e6b6e81ae1e56e279fed55d4..da99d7b9708cebca8c600f61fea7 100755
--- a/roms/ipxe/src/util/catrom.pl
+++ b/roms/ipxe/src/util/catrom.pl
@@ -3,46 +3,27 @@
 use warnings;
 use strict;
 
-use bytes;
+use FindBin;
+use lib "$FindBin::Bin";
+use Option::ROM qw ( :all );
 
-use constant MAX_ROM_LEN => 1024*1024;
-use constant PCI_OFF => 0x18;
-use constant INDICATOR_OFF => 0x15;
-
-my $total_len = 0;
 my @romfiles = @ARGV
     or die "Usage: $0 rom-file-1 rom-file-2 ... > multi-rom-file\n";
 
 while ( my $romfile = shift @romfiles ) {
-  my $last = @romfiles ? 0 : 1;
-
-  open ROM, "<$romfile" or die "Could not open $romfile: $!\n";
-  my $len = read ( ROM, my $romdata, MAX_ROM_LEN )
-      or die "Could not read $romfile: $!\n";
-  close ROM;
-
-  die "$romfile is not a ROM file\n"
-      unless substr ( $romdata, 0, 2 ) eq "\x55\xAA";
 
-  ( my $checklen ) = unpack ( 'C', substr ( $romdata, 2, 1 ) );
-  $checklen *= 512;
-  die "$romfile has incorrect length field $checklen (should be $len)\n"
-      unless $len == $checklen;
+  # Read ROM file
+  my $rom = new Option::ROM;
+  $rom->load ( $romfile );
 
-  ( my $pci ) = unpack ( 'v', substr ( $romdata, PCI_OFF, 2 ) );
-  die "Invalid PCI offset field in $romfile\n"
-      if $pci >= $len;
-  die "No PCIR signature in $romfile\n"
-      unless substr ( $romdata, $pci, 4 ) eq "PCIR";
-  
-  ( my $indicator ) =
-      unpack ( 'C', substr ( $romdata, $pci + INDICATOR_OFF, 1 ) );
-  my $msg = sprintf ( "$romfile: indicator was %02x, ", $indicator );
-  $indicator &= ! ( 1 << 7 );
-  $indicator |= ( $last << 7 );
-  $msg .= sprintf ( "now %02x\n", $indicator );
-  substr ( $romdata, $pci + INDICATOR_OFF, 1 ) = pack ( 'C', $indicator );
-  warn $msg;
+  # Tag final image as non-final in all except the final ROM
+  if ( @romfiles ) {
+    my $image = $rom;
+    $image = $image->next_image() while $image->next_image();
+    $image->pci_header->{last_image} &= ~PCI_LAST_IMAGE;
+    $image->fix_checksum();
+  }
 
-  print $romdata;
+  # Write ROM file to STDOUT
+  $rom->save ( "-" );
 }
diff --git a/roms/ipxe/src/util/disrom.pl b/roms/ipxe/src/util/disrom.pl
index 1fb4cc3cb80daeb382c13e098c18..574957acda8cce1b702459e1c460 100755
--- a/roms/ipxe/src/util/disrom.pl
+++ b/roms/ipxe/src/util/disrom.pl
@@ -14,7 +14,8 @@
 #
 # 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.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
 
 use strict;
 use warnings;
@@ -27,55 +28,88 @@ my $romfile = shift || "-";
 my $rom = new Option::ROM;
 $rom->load ( $romfile );
 
-die "Not an option ROM image\n"
-    unless $rom->{signature} == ROM_SIGNATURE;
+do {
 
-my $romlength = ( $rom->{length} * 512 );
-my $filelength = $rom->length;
-die "ROM image truncated (is $filelength, should be $romlength)\n"
-    if $filelength < $romlength;
+  die "Not an option ROM image\n"
+      unless $rom->{signature} == ROM_SIGNATURE;
 
-printf "ROM header:\n\n";
-printf "  %-16s 0x%02x (%d)\n", "Length:", $rom->{length}, ( $rom->{length} * 512 );
-printf "  %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $rom->{checksum},
-       ( ( $rom->checksum == 0 ) ? "" : "INCORRECT: " ), $rom->checksum;
-printf "  %-16s 0x%04x\n", "Init:", $rom->{init};
-printf "  %-16s 0x%04x\n", "UNDI header:", $rom->{undi_header};
-printf "  %-16s 0x%04x\n", "PCI header:", $rom->{pci_header};
-printf "  %-16s 0x%04x\n", "PnP header:", $rom->{pnp_header};
-printf "\n";
+  my $romlength = ( $rom->{length} * 512 );
+  my $filelength = $rom->length;
+  die "ROM image truncated (is $filelength, should be $romlength)\n"
+      if $filelength < $romlength;
 
-my $pci = $rom->pci_header();
-if ( $pci ) {
-  printf "PCI header:\n\n";
-  printf "  %-16s %s\n", "Signature:", $pci->{signature};
-  printf "  %-16s 0x%04x\n", "Vendor ID:", $pci->{vendor_id};
-  printf "  %-16s 0x%04x\n", "Device ID:", $pci->{device_id};
-  printf "  %-16s 0x%02x%02x%02x\n", "Device class:",
-	 $pci->{base_class}, $pci->{sub_class}, $pci->{prog_intf};
-  printf "  %-16s 0x%04x (%d)\n", "Image length:",
-	 $pci->{image_length}, ( $pci->{image_length} * 512 );
-  printf "  %-16s 0x%04x (%d)\n", "Runtime length:",
-	 $pci->{runtime_length}, ( $pci->{runtime_length} * 512 );
-  if ( exists $pci->{conf_header} ) {
-    printf "  %-16s 0x%04x\n", "Config header:", $pci->{conf_header};
-    printf "  %-16s 0x%04x\n", "CLP entry:", $pci->{clp_entry};
-  }
+  printf "ROM header:\n\n";
+  printf "  %-16s 0x%02x (%d)\n", "Length:",
+	 $rom->{length}, ( $rom->{length} * 512 );
+  printf "  %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $rom->{checksum},
+	 ( ( $rom->checksum == 0 ) ? "" : "INCORRECT: " ), $rom->checksum;
+  printf "  %-16s 0x%04x\n", "Init:", $rom->{init};
+  printf "  %-16s 0x%04x\n", "UNDI header:", $rom->{undi_header};
+  printf "  %-16s 0x%04x\n", "PCI header:", $rom->{pci_header};
+  printf "  %-16s 0x%04x\n", "PnP header:", $rom->{pnp_header};
   printf "\n";
-}
 
-my $pnp = $rom->pnp_header();
-if ( $pnp ) {
-  printf "PnP header:\n\n";
-  printf "  %-16s %s\n", "Signature:", $pnp->{signature};
-  printf "  %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $pnp->{checksum},
-	 ( ( $pnp->checksum == 0 ) ? "" : "INCORRECT: " ), $pnp->checksum;
-  printf "  %-16s 0x%04x \"%s\"\n", "Manufacturer:",
-	 $pnp->{manufacturer}, $pnp->manufacturer;
-  printf "  %-16s 0x%04x \"%s\"\n", "Product:",
-	 $pnp->{product}, $pnp->product;
-  printf "  %-16s 0x%04x\n", "BCV:", $pnp->{bcv};
-  printf "  %-16s 0x%04x\n", "BDV:", $pnp->{bdv};
-  printf "  %-16s 0x%04x\n", "BEV:", $pnp->{bev};
-  printf "\n";
-}
+  my $pci = $rom->pci_header();
+  if ( $pci ) {
+    printf "PCI header:\n\n";
+    printf "  %-16s %s\n", "Signature:", $pci->{signature};
+    printf "  %-16s 0x%04x\n", "Vendor ID:", $pci->{vendor_id};
+    printf "  %-16s 0x%04x\n", "Device ID:", $pci->{device_id};
+    printf "  %-16s 0x%02x%02x%02x\n", "Device class:",
+	   $pci->{base_class}, $pci->{sub_class}, $pci->{prog_intf};
+    printf "  %-16s 0x%04x (%d)\n", "Image length:",
+	   $pci->{image_length}, ( $pci->{image_length} * 512 );
+    printf "  %-16s 0x%04x (%d)\n", "Runtime length:",
+	   $pci->{runtime_length}, ( $pci->{runtime_length} * 512 );
+    printf "  %-16s 0x%02x\n", "Code type:", $pci->{code_type};
+    if ( exists $pci->{conf_header} ) {
+      printf "  %-16s 0x%04x\n", "Config header:", $pci->{conf_header};
+      printf "  %-16s 0x%04x\n", "CLP entry:", $pci->{clp_entry};
+    }
+    printf "\n";
+  }
+
+  my $pnp = $rom->pnp_header();
+  if ( $pnp ) {
+    printf "PnP header:\n\n";
+    printf "  %-16s %s\n", "Signature:", $pnp->{signature};
+    printf "  %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $pnp->{checksum},
+	   ( ( $pnp->checksum == 0 ) ? "" : "INCORRECT: " ), $pnp->checksum;
+    printf "  %-16s 0x%04x \"%s\"\n", "Manufacturer:",
+	   $pnp->{manufacturer}, $pnp->manufacturer;
+    printf "  %-16s 0x%04x \"%s\"\n", "Product:",
+	   $pnp->{product}, $pnp->product;
+    printf "  %-16s 0x%04x\n", "BCV:", $pnp->{bcv};
+    printf "  %-16s 0x%04x\n", "BDV:", $pnp->{bdv};
+    printf "  %-16s 0x%04x\n", "BEV:", $pnp->{bev};
+    printf "\n";
+  }
+
+  my $undi = $rom->undi_header();
+  if ( $undi ) {
+    printf "UNDI header:\n\n";
+    printf "  %-16s %s\n", "Signature:", $undi->{signature};
+    printf "  %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $undi->{checksum},
+	   ( ( $undi->checksum == 0 ) ? "" : "INCORRECT: " ), $undi->checksum;
+    printf "  %-16s %d.%d.%d\n", "UNDI version:", $undi->{version_major},
+	   $undi->{version_minor}, $undi->{version_revision};
+    printf "  %-16s 0x%04x\n", "Loader entry:", $undi->{loader_entry};
+    printf "  %-16s 0x%04x\n", "Stack size:", $undi->{stack_size};
+    printf "  %-16s 0x%04x\n", "Data size:", $undi->{data_size};
+    printf "  %-16s 0x%04x\n", "Code size:", $undi->{code_size};
+    printf "  %-16s %s\n", "Bus type:", $undi->{bus_type};
+    printf "\n";
+  }
+
+  my $ipxe = $rom->ipxe_header();
+  if ( $ipxe ) {
+    printf "iPXE header:\n\n";
+    printf "  %-16s 0x%02x (%s0x%02x)\n", "Checksum:", $ipxe->{checksum},
+	   ( ( $ipxe->checksum == 0 ) ? "" : "INCORRECT: " ), $ipxe->checksum;
+    printf "  %-16s 0x%02x (%d)\n", "Shrunk length:",
+	   $ipxe->{shrunk_length}, ( $ipxe->{shrunk_length} * 512 );
+    printf "  %-16s 0x%08x\n", "Build ID:", $ipxe->{build_id};
+    printf "\n";
+  }
+
+} while ( $rom = $rom->next_image );
diff --git a/roms/ipxe/src/util/efirom.c b/roms/ipxe/src/util/efirom.c
index d0bdace62df9f664451ea99c0433..abee496dd0d7fd6441612366234b 100644
--- a/roms/ipxe/src/util/efirom.c
+++ b/roms/ipxe/src/util/efirom.c
@@ -13,7 +13,8 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #include <stdint.h>
@@ -56,18 +57,6 @@ static void * xmalloc ( size_t len ) {
 	return ptr;
 }
 
-/**
- * Get file size
- *
- * @v file		File
- * @v len		File size
- */
-static size_t file_size ( FILE *file ) {
-	ssize_t len;
-
-	return len;
-}
-
 /**
  * Read information from PE headers
  *
@@ -239,15 +228,15 @@ static int parse_options ( const int argc, char **argv,
 }
 
 int main ( int argc, char **argv ) {
-	struct options opts = {
-	};
-	unsigned int infile_index;
+	struct options opts;
+	int infile_index;
 	const char *infile_name;
 	const char *outfile_name;
 	FILE *infile;
 	FILE *outfile;
 
 	/* Parse command-line arguments */
+	memset ( &opts, 0, sizeof ( opts ) );
 	infile_index = parse_options ( argc, argv, &opts );
 	if ( argc != ( infile_index + 2 ) ) {
 		print_help ( argv[0] );
diff --git a/roms/ipxe/src/util/einfo.c b/roms/ipxe/src/util/einfo.c
index 06736f219abe8ef56a6f0e206ec5..354d475fa2b46aa5806f8d3b39e4 100644
--- a/roms/ipxe/src/util/einfo.c
+++ b/roms/ipxe/src/util/einfo.c
@@ -13,13 +13,15 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #include <stddef.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <string.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -49,7 +51,8 @@ struct einfo {
  * @v infile		Filename
  * @v opts		Command-line options
  */
-static void einfo ( const char *infile, struct options *opts ) {
+static void einfo ( const char *infile,
+		    struct options *opts __attribute__ (( unused )) ) {
 	int fd;
 	struct stat stat;
 	size_t len;
@@ -85,15 +88,16 @@ static void einfo ( const char *infile, struct options *opts ) {
 		for ( einfo = start ; ( ( void * ) einfo ) < ( start + len ) ;
 		      einfo = ( ( ( void * ) einfo ) + einfo->size ) ) {
 			printf ( "%08x\t%s\t%d\t%s\n", einfo->error,
-				 ( ( ( void * ) einfo ) + einfo->file ),
+				 ( ( ( char * ) einfo ) + einfo->file ),
 				 einfo->line,
-				 ( ( ( void * ) einfo ) + einfo->desc ) );
+				 ( ( ( char * ) einfo ) + einfo->desc ) );
 		}
 
+		/* Unmap file */
+		munmap ( start, len );
 	}
 
-	/* Unmap and close file */
-	munmap ( start, len );
+	/* Close file */
 	close ( fd );
 }
 
@@ -115,8 +119,7 @@ static void print_help ( const char *program_name ) {
  * @v opts		Options structure to populate
  */
 static int parse_options ( const int argc, char **argv,
-			   struct options *opts ) {
-	char *end;
+			   struct options *opts __attribute__ (( unused )) ) {
 	int c;
 
 	while (1) {
@@ -147,7 +150,7 @@ static int parse_options ( const int argc, char **argv,
 int main ( int argc, char **argv ) {
 	struct options opts = {
 	};
-	unsigned int infile_index;
+	int infile_index;
 	const char *infile;
 
 	/* Parse command-line arguments */
diff --git a/roms/ipxe/src/util/elf2efi.c b/roms/ipxe/src/util/elf2efi.c
index e66292966d3eed7c5baee0ffdc03..45d539574e3be734958f7af38ab1 100644
--- a/roms/ipxe/src/util/elf2efi.c
+++ b/roms/ipxe/src/util/elf2efi.c
@@ -13,10 +13,13 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #define _GNU_SOURCE
+#define PACKAGE "elf2efi"
+#define PACKAGE_VERSION "1"
 #include <stdint.h>
 #include <stddef.h>
 #include <stdlib.h>
@@ -405,6 +408,10 @@ static struct pe_section * process_section ( bfd *bfd,
 			  EFI_IMAGE_SCN_MEM_WRITE );
 		applicable_start = &data_mid;
 		applicable_end = &data_end;
+	} else {
+		eprintf ( "Unrecognised characteristics %#lx for section %s\n",
+			  flags, section->name );
+		exit ( 1 );
 	}
 
 	/* Copy in section contents */
@@ -459,7 +466,8 @@ static struct pe_section * process_section ( bfd *bfd,
  * @v rel		Relocation entry
  * @v pe_reltab		PE relocation table to fill in
  */
-static void process_reloc ( bfd *bfd, asection *section, arelent *rel,
+static void process_reloc ( bfd *bfd __attribute__ (( unused )),
+			    asection *section, arelent *rel,
 			    struct pe_relocs **pe_reltab ) {
 	reloc_howto_type *howto = rel->howto;
 	asymbol *sym = *(rel->sym_ptr_ptr);
@@ -608,8 +616,11 @@ static void write_pe_file ( struct pe_header *pe_header,
 	struct pe_section *section;
 	unsigned long fpos = 0;
 
+	/* Align length of headers */
+	fpos = pe_header->nt.OptionalHeader.SizeOfHeaders =
+		efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders );
+
 	/* Assign raw data pointers */
-	fpos = efi_file_align ( pe_header->nt.OptionalHeader.SizeOfHeaders );
 	for ( section = pe_sections ; section ; section = section->next ) {
 		if ( section->hdr.SizeOfRawData ) {
 			section->hdr.PointerToRawData = fpos;
@@ -637,7 +648,7 @@ static void write_pe_file ( struct pe_header *pe_header,
 	for ( section = pe_sections ; section ; section = section->next ) {
 		if ( fseek ( pe, section->hdr.PointerToRawData,
 			     SEEK_SET ) != 0 ) {
-			eprintf ( "Could not seek to %lx: %s\n",
+			eprintf ( "Could not seek to %x: %s\n",
 				  section->hdr.PointerToRawData,
 				  strerror ( errno ) );
 			exit ( 1 );
@@ -786,7 +797,7 @@ int main ( int argc, char **argv ) {
 	struct options opts = {
 		.subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION,
 	};
-	unsigned int infile_index;
+	int infile_index;
 	const char *infile;
 	const char *outfile;
 
diff --git a/roms/ipxe/src/util/fixrom.pl b/roms/ipxe/src/util/fixrom.pl
index c3a31f41e37cc304f5a84548bd49..dcc38fe4ba831fb0156f751c33ba 100755
--- a/roms/ipxe/src/util/fixrom.pl
+++ b/roms/ipxe/src/util/fixrom.pl
@@ -14,7 +14,8 @@
 #
 # 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.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
 
 use strict;
 use warnings;
@@ -28,7 +29,13 @@ my @romfiles = @ARGV;
 foreach my $romfile ( @romfiles ) {
   my $rom = new Option::ROM;
   $rom->load ( $romfile );
-  $rom->pnp_header->fix_checksum() if $rom->pnp_header;
-  $rom->fix_checksum();
+  my $image = $rom;
+  while ( $image ) {
+    $image->pnp_header->fix_checksum() if $image->pnp_header;
+    $image->undi_header->fix_checksum() if $image->undi_header;
+    $image->ipxe_header->fix_checksum() if $image->ipxe_header;
+    $image->fix_checksum();
+    $image = $image->next_image();
+  }
   $rom->save ( $romfile );
 }
diff --git a/roms/ipxe/src/util/fnrec.pl b/roms/ipxe/src/util/fnrec.pl
index 9a2b3d81f98e1d366b9bc0608bd9..cc7312b61a42ae85206983171e9c 100755
--- a/roms/ipxe/src/util/fnrec.pl
+++ b/roms/ipxe/src/util/fnrec.pl
@@ -14,7 +14,8 @@
 #
 # 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.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
 
 =head1 NAME
 
diff --git a/roms/ipxe/src/util/geniso b/roms/ipxe/src/util/geniso
index 790e7171d593dcaa698cab87269e..48ea2f2aae08f9732a1ca3a33600 100755
--- a/roms/ipxe/src/util/geniso
+++ b/roms/ipxe/src/util/geniso
@@ -56,7 +56,7 @@ do
 	g=${g//[^a-z0-9]}.krn
 	case "$first" in
 	"")
-		echo DEFAULT $g
+		echo DEFAULT $b
 		;;
 	esac
 	first=$g
diff --git a/roms/ipxe/src/util/genkeymap.pl b/roms/ipxe/src/util/genkeymap.pl
index d556df27521e3146c4457fe98832..7a5024bf8e45f41b45d5a7aeb63f 100755
--- a/roms/ipxe/src/util/genkeymap.pl
+++ b/roms/ipxe/src/util/genkeymap.pl
@@ -14,7 +14,8 @@
 #
 # 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.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
 
 =head1 NAME
 
@@ -124,8 +125,10 @@ sub keysym_to_ascii {
   return unless $keysym;
 
   # Sanity check
-  die "Unexpected keysym ".sprintf ( "0x%04x\n", $keysym )."\n"
-      if $keysym & 0xf000;
+  if ( $keysym & 0xf000 ) {
+    warn "Unexpected keysym ".sprintf ( "0x%04x", $keysym )."\n";
+    return;
+  }
 
   # Extract type and value
   my $type = ( $keysym >> 8 );
diff --git a/roms/ipxe/src/util/get-pci-ids b/roms/ipxe/src/util/get-pci-ids
index 6501a7f7c401f6483d60b9704b3b..424662212769878438b9c55a4ff9 100755
--- a/roms/ipxe/src/util/get-pci-ids
+++ b/roms/ipxe/src/util/get-pci-ids
@@ -16,7 +16,8 @@
 
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
 
 
 # Known bugs/limitations:
diff --git a/roms/ipxe/src/util/iccfix.c b/roms/ipxe/src/util/iccfix.c
index 8b555c5454e0a5f6e298ed37abb4..528bf4b26c09c6b39e949204e736 100644
--- a/roms/ipxe/src/util/iccfix.c
+++ b/roms/ipxe/src/util/iccfix.c
@@ -2,6 +2,7 @@
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
@@ -49,7 +50,7 @@ static int ICCFIX ( void *elf ) {
 		     ( align >= ICC_ALIGN_HACK_FACTOR ) ) {
 			new_align = ( align / ICC_ALIGN_HACK_FACTOR );
 			shdr->sh_addralign = new_align;
-			dprintf ( "Section \"%s\": alignment %d->%d\n",
+			dprintf ( "Section \"%s\": alignment %ld->%ld\n",
 				  name, align, new_align );
 		}
 	}
diff --git a/roms/ipxe/src/util/licence.pl b/roms/ipxe/src/util/licence.pl
index c37685d3aa4d0cc02da1e7441b12..0e43c7b4c783cefce7e99aabc228 100755
--- a/roms/ipxe/src/util/licence.pl
+++ b/roms/ipxe/src/util/licence.pl
@@ -14,7 +14,8 @@
 #
 # 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.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
 
 use strict;
 use warnings;
diff --git a/roms/ipxe/src/util/mergerom.pl b/roms/ipxe/src/util/mergerom.pl
index f9c52502d13de827ca6ee848e474..f5c1632b0ce22f0a6284a03fa118 100755
--- a/roms/ipxe/src/util/mergerom.pl
+++ b/roms/ipxe/src/util/mergerom.pl
@@ -14,7 +14,8 @@
 #
 # 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.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
 
 use strict;
 use warnings;
@@ -43,9 +44,6 @@ my $offset = $baserom->length;
 
 foreach my $rom ( @roms ) {
 
-  # Update base length
-  $baserom->{length} += $rom->{length};
-
   # Merge initialisation entry point
   merge_entry_points ( $baserom->{init}, $rom->{init}, $offset );
 
@@ -84,15 +82,36 @@ foreach my $rom ( @roms ) {
     merge_entry_points ( $baserom_pnp->{bev}, $rom_pnp->{bev}, $offset );
   }
 
+  # Update iPXE header, if present
+  my $baserom_ipxe = $baserom->ipxe_header;
+  my $rom_ipxe = $rom->ipxe_header;
+  if ( $baserom_ipxe ) {
+
+    # Update shrunk length
+    $baserom_ipxe->{shrunk_length} = ( $baserom->{length} +
+				       ( $rom_ipxe ?
+					 $rom_ipxe->{shrunk_length} :
+					 $rom->{length} ) );
+
+    # Fix checksum
+    $baserom_ipxe->fix_checksum();
+  }
+
+  # Update base length
+  $baserom->{length} += $rom->{length};
+
   # Fix checksum for this ROM segment
   $rom->fix_checksum();
 
+  # Add this ROM to base ROM
+  my $data = substr ( $baserom->get(), 0, $baserom->length() );
+  $data .= $rom->get();
+  $data .= $baserom->next_image()->get() if $baserom->next_image();
+  $baserom->set ( $data );
+
   $offset += $rom->length;
 }
 
 $baserom->pnp_header->fix_checksum() if $baserom->pnp_header;
 $baserom->fix_checksum();
 $baserom->save ( "-" );
-foreach my $rom ( @roms ) {
-  $rom->save ( "-" );
-}
diff --git a/roms/ipxe/src/util/niclist.pl b/roms/ipxe/src/util/niclist.pl
new file mode 100755
index 0000000000000000000000000000000000000000..0600c82322d76ce738838bd0d4bd6d9cabdb25cc
--- /dev/null
+++ b/roms/ipxe/src/util/niclist.pl
@@ -0,0 +1,588 @@
+#!/usr/bin/env perl
+#
+# Generates list of supported NICs with PCI vendor/device IDs, driver name
+# and other useful things.
+#
+# Initial version by Robin Smidsrød <robin@smidsrod.no>
+#
+
+use strict;
+use warnings;
+use autodie;
+use v5.10;
+
+use File::stat;
+use File::Basename qw(basename);
+use File::Find ();
+use Getopt::Long qw(GetOptions);
+
+GetOptions(
+    'help'       => \( my $help     = 0      ),
+    'format=s'   => \( my $format   = 'text' ),
+    'sort=s'     => \( my $sort     = 'bus,ipxe_driver,ipxe_name' ),
+    'columns=s'  => \( my $columns  = 'bus,vendor_id,device_id,'
+                                    . 'vendor_name,device_name,ipxe_driver,'
+                                    . 'ipxe_name,ipxe_description,file,legacy_api'
+                     ),
+    'pci-url=s'  => \( my $pci_url  = 'http://pciids.sourceforge.net/v2.2/pci.ids' ),
+    'pci-file=s' => \( my $pci_file = '/tmp/pci.ids' ),
+    'output=s'   => \( my $output   = '' ),
+);
+
+die(<<"EOM") if $help;
+Usage: $0 [options] [<directory>]
+
+Options:
+    --help     This page
+    --format   Set output format
+    --sort     Set output sort order (comma-separated)
+    --columns  Set output columns (comma-separated)
+    --pci-url  URL to pci.ids file
+    --pci-file Cache file for downloaded pci.ids
+    --output   Output file (not specified is STDOUT)
+
+Output formats:
+    text, csv, json, html, dokuwiki
+
+Column names (default order):
+    bus, vendor_id, device_id, vendor_name, device_name,
+    ipxe_driver, ipxe_name, ipxe_description, file, legacy_api
+EOM
+
+# Only load runtime requirements if actually in use
+given($format) {
+    when( /csv/  ) {
+                       eval { require Text::CSV; };
+                       die("Please install Text::CSV CPAN module to use this feature.\n")
+                           if $@;
+                   }
+    when( /json/ ) {
+                       eval { require JSON; };
+                       die("Please install JSON CPAN module to use this feature.\n")
+                           if $@;
+                   }
+    when( /html/ ) {
+                       eval { require HTML::Entities; };
+                       die("Please install HTML::Entities CPAN module to use this feature.\n")
+                           if $@;
+                   }
+    default        { }
+}
+
+# Scan source dir and build NIC list
+my $ipxe_src_dir = shift || '.'; # Default to current directory
+my $ipxe_nic_list = build_ipxe_nic_list( $ipxe_src_dir );
+
+# Download pci.ids file and parse it
+fetch_pci_ids_file($pci_url, $pci_file);
+my $pci_id_map = build_pci_id_map($pci_file);
+
+# Merge 'official' vendor/device names and sort list
+update_ipxe_nic_names($ipxe_nic_list, $pci_id_map);
+my $sorted_list = sort_ipxe_nic_list($ipxe_nic_list, $sort);
+
+# Run specified formatter
+my $column_names = parse_columns_param($columns);
+say STDERR "Formatting NIC list in format '$format' with columns: "
+         . join(", ", @$column_names);
+my $formatter = \&{ "format_nic_list_$format" };
+my $report = $formatter->( $sorted_list, $column_names );
+
+# Print final report
+if ( $output and $output ne '-' ) {
+    say STDERR "Printing report to '$output'...";
+    open( my $out_fh, ">", $output );
+    print $out_fh $report;
+    close($out_fh);
+}
+else {
+    print STDOUT $report;
+}
+
+exit;
+
+# fetch URL into specified filename
+sub fetch_pci_ids_file {
+    my ($url, $filename) = @_;
+    my @cmd = ( "wget", "--quiet", "-O", $filename, $url );
+    my @touch = ( "touch", $filename );
+    if ( -r $filename ) {
+        my $age = time - stat($filename)->mtime;
+        # Refresh if older than 1 day
+        if ( $age > 86400 ) {
+            say STDERR "Refreshing $filename from $url...";
+            system(@cmd);
+            system(@touch);
+        }
+    }
+    else {
+        say STDERR "Fetching $url into $filename...";
+        system(@cmd);
+        system(@touch);
+    }
+    return $filename;
+}
+
+sub build_pci_id_map {
+    my ($filename) = @_;
+    say STDERR "Building PCI ID map...";
+
+    my $devices = {};
+    my $classes = {};
+    my $pci_id = qr/[[:xdigit:]]{4}/;
+    my $c_id = qr/[[:xdigit:]]{2}/;
+    my $non_space = qr/[^\s]/;
+
+    # open pci.ids file specified
+    open( my $fh, "<", $filename );
+
+    # For devices
+    my $vendor_id = "";
+    my $vendor_name = "";
+    my $device_id = "";
+    my $device_name = "";
+
+    # For classes
+    my $class_id = "";
+    my $class_name = "";
+    my $subclass_id = "";
+    my $subclass_name = "";
+
+    while(<$fh>) {
+        # skip # and blank lines
+        next if m/^$/;
+        next if m/^\s*#/;
+
+        # Vendors, devices and subsystems. Please keep sorted.
+        # Syntax:
+        # vendor  vendor_name
+        #   device  device_name             <-- single tab
+        #       subvendor subdevice  subsystem_name <-- two tabs
+        if ( m/^ ($pci_id) \s+ ( $non_space .* ) /x ) {
+            $vendor_id = lc $1;
+            $vendor_name = $2;
+            $devices->{$vendor_id} = { name => $vendor_name };
+            next;
+        }
+
+        if ( $vendor_id and m/^ \t ($pci_id) \s+ ( $non_space .* ) /x ) {
+            $device_id = lc $1;
+            $device_name = $2;
+            $devices->{$vendor_id}->{'devices'} //= {};
+            $devices->{$vendor_id}->{'devices'}->{$device_id} = { name => $device_name };
+            next;
+        }
+
+        if ( $vendor_id and $device_id and m/^ \t{2} ($pci_id) \s+ ($pci_id) \s+ ( $non_space .* ) /x ) {
+            my $subvendor_id = lc $1;
+            my $subdevice_id = lc $2;
+            my $subsystem_name = $3;
+            $devices->{$vendor_id}->{'devices'}->{$device_id}->{'subvendor'} //= {};
+            $devices->{$vendor_id}->{'devices'}->{$device_id}->{'subvendor'}->{$subvendor_id} //= {};
+            $devices->{$vendor_id}->{'devices'}->{$device_id}->{'subvendor'}->{$subvendor_id}->{'devices'} //= {};
+            $devices->{$vendor_id}->{'devices'}->{$device_id}->{'subvendor'}->{$subvendor_id}->{'devices'}->{$subdevice_id} = { name => $subsystem_name };
+            next;
+        }
+
+        # List of known device classes, subclasses and programming interfaces
+        # Syntax:
+        # C class   class_name
+        #   subclass    subclass_name       <-- single tab
+        #       prog-if  prog-if_name   <-- two tabs
+        if ( m/^C \s+ ($c_id) \s+ ( $non_space .* ) /x ) {
+            $class_id = lc $1;
+            $class_name = $2;
+            $classes->{$class_id} = { name => $class_name };
+            next;
+        }
+
+        if ( $class_id and m/^ \t ($c_id) \s+ ( $non_space .* ) /x ) {
+            $subclass_id = lc $1;
+            $subclass_name = $2;
+            $classes->{$class_id}->{'subclasses'} //= {};
+            $classes->{$class_id}->{'subclasses'}->{$subclass_id} = { name => $subclass_name };
+            next;
+        }
+
+        if ( $class_id and $subclass_id and m/^ \t{2} ($c_id) \s+ ( $non_space .* )  /x ) {
+            my $prog_if_id = lc $1;
+            my $prog_if_name = $2;
+            $classes->{$class_id}->{'subclasses'}->{$subclass_id}->{'programming_interfaces'} //= {};
+            $classes->{$class_id}->{'subclasses'}->{$subclass_id}->{'programming_interfaces'}->{$prog_if_id} = { name => $prog_if_name };
+            next;
+        }
+    }
+
+    close($fh);
+
+    # Populate subvendor names
+    foreach my $vendor_id ( keys %$devices ) {
+        my $device_map = $devices->{$vendor_id}->{'devices'};
+        foreach my $device_id ( keys %$device_map ) {
+            my $subvendor_map = $device_map->{$device_id}->{'subvendor'};
+            foreach my $subvendor_id ( keys %$subvendor_map ) {
+                $subvendor_map->{$subvendor_id}->{'name'} = $devices->{$subvendor_id}->{'name'} || "";
+            }
+        }
+    }
+
+    return {
+        'devices' => $devices,
+        'classes' => $classes,
+    };
+}
+
+# Scan through C code and parse ISA_ROM and PCI_ROM lines
+sub build_ipxe_nic_list {
+    my ($dir) = @_;
+    say STDERR "Building iPXE NIC list from " . ( $dir eq '.' ? 'current directory' : $dir ) . "...";
+
+    # recursively iterate through dir and find .c files
+    my @c_files;
+    File::Find::find(sub {
+        # only process files
+        return if -d $_;
+        # skip unreadable files
+        return unless -r $_;
+        # skip all but files with .c extension
+        return unless /\.c$/;
+        push @c_files, $File::Find::name;
+    }, $dir);
+
+    # Look for ISA_ROM or PCI_ROM lines
+    my $ipxe_nic_list = [];
+    my $hex_id = qr/0 x [[:xdigit:]]{4} /x;
+    my $quote = qr/ ['"] /x;
+    my $non_space = qr/ [^\s] /x;
+    my $rom_line_counter = 0;
+    foreach my $c_path ( sort @c_files ) {
+        my $legacy = 0;
+        open( my $fh, "<", $c_path );
+        my $c_file = $c_path;
+        $c_file =~ s{^\Q$dir\E/?}{} if -d $dir; # Strip directory from reported filename
+        my $ipxe_driver = basename($c_file, '.c');
+        while(<$fh>) {
+            # Most likely EtherBoot legacy API
+            $legacy = 1 if m/struct \s* nic \s*/x;
+
+            # parse ISA|PCI_ROM lines into hashref and append to $ipxe_nic_list
+            next unless m/^ \s* (?:ISA|PCI)_ROM /x;
+            $rom_line_counter++;
+            chomp;
+            #say; # for debugging regexp
+            if ( m/^ \s* ISA_ROM \s* \( \s* $quote ( .*? ) $quote \s* , \s* $quote ( .*? ) $quote \s* \) /x ) {
+                my $image = $1;
+                my $name = $2;
+                push @$ipxe_nic_list, {
+                    file             => $c_file,
+                    bus              => 'isa',
+                    ipxe_driver      => $ipxe_driver,
+                    ipxe_name        => $image,
+                    ipxe_description => $name,
+                    legacy_api       => ( $legacy ? 'yes' : 'no' ),
+                };
+                next;
+            }
+            if ( m/^ \s* PCI_ROM \s* \( \s* ($hex_id) \s* , \s* ($hex_id) \s* , \s* $quote (.*?) $quote \s* , \s* $quote (.*?) $quote /x ) {
+                my $vendor_id = lc $1;
+                my $device_id = lc $2;
+                my $name = $3;
+                my $desc = $4;
+                push @$ipxe_nic_list, {
+                    file             => $c_file,
+                    bus              => 'pci',
+                    vendor_id        => substr($vendor_id, 2), # strip 0x
+                    device_id        => substr($device_id, 2), # strip 0x
+                    ipxe_driver      => $ipxe_driver,
+                    ipxe_name        => $name,
+                    ipxe_description => $desc,
+                    legacy_api       => ( $legacy ? 'yes' : 'no' ),
+                };
+                next;
+            }
+        }
+        close($fh);
+    }
+
+    # Verify all ROM lines where parsed properly
+    my @isa_roms = grep { $_->{'bus'} eq 'isa' } @$ipxe_nic_list;
+    my @pci_roms = grep { $_->{'bus'} eq 'pci' } @$ipxe_nic_list;
+    if ( $rom_line_counter != ( @isa_roms + @pci_roms ) ) {
+        say STDERR "Found ROM lines: $rom_line_counter";
+        say STDERR "Extracted ISA_ROM lines: " . scalar @isa_roms;
+        say STDERR "Extracted PCI_ROM lines: " . scalar @pci_roms;
+        die("Mismatch between number of ISA_ROM/PCI_ROM lines and extracted entries. Verify regular expressions.\n");
+    }
+
+    return $ipxe_nic_list;
+}
+
+# merge vendor/product name from $pci_id_map into $ipxe_nic_list
+sub update_ipxe_nic_names {
+    my ($ipxe_nic_list, $pci_id_map) = @_;
+    say STDERR "Merging 'official' vendor/device names...";
+
+    foreach my $nic ( @$ipxe_nic_list ) {
+        next unless $nic->{'bus'} eq 'pci';
+        $nic->{'vendor_name'} = $pci_id_map->{'devices'}->{ $nic->{'vendor_id'} }->{'name'} || "";
+        $nic->{'device_name'} = $pci_id_map->{'devices'}->{ $nic->{'vendor_id'} }->{'devices'}->{ $nic->{'device_id'} }->{'name'} || "";
+    }
+    return $ipxe_nic_list; # Redundant, as we're mutating the input list, useful for chaining calls
+}
+
+# Sort entries in NIC list according to sort criteria
+sub sort_ipxe_nic_list {
+    my ($ipxe_nic_list, $sort_column_names) = @_;
+    my @sort_column_names = @{ parse_columns_param($sort_column_names) };
+    say STDERR "Sorting NIC list by: " . join(", ", @sort_column_names );
+    # Start at the end of the list and resort until list is exhausted
+    my @sorted_list = @{ $ipxe_nic_list };
+    while(@sort_column_names) {
+        my $column_name = pop @sort_column_names;
+        @sorted_list = sort { ( $a->{$column_name} || "" ) cmp ( $b->{$column_name} || "" ) }
+                       @sorted_list;
+    }
+    return \@sorted_list;
+}
+
+# Parse comma-separated values into array
+sub parse_columns_param {
+    my ($columns) = @_;
+    return [
+        grep { is_valid_column($_) } # only include valid entries
+        map  { s/\s//g; $_; }        # filter whitespace
+        split( /,/, $columns )       # split on comma
+    ];
+}
+
+# Return true if the input column name is valid
+sub is_valid_column {
+    my ($name) = @_;
+    my $valid_column_map = {
+        map { $_ => 1 }
+        qw(
+           bus file legacy_api
+           ipxe_driver ipxe_name ipxe_description
+           vendor_id device_id vendor_name device_name
+        )
+    };
+    return unless $name;
+    return unless $valid_column_map->{$name};
+    return 1;
+}
+
+# Output NIC list in plain text
+sub format_nic_list_text {
+    my ($nic_list, $column_names) = @_;
+    return join("\n",
+        map { format_nic_text($_, $column_names) }
+        @$nic_list
+    );
+}
+
+# Format one ipxe_nic_list entry for display
+# Column order not supported by text format
+sub format_nic_text {
+    my ($nic, $column_names) = @_;
+    my $labels = {
+        bus              => 'Bus:             ',
+        ipxe_driver      => 'iPXE driver:     ',
+        ipxe_name        => 'iPXE name:       ',
+        ipxe_description => 'iPXE description:',
+        file             => 'Source file:     ',
+        legacy_api       => 'Using legacy API:',
+        vendor_id        => 'PCI vendor ID:   ',
+        device_id        => 'PCI device ID:   ',
+        vendor_name      => 'Vendor name:     ',
+        device_name      => 'Device name:     ',
+    };
+    my $pci_only = {
+        vendor_id   => 1,
+        device_id   => 1,
+        vendor_name => 1,
+        device_name => 1,
+    };
+    my $output = "";
+    foreach my $column ( @$column_names ) {
+        next if $nic->{'bus'} eq 'isa' and $pci_only->{$column};
+        $output .= $labels->{$column}
+                .  " "
+                . ( $nic->{$column} || "" )
+                . "\n";
+    }
+    return $output;
+}
+
+# Output NIC list in JSON
+sub format_nic_list_json {
+    my ($nic_list, $column_names) = @_;
+
+    # Filter columns not mentioned
+    my @nics;
+    foreach my $nic ( @$nic_list ) {
+        my $filtered_nic = {};
+        foreach my $key ( @$column_names ) {
+            $filtered_nic->{$key} = $nic->{$key};
+        }
+        push @nics, $filtered_nic;
+    }
+
+    return JSON->new->pretty->utf8->encode(\@nics);
+}
+
+# Output NIC list in CSV
+sub format_nic_list_csv {
+    my ($nic_list, $column_names) = @_;
+    my @output;
+
+    # Output CSV header
+    my $csv = Text::CSV->new();
+    if ( $csv->combine( @$column_names ) ) {
+        push @output, $csv->string();
+    }
+
+    # Output CSV lines
+    foreach my $nic ( @$nic_list ) {
+        my @columns = @{ $nic }{ @$column_names };
+        if ( $csv->combine( @columns ) ) {
+            push @output, $csv->string();
+        }
+    }
+    return join("\n", @output) . "\n";
+}
+
+# Output NIC list in HTML
+sub format_nic_list_html {
+    my ($nic_list, $column_names) = @_;
+    my @output;
+
+    push @output, <<'EOM';
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Network cards supported by iPXE</title>
+<style>
+table.tablesorter {
+ border: thin solid black;
+}
+
+table.tablesorter thead {
+ background-color: #EEE;
+}
+
+table.tablesorter thead th {
+ font-weight: bold;
+}
+
+table.tablesorter tbody td {
+ vertical-align: top;
+ padding-left: 0.25em;
+ padding-right: 0.25em;
+ padding-bottom: 0.125em;
+ white-space: nowrap;
+}
+
+table.tablesorter tbody tr.even {
+ background-color: #eee;
+}
+
+table.tablesorter tbody tr.odd {
+ background-color: #fff;
+}
+</style>
+</head>
+<body>
+<h1>Network cards supported by iPXE</h1>
+<table class="tablesorter">
+<thead>
+EOM
+
+    # Output HTML header
+    push @output, "<tr>"
+                . join("",
+                    map { "<th>" . HTML::Entities::encode($_) . "</th>" }
+                    @$column_names
+                  )
+                . "</tr>";
+
+    push @output, <<"EOM";
+</thead>
+<tbody>
+EOM
+    # Output HTML lines
+    my $counter = 0;
+    foreach my $nic ( @$nic_list ) {
+        my @columns = @{ $nic }{ @$column_names }; # array slice from hashref, see perldoc perldata if confusing
+        push @output, q!<tr class="! . ( $counter % 2 ? 'even' : 'odd' ) . q!">!
+                    . join("",
+                        map { "<td>" . HTML::Entities::encode( $_ || "" ) . "</td>" }
+                        @columns
+                      )
+                    . "</tr>";
+        $counter++;
+    }
+
+    push @output, <<'EOM';
+</tbody>
+</table>
+<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+<script>
+/*
+ *
+ * TableSorter 2.0 - Client-side table sorting with ease!
+ * Version 2.0.5b
+ * @requires jQuery v1.2.3
+ * From http://tablesorter.com/
+ *
+ * Copyright (c) 2007 Christian Bach
+ * Examples and docs at: http://tablesorter.com
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+(function($){$.extend({tablesorter:new
+function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",cssChildRow:"expand-child",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,sortLocaleCompare:true,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'/\.|\,/g',onRenderHeader:null,selectorHeaders:'thead th',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}if(table.tBodies.length==0)return;var rows=table.tBodies[0].rows;if(rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i<l;i++){var p=false;if($.metadata&&($($headers[i]).metadata()&&$($headers[i]).metadata().sorter)){p=getParserById($($headers[i]).metadata().sorter);}else if((table.config.headers[i]&&table.config.headers[i].sorter)){p=getParserById(table.config.headers[i].sorter);}if(!p){p=detectParserForColumn(table,rows,-1,i);}if(table.config.debug){parsersDebug+="column:"+i+" parser:"+p.id+"\n";}list.push(p);}}if(table.config.debug){log(parsersDebug);}return list;};function detectParserForColumn(table,rows,rowIndex,cellIndex){var l=parsers.length,node=false,nodeValue=false,keepLooking=true;while(nodeValue==''&&keepLooking){rowIndex++;if(rows[rowIndex]){node=getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex);nodeValue=trimAndGetNodeText(table.config,node);if(table.config.debug){log('Checking if value was empty on row:'+rowIndex);}}else{keepLooking=false;}}for(var i=1;i<l;i++){if(parsers[i].is(nodeValue,table,node)){return parsers[i];}}return parsers[0];}function getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex){return rows[rowIndex].cells[cellIndex];}function trimAndGetNodeText(config,node){return $.trim(getElementText(config,node));}function getParserById(name){var l=parsers.length;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==name.toLowerCase()){return parsers[i];}}return false;}function buildCache(table){if(table.config.debug){var cacheTime=new Date();}var totalRows=(table.tBodies[0]&&table.tBodies[0].rows.length)||0,totalCells=(table.tBodies[0].rows[0]&&table.tBodies[0].rows[0].cells.length)||0,parsers=table.config.parsers,cache={row:[],normalized:[]};for(var i=0;i<totalRows;++i){var c=$(table.tBodies[0].rows[i]),cols=[];if(c.hasClass(table.config.cssChildRow)){cache.row[cache.row.length-1]=cache.row[cache.row.length-1].add(c);continue;}cache.row.push(c);for(var j=0;j<totalCells;++j){cols.push(parsers[j].format(getElementText(table.config,c[0].cells[j]),table,c[0].cells[j]));}cols.push(cache.normalized.length);cache.normalized.push(cols);cols=null;};if(table.config.debug){benchmark("Building cache for "+totalRows+" rows:",cacheTime);}return cache;};function getElementText(config,node){var text="";if(!node)return"";if(!config.supportsTextContent)config.supportsTextContent=node.textContent||false;if(config.textExtraction=="simple"){if(config.supportsTextContent){text=node.textContent;}else{if(node.childNodes[0]&&node.childNodes[0].hasChildNodes()){text=node.childNodes[0].innerHTML;}else{text=node.innerHTML;}}}else{if(typeof(config.textExtraction)=="function"){text=config.textExtraction(node);}else{text=$(node).text();}}return text;}function appendToTable(table,cache){if(table.config.debug){var appendTime=new Date()}var c=cache,r=c.row,n=c.normalized,totalRows=n.length,checkCell=(n[0].length-1),tableBody=$(table.tBodies[0]),rows=[];for(var i=0;i<totalRows;i++){var pos=n[i][checkCell];rows.push(r[pos]);if(!table.config.appender){var l=r[pos].length;for(var j=0;j<l;j++){tableBody[0].appendChild(r[pos][j]);}}}if(table.config.appender){table.config.appender(table,rows);}rows=null;if(table.config.debug){benchmark("Rebuilt table:",appendTime);}applyWidget(table);setTimeout(function(){$(table).trigger("sortEnd");},0);};function buildHeaders(table){if(table.config.debug){var time=new Date();}var meta=($.metadata)?true:false;var header_index=computeTableHeaderCellIndexes(table);$tableHeaders=$(table.config.selectorHeaders,table).each(function(index){this.column=header_index[this.parentNode.rowIndex+"-"+this.cellIndex];this.order=formatSortingOrder(table.config.sortInitialOrder);this.count=this.order;if(checkHeaderMetadata(this)||checkHeaderOptions(table,index))this.sortDisabled=true;if(checkHeaderOptionsSortingLocked(table,index))this.order=this.lockedOrder=checkHeaderOptionsSortingLocked(table,index);if(!this.sortDisabled){var $th=$(this).addClass(table.config.cssHeader);if(table.config.onRenderHeader)table.config.onRenderHeader.apply($th);}table.config.headerList[index]=this;});if(table.config.debug){benchmark("Built headers:",time);log($tableHeaders);}return $tableHeaders;};function computeTableHeaderCellIndexes(t){var matrix=[];var lookup={};var thead=t.getElementsByTagName('THEAD')[0];var trs=thead.getElementsByTagName('TR');for(var i=0;i<trs.length;i++){var cells=trs[i].cells;for(var j=0;j<cells.length;j++){var c=cells[j];var rowIndex=c.parentNode.rowIndex;var cellId=rowIndex+"-"+c.cellIndex;var rowSpan=c.rowSpan||1;var colSpan=c.colSpan||1
+var firstAvailCol;if(typeof(matrix[rowIndex])=="undefined"){matrix[rowIndex]=[];}for(var k=0;k<matrix[rowIndex].length+1;k++){if(typeof(matrix[rowIndex][k])=="undefined"){firstAvailCol=k;break;}}lookup[cellId]=firstAvailCol;for(var k=rowIndex;k<rowIndex+rowSpan;k++){if(typeof(matrix[k])=="undefined"){matrix[k]=[];}var matrixrow=matrix[k];for(var l=firstAvailCol;l<firstAvailCol+colSpan;l++){matrixrow[l]="x";}}}}return lookup;}function checkCellColSpan(table,rows,row){var arr=[],r=table.tHead.rows,c=r[row].cells;for(var i=0;i<c.length;i++){var cell=c[i];if(cell.colSpan>1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function checkHeaderOptionsSortingLocked(table,i){if((table.config.headers[i])&&(table.config.headers[i].lockedOrder))return table.config.headers[i].lockedOrder;return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i<l;i++){getWidgetById(c[i]).format(table);}}function getWidgetById(name){var l=widgets.length;for(var i=0;i<l;i++){if(widgets[i].id.toLowerCase()==name.toLowerCase()){return widgets[i];}}};function formatSortingOrder(v){if(typeof(v)!="Number"){return(v.toLowerCase()=="desc")?1:0;}else{return(v==1)?1:0;}}function isValueInArray(v,a){var l=a.length;for(var i=0;i<l;i++){if(a[i][0]==v){return true;}}return false;}function setHeadersCss(table,$headers,list,css){$headers.removeClass(css[0]).removeClass(css[1]);var h=[];$headers.each(function(offset){if(!this.sortDisabled){h[this.column]=$(this);}});var l=list.length;for(var i=0;i<l;i++){h[list[i][0]].addClass(css[list[i][1]]);}}function fixColumnWidth(table,$headers){var c=table.config;if(c.widthFixed){var colgroup=$('<colgroup>');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('<col>').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i<l;i++){var s=sortList[i],o=c.headerList[s[0]];o.count=s[1];o.count++;}}function multisort(table,sortList,cache){if(table.config.debug){var sortTime=new Date();}var dynamicExp="var sortWrapper = function(a,b) {",l=sortList.length;for(var i=0;i<l;i++){var c=sortList[i][0];var order=sortList[i][1];var s=(table.config.parsers[c].type=="text")?((order==0)?makeSortFunction("text","asc",c):makeSortFunction("text","desc",c)):((order==0)?makeSortFunction("numeric","asc",c):makeSortFunction("numeric","desc",c));var e="e"+i;dynamicExp+="var "+e+" = "+s;dynamicExp+="if("+e+") { return "+e+"; } ";dynamicExp+="else { ";}var orgOrderCol=cache.normalized[0].length-1;dynamicExp+="return a["+orgOrderCol+"]-b["+orgOrderCol+"];";for(var i=0;i<l;i++){dynamicExp+="}; ";}dynamicExp+="return 0; ";dynamicExp+="}; ";if(table.config.debug){benchmark("Evaling expression:"+dynamicExp,new Date());}eval(dynamicExp);cache.normalized.sort(sortWrapper);if(table.config.debug){benchmark("Sorting on "+sortList.toString()+" and dir "+order+" time:",sortTime);}return cache;};function makeSortFunction(type,direction,index){var a="a["+index+"]",b="b["+index+"]";if(type=='text'&&direction=='asc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+a+" < "+b+") ? -1 : 1 )));";}else if(type=='text'&&direction=='desc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+b+" < "+a+") ? -1 : 1 )));";}else if(type=='numeric'&&direction=='asc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+a+" - "+b+"));";}else if(type=='numeric'&&direction=='desc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+b+" - "+a+"));";}};function makeSortText(i){return"((a["+i+"] < b["+i+"]) ? -1 : ((a["+i+"] > b["+i+"]) ? 1 : 0));";};function makeSortTextDesc(i){return"((b["+i+"] < a["+i+"]) ? -1 : ((b["+i+"] > a["+i+"]) ? 1 : 0));";};function makeSortNumeric(i){return"a["+i+"]-b["+i+"];";};function makeSortNumericDesc(i){return"b["+i+"]-a["+i+"];";};function sortText(a,b){if(table.config.sortLocaleCompare)return a.localeCompare(b);return((a<b)?-1:((a>b)?1:0));};function sortTextDesc(a,b){if(table.config.sortLocaleCompare)return b.localeCompare(a);return((b<a)?-1:((b>a)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$.data(this,"tablesorter",config);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){$this.trigger("sortStart");var $cell=$(this);var i=this.column;this.order=this.count++%2;if(this.lockedOrder)this.order=this.lockedOrder;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j<a.length;j++){if(a[j][0]!=i){config.sortList.push(a[j]);}}}config.sortList.push([i,this.order]);}else{if(isValueInArray(i,config.sortList)){for(var j=0;j<config.sortList.length;j++){var s=config.sortList[j],o=config.headerList[s[0]];if(s[0]==i){o.count=s[1];o.count++;s[1]=o.count%2;}}}else{config.sortList.push([i,this.order]);}};setTimeout(function(){setHeadersCss($this[0],$headers,config.sortList,sortCSS);appendToTable($this[0],multisort($this[0],config.sortList,cache));},1);return false;}}).mousedown(function(){if(config.cancelSelection){this.onselectstart=function(){return false};return false;}});$this.bind("update",function(){var me=this;setTimeout(function(){me.config.parsers=buildParserCache(me,$headers);cache=buildCache(me);},1);}).bind("updateCell",function(e,cell){var config=this.config;var pos=[(cell.parentNode.rowIndex-1),cell.cellIndex];cache.normalized[pos[0]][pos[1]]=config.parsers[pos[1]].format(getElementText(config,cell),cell);}).bind("sorton",function(e,list){$(this).trigger("sortStart");config.sortList=list;var sortList=config.sortList;updateHeaderSortCount(this,sortList);setHeadersCss(this,$headers,sortList,sortCSS);appendToTable(this,multisort(this,sortList,cache));}).bind("appendCache",function(){appendToTable(this,cache);}).bind("applyWidgetId",function(e,id){getWidgetById(id).format(this);}).bind("applyWidgets",function(){applyWidget(this);});if($.metadata&&($(this).metadata()&&$(this).metadata().sortlist)){config.sortList=$(this).metadata().sortlist;}if(config.sortList.length>0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==parser.id.toLowerCase()){a=false;}}if(a){parsers.push(parser);};};this.addWidget=function(widget){widgets.push(widget);};this.formatFloat=function(s){var i=parseFloat(s);return(isNaN(i))?0:i;};this.formatInt=function(s){var i=parseInt(s);return(isNaN(i))?0:i;};this.isDigit=function(s,config){return/^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g,'')));};this.clearTableBody=function(table){if($.browser.msie){function empty(){while(this.firstChild)this.removeChild(this.firstChild);}empty.apply(table.tBodies[0]);}else{table.tBodies[0].innerHTML="";}};}});$.fn.extend({tablesorter:$.tablesorter.construct});var ts=$.tablesorter;ts.addParser({id:"text",is:function(s){return true;},format:function(s){return $.trim(s.toLocaleLowerCase());},type:"text"});ts.addParser({id:"digit",is:function(s,table){var c=table.config;return $.tablesorter.isDigit(s,c);},format:function(s){return $.tablesorter.formatFloat(s);},type:"numeric"});ts.addParser({id:"currency",is:function(s){return/^[£$€?.]/.test(s);},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g),""));},type:"numeric"});ts.addParser({id:"ipAddress",is:function(s){return/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);},format:function(s){var a=s.split("."),r="",l=a.length;for(var i=0;i<l;i++){var item=a[i];if(item.length==2){r+="0"+item;}else{r+=item;}}return $.tablesorter.formatFloat(r);},type:"numeric"});ts.addParser({id:"url",is:function(s){return/^(https?|ftp|file):\/\/$/.test(s);},format:function(s){return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));},type:"text"});ts.addParser({id:"isoDate",is:function(s){return/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);},format:function(s){return $.tablesorter.formatFloat((s!="")?new Date(s.replace(new RegExp(/-/g),"/")).getTime():"0");},type:"numeric"});ts.addParser({id:"percent",is:function(s){return/\%$/.test($.trim(s));},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));},type:"numeric"});ts.addParser({id:"usLongDate",is:function(s){return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));},format:function(s){return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"shortDate",is:function(s){return/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);},format:function(s,table){var c=table.config;s=s.replace(/\-/g,"/");if(c.dateFormat=="us"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$1/$2");}else if(c.dateFormat=="uk"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$2/$1");}else if(c.dateFormat=="dd/mm/yy"||c.dateFormat=="dd-mm-yy"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/,"$1/$2/$3");}return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"time",is:function(s){return/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);},format:function(s){return $.tablesorter.formatFloat(new Date("2000/01/01 "+s).getTime());},type:"numeric"});ts.addParser({id:"metadata",is:function(s){return false;},format:function(s,table,cell){var c=table.config,p=(!c.parserMetadataName)?'sortValue':c.parserMetadataName;return $(cell).metadata()[p];},type:"numeric"});ts.addWidget({id:"zebra",format:function(table){if(table.config.debug){var time=new Date();}var $tr,row=-1,odd;$("tr:visible",table.tBodies[0]).each(function(i){$tr=$(this);if(!$tr.hasClass(table.config.cssChildRow))row++;odd=(row%2==0);$tr.removeClass(table.config.widgetZebra.css[odd?0:1]).addClass(table.config.widgetZebra.css[odd?1:0])});if(table.config.debug){$.tablesorter.benchmark("Applying Zebra widget",time);}}});})(jQuery);
+</script>
+<script type="text/javascript">
+$(document).ready(function() {
+    $("table.tablesorter").tablesorter();
+});
+</script>
+</body>
+</html>
+EOM
+    return join("\n", @output);
+}
+
+# Output NIC list in DokuWiki format (for http://ipxe.org)
+sub format_nic_list_dokuwiki {
+    my ($nic_list, $column_names) = @_;
+    my @output;
+
+    push @output, <<'EOM';
+EOM
+
+    # Output DokuWiki table header
+    push @output, "^"
+                . join("^",
+                    map { $_ || "" }
+                    @$column_names
+                  )
+                . "^";
+
+    # Output DokuWiki table entries
+    foreach my $nic ( @$nic_list ) {
+        my @columns = @{ $nic }{ @$column_names }; # array slice from hashref, see perldoc perldata if confusing
+        push @output, '|'
+                    . join('|',
+                        map { $_ || "" }
+                        @columns
+                      )
+                    . '|';
+    }
+
+    return join("\n", @output);
+}
diff --git a/roms/ipxe/src/util/nrv2b.c b/roms/ipxe/src/util/nrv2b.c
index 6bac4cdda28dde04198f6a6f52b4..031f5d9cb4a2c2560fb0a5ed2d24 100644
--- a/roms/ipxe/src/util/nrv2b.c
+++ b/roms/ipxe/src/util/nrv2b.c
@@ -77,7 +77,7 @@ static __inline__ void Error(char *message)
 
 /* These will be a complete waste of time on a lo-endian */
 /* system, but it only gets done once so WTF. */
-static unsigned long i86ul_to_host(unsigned long ul)
+static unsigned long __attribute__ (( unused )) i86ul_to_host(unsigned long ul)
 {
 	unsigned long res = 0;
 	int i;
@@ -209,7 +209,7 @@ struct ucl_compress
 
 #define SWD_HSIZE	16384
 #define SWD_MAX_CHAIN	2048
-#define SWD_BEST_OFF    1
+#undef SWD_BEST_OFF
 
 #define HEAD3(b,p) \
     (((0x9f5f*(((((uint32_t)b[p]<<5)^b[p+1])<<5)^b[p+2]))>>5) & (SWD_HSIZE-1))
@@ -375,7 +375,6 @@ static
 int swd_init(struct ucl_swd *s, const uint8_t *dict, unsigned int dict_len)
 {
 	unsigned int i = 0;
-	int c = 0;
 
 	if (s->n == 0)
 		s->n = N;
@@ -439,7 +438,7 @@ static
 void swd_exit(struct ucl_swd *s)
 {
 	/* unused s */
-
+	( void ) s;
 }
 
 #define swd_pos2off(s,pos) \
diff --git a/roms/ipxe/src/util/parserom.pl b/roms/ipxe/src/util/parserom.pl
old mode 100644
new mode 100755
index cf9f7c69b8206e72c7a63c4a1c532f064a6ed96a..e278e6336e4dbaded98a26a72db1f9081b5c9fba
--- a/roms/ipxe/src/util/parserom.pl
+++ b/roms/ipxe/src/util/parserom.pl
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/env perl
 #
 # Parse PCI_ROM and ISA_ROM entries from a source file on stdin and
 # output the relevant Makefile variable definitions to stdout
@@ -28,6 +28,7 @@ sub rom {
     $printed_family = 1;
   }
   print "\n";
+  return if ( $vendor && ( ( $vendor eq "ffff" ) || ( $device eq "ffff" ) ) );
   print "# NIC\t$image\t$ids\t$desc\n";
   print "DRIVER_$image = $driver_name\n";
   print "ROM_TYPE_$image = $type\n";
@@ -49,7 +50,6 @@ while ( <DRV> ) {
          \s*.*\s*		   # Driver data
        \)/x ) {
     ( my $vendor, my $device, my $image, my $desc ) = ( lc $1, lc $2, $3, $4 );
-    next if ( $vendor eq "ffff" ) || ( $device eq "ffff" );
     rom ( "pci", lc "${vendor}${device}", $desc, $vendor, $device );
     rom ( "pci", $image, $desc, $vendor, $device, 1 );
   } elsif ( /^\s*ISA_ROM\s*\(
diff --git a/roms/ipxe/src/util/romcheck.pl b/roms/ipxe/src/util/romcheck.pl
new file mode 100755
index 0000000000000000000000000000000000000000..f47bb07e875299bffe2ee181797f62bf413a6eb5
--- /dev/null
+++ b/roms/ipxe/src/util/romcheck.pl
@@ -0,0 +1,54 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+
+use constant DEVICES => "/proc/bus/pci/devices";
+
+open my $fh, DEVICES
+    or die "Could not open ".DEVICES.": $!";
+
+while ( ( my $line = <$fh> ) ) {
+
+  # Parse line from /proc/bus/pci/devices
+  chomp $line;
+  ( my $bus, my $devfn, my $vendor, my $device, my $irq, my $bars, my $lengths,
+    my $driver )
+      = ( $line =~ /^ ([0-9a-f]{2}) ([0-9a-f]{2}) \s+
+		      ([0-9a-f]{4}) ([0-9a-f]{4}) \s+ ([0-9a-f]+) \s+
+		      ((?:[0-9a-f]+\s+){7}) ((?:[0-9a-f]+\s+){7})
+		      (.+)?$/x )
+      or die "Invalid line \"".$line."\"\n";
+  ( $bus, $devfn, $vendor, $device, $irq ) =
+      map { hex ( $_ ) } ( $bus, $devfn, $vendor, $device, $irq );
+  my $dev = ( $devfn >> 3 );
+  my $fn = ( $devfn & 0x7 );
+  $bars = [ map { hex ( $_ ) } split ( /\s+/, $bars ) ];
+  $lengths = [ map { hex ( $_ ) } split ( /\s+/, $lengths ) ];
+
+  # Calculate expansion ROM BAR presence and length
+  my $rom_length = $lengths->[6];
+
+  # Look for a BAR that could support a .mrom
+  my $mrom_ok;
+  if ( $rom_length ) {
+    for ( my $bar = 0 ; $bar < 7 ; $bar++ ) {
+      # Skip I/O BARs
+      next if $bars->[$bar] & 0x01;
+      # Skip low half of 64-bit BARs
+      $bar++ if $bars->[$bar] & 0x04;
+      # Skip 64-bit BARs with high dword set
+      next if $bars->[$bar] >> 32;
+      # Skip BARs smaller than the expansion ROM BAR
+      next if $lengths->[$bar] < $rom_length;
+      # This BAR is usable!
+      $mrom_ok = 1;
+      last;
+    }
+  }
+
+  printf "%02x:%02x.%x (%04x:%04x)", $bus, $dev, $fn, $vendor, $device;
+  printf " supports a %dkB .rom", ( $rom_length / 1024 ) if $rom_length;
+  printf " or .mrom" if $mrom_ok;
+  printf "\n";
+}
diff --git a/roms/ipxe/src/util/zbin.c b/roms/ipxe/src/util/zbin.c
index f0df5ea0d7e2bbd2674f471e3633..3b7cf95b3df7491dc3c5ef78f087 100644
--- a/roms/ipxe/src/util/zbin.c
+++ b/roms/ipxe/src/util/zbin.c
@@ -143,7 +143,7 @@ static int alloc_output_file ( size_t max_len, struct output_file *output ) {
 			  max_len );
 		return -1;
 	}
-	memset ( output->buf, 0xff, sizeof ( output->buf ) );
+	memset ( output->buf, 0xff, max_len );
 	return 0;
 }
 
@@ -218,7 +218,8 @@ static int process_zinfo_pack ( struct input_file *input,
 	return 0;
 }
 
-static int process_zinfo_payl ( struct input_file *input,
+static int process_zinfo_payl ( struct input_file *input
+					__attribute__ (( unused )),
 				struct output_file *output,
 				union zinfo_record *zinfo ) {
 	struct zinfo_payload *payload = &zinfo->payload;
@@ -229,20 +230,22 @@ static int process_zinfo_payl ( struct input_file *input,
 	if ( DEBUG ) {
 		fprintf ( stderr, "PAYL at %#zx\n", output->hdr_len );
 	}
+	return 0;
 }
 
-static int process_zinfo_add ( struct input_file *input,
+static int process_zinfo_add ( struct input_file *input
+					__attribute__ (( unused )),
 			       struct output_file *output,
 			       size_t len,
-			       struct zinfo_add *add,
+			       struct zinfo_add *add, size_t offset,
 			       size_t datasize ) {
-	size_t offset = add->offset;
 	void *target;
 	signed long addend;
 	unsigned long size;
 	signed long val;
 	unsigned long mask;
 
+	offset += add->offset;
 	if ( ( offset + datasize ) > output->len ) {
 		fprintf ( stderr, "Add at %#zx outside output buffer\n",
 			  offset );
@@ -316,42 +319,90 @@ static int process_zinfo_addb ( struct input_file *input,
 				struct output_file *output,
 				union zinfo_record *zinfo ) {
 	return process_zinfo_add ( input, output, output->len,
-				   &zinfo->add, 1 );
+				   &zinfo->add, 0, 1 );
 }
 
 static int process_zinfo_addw ( struct input_file *input,
 				struct output_file *output,
 				union zinfo_record *zinfo ) {
 	return process_zinfo_add ( input, output, output->len,
-				   &zinfo->add, 2 );
+				   &zinfo->add, 0, 2 );
 }
 
 static int process_zinfo_addl ( struct input_file *input,
 				struct output_file *output,
 				union zinfo_record *zinfo ) {
 	return process_zinfo_add ( input, output, output->len,
-				   &zinfo->add, 4 );
+				   &zinfo->add, 0, 4 );
 }
 
 static int process_zinfo_adhb ( struct input_file *input,
 				struct output_file *output,
 				union zinfo_record *zinfo ) {
 	return process_zinfo_add ( input, output, output->hdr_len,
-				   &zinfo->add, 1 );
+				   &zinfo->add, 0, 1 );
 }
 
 static int process_zinfo_adhw ( struct input_file *input,
 				struct output_file *output,
 				union zinfo_record *zinfo ) {
 	return process_zinfo_add ( input, output, output->hdr_len,
-				   &zinfo->add, 2 );
+				   &zinfo->add, 0, 2 );
 }
 
 static int process_zinfo_adhl ( struct input_file *input,
 				struct output_file *output,
 				union zinfo_record *zinfo ) {
 	return process_zinfo_add ( input, output, output->hdr_len,
-				   &zinfo->add, 4 );
+				   &zinfo->add, 0, 4 );
+}
+
+static int process_zinfo_adpb ( struct input_file *input,
+				struct output_file *output,
+				union zinfo_record *zinfo ) {
+	return process_zinfo_add ( input, output,
+				   ( output->len - output->hdr_len ),
+				   &zinfo->add, 0, 1 );
+}
+
+static int process_zinfo_adpw ( struct input_file *input,
+				struct output_file *output,
+				union zinfo_record *zinfo ) {
+	return process_zinfo_add ( input, output,
+				   ( output->len - output->hdr_len ),
+				   &zinfo->add, 0, 2 );
+}
+
+static int process_zinfo_adpl ( struct input_file *input,
+				struct output_file *output,
+				union zinfo_record *zinfo ) {
+	return process_zinfo_add ( input, output,
+				   ( output->len - output->hdr_len ),
+				   &zinfo->add, 0, 4 );
+}
+
+static int process_zinfo_appb ( struct input_file *input,
+				struct output_file *output,
+				union zinfo_record *zinfo ) {
+	return process_zinfo_add ( input, output,
+				   ( output->len - output->hdr_len ),
+				   &zinfo->add, output->hdr_len, 1 );
+}
+
+static int process_zinfo_appw ( struct input_file *input,
+				struct output_file *output,
+				union zinfo_record *zinfo ) {
+	return process_zinfo_add ( input, output,
+				   ( output->len - output->hdr_len ),
+				   &zinfo->add, output->hdr_len, 2 );
+}
+
+static int process_zinfo_appl ( struct input_file *input,
+				struct output_file *output,
+				union zinfo_record *zinfo ) {
+	return process_zinfo_add ( input, output,
+				   ( output->len - output->hdr_len ),
+				   &zinfo->add, output->hdr_len, 4 );
 }
 
 struct zinfo_processor {
@@ -371,6 +422,12 @@ static struct zinfo_processor zinfo_processors[] = {
 	{ "ADHB", process_zinfo_adhb },
 	{ "ADHW", process_zinfo_adhw },
 	{ "ADHL", process_zinfo_adhl },
+	{ "ADPB", process_zinfo_adpb },
+	{ "ADPW", process_zinfo_adpw },
+	{ "ADPL", process_zinfo_adpl },
+	{ "APPB", process_zinfo_appb },
+	{ "APPW", process_zinfo_appw },
+	{ "APPL", process_zinfo_appl },
 };
 
 static int process_zinfo ( struct input_file *input,
